Skip to content

Commit 53925e6

Browse files
committed
added holed comments + made unsafe tag compatible
1 parent 35eb661 commit 53925e6

File tree

9 files changed

+35
-48
lines changed

9 files changed

+35
-48
lines changed

src/dom/ish.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { assign, freeze, isArray } from '../utils.js';
55
export const ELEMENT = 1;
66
export const ATTRIBUTE = 2;
77
export const TEXT = 3;
8+
export const DATA = 4;
89
export const COMMENT = 8;
910
export const DOCUMENT_TYPE = 10;
1011
export const FRAGMENT = 11;

src/dom/node.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import DEBUG from '../debug.js';
22
import errors from '../errors.js';
3-
3+
import { reduce } from '../utils.js';
44
import resolve from './resolve.js';
55
import set from './process.js';
66
import props from './props.js';
@@ -51,9 +51,7 @@ const create = ({ p: fragment, d: updates }, values) => {
5151
if (refs) setRefs(refs);
5252

5353
if (DEBUG && values.length) console.timeEnd(`mapping ${values.length} updates`);
54-
const { childNodes } = root;
55-
length = childNodes.length;
56-
return length === 1 ? childNodes[0] : root;
54+
return reduce(root);
5755
};
5856

5957
const tag = (xml, cache = new WeakMap) =>

src/dom/update.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import {
55
ATTRIBUTE as TEMPLATE_ATTRIBUTE,
66
COMMENT as TEMPLATE_COMMENT,
77
COMPONENT as TEMPLATE_COMPONENT,
8+
DATA as TEMPLATE_DATA,
89
TEXT as TEMPLATE_TEXT,
910
} from './ish.js';
1011

11-
import { Unsafe, assign, entries, isArray } from '../utils.js';
12+
import { Unsafe, assign, entries, reduce, isArray } from '../utils.js';
1213
import { PersistentFragment, diffFragment } from './persistent-fragment.js';
1314
import { ref } from './ref.js';
1415
import creator from './creator.js';
@@ -167,6 +168,7 @@ export const update = (node, type, path, name, hint) => {
167168
}
168169
}
169170
}
171+
case TEMPLATE_DATA: return pdt(path, directFor('data'), TEXT);
170172
}
171173
};
172174

@@ -211,8 +213,10 @@ function toggle(node, curr) {
211213

212214
function unsafe(node, curr) {
213215
const [wm, xml] = this;
214-
const pf = PersistentFragment(fragment(curr, xml));
215-
(wm.get(node) ?? node).replaceWith(pf);
216-
wm.set(node, pf);
216+
const f = fragment(curr, xml);
217+
const u = reduce(f);
218+
const n = u === f ? PersistentFragment(u) : u;
219+
(wm.get(node) ?? node).replaceWith(n);
220+
wm.set(node, n);
217221
return curr;
218222
}

src/parser/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ATTRIBUTE,
88
COMMENT,
99
COMPONENT,
10+
DATA,
1011
ELEMENT,
1112
TEXT,
1213
TEXT_ELEMENTS,
@@ -34,7 +35,7 @@ const ATTRS = /([^\s/>=]+)(?:=(\x00|(?:(['"])[\s\S]*?\3)))?/g;
3435
/** @typedef {import('../dom/ish.js').Node} Node */
3536
/** @typedef {import('../dom/ish.js').Element} Element */
3637
/** @typedef {import('../dom/ish.js').Component} Component */
37-
/** @typedef {(node: import('../dom/ish.js').Node, type: typeof ATTRIBUTE | typeof TEXT | typeof COMMENT | typeof COMPONENT, path: number[], name: string, hint: unknown) => unknown} update */
38+
/** @typedef {(node: import('../dom/ish.js').Node, type: typeof ATTRIBUTE | typeof DATA | typeof TEXT | typeof COMMENT | typeof COMPONENT, path: number[], name: string, hint: unknown) => unknown} update */
3839
/** @typedef {Element | Component} Container */
3940

4041
/** @type {update} */
@@ -130,6 +131,11 @@ export default ({
130131
if (DEBUG && (i - index) < 6) throw errors.invalid_comment(template);
131132
const data = content.slice(index + 4, i - 2);
132133
if (data[0] === '!') append(node, new Comment(data.slice(1).replace(/!$/, '')));
134+
else if (data === NUL) {
135+
const comment = append(node, new Comment('◦'));
136+
values.push(update(comment, DATA, path(comment), '', holes[hole++]));
137+
pos = i + 1;
138+
}
133139
}
134140
else {
135141
if (DEBUG && !content.slice(index + 2, i).toLowerCase().startsWith('doctype')) throw errors.invalid_doctype(template, content.slice(index + 2, i));

src/utils.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,16 @@ export class Unsafe {
3434
}
3535
}
3636

37-
export const unsafe = data => new Unsafe(data);
37+
export const reduce = node => {
38+
const { childNodes } = node;
39+
return childNodes.length === 1 ? childNodes[0] : node;
40+
};
41+
42+
export const unsafe = (template, ...values) => new Unsafe(
43+
typeof template === 'string' ?
44+
template :
45+
[template[0], ...values.map((v, i) => v + template[i + 1])].join('')
46+
);
3847

3948
export const createComment = value => document.createComment(value);
4049
/* c8 ignore stop */

test/base.html

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,7 @@
1212
</script>
1313
<script type="module">
1414
import { render, html, unsafe } from 'uhtml';
15-
import { effect, signal } from 'dom-cue';
16-
import { proxy, deref } from 'weaky';
1715

18-
const fr = new FinalizationRegistry(cleanup => {
19-
console.log('cleaning up');
20-
cleanup();
21-
});
22-
23-
function Button(props, state) {
24-
const counter = proxy(html`0`);
25-
const node = html`
26-
<button class="counter" onclick=${() => props.signal.value++}>
27-
${props.text}
28-
${deref(counter)}
29-
</button>
30-
`;
31-
32-
fr.register(node, effect(() => {
33-
counter.data = props.signal.value;
34-
}));
35-
36-
return node;
37-
}
38-
39-
const ref = { current: null };
40-
render(document.body, () => html`
41-
<h1 key=${1} ref=${ref} class=${'title'} onclick=${() => alert('Hello DOM!')}>
42-
Hello ${[html`DOM`]} !
43-
</h2>
44-
${unsafe('<hr />')}
45-
<${Button} text=${'👋'} signal=${signal(0)} />
46-
<${Button} text=${'👋'} signal=${signal(0)} />
47-
<${Button} text=${'👋'} signal=${signal(0)} />
48-
`);
49-
50-
console.log(ref.current);
51-
ref.current = null;
16+
debugger;
17+
render(document.body, html`${unsafe`<hr /><hr />`} ah, <em>ok</em>`);
5218
</script>

types/dom/ish.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const ELEMENT: 1;
22
export const ATTRIBUTE: 2;
33
export const TEXT: 3;
4+
export const DATA: 4;
45
export const COMMENT: 8;
56
export const DOCUMENT_TYPE: 10;
67
export const FRAGMENT: 11;

types/parser/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default _default;
1111
export type Node = import("../dom/ish.js").Node;
1212
export type Element = import("../dom/ish.js").Element;
1313
export type Component = import("../dom/ish.js").Component;
14-
export type update = (node: import("../dom/ish.js").Node, type: typeof ATTRIBUTE | typeof TEXT | typeof COMMENT | typeof COMPONENT, path: number[], name: string, hint: unknown) => unknown;
14+
export type update = (node: import("../dom/ish.js").Node, type: typeof ATTRIBUTE | typeof DATA | typeof TEXT | typeof COMMENT | typeof COMPONENT, path: number[], name: string, hint: unknown) => unknown;
1515
export type Container = Element | Component;
1616
import { Comment as DOMComment } from '../dom/ish.js';
1717
import { DocumentType as DOMDocumentType } from '../dom/ish.js';
@@ -20,6 +20,7 @@ import { Fragment as DOMFragment } from '../dom/ish.js';
2020
import { Element as DOMElement } from '../dom/ish.js';
2121
import { Component as DOMComponent } from '../dom/ish.js';
2222
import { ATTRIBUTE } from '../dom/ish.js';
23+
import { DATA } from '../dom/ish.js';
2324
import { TEXT } from '../dom/ish.js';
2425
import { COMMENT } from '../dom/ish.js';
2526
import { COMPONENT } from '../dom/ish.js';

types/utils.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export class Unsafe {
55
toString(): string;
66
#private;
77
}
8-
export function unsafe(data: any): Unsafe;
8+
export function reduce(node: any): any;
9+
export function unsafe(template: any, ...values: any[]): Unsafe;
910
export function createComment(value: any): Comment;
1011
export const assign: {
1112
<T extends {}, U>(target: T, source: U): T & U;

0 commit comments

Comments
 (0)