@barefootjs/client 0.26.3 → 0.27.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/reactive.d.ts.map +1 -1
- package/dist/runtime/claim-slots.d.ts +157 -0
- package/dist/runtime/claim-slots.d.ts.map +1 -0
- package/dist/runtime/component.d.ts +29 -17
- package/dist/runtime/component.d.ts.map +1 -1
- package/dist/runtime/dynamic-text.d.ts +24 -1
- package/dist/runtime/dynamic-text.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +4 -4
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +206 -206
- package/dist/runtime/loop-markers.d.ts +26 -0
- package/dist/runtime/loop-markers.d.ts.map +1 -0
- package/dist/runtime/patch-leaf.d.ts +17 -0
- package/dist/runtime/patch-leaf.d.ts.map +1 -0
- package/dist/runtime/standalone.js +206 -206
- package/package.json +2 -2
- package/src/reactive.ts +2 -1
- package/src/runtime/claim-slots.ts +449 -0
- package/src/runtime/component.ts +39 -69
- package/src/runtime/dynamic-text.ts +24 -1
- package/src/runtime/index.ts +17 -6
- package/src/runtime/insert.ts +1 -1
- package/src/runtime/loop-markers.ts +100 -0
- package/src/runtime/patch-leaf.ts +41 -0
- package/dist/runtime/client-marker.d.ts +0 -21
- package/dist/runtime/client-marker.d.ts.map +0 -1
- package/dist/runtime/list.d.ts +0 -21
- package/dist/runtime/list.d.ts.map +0 -1
- package/dist/runtime/reconcile-elements.d.ts +0 -44
- package/dist/runtime/reconcile-elements.d.ts.map +0 -1
- package/src/runtime/client-marker.ts +0 -46
- package/src/runtime/list.ts +0 -47
- package/src/runtime/reconcile-elements.ts +0 -391
package/src/runtime/index.ts
CHANGED
|
@@ -77,11 +77,17 @@ export {
|
|
|
77
77
|
type PortalChildren,
|
|
78
78
|
} from './portal.ts'
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
export {
|
|
80
|
+
// Loop boundary marker lookup (used by mapArray/mapArrayAnchored consumers
|
|
81
|
+
// and compiler-generated clearing code — see ./loop-markers.ts docstring)
|
|
82
|
+
export { getLoopChildren, getLoopNodes } from './loop-markers.ts'
|
|
83
83
|
export { qsaItem, upsertChildItem } from './qsa-item.ts'
|
|
84
84
|
export { mapArray, mapArrayAnchored } from './map-array.ts'
|
|
85
|
+
export { patchLeaf } from './patch-leaf.ts'
|
|
86
|
+
|
|
87
|
+
// Claim-plan interpreter (slot unification A2/A3, spec/slot-unification.md)
|
|
88
|
+
// — the ONE content-slot update mechanism, wired up by the compiler in A3.
|
|
89
|
+
// Supersedes (deleted) `patchSlotRange` and `updateClientMarker`.
|
|
90
|
+
export { claimSlots, lazySlots, type SlotSpec, type ClaimPlan, type ClaimedSlots, type SlotWriter } from './claim-slots.ts'
|
|
85
91
|
|
|
86
92
|
// Template registry
|
|
87
93
|
export { registerTemplate, getTemplate, hasTemplate, type TemplateFn } from './template.ts'
|
|
@@ -90,11 +96,10 @@ export { registerTemplate, getTemplate, hasTemplate, type TemplateFn } from './t
|
|
|
90
96
|
export {
|
|
91
97
|
createComponent,
|
|
92
98
|
renderChild,
|
|
93
|
-
getPropsUpdateFn,
|
|
94
|
-
getComponentProps,
|
|
95
99
|
parseHTML,
|
|
96
100
|
escapeAttr,
|
|
97
101
|
escapeText,
|
|
102
|
+
escapeTextOrNode,
|
|
98
103
|
} from './component.ts'
|
|
99
104
|
|
|
100
105
|
// Spread props helpers
|
|
@@ -109,8 +114,14 @@ export { hydrate, rehydrateAll, rehydrateScope, disposeScope, flushHydration, ge
|
|
|
109
114
|
export { registerComponent, getComponentInit, initChild, upsertChild } from './registry.ts'
|
|
110
115
|
export { insert, type BranchConfig, type BranchTemplateResult } from './insert.ts'
|
|
111
116
|
export { __bfSlot } from './branch-slot.ts'
|
|
117
|
+
// `__bfText` (dynamic-text.ts) and `$t` (query.ts) are kept: one narrow
|
|
118
|
+
// emission site — a `@client`-nested-inside-a-top-level-conditional dynamic
|
|
119
|
+
// text/JSX expression (`emitDynamicTextUpdates`'s `conditionalElems` path in
|
|
120
|
+
// `ir-to-client-js/emit-reactive.ts`) still uses them, deferred from slot
|
|
121
|
+
// unification A3 (see that function's docstring for why the claim-plan
|
|
122
|
+
// model doesn't fit that one case cleanly). `updateClientMarker` had no
|
|
123
|
+
// such holdout and is fully deleted.
|
|
112
124
|
export { __bfText } from './dynamic-text.ts'
|
|
113
|
-
export { updateClientMarker } from './client-marker.ts'
|
|
114
125
|
|
|
115
126
|
// Hydration state
|
|
116
127
|
export { hydratedScopes } from './hydration-state.ts'
|
package/src/runtime/insert.ts
CHANGED
|
@@ -338,7 +338,7 @@ export function insert(
|
|
|
338
338
|
function autoFocusConditionalElement(region: CondRegion, id: string): void {
|
|
339
339
|
// Use requestAnimationFrame to defer focus until after DOM updates.
|
|
340
340
|
// This is necessary because createComponent() may call insert() before
|
|
341
|
-
// the element is added to the document by
|
|
341
|
+
// the element is added to the document by mapArray()/mapArrayAnchored().
|
|
342
342
|
requestAnimationFrame(() => {
|
|
343
343
|
const condEl = region.anchor
|
|
344
344
|
? findCondElInRange(region.anchor, id)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BarefootJS - Loop Boundary Marker Lookup
|
|
3
|
+
*
|
|
4
|
+
* `<!--bf-loop:<id>-->` / `<!--bf-/loop:<id>-->` comment markers delimit a
|
|
5
|
+
* loop's rendered range inside its container so `mapArray`/`mapArrayAnchored`
|
|
6
|
+
* (`./map-array.ts`) can reconcile only that range without disturbing
|
|
7
|
+
* non-loop siblings. These lookups used to also back the now-removed
|
|
8
|
+
* `reconcileElements`/`reconcileList` element-reconciler (slot unification
|
|
9
|
+
* A4); they remain as the compiler-facing marker API.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { BF_LOOP_START, BF_LOOP_END, loopStartMarker, loopEndMarker } from '@barefootjs/shared'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Find loop boundary comment markers in a container.
|
|
16
|
+
*
|
|
17
|
+
* `markerId` scopes the lookup to `<!--bf-loop:<id>-->` / `<!--bf-/loop:<id>-->`
|
|
18
|
+
* so sibling loops under the same parent disambiguate (#1087). Without an id,
|
|
19
|
+
* accepts the legacy unscoped form too — used by tests that build containers
|
|
20
|
+
* without compiler-emitted markers.
|
|
21
|
+
*/
|
|
22
|
+
function findLoopMarkers(
|
|
23
|
+
container: HTMLElement,
|
|
24
|
+
markerId?: string,
|
|
25
|
+
): { startMarker: Comment | null; endMarker: Comment | null } {
|
|
26
|
+
let startMarker: Comment | null = null
|
|
27
|
+
let endMarker: Comment | null = null
|
|
28
|
+
if (markerId) {
|
|
29
|
+
const startVal = loopStartMarker(markerId)
|
|
30
|
+
const endVal = loopEndMarker(markerId)
|
|
31
|
+
for (const node of Array.from(container.childNodes)) {
|
|
32
|
+
if (node.nodeType !== Node.COMMENT_NODE) continue
|
|
33
|
+
const value = (node as Comment).nodeValue
|
|
34
|
+
if (value === startVal) startMarker = node as Comment
|
|
35
|
+
else if (value === endVal) endMarker = node as Comment
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
const startPrefix = `${BF_LOOP_START}:`
|
|
39
|
+
const endPrefix = `${BF_LOOP_END}:`
|
|
40
|
+
for (const node of Array.from(container.childNodes)) {
|
|
41
|
+
if (node.nodeType !== Node.COMMENT_NODE) continue
|
|
42
|
+
const value = (node as Comment).nodeValue ?? ''
|
|
43
|
+
if (!startMarker && (value === BF_LOOP_START || value.startsWith(startPrefix))) {
|
|
44
|
+
startMarker = node as Comment
|
|
45
|
+
} else if (!endMarker && (value === BF_LOOP_END || value.startsWith(endPrefix))) {
|
|
46
|
+
endMarker = node as Comment
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (startMarker && endMarker) return { startMarker, endMarker }
|
|
51
|
+
return { startMarker: null, endMarker: null }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Get all Element nodes between start and end comment markers. */
|
|
55
|
+
function getElementsBetweenMarkers(start: Comment, end: Comment): Element[] {
|
|
56
|
+
const elements: Element[] = []
|
|
57
|
+
let node: Node | null = start.nextSibling
|
|
58
|
+
while (node && node !== end) {
|
|
59
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
60
|
+
elements.push(node as Element)
|
|
61
|
+
}
|
|
62
|
+
node = node.nextSibling
|
|
63
|
+
}
|
|
64
|
+
return elements
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get loop children from a container, respecting bf-loop boundary markers.
|
|
69
|
+
* When markers are present, returns only elements between them.
|
|
70
|
+
* When absent, returns all children (backward compatible).
|
|
71
|
+
* Exported for use by compiler-generated hydration code.
|
|
72
|
+
*/
|
|
73
|
+
export function getLoopChildren(container: HTMLElement, markerId?: string): HTMLElement[] {
|
|
74
|
+
const { startMarker, endMarker } = findLoopMarkers(container, markerId)
|
|
75
|
+
if (startMarker && endMarker) {
|
|
76
|
+
return getElementsBetweenMarkers(startMarker, endMarker) as HTMLElement[]
|
|
77
|
+
}
|
|
78
|
+
return Array.from(container.children) as HTMLElement[]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Like {@link getLoopChildren}, but returns every node between the loop
|
|
83
|
+
* boundary markers — Comments (per-item `<!--bf-loop-i-->` markers) and
|
|
84
|
+
* text included. The branch-clearing path needs to remove the per-item
|
|
85
|
+
* marker comments alongside elements; otherwise stale markers would
|
|
86
|
+
* accumulate when a branch swap forces mapArray to start over (#1212).
|
|
87
|
+
*/
|
|
88
|
+
export function getLoopNodes(container: HTMLElement, markerId?: string): Node[] {
|
|
89
|
+
const { startMarker, endMarker } = findLoopMarkers(container, markerId)
|
|
90
|
+
const nodes: Node[] = []
|
|
91
|
+
if (startMarker && endMarker) {
|
|
92
|
+
let node: Node | null = startMarker.nextSibling
|
|
93
|
+
while (node && node !== endMarker) {
|
|
94
|
+
nodes.push(node)
|
|
95
|
+
node = node.nextSibling
|
|
96
|
+
}
|
|
97
|
+
return nodes
|
|
98
|
+
}
|
|
99
|
+
return Array.from(container.childNodes)
|
|
100
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-place patch for flatMap leaf elements (the descriptor-based
|
|
3
|
+
* `mapArray` path — see `stringifyPlainLoop`'s flatMap branch in
|
|
4
|
+
* `@barefootjs/jsx`).
|
|
5
|
+
*
|
|
6
|
+
* flatMap leaves carry no per-slot reactive wiring (the compiler refuses
|
|
7
|
+
* leaves that would need it), so a leaf whose rendered HTML changed under a
|
|
8
|
+
* stable key is updated wholesale: attributes are synced and children are
|
|
9
|
+
* replaced from the freshly rendered string. The element's identity is
|
|
10
|
+
* preserved — `mapArray` holds the node in its keyed scope map, so the
|
|
11
|
+
* patch must never swap the node itself.
|
|
12
|
+
*
|
|
13
|
+
* `data-key` is excluded from attribute sync: reconciliation identity is
|
|
14
|
+
* owned by `mapArray` (stamped via `setAttribute`), never by leaf content.
|
|
15
|
+
*/
|
|
16
|
+
export function patchLeaf(el: Element, html: string): void {
|
|
17
|
+
const tpl = document.createElement('template')
|
|
18
|
+
tpl.innerHTML = html
|
|
19
|
+
const next = tpl.content.firstElementChild
|
|
20
|
+
if (!next) return
|
|
21
|
+
if (next.tagName !== el.tagName) {
|
|
22
|
+
// A root-tag change under a stable key cannot swap the node without
|
|
23
|
+
// desyncing mapArray's keyed scope. Attributes/children still patch
|
|
24
|
+
// onto the existing tag; the honest fix is a distinct key per branch.
|
|
25
|
+
console.warn(
|
|
26
|
+
'[barefootjs] flatMap leaf root tag changed under a stable key ' +
|
|
27
|
+
`(<${el.tagName.toLowerCase()}> -> <${next.tagName.toLowerCase()}>); ` +
|
|
28
|
+
'give each branch its own key so the node is replaced instead of patched.',
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
for (const name of el.getAttributeNames()) {
|
|
32
|
+
if (name === 'data-key') continue
|
|
33
|
+
if (!next.hasAttribute(name)) el.removeAttribute(name)
|
|
34
|
+
}
|
|
35
|
+
for (const name of next.getAttributeNames()) {
|
|
36
|
+
if (name === 'data-key') continue
|
|
37
|
+
const value = next.getAttribute(name)
|
|
38
|
+
if (value !== null && el.getAttribute(name) !== value) el.setAttribute(name, value)
|
|
39
|
+
}
|
|
40
|
+
el.replaceChildren(...Array.from(next.childNodes))
|
|
41
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BarefootJS - Client Marker
|
|
3
|
-
*
|
|
4
|
-
* Update text content for @client directive expressions
|
|
5
|
-
* that are evaluated only on the client side.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Update text content for a client marker.
|
|
9
|
-
*
|
|
10
|
-
* Expects comment marker format: <!--bf-client:sX-->
|
|
11
|
-
* Both GoTemplateAdapter and HonoAdapter output this format for @client directives.
|
|
12
|
-
*
|
|
13
|
-
* A zero-width space (\u200B) is used as a prefix to mark text nodes managed by @client.
|
|
14
|
-
* This allows distinguishing managed text nodes from other content.
|
|
15
|
-
*
|
|
16
|
-
* @param scope - The component scope element to search within
|
|
17
|
-
* @param id - The slot ID (e.g., 's5')
|
|
18
|
-
* @param value - The value to display (will be converted to string)
|
|
19
|
-
*/
|
|
20
|
-
export declare function updateClientMarker(scope: Element | null, id: string, value: unknown): void;
|
|
21
|
-
//# sourceMappingURL=client-marker.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-marker.d.ts","sourceRoot":"","sources":["../../src/runtime/client-marker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAyB1F"}
|
package/dist/runtime/list.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BarefootJS - List Reconciliation
|
|
3
|
-
*
|
|
4
|
-
* Key-based DOM reconciliation for efficient list updates.
|
|
5
|
-
* Delegates to reconcileElements for element-based rendering.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Render function type for list items.
|
|
9
|
-
* Returns an HTMLElement for each item.
|
|
10
|
-
*/
|
|
11
|
-
export type RenderItemFn<T> = (item: T, index: number) => HTMLElement;
|
|
12
|
-
/**
|
|
13
|
-
* Reconcile a list container with new items using key-based matching.
|
|
14
|
-
*
|
|
15
|
-
* @param container - The parent element containing list items
|
|
16
|
-
* @param items - Array of items to render
|
|
17
|
-
* @param getKey - Function to extract a unique key from each item (or null to use index)
|
|
18
|
-
* @param renderItem - Function to render an item as HTMLElement
|
|
19
|
-
*/
|
|
20
|
-
export declare function reconcileList<T>(container: HTMLElement | null, items: T[], getKey: ((item: T, index: number) => string) | null, renderItem: RenderItemFn<T>): void;
|
|
21
|
-
//# sourceMappingURL=list.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/runtime/list.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,WAAW,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,GAC1B,IAAI,CAkBN"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BarefootJS - Element-based List Reconciliation
|
|
3
|
-
*
|
|
4
|
-
* Key-based DOM reconciliation for component-based list rendering.
|
|
5
|
-
* Used when renderItem returns HTMLElement (via createComponent).
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Get loop children from a container, respecting bf-loop boundary markers.
|
|
9
|
-
* When markers are present, returns only elements between them.
|
|
10
|
-
* When absent, returns all children (backward compatible).
|
|
11
|
-
* Exported for use by compiler-generated hydration code.
|
|
12
|
-
*/
|
|
13
|
-
export declare function getLoopChildren(container: HTMLElement, markerId?: string): HTMLElement[];
|
|
14
|
-
/**
|
|
15
|
-
* Like {@link getLoopChildren}, but returns every node between the loop
|
|
16
|
-
* boundary markers — Comments (per-item `<!--bf-loop-i-->` markers) and
|
|
17
|
-
* text included. The branch-clearing path needs to remove the per-item
|
|
18
|
-
* marker comments alongside elements; otherwise stale markers would
|
|
19
|
-
* accumulate when a branch swap forces mapArray to start over (#1212).
|
|
20
|
-
*/
|
|
21
|
-
export declare function getLoopNodes(container: HTMLElement, markerId?: string): Node[];
|
|
22
|
-
/**
|
|
23
|
-
* Ensure loop boundary markers exist in a container for SSR-rendered content.
|
|
24
|
-
* SSR HTML doesn't include markers, so we insert them during hydration.
|
|
25
|
-
* Uses itemCount to identify the last N children as loop items (rest are siblings).
|
|
26
|
-
*/
|
|
27
|
-
export declare function ensureLoopMarkers(container: HTMLElement, itemCount: number, markerId?: string): void;
|
|
28
|
-
/**
|
|
29
|
-
* Reconcile a list container using HTMLElement mode (for createComponent).
|
|
30
|
-
* Reuses existing elements by key, creates new elements as needed.
|
|
31
|
-
*
|
|
32
|
-
* @param container - The parent element containing list items
|
|
33
|
-
* @param items - Array of items to render
|
|
34
|
-
* @param getKey - Function to extract a unique key from each item (or null to use index)
|
|
35
|
-
* @param renderItem - Function that returns an HTMLElement for each item
|
|
36
|
-
* @param firstElement - Pre-created element for first item (avoids duplicate creation when caller already rendered item 0)
|
|
37
|
-
*/
|
|
38
|
-
export declare function reconcileElements<T>(container: HTMLElement | null, items: T[], getKey: ((item: T, index: number) => string) | null, renderItem: (item: T, index: number) => HTMLElement, firstElement?: HTMLElement, markerId?: string): void;
|
|
39
|
-
/**
|
|
40
|
-
* Sync reactive DOM state from a source element to a target element.
|
|
41
|
-
* Copies class names, replaces conditional elements, and syncs text content.
|
|
42
|
-
*/
|
|
43
|
-
export declare function syncElementState(target: HTMLElement, source: HTMLElement): void;
|
|
44
|
-
//# sourceMappingURL=reconcile-elements.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-elements.d.ts","sourceRoot":"","sources":["../../src/runtime/reconcile-elements.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoEH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAMxF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAY9E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAgBpG;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,WAAW,EACnD,YAAY,CAAC,EAAE,WAAW,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CA2JN;AAkCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAiD/E"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BarefootJS - Client Marker
|
|
3
|
-
*
|
|
4
|
-
* Update text content for @client directive expressions
|
|
5
|
-
* that are evaluated only on the client side.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Update text content for a client marker.
|
|
10
|
-
*
|
|
11
|
-
* Expects comment marker format: <!--bf-client:sX-->
|
|
12
|
-
* Both GoTemplateAdapter and HonoAdapter output this format for @client directives.
|
|
13
|
-
*
|
|
14
|
-
* A zero-width space (\u200B) is used as a prefix to mark text nodes managed by @client.
|
|
15
|
-
* This allows distinguishing managed text nodes from other content.
|
|
16
|
-
*
|
|
17
|
-
* @param scope - The component scope element to search within
|
|
18
|
-
* @param id - The slot ID (e.g., 's5')
|
|
19
|
-
* @param value - The value to display (will be converted to string)
|
|
20
|
-
*/
|
|
21
|
-
export function updateClientMarker(scope: Element | null, id: string, value: unknown): void {
|
|
22
|
-
if (!scope) return
|
|
23
|
-
|
|
24
|
-
const marker = `bf-client:${id}`
|
|
25
|
-
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_COMMENT)
|
|
26
|
-
|
|
27
|
-
while (walker.nextNode()) {
|
|
28
|
-
if (walker.currentNode.nodeValue === marker) {
|
|
29
|
-
const comment = walker.currentNode
|
|
30
|
-
let textNode = comment.nextSibling
|
|
31
|
-
|
|
32
|
-
// Check if next sibling is our managed text node (prefixed with zero-width space)
|
|
33
|
-
if (textNode?.nodeType !== Node.TEXT_NODE ||
|
|
34
|
-
!textNode.nodeValue?.startsWith('\u200B')) {
|
|
35
|
-
// Create new text node with zero-width space marker
|
|
36
|
-
textNode = document.createTextNode('\u200B' + String(value ?? ''))
|
|
37
|
-
// Insert after the comment node
|
|
38
|
-
comment.parentNode?.insertBefore(textNode, comment.nextSibling)
|
|
39
|
-
} else {
|
|
40
|
-
// Update existing managed text node
|
|
41
|
-
textNode.nodeValue = '\u200B' + String(value ?? '')
|
|
42
|
-
}
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
package/src/runtime/list.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BarefootJS - List Reconciliation
|
|
3
|
-
*
|
|
4
|
-
* Key-based DOM reconciliation for efficient list updates.
|
|
5
|
-
* Delegates to reconcileElements for element-based rendering.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { reconcileElements } from './reconcile-elements.ts'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Render function type for list items.
|
|
12
|
-
* Returns an HTMLElement for each item.
|
|
13
|
-
*/
|
|
14
|
-
export type RenderItemFn<T> = (item: T, index: number) => HTMLElement
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Reconcile a list container with new items using key-based matching.
|
|
18
|
-
*
|
|
19
|
-
* @param container - The parent element containing list items
|
|
20
|
-
* @param items - Array of items to render
|
|
21
|
-
* @param getKey - Function to extract a unique key from each item (or null to use index)
|
|
22
|
-
* @param renderItem - Function to render an item as HTMLElement
|
|
23
|
-
*/
|
|
24
|
-
export function reconcileList<T>(
|
|
25
|
-
container: HTMLElement | null,
|
|
26
|
-
items: T[],
|
|
27
|
-
getKey: ((item: T, index: number) => string) | null,
|
|
28
|
-
renderItem: RenderItemFn<T>
|
|
29
|
-
): void {
|
|
30
|
-
if (!container || !items) return
|
|
31
|
-
|
|
32
|
-
if (items.length === 0) {
|
|
33
|
-
container.innerHTML = ''
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Pre-create first element to avoid duplicate creation inside reconcileElements
|
|
38
|
-
const firstElement = renderItem(items[0], 0)
|
|
39
|
-
|
|
40
|
-
reconcileElements(
|
|
41
|
-
container,
|
|
42
|
-
items,
|
|
43
|
-
getKey,
|
|
44
|
-
renderItem,
|
|
45
|
-
firstElement
|
|
46
|
-
)
|
|
47
|
-
}
|