mancha 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +41 -0
- package/README.md +30 -8
- package/dist/browser.d.ts +2 -1
- package/dist/browser.js +3 -2
- package/dist/css_gen_utils.js +37 -27
- package/dist/dome.d.ts +15 -4
- package/dist/dome.js +43 -7
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/interfaces.d.ts +1 -1
- package/dist/mancha.js +2 -2
- package/dist/plugins.js +124 -76
- package/dist/{core.d.ts → renderer.d.ts} +1 -0
- package/dist/{core.js → renderer.js} +5 -3
- package/dist/safe_browser.d.ts +2 -1
- package/dist/safe_browser.js +45 -8
- package/dist/store.d.ts +1 -1
- package/dist/store.js +1 -1
- package/dist/test_utils.d.ts +10 -0
- package/dist/test_utils.js +44 -0
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +2 -1
- package/gulpfile.js +7 -4
- package/package.json +20 -9
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: "pages"
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build-test-deploy:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
name: Build Test Deploy
|
|
21
|
+
environment:
|
|
22
|
+
name: github-pages
|
|
23
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: "22"
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: npm install --include=dev
|
|
31
|
+
- name: Build project
|
|
32
|
+
run: npm run build
|
|
33
|
+
- name: Test project
|
|
34
|
+
run: npm run test
|
|
35
|
+
- name: Upload artifact
|
|
36
|
+
uses: actions/upload-pages-artifact@v3
|
|
37
|
+
with:
|
|
38
|
+
path: "dist"
|
|
39
|
+
- name: Deploy to GitHub Pages
|
|
40
|
+
id: deployment
|
|
41
|
+
uses: actions/deploy-pages@v4
|
package/README.md
CHANGED
|
@@ -63,7 +63,8 @@ front-end development. Whether you decide to break up your app into reusable par
|
|
|
63
63
|
`<include>` or create custom web components, you can write HTML as if your mother was watching.
|
|
64
64
|
|
|
65
65
|
`mancha` implements its own reactivity engine, so the bundled browser module contains no external
|
|
66
|
-
dependencies
|
|
66
|
+
dependencies with the exception of [`jexpr`][jexpr] for safe expression evaluation (see the
|
|
67
|
+
[dependencies section](#dependencies)).
|
|
67
68
|
|
|
68
69
|
## Preprocessing
|
|
69
70
|
|
|
@@ -130,6 +131,10 @@ element tag or attributes match a specific criteria. Here's the list of attribut
|
|
|
130
131
|
```html
|
|
131
132
|
<div :data="{foo: false}" :show="foo"></div>
|
|
132
133
|
```
|
|
134
|
+
- `:class` appends rendered text to existing class attribute
|
|
135
|
+
```html
|
|
136
|
+
<span :class="error ? 'red' : 'blue'" class="text-xl">...</span>
|
|
137
|
+
```
|
|
133
138
|
- `:bind` binds (two-way) a variable to the `value` or `checked` property of the element.
|
|
134
139
|
```html
|
|
135
140
|
<div :data="{ name: 'Stranger' }">
|
|
@@ -140,9 +145,13 @@ element tag or attributes match a specific criteria. Here's the list of attribut
|
|
|
140
145
|
```html
|
|
141
146
|
<button :on:click="console.log('clicked')"></button>
|
|
142
147
|
```
|
|
143
|
-
- `:{
|
|
148
|
+
- `:attr:{name}` sets the corresponding attribute for `name` in the node
|
|
149
|
+
```html
|
|
150
|
+
<a :attr:href="buildUrl()"></a>
|
|
151
|
+
```
|
|
152
|
+
- `:prop:{name}` sets the corresponding property for (camel-case converted) `name` in the node
|
|
144
153
|
```html
|
|
145
|
-
<
|
|
154
|
+
<video :prop:src="buildSrc()"></video>
|
|
146
155
|
```
|
|
147
156
|
- `{{ value }}` replaces `value` in text nodes
|
|
148
157
|
```html
|
|
@@ -153,7 +162,7 @@ element tag or attributes match a specific criteria. Here's the list of attribut
|
|
|
153
162
|
|
|
154
163
|
To avoid violation of Content Security Policy (CSP) that forbids the use of `eval()`, `Mancha`
|
|
155
164
|
evaluates all expressions using [`jexpr`][jexpr]. This means that only simple expressions are
|
|
156
|
-
allowed, and spaces must be used to separate different
|
|
165
|
+
allowed, and spaces must be used to separate different expression tokens. For example:
|
|
157
166
|
|
|
158
167
|
```html
|
|
159
168
|
<!-- Valid expression: string concatenation -->
|
|
@@ -210,13 +219,13 @@ allowed, and spaces must be used to separate different expressions tokens. For e
|
|
|
210
219
|
</body>
|
|
211
220
|
```
|
|
212
221
|
|
|
213
|
-
## Scoping
|
|
222
|
+
## Variable Scoping
|
|
214
223
|
|
|
215
224
|
Contents of the `:data` attribute are only available to subnodes in the HTML tree. This is better
|
|
216
225
|
illustrated with an example:
|
|
217
226
|
|
|
218
227
|
```html
|
|
219
|
-
<body :data="{ name: 'stranger' }">
|
|
228
|
+
<body :data="{ name: 'stranger', key: '1234' }">
|
|
220
229
|
<!-- Hello, stranger -->
|
|
221
230
|
<h1>Hello, {{ name }}</h1>
|
|
222
231
|
|
|
@@ -225,7 +234,7 @@ illustrated with an example:
|
|
|
225
234
|
|
|
226
235
|
<!-- How are you, danger? The secret message is "secret" -->
|
|
227
236
|
<p :data="{ name: 'danger', message: 'secret' }">
|
|
228
|
-
How are you, {{ name }}? The secret message is: "{{ message }}".
|
|
237
|
+
How are you, {{ name }}? The secret message is: "{{ message }}"".
|
|
229
238
|
</p>
|
|
230
239
|
</body>
|
|
231
240
|
```
|
|
@@ -257,6 +266,19 @@ const subrenderer = document.querySelector("p").renderer;
|
|
|
257
266
|
subrenderer.$.message = "banana";
|
|
258
267
|
```
|
|
259
268
|
|
|
269
|
+
To access variables defined in the parent renderer, you can use the subrenderer's `$parent`
|
|
270
|
+
attribute:
|
|
271
|
+
|
|
272
|
+
```html
|
|
273
|
+
<body :data="{ name: 'stranger' }">
|
|
274
|
+
<!-- Hello, stranger! -->
|
|
275
|
+
<p :data="{}">Hello, {{ $parent.name }}!</p>
|
|
276
|
+
</body>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Renderers also have a `$root` attribute, which references the root element where `mancha` was
|
|
280
|
+
mounted and defaults to the document's body, unless explicitly provided.
|
|
281
|
+
|
|
260
282
|
## Styling
|
|
261
283
|
|
|
262
284
|
Some basic styling rules are built into the library and can be optionally used. The styling
|
|
@@ -264,7 +286,7 @@ component was designed to be used in the browser, and it's enabled by adding a `
|
|
|
264
286
|
to the `<script>` tag that loads `mancha`. The supported rulesets are:
|
|
265
287
|
|
|
266
288
|
- `basic`: inspired by [these rules](https://www.swyx.io/css-100-bytes), the full CSS can be found
|
|
267
|
-
[here](./src/
|
|
289
|
+
[here](./src/css_gen_basic.ts).
|
|
268
290
|
- `utils`: utility classes inspired by [tailwindcss](https://tailwindcss.com), the resulting CSS is
|
|
269
291
|
a drop-in replacement for a subset of the classes provided by `tailwindcss` with the main
|
|
270
292
|
exception of the color palette which is borrowed from
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { IRenderer } from "./
|
|
1
|
+
import { IRenderer } from "./renderer.js";
|
|
2
2
|
import { ParserParams, RenderParams } from "./interfaces.js";
|
|
3
3
|
export declare class Renderer extends IRenderer {
|
|
4
|
+
readonly impl = "browser";
|
|
4
5
|
protected readonly dirpath: string;
|
|
5
6
|
parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
|
|
6
7
|
serializeHTML(root: Node | DocumentFragment): string;
|
package/dist/browser.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { IRenderer } from "./
|
|
1
|
+
import { IRenderer } from "./renderer.js";
|
|
2
2
|
import { dirname } from "./dome.js";
|
|
3
3
|
export class Renderer extends IRenderer {
|
|
4
|
-
|
|
4
|
+
impl = "browser";
|
|
5
|
+
dirpath = dirname(globalThis.location?.href ?? "http://localhost/");
|
|
5
6
|
parseHTML(content, params = { rootDocument: false }) {
|
|
6
7
|
if (params.rootDocument) {
|
|
7
8
|
return new DOMParser().parseFromString(content, "text/html");
|
package/dist/css_gen_utils.js
CHANGED
|
@@ -461,7 +461,7 @@ function posneg(props) {
|
|
|
461
461
|
// Positive percent units.
|
|
462
462
|
...PERCENTS.map((v) => [`${klass}-${v}\\%`, `${prop}: ${v}%`]),
|
|
463
463
|
// Negative percent units.
|
|
464
|
-
...PERCENTS.map((v) => [`-${klass}-${v}\\%`,
|
|
464
|
+
...PERCENTS.map((v) => [`-${klass}-${v}\\%`, `${prop}: -${v}%`]),
|
|
465
465
|
])
|
|
466
466
|
.flatMap(([klass, rule]) => [
|
|
467
467
|
`.${klass} { ${rule} }`,
|
|
@@ -470,29 +470,35 @@ function posneg(props) {
|
|
|
470
470
|
]);
|
|
471
471
|
}
|
|
472
472
|
function autoxy(props) {
|
|
473
|
-
return Object.entries(props)
|
|
473
|
+
return Object.entries(props)
|
|
474
|
+
.flatMap(([prop, klass]) => [
|
|
474
475
|
// Auto.
|
|
475
|
-
|
|
476
|
+
[`${klass}-auto`, `${prop}: auto`],
|
|
476
477
|
// Auto x-axis.
|
|
477
|
-
|
|
478
|
+
[`${klass}x-auto`, `${prop}-left: auto; ${prop}-right: auto;`],
|
|
478
479
|
// Auto y-axis.
|
|
479
|
-
|
|
480
|
+
[`${klass}y-auto`, `${prop}-top: auto; ${prop}-bottom: auto;`],
|
|
480
481
|
// Zero x-axis.
|
|
481
|
-
|
|
482
|
+
[`${klass}x-0`, `${prop}-left: 0; ${prop}-right: 0;`],
|
|
482
483
|
// Zero y-axis.
|
|
483
|
-
|
|
484
|
+
[`${klass}y-0`, `${prop}-top: 0; ${prop}-bottom: 0;`],
|
|
484
485
|
// Positive REM units x-axis.
|
|
485
|
-
...UNITS_ALL.map((v) => [v, v * REM_UNIT]).map(([k, v]) =>
|
|
486
|
+
...UNITS_ALL.map((v) => [v, v * REM_UNIT]).map(([k, v]) => [`${klass}x-${k}`, `${prop}-left: ${v}rem; ${prop}-right: ${v}rem;`]),
|
|
486
487
|
// Positive REM units y-axis.
|
|
487
|
-
...UNITS_ALL.map((v) => [v, v * REM_UNIT]).map(([k, v]) =>
|
|
488
|
+
...UNITS_ALL.map((v) => [v, v * REM_UNIT]).map(([k, v]) => [`${klass}y-${k}`, `${prop}-top: ${v}rem; ${prop}-bottom: ${v}rem;`]),
|
|
488
489
|
// Positive PX units x-axis.
|
|
489
|
-
...UNITS_ALL.map((v) =>
|
|
490
|
+
...UNITS_ALL.map((v) => [`${klass}x-${v}px`, `${prop}-left: ${v}px; ${prop}-right: ${v}px;`]),
|
|
490
491
|
// Positive PX units y-axis.
|
|
491
|
-
...UNITS_ALL.map((v) =>
|
|
492
|
+
...UNITS_ALL.map((v) => [`${klass}y-${v}px`, `${prop}-top: ${v}px; ${prop}-bottom: ${v}px;`]),
|
|
492
493
|
// Positive percent units x-axis.
|
|
493
|
-
...PERCENTS.map((v) =>
|
|
494
|
+
...PERCENTS.map((v) => [`${klass}x-${v}\\%`, `${prop}-left: ${v}%; ${prop}-right: ${v}%;`]),
|
|
494
495
|
// Positive percent units y-axis.
|
|
495
|
-
...PERCENTS.map((v) =>
|
|
496
|
+
...PERCENTS.map((v) => [`${klass}y-${v}\\%`, `${prop}-top: ${v}%; ${prop}-bottom: ${v}%;`]),
|
|
497
|
+
])
|
|
498
|
+
.flatMap(([klass, rule]) => [
|
|
499
|
+
`.${klass} { ${rule} }`,
|
|
500
|
+
`${wrapPseudoStates(klass).join(",")} { ${rule} }`,
|
|
501
|
+
...wrapMediaQueries(klass, rule),
|
|
496
502
|
]);
|
|
497
503
|
}
|
|
498
504
|
function tblr(props) {
|
|
@@ -573,32 +579,36 @@ function border() {
|
|
|
573
579
|
function between() {
|
|
574
580
|
return [
|
|
575
581
|
// Zero for x margin.
|
|
576
|
-
|
|
582
|
+
[`space-x-0 > *`, `margin-left: 0`],
|
|
577
583
|
// Zero for y margin.
|
|
578
|
-
|
|
584
|
+
[`space-y-0 > *`, `margin-top: 0`],
|
|
579
585
|
// Positive REM units for x margin.
|
|
580
|
-
...UNITS_ALL.map((v) =>
|
|
586
|
+
...UNITS_ALL.map((v) => [`space-x-${v} > :not(:first-child)`, `margin-left: ${v * REM_UNIT}rem`]),
|
|
581
587
|
// Positive REM units for y margin.
|
|
582
|
-
...UNITS_ALL.map((v) =>
|
|
588
|
+
...UNITS_ALL.map((v) => [`space-y-${v} > :not(:first-child)`, `margin-top: ${v * REM_UNIT}rem`]),
|
|
583
589
|
// Positive PX units for x margin.
|
|
584
|
-
...UNITS_ALL.map((v) =>
|
|
590
|
+
...UNITS_ALL.map((v) => [`space-x-${v}px > :not(:first-child)`, `margin-left: ${v}px`]),
|
|
585
591
|
// Positive PX units for y margin.
|
|
586
|
-
...UNITS_ALL.map((v) =>
|
|
592
|
+
...UNITS_ALL.map((v) => [`space-y-${v}px > :not(:first-child)`, `margin-top: ${v}px`]),
|
|
587
593
|
// Zero for gap.
|
|
588
|
-
|
|
594
|
+
[`gap-0`, `gap: 0`],
|
|
589
595
|
// Positive REM units for gap.
|
|
590
|
-
...UNITS_ALL.map((v) =>
|
|
596
|
+
...UNITS_ALL.map((v) => [`gap-${v}`, `gap: ${v * REM_UNIT}rem`]),
|
|
591
597
|
// Positive PX units for gap.
|
|
592
|
-
...UNITS_ALL.map((v) =>
|
|
598
|
+
...UNITS_ALL.map((v) => [`gap-${v}px`, `gap: ${v}px`]),
|
|
593
599
|
// Positive REM units for col gap.
|
|
594
|
-
...UNITS_ALL.map((v) =>
|
|
600
|
+
...UNITS_ALL.map((v) => [`gap-x-${v}`, `column-gap: ${v * REM_UNIT}rem`]),
|
|
595
601
|
// Positive REM units for row gap.
|
|
596
|
-
...UNITS_ALL.map((v) =>
|
|
602
|
+
...UNITS_ALL.map((v) => [`gap-y-${v}`, `row-gap: ${v * REM_UNIT}rem`]),
|
|
597
603
|
// Positive PX units for col gap.
|
|
598
|
-
...UNITS_ALL.map((v) =>
|
|
604
|
+
...UNITS_ALL.map((v) => [`gap-x-${v}px`, `column-gap: ${v}px`]),
|
|
599
605
|
// Positive PX units for row gap.
|
|
600
|
-
...UNITS_ALL.map((v) =>
|
|
601
|
-
]
|
|
606
|
+
...UNITS_ALL.map((v) => [`gap-y-${v}px`, `row-gap: ${v}px`]),
|
|
607
|
+
].flatMap(([klass, rule]) => [
|
|
608
|
+
`.${klass} { ${rule} }`,
|
|
609
|
+
`${wrapPseudoStates(klass).join(",")} { ${rule} }`,
|
|
610
|
+
...wrapMediaQueries(klass, rule),
|
|
611
|
+
]);
|
|
602
612
|
}
|
|
603
613
|
function custom() {
|
|
604
614
|
return Object.entries(PROPS_CUSTOM).flatMap(([klass, props]) => Object.entries(props).flatMap(([propkey, propval]) => [
|
package/dist/dome.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
type ElementWithAttribs = Element & {
|
|
2
|
+
dataset?: DOMStringMap;
|
|
3
|
+
attribs?: {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
1
7
|
/**
|
|
2
8
|
* Traverses the DOM tree starting from the given root node and yields each child node.
|
|
3
9
|
* Nodes in the `skip` set will be skipped during traversal.
|
|
@@ -15,10 +21,14 @@ export declare function hasFunction(obj: any, func: string): boolean;
|
|
|
15
21
|
* @returns camel-cased attribute name
|
|
16
22
|
*/
|
|
17
23
|
export declare function attributeNameToCamelCase(name: string): string;
|
|
18
|
-
export declare function getAttribute(elem:
|
|
19
|
-
export declare function
|
|
20
|
-
export declare function
|
|
21
|
-
export declare function
|
|
24
|
+
export declare function getAttribute(elem: ElementWithAttribs, name: string): string | null;
|
|
25
|
+
export declare function getAttributeOrDataset(elem: ElementWithAttribs, name: string, attributePrefix?: string): string | null;
|
|
26
|
+
export declare function setAttribute(elem: ElementWithAttribs, name: string, value: string): void;
|
|
27
|
+
export declare function safeSetAttribute(elem: ElementWithAttribs, name: string, value: string): void;
|
|
28
|
+
export declare function setProperty(elem: ElementWithAttribs, name: string, value: any): void;
|
|
29
|
+
export declare function removeAttribute(elem: ElementWithAttribs, name: string): void;
|
|
30
|
+
export declare function removeAttributeOrDataset(elem: ElementWithAttribs, name: string, prefix?: string): void;
|
|
31
|
+
export declare function cloneAttribute(elemFrom: ElementWithAttribs, elemDest: ElementWithAttribs, name: string): void;
|
|
22
32
|
export declare function firstElementChild(elem: Element): Element | null;
|
|
23
33
|
export declare function replaceWith(original: ChildNode, ...replacement: Node[]): void;
|
|
24
34
|
export declare function replaceChildren(parent: ParentNode, ...nodes: Node[]): void;
|
|
@@ -40,3 +50,4 @@ export declare function dirname(fpath: string): string;
|
|
|
40
50
|
* @returns A boolean indicating whether the file path is relative or not.
|
|
41
51
|
*/
|
|
42
52
|
export declare function isRelativePath(fpath: string): boolean;
|
|
53
|
+
export {};
|
package/dist/dome.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { safeAttrPrefix } from "safevalues";
|
|
2
2
|
import { safeElement } from "safevalues/dom";
|
|
3
|
-
const SAFE_ATTRS = [
|
|
4
|
-
safeAttrPrefix `:`,
|
|
5
|
-
safeAttrPrefix `style`,
|
|
6
|
-
safeAttrPrefix `class`,
|
|
7
|
-
];
|
|
3
|
+
const SAFE_ATTRS = [safeAttrPrefix `:`, safeAttrPrefix `style`, safeAttrPrefix `class`];
|
|
8
4
|
/**
|
|
9
5
|
* Traverses the DOM tree starting from the given root node and yields each child node.
|
|
10
6
|
* Nodes in the `skip` set will be skipped during traversal.
|
|
@@ -49,27 +45,62 @@ export function getAttribute(elem, name) {
|
|
|
49
45
|
if (hasProperty(elem, "attribs"))
|
|
50
46
|
return elem.attribs?.[name] ?? null;
|
|
51
47
|
else
|
|
52
|
-
return elem.getAttribute?.(name);
|
|
48
|
+
return elem.getAttribute?.(name) ?? null;
|
|
49
|
+
}
|
|
50
|
+
export function getAttributeOrDataset(elem, name, attributePrefix = "") {
|
|
51
|
+
return (getAttribute(elem, attributePrefix + name) ||
|
|
52
|
+
(elem.dataset?.[attributeNameToCamelCase(name)] ?? null));
|
|
53
53
|
}
|
|
54
54
|
export function setAttribute(elem, name, value) {
|
|
55
|
+
if (hasProperty(elem, "attribs"))
|
|
56
|
+
elem.attribs[name] = value;
|
|
57
|
+
else
|
|
58
|
+
elem.setAttribute?.(name, value);
|
|
59
|
+
}
|
|
60
|
+
export function safeSetAttribute(elem, name, value) {
|
|
55
61
|
if (hasProperty(elem, "attribs"))
|
|
56
62
|
elem.attribs[name] = value;
|
|
57
63
|
else
|
|
58
64
|
safeElement.setPrefixedAttribute(SAFE_ATTRS, elem, name, value);
|
|
59
65
|
}
|
|
66
|
+
export function setProperty(elem, name, value) {
|
|
67
|
+
switch (name) {
|
|
68
|
+
// Directly set some safe, known properties.
|
|
69
|
+
case "disabled":
|
|
70
|
+
elem.disabled = value;
|
|
71
|
+
return;
|
|
72
|
+
case "selected":
|
|
73
|
+
elem.selected = value;
|
|
74
|
+
return;
|
|
75
|
+
case "checked":
|
|
76
|
+
elem.checked = value;
|
|
77
|
+
return;
|
|
78
|
+
// Fall back to setting the property directly (unsafe).
|
|
79
|
+
default:
|
|
80
|
+
elem[name] = value;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
60
83
|
export function removeAttribute(elem, name) {
|
|
61
84
|
if (hasProperty(elem, "attribs"))
|
|
62
85
|
delete elem.attribs[name];
|
|
63
86
|
else
|
|
64
87
|
elem.removeAttribute?.(name);
|
|
65
88
|
}
|
|
89
|
+
export function removeAttributeOrDataset(elem, name, prefix = "") {
|
|
90
|
+
removeAttribute(elem, `${prefix}${name}`);
|
|
91
|
+
removeAttribute(elem, `data-${name}`);
|
|
92
|
+
}
|
|
66
93
|
export function cloneAttribute(elemFrom, elemDest, name) {
|
|
67
94
|
if (hasProperty(elemFrom, "attribs") && hasProperty(elemDest, "attribs")) {
|
|
68
95
|
elemDest.attribs[name] = elemFrom.attribs[name];
|
|
69
96
|
}
|
|
97
|
+
else if (name.startsWith("data-")) {
|
|
98
|
+
const datasetKey = attributeNameToCamelCase(name.slice(5));
|
|
99
|
+
elemDest.dataset[datasetKey] = elemFrom.dataset?.[datasetKey];
|
|
100
|
+
}
|
|
70
101
|
else {
|
|
71
102
|
const attr = elemFrom?.getAttribute?.(name);
|
|
72
|
-
|
|
103
|
+
safeSetAttribute(elemDest, name, attr || "");
|
|
73
104
|
}
|
|
74
105
|
}
|
|
75
106
|
export function firstElementChild(elem) {
|
|
@@ -145,6 +176,11 @@ export function ellipsize(str, maxLength = 0) {
|
|
|
145
176
|
return str.slice(0, maxLength - 1) + "…";
|
|
146
177
|
}
|
|
147
178
|
export function nodeToString(node, maxLength = 0) {
|
|
179
|
+
if (globalThis.DocumentFragment && node instanceof DocumentFragment) {
|
|
180
|
+
return Array.from(node.childNodes)
|
|
181
|
+
.map((node) => nodeToString(node, maxLength))
|
|
182
|
+
.join("");
|
|
183
|
+
}
|
|
148
184
|
return ellipsize(node.outerHTML || node.nodeValue || String(node), maxLength);
|
|
149
185
|
}
|
|
150
186
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ParserParams, RenderParams } from "./interfaces.js";
|
|
2
|
-
import { IRenderer } from "./
|
|
2
|
+
import { IRenderer } from "./renderer.js";
|
|
3
3
|
export declare class Renderer extends IRenderer {
|
|
4
|
+
readonly impl = "jsdom";
|
|
4
5
|
parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
|
|
5
6
|
serializeHTML(root: Node | DocumentFragment | Document): string;
|
|
6
7
|
createElement(tag: string, owner?: Document | null): Element;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as fs from "fs/promises";
|
|
2
2
|
import { JSDOM } from "jsdom";
|
|
3
|
-
import { IRenderer } from "./
|
|
3
|
+
import { IRenderer } from "./renderer.js";
|
|
4
4
|
export class Renderer extends IRenderer {
|
|
5
|
+
impl = "jsdom";
|
|
5
6
|
parseHTML(content, params = { rootDocument: false }) {
|
|
6
7
|
if (params.rootDocument) {
|
|
7
8
|
return new JSDOM(content).window.document;
|
package/dist/interfaces.d.ts
CHANGED