synstate-dom 0.6.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.
@@ -17,6 +17,10 @@ import { type JSX } from '../jsx/index.mjs';
17
17
  * nodes; the rows that stay are moved as little as the longest increasing
18
18
  * subsequence allows.
19
19
  *
20
+ * An update that arrives before the anchor is in a parent (a later sibling
21
+ * wrote `items` while the enclosing element was still mounting its children) is
22
+ * applied, with the latest `items`, once the nodes `For` returned are inserted.
23
+ *
20
24
  * `key` is required, as in React; `(_, i) => i` matches rows by position. A key
21
25
  * that appears twice is reported with `console.error`, and its later
22
26
  * occurrences are rebuilt on every update.
@@ -1 +1 @@
1
- {"version":3,"file":"for.d.mts","sourceRoot":"","sources":["../../src/control/for.mts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,qBAAqB,EAG3B,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,EAAsB,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAGhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,6BAIlB,QAAQ,CAAC;IACV,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC9B,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,QAAQ,EAAE,CACR,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,KAClC,GAAG,CAAC,OAAO,CAAC;CAClB,CAAC,KAAG,GAAG,CAAC,OAwML,CAAC"}
1
+ {"version":3,"file":"for.d.mts","sourceRoot":"","sources":["../../src/control/for.mts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,qBAAqB,EAG3B,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOpE,OAAO,EAAsB,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAGhE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,6BAIlB,QAAQ,CAAC;IACV,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC9B,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,QAAQ,EAAE,CACR,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,KAClC,GAAG,CAAC,OAAO,CAAC;CAClB,CAAC,KAAG,GAAG,CAAC,OAqNL,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { createInitializedSyncChildObservable, createScope, getCurrentScope, map, onScopeDispose, } from 'synstate';
2
2
  import { Arr, Optional } from 'ts-data-forge';
3
3
  import { toObservable } from '../constant/index.mjs';
4
- import { bindValue } from '../internal/index.mjs';
4
+ import { applyWhenAttached, bindValue, insertBefore, mountThenInsert, } from '../internal/index.mjs';
5
5
  import { mountable, toNodes } from '../jsx/index.mjs';
6
6
  import { longestIncreasingSubsequence } from './longest-increasing-subsequence.mjs';
7
7
 
@@ -20,6 +20,10 @@ import { longestIncreasingSubsequence } from './longest-increasing-subsequence.m
20
20
 
21
21
 
22
22
 
23
+
24
+
25
+
26
+
23
27
 
24
28
 
25
29
 
@@ -35,7 +39,10 @@ export const For = ({ items, key, children, }) => mountable(() => {
35
39
  const callChildren = children;
36
40
  const mut_rows = new Map();
37
41
  const rowStarts = new WeakSet();
38
- const mut_initial = { nodes: [] };
42
+ const mut_initial = {
43
+ nodes: [],
44
+ built: false,
45
+ };
39
46
 
40
47
  const createRow = (rowKey, entry) => {
41
48
  const scope = createScope(parent);
@@ -86,11 +93,10 @@ export const For = ({ items, key, children, }) => mountable(() => {
86
93
  range.setEndBefore(anchor);
87
94
  range.deleteContents();
88
95
  };
89
- bindValue(entries$, (entries) => {
96
+
97
+ const update = (entries) => {
90
98
  const previousOrder = Array.from(mut_rows.keys());
91
- if (anchor.parentNode !== null) {
92
- removeAllAtOnceIfEveryKeyGoes(previousOrder, entries);
93
- }
99
+ removeAllAtOnceIfEveryKeyGoes(previousOrder, entries);
94
100
  for (const [rowKey, row] of mut_rows) {
95
101
  if (entries.byKey.has(rowKey)) {
96
102
  continue;
@@ -98,13 +104,6 @@ export const For = ({ items, key, children, }) => mountable(() => {
98
104
  row.scope.dispose();
99
105
  mut_rows.delete(rowKey);
100
106
  }
101
- if (anchor.parentNode === null) {
102
- mut_initial.nodes = entries.order.flatMap((rowKey) => {
103
- const entry = entries.byKey.get(rowKey);
104
- return entry === undefined ? [] : createRow(rowKey, entry);
105
- });
106
- return;
107
- }
108
107
  if (Arr.eq(previousOrder, entries.order)) {
109
108
  return;
110
109
  }
@@ -124,9 +123,8 @@ export const For = ({ items, key, children, }) => mountable(() => {
124
123
  if (entry === undefined) {
125
124
  continue;
126
125
  }
127
- const [start, ...rest] = createRow(rowKey, entry);
126
+ const [start] = mountThenInsert((e) => createRow(rowKey, e), entry, insertBefore, mut_next);
128
127
  if (start !== undefined) {
129
- mut_next.before(start, ...rest);
130
128
  mut_next = start;
131
129
  }
132
130
  continue;
@@ -137,6 +135,18 @@ export const For = ({ items, key, children, }) => mountable(() => {
137
135
  mut_next = existing.start;
138
136
  }
139
137
  reorderMap(mut_rows, entries.order);
138
+ };
139
+ const updateWhenAttached = applyWhenAttached(anchor, update);
140
+ bindValue(entries$, (entries) => {
141
+ if (!mut_initial.built) {
142
+ mut_initial.built = true;
143
+ mut_initial.nodes = entries.order.flatMap((rowKey) => {
144
+ const entry = entries.byKey.get(rowKey);
145
+ return entry === undefined ? [] : createRow(rowKey, entry);
146
+ });
147
+ return;
148
+ }
149
+ updateWhenAttached(entries);
140
150
  });
141
151
  return Arr.toPushed(mut_initial.nodes, anchor);
142
152
  });
@@ -1 +1 @@
1
- {"version":3,"file":"for.mjs","sourceRoot":"","sources":["../../src/control/for.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"for.mjs","sourceRoot":"","sources":["../../src/control/for.mts"],"names":[],"mappings":"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"}
@@ -13,6 +13,10 @@ import { type Mountable, type MountedNodes } from '../jsx/index.mjs';
13
13
  *
14
14
  * `branch` runs inside the new scope, so whatever it creates belongs to the
15
15
  * branch.
16
+ *
17
+ * A value that arrives before the anchor is in a parent (a later sibling wrote
18
+ * it while the enclosing element was still mounting its children) is kept, and
19
+ * the switch follows the latest one once the nodes it returned are inserted.
16
20
  */
17
21
  export declare const mountSwitch: <V, K>(value: Bindable<V>, keyOf: (current: V) => K, branch: (key: K, current: V) => Mountable | undefined) => MountedNodes;
18
22
  //# sourceMappingURL=mount-switch.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mount-switch.d.mts","sourceRoot":"","sources":["../../src/control/mount-switch.mts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAW,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,CAAC,SACvB,QAAQ,CAAC,CAAC,CAAC,SACX,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,UAChB,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,SAAS,GAAG,SAAS,KACpD,YA6CF,CAAC"}
1
+ {"version":3,"file":"mount-switch.d.mts","sourceRoot":"","sources":["../../src/control/mount-switch.mts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOtD,OAAO,EAAW,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,CAAC,SACvB,QAAQ,CAAC,CAAC,CAAC,SACX,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,UAChB,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,SAAS,GAAG,SAAS,KACpD,YAyDF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { createScope, getCurrentScope, onScopeDispose, } from 'synstate';
2
2
  import { Arr } from 'ts-data-forge';
3
- import { bindValue } from '../internal/index.mjs';
3
+ import { applyWhenAttached, bindValue, insertBefore, mountThenInsert, } from '../internal/index.mjs';
4
4
  import { toNodes } from '../jsx/index.mjs';
5
5
 
6
6
 
@@ -16,18 +16,16 @@ import { toNodes } from '../jsx/index.mjs';
16
16
 
17
17
 
18
18
 
19
+
20
+
21
+
22
+
19
23
  export const mountSwitch = (value, keyOf, branch) => {
20
24
  const parent = getCurrentScope();
21
25
  const anchor = document.createComment('');
22
26
  const mut_state = { current: undefined, initialNodes: [] };
23
- bindValue(value, (v) => {
24
- const key = keyOf(v);
25
- if (mut_state.current !== undefined) {
26
- if (Object.is(mut_state.current.key, key)) {
27
- return;
28
- }
29
- mut_state.current.scope.dispose();
30
- }
27
+
28
+ const mountBranch = (key, v) => {
31
29
  const scope = createScope(parent);
32
30
  const nodes = scope.run(() => {
33
31
  const mounted = toNodes(branch(key, v)?.mount() ?? []);
@@ -39,11 +37,26 @@ export const mountSwitch = (value, keyOf, branch) => {
39
37
  return mounted;
40
38
  });
41
39
  mut_state.current = { key, scope };
42
- if (anchor.parentNode === null) {
43
- mut_state.initialNodes = nodes;
40
+ return nodes;
41
+ };
42
+
43
+ const switchTo = (v) => {
44
+ const key = keyOf(v);
45
+ if (mut_state.current !== undefined) {
46
+ if (Object.is(mut_state.current.key, key)) {
47
+ return;
48
+ }
49
+ mut_state.current.scope.dispose();
50
+ }
51
+ mountThenInsert((k) => mountBranch(k, v), key, insertBefore, anchor);
52
+ };
53
+ const switchWhenAttached = applyWhenAttached(anchor, switchTo);
54
+ bindValue(value, (v) => {
55
+ if (mut_state.current === undefined) {
56
+ mut_state.initialNodes = mountBranch(keyOf(v), v);
44
57
  }
45
58
  else {
46
- anchor.before(...nodes);
59
+ switchWhenAttached(v);
47
60
  }
48
61
  });
49
62
  return Arr.toPushed(mut_state.initialNodes, anchor);
@@ -1 +1 @@
1
- {"version":3,"file":"mount-switch.mjs","sourceRoot":"","sources":["../../src/control/mount-switch.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,eAAe,EACf,cAAc,GAEf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAqC,MAAM,kBAAkB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,KAAkB,EAClB,KAAwB,EACxB,MAAqD,EACvC,EAAE;IAChB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAGX,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAE7C,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;QACrB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1C,OAAO;YACT,CAAC;YAED,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QAED,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAEvD,cAAc,CAAC,GAAG,EAAE;gBAClB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;oBAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAEnC,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC/B,SAAS,CAAC,YAAY,GAAG,KAAK,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC,CAAC"}
1
+ {"version":3,"file":"mount-switch.mjs","sourceRoot":"","sources":["../../src/control/mount-switch.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,eAAe,EACf,cAAc,GAEf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAqC,MAAM,kBAAkB,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,KAAkB,EAClB,KAAwB,EACxB,MAAqD,EACvC,EAAE;IAChB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAGX,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAE7C,6EAA6E;IAC7E,MAAM,WAAW,GAAG,CAAC,GAAM,EAAE,CAAI,EAAwB,EAAE;QACzD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAEvD,cAAc,CAAC,GAAG,EAAE;gBAClB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;oBAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAEnC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,CAAC,CAAI,EAAQ,EAAE;QAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1C,OAAO;YACT,CAAC;YAED,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QAED,eAAe,CAAC,CAAC,CAAI,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC1E,CAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAE/D,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;QACrB,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS,CAAC,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"portal.d.mts","sourceRoot":"","sources":["../../src/control/portal.mts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAE/E;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,0BAGhB,QAAQ,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;CACjB,CAAC,KAAG,GAAG,CAAC,OAaL,CAAC"}
1
+ {"version":3,"file":"portal.d.mts","sourceRoot":"","sources":["../../src/control/portal.mts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAE/E;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,0BAGhB,QAAQ,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;CACjB,CAAC,KAAG,GAAG,CAAC,OAgBL,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { onScopeDispose } from 'synstate';
2
+ import { appendTo, mountThenInsert } from '../internal/index.mjs';
2
3
  import { mountChild, mountable } from '../jsx/index.mjs';
3
4
 
4
5
 
@@ -10,8 +11,7 @@ import { mountChild, mountable } from '../jsx/index.mjs';
10
11
 
11
12
 
12
13
  export const Portal = ({ target, children, }) => mountable(() => {
13
- const nodes = mountChild(children);
14
- (target ?? document.body).append(...nodes);
14
+ const nodes = mountThenInsert(mountChild, children, appendTo, target ?? document.body);
15
15
  onScopeDispose(() => {
16
16
  for (const node of nodes) {
17
17
  node.remove();
@@ -1 +1 @@
1
- {"version":3,"file":"portal.mjs","sourceRoot":"","sources":["../../src/control/portal.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAwB,MAAM,kBAAkB,CAAC;AAE/E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,MAAM,EACN,QAAQ,GAIR,EAAe,EAAE,CACjB,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEnC,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;IAE3C,cAAc,CAAC,GAAG,EAAE;QAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"portal.mjs","sourceRoot":"","sources":["../../src/control/portal.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAwB,MAAM,kBAAkB,CAAC;AAE/E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,MAAM,EACN,QAAQ,GAIR,EAAe,EAAE,CACjB,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,KAAK,GAAG,eAAe,CAC3B,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,MAAM,IAAI,QAAQ,CAAC,IAAI,CACxB,CAAC;IAEF,cAAc,CAAC,GAAG,EAAE;QAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Nodes are mounted before they are inserted: an element mounts all its
3
+ * children and then appends them, `render` mounts the app and then appends it,
4
+ * and `For` and `If` mount a row or a branch and then insert it. A child
5
+ * mounted later that writes to what an earlier `For` or `If` reads updates them
6
+ * while their anchor is in no parent yet (#2935).
7
+ *
8
+ * Every mount-and-insert goes through {@link mountThenInsert}. A `For` or a
9
+ * switch takes {@link applyWhenAttached} when it is mounted, which notes the
10
+ * mount open then; a value that arrives while its anchor is detached is kept,
11
+ * and the latest one is applied once that mount has inserted its nodes.
12
+ *
13
+ * `mount` takes `arg` rather than closing over it, so that the element and
14
+ * `render` paths allocate nothing; a mount that nothing defers to allocates no
15
+ * frame.
16
+ */
17
+ export declare const mountThenInsert: <A, N, T>(mount: (input: A) => N, arg: A, insert: (into: T, mounted: N) => void, target: T) => N;
18
+ /** Appends `nodes` to `parent`: an `insert` for {@link mountThenInsert}. */
19
+ export declare const appendTo: (parent: Element, nodes: readonly ChildNode[]) => void;
20
+ /** Inserts `nodes` in front of `next`: an `insert` for {@link mountThenInsert}. */
21
+ export declare const insertBefore: (next: ChildNode, nodes: readonly ChildNode[]) => void;
22
+ /**
23
+ * Returns the function a `For` or a switch calls with each value after its
24
+ * first. While `anchor` is attached the value is applied at once, and replaces
25
+ * any value still waiting. While it is detached the value is kept, and the
26
+ * latest one is applied once the mount open now has inserted its nodes, and
27
+ * only if `anchor` is then attached: it is not when the `For` or switch was
28
+ * disposed in between.
29
+ *
30
+ * Mounted outside every {@link mountThenInsert} (a description mounted by hand),
31
+ * there is nothing to wait for: a value that arrives while `anchor` is detached
32
+ * is dropped.
33
+ */
34
+ export declare const applyWhenAttached: <V>(anchor: Node, apply: (value: V) => void) => ((value: V) => void);
35
+ //# sourceMappingURL=after-attach.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"after-attach.d.mts","sourceRoot":"","sources":["../../src/internal/after-attach.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAC9B,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,OACjB,CAAC,UACE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,IAAI,UAC7B,CAAC,KACR,CAuBF,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,WACX,OAAO,SACR,SAAS,SAAS,EAAE,KAC1B,IAEF,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,YAAY,SACjB,SAAS,SACR,SAAS,SAAS,EAAE,KAC1B,IAEF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,UACzB,IAAI,SACL,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KACxB,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAmDrB,CAAC"}
@@ -0,0 +1,122 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+ export const mountThenInsert = (mount, arg, insert, target) => {
18
+ mut_state.depth += 1;
19
+ mut_state.lastId += 1;
20
+ const { depth } = mut_state;
21
+ mut_state.ids[depth] = mut_state.lastId;
22
+
23
+ takeFrame(depth);
24
+ const nodes = runMount(mount, arg, depth);
25
+ const frame = takeFrame(depth);
26
+ insert(target, nodes);
27
+ if (frame !== undefined) {
28
+ runAll(frame);
29
+ }
30
+ return nodes;
31
+ };
32
+
33
+ export const appendTo = (parent, nodes) => {
34
+ parent.append(...nodes);
35
+ };
36
+
37
+ export const insertBefore = (next, nodes) => {
38
+ next.before(...nodes);
39
+ };
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+ export const applyWhenAttached = (anchor, apply) => {
53
+ const { depth } = mut_state;
54
+ const id = mut_state.ids[depth];
55
+ const mut_pending = {
56
+ latest: undefined,
57
+ };
58
+ const flush = () => {
59
+ const { latest } = mut_pending;
60
+ mut_pending.latest = undefined;
61
+ if (latest !== undefined && anchor.parentNode !== null) {
62
+ apply(latest.value);
63
+ }
64
+ };
65
+ return (value) => {
66
+ if (anchor.parentNode !== null) {
67
+ mut_pending.latest = undefined;
68
+ apply(value);
69
+ return;
70
+ }
71
+ const scheduled = mut_pending.latest !== undefined;
72
+ mut_pending.latest = { value };
73
+ if (scheduled) {
74
+ return;
75
+ }
76
+ if (depth === 0 || mut_state.depth < depth || mut_state.ids[depth] !== id) {
77
+
78
+ flush();
79
+ return;
80
+ }
81
+ const mut_frame = mut_state.frames[depth];
82
+ if (mut_frame === undefined) {
83
+ mut_state.frames[depth] = [flush];
84
+ }
85
+ else {
86
+ mut_frame.push(flush);
87
+ }
88
+ };
89
+ };
90
+ const mut_state = { depth: 0, lastId: 0, ids: [0], frames: [] };
91
+
92
+ const takeFrame = (depth) => {
93
+ const frame = mut_state.frames[depth];
94
+ mut_state.frames[depth] = undefined;
95
+ return frame;
96
+ };
97
+
98
+
99
+
100
+
101
+
102
+ const runAll = (frame) => {
103
+ for (const [index, apply] of frame.entries()) {
104
+ try {
105
+ apply();
106
+ }
107
+ catch (error) {
108
+ runAll(frame.slice(index + 1));
109
+ throw error;
110
+ }
111
+ }
112
+ };
113
+
114
+ const runMount = (mount, arg, depth) => {
115
+ try {
116
+ return mount(arg);
117
+ }
118
+ finally {
119
+ mut_state.depth = depth - 1;
120
+ }
121
+ };
122
+ //# sourceMappingURL=after-attach.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"after-attach.mjs","sourceRoot":"","sources":["../../src/internal/after-attach.mts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ export * from './after-attach.mjs';
1
2
  export * from './as-constant.mjs';
2
3
  export * from './bind-value.mjs';
3
4
  export * from './dom-tables.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/internal/index.mts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/internal/index.mts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
@@ -1,3 +1,4 @@
1
+ export * from './after-attach.mjs';
1
2
  export * from './as-constant.mjs';
2
3
  export * from './bind-value.mjs';
3
4
  export * from './dom-tables.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/internal/index.mts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/internal/index.mts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
package/dist/jsx/jsx.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { hasKey, isRecord } from 'ts-data-forge';
2
2
  import { bindProps } from '../bind/index.mjs';
3
- import { svgTagNames } from '../internal/index.mjs';
3
+ import { appendTo, mountThenInsert, svgTagNames } from '../internal/index.mjs';
4
4
  import { isChild, mountChild } from './child.mjs';
5
5
  import { mountable } from './mountable.mjs';
6
6
 
@@ -36,7 +36,7 @@ const mountElement = (tag, props) => {
36
36
  }
37
37
 
38
38
  if (hasKey(props, 'children') && isChild(props.children)) {
39
- element.append(...mountChild(props.children));
39
+ mountThenInsert(mountChild, props.children, appendTo, element);
40
40
  }
41
41
  bindProps(element, props);
42
42
  return element;
@@ -1 +1 @@
1
- {"version":3,"file":"jsx.mjs","sourceRoot":"","sources":["../../src/jsx/jsx.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAkB,MAAM,iBAAiB,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAiD,EACjD,KAAQ,EACR,GAAa,EACF,EAAE;IACb,6EAA6E;IAC7E,sEAAsE;IACtE,MAAM,YAAY,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,GAAG,KAAK,EAAE,GAAG,EAAY,CAAC;IAE9E,OAAO,OAAO,IAAI,KAAK,QAAQ;QAC7B,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAqC,EAAa,EAAE,CAC3E,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,aAAa,GAAG,CAAC,KAAc,EAAuC,EAAE,CAC5E,OAAO,KAAK,KAAK,UAAU,CAAC;AAE9B,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,KAAc,EAAW,EAAE;IAC5D,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,YAAY,EAAE,GAAG,CAAC;QAC7C,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAEhC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED,wEAAwE;IACxE,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAE1B,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAElD,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC"}
1
+ {"version":3,"file":"jsx.mjs","sourceRoot":"","sources":["../../src/jsx/jsx.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAkB,MAAM,iBAAiB,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAiD,EACjD,KAAQ,EACR,GAAa,EACF,EAAE;IACb,6EAA6E;IAC7E,sEAAsE;IACtE,MAAM,YAAY,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,GAAG,KAAK,EAAE,GAAG,EAAY,CAAC;IAE9E,OAAO,OAAO,IAAI,KAAK,QAAQ;QAC7B,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAqC,EAAa,EAAE,CAC3E,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,aAAa,GAAG,CAAC,KAAc,EAAuC,EAAE,CAC5E,OAAO,KAAK,KAAK,UAAU,CAAC;AAE9B,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,KAAc,EAAW,EAAE;IAC5D,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,YAAY,EAAE,GAAG,CAAC;QAC7C,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAEhC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED,wEAAwE;IACxE,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAED,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAE1B,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAElD,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC"}
package/dist/render.d.mts CHANGED
@@ -5,7 +5,8 @@ import { type JSX } from './jsx/index.mjs';
5
5
  *
6
6
  * `app` is called once, inside a new root scope; everything created while it
7
7
  * and the description it returns are mounted belongs to that scope, and
8
- * unmounting disposes it and removes the nodes.
8
+ * unmounting disposes it and removes the nodes. If mounting throws, what was
9
+ * mounted is disposed and removed before the error is rethrown.
9
10
  *
10
11
  * `render(App, el)` rather than `render(<App />, el)`: taking the component
11
12
  * makes it plain that it is evaluated here.
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.mts","sourceRoot":"","sources":["../src/render.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,QACZ,MAAM,GAAG,CAAC,OAAO,aACX,OAAO,KACjB,CAAC,MAAM,IAAI,CAcb,CAAC"}
1
+ {"version":3,"file":"render.d.mts","sourceRoot":"","sources":["../src/render.mts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,QACZ,MAAM,GAAG,CAAC,OAAO,aACX,OAAO,KACjB,CAAC,MAAM,IAAI,CAmCb,CAAC"}
package/dist/render.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createScope } from 'synstate';
2
+ import { appendTo, mountThenInsert } from './internal/index.mjs';
2
3
  import { toNodes } from './jsx/index.mjs';
3
4
 
4
5
 
@@ -11,15 +12,29 @@ import { toNodes } from './jsx/index.mjs';
11
12
 
12
13
 
13
14
 
15
+
14
16
  export const render = (app, container) => {
15
17
  const root = createScope(undefined);
16
- const nodes = root.run(() => toNodes(app().mount()));
17
- container.append(...nodes);
18
- return () => {
18
+ const mut_inserted = { nodes: [] };
19
+ const unmount = () => {
19
20
  root.dispose();
20
- for (const node of nodes) {
21
+ for (const node of mut_inserted.nodes) {
21
22
  node.remove();
22
23
  }
23
24
  };
25
+ try {
26
+ root.run(() => mountThenInsert(mountApp, app, (into, nodes) => {
27
+ mut_inserted.nodes = nodes;
28
+ appendTo(into, nodes);
29
+ }, container));
30
+ }
31
+ catch (error) {
32
+
33
+
34
+ unmount();
35
+ throw error;
36
+ }
37
+ return unmount;
24
38
  };
39
+ const mountApp = (app) => toNodes(app().mount());
25
40
  //# sourceMappingURL=render.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.mjs","sourceRoot":"","sources":["../src/render.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAY,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,GAAsB,EACtB,SAAkB,EACJ,EAAE;IAChB,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAErD,SAAS,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;IAE3B,OAAO,GAAG,EAAE;QACV,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"render.mjs","sourceRoot":"","sources":["../src/render.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAY,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,GAAsB,EACtB,SAAkB,EACJ,EAAE;IAChB,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAEpC,MAAM,YAAY,GAAoC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAEpE,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CACZ,eAAe,CACb,QAAQ,EACR,GAAG,EACH,CAAC,IAAa,EAAE,KAA2B,EAAE,EAAE;YAC7C,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;YAE3B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC,EACD,SAAS,CACV,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,0EAA0E;QAC1E,OAAO,EAAE,CAAC;QAEV,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,GAAsB,EAAwB,EAAE,CAChE,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synstate-dom",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Compiler-free fine-grained UI library that binds synstate observables directly to the DOM",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,21 +44,21 @@
44
44
  },
45
45
  "devDependencies": {
46
46
  "@vitest/browser-playwright": "5.0.5",
47
- "eslint-config-typed": "7.3.1",
48
- "eslint-plugin-ts-data-forge": "0.10.8",
49
- "eslint-plugin-ts-fortress": "1.3.12",
50
- "eslint-plugin-ts-type-forge": "0.8.17",
47
+ "eslint-config-typed": "7.4.0",
48
+ "eslint-plugin-ts-data-forge": "0.10.9",
49
+ "eslint-plugin-ts-fortress": "1.3.13",
50
+ "eslint-plugin-ts-type-forge": "0.8.18",
51
51
  "playwright": "1.64.1",
52
52
  "prettier": "3.9.10",
53
53
  "prettier-plugin-organize-imports": "4.3.0",
54
54
  "prettier-plugin-packagejson": "3.0.2",
55
- "synstate": "6.2.1",
56
- "ts-data-forge": "14.10.2",
57
- "ts-repo-utils": "10.7.1"
55
+ "synstate": "7.0.0",
56
+ "ts-data-forge": "14.11.0",
57
+ "ts-repo-utils": "10.7.2"
58
58
  },
59
59
  "peerDependencies": {
60
- "synstate": ">=6.2.1",
61
- "ts-data-forge": ">=14.10.2"
60
+ "synstate": ">=7.0.0",
61
+ "ts-data-forge": ">=14.11.0"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=22.23.4",
@@ -11,7 +11,12 @@ import {
11
11
  import { Arr, Optional } from 'ts-data-forge';
12
12
  import type { BivariantHack } from 'ts-type-forge';
13
13
  import { toObservable, type Bindable } from '../constant/index.mjs';
14
- import { bindValue } from '../internal/index.mjs';
14
+ import {
15
+ applyWhenAttached,
16
+ bindValue,
17
+ insertBefore,
18
+ mountThenInsert,
19
+ } from '../internal/index.mjs';
15
20
  import { mountable, toNodes, type JSX } from '../jsx/index.mjs';
16
21
  import { longestIncreasingSubsequence } from './longest-increasing-subsequence.mjs';
17
22
 
@@ -31,6 +36,10 @@ import { longestIncreasingSubsequence } from './longest-increasing-subsequence.m
31
36
  * nodes; the rows that stay are moved as little as the longest increasing
32
37
  * subsequence allows.
33
38
  *
39
+ * An update that arrives before the anchor is in a parent (a later sibling
40
+ * wrote `items` while the enclosing element was still mounting its children) is
41
+ * applied, with the latest `items`, once the nodes `For` returned are inserted.
42
+ *
34
43
  * `key` is required, as in React; `(_, i) => i` matches rows by position. A key
35
44
  * that appears twice is reported with `console.error`, and its later
36
45
  * occurrences are rebuilt on every update.
@@ -72,7 +81,10 @@ export const For = <T,>({
72
81
 
73
82
  const rowStarts = new WeakSet<Node>();
74
83
 
75
- const mut_initial: { nodes: readonly ChildNode[] } = { nodes: [] };
84
+ const mut_initial: { nodes: readonly ChildNode[]; built: boolean } = {
85
+ nodes: [],
86
+ built: false,
87
+ };
76
88
 
77
89
  /** Creates a row in a scope of its own and returns its first nodes. */
78
90
  const createRow = (
@@ -161,12 +173,11 @@ export const For = <T,>({
161
173
  range.deleteContents();
162
174
  };
163
175
 
164
- bindValue(entries$, (entries) => {
176
+ /** Brings the attached rows in line with `entries`. */
177
+ const update = (entries: Entries<T>): void => {
165
178
  const previousOrder = Array.from(mut_rows.keys());
166
179
 
167
- if (anchor.parentNode !== null) {
168
- removeAllAtOnceIfEveryKeyGoes(previousOrder, entries);
169
- }
180
+ removeAllAtOnceIfEveryKeyGoes(previousOrder, entries);
170
181
 
171
182
  for (const [rowKey, row] of mut_rows) {
172
183
  if (entries.byKey.has(rowKey)) {
@@ -178,16 +189,6 @@ export const For = <T,>({
178
189
  mut_rows.delete(rowKey);
179
190
  }
180
191
 
181
- if (anchor.parentNode === null) {
182
- mut_initial.nodes = entries.order.flatMap((rowKey) => {
183
- const entry = entries.byKey.get(rowKey);
184
-
185
- return entry === undefined ? [] : createRow(rowKey, entry);
186
- });
187
-
188
- return;
189
- }
190
-
191
192
  if (Arr.eq(previousOrder, entries.order)) {
192
193
  return;
193
194
  }
@@ -224,11 +225,14 @@ export const For = <T,>({
224
225
  continue;
225
226
  }
226
227
 
227
- const [start, ...rest] = createRow(rowKey, entry);
228
+ const [start] = mountThenInsert(
229
+ (e: Entry<T>) => createRow(rowKey, e),
230
+ entry,
231
+ insertBefore,
232
+ mut_next,
233
+ );
228
234
 
229
235
  if (start !== undefined) {
230
- mut_next.before(start, ...rest);
231
-
232
236
  mut_next = start;
233
237
  }
234
238
 
@@ -243,6 +247,24 @@ export const For = <T,>({
243
247
  }
244
248
 
245
249
  reorderMap(mut_rows, entries.order);
250
+ };
251
+
252
+ const updateWhenAttached = applyWhenAttached(anchor, update);
253
+
254
+ bindValue(entries$, (entries) => {
255
+ if (!mut_initial.built) {
256
+ mut_initial.built = true;
257
+
258
+ mut_initial.nodes = entries.order.flatMap((rowKey) => {
259
+ const entry = entries.byKey.get(rowKey);
260
+
261
+ return entry === undefined ? [] : createRow(rowKey, entry);
262
+ });
263
+
264
+ return;
265
+ }
266
+
267
+ updateWhenAttached(entries);
246
268
  });
247
269
 
248
270
  return Arr.toPushed(mut_initial.nodes, anchor);
@@ -6,7 +6,12 @@ import {
6
6
  } from 'synstate';
7
7
  import { Arr } from 'ts-data-forge';
8
8
  import type { Bindable } from '../constant/index.mjs';
9
- import { bindValue } from '../internal/index.mjs';
9
+ import {
10
+ applyWhenAttached,
11
+ bindValue,
12
+ insertBefore,
13
+ mountThenInsert,
14
+ } from '../internal/index.mjs';
10
15
  import { toNodes, type Mountable, type MountedNodes } from '../jsx/index.mjs';
11
16
 
12
17
  /**
@@ -22,6 +27,10 @@ import { toNodes, type Mountable, type MountedNodes } from '../jsx/index.mjs';
22
27
  *
23
28
  * `branch` runs inside the new scope, so whatever it creates belongs to the
24
29
  * branch.
30
+ *
31
+ * A value that arrives before the anchor is in a parent (a later sibling wrote
32
+ * it while the enclosing element was still mounting its children) is kept, and
33
+ * the switch follows the latest one once the nodes it returned are inserted.
25
34
  */
26
35
  export const mountSwitch = <V, K>(
27
36
  value: Bindable<V>,
@@ -37,17 +46,8 @@ export const mountSwitch = <V, K>(
37
46
  initialNodes: readonly ChildNode[];
38
47
  } = { current: undefined, initialNodes: [] };
39
48
 
40
- bindValue(value, (v) => {
41
- const key = keyOf(v);
42
-
43
- if (mut_state.current !== undefined) {
44
- if (Object.is(mut_state.current.key, key)) {
45
- return;
46
- }
47
-
48
- mut_state.current.scope.dispose();
49
- }
50
-
49
+ /** Mounts the branch for `v` in a scope of its own and returns its nodes. */
50
+ const mountBranch = (key: K, v: V): readonly ChildNode[] => {
51
51
  const scope = createScope(parent);
52
52
 
53
53
  const nodes = scope.run(() => {
@@ -64,10 +64,31 @@ export const mountSwitch = <V, K>(
64
64
 
65
65
  mut_state.current = { key, scope };
66
66
 
67
- if (anchor.parentNode === null) {
68
- mut_state.initialNodes = nodes;
67
+ return nodes;
68
+ };
69
+
70
+ /** Switches the attached switch to the branch for `v`. */
71
+ const switchTo = (v: V): void => {
72
+ const key = keyOf(v);
73
+
74
+ if (mut_state.current !== undefined) {
75
+ if (Object.is(mut_state.current.key, key)) {
76
+ return;
77
+ }
78
+
79
+ mut_state.current.scope.dispose();
80
+ }
81
+
82
+ mountThenInsert((k: K) => mountBranch(k, v), key, insertBefore, anchor);
83
+ };
84
+
85
+ const switchWhenAttached = applyWhenAttached(anchor, switchTo);
86
+
87
+ bindValue(value, (v) => {
88
+ if (mut_state.current === undefined) {
89
+ mut_state.initialNodes = mountBranch(keyOf(v), v);
69
90
  } else {
70
- anchor.before(...nodes);
91
+ switchWhenAttached(v);
71
92
  }
72
93
  });
73
94
 
@@ -1,4 +1,5 @@
1
1
  import { onScopeDispose } from 'synstate';
2
+ import { appendTo, mountThenInsert } from '../internal/index.mjs';
2
3
  import { mountChild, mountable, type Child, type JSX } from '../jsx/index.mjs';
3
4
 
4
5
  /**
@@ -18,9 +19,12 @@ export const Portal = ({
18
19
  children: Child;
19
20
  }>): JSX.Element =>
20
21
  mountable(() => {
21
- const nodes = mountChild(children);
22
-
23
- (target ?? document.body).append(...nodes);
22
+ const nodes = mountThenInsert(
23
+ mountChild,
24
+ children,
25
+ appendTo,
26
+ target ?? document.body,
27
+ );
24
28
 
25
29
  onScopeDispose(() => {
26
30
  for (const node of nodes) {
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Nodes are mounted before they are inserted: an element mounts all its
3
+ * children and then appends them, `render` mounts the app and then appends it,
4
+ * and `For` and `If` mount a row or a branch and then insert it. A child
5
+ * mounted later that writes to what an earlier `For` or `If` reads updates them
6
+ * while their anchor is in no parent yet (#2935).
7
+ *
8
+ * Every mount-and-insert goes through {@link mountThenInsert}. A `For` or a
9
+ * switch takes {@link applyWhenAttached} when it is mounted, which notes the
10
+ * mount open then; a value that arrives while its anchor is detached is kept,
11
+ * and the latest one is applied once that mount has inserted its nodes.
12
+ *
13
+ * `mount` takes `arg` rather than closing over it, so that the element and
14
+ * `render` paths allocate nothing; a mount that nothing defers to allocates no
15
+ * frame.
16
+ */
17
+ export const mountThenInsert = <A, N, T>(
18
+ mount: (input: A) => N,
19
+ arg: A,
20
+ insert: (into: T, mounted: N) => void,
21
+ target: T,
22
+ ): N => {
23
+ mut_state.depth += 1;
24
+
25
+ mut_state.lastId += 1;
26
+
27
+ const { depth } = mut_state;
28
+
29
+ mut_state.ids[depth] = mut_state.lastId;
30
+
31
+ // Left behind by a mount at this depth that threw.
32
+ takeFrame(depth);
33
+
34
+ const nodes = runMount(mount, arg, depth);
35
+
36
+ const frame = takeFrame(depth);
37
+
38
+ insert(target, nodes);
39
+
40
+ if (frame !== undefined) {
41
+ runAll(frame);
42
+ }
43
+
44
+ return nodes;
45
+ };
46
+
47
+ /** Appends `nodes` to `parent`: an `insert` for {@link mountThenInsert}. */
48
+ export const appendTo = (
49
+ parent: Element,
50
+ nodes: readonly ChildNode[],
51
+ ): void => {
52
+ parent.append(...nodes);
53
+ };
54
+
55
+ /** Inserts `nodes` in front of `next`: an `insert` for {@link mountThenInsert}. */
56
+ export const insertBefore = (
57
+ next: ChildNode,
58
+ nodes: readonly ChildNode[],
59
+ ): void => {
60
+ next.before(...nodes);
61
+ };
62
+
63
+ /**
64
+ * Returns the function a `For` or a switch calls with each value after its
65
+ * first. While `anchor` is attached the value is applied at once, and replaces
66
+ * any value still waiting. While it is detached the value is kept, and the
67
+ * latest one is applied once the mount open now has inserted its nodes, and
68
+ * only if `anchor` is then attached: it is not when the `For` or switch was
69
+ * disposed in between.
70
+ *
71
+ * Mounted outside every {@link mountThenInsert} (a description mounted by hand),
72
+ * there is nothing to wait for: a value that arrives while `anchor` is detached
73
+ * is dropped.
74
+ */
75
+ export const applyWhenAttached = <V,>(
76
+ anchor: Node,
77
+ apply: (value: V) => void,
78
+ ): ((value: V) => void) => {
79
+ const { depth } = mut_state;
80
+
81
+ const id = mut_state.ids[depth];
82
+
83
+ const mut_pending: { latest: Readonly<{ value: V }> | undefined } = {
84
+ latest: undefined,
85
+ };
86
+
87
+ const flush = (): void => {
88
+ const { latest } = mut_pending;
89
+
90
+ mut_pending.latest = undefined;
91
+
92
+ if (latest !== undefined && anchor.parentNode !== null) {
93
+ apply(latest.value);
94
+ }
95
+ };
96
+
97
+ return (value) => {
98
+ if (anchor.parentNode !== null) {
99
+ mut_pending.latest = undefined;
100
+
101
+ apply(value);
102
+
103
+ return;
104
+ }
105
+
106
+ const scheduled = mut_pending.latest !== undefined;
107
+
108
+ mut_pending.latest = { value };
109
+
110
+ if (scheduled) {
111
+ return;
112
+ }
113
+
114
+ if (depth === 0 || mut_state.depth < depth || mut_state.ids[depth] !== id) {
115
+ // That mount has ended: its nodes are inserted.
116
+ flush();
117
+
118
+ return;
119
+ }
120
+
121
+ const mut_frame = mut_state.frames[depth];
122
+
123
+ if (mut_frame === undefined) {
124
+ mut_state.frames[depth] = [flush];
125
+ } else {
126
+ mut_frame.push(flush);
127
+ }
128
+ };
129
+ };
130
+
131
+ const mut_state: {
132
+ depth: number;
133
+ lastId: number;
134
+ /** The id of the mount open at each depth. */
135
+ ids: number[];
136
+ /** What was deferred to the mount open at each depth, in order. */
137
+ frames: ((() => void)[] | undefined)[];
138
+ } = { depth: 0, lastId: 0, ids: [0], frames: [] };
139
+
140
+ /** Takes what was deferred to the mount at `depth` out of the state. */
141
+ const takeFrame = (depth: number): readonly (() => void)[] | undefined => {
142
+ const frame = mut_state.frames[depth];
143
+
144
+ mut_state.frames[depth] = undefined;
145
+
146
+ return frame;
147
+ };
148
+
149
+ /**
150
+ * Runs what was deferred to a mount. One that throws does not keep the rest
151
+ * from running, or they would keep their value waiting for good; the first
152
+ * error is rethrown once they have run.
153
+ */
154
+ const runAll = (frame: readonly (() => void)[]): void => {
155
+ for (const [index, apply] of frame.entries()) {
156
+ try {
157
+ apply();
158
+ } catch (error) {
159
+ runAll(frame.slice(index + 1));
160
+
161
+ throw error;
162
+ }
163
+ }
164
+ };
165
+
166
+ /** A mount that throws must not leave the depth raised. */
167
+ const runMount = <A, N>(mount: (input: A) => N, arg: A, depth: number): N => {
168
+ try {
169
+ return mount(arg);
170
+ } finally {
171
+ mut_state.depth = depth - 1;
172
+ }
173
+ };
@@ -1,3 +1,4 @@
1
+ export * from './after-attach.mjs';
1
2
  export * from './as-constant.mjs';
2
3
  export * from './bind-value.mjs';
3
4
  export * from './dom-tables.mjs';
package/src/jsx/jsx.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { hasKey, isRecord } from 'ts-data-forge';
2
2
  import { bindProps } from '../bind/index.mjs';
3
- import { svgTagNames } from '../internal/index.mjs';
3
+ import { appendTo, mountThenInsert, svgTagNames } from '../internal/index.mjs';
4
4
  import { isChild, mountChild, type Child } from './child.mjs';
5
5
  import { mountable, type Mountable } from './mountable.mjs';
6
6
 
@@ -50,7 +50,7 @@ const mountElement = (tag: string, props: unknown): Element => {
50
50
 
51
51
  // Children first, so that a `<select>`'s `value` finds its `<option>`s.
52
52
  if (hasKey(props, 'children') && isChild(props.children)) {
53
- element.append(...mountChild(props.children));
53
+ mountThenInsert(mountChild, props.children, appendTo, element);
54
54
  }
55
55
 
56
56
  bindProps(element, props);
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 = root.run(() => toNodes(app().mount()));
23
+ const mut_inserted: { nodes: readonly ChildNode[] } = { nodes: [] };
22
24
 
23
- container.append(...nodes);
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());