├── .gitignore
├── .vscode
└── launch.json
├── README.md
├── dist
├── attributes.js
├── attributes.js.map
├── class-name.js
├── class-name.js.map
├── custom-types
│ ├── colors.js
│ ├── colors.js.map
│ ├── css-properties.js
│ ├── css-properties.js.map
│ ├── css-property-values.js
│ ├── css-property-values.js.map
│ ├── tag-names.js
│ ├── tag-names.js.map
│ ├── types.js
│ └── types.js.map
├── generation
│ ├── css-generator.js
│ ├── css-generator.js.map
│ ├── html-generator.js
│ └── html-generator.js.map
├── hobo.js
├── hobo.js.map
├── hobo.min.mjs
├── hobo.min.mjs.gz
├── hobo.mjs
├── hobo.umd.js
├── hobo.umd.min.js
├── hobo.umd.min.js.gz
├── style.js
├── style.js.map
├── tag-builder.js
├── tag-builder.js.map
├── tag.js
├── tag.js.map
├── types
│ ├── attributes.d.ts
│ ├── class-name.d.ts
│ ├── custom-types
│ │ ├── colors.d.ts
│ │ ├── css-properties.d.ts
│ │ ├── css-property-values.d.ts
│ │ ├── tag-names.d.ts
│ │ └── types.d.ts
│ ├── generation
│ │ ├── css-generator.d.ts
│ │ └── html-generator.d.ts
│ ├── hobo.d.ts
│ ├── style.d.ts
│ ├── tag-builder.d.ts
│ ├── tag.d.ts
│ └── util.d.ts
├── util.js
└── util.js.map
├── docs
├── .nojekyll
├── assets
│ ├── highlight.css
│ ├── main.js
│ ├── navigation.js
│ ├── search.js
│ └── style.css
├── classes
│ ├── attributes.AttrSet.html
│ ├── class_name.ClassName.html
│ ├── style.StyleSet.html
│ ├── tag.Tag.html
│ └── tag_builder.TagBuilder.html
├── functions
│ ├── hobo.attach.html
│ ├── hobo.detach.html
│ ├── hobo.doc.html
│ ├── hobo.generate.html
│ ├── util.camelToDash.html
│ ├── util.dashToCamel.html
│ ├── util.generateId.html
│ ├── util.isObject.html
│ ├── util.justFnBody.html
│ └── util.replaceDoubleQuotes.html
├── index.html
├── modules
│ ├── attributes.html
│ ├── class_name.html
│ ├── hobo.html
│ ├── style.html
│ ├── tag.html
│ ├── tag_builder.html
│ └── util.html
├── types
│ └── tag_builder.PickArgType.html
└── variables
│ ├── hobo._context.html
│ ├── hobo.builders.html
│ └── tag_builder.builders.html
├── examples
├── _test.ts
├── generated
│ ├── readme-1.html
│ ├── tag-attributes.html
│ ├── tag-classes.html
│ ├── tag-inline-styles.html
│ ├── tag-scripts.html
│ └── tag-styles.html
├── hobo-in-js.js
├── readme-1.ts
├── tag-attributes.ts
├── tag-classes.ts
├── tag-inline-styles.ts
├── tag-script.ts
└── tag-style.ts
├── hobo-header.png
├── jest.config.js
├── package-lock.json
├── package.json
├── scripts
└── generate_api_docs.js
├── src
├── attributes.ts
├── class-name.ts
├── custom-types
│ ├── colors.ts
│ ├── css-properties.ts
│ ├── css-property-values.ts
│ ├── tag-names.ts
│ └── types.ts
├── generation
│ ├── css-generator.ts
│ └── html-generator.ts
├── hobo.ts
├── style.ts
├── tag-builder.ts
├── tag.ts
└── util.ts
├── tests
└── unit
│ ├── css-generator.test.ts
│ ├── hobo.test.ts
│ ├── html-generator.test.ts
│ ├── miscelaneous.test.ts
│ ├── tag-builder.test.ts
│ └── tag.test.ts
├── tsconfig.build.json
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /_*
2 | /_*/
3 | /node_modules/
4 | /src/*.html
5 | /src/*.js
6 | /src/*.js.map
7 | /coverage/
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 |
8 | {
9 | "type": "node",
10 | "request": "launch",
11 | "name": "Debug Program",
12 | "program": "${workspaceFolder}/example/scripts-and-js.ts",
13 | "preLaunchTask": "tsc: build - ts-config.json",
14 | "outFiles": ["${workspaceFolder}/out/**/*.js"],
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Hobo.js
2 | 
3 |
4 |
5 | Welcome to Hobo. A little utility to generate html inside your js/ts code. Meant as a side-project, but after writing it I thought it might be useful to some people in some scenarios.
6 |
7 |
8 | ### Who's this for?
9 |
10 | I have no idea! I might use it some time. But if you use it, and feel like letting me know, you can either leave a star, contribute or reach out! I would be interested in knowing how it's being used, if at all!
11 |
12 | ### What does it do?
13 |
14 | Well, in essence it allows us to create html documents inside js or ts with ease. If I've not missed anything obvious, I think it's possible to generate any kind of html document. Or maybe other stuff like XML too 🤷🏻♂️
15 |
16 | You can generate any tag you want. Add **classes**, **ids**, **styles**, and **attributes**. Create **css** and add **scripts**. All of this, with a quite simple api. I know it might look weird at first, but it's quite intuitive when you gget the hang (_it's quite fast, api is quite small_).
17 |
18 | It even handles self closing tags (void elements) for you. So when creating a **img** tag, it will know it's self closing.
19 |
20 | Additionally it's almost fully typed, not only the surface, but into most css property values! IDEs will help autocomplete a lot of stuff! And is extensively tested.
21 |
22 | > NOTE: If you want a similar API but for creating apps at Runtime, take a look at my other project [Cardboard](https://github.com/nombrekeff/cardboard-js).
23 |
24 | ### Getting Started
25 | Install package:
26 |
27 | ```
28 | npm install https://github.com/nombrekeff/hobo-js
29 | npm install hobo-js
30 | ```
31 |
32 | Then you can import the package.
33 |
34 | ```ts
35 | import { builders, generate } from 'hobo-js';
36 | // Or
37 | const { builders, generate } = require('hobo-js')
38 | ```
39 |
40 | I recommend destructuring builders, for cleaner code:
41 |
42 | ```ts
43 | const { div, p, span, b, script, button, style, a, hr } = builders;
44 | ```
45 |
46 | ### Examples
47 |
48 | Check out the [`examples`](/examples) folder for a variety of examples on how to use hobo.
49 |
50 | You can check the interactive demo [here](https://nombrekeff.github.io/hobo-interactive-demo/)
51 |
52 | ### Docs
53 | You can find docs [here](https://nombrekeff.github.io/hobo-js/)
54 |
55 | ### Demo
56 |
57 | Let me show you a little sample (_I explain everything in detail below_)
58 |
59 | ```ts
60 | const myPage = doc('My Page Title');
61 |
62 | myPage.head.append(
63 | style({
64 | '.wrapper': {
65 | background: 'black',
66 | display: 'flex',
67 | alignItems: 'center',
68 | justifyContent: 'center',
69 | ':hover': {
70 | background: 'red'
71 | }
72 | },
73 | }, {/* more style objects */}),
74 | );
75 |
76 | div.attach.ac('wrapper').build(
77 | p("I'm a child of div.wrapper"),
78 | b.addStyle('color', 'aliceblue')('And so am I'),
79 | hr,
80 | a.addAttr('href', 'http://example.com').b('Click me'),
81 | button.id('button-id').b("I'm also a child"),
82 | );
83 |
84 | script.a(() => {
85 | const btn = document.querySelector('#button-id');
86 | }, () => {/* more js */});
87 |
88 | console.log(generate(myPage.doc));
89 | ```
90 |
91 | The above snippet would output the following html:
92 | ```html
93 |
94 |
95 | My Page Title
96 |
107 |
108 |
109 |
110 |
I'm a child of div.wrapper
111 |
And so am I
112 |
113 |
Click me
114 |
115 |
118 |
119 |
120 | ```
121 |
122 | #### Demo explanation
123 |
124 | ```ts
125 | const myPage = doc('My Page Title');
126 | ```
127 |
128 | First of all we create an HTML Page, by calling `doc()`. This will create an HTML, head and body tags. And returns 3 tags, `doc`, `head` and `body`. You can pass in an optional `title`, and `attachMode` arguments (_look at the [Attaching](#attaching) section for more info_).
129 |
130 | > It's not required to create a doc, you can start the document with any tag you want.
131 | > It also "attaches" the `body` tag to the hobo context. This means that you can then automatically add tags to the attached tag without having to use `.append`. I will explain further down.
132 | > * `doc(mode)`, the doc can receive an argument to change the Attach behaviour. You can specify if you want to attach to the body, head or HTML tags. It will attach to the body by default
133 |
134 | ----
135 |
136 | ```ts
137 | myPage.head.append(
138 | style({
139 | '.wrapper': {
140 | background: 'black',
141 | display: 'flex',
142 | alignItems: 'center',
143 | justifyContent: 'center',
144 | ':hover': {
145 | background: 'red'
146 | }
147 | },
148 | }, {
149 | 'div': {...}
150 | }),
151 | );
152 | ```
153 |
154 | The above code adds a style tag to the `head` tag. The style tag accepts objects with css definitions. It's typed, so intelisense will work.
155 | You can pass any number of style objects. And you can also nest like in SCSS.
156 |
157 | For example, this:
158 | ```ts
159 | '.wrapper': {
160 | background: 'blue'
161 | ':hover': {
162 | background: 'red'
163 | }
164 | }
165 | ```
166 |
167 | Will generate:
168 | ```css
169 | .wrapper { background: 'blue' }
170 | .wrapper:hover { background: 'red' }
171 | ```
172 |
173 | > Note that in this case we use `.append` as the head is not attached.
174 |
175 | ----
176 |
177 | ```ts
178 | div.a.ac('wrapper').build(
179 | p("I'm a child of div.wrapper"),
180 | b.addStyle('color', 'aliceblue')('And so am I'),
181 | hr,
182 | a.addAttr('href', 'http://example.com').b('Click me'),
183 | button.id('button-id').b("I'm also a child"),
184 | );
185 | ```
186 |
187 | In the step above step, we create the HTML that will be inside the `body`. As you can see instead of calling `.append` in the body tag like with the style.
188 | `.a` and `.attach` are used to [attach](#attaching) to the current hobo context's attached tag (_which will be the body tag in the example_)
189 |
190 | Then we set the tag's class name by calling `.ac` (you can also use `.addClass()`), this will set the class wrapper to the div (``)
191 |
192 | After that, we build the tag by calling `.b` (or `.build()`, or you can also call the builder `div()`), and pass in a list of children.
193 |
194 | Hobo uses the builder pattern to ease the creation of tags. A tag can be built by, either calling the builder directly:
195 | ```ts
196 | p("I'm a child of div.wrapper");
197 | ```
198 | or by calling the `.b` method:
199 | ```ts
200 | b.build('And so am I'),
201 | ```
202 |
203 | > NOTE that it's not required to build the tag if you don't need to pass children to it:
204 | > ```ts
205 | > div(
206 | > hr,
207 | > div.addClass('white-box'),
208 | > )
209 | > ```
210 |
211 | > **NOTE** Each time you modify the builder it returns a new TagBuilder instance.
212 | > So you can't assign it and then modify it, you need to chain.
213 | > This is done so Hobo can generate new tag builders for each tag without needing to be a function.
214 | >
215 | > This does not work:
216 | > ```ts
217 | > const tag = div.ac('cl'); // .ac is shorthand for addClass
218 | > tag.append(p()); // Will not affect `tag`
219 | > ```
220 |
221 | > Instead use chaining:
222 | > ```ts
223 | > const tag = div.ac('cl').append(p());
224 | > ```
225 |
226 | You can set any attribute by using `.aa`, or `.am`:
227 | ```ts
228 | a.addAttr('href', 'http://example.com');
229 | a.aa('href', 'http://example.com');
230 | a.setAttr({ 'href': 'http://example.com' });
231 | a.sa({ 'href': 'http://example.com' });
232 | ```
233 |
234 | ----
235 |
236 | ```ts
237 | p.addStyle('color', 'aliceblue');
238 | p.as('color', 'aliceblue');
239 | p.setStyle({ 'color': 'aliceblue' });
240 | p.ss({ 'color': 'aliceblue' });
241 | ```
242 | Tags can also have inline styles. You can add a single style using the add style (`.as`) method, or add multiple at once using the set styles (`.ss`) method.
243 |
244 | ----
245 |
246 | ```ts
247 | script.a(() => {
248 | const btn = document.querySelector('#button-id');
249 | }, () => {
250 | // More JS
251 | });
252 | ```
253 |
254 | Creates a `script` tag. Anything inside the function will be inserted into the generated script.
255 | The script accepts a list of functions. You will also have complete typing for dom.
256 |
257 | ----
258 |
259 | ```ts
260 | console.log(generate(myPage.doc));
261 | ```
262 |
263 | Finally, generate the html. `generate` returns a string. It's up to you to handle it from here.
264 |
265 | > NOTE that generate must receive the root tag you want to generate.
266 | > In this example we pass in `myPage.doc` to generate the whole page.
267 | >
268 | > But you can generate any tag you want:
269 | > ```ts
270 | > generate(div(p('Hello'), p('world')));
271 | > ```
272 |
273 |
274 | ### Attaching
275 |
276 | by calling `attach` on a tag, it makes it so that you don't need to manually add children to a tag:
277 |
278 | ```ts
279 | const root = div.build("I'm the root tag");
280 |
281 | attach(root);
282 | div.a;
283 | div.attach;
284 | p.attach;
285 | ```
286 |
287 | > Any tag that calls `.a` or `.attach` will be added as children of the root div.
288 |
289 | You can also attach multiple times:
290 | ```ts
291 | const root = div.build("I'm the root tag");
292 |
293 | attach(root);
294 | div.a;
295 | const child = div.attach.addClass('child-wrapper');
296 |
297 | attach(child);
298 | p.a("I'm a child of child-wrapper");
299 | p.a("And so am I");
300 | detach();
301 |
302 | p.a("I'm now a child of root div again");
303 | detach();
304 |
305 | p.a("I'm now not attached as there are no attached tags");
306 | ```
307 |
308 | By calling attach the last tag is attached to, then by calling detach, the previously attached tag is now attached. Note that if you call attach and there's only 1 tag attached, it will detach that also. So consequent tags that try to attach will not attach as there's no tag attached.
309 |
310 | When calling `doc()`, it will automatically attach to the body. Although you can specify the tag you want to attach to by passing the attachMode argument.
311 |
--------------------------------------------------------------------------------
/dist/attributes.js:
--------------------------------------------------------------------------------
1 | import { ClassName } from './class-name';
2 | import { StyleSet } from './style';
3 | /**
4 | * Represents a tag's attribute set.
5 | */
6 | export class AttrSet {
7 | constructor() {
8 | this.className = new ClassName();
9 | this.style = new StyleSet();
10 | this.additionalAttributes = {};
11 | }
12 | copy() {
13 | const newSet = new AttrSet();
14 | newSet.className = this.className.copy();
15 | newSet.id = this.id;
16 | newSet.style = this.style.copy();
17 | newSet.additionalAttributes = Object.assign({}, this.additionalAttributes);
18 | return newSet;
19 | }
20 | /** Set single attribute */
21 | set(key, value) {
22 | this.additionalAttributes[key] = value;
23 | return this;
24 | }
25 | /** Remove attributes */
26 | remove(...attrs) {
27 | for (const cn of attrs) {
28 | delete this.additionalAttributes[cn];
29 | }
30 | return this;
31 | }
32 | /** Check if an attribute is set */
33 | has(key) {
34 | return key in this.additionalAttributes;
35 | }
36 | }
37 | //# sourceMappingURL=attributes.js.map
--------------------------------------------------------------------------------
/dist/attributes.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;GAEG;AACH,MAAM,OAAO,OAAO;IAApB;QACE,cAAS,GAAc,IAAI,SAAS,EAAE,CAAC;QAEvC,UAAK,GAAa,IAAI,QAAQ,EAAE,CAAC;QAEjC,yBAAoB,GAA8B,EAAE,CAAC;IA6BvD,CAAC;IA3BC,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,CAAC,oBAAoB,qBAAQ,IAAI,CAAC,oBAAoB,CAAE,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,2BAA2B;IAC3B,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wBAAwB;IACxB,MAAM,CAAC,GAAG,KAAe;QACvB,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE;YACtB,OAAO,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;SACtC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mCAAmC;IACnC,GAAG,CAAC,GAAW;QACb,OAAO,GAAG,IAAI,IAAI,CAAC,oBAAoB,CAAC;IAC1C,CAAC;CACF"}
--------------------------------------------------------------------------------
/dist/class-name.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents a tag's class list.
3 | */
4 | export class ClassName {
5 | constructor(classNames = []) {
6 | this.classNames = [];
7 | this.classNames = classNames;
8 | }
9 | copy() {
10 | const newClassName = new ClassName();
11 | newClassName.classNames = [...this.classNames];
12 | return newClassName;
13 | }
14 | /**
15 | * Returns a string of all the class names separated by spaces.
16 | */
17 | raw() {
18 | return this.classNames.join(' ');
19 | }
20 | /** Add one or more class names */
21 | add(...classNames) {
22 | for (const cn of classNames) {
23 | if (!this.has(cn)) {
24 | this.classNames.push(cn);
25 | }
26 | }
27 | return this;
28 | }
29 | /** Remove one or more class names */
30 | remove(...classNames) {
31 | for (const cn of classNames) {
32 | if (!this.has(cn))
33 | return this;
34 | const index = this.classNames.indexOf(cn);
35 | this.classNames.splice(index, 1);
36 | }
37 | return this;
38 | }
39 | /** Check if a class name is present. */
40 | has(str) {
41 | return this.classNames.includes(str);
42 | }
43 | }
44 | //# sourceMappingURL=class-name.js.map
--------------------------------------------------------------------------------
/dist/class-name.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"class-name.js","sourceRoot":"","sources":["../src/class-name.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,SAAS;IAGpB,YAAY,aAAuB,EAAE;QAFrC,eAAU,GAAa,EAAE,CAAC;QAGxB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,IAAI;QACF,MAAM,YAAY,GAAG,IAAI,SAAS,EAAE,CAAC;QACrC,YAAY,CAAC,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/C,OAAO,YAAY,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,GAAG;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,kCAAkC;IAClC,GAAG,CAAC,GAAG,UAAoB;QACzB,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBACjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC1B;SACF;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qCAAqC;IACrC,MAAM,CAAC,GAAG,UAAoB;QAC5B,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;YAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;SAClC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wCAAwC;IACxC,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;CACF"}
--------------------------------------------------------------------------------
/dist/custom-types/colors.js:
--------------------------------------------------------------------------------
1 | export {};
2 | //# sourceMappingURL=colors.js.map
--------------------------------------------------------------------------------
/dist/custom-types/colors.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/custom-types/colors.ts"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/dist/custom-types/css-properties.js:
--------------------------------------------------------------------------------
1 | export {};
2 | //# sourceMappingURL=css-properties.js.map
--------------------------------------------------------------------------------
/dist/custom-types/css-properties.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"css-properties.js","sourceRoot":"","sources":["../../src/custom-types/css-properties.ts"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/dist/custom-types/css-property-values.js:
--------------------------------------------------------------------------------
1 | export {};
2 | //# sourceMappingURL=css-property-values.js.map
--------------------------------------------------------------------------------
/dist/custom-types/css-property-values.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"css-property-values.js","sourceRoot":"","sources":["../../src/custom-types/css-property-values.ts"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/dist/custom-types/tag-names.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @export
3 | * List of all known self-closing HTML tags
4 | */
5 | export const selfClosingTags = [
6 | 'area',
7 | 'base',
8 | 'br',
9 | 'col',
10 | 'embed',
11 | 'hr',
12 | 'img',
13 | 'input',
14 | 'link',
15 | 'meta',
16 | 'param',
17 | 'source',
18 | 'track',
19 | 'wbr',
20 | ];
21 | /** List of all known closing HTML tags */
22 | export const closingTags = [
23 | 'a',
24 | 'abbr',
25 | 'acronym',
26 | 'address',
27 | 'article',
28 | 'aside',
29 | 'audio',
30 | 'b',
31 | 'basefont',
32 | 'bdi',
33 | 'bdo',
34 | 'big',
35 | 'blockquote',
36 | 'body',
37 | 'button',
38 | 'canvas',
39 | 'caption',
40 | 'center',
41 | 'cite',
42 | 'code',
43 | 'colgroup',
44 | 'data',
45 | 'datalist',
46 | 'dd',
47 | 'del',
48 | 'details',
49 | 'dfn',
50 | 'dialog',
51 | 'div',
52 | 'dl',
53 | 'dt',
54 | 'em',
55 | 'fieldset',
56 | 'figcaption',
57 | 'figure',
58 | 'footer',
59 | 'form',
60 | 'h1',
61 | 'h2',
62 | 'h3',
63 | 'h4',
64 | 'h5',
65 | 'h6',
66 | 'head',
67 | 'header',
68 | 'html',
69 | 'i',
70 | 'iframe',
71 | 'ins',
72 | 'kbd',
73 | 'label',
74 | 'legend',
75 | 'li',
76 | 'main',
77 | 'map',
78 | 'mark',
79 | 'meter',
80 | 'nav',
81 | 'noscript',
82 | 'object',
83 | 'ol',
84 | 'optgroup',
85 | 'option',
86 | 'output',
87 | 'p',
88 | 'picture',
89 | 'pre',
90 | 'progress',
91 | 'q',
92 | 'rp',
93 | 'rt',
94 | 'ruby',
95 | 's',
96 | 'samp',
97 | 'script',
98 | 'section',
99 | 'select',
100 | 'small',
101 | 'span',
102 | 'strong',
103 | 'style',
104 | 'sub',
105 | 'summary',
106 | 'sup',
107 | 'svg',
108 | 'table',
109 | 'tbody',
110 | 'td',
111 | 'template',
112 | 'textarea',
113 | 'tfoot',
114 | 'th',
115 | 'thead',
116 | 'time',
117 | 'title',
118 | 'tr',
119 | 'u',
120 | 'ul',
121 | 'var',
122 | 'video',
123 | ];
124 | /** List of all known HTML tags */
125 | export const allKnownTags = [
126 | 'area',
127 | 'base',
128 | 'br',
129 | 'col',
130 | 'embed',
131 | 'hr',
132 | 'img',
133 | 'input',
134 | 'link',
135 | 'meta',
136 | 'param',
137 | 'source',
138 | 'track',
139 | 'wbr',
140 | 'a',
141 | 'abbr',
142 | 'acronym',
143 | 'address',
144 | 'article',
145 | 'aside',
146 | 'audio',
147 | 'b',
148 | 'basefont',
149 | 'bdi',
150 | 'bdo',
151 | 'big',
152 | 'blockquote',
153 | 'body',
154 | 'button',
155 | 'canvas',
156 | 'caption',
157 | 'center',
158 | 'cite',
159 | 'code',
160 | 'colgroup',
161 | 'data',
162 | 'datalist',
163 | 'dd',
164 | 'del',
165 | 'details',
166 | 'dfn',
167 | 'dialog',
168 | 'div',
169 | 'dl',
170 | 'dt',
171 | 'em',
172 | 'fieldset',
173 | 'figcaption',
174 | 'figure',
175 | 'footer',
176 | 'form',
177 | 'h1',
178 | 'h2',
179 | 'h3',
180 | 'h4',
181 | 'h5',
182 | 'h6',
183 | 'head',
184 | 'header',
185 | 'html',
186 | 'i',
187 | 'iframe',
188 | 'ins',
189 | 'kbd',
190 | 'label',
191 | 'legend',
192 | 'li',
193 | 'main',
194 | 'map',
195 | 'mark',
196 | 'meter',
197 | 'nav',
198 | 'noscript',
199 | 'object',
200 | 'ol',
201 | 'optgroup',
202 | 'option',
203 | 'output',
204 | 'p',
205 | 'picture',
206 | 'pre',
207 | 'progress',
208 | 'q',
209 | 'rp',
210 | 'rt',
211 | 'ruby',
212 | 's',
213 | 'samp',
214 | 'script',
215 | 'section',
216 | 'select',
217 | 'small',
218 | 'span',
219 | 'strong',
220 | 'style',
221 | 'sub',
222 | 'summary',
223 | 'sup',
224 | 'svg',
225 | 'table',
226 | 'tbody',
227 | 'td',
228 | 'template',
229 | 'textarea',
230 | 'tfoot',
231 | 'th',
232 | 'thead',
233 | 'time',
234 | 'title',
235 | 'tr',
236 | 'u',
237 | 'ul',
238 | 'var',
239 | 'video',
240 | ];
241 | export const storableTags = ['style', 'script'];
242 | //# sourceMappingURL=tag-names.js.map
--------------------------------------------------------------------------------
/dist/custom-types/tag-names.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"tag-names.js","sourceRoot":"","sources":["../../src/custom-types/tag-names.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/custom-types/types.js:
--------------------------------------------------------------------------------
1 | export var AttachMode;
2 | (function (AttachMode) {
3 | AttachMode[AttachMode["none"] = 0] = "none";
4 | AttachMode[AttachMode["body"] = 1] = "body";
5 | AttachMode[AttachMode["html"] = 2] = "html";
6 | AttachMode[AttachMode["head"] = 3] = "head";
7 | })(AttachMode || (AttachMode = {}));
8 | //# sourceMappingURL=types.js.map
--------------------------------------------------------------------------------
/dist/custom-types/types.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/custom-types/types.ts"],"names":[],"mappings":"AAWA,MAAM,CAAN,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,2CAAI,CAAA;IACJ,2CAAI,CAAA;IACJ,2CAAI,CAAA;IACJ,2CAAI,CAAA;AACN,CAAC,EALW,UAAU,KAAV,UAAU,QAKrB"}
--------------------------------------------------------------------------------
/dist/generation/css-generator.js:
--------------------------------------------------------------------------------
1 | import { camelToDash, isObject } from '../util';
2 | export class CssGenerator {
3 | generateCss(styleSheet) {
4 | let stylesheets = styleSheet instanceof Array ? styleSheet : [styleSheet];
5 | let generatedCss = '';
6 | for (const sheet of stylesheets) {
7 | for (const key in sheet) {
8 | generatedCss += this.generateBlock(key, sheet[key]);
9 | }
10 | }
11 | return generatedCss;
12 | }
13 | generateBlock(selector, style) {
14 | let blocks = this.generateBlockContent(selector, style);
15 | return blocks.join('');
16 | }
17 | generateBlockContent(selector, style) {
18 | let inside = '';
19 | let blocks = [];
20 | for (const key in style) {
21 | if (isObject(style[key])) {
22 | blocks.push(this.generateBlockContent(selector + key, style[key]));
23 | }
24 | else if (style[key]) {
25 | inside += this.generateStyle(key, style[key]);
26 | }
27 | }
28 | blocks.unshift(`${selector}{${inside}}`);
29 | return blocks;
30 | }
31 | generateInline(style) {
32 | let inside = '';
33 | for (const key in style) {
34 | if (style[key]) {
35 | inside += this.generateStyle(key, style[key]);
36 | }
37 | }
38 | return inside;
39 | }
40 | generateStyle(name, value) {
41 | return `${camelToDash(name)}:${value};`;
42 | }
43 | }
44 | //# sourceMappingURL=css-generator.js.map
--------------------------------------------------------------------------------
/dist/generation/css-generator.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"css-generator.js","sourceRoot":"","sources":["../../src/generation/css-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhD,MAAM,OAAO,YAAY;IACvB,WAAW,CAAC,UAAmF;QAC7F,IAAI,WAAW,GAAG,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC1E,IAAI,YAAY,GAAG,EAAE,CAAC;QAEtB,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE;YAC/B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE;gBACvB,YAAY,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;aACrD;SACF;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,aAAa,CAAC,QAAgB,EAAE,KAAqB;QACnD,IAAI,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACxD,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,oBAAoB,CAAC,QAAgB,EAAE,KAAqB;QAC1D,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE;YACvB,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;gBACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,GAAG,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aACpE;iBACI,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;gBACnB,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAW,CAAC,CAAC;aACzD;SACF;QAED,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC;QAEzC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,cAAc,CAAC,KAAe;QAC5B,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE;YACvB,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;gBACd,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAW,CAAC,CAAC;aACzD;SACF;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,aAAa,CAAC,IAAY,EAAE,KAAa;QACvC,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;IAC1C,CAAC;CACF"}
--------------------------------------------------------------------------------
/dist/generation/html-generator.js:
--------------------------------------------------------------------------------
1 | import { Tag } from '../tag';
2 | import { CssGenerator } from './css-generator';
3 | import { justFnBody } from '../util';
4 | import { TagBuilder } from '../tag-builder';
5 | export class HtmlGenerator {
6 | constructor() {
7 | this.cssGenerator = new CssGenerator();
8 | this.beautifyCss = true;
9 | }
10 | /** Generate html from the tag provided */
11 | generateHtml(rootTag) {
12 | let generatedHtml = this._generateTag(rootTag);
13 | return generatedHtml;
14 | }
15 | _generateTag(tag) {
16 | if (tag.tagName == 'style') {
17 | return this._createTag(tag, this.cssGenerator.generateCss(tag._meta.storage));
18 | }
19 | if (tag.tagName == 'script') {
20 | return this._createTag(tag, this._generateScriptContent(tag._meta.storage));
21 | }
22 | let inside = '';
23 | for (const child of tag.children) {
24 | let effectiveChild = child;
25 | if (child instanceof TagBuilder) {
26 | effectiveChild = child.b();
27 | }
28 | if (effectiveChild instanceof Tag) {
29 | inside += this._generateTag(effectiveChild);
30 | }
31 | else {
32 | inside += child;
33 | }
34 | }
35 | return this._createTag(tag, inside);
36 | }
37 | _createTag(tag, inside) {
38 | const attributesString = this._generateAttributeString(tag);
39 | let openTag = [tag.tagName, attributesString].filter((n) => n).join(' ');
40 | if (tag._meta.selfClosing) {
41 | return `<${openTag}/>`;
42 | }
43 | return `<${openTag}>${inside}${tag.tagName}>`;
44 | }
45 | _generateAttributeString(tag) {
46 | let attributesString = '';
47 | if (tag.attr.id) {
48 | attributesString += this._attr('id', tag.attr.id);
49 | }
50 | attributesString += this._attr('class', tag.attr.className.raw());
51 | attributesString += this._generateInlineStyle(tag);
52 | for (const key in tag.attr.additionalAttributes) {
53 | attributesString += this._attr(key, tag.attr.additionalAttributes[key]);
54 | }
55 | return attributesString;
56 | }
57 | _generateInlineStyle(tag) {
58 | let styleContent = this.cssGenerator.generateInline(tag.attr.style.styles);
59 | return this._attr('style', styleContent);
60 | }
61 | _generateScriptContent(storage) {
62 | let scriptContent = '';
63 | if (storage instanceof Function) {
64 | scriptContent += justFnBody(storage);
65 | }
66 | else if (storage instanceof Array) {
67 | for (const fn of storage) {
68 | scriptContent += this._generateScriptContent(fn);
69 | }
70 | }
71 | return scriptContent;
72 | }
73 | _attr(name, value) {
74 | if (!value)
75 | return '';
76 | return `${name}="${value}"`;
77 | }
78 | }
79 | //# sourceMappingURL=html-generator.js.map
--------------------------------------------------------------------------------
/dist/generation/html-generator.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"html-generator.js","sourceRoot":"","sources":["../../src/generation/html-generator.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/hobo.js:
--------------------------------------------------------------------------------
1 | export { Tag } from './tag';
2 | import { HtmlGenerator } from './generation/html-generator';
3 | import { AttachMode } from './custom-types/types';
4 | import { builders as tagBuilders } from './tag-builder';
5 | export { TagBuilder } from './tag-builder';
6 | export let _context = {
7 | attachedTag: null,
8 | attachedTagStack: [],
9 | globalStuff: [],
10 | };
11 | /**
12 | * Creates an HTML document, with a head and body tags.
13 | * You can pass in the AttachMode to attach to different tags.
14 | */
15 | export function doc(pageTitle = 'New Hobo Document', mode = AttachMode.body) {
16 | const dhead = builders.head
17 | .aa('lang', 'en')
18 | .build(builders.meta.addAttr('charset', 'UTF-8'), builders.meta.setAttr({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }), builders.title(pageTitle));
19 | const dbody = builders.body.build();
20 | const doc = builders.html.build(dhead, dbody);
21 | switch (mode) {
22 | case AttachMode.html:
23 | attach(doc);
24 | break;
25 | case AttachMode.head:
26 | attach(doc.findByTagName('head')); // We know there is a head tag
27 | break;
28 | case AttachMode.body:
29 | attach(doc.findByTagName('body')); // We know there is a body tag
30 | break;
31 | case AttachMode.none:
32 | break;
33 | }
34 | return { doc, head: dhead, body: dbody };
35 | }
36 | /**
37 | * Attach a given tag to the current context.
38 | * When you attach a tag, this tag will be the "root" for any tag created without a parent.
39 | *
40 | * * If there is not attached tag, it will be attached
41 | * * If there is already a tag attached, it will store the previous tag
42 | * and will set the new tag as the root. After finishing using the tag as the root, you can call `@detach`
43 | * and return to the previous root tag.
44 | *
45 | * This is used to remove clutter and reduntancies when creating hobo docs.
46 | * Like this:
47 | *
48 | * @example
49 | * Simple example with only 1 attach
50 | * ```ts
51 | * const parent = doc();
52 | * attach(parent);
53 | *
54 | * div();
55 | * p();
56 | * ```
57 | * The `div` and `p` tags will be automatically added as child of `parentDiv`
58 | *
59 | * @example
60 | * Example attaching and detaching
61 | * ```ts
62 | * const parent = doc();
63 | * attach(parent);
64 | *
65 | * div();
66 | * p();
67 | * let d1 = div();
68 | * attach(d1);
69 | * // All the p tags will be added to `d1`
70 | * p();
71 | * p();
72 | * p();
73 | * // remember to call detach when you want to go back to the previous root tag
74 | * detach();
75 | * ```
76 | *
77 | * @param {Tag} tag
78 | */
79 | export function attach(tag) {
80 | if (_context.attachedTag) {
81 | _context.attachedTagStack.push(_context.attachedTag);
82 | }
83 | _context.attachedTag = tag;
84 | }
85 | /**
86 | * Detached the currently attached tag, and pops back to the previously attached tag.
87 | * If there are no stored tags, it will clear the attached tag.
88 | * You will need to handle the consecuent created tags.
89 | */
90 | export function detach() {
91 | if (_context.attachedTagStack.length > 0) {
92 | _context.attachedTag = _context.attachedTagStack.pop();
93 | }
94 | else {
95 | _context.attachedTag = null;
96 | }
97 | }
98 | function makeAttachable(builder) {
99 | const attachFn = () => {
100 | if (_context.attachedTag) {
101 | return builder.p(_context.attachedTag);
102 | }
103 | return builder;
104 | };
105 | Object.defineProperty(builder, 'a', {
106 | get: attachFn,
107 | });
108 | Object.defineProperty(builder, 'attach', {
109 | get: attachFn,
110 | });
111 | return builder;
112 | }
113 | const exportedTagBuilders = {};
114 | for (let key in tagBuilders) {
115 | exportedTagBuilders[key] = makeAttachable(tagBuilders[key]);
116 | }
117 | const _generator = new HtmlGenerator();
118 | /** Converts's the Tag tree into a html string */
119 | export function generate(root) {
120 | return _generator.generateHtml(root);
121 | }
122 | /**
123 | * TagBuilders for each known tag. From `div` to `acronym`
124 | */
125 | export const builders = exportedTagBuilders;
126 | //# sourceMappingURL=hobo.js.map
--------------------------------------------------------------------------------
/dist/hobo.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"hobo.js","sourceRoot":"","sources":["../src/hobo.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/hobo.min.mjs:
--------------------------------------------------------------------------------
1 | class t{constructor(t=[]){this.classNames=[],this.classNames=t}copy(){const e=new t;return e.classNames=[...this.classNames],e}raw(){return this.classNames.join(" ")}add(...t){for(const e of t)this.has(e)||this.classNames.push(e);return this}remove(...t){for(const e of t){if(!this.has(e))return this;const t=this.classNames.indexOf(e);this.classNames.splice(t,1)}return this}has(t){return this.classNames.includes(t)}}class e{constructor(){this.styles={}}copy(){const t=new e;return t.styles=Object.assign({},this.styles),t}set(t,e){return this.styles[t]=e,this}remove(...t){for(const e of t)delete this.styles[e];return this}has(t){return t in this.styles}}class s{constructor(){this.className=new t,this.style=new e,this.additionalAttributes={}}copy(){const t=new s;return t.className=this.className.copy(),t.id=this.id,t.style=this.style.copy(),t.additionalAttributes=Object.assign({},this.additionalAttributes),t}set(t,e){return this.additionalAttributes[t]=e,this}remove(...t){for(const e of t)delete this.additionalAttributes[e];return this}has(t){return t in this.additionalAttributes}}const r=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"],a=["style","script"];class n extends Function{constructor(){super("...args","return this.__self__.__call__(...args)");var t=this.bind(this);return this.__self__=t,t}__call__(...t){}}class i extends n{get className(){return this.attr.className}get tagId(){return this.attr.id}constructor(t,...e){super(),this.children=[],this.attr=new s,this._meta={selfClosing:!1,storesChildren:!1,storage:!1},this.setTagName(t),this.children.push(...e)}copy(){const t=new i(this.tagName,...this.children);return t.attr=this.attr.copy(),t._parent=this._parent,t._meta=Object.assign(Object.assign({},this._meta),t._meta),t}setTagName(t){return this.tagName=this.sanitizeTagName(t),this.validateTagName(this.tagName),this._meta=Object.assign(Object.assign({},this._meta),this.getMetaForTag(this.tagName)),this}b(...t){return this.build(...t)}build(...t){return this.__call__(...t)}__call__(...t){let e=[...this.children,...t];this._meta.storesChildren&&(this._meta.storage=t,e=[]);const s=new d(this.tagName,e,this.attr,this._meta);return this._parent&&this._parent.children.push(s),s}get a(){return this.copy()}get attach(){return this.copy()}p(t){const e=this.copy();return e._parent=t,e}id(t){const e=this.copy();return e.attr.id=t,e}text(t){const e=this.copy();return e.children=[t],e}append(...t){if(this._meta.selfClosing)return this;const e=this.copy();return e.children.push(...t.map((t=>t instanceof i?t.b():t))),e}setChildren(t){const e=this.copy();return e.children=t,e}store(t){const e=this.copy();return e._meta.storage=t,e}m(t){return this.mod(t)}mod(t){const e=this.copy();return t(e),e}mc(t){return this.modClass(t)}modClass(t){return this.copy().m((e=>t(e.className)))}ac(...t){return this.addClass(...t)}addClass(...t){const e=this.copy();return e.className.add(...t),e}rc(...t){return this.rmClass(...t)}rmClass(...t){const e=this.copy();return e.className.remove(...t),e}aa(t,e){return this.addAttr(t,e)}addAttr(t,e){const s=this.copy();return s.attr.set(t,e),s}sa(t){return this.setAttr(t)}setAttr(t){const e=this.copy();return e.attr.additionalAttributes=Object.assign(Object.assign({},e.attr.additionalAttributes),t),e}ra(...t){return this.rmAttr(...t)}rmAttr(...t){const e=this.copy();return e.attr.remove(...t),e}as(t,e){return this.addStyle(t,e)}addStyle(t,e){const s=this.copy();return s.attr.style.set(t,e),s}ss(t){return this.setStyles(t)}setStyles(t){const e=this.copy();return e.attr.style.styles=Object.assign(Object.assign({},e.attr.style.styles),t),e}rs(...t){return this.rmStyle(...t)}rmStyle(...t){const e=this.copy();return e.attr.style.remove(...t),e}getMetaForTag(t){return{selfClosing:this.isSelfClosingTag(t),storesChildren:this.isStorableTag(t),storage:null}}isSelfClosingTag(t){return r.includes(t)}isStorableTag(t){return a.includes(t)}validateTagName(t){if(!/[a-zA-Z_][a-z-A-Z0-9_]*/.test(t))throw new Error(`Invalid tag name "${t}"`)}sanitizeTagName(t){return t.replace(/[^\w\d-_]/,"")}}function o(t,...e){return new i(t,...e)}const c=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr","a","abbr","acronym","address","article","aside","audio","b","basefont","bdi","bdo","big","blockquote","body","button","canvas","caption","center","cite","code","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","html","i","iframe","ins","kbd","label","legend","li","main","map","mark","meter","nav","noscript","object","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","span","strong","style","sub","summary","sup","svg","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","u","ul","var","video"];let l={tag:o};for(let t of c)l[t]=o(t);const h=l;class d{get className(){return this.attr.className}get tagId(){return this.attr.id}constructor(t,e,r,a){this.children=[],this.attr=new s,this._meta={selfClosing:!1,storesChildren:!1,storage:!1},this.tagName=t,this.children=e,this.attr=r,this._meta=a}append(t){t instanceof i&&(t=t.b()),this.children.push(t)}findByTagName(t){return this.findOneBy((e=>e.tagName==t))}findOneBy(t){const e=[];for(e.push(this);e.length>0;){let s=e.pop();if(t(s))return s;if(s.children&&s.children.length)for(let t=0;t`-${t.toLowerCase()}`))}:${e};`;var s}}var g;!function(t){t[t.none=0]="none",t[t.body=1]="body",t[t.html=2]="html",t[t.head=3]="head"}(g||(g={}));let m={attachedTag:null,attachedTagStack:[],globalStuff:[]};function p(t="New Hobo Document",e=g.body){const s=C.head.aa("lang","en").build(C.meta.addAttr("charset","UTF-8"),C.meta.setAttr({name:"viewport",content:"width=device-width, initial-scale=1.0"}),C.title(t)),r=C.body.build(),a=C.html.build(s,r);switch(e){case g.html:f(a);break;case g.head:f(a.findByTagName("head"));break;case g.body:f(a.findByTagName("body"));case g.none:}return{doc:a,head:s,body:r}}function f(t){m.attachedTag&&m.attachedTagStack.push(m.attachedTag),m.attachedTag=t}function y(){m.attachedTagStack.length>0?m.attachedTag=m.attachedTagStack.pop():m.attachedTag=null}function b(t){const e=()=>m.attachedTag?t.p(m.attachedTag):t;return Object.defineProperty(t,"a",{get:e}),Object.defineProperty(t,"attach",{get:e}),t}const _={};for(let t in h)_[t]=b(h[t]);const N=new class{constructor(){this.cssGenerator=new u,this.beautifyCss=!0}generateHtml(t){return this._generateTag(t)}_generateTag(t){if("style"==t.tagName)return this._createTag(t,this.cssGenerator.generateCss(t._meta.storage));if("script"==t.tagName)return this._createTag(t,this._generateScriptContent(t._meta.storage));let e="";for(const s of t.children){let t=s;s instanceof i&&(t=s.b()),e+=t instanceof d?this._generateTag(t):s}return this._createTag(t,e)}_createTag(t,e){const s=this._generateAttributeString(t);let r=[t.tagName,s].filter((t=>t)).join(" ");return t._meta.selfClosing?`<${r}/>`:`<${r}>${e}${t.tagName}>`}_generateAttributeString(t){let e="";t.attr.id&&(e+=this._attr("id",t.attr.id)),e+=this._attr("class",t.attr.className.raw()),e+=this._generateInlineStyle(t);for(const s in t.attr.additionalAttributes)e+=this._attr(s,t.attr.additionalAttributes[s]);return e}_generateInlineStyle(t){let e=this.cssGenerator.generateInline(t.attr.style.styles);return this._attr("style",e)}_generateScriptContent(t){let e="";if(t instanceof Function)e+=function(t){let e=t.toString();return e=e.replace(/^(.*{)/,""),e=e.replace(/}$/,""),e=e.replace(/^\(.*\)\s?=>\s?{/,""),e.trim()}(t);else if(t instanceof Array)for(const s of t)e+=this._generateScriptContent(s);return e}_attr(t,e){return e?`${t}="${e}"`:""}};function T(t){return N.generateHtml(t)}const C=_;export{d as Tag,i as TagBuilder,m as _context,f as attach,C as builders,y as detach,p as doc,T as generate};
--------------------------------------------------------------------------------
/dist/hobo.min.mjs.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nombrekeff/hobo-js/1cd54a3fe83bbd15820fb2e05fb6736a35efba6b/dist/hobo.min.mjs.gz
--------------------------------------------------------------------------------
/dist/hobo.umd.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).sayHello={})}(this,(function(t){"use strict";class e{constructor(t=[]){this.classNames=[],this.classNames=t}copy(){const t=new e;return t.classNames=[...this.classNames],t}raw(){return this.classNames.join(" ")}add(...t){for(const e of t)this.has(e)||this.classNames.push(e);return this}remove(...t){for(const e of t){if(!this.has(e))return this;const t=this.classNames.indexOf(e);this.classNames.splice(t,1)}return this}has(t){return this.classNames.includes(t)}}class s{constructor(){this.styles={}}copy(){const t=new s;return t.styles=Object.assign({},this.styles),t}set(t,e){return this.styles[t]=e,this}remove(...t){for(const e of t)delete this.styles[e];return this}has(t){return t in this.styles}}class a{constructor(){this.className=new e,this.style=new s,this.additionalAttributes={}}copy(){const t=new a;return t.className=this.className.copy(),t.id=this.id,t.style=this.style.copy(),t.additionalAttributes=Object.assign({},this.additionalAttributes),t}set(t,e){return this.additionalAttributes[t]=e,this}remove(...t){for(const e of t)delete this.additionalAttributes[e];return this}has(t){return t in this.additionalAttributes}}const r=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"],n=["style","script"];class i extends Function{constructor(){super("...args","return this.__self__.__call__(...args)");var t=this.bind(this);return this.__self__=t,t}__call__(...t){}}class o extends i{get className(){return this.attr.className}get tagId(){return this.attr.id}constructor(t,...e){super(),this.children=[],this.attr=new a,this._meta={selfClosing:!1,storesChildren:!1,storage:!1},this.setTagName(t),this.children.push(...e)}copy(){const t=new o(this.tagName,...this.children);return t.attr=this.attr.copy(),t._parent=this._parent,t._meta=Object.assign(Object.assign({},this._meta),t._meta),t}setTagName(t){return this.tagName=this.sanitizeTagName(t),this.validateTagName(this.tagName),this._meta=Object.assign(Object.assign({},this._meta),this.getMetaForTag(this.tagName)),this}b(...t){return this.build(...t)}build(...t){return this.__call__(...t)}__call__(...t){let e=[...this.children,...t];this._meta.storesChildren&&(this._meta.storage=t,e=[]);const s=new u(this.tagName,e,this.attr,this._meta);return this._parent&&this._parent.children.push(s),s}get a(){return this.copy()}get attach(){return this.copy()}p(t){const e=this.copy();return e._parent=t,e}id(t){const e=this.copy();return e.attr.id=t,e}text(t){const e=this.copy();return e.children=[t],e}append(...t){if(this._meta.selfClosing)return this;const e=this.copy();return e.children.push(...t.map((t=>t instanceof o?t.b():t))),e}setChildren(t){const e=this.copy();return e.children=t,e}store(t){const e=this.copy();return e._meta.storage=t,e}m(t){return this.mod(t)}mod(t){const e=this.copy();return t(e),e}mc(t){return this.modClass(t)}modClass(t){return this.copy().m((e=>t(e.className)))}ac(...t){return this.addClass(...t)}addClass(...t){const e=this.copy();return e.className.add(...t),e}rc(...t){return this.rmClass(...t)}rmClass(...t){const e=this.copy();return e.className.remove(...t),e}aa(t,e){return this.addAttr(t,e)}addAttr(t,e){const s=this.copy();return s.attr.set(t,e),s}sa(t){return this.setAttr(t)}setAttr(t){const e=this.copy();return e.attr.additionalAttributes=Object.assign(Object.assign({},e.attr.additionalAttributes),t),e}ra(...t){return this.rmAttr(...t)}rmAttr(...t){const e=this.copy();return e.attr.remove(...t),e}as(t,e){return this.addStyle(t,e)}addStyle(t,e){const s=this.copy();return s.attr.style.set(t,e),s}ss(t){return this.setStyles(t)}setStyles(t){const e=this.copy();return e.attr.style.styles=Object.assign(Object.assign({},e.attr.style.styles),t),e}rs(...t){return this.rmStyle(...t)}rmStyle(...t){const e=this.copy();return e.attr.style.remove(...t),e}getMetaForTag(t){return{selfClosing:this.isSelfClosingTag(t),storesChildren:this.isStorableTag(t),storage:null}}isSelfClosingTag(t){return r.includes(t)}isStorableTag(t){return n.includes(t)}validateTagName(t){if(!/[a-zA-Z_][a-z-A-Z0-9_]*/.test(t))throw new Error(`Invalid tag name "${t}"`)}sanitizeTagName(t){return t.replace(/[^\w\d-_]/,"")}}function c(t,...e){return new o(t,...e)}const l=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr","a","abbr","acronym","address","article","aside","audio","b","basefont","bdi","bdo","big","blockquote","body","button","canvas","caption","center","cite","code","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","html","i","iframe","ins","kbd","label","legend","li","main","map","mark","meter","nav","noscript","object","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","span","strong","style","sub","summary","sup","svg","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","u","ul","var","video"];let h={tag:c};for(let t of l)h[t]=c(t);const d=h;class u{get className(){return this.attr.className}get tagId(){return this.attr.id}constructor(t,e,s,r){this.children=[],this.attr=new a,this._meta={selfClosing:!1,storesChildren:!1,storage:!1},this.tagName=t,this.children=e,this.attr=s,this._meta=r}append(t){t instanceof o&&(t=t.b()),this.children.push(t)}findByTagName(t){return this.findOneBy((e=>e.tagName==t))}findOneBy(t){const e=[];for(e.push(this);e.length>0;){let s=e.pop();if(t(s))return s;if(s.children&&s.children.length)for(let t=0;t`-${t.toLowerCase()}`))}:${e};`;var s}}var m;!function(t){t[t.none=0]="none",t[t.body=1]="body",t[t.html=2]="html",t[t.head=3]="head"}(m||(m={}));let p={attachedTag:null,attachedTagStack:[],globalStuff:[]};function f(t){p.attachedTag&&p.attachedTagStack.push(p.attachedTag),p.attachedTag=t}function y(t){const e=()=>p.attachedTag?t.p(p.attachedTag):t;return Object.defineProperty(t,"a",{get:e}),Object.defineProperty(t,"attach",{get:e}),t}const b={};for(let t in d)b[t]=y(d[t]);const _=new class{constructor(){this.cssGenerator=new g,this.beautifyCss=!0}generateHtml(t){return this._generateTag(t)}_generateTag(t){if("style"==t.tagName)return this._createTag(t,this.cssGenerator.generateCss(t._meta.storage));if("script"==t.tagName)return this._createTag(t,this._generateScriptContent(t._meta.storage));let e="";for(const s of t.children){let t=s;s instanceof o&&(t=s.b()),e+=t instanceof u?this._generateTag(t):s}return this._createTag(t,e)}_createTag(t,e){const s=this._generateAttributeString(t);let a=[t.tagName,s].filter((t=>t)).join(" ");return t._meta.selfClosing?`<${a}/>`:`<${a}>${e}${t.tagName}>`}_generateAttributeString(t){let e="";t.attr.id&&(e+=this._attr("id",t.attr.id)),e+=this._attr("class",t.attr.className.raw()),e+=this._generateInlineStyle(t);for(const s in t.attr.additionalAttributes)e+=this._attr(s,t.attr.additionalAttributes[s]);return e}_generateInlineStyle(t){let e=this.cssGenerator.generateInline(t.attr.style.styles);return this._attr("style",e)}_generateScriptContent(t){let e="";if(t instanceof Function)e+=function(t){let e=t.toString();return e=e.replace(/^(.*{)/,""),e=e.replace(/}$/,""),e=e.replace(/^\(.*\)\s?=>\s?{/,""),e.trim()}(t);else if(t instanceof Array)for(const s of t)e+=this._generateScriptContent(s);return e}_attr(t,e){return e?`${t}="${e}"`:""}};const N=b;t.Tag=u,t.TagBuilder=o,t._context=p,t.attach=f,t.builders=N,t.detach=function(){p.attachedTagStack.length>0?p.attachedTag=p.attachedTagStack.pop():p.attachedTag=null},t.doc=function(t="New Hobo Document",e=m.body){const s=N.head.aa("lang","en").build(N.meta.addAttr("charset","UTF-8"),N.meta.setAttr({name:"viewport",content:"width=device-width, initial-scale=1.0"}),N.title(t)),a=N.body.build(),r=N.html.build(s,a);switch(e){case m.html:f(r);break;case m.head:f(r.findByTagName("head"));break;case m.body:f(r.findByTagName("body"));case m.none:}return{doc:r,head:s,body:a}},t.generate=function(t){return _.generateHtml(t)}}));
--------------------------------------------------------------------------------
/dist/hobo.umd.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nombrekeff/hobo-js/1cd54a3fe83bbd15820fb2e05fb6736a35efba6b/dist/hobo.umd.min.js.gz
--------------------------------------------------------------------------------
/dist/style.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents a set of styles
3 | */
4 | export class StyleSet {
5 | constructor() {
6 | this.styles = {};
7 | }
8 | copy() {
9 | const newStyles = new StyleSet();
10 | newStyles.styles = Object.assign({}, this.styles);
11 | return newStyles;
12 | }
13 | /** Set a single style */
14 | set(key, value) {
15 | this.styles[key] = value;
16 | return this;
17 | }
18 | /** Remove styles */
19 | remove(...styles) {
20 | for (const sn of styles) {
21 | delete this.styles[sn];
22 | }
23 | return this;
24 | }
25 | /** Check if a style is set */
26 | has(key) {
27 | return key in this.styles;
28 | }
29 | }
30 | //# sourceMappingURL=style.js.map
--------------------------------------------------------------------------------
/dist/style.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"style.js","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,QAAQ;IAArB;QACE,WAAM,GAAuD,EAAE,CAAC;IA0BlE,CAAC;IAxBC,IAAI;QACF,MAAM,SAAS,GAAG,IAAI,QAAQ,EAAE,CAAC;QACjC,SAAS,CAAC,MAAM,qBAAQ,IAAI,CAAC,MAAM,CAAE,CAAC;QACtC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,yBAAyB;IACzB,GAAG,CAAwB,GAAM,EAAE,KAA4B;QAC7D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAY,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,MAAM,CAAC,GAAG,MAAgB;QACxB,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE;YACvB,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;SACxB;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8BAA8B;IAC9B,GAAG,CAAC,GAAW;QACb,OAAO,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF"}
--------------------------------------------------------------------------------
/dist/tag-builder.js:
--------------------------------------------------------------------------------
1 | import { AttrSet } from './attributes';
2 | import { Tag } from './tag';
3 | import { allKnownTags, selfClosingTags, storableTags } from './custom-types/tag-names';
4 | class ExFunc extends Function {
5 | constructor() {
6 | super('...args', 'return this.__self__.__call__(...args)');
7 | var self = this.bind(this);
8 | this.__self__ = self;
9 | return self;
10 | }
11 | /* istanbul ignore next */
12 | __call__(...children) { }
13 | }
14 | /**
15 | * TagBuilder class, used to build tags of course.
16 | */
17 | export class TagBuilder extends ExFunc {
18 | /** Get the tag className */
19 | get className() {
20 | return this.attr.className;
21 | }
22 | /** Get the tag id */
23 | get tagId() {
24 | return this.attr.id;
25 | }
26 | constructor(tagName, ...children) {
27 | super();
28 | this.children = [];
29 | /**
30 | * Do not modify directly, use helper methods in the tag instead.
31 | */
32 | this.attr = new AttrSet();
33 | this._meta = {
34 | selfClosing: false,
35 | storesChildren: false,
36 | storage: false,
37 | };
38 | this.setTagName(tagName);
39 | this.children.push(...children);
40 | }
41 | copy() {
42 | const newBuilder = new TagBuilder(this.tagName, ...this.children);
43 | newBuilder.attr = this.attr.copy();
44 | newBuilder._parent = this._parent;
45 | newBuilder._meta = Object.assign(Object.assign({}, this._meta), newBuilder._meta);
46 | return newBuilder;
47 | }
48 | /** Sets and validates the tag name */
49 | setTagName(name) {
50 | this.tagName = this.sanitizeTagName(name);
51 | this.validateTagName(this.tagName);
52 | this._meta = Object.assign(Object.assign({}, this._meta), this.getMetaForTag(this.tagName));
53 | return this;
54 | }
55 | /**
56 | * Shorthand for `.build` method
57 | * Build the tag with additional children
58 | */
59 | b(...children) {
60 | return this.build(...children);
61 | }
62 | /**
63 | * Build the tag with additional children
64 | */
65 | build(...children) {
66 | return this.__call__(...children);
67 | }
68 | __call__(...children) {
69 | let tagChildren = [...this.children, ...children];
70 | if (this._meta.storesChildren) {
71 | this._meta.storage = children;
72 | tagChildren = [];
73 | }
74 | const built = new Tag(this.tagName, tagChildren, this.attr, this._meta);
75 | if (this._parent) {
76 | this._parent.children.push(built);
77 | }
78 | return built;
79 | }
80 | /** Attach to the currently attached tag in the global hobo context */
81 | /* istanbul ignore next */
82 | get a() {
83 | return this.copy();
84 | }
85 | /** Same as .a - Attach to the currently attached tag in the global hobo context */
86 | /* istanbul ignore next */
87 | get attach() {
88 | return this.copy();
89 | }
90 | /** Set the parent of the tag. If a parent is set, this tag will be added as a child when built */
91 | p(parent) {
92 | const copy = this.copy();
93 | copy._parent = parent;
94 | return copy;
95 | }
96 | /**
97 | * Set the id of the tag
98 | * Can't be empty
99 | */
100 | id(newId) {
101 | const copy = this.copy();
102 | copy.attr.id = newId;
103 | return copy;
104 | }
105 | /** replaces the children of this tag with the provided string */
106 | text(content) {
107 | const copy = this.copy();
108 | copy.children = [content];
109 | return copy;
110 | }
111 | /**
112 | * Adds tags as children if the tag can have children.
113 | * For example, if tag is `img` there's no need to add the childre as they will not be generated.
114 | */
115 | append(...tags) {
116 | if (this._meta.selfClosing) {
117 | return this;
118 | }
119 | const copy = this.copy();
120 | copy.children.push(...tags.map((c) => (c instanceof TagBuilder ? c.b() : c)));
121 | return copy;
122 | }
123 | /** Set the children of this tag. Replaces any current children */
124 | setChildren(children) {
125 | const copy = this.copy();
126 | copy.children = children;
127 | return copy;
128 | }
129 | /** Store metadata inside tag. Internal method, you won't need this */
130 | store(o) {
131 | const copy = this.copy();
132 | copy._meta.storage = o;
133 | return copy;
134 | }
135 | /**
136 | * cm = modify
137 | * calls `fn` with the tag, and returns the tag
138 | *
139 | * usefull to change a tag while maintaing chaning
140 | *
141 | * @example
142 | * ```ts
143 | * div().m(t => t.className.add("Container"))
144 | * .div("I'm a child!"),
145 | * ```
146 | * @example
147 | * ```ts
148 | * div([
149 | * p("Child1").m(t => t.className.add("child-1")),
150 | * p("Child1").m(t => t.className.add("child-2"))
151 | * ])
152 | * ```
153 | */
154 | m(fn) {
155 | return this.mod(fn);
156 | }
157 | /**
158 | * calls `fn` with the tag, and returns the tag
159 | *
160 | * usefull to change a tag while maintaing chaning
161 | *
162 | * @example
163 | * ```ts
164 | * div().m(t => t.className.add("Container"))
165 | * .div("I'm a child!"),
166 | * ```
167 | * @example
168 | * ```ts
169 | * div([
170 | * p("Child1").mod(t => t.className.add("child-1")),
171 | * p("Child1").mod(t => t.className.add("child-2"))
172 | * ])
173 | * ```
174 | */
175 | mod(fn) {
176 | const copy = this.copy();
177 | fn(copy);
178 | return copy;
179 | }
180 | /**
181 | * Shortcut for method .modClass
182 | *
183 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
184 | * but it passes the className instead of the complete tag.
185 | *
186 | * Retuns a new TagBuilder
187 | */
188 | mc(arg0) {
189 | return this.modClass(arg0);
190 | }
191 | /**
192 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
193 | * but it passes the className instead of the complete tag.
194 | *
195 | * Retuns a new TagBuilder
196 | *
197 | * @example
198 | * ```ts
199 | * div(
200 | * p("Child1").modClass(c => c.add("child-1")),
201 | * p("Child1").modClass(c => c.add("child-2"))
202 | * )
203 | * ```
204 | */
205 | modClass(arg0) {
206 | const copy = this.copy();
207 | return copy.m((t) => arg0(t.className));
208 | }
209 | /**
210 | * Shorthand for .addClass method.
211 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
212 | */
213 | ac(...classNames) {
214 | return this.addClass(...classNames);
215 | }
216 | /**
217 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
218 | */
219 | addClass(...classNames) {
220 | const copy = this.copy();
221 | copy.className.add(...classNames);
222 | return copy;
223 | }
224 | /**
225 | * Shorthand for .rmClass method.
226 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
227 | */
228 | rc(...classNames) {
229 | return this.rmClass(...classNames);
230 | }
231 | /**
232 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
233 | */
234 | rmClass(...classNames) {
235 | const copy = this.copy();
236 | copy.className.remove(...classNames);
237 | return copy;
238 | }
239 | /**
240 | * Shorthand for .addAttr method.
241 | * Adds attribute, and returns a new TagBuilder
242 | */
243 | aa(key, value) {
244 | return this.addAttr(key, value);
245 | }
246 | /** Add one attribute, and return a new TagBuilder */
247 | addAttr(key, value) {
248 | const copy = this.copy();
249 | copy.attr.set(key, value);
250 | return copy;
251 | }
252 | /**
253 | * Shorthand for .setAttr method.
254 | * Sets multiple atributes at once, and returns a new TagBuilder
255 | */
256 | sa(attributes) {
257 | return this.setAttr(attributes);
258 | }
259 | /** Sets multiple atributes at once, and returns a new TagBuilder */
260 | setAttr(attributes) {
261 | const copy = this.copy();
262 | copy.attr.additionalAttributes = Object.assign(Object.assign({}, copy.attr.additionalAttributes), attributes);
263 | return copy;
264 | }
265 | /**
266 | * Shorthand for .removeAttr method.
267 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
268 | */
269 | ra(...attr) {
270 | return this.rmAttr(...attr);
271 | }
272 | /**
273 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
274 | */
275 | rmAttr(...attr) {
276 | const copy = this.copy();
277 | copy.attr.remove(...attr);
278 | return copy;
279 | }
280 | /**
281 | * Shorthand for .addStyle method
282 | * Adds a single style, and returns a new TagBuilder
283 | */
284 | as(key, value) {
285 | return this.addStyle(key, value);
286 | }
287 | /**
288 | * Adds a single style, and returns a new TagBuilder
289 | */
290 | addStyle(key, value) {
291 | const copy = this.copy();
292 | copy.attr.style.set(key, value);
293 | return copy;
294 | }
295 | /**
296 | * Shorthand for .setStyles method.
297 | * Adds style from object, and returns a new TagBuilder
298 | */
299 | ss(styles) {
300 | return this.setStyles(styles);
301 | }
302 | /** Adds style from object, and returns a new TagBuilder */
303 | setStyles(styles) {
304 | const copy = this.copy();
305 | copy.attr.style.styles = Object.assign(Object.assign({}, copy.attr.style.styles), styles);
306 | return copy;
307 | }
308 | /**
309 | * Shorthand for .removeStyles method.
310 | * Removes styles from this TagBuilder, and returns a new TagBuilder
311 | */
312 | rs(...styleNames) {
313 | return this.rmStyle(...styleNames);
314 | }
315 | /**
316 | * Removes styles from this TagBuilder, and returns a new TagBuilder
317 | */
318 | rmStyle(...styleNames) {
319 | const copy = this.copy();
320 | copy.attr.style.remove(...styleNames);
321 | return copy;
322 | }
323 | // Utilities
324 | getMetaForTag(tagName) {
325 | return {
326 | selfClosing: this.isSelfClosingTag(tagName),
327 | storesChildren: this.isStorableTag(tagName),
328 | storage: null,
329 | };
330 | }
331 | isSelfClosingTag(tagName) {
332 | return selfClosingTags.includes(tagName);
333 | }
334 | isStorableTag(tagName) {
335 | return storableTags.includes(tagName);
336 | }
337 | validateTagName(tagName) {
338 | if (!/[a-zA-Z_][a-z-A-Z0-9_]*/.test(tagName)) {
339 | throw new Error(`Invalid tag name "${tagName}"`);
340 | }
341 | }
342 | sanitizeTagName(tagName) {
343 | return tagName.replace(/[^\w\d-_]/, '');
344 | }
345 | }
346 | function tagBuilder(tagName, ...children) {
347 | return new TagBuilder(tagName, ...children);
348 | }
349 | const tagNames = allKnownTags;
350 | let fns = {
351 | tag: tagBuilder,
352 | };
353 | for (let tname of tagNames) {
354 | fns[tname] = tagBuilder(tname);
355 | }
356 | export const builders = fns;
357 | //# sourceMappingURL=tag-builder.js.map
--------------------------------------------------------------------------------
/dist/tag-builder.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"tag-builder.js","sourceRoot":"","sources":["../src/tag-builder.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/tag.js:
--------------------------------------------------------------------------------
1 | import { AttrSet } from './attributes';
2 | import { TagBuilder } from './tag-builder';
3 | /**
4 | * Represents an html tag
5 | */
6 | export class Tag {
7 | get className() {
8 | return this.attr.className;
9 | }
10 | get tagId() {
11 | return this.attr.id;
12 | }
13 | constructor(tagName, children, attr, meta) {
14 | this.children = [];
15 | this.attr = new AttrSet();
16 | this._meta = {
17 | selfClosing: false,
18 | storesChildren: false,
19 | storage: false,
20 | };
21 | this.tagName = tagName;
22 | this.children = children;
23 | this.attr = attr;
24 | this._meta = meta;
25 | }
26 | /** Append children */
27 | append(child) {
28 | if (child instanceof TagBuilder)
29 | child = child.b();
30 | this.children.push(child);
31 | }
32 | /** Find a child by tag name */
33 | findByTagName(targetTagName) {
34 | return this.findOneBy((t) => t.tagName == targetTagName);
35 | }
36 | /** Find a child by custom test */
37 | findOneBy(test) {
38 | const stack = [];
39 | stack.push(this);
40 | while (stack.length > 0) {
41 | let tag = stack.pop();
42 | if (test(tag)) {
43 | return tag;
44 | }
45 | else if (tag.children && tag.children.length) {
46 | for (let ii = 0; ii < tag.children.length; ii += 1) {
47 | if (this.children[ii] instanceof Tag) {
48 | stack.push(tag.children[ii]);
49 | }
50 | }
51 | }
52 | }
53 | return null;
54 | }
55 | }
56 | //# sourceMappingURL=tag.js.map
--------------------------------------------------------------------------------
/dist/tag.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"tag.js","sourceRoot":"","sources":["../src/tag.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;GAEG;AACH,MAAM,OAAO,GAAG;IAWd,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,YAAY,OAAgB,EAAE,QAAyB,EAAE,IAAa,EAAE,IAAa;QAhBrF,aAAQ,GAAoB,EAAE,CAAC;QAC/B,SAAI,GAAY,IAAI,OAAO,EAAE,CAAC;QAE9B,UAAK,GAAY;YACf,WAAW,EAAE,KAAK;YAClB,cAAc,EAAE,KAAK;YACrB,OAAO,EAAE,KAAK;SACf,CAAC;QAUA,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,uBAAuB;IACvB,MAAM,CAAC,KAAoB;QACzB,IAAI,KAAK,YAAY,UAAU;YAAE,KAAK,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,gCAAgC;IAChC,aAAa,CAAC,aAAsB;QAClC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED,mCAAmC;IACnC,SAAS,CAAC,IAAY;QACpB,MAAM,KAAK,GAAU,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;YACvB,IAAI,GAAG,GAAQ,KAAK,CAAC,GAAG,EAAS,CAAC;YAElC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE;gBACb,OAAO,GAAG,CAAC;aACZ;iBAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE;gBAC9C,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;oBAClD,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,GAAG,EAAE;wBACpC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAQ,CAAC,CAAC;qBACrC;iBACF;aACF;SACF;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
--------------------------------------------------------------------------------
/dist/types/attributes.d.ts:
--------------------------------------------------------------------------------
1 | import { ClassName } from './class-name';
2 | import { StyleSet } from './style';
3 | /**
4 | * Represents a tag's attribute set.
5 | */
6 | export declare class AttrSet {
7 | className: ClassName;
8 | id?: string;
9 | style: StyleSet;
10 | additionalAttributes: {
11 | [key: string]: string;
12 | };
13 | copy(): AttrSet;
14 | /** Set single attribute */
15 | set(key: string, value: string): AttrSet;
16 | /** Remove attributes */
17 | remove(...attrs: string[]): AttrSet;
18 | /** Check if an attribute is set */
19 | has(key: string): boolean;
20 | }
21 |
--------------------------------------------------------------------------------
/dist/types/class-name.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents a tag's class list.
3 | */
4 | export declare class ClassName {
5 | classNames: string[];
6 | constructor(classNames?: string[]);
7 | copy(): ClassName;
8 | /**
9 | * Returns a string of all the class names separated by spaces.
10 | */
11 | raw(): string;
12 | /** Add one or more class names */
13 | add(...classNames: string[]): ClassName;
14 | /** Remove one or more class names */
15 | remove(...classNames: string[]): ClassName;
16 | /** Check if a class name is present. */
17 | has(str: string): boolean;
18 | }
19 |
--------------------------------------------------------------------------------
/dist/types/custom-types/colors.d.ts:
--------------------------------------------------------------------------------
1 | export type NamedColor = 'black' | 'silver' | 'gray' | 'white' | 'maroon' | 'red' | 'purple' | 'fuchsia' | 'green' | 'lime' | 'olive' | 'yellow' | 'navy' | 'blue' | 'teal' | 'aqua' | 'aliceblue' | 'antiquewhite' | 'aqua' | 'aquamarine' | 'azure' | 'beige' | 'bisque' | 'black' | 'blanchedalmond' | 'blue' | 'blueviolet' | 'brown' | 'burlywood' | 'cadetblue' | 'chartreuse' | 'chocolate' | 'coral' | 'cornflowerblue' | 'cornsilk' | 'crimson' | 'cyan' | 'darkblue' | 'darkcyan' | 'darkgoldenrod' | 'darkgray' | 'darkgreen' | 'darkgrey' | 'darkkhaki' | 'darkmagenta' | 'darkolivegreen' | 'darkorange' | 'darkorchid' | 'darkred' | 'darksalmon' | 'darkseagreen' | 'darkslateblue' | 'darkslategray' | 'darkslategrey' | 'darkturquoise' | 'darkviolet' | 'deeppink' | 'deepskyblue' | 'dimgray' | 'dimgrey' | 'dodgerblue' | 'firebrick' | 'floralwhite' | 'forestgreen' | 'fuchsia' | 'gainsboro' | 'ghostwhite' | 'gold' | 'goldenrod' | 'gray' | 'green' | 'greenyellow' | 'grey' | 'honeydew' | 'hotpink' | 'indianred' | 'indigo' | 'ivory' | 'khaki' | 'lavender' | 'lavenderblush' | 'lawngreen' | 'lemonchiffon' | 'lightblue' | 'lightcoral' | 'lightcyan' | 'lightgoldenrodyellow' | 'lightgray' | 'lightgreen' | 'lightgrey' | 'lightpink' | 'lightsalmon' | 'lightseagreen' | 'lightskyblue' | 'lightslategray' | 'lightslategrey' | 'lightsteelblue' | 'lightyellow' | 'lime' | 'limegreen' | 'linen' | 'magenta' | 'maroon' | 'mediumaquamarine' | 'mediumblue' | 'mediumorchid' | 'mediumpurple' | 'mediumseagreen' | 'mediumslateblue' | 'mediumspringgreen' | 'mediumturquoise' | 'mediumvioletred' | 'midnightblue' | 'mintcream' | 'mistyrose' | 'moccasin' | 'navajowhite' | 'navy' | 'oldlace' | 'olive' | 'olivedrab' | 'orange' | 'orangered' | 'orchid' | 'palegoldenrod' | 'palegreen' | 'paleturquoise' | 'palevioletred' | 'papayawhip' | 'peachpuff' | 'peru' | 'pink' | 'plum' | 'powderblue' | 'purple' | 'rebeccapurple' | 'red' | 'rosybrown' | 'royalblue' | 'saddlebrown' | 'salmon' | 'sandybrown' | 'seagreen' | 'seashell' | 'sienna' | 'silver' | 'skyblue' | 'slateblue' | 'slategray' | 'slategrey' | 'snow' | 'springgreen' | 'steelblue' | 'tan' | 'teal' | 'thistle' | 'tomato' | 'turquoise' | 'violet' | 'wheat' | 'white' | 'whitesmoke' | 'yellow' | 'yellowgreen';
2 |
--------------------------------------------------------------------------------
/dist/types/custom-types/css-properties.d.ts:
--------------------------------------------------------------------------------
1 | export type CssProperty = 'color' | 'border' | 'margin' | 'fontStyle' | 'transform' | 'backgroundColor' | 'alignContent' | 'alignItems' | 'alignSelf' | 'all' | 'animation' | 'animationDelay' | 'animationDirection' | 'animationDuration' | 'animationFillMode' | 'animationIterationCount' | 'animationName' | 'animationPlayState' | 'animationTimingFunction' | 'backfaceVisibility' | 'background' | 'backgroundAttachment' | 'backgroundBlendMode' | 'backgroundClip' | 'backgroundColor' | 'backgroundImage' | 'backgroundOrigin' | 'backgroundPosition' | 'backgroundRepeat' | 'backgroundSize' | 'border' | 'borderBottom' | 'borderBottomColor' | 'borderBottomLeftRadius' | 'borderBottomRightRadius' | 'borderBottomStyle' | 'borderBottomWidth' | 'borderCollapse' | 'borderColor' | 'borderImage' | 'borderImageOutset' | 'borderImageRepeat' | 'borderImageSlice' | 'borderImageSource' | 'borderImageWidth' | 'borderLeft' | 'borderLeftColor' | 'borderLeftStyle' | 'borderLeftWidth' | 'borderRadius' | 'borderRight' | 'borderRightColor' | 'borderRightStyle' | 'borderRightWidth' | 'borderSpacing' | 'borderStyle' | 'borderTop' | 'borderTopColor' | 'borderTopLeftRadius' | 'borderTopRightRadius' | 'borderTopStyle' | 'borderTopWidth' | 'borderWidth' | 'bottom' | 'boxShadow' | 'boxSizing' | 'captionSide' | 'caretColor' | '@charset' | 'clear' | 'clip' | 'clipPath' | 'color' | 'columnCount' | 'columnFill' | 'columnGap' | 'columnRule' | 'columnRuleColor' | 'columnRuleStyle' | 'columnRuleWidth' | 'columnSpan' | 'columnWidth' | 'columns' | 'content' | 'counterIncrement' | 'counterReset' | 'cursor' | 'direction' | 'display' | 'emptyCells' | 'filter' | 'flex' | 'flexBasis' | 'flexDirection' | 'flexFlow' | 'flexGrow' | 'flexShrink' | 'flexWrap' | 'float' | 'font' | '@fontFace' | 'fontFamily' | 'fontKerning' | 'fontSize' | 'fontSizeAdjust' | 'fontStretch' | 'fontStyle' | 'fontVariant' | 'fontWeight' | 'grid' | 'gridArea' | 'gridAutoColumns' | 'gridAutoFlow' | 'gridAutoRows' | 'gridColumn' | 'gridColumnEnd' | 'gridColumnGap' | 'gridColumnStart' | 'gridGap' | 'gridRow' | 'gridRowEnd' | 'gridRowGap' | 'gridRowStart' | 'gridTemplate' | 'gridTemplateAreas' | 'gridTemplateColumns' | 'gridTemplateRows' | 'height' | 'hyphens' | '@import' | 'justifyContent' | '@keyframes' | 'left' | 'letterSpacing' | 'lineHeight' | 'listStyle' | 'listStyleImage' | 'listStylePosition' | 'listStyleType' | 'margin' | 'marginBottom' | 'marginLeft' | 'marginRight' | 'marginTop' | 'maxHeight' | 'maxWidth' | '@media' | 'minHeight' | 'minWidth' | 'objectFit' | 'objectPosition' | 'opacity' | 'order' | 'outline' | 'outlineColor' | 'outlineOffset' | 'outlineStyle' | 'outlineWidth' | 'overflow' | 'overflowX' | 'overflowY' | 'padding' | 'paddingBottom' | 'paddingLeft' | 'paddingRight' | 'paddingTop' | 'pageBreakAfter' | 'pageBreakBefore' | 'pageBreakInside' | 'perspective' | 'perspectiveOrigin' | 'pointerEvents' | 'position' | 'quotes' | 'right' | 'scrollBehavior' | 'tableLayout' | 'textAlign' | 'textAlignLast' | 'textDecoration' | 'textDecorationColor' | 'textDecorationLine' | 'textDecorationStyle' | 'textIndent' | 'textJustify' | 'textOverflow' | 'textShadow' | 'textTransform' | 'top' | 'transform' | 'transformOrigin' | 'transformStyle' | 'transition' | 'transitionDelay' | 'transitionDuration' | 'transitionProperty' | 'transitionTimingFunction' | 'userSelect' | 'verticalAlign' | 'visibility' | 'whiteSpace' | 'width' | 'wordBreak' | 'wordSpacing' | 'wordWrap' | 'writingMode' | 'zIndex' | (string & {});
2 |
--------------------------------------------------------------------------------
/dist/types/custom-types/css-property-values.d.ts:
--------------------------------------------------------------------------------
1 | import { NamedColor } from './colors';
2 | export type PickPropertyValues = T extends 'color' ? ColorOptions : T extends 'alignContent' ? AlignContentOptions : T extends 'alignItems' ? AlignItemsOptions : T extends 'alignSelf' ? AlignSelfOptions : T extends 'all' ? AllOptions : T extends 'accentColor' ? ColorOptions : T extends 'animationDirection' ? AnimationDirectionOptions : T extends 'animationFillMode' ? AnimationFillModeOptions : T extends 'animationPlayState' ? AnimationPlayStateOptions : T extends 'animationPlayState' ? AnimationPlayStateOptions : T extends 'borderStyle' ? BorderStyleOptions : T extends 'background' ? ColorOptions : T extends 'backgroundColor' ? ColorOptions : T extends 'backgroundImage' ? BackgroundImageOptions : T extends 'backgroundRepeat' ? BackgroundRepeatOptions : T extends 'backgroundAttachment' ? BackgroundAttachmentOptions : T extends 'backgroundPosition' ? BackgroundPositionOptions : T extends 'position' ? PPositionOptions : T extends 'transform' ? TransformOptions : T extends 'fontStyle' ? FontStyleOptions : T extends 'fontWeight' ? FontWeightOptions : T extends 'flexDirection' ? FlexDirectionOptions : T extends 'zIndex' ? Number : T extends 'top' ? Number : T extends 'display' ? DisplayOptions : T extends 'bottom' ? Number : T extends 'left' ? Number : T extends 'right' ? Number : string & {};
3 | export type CommonOptions = 'initial' | 'inherit' | (string & {});
4 | export type ColorOptions = NamedColor | (string & {});
5 | export type AlignContentOptions = 'flex-wrap' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'space-between' | 'space-around' | CommonOptions;
6 | export type AlignItemsOptions = 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline' | CommonOptions;
7 | export type DisplayOptions = 'inline' | 'block' | 'contents' | 'flex' | 'grid' | 'inline-block' | 'inline-flex' | 'inline-grid' | 'inline-table' | 'list-item' | 'run-in' | 'table' | 'table-caption' | 'table-column-group' | 'table-header-group' | 'table-footer-group' | 'table-row-group' | 'table-cell' | 'table-column' | 'table-row' | 'none' | CommonOptions;
8 | type AlignSelfOptions = 'auto' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline' | CommonOptions;
9 | type AllOptions = CommonOptions | 'unset';
10 | type AnimationDirectionOptions = 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' | 'initial' | 'inherit' | (string & {});
11 | type AnimationFillModeOptions = 'none' | 'forwards' | 'backwards' | 'both' | CommonOptions;
12 | type AnimationPlayStateOptions = 'paused' | 'running' | CommonOptions;
13 | type BorderStyleOptions = 'none' | 'no' | 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | CommonOptions;
14 | export type BackgroundImageOptions = 'url()' | 'none' | 'conic-gradient()' | 'linear-gradient()' | 'radial-gradient()' | 'repeating-conic-gradient()' | 'repeating-linear-gradient()' | 'repeating-radial-gradient()' | 'initial' | 'inherit';
15 | type BackgroundRepeatOptions = 'repeat' | 'no' | 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' | 'space' | 'round' | CommonOptions;
16 | type BackgroundAttachmentOptions = 'scroll' | 'no' | 'scroll' | 'fixed' | 'local' | CommonOptions;
17 | type BackgroundPositionOptions = 'left top' | 'left center' | 'left bottom' | 'right top' | 'right center' | 'right bottom' | 'center top' | 'center center' | 'center bottom' | 'inherit' | 'initial' | (string & {});
18 | export type PPositionOptions = 'static' | 'fixed' | 'absolute' | 'relative' | 'sticky' | CommonOptions;
19 | export type TransformOptions = 'none' | 'matrix(n,n,n,n,n,n)' | 'matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n)' | 'translate(x,y)' | 'translate3d(x,y,z)' | 'translateX(x)' | 'translateY(y)' | 'translateZ(z)' | 'scale(x,y)' | 'scale3d(x,y,z)' | 'scaleX(x)' | 'scaleY(y)' | 'scaleZ(z)' | 'rotate(angle)' | 'rotate3d(x,y,z,angle)' | 'rotateX(angle)' | 'rotateY(angle)' | 'rotateZ(angle)' | 'skew(x-angle,y-angle)' | 'skewX(angle)' | 'skewY(angle)' | 'perspective(n)' | CommonOptions;
20 | export type FontWeightOptions = 'normal' | 'bold' | 'bolder' | 'lighter' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | CommonOptions;
21 | export type FontStyleOptions = 'normal' | 'italic' | 'oblique' | CommonOptions;
22 | export type FlexDirectionOptions = 'row' | 'column' | 'row-reverse' | 'column-reverse' | CommonOptions;
23 | export {};
24 |
--------------------------------------------------------------------------------
/dist/types/custom-types/tag-names.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @export
3 | * List of all known self-closing HTML tags
4 | */
5 | export declare const selfClosingTags: string[];
6 | /** List of all known closing HTML tags */
7 | export declare const closingTags: string[];
8 | /** List of all known HTML tags */
9 | export declare const allKnownTags: string[];
10 | export declare const storableTags: string[];
11 | /** @export @type {TagName} */
12 | export type TagName = ValidTagName | (string & {});
13 | /** @type {ValidTagName} */
14 | export type ValidTagName = 'a' | 'abbr' | 'acronym' | 'address' | 'area' | 'article' | 'aside' | 'audio' | 'b' | 'base' | 'basefont' | 'bdi' | 'bdo' | 'big' | 'blockquote' | 'body' | 'br' | 'button' | 'canvas' | 'caption' | 'center' | 'cite' | 'code' | 'col' | 'colgroup' | 'data' | 'datalist' | 'dd' | 'del' | 'details' | 'dfn' | 'dialog' | 'div' | 'dl' | 'dt' | 'em' | 'embed' | 'fieldset' | 'figcaption' | 'figure' | 'footer' | 'form' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'head' | 'header' | 'hr' | 'html' | 'i' | 'iframe' | 'img' | 'input' | 'ins' | 'kbd' | 'label' | 'legend' | 'li' | 'link' | 'main' | 'map' | 'mark' | 'meta' | 'meter' | 'nav' | 'noscript' | 'object' | 'ol' | 'optgroup' | 'option' | 'output' | 'p' | 'param' | 'picture' | 'pre' | 'progress' | 'q' | 'rp' | 'rt' | 'ruby' | 's' | 'samp' | 'script' | 'section' | 'select' | 'selfClosingTagName' | 'small' | 'span' | 'strong' | 'style' | 'sub' | 'summary' | 'sup' | 'svg' | 'table' | 'tbody' | 'td' | 'template' | 'textarea' | 'tfoot' | 'th' | 'thead' | 'time' | 'title' | 'track' | 'tr' | 'u' | 'ul' | 'var' | 'video' | 'wbr';
15 |
--------------------------------------------------------------------------------
/dist/types/custom-types/types.d.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from '../tag';
2 | import { TagBuilder } from '../tag-builder';
3 | import { CssProperty } from './css-properties';
4 | import { PickPropertyValues } from './css-property-values';
5 | export type StyleMap = {
6 | [key in CssProperty]?: PickPropertyValues;
7 | };
8 | export type NestedStyleMap = {
9 | [key in CssProperty]?: PickPropertyValues | StyleMap;
10 | };
11 | export type StyleSet = {
12 | [key: string]: NestedStyleMap;
13 | };
14 | export declare enum AttachMode {
15 | none = 0,
16 | body = 1,
17 | html = 2,
18 | head = 3
19 | }
20 | export type ValidTagChild = string | Tag | {
21 | [key: string]: StyleMap;
22 | } | TagBuilder | ((_: string) => void);
23 | export type TagMeta = {
24 | storage: any;
25 | selfClosing: boolean;
26 | storesChildren: boolean;
27 | };
28 | export type FindBy = (tag: Tag) => boolean;
29 | export type State = {} & {};
30 | export type StateProxy = T & {
31 | state: boolean;
32 | };
33 | export type GlobalStuff = Function | string;
34 | export type HoboContext = {
35 | attachedTag: Tag | undefined | null;
36 | attachedTagStack: Tag[];
37 | globalStuff: GlobalStuff[];
38 | };
39 | export type HtmlEventType = 'click' | (string & {});
40 |
--------------------------------------------------------------------------------
/dist/types/generation/css-generator.d.ts:
--------------------------------------------------------------------------------
1 | import { NestedStyleMap, StyleMap } from '../custom-types/types';
2 | export declare class CssGenerator {
3 | generateCss(styleSheet: {
4 | [key: string]: NestedStyleMap;
5 | } | {
6 | [key: string]: NestedStyleMap;
7 | }[]): string;
8 | generateBlock(selector: string, style: NestedStyleMap): string;
9 | generateBlockContent(selector: string, style: NestedStyleMap): string[];
10 | generateInline(style: StyleMap): string;
11 | generateStyle(name: string, value: string): string;
12 | }
13 |
--------------------------------------------------------------------------------
/dist/types/generation/html-generator.d.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from '../tag';
2 | export declare class HtmlGenerator {
3 | private cssGenerator;
4 | beautifyCss: boolean;
5 | /** Generate html from the tag provided */
6 | generateHtml(rootTag: Tag): string;
7 | private _generateTag;
8 | private _createTag;
9 | private _generateAttributeString;
10 | private _generateInlineStyle;
11 | private _generateScriptContent;
12 | private _attr;
13 | }
14 |
--------------------------------------------------------------------------------
/dist/types/hobo.d.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from './tag';
2 | export { Tag } from './tag';
3 | import { AttachMode, HoboContext } from './custom-types/types';
4 | import { TagBuilder, PickArgType } from './tag-builder';
5 | export { TagBuilder } from './tag-builder';
6 | import { TagName, ValidTagName } from './custom-types/tag-names';
7 | export declare let _context: HoboContext;
8 | /**
9 | * Creates an HTML document, with a head and body tags.
10 | * You can pass in the AttachMode to attach to different tags.
11 | */
12 | export declare function doc(pageTitle?: string, mode?: AttachMode): {
13 | doc: Tag;
14 | head: Tag;
15 | body: Tag;
16 | };
17 | /**
18 | * Attach a given tag to the current context.
19 | * When you attach a tag, this tag will be the "root" for any tag created without a parent.
20 | *
21 | * * If there is not attached tag, it will be attached
22 | * * If there is already a tag attached, it will store the previous tag
23 | * and will set the new tag as the root. After finishing using the tag as the root, you can call `@detach`
24 | * and return to the previous root tag.
25 | *
26 | * This is used to remove clutter and reduntancies when creating hobo docs.
27 | * Like this:
28 | *
29 | * @example
30 | * Simple example with only 1 attach
31 | * ```ts
32 | * const parent = doc();
33 | * attach(parent);
34 | *
35 | * div();
36 | * p();
37 | * ```
38 | * The `div` and `p` tags will be automatically added as child of `parentDiv`
39 | *
40 | * @example
41 | * Example attaching and detaching
42 | * ```ts
43 | * const parent = doc();
44 | * attach(parent);
45 | *
46 | * div();
47 | * p();
48 | * let d1 = div();
49 | * attach(d1);
50 | * // All the p tags will be added to `d1`
51 | * p();
52 | * p();
53 | * p();
54 | * // remember to call detach when you want to go back to the previous root tag
55 | * detach();
56 | * ```
57 | *
58 | * @param {Tag} tag
59 | */
60 | export declare function attach(tag: Tag): void;
61 | /**
62 | * Detached the currently attached tag, and pops back to the previously attached tag.
63 | * If there are no stored tags, it will clear the attached tag.
64 | * You will need to handle the consecuent created tags.
65 | */
66 | export declare function detach(): void;
67 | type BuilderFunctions = {
68 | [key in ValidTagName]: ((...children: PickArgType) => Tag) & TagBuilder & {
69 | a: TagBuilder;
70 | };
71 | } & {
72 | tag: (tagName: TagName, ...children: PickArgType) => TagBuilder;
73 | };
74 | /** Converts's the Tag tree into a html string */
75 | export declare function generate(root: Tag): string;
76 | /**
77 | * TagBuilders for each known tag. From `div` to `acronym`
78 | */
79 | export declare const builders: BuilderFunctions;
80 |
--------------------------------------------------------------------------------
/dist/types/style.d.ts:
--------------------------------------------------------------------------------
1 | import { CssProperty } from './custom-types/css-properties';
2 | import { PickPropertyValues } from './custom-types/css-property-values';
3 | /**
4 | * Represents a set of styles
5 | */
6 | export declare class StyleSet {
7 | styles: {
8 | [key in CssProperty]?: PickPropertyValues;
9 | };
10 | copy(): StyleSet;
11 | /** Set a single style */
12 | set(key: T, value: PickPropertyValues): StyleSet;
13 | /** Remove styles */
14 | remove(...styles: string[]): StyleSet;
15 | /** Check if a style is set */
16 | has(key: string): boolean;
17 | }
18 |
--------------------------------------------------------------------------------
/dist/types/tag-builder.d.ts:
--------------------------------------------------------------------------------
1 | import { AttrSet } from './attributes';
2 | import { ClassName } from './class-name';
3 | import { Tag } from './tag';
4 | import { CssProperty } from './custom-types/css-properties';
5 | import { PickPropertyValues } from './custom-types/css-property-values';
6 | import { TagName, ValidTagName } from './custom-types/tag-names';
7 | import { StyleMap, StyleSet, TagMeta, ValidTagChild } from './custom-types/types';
8 | declare class ExFunc extends Function {
9 | private __self__;
10 | constructor();
11 | __call__(...children: ValidTagChild[]): void;
12 | }
13 | /**
14 | * TagBuilder class, used to build tags of course.
15 | */
16 | export declare class TagBuilder extends ExFunc {
17 | tagName: TagName;
18 | children: ValidTagChild[];
19 | /** Get the tag className */
20 | get className(): ClassName;
21 | /** Get the tag id */
22 | get tagId(): string;
23 | /**
24 | * Do not modify directly, use helper methods in the tag instead.
25 | */
26 | attr: AttrSet;
27 | _parent: Tag;
28 | _meta: TagMeta;
29 | constructor(tagName: TagName, ...children: ValidTagChild[]);
30 | copy(): TagBuilder;
31 | /** Sets and validates the tag name */
32 | setTagName(name: string): this;
33 | /**
34 | * Shorthand for `.build` method
35 | * Build the tag with additional children
36 | */
37 | b(...children: ValidTagChild[]): Tag;
38 | /**
39 | * Build the tag with additional children
40 | */
41 | build(...children: ValidTagChild[]): Tag;
42 | __call__(...children: ValidTagChild[]): Tag;
43 | /** Attach to the currently attached tag in the global hobo context */
44 | get a(): TagBuilder;
45 | /** Same as .a - Attach to the currently attached tag in the global hobo context */
46 | get attach(): TagBuilder;
47 | /** Set the parent of the tag. If a parent is set, this tag will be added as a child when built */
48 | p(parent: Tag): TagBuilder;
49 | /**
50 | * Set the id of the tag
51 | * Can't be empty
52 | */
53 | id(newId: T extends '' ? never : T): TagBuilder;
54 | /** replaces the children of this tag with the provided string */
55 | text(content: string): TagBuilder;
56 | /**
57 | * Adds tags as children if the tag can have children.
58 | * For example, if tag is `img` there's no need to add the childre as they will not be generated.
59 | */
60 | append(...tags: ValidTagChild[]): TagBuilder;
61 | /** Set the children of this tag. Replaces any current children */
62 | setChildren(children: ValidTagChild[]): TagBuilder;
63 | /** Store metadata inside tag. Internal method, you won't need this */
64 | store(o: any): TagBuilder;
65 | /**
66 | * cm = modify
67 | * calls `fn` with the tag, and returns the tag
68 | *
69 | * usefull to change a tag while maintaing chaning
70 | *
71 | * @example
72 | * ```ts
73 | * div().m(t => t.className.add("Container"))
74 | * .div("I'm a child!"),
75 | * ```
76 | * @example
77 | * ```ts
78 | * div([
79 | * p("Child1").m(t => t.className.add("child-1")),
80 | * p("Child1").m(t => t.className.add("child-2"))
81 | * ])
82 | * ```
83 | */
84 | m(fn: (tag: TagBuilder) => void): TagBuilder;
85 | /**
86 | * calls `fn` with the tag, and returns the tag
87 | *
88 | * usefull to change a tag while maintaing chaning
89 | *
90 | * @example
91 | * ```ts
92 | * div().m(t => t.className.add("Container"))
93 | * .div("I'm a child!"),
94 | * ```
95 | * @example
96 | * ```ts
97 | * div([
98 | * p("Child1").mod(t => t.className.add("child-1")),
99 | * p("Child1").mod(t => t.className.add("child-2"))
100 | * ])
101 | * ```
102 | */
103 | mod(fn: (tag: TagBuilder) => void): TagBuilder;
104 | /**
105 | * Shortcut for method .modClass
106 | *
107 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
108 | * but it passes the className instead of the complete tag.
109 | *
110 | * Retuns a new TagBuilder
111 | */
112 | mc(arg0: (c: ClassName) => void): TagBuilder;
113 | /**
114 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
115 | * but it passes the className instead of the complete tag.
116 | *
117 | * Retuns a new TagBuilder
118 | *
119 | * @example
120 | * ```ts
121 | * div(
122 | * p("Child1").modClass(c => c.add("child-1")),
123 | * p("Child1").modClass(c => c.add("child-2"))
124 | * )
125 | * ```
126 | */
127 | modClass(arg0: (c: ClassName) => void): TagBuilder;
128 | /**
129 | * Shorthand for .addClass method.
130 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
131 | */
132 | ac(...classNames: string[]): TagBuilder;
133 | /**
134 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
135 | */
136 | addClass(...classNames: string[]): TagBuilder;
137 | /**
138 | * Shorthand for .rmClass method.
139 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
140 | */
141 | rc(...classNames: string[]): TagBuilder;
142 | /**
143 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
144 | */
145 | rmClass(...classNames: string[]): TagBuilder;
146 | /**
147 | * Shorthand for .addAttr method.
148 | * Adds attribute, and returns a new TagBuilder
149 | */
150 | aa(key: string, value: string): TagBuilder;
151 | /** Add one attribute, and return a new TagBuilder */
152 | addAttr(key: string, value: string): TagBuilder;
153 | /**
154 | * Shorthand for .setAttr method.
155 | * Sets multiple atributes at once, and returns a new TagBuilder
156 | */
157 | sa(attributes: {
158 | [key: string]: string;
159 | }): TagBuilder;
160 | /** Sets multiple atributes at once, and returns a new TagBuilder */
161 | setAttr(attributes: {
162 | [key: string]: string;
163 | }): TagBuilder;
164 | /**
165 | * Shorthand for .removeAttr method.
166 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
167 | */
168 | ra(...attr: string[]): TagBuilder;
169 | /**
170 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
171 | */
172 | rmAttr(...attr: string[]): TagBuilder;
173 | /**
174 | * Shorthand for .addStyle method
175 | * Adds a single style, and returns a new TagBuilder
176 | */
177 | as(key: T, value: PickPropertyValues): TagBuilder;
178 | /**
179 | * Adds a single style, and returns a new TagBuilder
180 | */
181 | addStyle(key: T, value: PickPropertyValues): TagBuilder;
182 | /**
183 | * Shorthand for .setStyles method.
184 | * Adds style from object, and returns a new TagBuilder
185 | */
186 | ss(styles: StyleMap): TagBuilder;
187 | /** Adds style from object, and returns a new TagBuilder */
188 | setStyles(styles: StyleMap): TagBuilder;
189 | /**
190 | * Shorthand for .removeStyles method.
191 | * Removes styles from this TagBuilder, and returns a new TagBuilder
192 | */
193 | rs(...styleNames: string[]): TagBuilder;
194 | /**
195 | * Removes styles from this TagBuilder, and returns a new TagBuilder
196 | */
197 | rmStyle(...styleNames: string[]): TagBuilder;
198 | private getMetaForTag;
199 | private isSelfClosingTag;
200 | private isStorableTag;
201 | private validateTagName;
202 | private sanitizeTagName;
203 | }
204 | export type PickArgType = T extends 'style' ? StyleSet[] : ValidTagChild[];
205 | type BuilderFunctions = {
206 | [key in ValidTagName]: ((...children: PickArgType) => Tag) & TagBuilder;
207 | } & {
208 | /**
209 | * Create a new TagBuilder with specified tagName
210 | * @example
211 | * ```ts
212 | * tag('uknown-tag');
213 | * ```
214 | */
215 | tag: (tagName: TagName, ...children: PickArgType) => TagBuilder;
216 | };
217 | export declare const builders: Partial;
218 | export {};
219 |
--------------------------------------------------------------------------------
/dist/types/tag.d.ts:
--------------------------------------------------------------------------------
1 | import { TagName } from './custom-types/tag-names';
2 | import { AttrSet } from './attributes';
3 | import { FindBy, TagMeta, ValidTagChild } from './custom-types/types';
4 | /**
5 | * Represents an html tag
6 | */
7 | export declare class Tag {
8 | tagName: TagName;
9 | children: ValidTagChild[];
10 | attr: AttrSet;
11 | _meta: TagMeta;
12 | get className(): import("./class-name").ClassName;
13 | get tagId(): string;
14 | constructor(tagName: TagName, children: ValidTagChild[], attr: AttrSet, meta: TagMeta);
15 | /** Append children */
16 | append(child: ValidTagChild): void;
17 | /** Find a child by tag name */
18 | findByTagName(targetTagName: TagName): Tag | null;
19 | /** Find a child by custom test */
20 | findOneBy(test: FindBy): Tag | null;
21 | }
22 |
--------------------------------------------------------------------------------
/dist/types/util.d.ts:
--------------------------------------------------------------------------------
1 | /** Receives a function, and returns just the body of the function as a string */
2 | export declare function justFnBody(fn: Function): string;
3 | export declare const replaceDoubleQuotes: (str: string) => string;
4 | export declare const generateId: () => string;
5 | export declare const camelToDash: (str: any) => any;
6 | export declare const dashToCamel: (str: any) => any;
7 | export declare function isObject(obj: any): boolean;
8 |
--------------------------------------------------------------------------------
/dist/util.js:
--------------------------------------------------------------------------------
1 | /** Receives a function, and returns just the body of the function as a string */
2 | export function justFnBody(fn) {
3 | let fnStr = fn.toString();
4 | fnStr = fnStr.replace(/^(.*{)/, '');
5 | fnStr = fnStr.replace(/}$/, '');
6 | fnStr = fnStr.replace(/^\(.*\)\s?=>\s?{/, '');
7 | return fnStr.trim();
8 | }
9 | export const replaceDoubleQuotes = (str) => str.replace(/"/g, "'");
10 | export const generateId = () => `_hb${s4() + s4()}`;
11 | export const camelToDash = (str) => str.replace(/([A-Z])/g, (val) => `-${val.toLowerCase()}`);
12 | export const dashToCamel = (str) => str.replace(/(\-[a-z])/g, (val) => val.toUpperCase().replace('-', ''));
13 | export function isObject(obj) {
14 | return typeof obj === 'object' && !(obj instanceof Array);
15 | }
16 | const s4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
17 | //# sourceMappingURL=util.js.map
--------------------------------------------------------------------------------
/dist/util.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,EAAY;IACrC,IAAI,KAAK,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC1B,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AACD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAC,EAAE,CAAA,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC9F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3G,MAAM,UAAU,QAAQ,CAAC,GAAQ;IAC/B,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;AAC5D,CAAC;AACD,MAAM,EAAE,GAAG,GAAE,EAAE,CAAA,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC"}
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
--------------------------------------------------------------------------------
/docs/assets/highlight.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --light-hl-0: #001080;
3 | --dark-hl-0: #9CDCFE;
4 | --light-hl-1: #000000;
5 | --dark-hl-1: #D4D4D4;
6 | --light-hl-2: #000000;
7 | --dark-hl-2: #C8C8C8;
8 | --light-hl-3: #008000;
9 | --dark-hl-3: #6A9955;
10 | --light-hl-4: #AF00DB;
11 | --dark-hl-4: #C586C0;
12 | --light-hl-5: #A31515;
13 | --dark-hl-5: #CE9178;
14 | --light-hl-6: #0000FF;
15 | --dark-hl-6: #569CD6;
16 | --light-hl-7: #0070C1;
17 | --dark-hl-7: #4FC1FF;
18 | --light-hl-8: #795E26;
19 | --dark-hl-8: #DCDCAA;
20 | --light-hl-9: #800000;
21 | --dark-hl-9: #808080;
22 | --light-hl-10: #800000;
23 | --dark-hl-10: #569CD6;
24 | --light-hl-11: #000000FF;
25 | --dark-hl-11: #D4D4D4;
26 | --light-hl-12: #800000;
27 | --dark-hl-12: #D7BA7D;
28 | --light-hl-13: #E50000;
29 | --dark-hl-13: #9CDCFE;
30 | --light-hl-14: #0451A5;
31 | --dark-hl-14: #CE9178;
32 | --light-hl-15: #0000FF;
33 | --dark-hl-15: #CE9178;
34 | --light-code-background: #FFFFFF;
35 | --dark-code-background: #1E1E1E;
36 | }
37 |
38 | @media (prefers-color-scheme: light) { :root {
39 | --hl-0: var(--light-hl-0);
40 | --hl-1: var(--light-hl-1);
41 | --hl-2: var(--light-hl-2);
42 | --hl-3: var(--light-hl-3);
43 | --hl-4: var(--light-hl-4);
44 | --hl-5: var(--light-hl-5);
45 | --hl-6: var(--light-hl-6);
46 | --hl-7: var(--light-hl-7);
47 | --hl-8: var(--light-hl-8);
48 | --hl-9: var(--light-hl-9);
49 | --hl-10: var(--light-hl-10);
50 | --hl-11: var(--light-hl-11);
51 | --hl-12: var(--light-hl-12);
52 | --hl-13: var(--light-hl-13);
53 | --hl-14: var(--light-hl-14);
54 | --hl-15: var(--light-hl-15);
55 | --code-background: var(--light-code-background);
56 | } }
57 |
58 | @media (prefers-color-scheme: dark) { :root {
59 | --hl-0: var(--dark-hl-0);
60 | --hl-1: var(--dark-hl-1);
61 | --hl-2: var(--dark-hl-2);
62 | --hl-3: var(--dark-hl-3);
63 | --hl-4: var(--dark-hl-4);
64 | --hl-5: var(--dark-hl-5);
65 | --hl-6: var(--dark-hl-6);
66 | --hl-7: var(--dark-hl-7);
67 | --hl-8: var(--dark-hl-8);
68 | --hl-9: var(--dark-hl-9);
69 | --hl-10: var(--dark-hl-10);
70 | --hl-11: var(--dark-hl-11);
71 | --hl-12: var(--dark-hl-12);
72 | --hl-13: var(--dark-hl-13);
73 | --hl-14: var(--dark-hl-14);
74 | --hl-15: var(--dark-hl-15);
75 | --code-background: var(--dark-code-background);
76 | } }
77 |
78 | :root[data-theme='light'] {
79 | --hl-0: var(--light-hl-0);
80 | --hl-1: var(--light-hl-1);
81 | --hl-2: var(--light-hl-2);
82 | --hl-3: var(--light-hl-3);
83 | --hl-4: var(--light-hl-4);
84 | --hl-5: var(--light-hl-5);
85 | --hl-6: var(--light-hl-6);
86 | --hl-7: var(--light-hl-7);
87 | --hl-8: var(--light-hl-8);
88 | --hl-9: var(--light-hl-9);
89 | --hl-10: var(--light-hl-10);
90 | --hl-11: var(--light-hl-11);
91 | --hl-12: var(--light-hl-12);
92 | --hl-13: var(--light-hl-13);
93 | --hl-14: var(--light-hl-14);
94 | --hl-15: var(--light-hl-15);
95 | --code-background: var(--light-code-background);
96 | }
97 |
98 | :root[data-theme='dark'] {
99 | --hl-0: var(--dark-hl-0);
100 | --hl-1: var(--dark-hl-1);
101 | --hl-2: var(--dark-hl-2);
102 | --hl-3: var(--dark-hl-3);
103 | --hl-4: var(--dark-hl-4);
104 | --hl-5: var(--dark-hl-5);
105 | --hl-6: var(--dark-hl-6);
106 | --hl-7: var(--dark-hl-7);
107 | --hl-8: var(--dark-hl-8);
108 | --hl-9: var(--dark-hl-9);
109 | --hl-10: var(--dark-hl-10);
110 | --hl-11: var(--dark-hl-11);
111 | --hl-12: var(--dark-hl-12);
112 | --hl-13: var(--dark-hl-13);
113 | --hl-14: var(--dark-hl-14);
114 | --hl-15: var(--dark-hl-15);
115 | --code-background: var(--dark-code-background);
116 | }
117 |
118 | .hl-0 { color: var(--hl-0); }
119 | .hl-1 { color: var(--hl-1); }
120 | .hl-2 { color: var(--hl-2); }
121 | .hl-3 { color: var(--hl-3); }
122 | .hl-4 { color: var(--hl-4); }
123 | .hl-5 { color: var(--hl-5); }
124 | .hl-6 { color: var(--hl-6); }
125 | .hl-7 { color: var(--hl-7); }
126 | .hl-8 { color: var(--hl-8); }
127 | .hl-9 { color: var(--hl-9); }
128 | .hl-10 { color: var(--hl-10); }
129 | .hl-11 { color: var(--hl-11); }
130 | .hl-12 { color: var(--hl-12); }
131 | .hl-13 { color: var(--hl-13); }
132 | .hl-14 { color: var(--hl-14); }
133 | .hl-15 { color: var(--hl-15); }
134 | pre, code { background: var(--code-background); }
135 |
--------------------------------------------------------------------------------
/docs/assets/navigation.js:
--------------------------------------------------------------------------------
1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5WVS3OCMBSF/0u61dZXH7rzMZ3ppo+RneM4IaQSjYlDkk6djv+9AYQEISndQc65Xw7hXlj9AIm/JZgAKGVCQiWxAB1whDLWawceKYrFndFuY3mg2rAnLAKTQQegmNAowQxMViVqqu1LLA0HUShElXPxVHn9wdN5fe6UoKyuy+AB1zNl2ibVWmWap/bXCqlIZZFKlz9XzENeT5SutsoSwK2n+iaXc8KoPx4NeyNrb63OlGbi5A+GcblQG8RZdlmCvmBCYFiiCkP1qYYDixHmuwgnozB4GLotIIoN4VMxJAlnF0IuV+sf7OeIsLc+l331HLmLOfJUbjHDCZTYWV4Yagy7nYQ80YYOz5ZbNdQydTZOXM4odH9Xy6a21Iv/7+li97Q4uAY0bNsNXR2txc1FbBujNh1WmpJlfPVwJto7Qftpsg1OR+v1SH1XhVm2q5C98WP/vu242Ejn1NgnpySh9SNLV1udFdLfORrwBRSNs5NxLI9vgLQc8HnqdZIsT4uBeomcIGPxcIh4C3cYSSelMHgYOyXkM5vx6OSkGIuHk+AjhQgvuNKv+UPxyi/2Ctjgbfh0rH8Byzk2xrcHAAA="
--------------------------------------------------------------------------------
/docs/assets/search.js:
--------------------------------------------------------------------------------
1 | window.searchData = "data:application/octet-stream;base64,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";
--------------------------------------------------------------------------------
/docs/variables/hobo._context.html:
--------------------------------------------------------------------------------
1 | _context | hobo-js
2 |
3 |
4 |
5 |
7 |
8 | - Preparing search index...
9 | - The search index is not available
hobo-js
10 |
11 |
12 |
13 |
14 |
18 |
Variable _context
19 |
_context: HoboContext = ...
22 |
47 |
49 |
--------------------------------------------------------------------------------
/examples/_test.ts:
--------------------------------------------------------------------------------
1 | import { attach, doc, generate } from '../src/hobo';
2 | import { builders } from '../src/tag-builder';
3 |
4 | const { div, img } = builders;
5 |
6 | console.log(generate(img!.id('src').b()))
7 | console.log(generate(img!.as('color', 'red').b()))
8 |
--------------------------------------------------------------------------------
/examples/generated/readme-1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | My Page Title
6 |
17 |
18 |
19 |
20 |
I'm a child of div.wrapper
21 |
And so am I
22 |
23 |
Click me
24 |
25 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/generated/tag-attributes.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/generated/tag-classes.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/examples/generated/tag-inline-styles.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/generated/tag-scripts.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/examples/generated/tag-styles.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/hobo-in-js.js:
--------------------------------------------------------------------------------
1 | const { builders } = require('../dist/hobo.js');
2 |
3 | console.log(builders.div());
--------------------------------------------------------------------------------
/examples/readme-1.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, doc, generate } from '../src/hobo';
4 |
5 | const { div, p, span, b, script, button, style, a, hr } = builders;
6 |
7 | // Create a document. It will create the html, head and body tags. A title will also be added to the head.
8 | // NOTE that doc, automatically attaches the body (read more on attaching below)
9 | const myPage = doc('My Page Title');
10 |
11 | // This will create a style tag with the given css definitions inside
12 | myPage.head.append(
13 | style({
14 | '.wrapper': {
15 | background: 'black',
16 | display: 'flex',
17 | alignItems: 'center',
18 | justifyContent: 'center',
19 | ':hover': {
20 | background: 'red'
21 | }
22 | },
23 | }),
24 | );
25 |
26 | // Creates a `div` with class wrapper, and 3 children (p, b, button).
27 | // `.a` indicates hobo to attach the `div` to the currently attached tag
28 | // you can attach manually to any tag, but by calling `doc`, the `body` will be attached
29 | div.a.addClass('wrapper').build(
30 | p("I'm a child of div.wrapper"),
31 | b.addStyle('color', 'aliceblue')('And so am I'),
32 | hr,
33 | a.addAttr('href', 'http://example.com').b('Click me'),
34 | button.id('button-id').b("I'm also a child"),
35 | );
36 |
37 | // The code inside the function will be inserted into a script tag
38 | script.a(() => {
39 | const btn = document.querySelector('#button-id');
40 | });
41 |
42 | fs.writeFileSync(path.join(__dirname, 'generated/readme-1.html'), generate(myPage.doc));
43 |
--------------------------------------------------------------------------------
/examples/tag-attributes.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, generate } from '../src/hobo';
4 |
5 | const { a } = builders;
6 |
7 | // Add single attribute
8 | const root = a
9 | .aa('href', 'https://example.com')
10 | // Add class names directly
11 | .am({ href: 'https://example.com', tooltip: 'Go to website' });
12 |
13 | fs.writeFileSync(path.join(__dirname, 'generated/tag-attributes.html'), generate(root.b()));
14 |
--------------------------------------------------------------------------------
/examples/tag-classes.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, doc, generate } from '../src/hobo';
4 |
5 | const { div } = builders;
6 |
7 | // Add class names using builder helper methods
8 | const root = div.ac('card-wrapper').append(div.ac('card', 'centered'));
9 |
10 | // Add class names directly
11 | root.attr.className.add('card-wrapper');
12 |
13 | fs.writeFileSync(path.join(__dirname, 'generated/tag-classes.html'), generate(root.b()));
--------------------------------------------------------------------------------
/examples/tag-inline-styles.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, generate } from '../src/hobo';
4 |
5 | const { a } = builders;
6 |
7 | // Add single style
8 | const root = a
9 | .as('color', 'bisque')
10 | // Add multiple styles at once
11 | .ss({ color: 'black', fontWeight: 'bold' });
12 |
13 | fs.writeFileSync(path.join(__dirname, 'generated/tag-inline-styles.html'), generate(root.b()));
14 |
--------------------------------------------------------------------------------
/examples/tag-script.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, generate } from '../src/hobo';
4 |
5 | const { div, script } = builders;
6 |
7 | const root = div.append(
8 | script(() => {
9 | const rootDiv = document.querySelector('div');
10 | }),
11 | );
12 |
13 | fs.writeFileSync(path.join(__dirname, 'generated/tag-scripts.html'), generate(root.b()));
14 |
--------------------------------------------------------------------------------
/examples/tag-style.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import * as fs from 'fs';
3 | import { builders, generate } from '../src/hobo';
4 |
5 | const { div, style } = builders;
6 |
7 | const root = div.append(
8 | style(
9 | {
10 | body: {
11 | backgroundColor: 'red',
12 | },
13 | },
14 | {
15 | '.some-class': {
16 | color: 'blue',
17 | },
18 | },
19 | ),
20 | );
21 |
22 | fs.writeFileSync(path.join(__dirname, 'generated/tag-styles.html'), generate(root.b()));
23 |
--------------------------------------------------------------------------------
/hobo-header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nombrekeff/hobo-js/1cd54a3fe83bbd15820fb2e05fb6736a35efba6b/hobo-header.png
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | // Sync object
2 | const config= {
3 | verbose: true,
4 | transform: {
5 | '^.+\\.tsx?$': 'ts-jest',
6 | },
7 | };
8 | module.exports= config;
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hobo-js",
3 | "version": "1.0.2",
4 | "description": "A little utility to generate html inside your js/ts code",
5 | "main": "dist/hobo.js",
6 | "module": "dist/hobo.mjs",
7 | "unpkg": "dist/hobo.umd.min.js",
8 | "types": "dist/types/hobo.d.ts",
9 | "files": [
10 | "dist"
11 | ],
12 | "scripts": {
13 | "test": "jest --coverage",
14 | "clean": "rm -fr dist",
15 | "build": "npm run clean && tsc -d --project tsconfig.build.json && build:docs && npm run bundle:esm && npm run bundle:esm:min && npm run bundle:umd && npm run bundle:umd:min",
16 | "bundle:esm": "rollup dist/hobo.js --file dist/hobo.mjs --format esm",
17 | "bundle:esm:min": "terser --ecma 6 --compress --mangle --module -o dist/hobo.min.mjs -- dist/hobo.mjs && gzip -9 -c dist/hobo.min.mjs > dist/hobo.min.mjs.gz",
18 | "bundle:umd": "rollup dist/hobo.js --file dist/hobo.umd.js --format umd --name sayHello",
19 | "bundle:umd:min": "terser --ecma 6 --compress --mangle -o dist/hobo.umd.min.js -- dist/hobo.umd.js && gzip -9 -c dist/hobo.umd.min.js > dist/hobo.umd.min.js.gz",
20 | "build:docs": "typedoc --out docs src/*.ts"
21 | },
22 | "keywords": [
23 | "js",
24 | "ts",
25 | "generate",
26 | "html",
27 | "from",
28 | "code",
29 | "typed",
30 | "template",
31 | "build",
32 | "in-code"
33 | ],
34 | "author": "nombrekeff",
35 | "repository": {
36 | "git": "https://github.com/nombrekeff/hobo-js"
37 | },
38 | "license": "ISC",
39 | "devDependencies": {
40 | "@types/jest": "^29.5.5",
41 | "@types/node": "^20.7.0",
42 | "jest": "^29.7.0",
43 | "rollup": "^3.29.4",
44 | "terser": "^5.21.0",
45 | "ts-jest": "^29.1.1",
46 | "ts-loader": "^9.4.4",
47 | "typedoc": "^0.25.1",
48 | "typescript": "^5.2.2",
49 | "webpack": "^5.88.2",
50 | "webpack-cli": "^5.1.4"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/scripts/generate_api_docs.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const { exec } = require("child_process");
4 |
5 | const jsFilesFoldPath = path.join(__dirname, '../dist');
6 | const output = path.join(__dirname, '../docs');
7 | const makeDocsCommand = (name, path) => `jsdoc2md -f ${path}/${name}.js > ${output}/${name}.api.md`;
8 |
9 | const ignoredFiles = [
10 | 'types',
11 | 'generation',
12 | 'util.js',
13 | 'tag-names.js',
14 | 'css-property-values.js',
15 | 'css-properties.js',
16 | 'css-property-values.js',
17 | ];
18 |
19 | function processFolder(folderPath) {
20 | const inFiles = fs.readdirSync(folderPath);
21 |
22 | for (const file of inFiles) {
23 | // Skip map files
24 | if (file.includes('map')) continue;
25 | if (ignoredFiles.includes(file)) continue;
26 |
27 | const filePath = path.join(folderPath, file);
28 | const fstat = fs.statSync(filePath);
29 |
30 | if (fstat.isDirectory()) {
31 | processFolder(filePath);
32 | }
33 | else {
34 | const extension = path.extname(filePath);
35 | const name = path.basename(filePath, extension).replace(extension, '');
36 |
37 | const command = makeDocsCommand(name, folderPath);
38 | exec(command, (error, _, stderr) => {
39 | if (error) {
40 | console.log(`error: ${error.message}`);
41 | return;
42 | }
43 | if (stderr) {
44 | console.log(`stderr: ${stderr}`);
45 | return;
46 | }
47 | });
48 | }
49 | }
50 |
51 | }
52 |
53 | fs.rmSync(output, {recursive: true});
54 | fs.mkdirSync(output);
55 |
56 | processFolder(jsFilesFoldPath);
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/attributes.ts:
--------------------------------------------------------------------------------
1 | import { ClassName } from './class-name';
2 | import { StyleSet } from './style';
3 |
4 | /**
5 | * Represents a tag's attribute set.
6 | */
7 | export class AttrSet {
8 | className: ClassName = new ClassName();
9 | id?: string;
10 | style: StyleSet = new StyleSet();
11 |
12 | additionalAttributes: { [key: string]: string } = {};
13 |
14 | copy() {
15 | const newSet = new AttrSet();
16 | newSet.className = this.className.copy();
17 | newSet.id = this.id;
18 | newSet.style = this.style.copy();
19 | newSet.additionalAttributes = { ...this.additionalAttributes };
20 | return newSet;
21 | }
22 |
23 | /** Set single attribute */
24 | set(key: string, value: string): AttrSet {
25 | this.additionalAttributes[key] = value;
26 | return this;
27 | }
28 |
29 | /** Remove attributes */
30 | remove(...attrs: string[]): AttrSet {
31 | for (const cn of attrs) {
32 | delete this.additionalAttributes[cn];
33 | }
34 | return this;
35 | }
36 |
37 | /** Check if an attribute is set */
38 | has(key: string): boolean {
39 | return key in this.additionalAttributes;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/class-name.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents a tag's class list.
3 | */
4 | export class ClassName {
5 | classNames: string[] = [];
6 |
7 | constructor(classNames: string[] = []) {
8 | this.classNames = classNames;
9 | }
10 |
11 | copy() {
12 | const newClassName = new ClassName();
13 | newClassName.classNames = [...this.classNames];
14 | return newClassName;
15 | }
16 |
17 | /**
18 | * Returns a string of all the class names separated by spaces.
19 | */
20 | raw(): string {
21 | return this.classNames.join(' ');
22 | }
23 |
24 | /** Add one or more class names */
25 | add(...classNames: string[]): ClassName {
26 | for (const cn of classNames) {
27 | if (!this.has(cn)) {
28 | this.classNames.push(cn);
29 | }
30 | }
31 |
32 | return this;
33 | }
34 |
35 | /** Remove one or more class names */
36 | remove(...classNames: string[]): ClassName {
37 | for (const cn of classNames) {
38 | if (!this.has(cn)) return this;
39 |
40 | const index = this.classNames.indexOf(cn);
41 | this.classNames.splice(index, 1);
42 | }
43 |
44 | return this;
45 | }
46 |
47 | /** Check if a class name is present. */
48 | has(str: string): boolean {
49 | return this.classNames.includes(str);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/custom-types/colors.ts:
--------------------------------------------------------------------------------
1 | export type NamedColor = 'black'|
2 | 'silver'|
3 | 'gray'|
4 | 'white'|
5 | 'maroon'|
6 | 'red'|
7 | 'purple'|
8 | 'fuchsia'|
9 | 'green'|
10 | 'lime'|
11 | 'olive'|
12 | 'yellow'|
13 | 'navy'|
14 | 'blue'|
15 | 'teal'|
16 | 'aqua'|
17 | 'aliceblue'|
18 | 'antiquewhite'|
19 | 'aqua'|
20 | 'aquamarine'|
21 | 'azure'|
22 | 'beige'|
23 | 'bisque'|
24 | 'black'|
25 | 'blanchedalmond'|
26 | 'blue'|
27 | 'blueviolet'|
28 | 'brown'|
29 | 'burlywood'|
30 | 'cadetblue'|
31 | 'chartreuse'|
32 | 'chocolate'|
33 | 'coral'|
34 | 'cornflowerblue'|
35 | 'cornsilk'|
36 | 'crimson'|
37 | 'cyan'|
38 | 'darkblue'|
39 | 'darkcyan'|
40 | 'darkgoldenrod'|
41 | 'darkgray'|
42 | 'darkgreen'|
43 | 'darkgrey'|
44 | 'darkkhaki'|
45 | 'darkmagenta'|
46 | 'darkolivegreen'|
47 | 'darkorange'|
48 | 'darkorchid'|
49 | 'darkred'|
50 | 'darksalmon'|
51 | 'darkseagreen'|
52 | 'darkslateblue'|
53 | 'darkslategray'|
54 | 'darkslategrey'|
55 | 'darkturquoise'|
56 | 'darkviolet'|
57 | 'deeppink'|
58 | 'deepskyblue'|
59 | 'dimgray'|
60 | 'dimgrey'|
61 | 'dodgerblue'|
62 | 'firebrick'|
63 | 'floralwhite'|
64 | 'forestgreen'|
65 | 'fuchsia'|
66 | 'gainsboro'|
67 | 'ghostwhite'|
68 | 'gold'|
69 | 'goldenrod'|
70 | 'gray'|
71 | 'green'|
72 | 'greenyellow'|
73 | 'grey'|
74 | 'honeydew'|
75 | 'hotpink'|
76 | 'indianred'|
77 | 'indigo'|
78 | 'ivory'|
79 | 'khaki'|
80 | 'lavender'|
81 | 'lavenderblush'|
82 | 'lawngreen'|
83 | 'lemonchiffon'|
84 | 'lightblue'|
85 | 'lightcoral'|
86 | 'lightcyan'|
87 | 'lightgoldenrodyellow'|
88 | 'lightgray'|
89 | 'lightgreen'|
90 | 'lightgrey'|
91 | 'lightpink'|
92 | 'lightsalmon'|
93 | 'lightseagreen'|
94 | 'lightskyblue'|
95 | 'lightslategray'|
96 | 'lightslategrey'|
97 | 'lightsteelblue'|
98 | 'lightyellow'|
99 | 'lime'|
100 | 'limegreen'|
101 | 'linen'|
102 | 'magenta'|
103 | 'maroon'|
104 | 'mediumaquamarine'|
105 | 'mediumblue'|
106 | 'mediumorchid'|
107 | 'mediumpurple'|
108 | 'mediumseagreen'|
109 | 'mediumslateblue'|
110 | 'mediumspringgreen'|
111 | 'mediumturquoise'|
112 | 'mediumvioletred'|
113 | 'midnightblue'|
114 | 'mintcream'|
115 | 'mistyrose'|
116 | 'moccasin'|
117 | 'navajowhite'|
118 | 'navy'|
119 | 'oldlace'|
120 | 'olive'|
121 | 'olivedrab'|
122 | 'orange'|
123 | 'orangered'|
124 | 'orchid'|
125 | 'palegoldenrod'|
126 | 'palegreen'|
127 | 'paleturquoise'|
128 | 'palevioletred'|
129 | 'papayawhip'|
130 | 'peachpuff'|
131 | 'peru'|
132 | 'pink'|
133 | 'plum'|
134 | 'powderblue'|
135 | 'purple'|
136 | 'rebeccapurple'|
137 | 'red'|
138 | 'rosybrown'|
139 | 'royalblue'|
140 | 'saddlebrown'|
141 | 'salmon'|
142 | 'sandybrown'|
143 | 'seagreen'|
144 | 'seashell'|
145 | 'sienna'|
146 | 'silver'|
147 | 'skyblue'|
148 | 'slateblue'|
149 | 'slategray'|
150 | 'slategrey'|
151 | 'snow'|
152 | 'springgreen'|
153 | 'steelblue'|
154 | 'tan'|
155 | 'teal'|
156 | 'thistle'|
157 | 'tomato'|
158 | 'turquoise'|
159 | 'violet'|
160 | 'wheat'|
161 | 'white'|
162 | 'whitesmoke'|
163 | 'yellow'|
164 | 'yellowgreen';
--------------------------------------------------------------------------------
/src/custom-types/css-properties.ts:
--------------------------------------------------------------------------------
1 | export type CssProperty =
2 | | 'color'
3 | | 'border'
4 | | 'margin'
5 | | 'fontStyle'
6 | | 'transform'
7 | | 'backgroundColor'
8 | | 'alignContent'
9 | | 'alignItems'
10 | | 'alignSelf'
11 | | 'all'
12 | | 'animation'
13 | | 'animationDelay'
14 | | 'animationDirection'
15 | | 'animationDuration'
16 | | 'animationFillMode'
17 | | 'animationIterationCount'
18 | | 'animationName'
19 | | 'animationPlayState'
20 | | 'animationTimingFunction'
21 | | 'backfaceVisibility'
22 | | 'background'
23 | | 'backgroundAttachment'
24 | | 'backgroundBlendMode'
25 | | 'backgroundClip'
26 | | 'backgroundColor'
27 | | 'backgroundImage'
28 | | 'backgroundOrigin'
29 | | 'backgroundPosition'
30 | | 'backgroundRepeat'
31 | | 'backgroundSize'
32 | | 'border'
33 | | 'borderBottom'
34 | | 'borderBottomColor'
35 | | 'borderBottomLeftRadius'
36 | | 'borderBottomRightRadius'
37 | | 'borderBottomStyle'
38 | | 'borderBottomWidth'
39 | | 'borderCollapse'
40 | | 'borderColor'
41 | | 'borderImage'
42 | | 'borderImageOutset'
43 | | 'borderImageRepeat'
44 | | 'borderImageSlice'
45 | | 'borderImageSource'
46 | | 'borderImageWidth'
47 | | 'borderLeft'
48 | | 'borderLeftColor'
49 | | 'borderLeftStyle'
50 | | 'borderLeftWidth'
51 | | 'borderRadius'
52 | | 'borderRight'
53 | | 'borderRightColor'
54 | | 'borderRightStyle'
55 | | 'borderRightWidth'
56 | | 'borderSpacing'
57 | | 'borderStyle'
58 | | 'borderTop'
59 | | 'borderTopColor'
60 | | 'borderTopLeftRadius'
61 | | 'borderTopRightRadius'
62 | | 'borderTopStyle'
63 | | 'borderTopWidth'
64 | | 'borderWidth'
65 | | 'bottom'
66 | | 'boxShadow'
67 | | 'boxSizing'
68 | | 'captionSide'
69 | | 'caretColor'
70 | | '@charset'
71 | | 'clear'
72 | | 'clip'
73 | | 'clipPath'
74 | | 'color'
75 | | 'columnCount'
76 | | 'columnFill'
77 | | 'columnGap'
78 | | 'columnRule'
79 | | 'columnRuleColor'
80 | | 'columnRuleStyle'
81 | | 'columnRuleWidth'
82 | | 'columnSpan'
83 | | 'columnWidth'
84 | | 'columns'
85 | | 'content'
86 | | 'counterIncrement'
87 | | 'counterReset'
88 | | 'cursor'
89 | | 'direction'
90 | | 'display'
91 | | 'emptyCells'
92 | | 'filter'
93 | | 'flex'
94 | | 'flexBasis'
95 | | 'flexDirection'
96 | | 'flexFlow'
97 | | 'flexGrow'
98 | | 'flexShrink'
99 | | 'flexWrap'
100 | | 'float'
101 | | 'font'
102 | | '@fontFace'
103 | | 'fontFamily'
104 | | 'fontKerning'
105 | | 'fontSize'
106 | | 'fontSizeAdjust'
107 | | 'fontStretch'
108 | | 'fontStyle'
109 | | 'fontVariant'
110 | | 'fontWeight'
111 | | 'grid'
112 | | 'gridArea'
113 | | 'gridAutoColumns'
114 | | 'gridAutoFlow'
115 | | 'gridAutoRows'
116 | | 'gridColumn'
117 | | 'gridColumnEnd'
118 | | 'gridColumnGap'
119 | | 'gridColumnStart'
120 | | 'gridGap'
121 | | 'gridRow'
122 | | 'gridRowEnd'
123 | | 'gridRowGap'
124 | | 'gridRowStart'
125 | | 'gridTemplate'
126 | | 'gridTemplateAreas'
127 | | 'gridTemplateColumns'
128 | | 'gridTemplateRows'
129 | | 'height'
130 | | 'hyphens'
131 | | '@import'
132 | | 'justifyContent'
133 | | '@keyframes'
134 | | 'left'
135 | | 'letterSpacing'
136 | | 'lineHeight'
137 | | 'listStyle'
138 | | 'listStyleImage'
139 | | 'listStylePosition'
140 | | 'listStyleType'
141 | | 'margin'
142 | | 'marginBottom'
143 | | 'marginLeft'
144 | | 'marginRight'
145 | | 'marginTop'
146 | | 'maxHeight'
147 | | 'maxWidth'
148 | | '@media'
149 | | 'minHeight'
150 | | 'minWidth'
151 | | 'objectFit'
152 | | 'objectPosition'
153 | | 'opacity'
154 | | 'order'
155 | | 'outline'
156 | | 'outlineColor'
157 | | 'outlineOffset'
158 | | 'outlineStyle'
159 | | 'outlineWidth'
160 | | 'overflow'
161 | | 'overflowX'
162 | | 'overflowY'
163 | | 'padding'
164 | | 'paddingBottom'
165 | | 'paddingLeft'
166 | | 'paddingRight'
167 | | 'paddingTop'
168 | | 'pageBreakAfter'
169 | | 'pageBreakBefore'
170 | | 'pageBreakInside'
171 | | 'perspective'
172 | | 'perspectiveOrigin'
173 | | 'pointerEvents'
174 | | 'position'
175 | | 'quotes'
176 | | 'right'
177 | | 'scrollBehavior'
178 | | 'tableLayout'
179 | | 'textAlign'
180 | | 'textAlignLast'
181 | | 'textDecoration'
182 | | 'textDecorationColor'
183 | | 'textDecorationLine'
184 | | 'textDecorationStyle'
185 | | 'textIndent'
186 | | 'textJustify'
187 | | 'textOverflow'
188 | | 'textShadow'
189 | | 'textTransform'
190 | | 'top'
191 | | 'transform'
192 | | 'transformOrigin'
193 | | 'transformStyle'
194 | | 'transition'
195 | | 'transitionDelay'
196 | | 'transitionDuration'
197 | | 'transitionProperty'
198 | | 'transitionTimingFunction'
199 | | 'userSelect'
200 | | 'verticalAlign'
201 | | 'visibility'
202 | | 'whiteSpace'
203 | | 'width'
204 | | 'wordBreak'
205 | | 'wordSpacing'
206 | | 'wordWrap'
207 | | 'writingMode'
208 | | 'zIndex'
209 | | (string & {});
210 |
--------------------------------------------------------------------------------
/src/custom-types/css-property-values.ts:
--------------------------------------------------------------------------------
1 | import { NamedColor } from './colors';
2 |
3 | // Create script to collect all the values, wherever posible.
4 | // Scrap https://dofactory.com/css/properties#list or other site, and get all single word options
5 |
6 | export type PickPropertyValues = T extends 'color'
7 | ? ColorOptions
8 | : T extends 'alignContent'
9 | ? AlignContentOptions
10 | : T extends 'alignItems'
11 | ? AlignItemsOptions
12 | : T extends 'alignSelf'
13 | ? AlignSelfOptions
14 | : T extends 'all'
15 | ? AllOptions
16 | : T extends 'accentColor'
17 | ? ColorOptions
18 | : T extends 'animationDirection'
19 | ? AnimationDirectionOptions
20 | : T extends 'animationFillMode'
21 | ? AnimationFillModeOptions
22 | : T extends 'animationPlayState'
23 | ? AnimationPlayStateOptions
24 | : T extends 'animationPlayState'
25 | ? AnimationPlayStateOptions
26 | : T extends 'borderStyle'
27 | ? BorderStyleOptions
28 | : T extends 'background'
29 | ? ColorOptions
30 | : T extends 'backgroundColor'
31 | ? ColorOptions
32 | : T extends 'backgroundImage'
33 | ? BackgroundImageOptions
34 | : T extends 'backgroundRepeat'
35 | ? BackgroundRepeatOptions
36 | : T extends 'backgroundAttachment'
37 | ? BackgroundAttachmentOptions
38 | : T extends 'backgroundPosition'
39 | ? BackgroundPositionOptions
40 | : T extends 'position'
41 | ? PPositionOptions
42 | : T extends 'transform'
43 | ? TransformOptions
44 | : T extends 'fontStyle'
45 | ? FontStyleOptions
46 | : T extends 'fontWeight'
47 | ? FontWeightOptions
48 | : T extends 'flexDirection'
49 | ? FlexDirectionOptions
50 | : T extends 'zIndex'
51 | ? Number
52 | : T extends 'top'
53 | ? Number
54 | : T extends 'display'
55 | ? DisplayOptions
56 | : T extends 'bottom'
57 | ? Number
58 | : T extends 'left'
59 | ? Number
60 | : T extends 'right'
61 | ? Number
62 | : string & {};
63 |
64 | export type CommonOptions = 'initial' | 'inherit' | (string & {});
65 | export type ColorOptions = NamedColor | (string & {});
66 | export type AlignContentOptions =
67 | | 'flex-wrap'
68 | | 'stretch'
69 | | 'center'
70 | | 'flex-start'
71 | | 'flex-end'
72 | | 'space-between'
73 | | 'space-around'
74 | | CommonOptions;
75 | export type AlignItemsOptions = 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline' | CommonOptions;
76 | export type DisplayOptions =
77 | | 'inline'
78 | | 'block'
79 | | 'contents'
80 | | 'flex'
81 | | 'grid'
82 | | 'inline-block'
83 | | 'inline-flex'
84 | | 'inline-grid'
85 | | 'inline-table'
86 | | 'list-item'
87 | | 'run-in'
88 | | 'table'
89 | | 'table-caption'
90 | | 'table-column-group'
91 | | 'table-header-group'
92 | | 'table-footer-group'
93 | | 'table-row-group'
94 | | 'table-cell'
95 | | 'table-column'
96 | | 'table-row'
97 | | 'none'
98 | | CommonOptions;
99 | type AlignSelfOptions = 'auto' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline' | CommonOptions;
100 | type AllOptions = CommonOptions | 'unset';
101 | type AnimationDirectionOptions =
102 | | 'normal'
103 | | 'reverse'
104 | | 'alternate'
105 | | 'alternate-reverse'
106 | | 'initial'
107 | | 'inherit'
108 | | (string & {});
109 | type AnimationFillModeOptions = 'none' | 'forwards' | 'backwards' | 'both' | CommonOptions;
110 | type AnimationPlayStateOptions = 'paused' | 'running' | CommonOptions;
111 | type BorderStyleOptions =
112 | | 'none'
113 | | 'no'
114 | | 'none'
115 | | 'hidden'
116 | | 'dotted'
117 | | 'dashed'
118 | | 'solid'
119 | | 'double'
120 | | 'groove'
121 | | 'ridge'
122 | | 'inset'
123 | | 'outset'
124 | | CommonOptions;
125 | export type BackgroundImageOptions =
126 | | 'url()'
127 | | 'none'
128 | | 'conic-gradient()'
129 | | 'linear-gradient()'
130 | | 'radial-gradient()'
131 | | 'repeating-conic-gradient()'
132 | | 'repeating-linear-gradient()'
133 | | 'repeating-radial-gradient()'
134 | | 'initial'
135 | | 'inherit';
136 | type BackgroundRepeatOptions =
137 | | 'repeat'
138 | | 'no'
139 | | 'repeat'
140 | | 'repeat-x'
141 | | 'repeat-y'
142 | | 'no-repeat'
143 | | 'space'
144 | | 'round'
145 | | CommonOptions;
146 | type BackgroundAttachmentOptions = 'scroll' | 'no' | 'scroll' | 'fixed' | 'local' | CommonOptions;
147 | type BackgroundPositionOptions =
148 | | 'left top'
149 | | 'left center'
150 | | 'left bottom'
151 | | 'right top'
152 | | 'right center'
153 | | 'right bottom'
154 | | 'center top'
155 | | 'center center'
156 | | 'center bottom'
157 | | 'inherit'
158 | | 'initial'
159 | | (string & {});
160 | export type PPositionOptions = 'static' | 'fixed' | 'absolute' | 'relative' | 'sticky' | CommonOptions;
161 | export type TransformOptions =
162 | | 'none'
163 | | 'matrix(n,n,n,n,n,n)'
164 | | 'matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n)'
165 | | 'translate(x,y)'
166 | | 'translate3d(x,y,z)'
167 | | 'translateX(x)'
168 | | 'translateY(y)'
169 | | 'translateZ(z)'
170 | | 'scale(x,y)'
171 | | 'scale3d(x,y,z)'
172 | | 'scaleX(x)'
173 | | 'scaleY(y)'
174 | | 'scaleZ(z)'
175 | | 'rotate(angle)'
176 | | 'rotate3d(x,y,z,angle)'
177 | | 'rotateX(angle)'
178 | | 'rotateY(angle)'
179 | | 'rotateZ(angle)'
180 | | 'skew(x-angle,y-angle)'
181 | | 'skewX(angle)'
182 | | 'skewY(angle)'
183 | | 'perspective(n)'
184 | | CommonOptions;
185 | export type FontWeightOptions =
186 | | 'normal'
187 | | 'bold'
188 | | 'bolder'
189 | | 'lighter'
190 | | '100'
191 | | '200'
192 | | '300'
193 | | '400'
194 | | '500'
195 | | '600'
196 | | '700'
197 | | '800'
198 | | '900'
199 | | CommonOptions;
200 | export type FontStyleOptions = 'normal' | 'italic' | 'oblique' | CommonOptions;
201 | export type FlexDirectionOptions = 'row' | 'column' | 'row-reverse' | 'column-reverse' | CommonOptions;
202 |
--------------------------------------------------------------------------------
/src/custom-types/tag-names.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @export
3 | * List of all known self-closing HTML tags
4 | */
5 | export const selfClosingTags = [
6 | 'area',
7 | 'base',
8 | 'br',
9 | 'col',
10 | 'embed',
11 | 'hr',
12 | 'img',
13 | 'input',
14 | 'link',
15 | 'meta',
16 | 'param',
17 | 'source',
18 | 'track',
19 | 'wbr',
20 | ];
21 |
22 | /** List of all known closing HTML tags */
23 | export const closingTags = [
24 | 'a',
25 | 'abbr',
26 | 'acronym',
27 | 'address',
28 | 'article',
29 | 'aside',
30 | 'audio',
31 | 'b',
32 | 'basefont',
33 | 'bdi',
34 | 'bdo',
35 | 'big',
36 | 'blockquote',
37 | 'body',
38 | 'button',
39 | 'canvas',
40 | 'caption',
41 | 'center',
42 | 'cite',
43 | 'code',
44 | 'colgroup',
45 | 'data',
46 | 'datalist',
47 | 'dd',
48 | 'del',
49 | 'details',
50 | 'dfn',
51 | 'dialog',
52 | 'div',
53 | 'dl',
54 | 'dt',
55 | 'em',
56 | 'fieldset',
57 | 'figcaption',
58 | 'figure',
59 | 'footer',
60 | 'form',
61 | 'h1',
62 | 'h2',
63 | 'h3',
64 | 'h4',
65 | 'h5',
66 | 'h6',
67 | 'head',
68 | 'header',
69 | 'html',
70 | 'i',
71 | 'iframe',
72 | 'ins',
73 | 'kbd',
74 | 'label',
75 | 'legend',
76 | 'li',
77 | 'main',
78 | 'map',
79 | 'mark',
80 | 'meter',
81 | 'nav',
82 | 'noscript',
83 | 'object',
84 | 'ol',
85 | 'optgroup',
86 | 'option',
87 | 'output',
88 | 'p',
89 | 'picture',
90 | 'pre',
91 | 'progress',
92 | 'q',
93 | 'rp',
94 | 'rt',
95 | 'ruby',
96 | 's',
97 | 'samp',
98 | 'script',
99 | 'section',
100 | 'select',
101 | 'small',
102 | 'span',
103 | 'strong',
104 | 'style',
105 | 'sub',
106 | 'summary',
107 | 'sup',
108 | 'svg',
109 | 'table',
110 | 'tbody',
111 | 'td',
112 | 'template',
113 | 'textarea',
114 | 'tfoot',
115 | 'th',
116 | 'thead',
117 | 'time',
118 | 'title',
119 | 'tr',
120 | 'u',
121 | 'ul',
122 | 'var',
123 | 'video',
124 | ];
125 |
126 | /** List of all known HTML tags */
127 | export const allKnownTags = [
128 | 'area',
129 | 'base',
130 | 'br',
131 | 'col',
132 | 'embed',
133 | 'hr',
134 | 'img',
135 | 'input',
136 | 'link',
137 | 'meta',
138 | 'param',
139 | 'source',
140 | 'track',
141 | 'wbr',
142 |
143 | 'a',
144 | 'abbr',
145 | 'acronym',
146 | 'address',
147 | 'article',
148 | 'aside',
149 | 'audio',
150 | 'b',
151 | 'basefont',
152 | 'bdi',
153 | 'bdo',
154 | 'big',
155 | 'blockquote',
156 | 'body',
157 | 'button',
158 | 'canvas',
159 | 'caption',
160 | 'center',
161 | 'cite',
162 | 'code',
163 | 'colgroup',
164 | 'data',
165 | 'datalist',
166 | 'dd',
167 | 'del',
168 | 'details',
169 | 'dfn',
170 | 'dialog',
171 | 'div',
172 | 'dl',
173 | 'dt',
174 | 'em',
175 | 'fieldset',
176 | 'figcaption',
177 | 'figure',
178 | 'footer',
179 | 'form',
180 | 'h1',
181 | 'h2',
182 | 'h3',
183 | 'h4',
184 | 'h5',
185 | 'h6',
186 | 'head',
187 | 'header',
188 | 'html',
189 | 'i',
190 | 'iframe',
191 | 'ins',
192 | 'kbd',
193 | 'label',
194 | 'legend',
195 | 'li',
196 | 'main',
197 | 'map',
198 | 'mark',
199 | 'meter',
200 | 'nav',
201 | 'noscript',
202 | 'object',
203 | 'ol',
204 | 'optgroup',
205 | 'option',
206 | 'output',
207 | 'p',
208 | 'picture',
209 | 'pre',
210 | 'progress',
211 | 'q',
212 | 'rp',
213 | 'rt',
214 | 'ruby',
215 | 's',
216 | 'samp',
217 | 'script',
218 | 'section',
219 | 'select',
220 | 'small',
221 | 'span',
222 | 'strong',
223 | 'style',
224 | 'sub',
225 | 'summary',
226 | 'sup',
227 | 'svg',
228 | 'table',
229 | 'tbody',
230 | 'td',
231 | 'template',
232 | 'textarea',
233 | 'tfoot',
234 | 'th',
235 | 'thead',
236 | 'time',
237 | 'title',
238 | 'tr',
239 | 'u',
240 | 'ul',
241 | 'var',
242 | 'video',
243 | ];
244 |
245 | export const storableTags = ['style', 'script'];
246 |
247 | /** @export @type {TagName} */
248 | export type TagName = ValidTagName | (string & {});
249 | /** @type {ValidTagName} */
250 | export type ValidTagName =
251 | | 'a'
252 | | 'abbr'
253 | | 'acronym'
254 | | 'address'
255 | | 'area'
256 | | 'article'
257 | | 'aside'
258 | | 'audio'
259 | | 'b'
260 | | 'base'
261 | | 'basefont'
262 | | 'bdi'
263 | | 'bdo'
264 | | 'big'
265 | | 'blockquote'
266 | | 'body'
267 | | 'br'
268 | | 'button'
269 | | 'canvas'
270 | | 'caption'
271 | | 'center'
272 | | 'cite'
273 | | 'code'
274 | | 'col'
275 | | 'colgroup'
276 | | 'data'
277 | | 'datalist'
278 | | 'dd'
279 | | 'del'
280 | | 'details'
281 | | 'dfn'
282 | | 'dialog'
283 | | 'div'
284 | | 'dl'
285 | | 'dt'
286 | | 'em'
287 | | 'embed'
288 | | 'fieldset'
289 | | 'figcaption'
290 | | 'figure'
291 | | 'footer'
292 | | 'form'
293 | | 'h1'
294 | | 'h2'
295 | | 'h3'
296 | | 'h4'
297 | | 'h5'
298 | | 'h6'
299 | | 'head'
300 | | 'header'
301 | | 'hr'
302 | | 'html'
303 | | 'i'
304 | | 'iframe'
305 | | 'img'
306 | | 'input'
307 | | 'ins'
308 | | 'kbd'
309 | | 'label'
310 | | 'legend'
311 | | 'li'
312 | | 'link'
313 | | 'main'
314 | | 'map'
315 | | 'mark'
316 | | 'meta'
317 | | 'meter'
318 | | 'nav'
319 | | 'noscript'
320 | | 'object'
321 | | 'ol'
322 | | 'optgroup'
323 | | 'option'
324 | | 'output'
325 | | 'p'
326 | | 'param'
327 | | 'picture'
328 | | 'pre'
329 | | 'progress'
330 | | 'q'
331 | | 'rp'
332 | | 'rt'
333 | | 'ruby'
334 | | 's'
335 | | 'samp'
336 | | 'script'
337 | | 'section'
338 | | 'select'
339 | | 'selfClosingTagName'
340 | | 'small'
341 | | 'span'
342 | | 'strong'
343 | | 'style'
344 | | 'sub'
345 | | 'summary'
346 | | 'sup'
347 | | 'svg'
348 | | 'table'
349 | | 'tbody'
350 | | 'td'
351 | | 'template'
352 | | 'textarea'
353 | | 'tfoot'
354 | | 'th'
355 | | 'thead'
356 | | 'time'
357 | | 'title'
358 | | 'track'
359 | | 'tr'
360 | | 'u'
361 | | 'ul'
362 | | 'var'
363 | | 'video'
364 | | 'wbr';
365 |
--------------------------------------------------------------------------------
/src/custom-types/types.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from '../tag';
2 | import { TagBuilder } from '../tag-builder';
3 | import { CssProperty } from './css-properties';
4 | import { PickPropertyValues } from './css-property-values';
5 |
6 | export type StyleMap = { [key in CssProperty]?: PickPropertyValues };
7 | export type NestedStyleMap = {
8 | [key in CssProperty]?: PickPropertyValues | StyleMap;
9 | };
10 | export type StyleSet = { [key: string]: NestedStyleMap };
11 |
12 | export enum AttachMode {
13 | none,
14 | body,
15 | html,
16 | head,
17 | }
18 | export type ValidTagChild = string | Tag | { [key: string]: StyleMap } | TagBuilder | ((_: string) => void);
19 |
20 | export type TagMeta = {
21 | storage: any;
22 | selfClosing: boolean;
23 | storesChildren: boolean;
24 | };
25 |
26 | export type FindBy = (tag: Tag) => boolean;
27 | export type State = {} & {};
28 | export type StateProxy = T & { state: boolean };
29 |
30 | export type GlobalStuff = Function | string;
31 | export type HoboContext = {
32 | attachedTag: Tag | undefined | null;
33 | attachedTagStack: Tag[];
34 | globalStuff: GlobalStuff[];
35 | };
36 |
37 | export type HtmlEventType = 'click' | (string & {});
38 |
--------------------------------------------------------------------------------
/src/generation/css-generator.ts:
--------------------------------------------------------------------------------
1 | import { NestedStyleMap, StyleMap } from '../custom-types/types';
2 | import { camelToDash, isObject } from '../util';
3 |
4 | export class CssGenerator {
5 | generateCss(styleSheet: { [key: string]: NestedStyleMap } | { [key: string]: NestedStyleMap }[]) {
6 | let stylesheets = styleSheet instanceof Array ? styleSheet : [styleSheet];
7 | let generatedCss = '';
8 |
9 | for (const sheet of stylesheets) {
10 | for (const key in sheet) {
11 | generatedCss += this.generateBlock(key, sheet[key]);
12 | }
13 | }
14 | return generatedCss;
15 | }
16 |
17 | generateBlock(selector: string, style: NestedStyleMap) {
18 | let blocks = this.generateBlockContent(selector, style);
19 | return blocks.join('');
20 | }
21 |
22 | generateBlockContent(selector: string, style: NestedStyleMap): string[] {
23 | let inside = '';
24 | let blocks = [];
25 |
26 | for (const key in style) {
27 | if (isObject(style[key])) {
28 | blocks.push(this.generateBlockContent(selector + key, style[key]));
29 | }
30 | else if (style[key]) {
31 | inside += this.generateStyle(key, style[key] as string);
32 | }
33 | }
34 |
35 | blocks.unshift(`${selector}{${inside}}`);
36 |
37 | return blocks;
38 | }
39 |
40 | generateInline(style: StyleMap): string {
41 | let inside = '';
42 | for (const key in style) {
43 | if (style[key]) {
44 | inside += this.generateStyle(key, style[key] as string);
45 | }
46 | }
47 | return inside;
48 | }
49 |
50 | generateStyle(name: string, value: string) {
51 | return `${camelToDash(name)}:${value};`;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/generation/html-generator.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from '../tag';
2 | import { CssGenerator } from './css-generator';
3 | import { justFnBody } from '../util';
4 | import { TagBuilder } from '../tag-builder';
5 |
6 | export class HtmlGenerator {
7 | private cssGenerator = new CssGenerator();
8 | public beautifyCss = true;
9 |
10 | /** Generate html from the tag provided */
11 | generateHtml(rootTag: Tag): string {
12 | let generatedHtml = this._generateTag(rootTag);
13 | return generatedHtml;
14 | }
15 |
16 | private _generateTag(tag: Tag) {
17 | if (tag.tagName == 'style') {
18 | return this._createTag(tag, this.cssGenerator.generateCss(tag._meta.storage));
19 | }
20 |
21 | if (tag.tagName == 'script') {
22 | return this._createTag(tag, this._generateScriptContent(tag._meta.storage));
23 | }
24 |
25 | let inside = '';
26 |
27 | for (const child of tag.children) {
28 | let effectiveChild = child;
29 |
30 | if (child instanceof TagBuilder) {
31 | effectiveChild = child.b();
32 | }
33 |
34 | if (effectiveChild instanceof Tag) {
35 | inside += this._generateTag(effectiveChild);
36 | } else {
37 | inside += child;
38 | }
39 | }
40 |
41 | return this._createTag(tag, inside);
42 | }
43 |
44 | private _createTag(tag: Tag, inside: string) {
45 | const attributesString = this._generateAttributeString(tag);
46 | let openTag = [tag.tagName, attributesString].filter((n) => n).join(' ');
47 |
48 | if (tag._meta.selfClosing) {
49 | return `<${openTag}/>`;
50 | }
51 |
52 | return `<${openTag}>${inside}${tag.tagName}>`;
53 | }
54 |
55 | private _generateAttributeString(tag: Tag) {
56 | let attributesString = '';
57 |
58 | if (tag.attr.id) {
59 | attributesString += this._attr('id', tag.attr.id);
60 | }
61 |
62 | attributesString += this._attr('class', tag.attr.className.raw());
63 | attributesString += this._generateInlineStyle(tag);
64 |
65 | for (const key in tag.attr.additionalAttributes) {
66 | attributesString += this._attr(key, tag.attr.additionalAttributes[key]);
67 | }
68 |
69 | return attributesString;
70 | }
71 |
72 | private _generateInlineStyle(tag: Tag) {
73 | let styleContent = this.cssGenerator.generateInline(tag.attr.style.styles);
74 |
75 | return this._attr('style', styleContent);
76 | }
77 |
78 | private _generateScriptContent(storage: Function | Function[]): string {
79 | let scriptContent = '';
80 |
81 | if (storage instanceof Function) {
82 | scriptContent += justFnBody(storage);
83 | } else if (storage instanceof Array) {
84 | for (const fn of storage) {
85 | scriptContent += this._generateScriptContent(fn);
86 | }
87 | }
88 |
89 | return scriptContent;
90 | }
91 |
92 | private _attr(name: string, value: string) {
93 | if (!value) return '';
94 | return `${name}="${value}"`;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/hobo.ts:
--------------------------------------------------------------------------------
1 | import { Tag } from './tag';
2 | export { Tag } from './tag';
3 | import { HtmlGenerator } from './generation/html-generator';
4 | import { AttachMode, HoboContext, ValidTagChild } from './custom-types/types';
5 | import { builders as tagBuilders, TagBuilder, PickArgType } from './tag-builder';
6 | export { TagBuilder } from './tag-builder';
7 | import { TagName, ValidTagName } from './custom-types/tag-names';
8 |
9 | export let _context: HoboContext = {
10 | attachedTag: null,
11 | attachedTagStack: [],
12 | globalStuff: [],
13 | };
14 |
15 | /**
16 | * Creates an HTML document, with a head and body tags.
17 | * You can pass in the AttachMode to attach to different tags.
18 | */
19 | export function doc(pageTitle: string = 'New Hobo Document', mode: AttachMode = AttachMode.body) {
20 | const dhead = builders.head
21 | .aa('lang', 'en')
22 | .build(
23 | builders.meta.addAttr('charset', 'UTF-8'),
24 | builders.meta.setAttr({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
25 | builders.title(pageTitle),
26 | );
27 | const dbody = builders.body.build();
28 | const doc = builders.html.build(dhead, dbody);
29 |
30 | switch (mode) {
31 | case AttachMode.html:
32 | attach(doc);
33 | break;
34 | case AttachMode.head:
35 | attach(doc.findByTagName('head') as Tag); // We know there is a head tag
36 | break;
37 | case AttachMode.body:
38 | attach(doc.findByTagName('body') as Tag); // We know there is a body tag
39 | break;
40 | case AttachMode.none:
41 | break;
42 | }
43 |
44 | return { doc, head: dhead, body: dbody };
45 | }
46 |
47 | /**
48 | * Attach a given tag to the current context.
49 | * When you attach a tag, this tag will be the "root" for any tag created without a parent.
50 | *
51 | * * If there is not attached tag, it will be attached
52 | * * If there is already a tag attached, it will store the previous tag
53 | * and will set the new tag as the root. After finishing using the tag as the root, you can call `@detach`
54 | * and return to the previous root tag.
55 | *
56 | * This is used to remove clutter and reduntancies when creating hobo docs.
57 | * Like this:
58 | *
59 | * @example
60 | * Simple example with only 1 attach
61 | * ```ts
62 | * const parent = doc();
63 | * attach(parent);
64 | *
65 | * div();
66 | * p();
67 | * ```
68 | * The `div` and `p` tags will be automatically added as child of `parentDiv`
69 | *
70 | * @example
71 | * Example attaching and detaching
72 | * ```ts
73 | * const parent = doc();
74 | * attach(parent);
75 | *
76 | * div();
77 | * p();
78 | * let d1 = div();
79 | * attach(d1);
80 | * // All the p tags will be added to `d1`
81 | * p();
82 | * p();
83 | * p();
84 | * // remember to call detach when you want to go back to the previous root tag
85 | * detach();
86 | * ```
87 | *
88 | * @param {Tag} tag
89 | */
90 | export function attach(tag: Tag) {
91 | if (_context.attachedTag) {
92 | _context.attachedTagStack.push(_context.attachedTag);
93 | }
94 | _context.attachedTag = tag;
95 | }
96 |
97 | /**
98 | * Detached the currently attached tag, and pops back to the previously attached tag.
99 | * If there are no stored tags, it will clear the attached tag.
100 | * You will need to handle the consecuent created tags.
101 | */
102 | export function detach() {
103 | if (_context.attachedTagStack.length > 0) {
104 | _context.attachedTag = _context.attachedTagStack.pop();
105 | } else {
106 | _context.attachedTag = null;
107 | }
108 | }
109 |
110 | function makeAttachable(builder: TagBuilder): TagBuilder & { a: TagBuilder; attach: TagBuilder } {
111 | const attachFn = () => {
112 | if (_context.attachedTag) {
113 | return builder.p(_context.attachedTag);
114 | }
115 | return builder;
116 | };
117 |
118 | Object.defineProperty(builder, 'a', {
119 | get: attachFn,
120 | });
121 |
122 | Object.defineProperty(builder, 'attach', {
123 | get: attachFn,
124 | });
125 |
126 | return builder;
127 | }
128 |
129 |
130 | type BuilderFunctions = {
131 | [key in ValidTagName]: ((...children: PickArgType) => Tag) & TagBuilder & { a: TagBuilder };
132 | } & {
133 | tag: (tagName: TagName, ...children: PickArgType) => TagBuilder;
134 | };
135 |
136 | const exportedTagBuilders: BuilderFunctions = {} as BuilderFunctions;
137 |
138 | for (let key in tagBuilders) {
139 | exportedTagBuilders[key] = makeAttachable(tagBuilders[key]);
140 | }
141 |
142 | const _generator = new HtmlGenerator();
143 |
144 | /** Converts's the Tag tree into a html string */
145 | export function generate(root: Tag) {
146 | return _generator.generateHtml(root);
147 | }
148 |
149 | /**
150 | * TagBuilders for each known tag. From `div` to `acronym`
151 | */
152 | export const builders = exportedTagBuilders;
153 |
--------------------------------------------------------------------------------
/src/style.ts:
--------------------------------------------------------------------------------
1 | import { CssProperty } from './custom-types/css-properties';
2 | import { PickPropertyValues } from './custom-types/css-property-values';
3 |
4 | /**
5 | * Represents a set of styles
6 | */
7 | export class StyleSet {
8 | styles: { [key in CssProperty]?: PickPropertyValues } = {};
9 |
10 | copy() {
11 | const newStyles = new StyleSet();
12 | newStyles.styles = { ...this.styles };
13 | return newStyles;
14 | }
15 |
16 | /** Set a single style */
17 | set(key: T, value: PickPropertyValues): StyleSet {
18 | this.styles[key] = value as any;
19 | return this;
20 | }
21 |
22 | /** Remove styles */
23 | remove(...styles: string[]): StyleSet {
24 | for (const sn of styles) {
25 | delete this.styles[sn];
26 | }
27 | return this;
28 | }
29 |
30 | /** Check if a style is set */
31 | has(key: string): boolean {
32 | return key in this.styles;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/tag-builder.ts:
--------------------------------------------------------------------------------
1 | import { AttrSet } from './attributes';
2 | import { ClassName } from './class-name';
3 | import { Tag } from './tag';
4 | import { CssProperty } from './custom-types/css-properties';
5 | import { PickPropertyValues } from './custom-types/css-property-values';
6 | import { TagName, ValidTagName, allKnownTags, selfClosingTags, storableTags } from './custom-types/tag-names';
7 | import { StyleMap, StyleSet, TagMeta, ValidTagChild } from './custom-types/types';
8 |
9 | class ExFunc extends Function {
10 | private __self__: any;
11 |
12 | constructor() {
13 | super('...args', 'return this.__self__.__call__(...args)');
14 | var self = this.bind(this);
15 | this.__self__ = self;
16 | return self;
17 | }
18 |
19 | /* istanbul ignore next */
20 | __call__(...children: ValidTagChild[]) {}
21 | }
22 |
23 | /**
24 | * TagBuilder class, used to build tags of course.
25 | */
26 | export class TagBuilder extends ExFunc {
27 | tagName: TagName;
28 | children: ValidTagChild[] = [];
29 |
30 | /** Get the tag className */
31 | get className() {
32 | return this.attr.className;
33 | }
34 |
35 | /** Get the tag id */
36 | get tagId() {
37 | return this.attr.id;
38 | }
39 |
40 | /**
41 | * Do not modify directly, use helper methods in the tag instead.
42 | */
43 | attr: AttrSet = new AttrSet();
44 |
45 | _parent: Tag;
46 | _meta: TagMeta = {
47 | selfClosing: false,
48 | storesChildren: false,
49 | storage: false,
50 | };
51 |
52 | constructor(tagName: TagName, ...children: ValidTagChild[]) {
53 | super();
54 | this.setTagName(tagName);
55 | this.children.push(...children);
56 | }
57 |
58 | copy() {
59 | const newBuilder = new TagBuilder(this.tagName, ...this.children);
60 | newBuilder.attr = this.attr.copy();
61 | newBuilder._parent = this._parent;
62 | newBuilder._meta = { ...this._meta, ...newBuilder._meta };
63 | return newBuilder;
64 | }
65 |
66 | /** Sets and validates the tag name */
67 | setTagName(name: string) {
68 | this.tagName = this.sanitizeTagName(name);
69 | this.validateTagName(this.tagName);
70 | this._meta = {
71 | ...this._meta,
72 | ...this.getMetaForTag(this.tagName),
73 | };
74 | return this;
75 | }
76 |
77 | /**
78 | * Shorthand for `.build` method
79 | * Build the tag with additional children
80 | */
81 | b(...children: ValidTagChild[]): Tag {
82 | return this.build(...children);
83 | }
84 |
85 | /**
86 | * Build the tag with additional children
87 | */
88 | build(...children: ValidTagChild[]): Tag {
89 | return this.__call__(...children);
90 | }
91 |
92 | __call__(...children: ValidTagChild[]): Tag {
93 | let tagChildren = [...this.children, ...children];
94 |
95 | if (this._meta.storesChildren) {
96 | this._meta.storage = children;
97 | tagChildren = [];
98 | }
99 |
100 | const built = new Tag(this.tagName, tagChildren, this.attr, this._meta);
101 |
102 | if (this._parent) {
103 | this._parent.children.push(built);
104 | }
105 | return built;
106 | }
107 |
108 | /** Attach to the currently attached tag in the global hobo context */
109 | /* istanbul ignore next */
110 | get a() {
111 | return this.copy();
112 | }
113 |
114 | /** Same as .a - Attach to the currently attached tag in the global hobo context */
115 | /* istanbul ignore next */
116 | get attach() {
117 | return this.copy();
118 | }
119 |
120 | /** Set the parent of the tag. If a parent is set, this tag will be added as a child when built */
121 | p(parent: Tag) {
122 | const copy = this.copy();
123 | copy._parent = parent;
124 | return copy;
125 | }
126 |
127 | /**
128 | * Set the id of the tag
129 | * Can't be empty
130 | */
131 | id(newId: T extends '' ? never : T) {
132 | const copy = this.copy();
133 | copy.attr.id = newId;
134 | return copy;
135 | }
136 |
137 | /** replaces the children of this tag with the provided string */
138 | text(content: string) {
139 | const copy = this.copy();
140 | copy.children = [content];
141 | return copy;
142 | }
143 |
144 | /**
145 | * Adds tags as children if the tag can have children.
146 | * For example, if tag is `img` there's no need to add the childre as they will not be generated.
147 | */
148 | append(...tags: ValidTagChild[]) {
149 | if (this._meta.selfClosing) {
150 | return this;
151 | }
152 |
153 | const copy = this.copy();
154 | copy.children.push(...tags.map((c) => (c instanceof TagBuilder ? c.b() : c)));
155 |
156 | return copy;
157 | }
158 |
159 | /** Set the children of this tag. Replaces any current children */
160 | setChildren(children: ValidTagChild[]) {
161 | const copy = this.copy();
162 | copy.children = children;
163 | return copy;
164 | }
165 |
166 | /** Store metadata inside tag. Internal method, you won't need this */
167 | store(o: any) {
168 | const copy = this.copy();
169 | copy._meta.storage = o;
170 | return copy;
171 | }
172 |
173 | /**
174 | * cm = modify
175 | * calls `fn` with the tag, and returns the tag
176 | *
177 | * usefull to change a tag while maintaing chaning
178 | *
179 | * @example
180 | * ```ts
181 | * div().m(t => t.className.add("Container"))
182 | * .div("I'm a child!"),
183 | * ```
184 | * @example
185 | * ```ts
186 | * div([
187 | * p("Child1").m(t => t.className.add("child-1")),
188 | * p("Child1").m(t => t.className.add("child-2"))
189 | * ])
190 | * ```
191 | */
192 | m(fn: (tag: TagBuilder) => void) {
193 | return this.mod(fn);
194 | }
195 |
196 | /**
197 | * calls `fn` with the tag, and returns the tag
198 | *
199 | * usefull to change a tag while maintaing chaning
200 | *
201 | * @example
202 | * ```ts
203 | * div().m(t => t.className.add("Container"))
204 | * .div("I'm a child!"),
205 | * ```
206 | * @example
207 | * ```ts
208 | * div([
209 | * p("Child1").mod(t => t.className.add("child-1")),
210 | * p("Child1").mod(t => t.className.add("child-2"))
211 | * ])
212 | * ```
213 | */
214 | mod(fn: (tag: TagBuilder) => void) {
215 | const copy = this.copy();
216 | fn(copy);
217 | return copy;
218 | }
219 |
220 | /**
221 | * Shortcut for method .modClass
222 | *
223 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
224 | * but it passes the className instead of the complete tag.
225 | *
226 | * Retuns a new TagBuilder
227 | */
228 | mc(arg0: (c: ClassName) => void) {
229 | return this.modClass(arg0);
230 | }
231 |
232 | /**
233 | * Modifies the classnames of a tag. Similar to the `.mod` or `.m` methods
234 | * but it passes the className instead of the complete tag.
235 | *
236 | * Retuns a new TagBuilder
237 | *
238 | * @example
239 | * ```ts
240 | * div(
241 | * p("Child1").modClass(c => c.add("child-1")),
242 | * p("Child1").modClass(c => c.add("child-2"))
243 | * )
244 | * ```
245 | */
246 | modClass(arg0: (c: ClassName) => void) {
247 | const copy = this.copy();
248 | return copy.m((t) => arg0(t.className));
249 | }
250 |
251 | /**
252 | * Shorthand for .addClass method.
253 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
254 | */
255 | ac(...classNames: string[]) {
256 | return this.addClass(...classNames);
257 | }
258 |
259 | /**
260 | * Adds classNames to this TagBuilder, and returns a new TagBuilder
261 | */
262 | addClass(...classNames: string[]) {
263 | const copy = this.copy();
264 | copy.className.add(...classNames);
265 | return copy;
266 | }
267 |
268 | /**
269 | * Shorthand for .rmClass method.
270 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
271 | */
272 | rc(...classNames: string[]) {
273 | return this.rmClass(...classNames);
274 | }
275 |
276 | /**
277 | * Removes classNames from this TagBuilder, and returns a new TagBuilder
278 | */
279 | rmClass(...classNames: string[]) {
280 | const copy = this.copy();
281 | copy.className.remove(...classNames);
282 | return copy;
283 | }
284 |
285 | /**
286 | * Shorthand for .addAttr method.
287 | * Adds attribute, and returns a new TagBuilder
288 | */
289 | aa(key: string, value: string) {
290 | return this.addAttr(key, value);
291 | }
292 |
293 | /** Add one attribute, and return a new TagBuilder */
294 | addAttr(key: string, value: string) {
295 | const copy = this.copy();
296 | copy.attr.set(key, value);
297 | return copy;
298 | }
299 |
300 | /**
301 | * Shorthand for .setAttr method.
302 | * Sets multiple atributes at once, and returns a new TagBuilder
303 | */
304 | sa(attributes: { [key: string]: string }) {
305 | return this.setAttr(attributes);
306 | }
307 |
308 | /** Sets multiple atributes at once, and returns a new TagBuilder */
309 | setAttr(attributes: { [key: string]: string }) {
310 | const copy = this.copy();
311 | copy.attr.additionalAttributes = {
312 | ...copy.attr.additionalAttributes,
313 | ...attributes,
314 | };
315 | return copy;
316 | }
317 |
318 | /**
319 | * Shorthand for .removeAttr method.
320 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
321 | */
322 | ra(...attr: string[]) {
323 | return this.rmAttr(...attr);
324 | }
325 |
326 | /**
327 | * Removes attribute from this TagBuilder, and returns a new TagBuilder
328 | */
329 | rmAttr(...attr: string[]) {
330 | const copy = this.copy();
331 | copy.attr.remove(...attr);
332 | return copy;
333 | }
334 |
335 | /**
336 | * Shorthand for .addStyle method
337 | * Adds a single style, and returns a new TagBuilder
338 | */
339 | as(key: T, value: PickPropertyValues) {
340 | return this.addStyle(key, value);
341 | }
342 |
343 | /**
344 | * Adds a single style, and returns a new TagBuilder
345 | */
346 | addStyle(key: T, value: PickPropertyValues) {
347 | const copy = this.copy();
348 | copy.attr.style.set(key, value);
349 | return copy;
350 | }
351 |
352 | /**
353 | * Shorthand for .setStyles method.
354 | * Adds style from object, and returns a new TagBuilder
355 | */
356 | ss(styles: StyleMap) {
357 | return this.setStyles(styles);
358 | }
359 |
360 | /** Adds style from object, and returns a new TagBuilder */
361 | setStyles(styles: StyleMap) {
362 | const copy = this.copy();
363 | copy.attr.style.styles = {
364 | ...copy.attr.style.styles,
365 | ...styles,
366 | };
367 | return copy;
368 | }
369 |
370 | /**
371 | * Shorthand for .removeStyles method.
372 | * Removes styles from this TagBuilder, and returns a new TagBuilder
373 | */
374 | rs(...styleNames: string[]) {
375 | return this.rmStyle(...styleNames);
376 | }
377 |
378 | /**
379 | * Removes styles from this TagBuilder, and returns a new TagBuilder
380 | */
381 | rmStyle(...styleNames: string[]) {
382 | const copy = this.copy();
383 | copy.attr.style.remove(...styleNames);
384 | return copy;
385 | }
386 |
387 | // Utilities
388 | private getMetaForTag(tagName: TagName): TagMeta {
389 | return {
390 | selfClosing: this.isSelfClosingTag(tagName),
391 | storesChildren: this.isStorableTag(tagName),
392 | storage: null,
393 | };
394 | }
395 |
396 | private isSelfClosingTag(tagName: string) {
397 | return selfClosingTags.includes(tagName);
398 | }
399 | private isStorableTag(tagName: string) {
400 | return storableTags.includes(tagName);
401 | }
402 | private validateTagName(tagName: TagName) {
403 | if (!/[a-zA-Z_][a-z-A-Z0-9_]*/.test(tagName)) {
404 | throw new Error(`Invalid tag name "${tagName}"`);
405 | }
406 | }
407 | private sanitizeTagName(tagName: TagName) {
408 | return tagName.replace(/[^\w\d-_]/, '');
409 | }
410 | }
411 |
412 | function tagBuilder(tagName: TagName, ...children: ValidTagChild[]): TagBuilder {
413 | return new TagBuilder(tagName, ...children);
414 | }
415 | const tagNames = allKnownTags;
416 |
417 | export type PickArgType = T extends 'style' ? StyleSet[] : ValidTagChild[];
418 |
419 | type BuilderFunctions = {
420 | [key in ValidTagName]: ((...children: PickArgType) => Tag) & TagBuilder;
421 | } & {
422 | /**
423 | * Create a new TagBuilder with specified tagName
424 | * @example
425 | * ```ts
426 | * tag('uknown-tag');
427 | * ```
428 | */
429 | tag: (tagName: TagName, ...children: PickArgType) => TagBuilder;
430 | };
431 |
432 | let fns: Partial = {
433 | tag: tagBuilder,
434 | };
435 |
436 | for (let tname of tagNames) {
437 | fns[tname] = tagBuilder(tname);
438 | }
439 |
440 | export const builders = fns;
441 |
--------------------------------------------------------------------------------
/src/tag.ts:
--------------------------------------------------------------------------------
1 | import { TagName } from './custom-types/tag-names';
2 | import { AttrSet } from './attributes';
3 | import { FindBy, TagMeta, ValidTagChild } from './custom-types/types';
4 | import { TagBuilder } from './tag-builder';
5 |
6 | /**
7 | * Represents an html tag
8 | */
9 | export class Tag {
10 | tagName: TagName;
11 | children: ValidTagChild[] = [];
12 | attr: AttrSet = new AttrSet();
13 |
14 | _meta: TagMeta = {
15 | selfClosing: false,
16 | storesChildren: false,
17 | storage: false,
18 | };
19 |
20 | get className() {
21 | return this.attr.className;
22 | }
23 | get tagId() {
24 | return this.attr.id;
25 | }
26 |
27 | constructor(tagName: TagName, children: ValidTagChild[], attr: AttrSet, meta: TagMeta) {
28 | this.tagName = tagName;
29 | this.children = children;
30 | this.attr = attr;
31 | this._meta = meta;
32 | }
33 |
34 | /** Append children */
35 | append(child: ValidTagChild) {
36 | if (child instanceof TagBuilder) child = child.b();
37 | this.children.push(child);
38 | }
39 |
40 | /** Find a child by tag name */
41 | findByTagName(targetTagName: TagName): Tag | null {
42 | return this.findOneBy((t) => t.tagName == targetTagName);
43 | }
44 |
45 | /** Find a child by custom test */
46 | findOneBy(test: FindBy): Tag | null {
47 | const stack: Tag[] = [];
48 | stack.push(this);
49 |
50 | while (stack.length > 0) {
51 | let tag: Tag = stack.pop() as Tag;
52 |
53 | if (test(tag)) {
54 | return tag;
55 | } else if (tag.children && tag.children.length) {
56 | for (let ii = 0; ii < tag.children.length; ii += 1) {
57 | if (this.children[ii] instanceof Tag) {
58 | stack.push(tag.children[ii] as Tag);
59 | }
60 | }
61 | }
62 | }
63 |
64 | return null;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/util.ts:
--------------------------------------------------------------------------------
1 | /** Receives a function, and returns just the body of the function as a string */
2 | export function justFnBody(fn: Function) {
3 | let fnStr = fn.toString();
4 | fnStr = fnStr.replace(/^(.*{)/, '');
5 | fnStr = fnStr.replace(/}$/, '');
6 | fnStr = fnStr.replace(/^\(.*\)\s?=>\s?{/, '');
7 | return fnStr.trim();
8 | }
9 | export const replaceDoubleQuotes = (str: string)=>str.replace(/"/g, "'");
10 | export const generateId = () => `_hb${s4() + s4()}`;
11 | export const camelToDash = (str) => str.replace(/([A-Z])/g, (val) => `-${val.toLowerCase()}`);
12 | export const dashToCamel = (str) => str.replace(/(\-[a-z])/g, (val) => val.toUpperCase().replace('-', ''));
13 | export function isObject(obj: any): boolean {
14 | return typeof obj === 'object' && !(obj instanceof Array);
15 | }
16 | const s4 = ()=>(((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
--------------------------------------------------------------------------------
/tests/unit/css-generator.test.ts:
--------------------------------------------------------------------------------
1 | import { CssGenerator } from '../../src/generation/css-generator';
2 |
3 | describe('CssGenerator', () => {
4 | const generator = new CssGenerator();
5 |
6 | it('generateCss() basic works', async () => {
7 | const generated = generator.generateCss({
8 | body: {},
9 | });
10 | expect(generated).toEqual('body{}');
11 | });
12 |
13 | it('generateCss() with styles', async () => {
14 | const generated = generator.generateCss({
15 | body: {
16 | color: 'red',
17 | flexDirection: 'column',
18 | },
19 | });
20 | expect(generated).toEqual('body{color:red;flex-direction:column;}');
21 | });
22 |
23 | it('generateCss() with nested styles', async () => {
24 | const generated = generator.generateCss({
25 | body: {
26 | color: 'red',
27 | flexDirection: 'column',
28 | ':hover': { color: 'blue' },
29 | },
30 | });
31 | expect(generated).toEqual('body{color:red;flex-direction:column;}body:hover{color:blue;}');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/tests/unit/hobo.test.ts:
--------------------------------------------------------------------------------
1 | import { AttachMode } from '../../src/custom-types/types';
2 | import { _context, attach, builders, detach, doc, generate } from '../../src/hobo';
3 | import { Tag } from '../../src/tag';
4 |
5 | describe('TagBuilder', () => {
6 | it('doc works', async () => {
7 | const d = doc();
8 | expect('doc' in d).toBeTruthy();
9 | expect('head' in d).toBeTruthy();
10 | expect('body' in d).toBeTruthy();
11 |
12 | expect(d.doc).toBeInstanceOf(Tag);
13 | expect(d.head).toBeInstanceOf(Tag);
14 | expect(d.body).toBeInstanceOf(Tag);
15 | });
16 |
17 | it('doc(AttachMode.html) works', async () => {
18 | _context.attachedTag = null; // Reset
19 | _context.attachedTagStack = [];
20 | const d = doc('title', AttachMode.html);
21 | expect(_context.attachedTag).toBe(d.doc);
22 | });
23 |
24 | it('doc(AttachMode.head) works', async () => {
25 | _context.attachedTag = null; // Reset
26 | _context.attachedTagStack = [];
27 | const d = doc('title', AttachMode.head);
28 | expect(_context.attachedTag).toBe(d.head);
29 | });
30 |
31 | it('doc(AttachMode.body) works', async () => {
32 | _context.attachedTag = null; // Reset
33 | _context.attachedTagStack = [];
34 | const d = doc('title', AttachMode.body);
35 | expect(_context.attachedTag).toBe(d.body);
36 | });
37 |
38 | it('doc(AttachMode.none) works', async () => {
39 | _context.attachedTag = null; // Reset
40 | _context.attachedTagStack = [];
41 | const d = doc('title', AttachMode.none);
42 | expect(_context.attachedTag).toBe(null);
43 | });
44 |
45 | it('attach() works', async () => {
46 | _context.attachedTag = null; // Reset
47 | _context.attachedTagStack = [];
48 | const d = builders.div.b();
49 | attach(d);
50 | expect(_context.attachedTag).toEqual(d);
51 |
52 | const child = builders.div.a.b();
53 |
54 | expect(_context.attachedTag.children).toContain(child);
55 | });
56 |
57 | it('attach() works when there are other attached tags', async () => {
58 | _context.attachedTag = null; // Reset
59 | _context.attachedTagStack = [];
60 | const d = builders.div.b();
61 | attach(d);
62 | const d1 = builders.div();
63 | attach(d1);
64 | expect(_context.attachedTag).toEqual(d1);
65 | expect(_context.attachedTagStack).toEqual([d]);
66 |
67 | detach();
68 | expect(_context.attachedTag).toEqual(d);
69 | expect(_context.attachedTagStack).toEqual([]);
70 | detach();
71 | expect(_context.attachedTag).toEqual(null);
72 | expect(_context.attachedTagStack).toEqual([]);
73 | });
74 |
75 | it('generate() works', async () => {
76 | const d = builders.div.b();
77 | expect(generate(d)).toEqual('');
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/tests/unit/html-generator.test.ts:
--------------------------------------------------------------------------------
1 | import { HtmlGenerator } from '../../src/generation/html-generator';
2 | import { builders } from '../../src/hobo';
3 |
4 | describe('HtmlGenerator', () => {
5 | const generator = new HtmlGenerator();
6 |
7 | it('generateHtml() basic tag works', async () => {
8 | const d1 = builders.div();
9 | const generated = generator.generateHtml(d1);
10 | expect(generated).toEqual('');
11 | });
12 |
13 | it('generateHtml() style tag works', async () => {
14 | const d1 = builders.style({ '.class': { color: 'red' } });
15 | const generated = generator.generateHtml(d1);
16 | expect(generated).toEqual('');
17 | });
18 |
19 | it('generateHtml() script tag works', async () => {
20 | const d1 = builders.script(() => {
21 | console.log('hey');
22 | });
23 | const generated = generator.generateHtml(d1);
24 | expect(generated).toEqual("");
25 | });
26 |
27 | it('generateHtml() works with nested childs', async () => {
28 | const d1 = builders.div(builders.span(), builders.p('Some string'));
29 | const generated = generator.generateHtml(d1);
30 | expect(generated).toEqual(``);
31 | });
32 |
33 | it('generateHtml() works with nested tag builders', async () => {
34 | const d1 = builders.div(builders.span(), builders.p);
35 | const generated = generator.generateHtml(d1);
36 | expect(generated).toEqual(``);
37 | });
38 |
39 | it('generateHtml() works for self closing tags', async () => {
40 | expect(generator.generateHtml(builders.img.b())).toEqual('
');
41 | });
42 |
43 | it('generateHtml() works with attributes', async () => {
44 | expect(generator.generateHtml(builders.img.aa('src', 'test.com').b())).toEqual('
');
45 | });
46 |
47 | it('generateHtml() works with class names', async () => {
48 | expect(generator.generateHtml(builders.img.ac('src').b())).toEqual('
');
49 | });
50 |
51 | it('generateHtml() works with id', async () => {
52 | expect(generator.generateHtml(builders.img.id('src').b())).toEqual('
');
53 | });
54 |
55 | it('generateHtml() works with inline styles', async () => {
56 | expect(generator.generateHtml(builders.img.as('color', 'red').b())).toEqual('
');
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/tests/unit/miscelaneous.test.ts:
--------------------------------------------------------------------------------
1 | import { AttrSet } from '../../src/attributes';
2 | import { StyleSet } from '../../src/style';
3 |
4 | describe('Misc tests', () => {
5 | it('attr.has()', () => {
6 | const attr = new AttrSet();
7 | attr.set('one', 'two');
8 | expect(attr.has('one')).toEqual(true);
9 | expect(attr.has('two')).toEqual(false);
10 | });
11 | it('style.has()', () => {
12 | const style = new StyleSet();
13 | style.set('one', 'two');
14 | expect(style.has('one')).toEqual(true);
15 | expect(style.has('two')).toEqual(false);
16 | });
17 | });
--------------------------------------------------------------------------------
/tests/unit/tag-builder.test.ts:
--------------------------------------------------------------------------------
1 | import { allKnownTags, closingTags, selfClosingTags } from '../../src/custom-types/tag-names';
2 | import { builders } from '../../src/hobo';
3 | import { Tag } from '../../src/tag';
4 | import { builders as tagBuilders, TagBuilder } from '../../src/tag-builder';
5 | const { tag } = builders;
6 |
7 | describe('TagBuilder', () => {
8 | it('creates correctly', async () => {
9 | const builder = tag('custom-tag');
10 | expect(builder).toBeDefined();
11 | expect(builder.tagName).toEqual('custom-tag');
12 | });
13 |
14 | it('all tags exist as builders', async () => {
15 | for (let tagName of allKnownTags) {
16 | expect(tagName in builders).toBeTruthy();
17 | }
18 | });
19 |
20 | it('selfClosing tags set correct metadata', async () => {
21 | for (let tagName of selfClosingTags) {
22 | const builder = builders[tagName] as TagBuilder;
23 | expect(builder._meta.selfClosing).toEqual(true);
24 | }
25 | });
26 |
27 | it('nonSelfClosing tags set correct metadata', async () => {
28 | for (let tagName of closingTags) {
29 | const builder = builders[tagName] as TagBuilder;
30 | expect(builder._meta.selfClosing).toEqual(false);
31 | }
32 | });
33 |
34 | it('.className returns className', async () => {
35 | const someTag = builders.div;
36 | expect(someTag.className).toBe(someTag.attr.className);
37 | });
38 |
39 | it('.tagId returns id', async () => {
40 | const someTag = builders.div.id('aaa');
41 | expect(someTag.attr.id).toEqual('aaa');
42 | expect(someTag.tagId).toEqual('aaa');
43 | });
44 |
45 | it('.b builds tag', async () => {
46 | const someTag = builders.div.id('aaa');
47 | const built = someTag.b();
48 |
49 | expect(built.tagName).toEqual('div');
50 | expect(built.tagId).toEqual('aaa');
51 | expect(built).toBeInstanceOf(Tag);
52 | });
53 |
54 | it('.a returns builder', async () => {
55 | const someTag = (tagBuilders.div as TagBuilder).a;
56 | expect(someTag).toBeInstanceOf(TagBuilder);
57 | });
58 |
59 | it('.p sets parent', async () => {
60 | const papa = builders.div();
61 | const someTag = builders.div.p(papa);
62 |
63 | expect(someTag._parent).toEqual(papa);
64 | });
65 |
66 | it('.text replaces children with given text', async () => {
67 | const papa = builders.div.text('Some text');
68 | expect(papa.b().children).toEqual(['Some text']);
69 | });
70 |
71 | it('.append adds children', async () => {
72 | const child = builders.div();
73 | const papa = builders.div.append(child);
74 |
75 | expect(papa.children).toEqual([child]);
76 | });
77 |
78 | it('.append does not add children for selfClosingTags', async () => {
79 | const child = builders.div();
80 | const papa = builders.img.append(child);
81 |
82 | expect(papa.children).toEqual([]);
83 | });
84 |
85 |
86 | it('.append works with TagBuilder', async () => {
87 |
88 | const papa = builders.div.append(builders.div);
89 |
90 | expect(papa.children).toEqual([builders.div()]);
91 | });
92 |
93 | it('.setChildren does not add children for selfClosingTags', async () => {
94 | const el = builders.div.append('Initial child');
95 | const child = builders.a();
96 | const papa = el.setChildren([builders.a()]);
97 |
98 | expect(papa.children).toEqual([builders.a()]);
99 | });
100 |
101 | it('.store stores', async () => {
102 | const el = builders.div.store('some data');
103 | expect(el._meta.storage).toEqual('some data');
104 | });
105 |
106 | it('.m works', async () => {
107 | const el = builders.div.m((b) => b.attr.className.add('one'));
108 | expect(el.b().attr.className.classNames).toContain('one');
109 | });
110 |
111 | it('.mc works', async () => {
112 | const el = builders.div.mc((c) => c.add('one'));
113 | expect(el.b().attr.className.classNames).toContain('one');
114 | });
115 |
116 | it('.ac works', async () => {
117 | const el = builders.div.ac('one');
118 | expect(el.b().attr.className.classNames).toContain('one');
119 | });
120 |
121 | it('.rc works', async () => {
122 | const el = builders.div.ac('one').rc('one');
123 | expect(el.b().attr.className.classNames).not.toContain('one');
124 | });
125 |
126 | it('.aa works', async () => {
127 | const el = builders.div.aa('one', 'two').b();
128 | expect('one' in el.attr.additionalAttributes).toEqual(true);
129 | expect(el.attr.additionalAttributes['one']).toEqual('two');
130 | });
131 |
132 | it('.am works', async () => {
133 | const el = builders.div.sa({ one: 'two' }).b();
134 | expect('one' in el.attr.additionalAttributes).toEqual(true);
135 | expect(el.attr.additionalAttributes['one']).toEqual('two');
136 | });
137 |
138 | it('.ra works', async () => {
139 | const el = builders.div.aa('one', 'two');
140 | el.ra('one');
141 | expect(el.b().attr.additionalAttributes).not.toContain('one');
142 | });
143 |
144 | it('.as works', async () => {
145 | const el = builders.div.as('color', 'red').b();
146 | expect('color' in el.attr.style.styles).toEqual(true);
147 | expect(el.attr.style.styles['color']).toEqual('red');
148 | });
149 |
150 | it('.ss works', async () => {
151 | const el = builders.div.ss({ color: 'red' }).b();
152 | expect('color' in el.attr.style.styles).toEqual(true);
153 | expect(el.attr.style.styles['color']).toEqual('red');
154 | });
155 |
156 | it('.rs works', async () => {
157 | const el = builders.div.ss({ color: 'red' }).rs('color').b();
158 | expect('color' in el.attr.style.styles).toEqual(false);
159 | });
160 |
161 | it('Error for invalid tag!', async () => {
162 | expect(() => {
163 | builders.tag('123&');
164 | }).toThrow();
165 | });
166 | });
167 |
--------------------------------------------------------------------------------
/tests/unit/tag.test.ts:
--------------------------------------------------------------------------------
1 | import { AttrSet } from '../../src/attributes';
2 | import { Tag } from '../../src/tag';
3 | import { builders } from '../../src/tag-builder';
4 |
5 | describe('TagBuilder', () => {
6 | it('creates correctly', async () => {
7 | const tag = new Tag('custom-tag', [], new AttrSet(), {
8 | selfClosing: false,
9 | storesChildren: false,
10 | storage: false,
11 | });
12 | expect(tag).toBeDefined();
13 | expect(tag.tagName).toEqual('custom-tag');
14 | expect(tag.children).toEqual([]);
15 | });
16 |
17 | it('.className returns className', async () => {
18 | const attrSet = new AttrSet();
19 | const tag = new Tag('custom-tag', [], attrSet, {
20 | selfClosing: false,
21 | storesChildren: false,
22 | storage: false,
23 | });
24 | expect(tag.className).toEqual(attrSet.className);
25 | });
26 |
27 | it('.append adds children', async () => {
28 | const tag1 = new Tag('custom-tag', [], new AttrSet(), {
29 | selfClosing: false,
30 | storesChildren: false,
31 | storage: false,
32 | });
33 | const tag2 = new Tag('custom-tag2', [], new AttrSet(), {
34 | selfClosing: false,
35 | storesChildren: false,
36 | storage: false,
37 | });
38 |
39 | tag1.append(tag2);
40 |
41 | expect(tag1.children).toEqual([tag2]);
42 | });
43 |
44 | it('.append works with TagBuilder', async () => {
45 | const tag1 = new Tag('custom-tag', [], new AttrSet(), {
46 | selfClosing: false,
47 | storesChildren: false,
48 | storage: false,
49 | });
50 | const d = builders.div.ac('aa');
51 |
52 | tag1.append(d);
53 |
54 | expect(tag1.children[0]).toBeInstanceOf(Tag);
55 | });
56 |
57 | it('.findByTagName works', async () => {
58 | const tag1 = new Tag('custom-tag', [], new AttrSet(), {
59 | selfClosing: false,
60 | storesChildren: false,
61 | storage: false,
62 | });
63 | const d = builders.div.ac('aa');
64 | tag1.append(d);
65 |
66 | const found = tag1.findByTagName('div');
67 | expect(found).toEqual(d.b());
68 | });
69 |
70 | it('.findByTagName returns null if not find', async () => {
71 | const tag1 = new Tag('custom-tag', [], new AttrSet(), {
72 | selfClosing: false,
73 | storesChildren: false,
74 | storage: false,
75 | });
76 | const found = tag1.findByTagName('div');
77 | expect(found).toEqual(null);
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "es6",
4 | "moduleResolution": "Node",
5 | "target": "ES6",
6 | "declaration": true,
7 | "esModuleInterop": true,
8 | "sourceMap": true,
9 | "noImplicitAny": false,
10 | "lib": [
11 | "es2015",
12 | "dom"
13 | ],
14 | "outDir": "dist",
15 | "types": [
16 | "node",
17 | "jest"
18 | ],
19 | "declarationDir": "dist/types"
20 | },
21 | "include": [
22 | "src/**/*"
23 | ],
24 | "lib": [
25 | "es2015",
26 | "dom"
27 | ]
28 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "CommonJS",
4 | "moduleResolution": "Node",
5 | "target": "ES2015",
6 | "declaration": true,
7 | "esModuleInterop": true,
8 | "sourceMap": true,
9 | "noImplicitAny": false,
10 | "lib": [
11 | "es2015",
12 | "dom"
13 | ],
14 | "outDir": "dist",
15 | "types": [
16 | "node",
17 | "jest"
18 | ],
19 | "declarationDir": "dist/types"
20 | },
21 | "include": [
22 | "src/**/*"
23 | ],
24 | "lib": [
25 | "es2015",
26 | "dom"
27 | ]
28 | }
--------------------------------------------------------------------------------