synstate-dom 0.5.0 → 0.7.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/README.md +1 -0
- package/dist/control/for.d.mts +4 -0
- package/dist/control/for.d.mts.map +1 -1
- package/dist/control/for.mjs +25 -15
- package/dist/control/for.mjs.map +1 -1
- package/dist/control/mount-switch.d.mts +4 -0
- package/dist/control/mount-switch.d.mts.map +1 -1
- package/dist/control/mount-switch.mjs +25 -12
- package/dist/control/mount-switch.mjs.map +1 -1
- package/dist/control/portal.d.mts.map +1 -1
- package/dist/control/portal.mjs +2 -2
- package/dist/control/portal.mjs.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/internal/after-attach.d.mts +35 -0
- package/dist/internal/after-attach.d.mts.map +1 -0
- package/dist/internal/after-attach.mjs +122 -0
- package/dist/internal/after-attach.mjs.map +1 -0
- package/dist/internal/as-constant.d.mts +4 -4
- package/dist/internal/dom-tables.d.mts.map +1 -1
- package/dist/internal/dom-tables.mjs +3 -0
- package/dist/internal/dom-tables.mjs.map +1 -1
- package/dist/internal/index.d.mts +1 -0
- package/dist/internal/index.d.mts.map +1 -1
- package/dist/internal/index.mjs +1 -0
- package/dist/internal/index.mjs.map +1 -1
- package/dist/jsx/element-props.d.mts +15 -2
- package/dist/jsx/element-props.d.mts.map +1 -1
- package/dist/jsx/jsx.mjs +2 -2
- package/dist/jsx/jsx.mjs.map +1 -1
- package/dist/keyboard/index.d.mts +2 -0
- package/dist/keyboard/index.d.mts.map +1 -0
- package/dist/keyboard/index.mjs +2 -0
- package/dist/keyboard/index.mjs.map +1 -0
- package/dist/keyboard/is-ime-key-down.d.mts +11 -0
- package/dist/keyboard/is-ime-key-down.d.mts.map +1 -0
- package/dist/keyboard/is-ime-key-down.mjs +15 -0
- package/dist/keyboard/is-ime-key-down.mjs.map +1 -0
- package/dist/render.d.mts +2 -1
- package/dist/render.d.mts.map +1 -1
- package/dist/render.mjs +19 -4
- package/dist/render.mjs.map +1 -1
- package/package.json +10 -10
- package/src/control/for.mts +41 -19
- package/src/control/mount-switch.mts +36 -15
- package/src/control/portal.mts +7 -3
- package/src/index.mts +1 -0
- package/src/internal/after-attach.mts +173 -0
- package/src/internal/as-constant.mts +4 -4
- package/src/internal/dom-tables.mts +3 -0
- package/src/internal/index.mts +1 -0
- package/src/jsx/element-props.mts +39 -2
- package/src/jsx/jsx.mts +2 -2
- package/src/keyboard/index.mts +1 -0
- package/src/keyboard/is-ime-key-down.mts +20 -0
- package/src/keyboard/is-ime-key-down.test.mts +42 -0
- package/src/render.mts +32 -6
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isImeKeyDown } from './is-ime-key-down.mjs';
|
|
2
|
+
|
|
3
|
+
// Plain objects stand in for `KeyboardEvent`s: it reads only these fields, and
|
|
4
|
+
// Node.js has no `KeyboardEvent`.
|
|
5
|
+
describe(isImeKeyDown, () => {
|
|
6
|
+
test('is a key down sent while an input method is composing', () => {
|
|
7
|
+
assert.isTrue(isImeKeyDown(keyDown('a', 229, true)));
|
|
8
|
+
|
|
9
|
+
assert.isTrue(isImeKeyDown(keyDown('ArrowUp', 229, true)));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test.each(['Enter', 'Escape'])(
|
|
13
|
+
'is %s with key code 229, which Safari sends after compositionend',
|
|
14
|
+
(key) => {
|
|
15
|
+
assert.isTrue(isImeKeyDown(keyDown(key, 229)));
|
|
16
|
+
},
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
test('is not another key with key code 229, as an Android virtual keyboard sends every key', () => {
|
|
20
|
+
assert.isFalse(isImeKeyDown(keyDown('ArrowUp', 229)));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test.each([
|
|
24
|
+
['Enter', 13],
|
|
25
|
+
['Escape', 27],
|
|
26
|
+
['a', 65],
|
|
27
|
+
] as const)('is not a plain %s', (key, code) => {
|
|
28
|
+
assert.isFalse(isImeKeyDown(keyDown(key, code)));
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** The fields of a key down that `isImeKeyDown` reads. */
|
|
33
|
+
const keyDown = (
|
|
34
|
+
key: string,
|
|
35
|
+
code: number,
|
|
36
|
+
isComposing: boolean = false,
|
|
37
|
+
): Readonly<{ key: string; keyCode: number; isComposing: boolean }> =>
|
|
38
|
+
({
|
|
39
|
+
key,
|
|
40
|
+
keyCode: code,
|
|
41
|
+
isComposing,
|
|
42
|
+
}) as const;
|
package/src/render.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createScope } from 'synstate';
|
|
2
|
+
import { appendTo, mountThenInsert } from './internal/index.mjs';
|
|
2
3
|
import { type JSX, toNodes } from './jsx/index.mjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -7,7 +8,8 @@ import { type JSX, toNodes } from './jsx/index.mjs';
|
|
|
7
8
|
*
|
|
8
9
|
* `app` is called once, inside a new root scope; everything created while it
|
|
9
10
|
* and the description it returns are mounted belongs to that scope, and
|
|
10
|
-
* unmounting disposes it and removes the nodes.
|
|
11
|
+
* unmounting disposes it and removes the nodes. If mounting throws, what was
|
|
12
|
+
* mounted is disposed and removed before the error is rethrown.
|
|
11
13
|
*
|
|
12
14
|
* `render(App, el)` rather than `render(<App />, el)`: taking the component
|
|
13
15
|
* makes it plain that it is evaluated here.
|
|
@@ -18,15 +20,39 @@ export const render = (
|
|
|
18
20
|
): (() => void) => {
|
|
19
21
|
const root = createScope(undefined);
|
|
20
22
|
|
|
21
|
-
const nodes =
|
|
23
|
+
const mut_inserted: { nodes: readonly ChildNode[] } = { nodes: [] };
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return () => {
|
|
25
|
+
const unmount = (): void => {
|
|
26
26
|
root.dispose();
|
|
27
27
|
|
|
28
|
-
for (const node of nodes) {
|
|
28
|
+
for (const node of mut_inserted.nodes) {
|
|
29
29
|
node.remove();
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
root.run(() =>
|
|
35
|
+
mountThenInsert(
|
|
36
|
+
mountApp,
|
|
37
|
+
app,
|
|
38
|
+
(into: Element, nodes: readonly ChildNode[]) => {
|
|
39
|
+
mut_inserted.nodes = nodes;
|
|
40
|
+
|
|
41
|
+
appendTo(into, nodes);
|
|
42
|
+
},
|
|
43
|
+
container,
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
// An update applied after the app was appended can throw; take back what
|
|
48
|
+
// was mounted rather than leave it in `container` with no way to unmount.
|
|
49
|
+
unmount();
|
|
50
|
+
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return unmount;
|
|
32
55
|
};
|
|
56
|
+
|
|
57
|
+
const mountApp = (app: () => JSX.Element): readonly ChildNode[] =>
|
|
58
|
+
toNodes(app().mount());
|