@barefootjs/client 0.28.1 → 0.30.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/dist/runtime/component.d.ts +28 -1
- package/dist/runtime/component.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +24 -6
- package/dist/runtime/map-array.d.ts.map +1 -1
- package/dist/runtime/qsa-item.d.ts +15 -11
- package/dist/runtime/qsa-item.d.ts.map +1 -1
- package/dist/runtime/standalone.js +24 -6
- package/package.json +2 -2
- package/src/runtime/component.ts +78 -9
- package/src/runtime/index.ts +1 -0
- package/src/runtime/map-array.ts +15 -6
- package/src/runtime/qsa-item.ts +22 -12
|
@@ -6,12 +6,39 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { ComponentDef } from './types.ts';
|
|
8
8
|
export declare function setParentScopeId(id: string | null): void;
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Where `mapArray` wants a fresh loop row connected before its `init` runs.
|
|
11
|
+
*
|
|
12
|
+
* `mounted` is written back by `mountRowRoot` so the caller can undo the
|
|
13
|
+
* connection if the rest of the row's body then throws — see `createItemScope`.
|
|
14
|
+
* Without it a half-built row stays visible, which detached rows never did.
|
|
15
|
+
*/
|
|
10
16
|
export type RowMountPoint = {
|
|
11
17
|
container: Node;
|
|
12
18
|
anchor: Node | null;
|
|
19
|
+
mounted?: Element | null;
|
|
13
20
|
};
|
|
14
21
|
export declare function setRowMountPoint(p: RowMountPoint | null): RowMountPoint | null;
|
|
22
|
+
/**
|
|
23
|
+
* Connect a loop row whose root is a template clone, before the emitted
|
|
24
|
+
* renderItem body's tail runs.
|
|
25
|
+
*
|
|
26
|
+
* The tail is where the row's nested children initialise (`upsertChild` and
|
|
27
|
+
* friends), and `useContext` resolves by walking `parentElement` — so a child
|
|
28
|
+
* that inits inside a detached row finds no ancestors and falls through to the
|
|
29
|
+
* global last-writer-wins context store, reading whichever provider on the page
|
|
30
|
+
* wrote last. `createComponent` row roots already avoid this by consuming the
|
|
31
|
+
* same ambient (step 7b); a clone root has no runtime function in the middle,
|
|
32
|
+
* so the compiler emits this call for it instead.
|
|
33
|
+
*
|
|
34
|
+
* Take-and-clear, like the `createComponent` path: a nested `createComponent`
|
|
35
|
+
* driven by this row's own children must not re-use the row's mount point.
|
|
36
|
+
*
|
|
37
|
+
* No-op when there is no ambient point — the hydration branch never calls this
|
|
38
|
+
* (its row came from SSR markup and is already in the document), and a loop
|
|
39
|
+
* runtime that does not hand one down leaves the row exactly as it was.
|
|
40
|
+
*/
|
|
41
|
+
export declare function mountRowRoot(el: Element): Element;
|
|
15
42
|
/**
|
|
16
43
|
* Create a component instance with DOM element and initialized state.
|
|
17
44
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExD;AAED
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CAAA;AAsB9F,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,aAAa,GAAG,IAAI,CAI9E;AAQD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAQjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH;;;GAGG;AACH;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,CAAC,EAAE,uBAAuB,EAC9B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GACvB,WAAW,CAcb;AAyOD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAqER;AA+DD;;;;;GAKG;AACH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOjD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG9D;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,gBAAgB,CAcjF"}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { mapArrayLazy, type LazyRowEntry, type LazyRowPlan } from './map-array-l
|
|
|
15
15
|
export { patchLeaf } from './patch-leaf.ts';
|
|
16
16
|
export { claimSlots, lazySlots, lazyClaimSlots, textOrNode, type SlotSpec, type ClaimPlan, type ClaimedSlots, type ClaimedSlotsRW, type SlotWriter } from './claim-slots.ts';
|
|
17
17
|
export { registerTemplate, getTemplate, hasTemplate, type TemplateFn } from './template.ts';
|
|
18
|
-
export { createComponent, renderChild, parseHTML, escapeAttr, escapeText, escapeTextOrNode, } from './component.ts';
|
|
18
|
+
export { createComponent, mountRowRoot, renderChild, parseHTML, escapeAttr, escapeText, escapeTextOrNode, } from './component.ts';
|
|
19
19
|
export { applyRestAttrs } from './apply-rest-attrs.ts';
|
|
20
20
|
export { spreadAttrs } from './spread-attrs.ts';
|
|
21
21
|
export { styleToCss } from './style.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -1361,6 +1361,14 @@ function takeRowMountPoint() {
|
|
|
1361
1361
|
_rowMountPoint = null;
|
|
1362
1362
|
return p;
|
|
1363
1363
|
}
|
|
1364
|
+
function mountRowRoot(el) {
|
|
1365
|
+
const p = takeRowMountPoint();
|
|
1366
|
+
if (p) {
|
|
1367
|
+
p.container.insertBefore(el, p.anchor);
|
|
1368
|
+
p.mounted = el;
|
|
1369
|
+
}
|
|
1370
|
+
return el;
|
|
1371
|
+
}
|
|
1364
1372
|
function createComponent(nameOrDef, props = {}, key, slot, mountAt) {
|
|
1365
1373
|
const element = materializeComponent(nameOrDef, props, key, slot, mountAt);
|
|
1366
1374
|
if (mountAt && mountAt.parentNode && element !== mountAt) {
|
|
@@ -1404,12 +1412,13 @@ function materializeComponent(nameOrDef, props = {}, key, slot, mountAt) {
|
|
|
1404
1412
|
});
|
|
1405
1413
|
const def = getRegisteredDef(name);
|
|
1406
1414
|
const isCommentWrapper = def?.comment === true;
|
|
1407
|
-
const
|
|
1415
|
+
const derivedScopeId = slot?.parent && slot.mount ? `${slot.parent}_${slot.mount}` : null;
|
|
1416
|
+
const scopeId = isCommentWrapper ? null : derivedScopeId ?? `${name}_${generateId()}`;
|
|
1408
1417
|
const prevParentScopeId = _parentScopeId;
|
|
1409
|
-
if (
|
|
1410
|
-
_parentScopeId = slot.parent;
|
|
1411
|
-
} else if (scopeId) {
|
|
1418
|
+
if (scopeId) {
|
|
1412
1419
|
_parentScopeId = scopeId;
|
|
1420
|
+
} else if (slot?.parent) {
|
|
1421
|
+
_parentScopeId = slot.parent;
|
|
1413
1422
|
}
|
|
1414
1423
|
let html;
|
|
1415
1424
|
try {
|
|
@@ -1477,7 +1486,8 @@ function renderChild(name, props, key, slotSuffix) {
|
|
|
1477
1486
|
if (!templateFn) {
|
|
1478
1487
|
return `<div ${bfsAttr}${slotAttrs}${keyAttr}></div>`;
|
|
1479
1488
|
}
|
|
1480
|
-
|
|
1489
|
+
const raw = templateFn(props);
|
|
1490
|
+
let html = raw.trim().replace(PLACEHOLDER_ATTR_PATTERN, _parentScopeId ? ` bf-s="${_parentScopeId}"` : "");
|
|
1481
1491
|
const firstElMatch = html.match(/<(\w+)/);
|
|
1482
1492
|
if (!firstElMatch)
|
|
1483
1493
|
return html;
|
|
@@ -1738,7 +1748,7 @@ function* itemRootElements(primaryEl) {
|
|
|
1738
1748
|
if (n.nodeType === Node.COMMENT_NODE) {
|
|
1739
1749
|
const v = n.nodeValue ?? "";
|
|
1740
1750
|
if (v === BF_LOOP_ITEM || v === BF_LOOP_START || v.startsWith(startPrefix) || v === BF_LOOP_END || v.startsWith(endPrefix)) {
|
|
1741
|
-
|
|
1751
|
+
break;
|
|
1742
1752
|
}
|
|
1743
1753
|
} else if (n.nodeType === Node.ELEMENT_NODE) {
|
|
1744
1754
|
yield n;
|
|
@@ -1911,9 +1921,16 @@ function createItemScope(item, index, renderItem, existingPrimary, existingExtra
|
|
|
1911
1921
|
const prevRowMount = ownsRowMount ? setRowMountPoint(rowMount) : null;
|
|
1912
1922
|
try {
|
|
1913
1923
|
primaryEl = renderItem(itemAccessor, index, existingPrimary);
|
|
1924
|
+
} catch (err) {
|
|
1925
|
+
const parked = rowMount?.mounted;
|
|
1926
|
+
if (parked?.parentNode)
|
|
1927
|
+
parked.remove();
|
|
1928
|
+
throw err;
|
|
1914
1929
|
} finally {
|
|
1915
1930
|
if (ownsRowMount)
|
|
1916
1931
|
setRowMountPoint(prevRowMount);
|
|
1932
|
+
if (rowMount)
|
|
1933
|
+
rowMount.mounted = null;
|
|
1917
1934
|
}
|
|
1918
1935
|
if (existingPrimary) {
|
|
1919
1936
|
extras = existingExtras ?? [];
|
|
@@ -3248,6 +3265,7 @@ export {
|
|
|
3248
3265
|
parseHTML,
|
|
3249
3266
|
onMount,
|
|
3250
3267
|
onCleanup,
|
|
3268
|
+
mountRowRoot,
|
|
3251
3269
|
mapArrayLazy,
|
|
3252
3270
|
mapArrayAnchored,
|
|
3253
3271
|
mapArray,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map-array.d.ts","sourceRoot":"","sources":["../../src/runtime/map-array.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAqCH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,WAAW,EACtB,QAAQ,CAAC,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CA+BhD;AA8DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA2B3E;
|
|
1
|
+
{"version":3,"file":"map-array.d.ts","sourceRoot":"","sources":["../../src/runtime/map-array.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAqCH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,WAAW,EACtB,QAAQ,CAAC,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CA+BhD;AA8DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA2B3E;AA2FD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,EAAE,EACnB,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,WAAW,EACjF,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CA6RN;AAqHD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,QAAQ,EAAE,MAAM,CAAC,EAAE,EACnB,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,gBAAgB,GAAG,OAAO,EAC5F,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CA+FN"}
|
|
@@ -20,18 +20,22 @@
|
|
|
20
20
|
* cannot escape into a neighbouring item or into nodes outside the
|
|
21
21
|
* loop.
|
|
22
22
|
* 3. The CSR-only `__bfExtras` stash. During renderItem-body setup
|
|
23
|
-
* (between the template clone and the function's return), the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* lookups reach the still-pending extras before `mapArray` inserts
|
|
27
|
-
* them into the DOM.
|
|
23
|
+
* (between the template clone and the function's return), the extras
|
|
24
|
+
* are not siblings yet. Reading `__bfExtras` lets lookups reach them
|
|
25
|
+
* before `mapArray` inserts them into the DOM.
|
|
28
26
|
*
|
|
29
|
-
* Step 3
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
27
|
+
* Step 3 must stay reachable whether or not the primary is attached, which
|
|
28
|
+
* is why step 2 ends its walk with `break` rather than `return`. Only the
|
|
29
|
+
* sibling walk is bounded; ending the generator there would skip the stash.
|
|
30
|
+
*
|
|
31
|
+
* This used to be a `return`, and the difference was invisible: with a
|
|
32
|
+
* detached primary `nextSibling` is `null`, so the walk never runs and
|
|
33
|
+
* control reaches the stash regardless. Attaching the primary made the very
|
|
34
|
+
* first sibling a boundary comment, which ended the generator before the
|
|
35
|
+
* stash was consulted and left the item's child placeholders unreplaced.
|
|
36
|
+
* Measured, not deduced — and note this is NOT the failure the earlier
|
|
37
|
+
* comment here described: the walk never ran past the item into a
|
|
38
|
+
* neighbouring one, it stopped correctly and then gave up too early.
|
|
35
39
|
*/
|
|
36
40
|
/**
|
|
37
41
|
* Find an element matching `selector` within an item's range. Searches
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qsa-item.d.ts","sourceRoot":"","sources":["../../src/runtime/qsa-item.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"qsa-item.d.ts","sourceRoot":"","sources":["../../src/runtime/qsa-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AA4CH;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQnF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,OAAO,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,GAC3B,WAAW,GAAG,IAAI,CAuBpB"}
|
|
@@ -1767,6 +1767,14 @@ function takeRowMountPoint() {
|
|
|
1767
1767
|
_rowMountPoint = null;
|
|
1768
1768
|
return p;
|
|
1769
1769
|
}
|
|
1770
|
+
function mountRowRoot(el) {
|
|
1771
|
+
const p = takeRowMountPoint();
|
|
1772
|
+
if (p) {
|
|
1773
|
+
p.container.insertBefore(el, p.anchor);
|
|
1774
|
+
p.mounted = el;
|
|
1775
|
+
}
|
|
1776
|
+
return el;
|
|
1777
|
+
}
|
|
1770
1778
|
function createComponent(nameOrDef, props = {}, key, slot, mountAt) {
|
|
1771
1779
|
const element = materializeComponent(nameOrDef, props, key, slot, mountAt);
|
|
1772
1780
|
if (mountAt && mountAt.parentNode && element !== mountAt) {
|
|
@@ -1810,12 +1818,13 @@ function materializeComponent(nameOrDef, props = {}, key, slot, mountAt) {
|
|
|
1810
1818
|
});
|
|
1811
1819
|
const def = getRegisteredDef(name);
|
|
1812
1820
|
const isCommentWrapper = def?.comment === true;
|
|
1813
|
-
const
|
|
1821
|
+
const derivedScopeId = slot?.parent && slot.mount ? `${slot.parent}_${slot.mount}` : null;
|
|
1822
|
+
const scopeId = isCommentWrapper ? null : derivedScopeId ?? `${name}_${generateId()}`;
|
|
1814
1823
|
const prevParentScopeId = _parentScopeId;
|
|
1815
|
-
if (
|
|
1816
|
-
_parentScopeId = slot.parent;
|
|
1817
|
-
} else if (scopeId) {
|
|
1824
|
+
if (scopeId) {
|
|
1818
1825
|
_parentScopeId = scopeId;
|
|
1826
|
+
} else if (slot?.parent) {
|
|
1827
|
+
_parentScopeId = slot.parent;
|
|
1819
1828
|
}
|
|
1820
1829
|
let html;
|
|
1821
1830
|
try {
|
|
@@ -1883,7 +1892,8 @@ function renderChild(name, props, key, slotSuffix) {
|
|
|
1883
1892
|
if (!templateFn) {
|
|
1884
1893
|
return `<div ${bfsAttr}${slotAttrs}${keyAttr}></div>`;
|
|
1885
1894
|
}
|
|
1886
|
-
|
|
1895
|
+
const raw = templateFn(props);
|
|
1896
|
+
let html = raw.trim().replace(PLACEHOLDER_ATTR_PATTERN, _parentScopeId ? ` bf-s="${_parentScopeId}"` : "");
|
|
1887
1897
|
const firstElMatch = html.match(/<(\w+)/);
|
|
1888
1898
|
if (!firstElMatch)
|
|
1889
1899
|
return html;
|
|
@@ -2144,7 +2154,7 @@ function* itemRootElements(primaryEl) {
|
|
|
2144
2154
|
if (n.nodeType === Node.COMMENT_NODE) {
|
|
2145
2155
|
const v = n.nodeValue ?? "";
|
|
2146
2156
|
if (v === BF_LOOP_ITEM || v === BF_LOOP_START || v.startsWith(startPrefix) || v === BF_LOOP_END || v.startsWith(endPrefix)) {
|
|
2147
|
-
|
|
2157
|
+
break;
|
|
2148
2158
|
}
|
|
2149
2159
|
} else if (n.nodeType === Node.ELEMENT_NODE) {
|
|
2150
2160
|
yield n;
|
|
@@ -2316,9 +2326,16 @@ function createItemScope(item, index, renderItem, existingPrimary, existingExtra
|
|
|
2316
2326
|
const prevRowMount = ownsRowMount ? setRowMountPoint(rowMount) : null;
|
|
2317
2327
|
try {
|
|
2318
2328
|
primaryEl = renderItem(itemAccessor, index, existingPrimary);
|
|
2329
|
+
} catch (err) {
|
|
2330
|
+
const parked = rowMount?.mounted;
|
|
2331
|
+
if (parked?.parentNode)
|
|
2332
|
+
parked.remove();
|
|
2333
|
+
throw err;
|
|
2319
2334
|
} finally {
|
|
2320
2335
|
if (ownsRowMount)
|
|
2321
2336
|
setRowMountPoint(prevRowMount);
|
|
2337
|
+
if (rowMount)
|
|
2338
|
+
rowMount.mounted = null;
|
|
2322
2339
|
}
|
|
2323
2340
|
if (existingPrimary) {
|
|
2324
2341
|
extras = existingExtras ?? [];
|
|
@@ -3647,6 +3664,7 @@ export {
|
|
|
3647
3664
|
parseHTML,
|
|
3648
3665
|
onMount,
|
|
3649
3666
|
onCleanup,
|
|
3667
|
+
mountRowRoot,
|
|
3650
3668
|
mapArrayLazy,
|
|
3651
3669
|
mapArrayAnchored,
|
|
3652
3670
|
mapArray,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "BarefootJS client package: reactive primitives (SSR-safe) plus browser runtime under the `/runtime` subpath (compiler target)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/client"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.
|
|
58
|
+
"@barefootjs/shared": "0.30.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0"
|
package/src/runtime/component.ts
CHANGED
|
@@ -25,8 +25,14 @@ export function setParentScopeId(id: string | null): void {
|
|
|
25
25
|
_parentScopeId = id
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Where `mapArray` wants a fresh loop row connected before its `init` runs.
|
|
30
|
+
*
|
|
31
|
+
* `mounted` is written back by `mountRowRoot` so the caller can undo the
|
|
32
|
+
* connection if the rest of the row's body then throws — see `createItemScope`.
|
|
33
|
+
* Without it a half-built row stays visible, which detached rows never did.
|
|
34
|
+
*/
|
|
35
|
+
export type RowMountPoint = { container: Node; anchor: Node | null; mounted?: Element | null }
|
|
30
36
|
|
|
31
37
|
// Ambient mount point for a loop row.
|
|
32
38
|
//
|
|
@@ -60,6 +66,35 @@ function takeRowMountPoint(): RowMountPoint | null {
|
|
|
60
66
|
return p
|
|
61
67
|
}
|
|
62
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Connect a loop row whose root is a template clone, before the emitted
|
|
71
|
+
* renderItem body's tail runs.
|
|
72
|
+
*
|
|
73
|
+
* The tail is where the row's nested children initialise (`upsertChild` and
|
|
74
|
+
* friends), and `useContext` resolves by walking `parentElement` — so a child
|
|
75
|
+
* that inits inside a detached row finds no ancestors and falls through to the
|
|
76
|
+
* global last-writer-wins context store, reading whichever provider on the page
|
|
77
|
+
* wrote last. `createComponent` row roots already avoid this by consuming the
|
|
78
|
+
* same ambient (step 7b); a clone root has no runtime function in the middle,
|
|
79
|
+
* so the compiler emits this call for it instead.
|
|
80
|
+
*
|
|
81
|
+
* Take-and-clear, like the `createComponent` path: a nested `createComponent`
|
|
82
|
+
* driven by this row's own children must not re-use the row's mount point.
|
|
83
|
+
*
|
|
84
|
+
* No-op when there is no ambient point — the hydration branch never calls this
|
|
85
|
+
* (its row came from SSR markup and is already in the document), and a loop
|
|
86
|
+
* runtime that does not hand one down leaves the row exactly as it was.
|
|
87
|
+
*/
|
|
88
|
+
export function mountRowRoot(el: Element): Element {
|
|
89
|
+
const p = takeRowMountPoint()
|
|
90
|
+
if (p) {
|
|
91
|
+
p.container.insertBefore(el, p.anchor)
|
|
92
|
+
// Record it so the row can be un-mounted if the body throws after this.
|
|
93
|
+
p.mounted = el
|
|
94
|
+
}
|
|
95
|
+
return el
|
|
96
|
+
}
|
|
97
|
+
|
|
63
98
|
/**
|
|
64
99
|
* Create a component instance with DOM element and initialized state.
|
|
65
100
|
*
|
|
@@ -200,9 +235,18 @@ function materializeComponent(
|
|
|
200
235
|
// already the inner component's root with its own bf-s. Don't overwrite
|
|
201
236
|
// it (scopeId stays null), or `$c(__scope, 's0')` from the wrapper's
|
|
202
237
|
// init resolves to null.
|
|
238
|
+
//
|
|
239
|
+
// `slot` is only supplied by `upsertChild` / `upsertChildItem` mounting a
|
|
240
|
+
// component nested below a loop row root — the SSR reference (Hono)
|
|
241
|
+
// derives that child's `bf-s` from `${hostScope}_${mountSlot}` rather
|
|
242
|
+
// than randomizing it (#2444), so CSR must match or the primary
|
|
243
|
+
// `(bf-h, bf-m)` SSR-scope lookup never finds the CSR-created element.
|
|
244
|
+
// A row root itself is never passed a `slot`, so it keeps its own
|
|
245
|
+
// random id, matching the reference behaviour.
|
|
203
246
|
const def = getRegisteredDef(name)
|
|
204
247
|
const isCommentWrapper = def?.comment === true
|
|
205
|
-
const
|
|
248
|
+
const derivedScopeId = slot?.parent && slot.mount ? `${slot.parent}_${slot.mount}` : null
|
|
249
|
+
const scopeId = isCommentWrapper ? null : (derivedScopeId ?? `${name}_${generateId()}`)
|
|
206
250
|
|
|
207
251
|
// 5. Generate HTML from props.
|
|
208
252
|
//
|
|
@@ -211,13 +255,18 @@ function materializeComponent(
|
|
|
211
255
|
// bf-m on child components — matching the SSR convention so a later
|
|
212
256
|
// `$c(scope, 'sN')` lookup resolves them. Without this, CSR-created
|
|
213
257
|
// children carry a random prefix and their event handlers never wire
|
|
214
|
-
// up (#1627). `slot.parent`
|
|
215
|
-
//
|
|
258
|
+
// up (#1627). `scopeId` takes precedence over `slot.parent` — once a
|
|
259
|
+
// slotted component derives its OWN scope id (above), that derived id
|
|
260
|
+
// is what ITS children must nest under, not the grandparent's `slot.parent`
|
|
261
|
+
// (that used to collapse a third composition level back onto the second,
|
|
262
|
+
// #2444's `grandchild-composition` case). A comment wrapper keeps
|
|
263
|
+
// `scopeId === null` and falls through to `slot?.parent`, preserving the
|
|
264
|
+
// hoisted-children placeholder resolution (#1320).
|
|
216
265
|
const prevParentScopeId = _parentScopeId
|
|
217
|
-
if (
|
|
218
|
-
_parentScopeId = slot.parent
|
|
219
|
-
} else if (scopeId) {
|
|
266
|
+
if (scopeId) {
|
|
220
267
|
_parentScopeId = scopeId
|
|
268
|
+
} else if (slot?.parent) {
|
|
269
|
+
_parentScopeId = slot.parent
|
|
221
270
|
}
|
|
222
271
|
let html: string
|
|
223
272
|
try {
|
|
@@ -381,11 +430,31 @@ export function renderChild(
|
|
|
381
430
|
return `<div ${bfsAttr}${slotAttrs}${keyAttr}></div>`
|
|
382
431
|
}
|
|
383
432
|
|
|
433
|
+
// NOTE: does NOT push `_parentScopeId` to this child's own derived scope
|
|
434
|
+
// while `templateFn` evaluates. That was tried (deriving a GRANDCHILD's
|
|
435
|
+
// scope from this scope rather than the caller's, to fix a third
|
|
436
|
+
// composition level collapsing onto the second — `grandchild-composition`)
|
|
437
|
+
// but it collides with `comment: true` wrapper transparency (#1211
|
|
438
|
+
// synthesized inline-JSX-callback wrappers, e.g. a `renderNode` callback
|
|
439
|
+
// prop): such a wrapper's OWN scope element IS its single child's element,
|
|
440
|
+
// and its init resolves itself via `$c(scope, 's0')`'s short-suffix
|
|
441
|
+
// self-match fallback (`query.ts`'s `$cSingle`). Pushing this scope makes
|
|
442
|
+
// a nested descendant of that SAME child derive `..._s0_s0` whenever the
|
|
443
|
+
// descendant's own first slot id also happens to be `s0` — the PRECISE
|
|
444
|
+
// suffix match then finds that unrelated descendant instead of falling
|
|
445
|
+
// through to the self-match, silently misrouting `initChild` (confirmed
|
|
446
|
+
// via `site/ui`'s xyflow Highlight-Depth demo, where this broke the
|
|
447
|
+
// `--node-glow` style effect). `grandchild-composition` stays a known
|
|
448
|
+
// limitation (CSR conformance skip) until the self-match lookup can be
|
|
449
|
+
// made unambiguous against a nested descendant sharing the same slot
|
|
450
|
+
// suffix.
|
|
451
|
+
const raw = templateFn(props)
|
|
452
|
+
|
|
384
453
|
// The placeholder substitution is anchored to the exact `bf-s="…"`
|
|
385
454
|
// shape so user content that contains the sentinel as text survives
|
|
386
455
|
// unchanged. When `_parentScopeId` is null (top-level render) the
|
|
387
456
|
// attribute strips rather than emitting `bf-s=""`. (#1320)
|
|
388
|
-
let html =
|
|
457
|
+
let html = raw.trim().replace(
|
|
389
458
|
PLACEHOLDER_ATTR_PATTERN,
|
|
390
459
|
_parentScopeId ? ` bf-s="${_parentScopeId}"` : '',
|
|
391
460
|
)
|
package/src/runtime/index.ts
CHANGED
package/src/runtime/map-array.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { createSignal, createEffect, createRoot } from '@barefootjs/client/reactive'
|
|
22
22
|
import { hydratedScopes } from './hydration-state.ts'
|
|
23
|
-
import { setRowMountPoint } from './component.ts'
|
|
23
|
+
import { setRowMountPoint, type RowMountPoint } from './component.ts'
|
|
24
24
|
import {
|
|
25
25
|
BF_KEY,
|
|
26
26
|
BF_LOOP_START,
|
|
@@ -234,7 +234,7 @@ function createItemScope<T>(
|
|
|
234
234
|
existingPrimary?: HTMLElement,
|
|
235
235
|
existingExtras?: HTMLElement[],
|
|
236
236
|
existingStart?: Comment | null,
|
|
237
|
-
rowMount?:
|
|
237
|
+
rowMount?: RowMountPoint | null,
|
|
238
238
|
): ItemScope<T> {
|
|
239
239
|
let primaryEl!: HTMLElement
|
|
240
240
|
let dispose!: () => void
|
|
@@ -246,10 +246,11 @@ function createItemScope<T>(
|
|
|
246
246
|
dispose = d
|
|
247
247
|
const [itemAccessor, itemSetter] = createSignal(item)
|
|
248
248
|
setItem = itemSetter
|
|
249
|
-
// Fresh row: hand the mount point
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
249
|
+
// Fresh row: hand the mount point down so the row's own root — whether a
|
|
250
|
+
// `createComponent` call or a `mountRowRoot(clone)` — observes a connected
|
|
251
|
+
// element when the body's tail initialises its children. A body that does
|
|
252
|
+
// neither (a plain loop's clone) leaves the point unconsumed, hence the
|
|
253
|
+
// restore below rather than a plain clear.
|
|
253
254
|
//
|
|
254
255
|
// Only touch the ambient when we are the one setting it, and put back what
|
|
255
256
|
// was there rather than `null`: this row's `init` can drive a nested
|
|
@@ -259,8 +260,16 @@ function createItemScope<T>(
|
|
|
259
260
|
const prevRowMount = ownsRowMount ? setRowMountPoint(rowMount) : null
|
|
260
261
|
try {
|
|
261
262
|
primaryEl = renderItem(itemAccessor, index, existingPrimary)
|
|
263
|
+
} catch (err) {
|
|
264
|
+
// A row that connected itself and then failed to finish would stay
|
|
265
|
+
// visible as a half-built row. Detached rows never could, so undo the
|
|
266
|
+
// connection before rethrowing and keep the failure mode as it was.
|
|
267
|
+
const parked = rowMount?.mounted
|
|
268
|
+
if (parked?.parentNode) parked.remove()
|
|
269
|
+
throw err
|
|
262
270
|
} finally {
|
|
263
271
|
if (ownsRowMount) setRowMountPoint(prevRowMount)
|
|
272
|
+
if (rowMount) rowMount.mounted = null
|
|
264
273
|
}
|
|
265
274
|
if (existingPrimary) {
|
|
266
275
|
extras = existingExtras ?? []
|
package/src/runtime/qsa-item.ts
CHANGED
|
@@ -20,18 +20,22 @@
|
|
|
20
20
|
* cannot escape into a neighbouring item or into nodes outside the
|
|
21
21
|
* loop.
|
|
22
22
|
* 3. The CSR-only `__bfExtras` stash. During renderItem-body setup
|
|
23
|
-
* (between the template clone and the function's return), the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* lookups reach the still-pending extras before `mapArray` inserts
|
|
27
|
-
* them into the DOM.
|
|
23
|
+
* (between the template clone and the function's return), the extras
|
|
24
|
+
* are not siblings yet. Reading `__bfExtras` lets lookups reach them
|
|
25
|
+
* before `mapArray` inserts them into the DOM.
|
|
28
26
|
*
|
|
29
|
-
* Step 3
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
27
|
+
* Step 3 must stay reachable whether or not the primary is attached, which
|
|
28
|
+
* is why step 2 ends its walk with `break` rather than `return`. Only the
|
|
29
|
+
* sibling walk is bounded; ending the generator there would skip the stash.
|
|
30
|
+
*
|
|
31
|
+
* This used to be a `return`, and the difference was invisible: with a
|
|
32
|
+
* detached primary `nextSibling` is `null`, so the walk never runs and
|
|
33
|
+
* control reaches the stash regardless. Attaching the primary made the very
|
|
34
|
+
* first sibling a boundary comment, which ended the generator before the
|
|
35
|
+
* stash was consulted and left the item's child placeholders unreplaced.
|
|
36
|
+
* Measured, not deduced — and note this is NOT the failure the earlier
|
|
37
|
+
* comment here described: the walk never ran past the item into a
|
|
38
|
+
* neighbouring one, it stopped correctly and then gave up too early.
|
|
35
39
|
*/
|
|
36
40
|
|
|
37
41
|
import { BF_LOOP_ITEM, BF_LOOP_START, BF_LOOP_END } from '@barefootjs/shared'
|
|
@@ -51,10 +55,16 @@ function* itemRootElements(primaryEl: Element): Iterable<Element> {
|
|
|
51
55
|
// Hard stops: another item starts, or the loop range ends. The
|
|
52
56
|
// BF_LOOP_START check defends against a sibling loop block whose
|
|
53
57
|
// start marker happens to follow ours.
|
|
58
|
+
// `break`, not `return`: stop the SIBLING walk, but still fall through
|
|
59
|
+
// to the `__bfExtras` stash below. A `return` ends the generator, and
|
|
60
|
+
// the stash is the only way to reach extras that are not siblings yet.
|
|
61
|
+
// That difference is invisible while the primary is detached — then
|
|
62
|
+
// `nextSibling` is `null`, this loop never runs, and control reaches the
|
|
63
|
+
// stash anyway — and decides the outcome the moment it is attached.
|
|
54
64
|
if (v === BF_LOOP_ITEM
|
|
55
65
|
|| v === BF_LOOP_START || v.startsWith(startPrefix)
|
|
56
66
|
|| v === BF_LOOP_END || v.startsWith(endPrefix)) {
|
|
57
|
-
|
|
67
|
+
break
|
|
58
68
|
}
|
|
59
69
|
} else if (n.nodeType === Node.ELEMENT_NODE) {
|
|
60
70
|
yield n as Element
|