@barefootjs/client 0.1.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/build.d.ts +56 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +76 -0
- package/dist/context.d.ts +25 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/csr-adapter.d.ts +26 -0
- package/dist/csr-adapter.d.ts.map +1 -0
- package/dist/forward-props.d.ts +17 -0
- package/dist/forward-props.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/reactive.d.ts +150 -0
- package/dist/reactive.d.ts.map +1 -0
- package/dist/reactive.js +215 -0
- package/dist/runtime/apply-rest-attrs.d.ts +16 -0
- package/dist/runtime/apply-rest-attrs.d.ts.map +1 -0
- package/dist/runtime/branch-slot.d.ts +22 -0
- package/dist/runtime/branch-slot.d.ts.map +1 -0
- package/dist/runtime/client-marker.d.ts +21 -0
- package/dist/runtime/client-marker.d.ts.map +1 -0
- package/dist/runtime/component.d.ts +99 -0
- package/dist/runtime/component.d.ts.map +1 -0
- package/dist/runtime/context.d.ts +40 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/hydrate.d.ts +100 -0
- package/dist/runtime/hydrate.d.ts.map +1 -0
- package/dist/runtime/hydration-state.d.ts +13 -0
- package/dist/runtime/hydration-state.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +27 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +2093 -0
- package/dist/runtime/insert.d.ts +75 -0
- package/dist/runtime/insert.d.ts.map +1 -0
- package/dist/runtime/list.d.ts +21 -0
- package/dist/runtime/list.d.ts.map +1 -0
- package/dist/runtime/map-array.d.ts +32 -0
- package/dist/runtime/map-array.d.ts.map +1 -0
- package/dist/runtime/portal.d.ts +96 -0
- package/dist/runtime/portal.d.ts.map +1 -0
- package/dist/runtime/qsa-item.d.ts +52 -0
- package/dist/runtime/qsa-item.d.ts.map +1 -0
- package/dist/runtime/query.d.ts +86 -0
- package/dist/runtime/query.d.ts.map +1 -0
- package/dist/runtime/reconcile-elements.d.ts +44 -0
- package/dist/runtime/reconcile-elements.d.ts.map +1 -0
- package/dist/runtime/registry.d.ts +53 -0
- package/dist/runtime/registry.d.ts.map +1 -0
- package/dist/runtime/render.d.ts +35 -0
- package/dist/runtime/render.d.ts.map +1 -0
- package/dist/runtime/scope.d.ts +28 -0
- package/dist/runtime/scope.d.ts.map +1 -0
- package/dist/runtime/slot-resolver.d.ts +36 -0
- package/dist/runtime/slot-resolver.d.ts.map +1 -0
- package/dist/runtime/spread-attrs.d.ts +19 -0
- package/dist/runtime/spread-attrs.d.ts.map +1 -0
- package/dist/runtime/standalone.js +2278 -0
- package/dist/runtime/streaming.d.ts +36 -0
- package/dist/runtime/streaming.d.ts.map +1 -0
- package/dist/runtime/style.d.ts +17 -0
- package/dist/runtime/style.d.ts.map +1 -0
- package/dist/runtime/template.d.ts +39 -0
- package/dist/runtime/template.d.ts.map +1 -0
- package/dist/runtime/types.d.ts +26 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/shims.d.ts +21 -0
- package/dist/shims.d.ts.map +1 -0
- package/dist/slot.d.ts +14 -0
- package/dist/slot.d.ts.map +1 -0
- package/dist/split-props.d.ts +26 -0
- package/dist/split-props.d.ts.map +1 -0
- package/dist/unwrap.d.ts +16 -0
- package/dist/unwrap.d.ts.map +1 -0
- package/package.json +71 -0
- package/src/build.ts +92 -0
- package/src/context.ts +33 -0
- package/src/csr-adapter.ts +134 -0
- package/src/forward-props.ts +43 -0
- package/src/index.ts +42 -0
- package/src/reactive.ts +411 -0
- package/src/runtime/apply-rest-attrs.ts +109 -0
- package/src/runtime/branch-slot.ts +32 -0
- package/src/runtime/client-marker.ts +46 -0
- package/src/runtime/component.ts +501 -0
- package/src/runtime/context.ts +111 -0
- package/src/runtime/hydrate.ts +311 -0
- package/src/runtime/hydration-state.ts +13 -0
- package/src/runtime/index.ts +96 -0
- package/src/runtime/insert.ts +407 -0
- package/src/runtime/list.ts +47 -0
- package/src/runtime/map-array.ts +381 -0
- package/src/runtime/portal.ts +174 -0
- package/src/runtime/qsa-item.ts +128 -0
- package/src/runtime/query.ts +632 -0
- package/src/runtime/reconcile-elements.ts +391 -0
- package/src/runtime/registry.ts +160 -0
- package/src/runtime/render.ts +105 -0
- package/src/runtime/scope.ts +46 -0
- package/src/runtime/slot-resolver.ts +66 -0
- package/src/runtime/spread-attrs.ts +88 -0
- package/src/runtime/streaming.ts +65 -0
- package/src/runtime/style.ts +27 -0
- package/src/runtime/template.ts +53 -0
- package/src/runtime/types.ts +27 -0
- package/src/shims.ts +54 -0
- package/src/slot.ts +23 -0
- package/src/split-props.ts +86 -0
- package/src/unwrap.ts +18 -0
|
@@ -0,0 +1,2278 @@
|
|
|
1
|
+
// src/reactive.ts
|
|
2
|
+
var Owner = null;
|
|
3
|
+
var Listener = null;
|
|
4
|
+
var MAX_EFFECT_RUNS = 100;
|
|
5
|
+
var BatchDepth = 0;
|
|
6
|
+
var PendingEffects = new Set;
|
|
7
|
+
function createSignal(initialValue) {
|
|
8
|
+
let value = initialValue;
|
|
9
|
+
const subscribers = new Set;
|
|
10
|
+
const get = () => {
|
|
11
|
+
if (Listener) {
|
|
12
|
+
subscribers.add(Listener);
|
|
13
|
+
Listener.dependencies.add(subscribers);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
const set = (valueOrFn) => {
|
|
18
|
+
const newValue = typeof valueOrFn === "function" ? valueOrFn(value) : valueOrFn;
|
|
19
|
+
if (Object.is(value, newValue)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
value = newValue;
|
|
23
|
+
if (BatchDepth > 0) {
|
|
24
|
+
for (const effect of subscribers) {
|
|
25
|
+
PendingEffects.add(effect);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
const effectsToRun = [...subscribers];
|
|
29
|
+
for (const effect of effectsToRun) {
|
|
30
|
+
runEffect(effect);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return [get, set];
|
|
35
|
+
}
|
|
36
|
+
function createEffect(fn) {
|
|
37
|
+
const effect = {
|
|
38
|
+
fn,
|
|
39
|
+
cleanup: null,
|
|
40
|
+
dependencies: new Set,
|
|
41
|
+
owner: Owner,
|
|
42
|
+
children: [],
|
|
43
|
+
disposed: false,
|
|
44
|
+
runCount: 0
|
|
45
|
+
};
|
|
46
|
+
if (Owner)
|
|
47
|
+
Owner.children.push(effect);
|
|
48
|
+
runEffect(effect);
|
|
49
|
+
}
|
|
50
|
+
function runEffect(effect) {
|
|
51
|
+
if (effect.disposed)
|
|
52
|
+
return;
|
|
53
|
+
effect.runCount++;
|
|
54
|
+
if (effect.runCount > MAX_EFFECT_RUNS) {
|
|
55
|
+
effect.runCount = 0;
|
|
56
|
+
throw new Error(`Circular dependency detected: effect re-entered itself ${MAX_EFFECT_RUNS} times.`);
|
|
57
|
+
}
|
|
58
|
+
if (effect.cleanup) {
|
|
59
|
+
effect.cleanup();
|
|
60
|
+
effect.cleanup = null;
|
|
61
|
+
}
|
|
62
|
+
for (const dep of effect.dependencies) {
|
|
63
|
+
dep.delete(effect);
|
|
64
|
+
}
|
|
65
|
+
effect.dependencies.clear();
|
|
66
|
+
const prevOwner = Owner;
|
|
67
|
+
const prevListener = Listener;
|
|
68
|
+
Owner = effect;
|
|
69
|
+
Listener = effect;
|
|
70
|
+
try {
|
|
71
|
+
const result = effect.fn();
|
|
72
|
+
if (typeof result === "function") {
|
|
73
|
+
effect.cleanup = result;
|
|
74
|
+
}
|
|
75
|
+
} finally {
|
|
76
|
+
Owner = prevOwner;
|
|
77
|
+
Listener = prevListener;
|
|
78
|
+
effect.runCount--;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function disposeSubtree(effect) {
|
|
82
|
+
if (effect.disposed)
|
|
83
|
+
return;
|
|
84
|
+
effect.disposed = true;
|
|
85
|
+
for (const child of effect.children) {
|
|
86
|
+
disposeSubtree(child);
|
|
87
|
+
}
|
|
88
|
+
effect.children.length = 0;
|
|
89
|
+
if (effect.cleanup) {
|
|
90
|
+
effect.cleanup();
|
|
91
|
+
effect.cleanup = null;
|
|
92
|
+
}
|
|
93
|
+
for (const dep of effect.dependencies) {
|
|
94
|
+
dep.delete(effect);
|
|
95
|
+
}
|
|
96
|
+
effect.dependencies.clear();
|
|
97
|
+
effect.owner = null;
|
|
98
|
+
}
|
|
99
|
+
function disposeEffect(effect) {
|
|
100
|
+
if (effect.disposed)
|
|
101
|
+
return;
|
|
102
|
+
if (effect.owner) {
|
|
103
|
+
const idx = effect.owner.children.indexOf(effect);
|
|
104
|
+
if (idx >= 0)
|
|
105
|
+
effect.owner.children.splice(idx, 1);
|
|
106
|
+
}
|
|
107
|
+
disposeSubtree(effect);
|
|
108
|
+
}
|
|
109
|
+
function createRoot(fn) {
|
|
110
|
+
const root = {
|
|
111
|
+
fn: () => {},
|
|
112
|
+
cleanup: null,
|
|
113
|
+
dependencies: new Set,
|
|
114
|
+
owner: Owner,
|
|
115
|
+
children: [],
|
|
116
|
+
disposed: false,
|
|
117
|
+
runCount: 0
|
|
118
|
+
};
|
|
119
|
+
if (Owner)
|
|
120
|
+
Owner.children.push(root);
|
|
121
|
+
const prevOwner = Owner;
|
|
122
|
+
const prevListener = Listener;
|
|
123
|
+
Owner = root;
|
|
124
|
+
Listener = null;
|
|
125
|
+
try {
|
|
126
|
+
return fn(() => disposeEffect(root));
|
|
127
|
+
} finally {
|
|
128
|
+
Owner = prevOwner;
|
|
129
|
+
Listener = prevListener;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function createDisposableEffect(fn) {
|
|
133
|
+
let disposed = false;
|
|
134
|
+
const effect = {
|
|
135
|
+
fn: () => {
|
|
136
|
+
if (disposed)
|
|
137
|
+
return;
|
|
138
|
+
return fn();
|
|
139
|
+
},
|
|
140
|
+
cleanup: null,
|
|
141
|
+
dependencies: new Set,
|
|
142
|
+
owner: Owner,
|
|
143
|
+
children: [],
|
|
144
|
+
disposed: false,
|
|
145
|
+
runCount: 0
|
|
146
|
+
};
|
|
147
|
+
if (Owner)
|
|
148
|
+
Owner.children.push(effect);
|
|
149
|
+
runEffect(effect);
|
|
150
|
+
return () => {
|
|
151
|
+
disposeEffect(effect);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function onCleanup(fn) {
|
|
155
|
+
if (Owner) {
|
|
156
|
+
const effect = Owner;
|
|
157
|
+
const prevCleanup = effect.cleanup;
|
|
158
|
+
effect.cleanup = () => {
|
|
159
|
+
if (prevCleanup)
|
|
160
|
+
prevCleanup();
|
|
161
|
+
fn();
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function untrack(fn) {
|
|
166
|
+
const prevListener = Listener;
|
|
167
|
+
Listener = null;
|
|
168
|
+
try {
|
|
169
|
+
return fn();
|
|
170
|
+
} finally {
|
|
171
|
+
Listener = prevListener;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function batch(fn) {
|
|
175
|
+
BatchDepth++;
|
|
176
|
+
try {
|
|
177
|
+
return fn();
|
|
178
|
+
} finally {
|
|
179
|
+
BatchDepth--;
|
|
180
|
+
if (BatchDepth === 0) {
|
|
181
|
+
flushEffects();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function flushEffects() {
|
|
186
|
+
while (PendingEffects.size > 0) {
|
|
187
|
+
const effects = [...PendingEffects];
|
|
188
|
+
PendingEffects.clear();
|
|
189
|
+
for (const effect of effects) {
|
|
190
|
+
runEffect(effect);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function onMount(fn) {
|
|
195
|
+
createEffect(() => untrack(fn));
|
|
196
|
+
}
|
|
197
|
+
function createMemo(fn) {
|
|
198
|
+
const [value, setValue] = createSignal(undefined);
|
|
199
|
+
createEffect(() => {
|
|
200
|
+
const result = fn();
|
|
201
|
+
setValue(() => result);
|
|
202
|
+
});
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
// src/split-props.ts
|
|
206
|
+
function splitProps(props, keys) {
|
|
207
|
+
const keySet = new Set(keys);
|
|
208
|
+
const local = new Proxy({}, {
|
|
209
|
+
get(_, key) {
|
|
210
|
+
if (keySet.has(key)) {
|
|
211
|
+
return props[key];
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
},
|
|
215
|
+
has(_, key) {
|
|
216
|
+
return keySet.has(key);
|
|
217
|
+
},
|
|
218
|
+
ownKeys() {
|
|
219
|
+
return [...keySet];
|
|
220
|
+
},
|
|
221
|
+
getOwnPropertyDescriptor(_, key) {
|
|
222
|
+
if (keySet.has(key)) {
|
|
223
|
+
return {
|
|
224
|
+
configurable: true,
|
|
225
|
+
enumerable: true,
|
|
226
|
+
get: () => props[key]
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const rest = new Proxy({}, {
|
|
233
|
+
get(_, key) {
|
|
234
|
+
if (!keySet.has(key)) {
|
|
235
|
+
return props[key];
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
},
|
|
239
|
+
has(_, key) {
|
|
240
|
+
return key in props && !keySet.has(key);
|
|
241
|
+
},
|
|
242
|
+
ownKeys() {
|
|
243
|
+
return Object.keys(props).filter((k) => !keySet.has(k));
|
|
244
|
+
},
|
|
245
|
+
getOwnPropertyDescriptor(_, key) {
|
|
246
|
+
if (key in props && !keySet.has(key)) {
|
|
247
|
+
return {
|
|
248
|
+
configurable: true,
|
|
249
|
+
enumerable: true,
|
|
250
|
+
get: () => props[key]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return [local, rest];
|
|
257
|
+
}
|
|
258
|
+
// src/slot.ts
|
|
259
|
+
function __slot(thunk) {
|
|
260
|
+
return {
|
|
261
|
+
__isSlot: true,
|
|
262
|
+
toString() {
|
|
263
|
+
const result = thunk();
|
|
264
|
+
return result == null ? "" : String(result);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// src/forward-props.ts
|
|
269
|
+
function forwardProps(source, overrides, excludeKeys) {
|
|
270
|
+
const result = {};
|
|
271
|
+
const exclude = new Set(excludeKeys);
|
|
272
|
+
const descs = Object.getOwnPropertyDescriptors(overrides);
|
|
273
|
+
for (const key of Object.keys(descs)) {
|
|
274
|
+
Object.defineProperty(result, key, { ...descs[key], enumerable: true, configurable: true });
|
|
275
|
+
}
|
|
276
|
+
for (const key of Object.keys(source)) {
|
|
277
|
+
if (exclude.has(key) || key in result)
|
|
278
|
+
continue;
|
|
279
|
+
const k = key;
|
|
280
|
+
Object.defineProperty(result, k, {
|
|
281
|
+
get: () => source[k],
|
|
282
|
+
enumerable: true,
|
|
283
|
+
configurable: true
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
// src/unwrap.ts
|
|
289
|
+
function unwrap(prop) {
|
|
290
|
+
return typeof prop === "function" ? prop() : prop;
|
|
291
|
+
}
|
|
292
|
+
// ../shared/src/markers.ts
|
|
293
|
+
var BF_SCOPE = "bf-s";
|
|
294
|
+
var BF_SLOT = "bf";
|
|
295
|
+
var BF_HOST = "bf-h";
|
|
296
|
+
var BF_AT = "bf-m";
|
|
297
|
+
var BF_PROPS = "bf-p";
|
|
298
|
+
var BF_COND = "bf-c";
|
|
299
|
+
var BF_PORTAL_OWNER = "bf-po";
|
|
300
|
+
var BF_PORTAL_ID = "bf-pi";
|
|
301
|
+
var BF_PORTAL_PLACEHOLDER = "bf-pp";
|
|
302
|
+
var BF_PARENT_OWNED_PREFIX = "^";
|
|
303
|
+
var BF_SCOPE_COMMENT_PREFIX = "bf-scope:";
|
|
304
|
+
var BF_LOOP_START = "bf-loop";
|
|
305
|
+
var BF_LOOP_END = "bf-/loop";
|
|
306
|
+
var BF_LOOP_ITEM = "bf-loop-i";
|
|
307
|
+
function loopStartMarker(markerId) {
|
|
308
|
+
return `${BF_LOOP_START}:${markerId}`;
|
|
309
|
+
}
|
|
310
|
+
function loopEndMarker(markerId) {
|
|
311
|
+
return `${BF_LOOP_END}:${markerId}`;
|
|
312
|
+
}
|
|
313
|
+
var BF_KEY = "data-key";
|
|
314
|
+
var BF_ASYNC = "bf-async";
|
|
315
|
+
var BF_ASYNC_RESOLVE = "bf-async-resolve";
|
|
316
|
+
var BF_PARENT_SCOPE_PLACEHOLDER = "__BF_PARENT_SCOPE__";
|
|
317
|
+
// src/context.ts
|
|
318
|
+
function createContext(defaultValue) {
|
|
319
|
+
return {
|
|
320
|
+
id: Symbol(),
|
|
321
|
+
defaultValue,
|
|
322
|
+
Provider: () => {
|
|
323
|
+
throw new Error("Context.Provider should be compiled away");
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/runtime/context.ts
|
|
329
|
+
var contextStore = new Map;
|
|
330
|
+
var CONTEXT_KEY = "__bfCtx";
|
|
331
|
+
var currentScope = null;
|
|
332
|
+
function setCurrentScope(scope) {
|
|
333
|
+
const prev = currentScope;
|
|
334
|
+
currentScope = scope;
|
|
335
|
+
return prev;
|
|
336
|
+
}
|
|
337
|
+
function useContext(context) {
|
|
338
|
+
if (currentScope) {
|
|
339
|
+
let el = currentScope;
|
|
340
|
+
while (el) {
|
|
341
|
+
const ctxMap = el[CONTEXT_KEY];
|
|
342
|
+
if (ctxMap?.has(context.id)) {
|
|
343
|
+
return ctxMap.get(context.id);
|
|
344
|
+
}
|
|
345
|
+
const portalOwnerId = el.getAttribute(BF_PORTAL_OWNER);
|
|
346
|
+
if (portalOwnerId) {
|
|
347
|
+
const ownerEl = document.querySelector(`[${BF_SCOPE}="${portalOwnerId}"]`);
|
|
348
|
+
if (ownerEl && ownerEl !== el) {
|
|
349
|
+
el = ownerEl;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
el = el.parentElement;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (contextStore.has(context.id)) {
|
|
357
|
+
return contextStore.get(context.id);
|
|
358
|
+
}
|
|
359
|
+
return context.defaultValue;
|
|
360
|
+
}
|
|
361
|
+
function provideContext(context, value) {
|
|
362
|
+
if (currentScope) {
|
|
363
|
+
let ctxMap = currentScope[CONTEXT_KEY];
|
|
364
|
+
if (!ctxMap) {
|
|
365
|
+
ctxMap = new Map;
|
|
366
|
+
currentScope[CONTEXT_KEY] = ctxMap;
|
|
367
|
+
}
|
|
368
|
+
ctxMap.set(context.id, value);
|
|
369
|
+
const childScopes = currentScope.querySelectorAll(`[${BF_SCOPE}]`);
|
|
370
|
+
for (const child of childScopes) {
|
|
371
|
+
let childCtxMap = child[CONTEXT_KEY];
|
|
372
|
+
if (!childCtxMap) {
|
|
373
|
+
childCtxMap = new Map;
|
|
374
|
+
child[CONTEXT_KEY] = childCtxMap;
|
|
375
|
+
}
|
|
376
|
+
if (!childCtxMap.has(context.id)) {
|
|
377
|
+
childCtxMap.set(context.id, value);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
contextStore.set(context.id, value);
|
|
382
|
+
}
|
|
383
|
+
// src/runtime/template.ts
|
|
384
|
+
var templateRegistry = new Map;
|
|
385
|
+
function registerTemplate(name, templateFn) {
|
|
386
|
+
templateRegistry.set(name, templateFn);
|
|
387
|
+
}
|
|
388
|
+
function getTemplate(name) {
|
|
389
|
+
return templateRegistry.get(name);
|
|
390
|
+
}
|
|
391
|
+
function hasTemplate(name) {
|
|
392
|
+
return templateRegistry.has(name);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/runtime/hydration-state.ts
|
|
396
|
+
var hydratedScopes = new WeakSet;
|
|
397
|
+
|
|
398
|
+
// src/runtime/scope.ts
|
|
399
|
+
var commentScopeRegistry = new WeakMap;
|
|
400
|
+
function getPortalScopeId(element) {
|
|
401
|
+
const info = commentScopeRegistry.get(element);
|
|
402
|
+
return info?.scopeId ?? null;
|
|
403
|
+
}
|
|
404
|
+
function getCommentScopeBoundary(commentNode) {
|
|
405
|
+
let node = commentNode.nextSibling;
|
|
406
|
+
while (node) {
|
|
407
|
+
if (node.nodeType === Node.COMMENT_NODE && node.nodeValue?.startsWith(BF_SCOPE_COMMENT_PREFIX)) {
|
|
408
|
+
return node;
|
|
409
|
+
}
|
|
410
|
+
node = node.nextSibling;
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// src/runtime/query.ts
|
|
416
|
+
var cssEscape = typeof CSS !== "undefined" && CSS.escape ? (s) => CSS.escape(s) : (s) => s.replace(/"/g, "\\\"");
|
|
417
|
+
function getScopeId(el) {
|
|
418
|
+
return el?.getAttribute(BF_SCOPE) ?? null;
|
|
419
|
+
}
|
|
420
|
+
var initializedComments = new WeakSet;
|
|
421
|
+
function parseCommentScopeId(value, prefix) {
|
|
422
|
+
if (!value.startsWith(prefix))
|
|
423
|
+
return null;
|
|
424
|
+
let id = value.slice(prefix.length);
|
|
425
|
+
const pipeIdx = id.indexOf("|");
|
|
426
|
+
if (pipeIdx >= 0)
|
|
427
|
+
id = id.slice(0, pipeIdx);
|
|
428
|
+
return id;
|
|
429
|
+
}
|
|
430
|
+
function nextElementSibling(node) {
|
|
431
|
+
let sibling = node.nextSibling;
|
|
432
|
+
while (sibling) {
|
|
433
|
+
if (sibling.nodeType === Node.ELEMENT_NODE)
|
|
434
|
+
return sibling;
|
|
435
|
+
sibling = sibling.nextSibling;
|
|
436
|
+
}
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
function findScope(name, idx, parent, comment) {
|
|
440
|
+
const parentEl = parent;
|
|
441
|
+
if (parentEl) {
|
|
442
|
+
const commentInfo = commentScopeRegistry.get(parentEl);
|
|
443
|
+
if (commentInfo && commentInfo.scopeId.startsWith(`${name}_`)) {
|
|
444
|
+
return parentEl;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const scopeId = getScopeId(parentEl);
|
|
448
|
+
if (scopeId) {
|
|
449
|
+
if (scopeId.startsWith(`${name}_`) || /_s\d/.test(scopeId) && parent !== document) {
|
|
450
|
+
hydratedScopes.add(parentEl);
|
|
451
|
+
return parent;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const searchRoot = parent || document;
|
|
455
|
+
const allScopes = Array.from(searchRoot.querySelectorAll(`[${BF_SCOPE}^="${name}_"]`));
|
|
456
|
+
const uninitializedScopes = allScopes.filter((s) => !hydratedScopes.has(s));
|
|
457
|
+
const scope = uninitializedScopes[idx] || null;
|
|
458
|
+
if (scope) {
|
|
459
|
+
hydratedScopes.add(scope);
|
|
460
|
+
return scope;
|
|
461
|
+
}
|
|
462
|
+
if (comment) {
|
|
463
|
+
return findScopeByComment(name, idx, searchRoot);
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
function findScopeByComment(name, idx, searchRoot) {
|
|
468
|
+
const prefix = BF_SCOPE_COMMENT_PREFIX;
|
|
469
|
+
const walker = document.createTreeWalker(searchRoot, NodeFilter.SHOW_COMMENT);
|
|
470
|
+
let matchIdx = 0;
|
|
471
|
+
while (walker.nextNode()) {
|
|
472
|
+
const comment = walker.currentNode;
|
|
473
|
+
const value = comment.nodeValue;
|
|
474
|
+
if (!value?.startsWith(prefix))
|
|
475
|
+
continue;
|
|
476
|
+
const scopeId = parseCommentScopeId(value, prefix);
|
|
477
|
+
if (!scopeId?.startsWith(`${name}_`))
|
|
478
|
+
continue;
|
|
479
|
+
if (initializedComments.has(comment))
|
|
480
|
+
continue;
|
|
481
|
+
if (matchIdx === idx) {
|
|
482
|
+
initializedComments.add(comment);
|
|
483
|
+
const proxyEl = nextElementSibling(comment) ?? comment.parentElement;
|
|
484
|
+
if (proxyEl) {
|
|
485
|
+
commentScopeRegistry.set(proxyEl, { commentNode: comment, scopeId });
|
|
486
|
+
}
|
|
487
|
+
return proxyEl;
|
|
488
|
+
}
|
|
489
|
+
matchIdx++;
|
|
490
|
+
}
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
function* candidatesInScope(scope, selector) {
|
|
494
|
+
const commentInfo = commentScopeRegistry.get(scope);
|
|
495
|
+
if (commentInfo) {
|
|
496
|
+
const boundary = getCommentScopeBoundary(commentInfo.commentNode);
|
|
497
|
+
let node = commentInfo.commentNode.nextSibling;
|
|
498
|
+
while (node && node !== boundary) {
|
|
499
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
500
|
+
const el = node;
|
|
501
|
+
if (el.matches?.(selector))
|
|
502
|
+
yield el;
|
|
503
|
+
yield* el.querySelectorAll(selector);
|
|
504
|
+
}
|
|
505
|
+
node = node.nextSibling;
|
|
506
|
+
}
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
yield* scope.querySelectorAll(selector);
|
|
510
|
+
const scopeId = scope.getAttribute(BF_SCOPE);
|
|
511
|
+
if (!scopeId)
|
|
512
|
+
return;
|
|
513
|
+
const parent = scope.parentElement;
|
|
514
|
+
if (!parent)
|
|
515
|
+
return;
|
|
516
|
+
const siblings = parent.querySelectorAll(`[${BF_SCOPE}="${scopeId}"]`);
|
|
517
|
+
for (const sibling of siblings) {
|
|
518
|
+
if (sibling === scope)
|
|
519
|
+
continue;
|
|
520
|
+
if (sibling.matches?.(selector))
|
|
521
|
+
yield sibling;
|
|
522
|
+
yield* sibling.querySelectorAll(selector);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function belongsToScope(element, scope) {
|
|
526
|
+
if (element.getAttribute(BF_SCOPE))
|
|
527
|
+
return false;
|
|
528
|
+
const nearestScope = element.closest(`[${BF_SCOPE}]`);
|
|
529
|
+
return nearestScope === scope;
|
|
530
|
+
}
|
|
531
|
+
function isInCommentScopeRange(element, commentNode) {
|
|
532
|
+
const boundary = getCommentScopeBoundary(commentNode);
|
|
533
|
+
let node = commentNode.nextSibling;
|
|
534
|
+
while (node && node !== boundary) {
|
|
535
|
+
if (node === element || node.nodeType === Node.ELEMENT_NODE && node.contains(element)) {
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
node = node.nextSibling;
|
|
539
|
+
}
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
function find(scope, selector, ignoreScope) {
|
|
543
|
+
if (!scope)
|
|
544
|
+
return null;
|
|
545
|
+
const commentInfo = commentScopeRegistry.get(scope);
|
|
546
|
+
if (!commentInfo && scope.matches?.(selector))
|
|
547
|
+
return scope;
|
|
548
|
+
for (const candidate of candidatesInScope(scope, selector)) {
|
|
549
|
+
if (ignoreScope)
|
|
550
|
+
return candidate;
|
|
551
|
+
if (commentInfo) {
|
|
552
|
+
if (candidate.parentElement === commentInfo.commentNode.parentElement)
|
|
553
|
+
return candidate;
|
|
554
|
+
if (!candidate.closest(`[${BF_SCOPE}]`))
|
|
555
|
+
return candidate;
|
|
556
|
+
} else {
|
|
557
|
+
if (belongsToScope(candidate, scope))
|
|
558
|
+
return candidate;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const scopeId = commentInfo?.scopeId ?? getScopeId(scope);
|
|
562
|
+
if (scopeId)
|
|
563
|
+
return findInPortals(scopeId, selector);
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
function findInPortals(scopeId, selector) {
|
|
567
|
+
const portals = document.querySelectorAll(`[${BF_PORTAL_OWNER}="${scopeId}"]`);
|
|
568
|
+
for (const portal of portals) {
|
|
569
|
+
if (portal.matches?.(selector))
|
|
570
|
+
return portal;
|
|
571
|
+
const matches = portal.querySelectorAll(selector);
|
|
572
|
+
for (const match of matches) {
|
|
573
|
+
const nearestScope = match.closest(`[${BF_SCOPE}]`);
|
|
574
|
+
if (!nearestScope) {
|
|
575
|
+
return match;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
function qsa(el, selector) {
|
|
582
|
+
if (!el)
|
|
583
|
+
return null;
|
|
584
|
+
if (selector.includes(",")) {
|
|
585
|
+
for (const clause of splitTopLevelCommas(selector)) {
|
|
586
|
+
const c = clause.trim();
|
|
587
|
+
if (!c)
|
|
588
|
+
continue;
|
|
589
|
+
const hit = qsa(el, c);
|
|
590
|
+
if (hit)
|
|
591
|
+
return hit;
|
|
592
|
+
}
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
if (SLOT_SUFFIX_SELECTOR.test(selector)) {
|
|
596
|
+
return qsaChildScope(el, selector);
|
|
597
|
+
}
|
|
598
|
+
if (el.matches(selector))
|
|
599
|
+
return el;
|
|
600
|
+
return el.querySelector(selector);
|
|
601
|
+
}
|
|
602
|
+
function splitTopLevelCommas(selector) {
|
|
603
|
+
const out = [];
|
|
604
|
+
let depth = 0;
|
|
605
|
+
let start = 0;
|
|
606
|
+
for (let i = 0;i < selector.length; i++) {
|
|
607
|
+
const ch = selector.charCodeAt(i);
|
|
608
|
+
if (ch === 91 || ch === 40)
|
|
609
|
+
depth++;
|
|
610
|
+
else if (ch === 93 || ch === 41)
|
|
611
|
+
depth--;
|
|
612
|
+
else if (ch === 44 && depth === 0) {
|
|
613
|
+
out.push(selector.slice(start, i));
|
|
614
|
+
start = i + 1;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
out.push(selector.slice(start));
|
|
618
|
+
return out;
|
|
619
|
+
}
|
|
620
|
+
var SLOT_SUFFIX_SELECTOR = /^\[bf-s\$="_s\d+"\]$/;
|
|
621
|
+
var NESTED_SLOT_SUFFIX = /_s\d+_s\d+$/;
|
|
622
|
+
function qsaChildScope(scope, selector) {
|
|
623
|
+
if (scope.matches(selector)) {
|
|
624
|
+
const bfs = scope.getAttribute(BF_SCOPE) || "";
|
|
625
|
+
if (!NESTED_SLOT_SUFFIX.test(bfs))
|
|
626
|
+
return scope;
|
|
627
|
+
}
|
|
628
|
+
for (const candidate of scope.querySelectorAll(selector)) {
|
|
629
|
+
const bfs = candidate.getAttribute(BF_SCOPE) || "";
|
|
630
|
+
if (!NESTED_SLOT_SUFFIX.test(bfs))
|
|
631
|
+
return candidate;
|
|
632
|
+
}
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
function qsaChildScopes(scope, selector) {
|
|
636
|
+
const out = [];
|
|
637
|
+
for (const candidate of scope.querySelectorAll(selector)) {
|
|
638
|
+
const bfs = candidate.getAttribute(BF_SCOPE) || "";
|
|
639
|
+
if (!NESTED_SLOT_SUFFIX.test(bfs))
|
|
640
|
+
out.push(candidate);
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
function $(scope, ...ids) {
|
|
645
|
+
return ids.map((id) => {
|
|
646
|
+
const ignoreScope = id.startsWith(BF_PARENT_OWNED_PREFIX);
|
|
647
|
+
return find(scope, `[${BF_SLOT}="${id}"]`, ignoreScope || undefined);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
function $c(scope, ...ids) {
|
|
651
|
+
return ids.map((id) => $cSingle(scope, id));
|
|
652
|
+
}
|
|
653
|
+
function $cSingle(scope, id) {
|
|
654
|
+
if (!scope)
|
|
655
|
+
return null;
|
|
656
|
+
const cleanId = id.startsWith(BF_PARENT_OWNED_PREFIX) ? id.slice(1) : id;
|
|
657
|
+
if (!/^s\d/.test(cleanId)) {
|
|
658
|
+
return findChildScope(scope, `[${BF_SCOPE}^="${cleanId}_"]`);
|
|
659
|
+
}
|
|
660
|
+
const parentScopeIds = getDualScopeIds(scope);
|
|
661
|
+
if (parentScopeIds.length > 0) {
|
|
662
|
+
for (const parentId of parentScopeIds) {
|
|
663
|
+
const result = findChildScope(scope, `[${BF_SCOPE}$="${parentId}_${cleanId}"]`);
|
|
664
|
+
if (result)
|
|
665
|
+
return result;
|
|
666
|
+
}
|
|
667
|
+
if (scope.matches?.(`[${BF_SCOPE}$="_${cleanId}"]`))
|
|
668
|
+
return scope;
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
return findChildScope(scope, `[${BF_SCOPE}$="_${cleanId}"]`);
|
|
672
|
+
}
|
|
673
|
+
function findChildScope(scope, selector) {
|
|
674
|
+
if (scope.matches?.(selector))
|
|
675
|
+
return scope;
|
|
676
|
+
for (const candidate of candidatesInScope(scope, selector)) {
|
|
677
|
+
return candidate;
|
|
678
|
+
}
|
|
679
|
+
const commentInfo = commentScopeRegistry.get(scope);
|
|
680
|
+
const scopeId = commentInfo?.scopeId ?? getScopeId(scope);
|
|
681
|
+
if (scopeId)
|
|
682
|
+
return findInPortals(scopeId, selector);
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
function getDualScopeIds(scope) {
|
|
686
|
+
if (!scope)
|
|
687
|
+
return [];
|
|
688
|
+
const bfScopeId = getScopeId(scope);
|
|
689
|
+
const commentInfo = commentScopeRegistry.get(scope);
|
|
690
|
+
const commentScopeId = commentInfo?.scopeId ?? null;
|
|
691
|
+
if (commentScopeId && bfScopeId && commentScopeId !== bfScopeId) {
|
|
692
|
+
return [commentScopeId, bfScopeId];
|
|
693
|
+
}
|
|
694
|
+
const id = commentScopeId ?? bfScopeId;
|
|
695
|
+
return id ? [id] : [];
|
|
696
|
+
}
|
|
697
|
+
function $t(scope, ...ids) {
|
|
698
|
+
const results = new Array(ids.length).fill(null);
|
|
699
|
+
if (!scope)
|
|
700
|
+
return results;
|
|
701
|
+
const commentInfo = commentScopeRegistry.get(scope);
|
|
702
|
+
const searchRoot = commentInfo ? commentInfo.commentNode.parentNode ?? scope : scope;
|
|
703
|
+
const isComponentScope = scope.hasAttribute(BF_SCOPE) || commentInfo != null;
|
|
704
|
+
const markerMap = new Map;
|
|
705
|
+
for (let i = 0;i < ids.length; i++) {
|
|
706
|
+
markerMap.set(`bf:${ids[i]}`, {
|
|
707
|
+
index: i,
|
|
708
|
+
isParentOwned: ids[i].startsWith(BF_PARENT_OWNED_PREFIX)
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
let remaining = ids.length;
|
|
712
|
+
const walker = document.createTreeWalker(searchRoot, NodeFilter.SHOW_COMMENT);
|
|
713
|
+
while (walker.nextNode() && remaining > 0) {
|
|
714
|
+
const comment = walker.currentNode;
|
|
715
|
+
const entry = markerMap.get(comment.nodeValue ?? "");
|
|
716
|
+
if (!entry || results[entry.index] !== null)
|
|
717
|
+
continue;
|
|
718
|
+
if (isComponentScope && !entry.isParentOwned && !commentBelongsToScope(comment, scope, commentInfo)) {
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
results[entry.index] = textNodeAfterComment(comment);
|
|
722
|
+
remaining--;
|
|
723
|
+
}
|
|
724
|
+
return results;
|
|
725
|
+
}
|
|
726
|
+
function textNodeAfterComment(comment) {
|
|
727
|
+
const next = comment.nextSibling;
|
|
728
|
+
if (next?.nodeType === Node.TEXT_NODE) {
|
|
729
|
+
return next;
|
|
730
|
+
}
|
|
731
|
+
const textNode = document.createTextNode("");
|
|
732
|
+
comment.parentNode?.insertBefore(textNode, comment.nextSibling);
|
|
733
|
+
return textNode;
|
|
734
|
+
}
|
|
735
|
+
function commentBelongsToScope(comment, scope, commentInfo) {
|
|
736
|
+
const parent = comment.parentElement;
|
|
737
|
+
if (!parent)
|
|
738
|
+
return false;
|
|
739
|
+
const parentScope = parent.closest(`[${BF_SCOPE}]`);
|
|
740
|
+
if (parentScope === scope)
|
|
741
|
+
return true;
|
|
742
|
+
if (commentInfo) {
|
|
743
|
+
return isInCommentScopeRange(parent, commentInfo.commentNode);
|
|
744
|
+
}
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/runtime/slot-resolver.ts
|
|
749
|
+
function parentScopeOf(parent, anchorScope) {
|
|
750
|
+
const ancestor = anchorScope ?? parent.closest(`[${BF_SCOPE}]`);
|
|
751
|
+
if (!ancestor)
|
|
752
|
+
return "";
|
|
753
|
+
return ancestor.getAttribute(BF_SCOPE) ?? "";
|
|
754
|
+
}
|
|
755
|
+
function buildSlotInfo(parent, slotId, anchorScope) {
|
|
756
|
+
return { parent: parentScopeOf(parent, anchorScope), mount: slotId };
|
|
757
|
+
}
|
|
758
|
+
function findSsrScopeBySlotIn(parent, slotId, anchorScope, selfMatch) {
|
|
759
|
+
const parentBfs = parentScopeOf(parent, anchorScope);
|
|
760
|
+
if (parentBfs) {
|
|
761
|
+
const selector = `[${BF_HOST}="${cssEscape(parentBfs)}"][${BF_AT}="${slotId}"]`;
|
|
762
|
+
if (selfMatch && parent.matches(selector))
|
|
763
|
+
return parent;
|
|
764
|
+
const direct = parent.querySelector(selector);
|
|
765
|
+
if (direct)
|
|
766
|
+
return direct;
|
|
767
|
+
}
|
|
768
|
+
const suffixSelector = `[${BF_SCOPE}$="_${slotId}"]`;
|
|
769
|
+
if (selfMatch && parent.matches(suffixSelector))
|
|
770
|
+
return parent;
|
|
771
|
+
return parent.querySelector(suffixSelector);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// src/runtime/registry.ts
|
|
775
|
+
var componentRegistry = new Map;
|
|
776
|
+
var pendingChildInits = new Map;
|
|
777
|
+
function registerComponent(name, init) {
|
|
778
|
+
componentRegistry.set(name, init);
|
|
779
|
+
const pending = pendingChildInits.get(name);
|
|
780
|
+
if (pending) {
|
|
781
|
+
pendingChildInits.delete(name);
|
|
782
|
+
for (const { scope, props } of pending) {
|
|
783
|
+
initChild(name, scope, props);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
function getComponentInit(name) {
|
|
788
|
+
return componentRegistry.get(name);
|
|
789
|
+
}
|
|
790
|
+
function initChild(name, childScope, props = {}) {
|
|
791
|
+
if (!childScope)
|
|
792
|
+
return;
|
|
793
|
+
const init = componentRegistry.get(name);
|
|
794
|
+
if (!init) {
|
|
795
|
+
if (!pendingChildInits.has(name)) {
|
|
796
|
+
pendingChildInits.set(name, []);
|
|
797
|
+
}
|
|
798
|
+
pendingChildInits.get(name).push({ scope: childScope, props });
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
if (hydratedScopes.has(childScope) && childScope.hasAttribute(BF_HOST)) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const prevScope = setCurrentScope(childScope);
|
|
805
|
+
try {
|
|
806
|
+
init(childScope, props);
|
|
807
|
+
} finally {
|
|
808
|
+
setCurrentScope(prevScope);
|
|
809
|
+
}
|
|
810
|
+
hydratedScopes.add(childScope);
|
|
811
|
+
}
|
|
812
|
+
function upsertChild(parent, name, slotId, props, key, anchorScope) {
|
|
813
|
+
let ssr = null;
|
|
814
|
+
if (slotId) {
|
|
815
|
+
ssr = findSsrScopeBySlotIn(parent, slotId, anchorScope, false);
|
|
816
|
+
} else {
|
|
817
|
+
ssr = parent.querySelector(`[${BF_SCOPE}^="${name}_"]`);
|
|
818
|
+
}
|
|
819
|
+
if (ssr) {
|
|
820
|
+
initChild(name, ssr, props);
|
|
821
|
+
return ssr;
|
|
822
|
+
}
|
|
823
|
+
const phId = slotId ?? name;
|
|
824
|
+
const ph = parent.querySelector(`[data-bf-ph="${phId}"]`);
|
|
825
|
+
if (ph) {
|
|
826
|
+
const slot = slotId ? buildSlotInfo(parent, slotId, anchorScope) : undefined;
|
|
827
|
+
const comp = createComponent(name, props, key, slot);
|
|
828
|
+
ph.replaceWith(comp);
|
|
829
|
+
return comp;
|
|
830
|
+
}
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/runtime/hydrate.ts
|
|
835
|
+
var registeredDefs = new Map;
|
|
836
|
+
function getRegisteredDef(name) {
|
|
837
|
+
return registeredDefs.get(name);
|
|
838
|
+
}
|
|
839
|
+
var microtaskScheduled = false;
|
|
840
|
+
var rafScheduled = false;
|
|
841
|
+
var scheduleMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (cb) => {
|
|
842
|
+
Promise.resolve().then(cb);
|
|
843
|
+
};
|
|
844
|
+
function scheduleWalk() {
|
|
845
|
+
if (!microtaskScheduled) {
|
|
846
|
+
microtaskScheduled = true;
|
|
847
|
+
scheduleMicrotask(() => {
|
|
848
|
+
if (!microtaskScheduled)
|
|
849
|
+
return;
|
|
850
|
+
microtaskScheduled = false;
|
|
851
|
+
walkAllInDocumentOrder();
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
if (!rafScheduled && typeof requestAnimationFrame === "function") {
|
|
855
|
+
rafScheduled = true;
|
|
856
|
+
requestAnimationFrame(() => {
|
|
857
|
+
if (!rafScheduled)
|
|
858
|
+
return;
|
|
859
|
+
rafScheduled = false;
|
|
860
|
+
walkAllInDocumentOrder();
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function hydrate(name, def) {
|
|
865
|
+
def.name = name;
|
|
866
|
+
registeredDefs.set(name, def);
|
|
867
|
+
registerComponent(name, def.init);
|
|
868
|
+
if (def.template) {
|
|
869
|
+
registerTemplate(name, def.template);
|
|
870
|
+
}
|
|
871
|
+
scheduleWalk();
|
|
872
|
+
}
|
|
873
|
+
function rehydrateAll() {
|
|
874
|
+
scheduleWalk();
|
|
875
|
+
}
|
|
876
|
+
function flushHydration() {
|
|
877
|
+
if (!microtaskScheduled && !rafScheduled)
|
|
878
|
+
return;
|
|
879
|
+
microtaskScheduled = false;
|
|
880
|
+
rafScheduled = false;
|
|
881
|
+
walkAllInDocumentOrder();
|
|
882
|
+
}
|
|
883
|
+
function walkAllInDocumentOrder() {
|
|
884
|
+
if (typeof document === "undefined")
|
|
885
|
+
return;
|
|
886
|
+
const walker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
|
|
887
|
+
while (walker.nextNode()) {
|
|
888
|
+
const node = walker.currentNode;
|
|
889
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
890
|
+
hydrateElementScope(node);
|
|
891
|
+
} else if (node.nodeType === Node.COMMENT_NODE) {
|
|
892
|
+
hydrateCommentScope(node);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function scopeName(id) {
|
|
897
|
+
const idx = id.indexOf("_");
|
|
898
|
+
return idx < 0 ? null : id.slice(0, idx);
|
|
899
|
+
}
|
|
900
|
+
function parseProps(json, where) {
|
|
901
|
+
if (!json)
|
|
902
|
+
return {};
|
|
903
|
+
try {
|
|
904
|
+
return JSON.parse(json);
|
|
905
|
+
} catch {
|
|
906
|
+
console.warn(`[BarefootJS] Invalid props JSON on ${where}:`, json);
|
|
907
|
+
return {};
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function runInit(scope, def, props) {
|
|
911
|
+
const prevScope = setCurrentScope(scope);
|
|
912
|
+
try {
|
|
913
|
+
def.init(scope, props);
|
|
914
|
+
} finally {
|
|
915
|
+
setCurrentScope(prevScope);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function hydrateElementScope(el) {
|
|
919
|
+
if (hydratedScopes.has(el))
|
|
920
|
+
return;
|
|
921
|
+
const bfs = el.getAttribute(BF_SCOPE);
|
|
922
|
+
if (!bfs)
|
|
923
|
+
return;
|
|
924
|
+
if (el.hasAttribute(BF_HOST))
|
|
925
|
+
return;
|
|
926
|
+
const name = scopeName(bfs);
|
|
927
|
+
if (!name)
|
|
928
|
+
return;
|
|
929
|
+
const def = registeredDefs.get(name);
|
|
930
|
+
if (!def)
|
|
931
|
+
return;
|
|
932
|
+
hydratedScopes.add(el);
|
|
933
|
+
if (def.comment)
|
|
934
|
+
return;
|
|
935
|
+
runInit(el, def, parseProps(el.getAttribute(BF_PROPS), bfs));
|
|
936
|
+
}
|
|
937
|
+
function hydrateCommentScope(comment) {
|
|
938
|
+
const value = comment.nodeValue;
|
|
939
|
+
if (!value?.startsWith(BF_SCOPE_COMMENT_PREFIX))
|
|
940
|
+
return;
|
|
941
|
+
const rest = value.slice(BF_SCOPE_COMMENT_PREFIX.length);
|
|
942
|
+
if (rest.includes("|h="))
|
|
943
|
+
return;
|
|
944
|
+
const flagged = comment;
|
|
945
|
+
if (flagged.__bfInitialized)
|
|
946
|
+
return;
|
|
947
|
+
const pipeIdx = rest.indexOf("|");
|
|
948
|
+
const scopeId = pipeIdx >= 0 ? rest.slice(0, pipeIdx) : rest;
|
|
949
|
+
const propsJson = pipeIdx >= 0 ? rest.slice(pipeIdx + 1) : "";
|
|
950
|
+
const name = scopeName(scopeId);
|
|
951
|
+
if (!name)
|
|
952
|
+
return;
|
|
953
|
+
const def = registeredDefs.get(name);
|
|
954
|
+
if (!def?.comment)
|
|
955
|
+
return;
|
|
956
|
+
flagged.__bfInitialized = true;
|
|
957
|
+
const proxyEl = nextElementSibling2(comment) ?? comment.parentElement;
|
|
958
|
+
if (!proxyEl)
|
|
959
|
+
return;
|
|
960
|
+
commentScopeRegistry.set(proxyEl, { commentNode: comment, scopeId });
|
|
961
|
+
const parsed = parseProps(propsJson || null, `comment scope ${scopeId}`);
|
|
962
|
+
const props = parsed[name] ?? {};
|
|
963
|
+
runInit(proxyEl, def, props);
|
|
964
|
+
}
|
|
965
|
+
function nextElementSibling2(node) {
|
|
966
|
+
let sibling = node.nextSibling;
|
|
967
|
+
while (sibling) {
|
|
968
|
+
if (sibling.nodeType === Node.ELEMENT_NODE)
|
|
969
|
+
return sibling;
|
|
970
|
+
sibling = sibling.nextSibling;
|
|
971
|
+
}
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// src/runtime/component.ts
|
|
976
|
+
var _parentScopeId = null;
|
|
977
|
+
function setParentScopeId(id) {
|
|
978
|
+
_parentScopeId = id;
|
|
979
|
+
}
|
|
980
|
+
var propsUpdateMap = new WeakMap;
|
|
981
|
+
var propsMap = new WeakMap;
|
|
982
|
+
function createComponent(nameOrDef, props, key, slot) {
|
|
983
|
+
if (typeof nameOrDef !== "string") {
|
|
984
|
+
return createComponentFromDef(nameOrDef, props, key);
|
|
985
|
+
}
|
|
986
|
+
const name = nameOrDef;
|
|
987
|
+
const templateFn = getTemplate(name);
|
|
988
|
+
if (!templateFn) {
|
|
989
|
+
console.warn(`[BarefootJS] Template not found for component: ${name}`);
|
|
990
|
+
return createPlaceholder(name, key);
|
|
991
|
+
}
|
|
992
|
+
const childrenDescriptor = Object.getOwnPropertyDescriptor(props, "children");
|
|
993
|
+
const childrenIsGetter = childrenDescriptor != null && typeof childrenDescriptor.get === "function";
|
|
994
|
+
const unwrappedProps = untrack(() => {
|
|
995
|
+
const result = {};
|
|
996
|
+
for (const k of Object.keys(props)) {
|
|
997
|
+
if (k === "children" && childrenIsGetter) {
|
|
998
|
+
result.children = "";
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
const descriptor = Object.getOwnPropertyDescriptor(props, k);
|
|
1002
|
+
if (descriptor && typeof descriptor.get === "function") {
|
|
1003
|
+
result[k] = descriptor.get();
|
|
1004
|
+
} else {
|
|
1005
|
+
result[k] = props[k];
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
if (Array.isArray(result.children) && !hasDomElements(result.children)) {
|
|
1009
|
+
result.children = result.children.flat().map((c) => c == null ? "" : String(c)).join("");
|
|
1010
|
+
}
|
|
1011
|
+
return result;
|
|
1012
|
+
});
|
|
1013
|
+
const prevParentScopeId = _parentScopeId;
|
|
1014
|
+
if (slot?.parent) {
|
|
1015
|
+
_parentScopeId = slot.parent;
|
|
1016
|
+
}
|
|
1017
|
+
let html;
|
|
1018
|
+
try {
|
|
1019
|
+
html = templateFn(unwrappedProps);
|
|
1020
|
+
} finally {
|
|
1021
|
+
_parentScopeId = prevParentScopeId;
|
|
1022
|
+
}
|
|
1023
|
+
const element = parseHTML(html.trim()).firstChild;
|
|
1024
|
+
if (!element) {
|
|
1025
|
+
console.warn(`[BarefootJS] Template returned empty HTML for component: ${name}`);
|
|
1026
|
+
return createPlaceholder(name, key);
|
|
1027
|
+
}
|
|
1028
|
+
const def = getRegisteredDef(name);
|
|
1029
|
+
const isCommentWrapper = def?.comment === true;
|
|
1030
|
+
if (!isCommentWrapper) {
|
|
1031
|
+
element.setAttribute(BF_SCOPE, `${name}_${generateId()}`);
|
|
1032
|
+
}
|
|
1033
|
+
if (slot) {
|
|
1034
|
+
if (slot.parent)
|
|
1035
|
+
element.setAttribute(BF_HOST, slot.parent);
|
|
1036
|
+
element.setAttribute(BF_AT, slot.mount);
|
|
1037
|
+
}
|
|
1038
|
+
if (key !== undefined) {
|
|
1039
|
+
element.setAttribute(BF_KEY, String(key));
|
|
1040
|
+
}
|
|
1041
|
+
const prevScope = setCurrentScope(element);
|
|
1042
|
+
const initFn = getComponentInit(name);
|
|
1043
|
+
if (initFn) {
|
|
1044
|
+
initFn(element, props);
|
|
1045
|
+
}
|
|
1046
|
+
if (childrenIsGetter) {
|
|
1047
|
+
const children = untrack(() => childrenDescriptor.get());
|
|
1048
|
+
if (children != null) {
|
|
1049
|
+
insertGetterChildren(element, children);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
setCurrentScope(prevScope);
|
|
1053
|
+
hydratedScopes.add(element);
|
|
1054
|
+
propsMap.set(element, props);
|
|
1055
|
+
registerPropsUpdate(element, name, props);
|
|
1056
|
+
return element;
|
|
1057
|
+
}
|
|
1058
|
+
function getComponentProps(element) {
|
|
1059
|
+
return propsMap.get(element);
|
|
1060
|
+
}
|
|
1061
|
+
function registerPropsUpdate(element, name, _initialProps) {
|
|
1062
|
+
propsUpdateMap.set(element, (newProps) => {
|
|
1063
|
+
const init = getComponentInit(name);
|
|
1064
|
+
if (init) {
|
|
1065
|
+
init(element, newProps);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
function getPropsUpdateFn(element) {
|
|
1070
|
+
return propsUpdateMap.get(element);
|
|
1071
|
+
}
|
|
1072
|
+
function renderChild(name, props, key, slotSuffix) {
|
|
1073
|
+
const templateFn = getTemplate(name);
|
|
1074
|
+
const suffix = slotSuffix ? `_${slotSuffix}` : "";
|
|
1075
|
+
const scopePrefix = _parentScopeId && slotSuffix ? _parentScopeId : `${name}_${generateId()}`;
|
|
1076
|
+
const keyAttr = key !== undefined ? ` ${BF_KEY}="${key}"` : "";
|
|
1077
|
+
const slotAttrs = _parentScopeId && slotSuffix ? ` ${BF_HOST}="${_parentScopeId}" ${BF_AT}="${slotSuffix}"` : "";
|
|
1078
|
+
const bfsAttr = `${BF_SCOPE}="${scopePrefix}${suffix}"`;
|
|
1079
|
+
if (!templateFn) {
|
|
1080
|
+
return `<div ${bfsAttr}${slotAttrs}${keyAttr}></div>`;
|
|
1081
|
+
}
|
|
1082
|
+
let html = templateFn(props).trim().replace(PLACEHOLDER_ATTR_PATTERN, _parentScopeId ? ` bf-s="${_parentScopeId}"` : "");
|
|
1083
|
+
const firstElMatch = html.match(/<(\w+)/);
|
|
1084
|
+
if (!firstElMatch)
|
|
1085
|
+
return html;
|
|
1086
|
+
const insertPos = firstElMatch.index;
|
|
1087
|
+
const afterInsert = html.slice(insertPos);
|
|
1088
|
+
const extraAttrs = `${slotAttrs}${keyAttr}`;
|
|
1089
|
+
if (ROOT_HAS_BFS_PATTERN.test(afterInsert)) {
|
|
1090
|
+
if (!extraAttrs)
|
|
1091
|
+
return html;
|
|
1092
|
+
return html.slice(0, insertPos) + afterInsert.replace(/^(<\w+)/, `$1${extraAttrs}`);
|
|
1093
|
+
}
|
|
1094
|
+
return html.slice(0, insertPos) + afterInsert.replace(/^(<\w+)/, `$1 ${bfsAttr}${extraAttrs}`);
|
|
1095
|
+
}
|
|
1096
|
+
var PLACEHOLDER_ATTR_PATTERN = new RegExp(`\\s+bf-s="${BF_PARENT_SCOPE_PLACEHOLDER}"`, "g");
|
|
1097
|
+
var ROOT_HAS_BFS_PATTERN = /^<\w+[^>]*\sbf-s="/;
|
|
1098
|
+
function generateId() {
|
|
1099
|
+
return Math.random().toString(36).slice(2, 8);
|
|
1100
|
+
}
|
|
1101
|
+
function createPlaceholder(name, key) {
|
|
1102
|
+
const el = document.createElement("div");
|
|
1103
|
+
el.setAttribute(BF_SCOPE, `${name}_placeholder`);
|
|
1104
|
+
if (key !== undefined) {
|
|
1105
|
+
el.setAttribute(BF_KEY, String(key));
|
|
1106
|
+
}
|
|
1107
|
+
el.textContent = `[${name}]`;
|
|
1108
|
+
el.style.cssText = "color: red; border: 1px dashed red; padding: 4px;";
|
|
1109
|
+
return el;
|
|
1110
|
+
}
|
|
1111
|
+
function unwrapPropsForTemplate(props) {
|
|
1112
|
+
const result = {};
|
|
1113
|
+
for (const key of Object.keys(props)) {
|
|
1114
|
+
const descriptor = Object.getOwnPropertyDescriptor(props, key);
|
|
1115
|
+
if (descriptor && typeof descriptor.get === "function") {
|
|
1116
|
+
result[key] = descriptor.get();
|
|
1117
|
+
} else {
|
|
1118
|
+
result[key] = props[key];
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (Array.isArray(result.children) && !hasDomElements(result.children)) {
|
|
1122
|
+
result.children = result.children.flat().map((c) => c == null ? "" : String(c)).join("");
|
|
1123
|
+
}
|
|
1124
|
+
return result;
|
|
1125
|
+
}
|
|
1126
|
+
function escapeAttrGt(html) {
|
|
1127
|
+
return html.replace(/"[^"]*"/g, (match) => match.replace(/>/g, ">"));
|
|
1128
|
+
}
|
|
1129
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1130
|
+
function parseHTML(html, parent) {
|
|
1131
|
+
const tpl = document.createElement("template");
|
|
1132
|
+
const escaped = escapeAttrGt(html);
|
|
1133
|
+
if (parent && parent.namespaceURI === SVG_NS) {
|
|
1134
|
+
tpl.innerHTML = `<svg>${escaped}</svg>`;
|
|
1135
|
+
const wrapper = tpl.content.firstElementChild;
|
|
1136
|
+
const frag = document.createDocumentFragment();
|
|
1137
|
+
if (wrapper) {
|
|
1138
|
+
while (wrapper.firstChild)
|
|
1139
|
+
frag.appendChild(wrapper.firstChild);
|
|
1140
|
+
}
|
|
1141
|
+
return frag;
|
|
1142
|
+
}
|
|
1143
|
+
tpl.innerHTML = escaped;
|
|
1144
|
+
return tpl.content;
|
|
1145
|
+
}
|
|
1146
|
+
function hasDomElements(value) {
|
|
1147
|
+
if (value instanceof Element)
|
|
1148
|
+
return true;
|
|
1149
|
+
if (Array.isArray(value))
|
|
1150
|
+
return value.some(hasDomElements);
|
|
1151
|
+
return false;
|
|
1152
|
+
}
|
|
1153
|
+
function insertGetterChildren(element, children) {
|
|
1154
|
+
if (children instanceof Element) {
|
|
1155
|
+
element.appendChild(children);
|
|
1156
|
+
} else if (Array.isArray(children)) {
|
|
1157
|
+
for (const child of children.flat()) {
|
|
1158
|
+
if (child instanceof Element) {
|
|
1159
|
+
element.appendChild(child);
|
|
1160
|
+
} else if (typeof child === "string" && child.length > 0) {
|
|
1161
|
+
element.appendChild(parseHTML(child.trim()));
|
|
1162
|
+
} else if (typeof child === "number") {
|
|
1163
|
+
element.appendChild(document.createTextNode(String(child)));
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
} else if (typeof children === "string" && children.length > 0) {
|
|
1167
|
+
element.appendChild(parseHTML(children.trim()));
|
|
1168
|
+
} else if (typeof children === "number") {
|
|
1169
|
+
element.appendChild(document.createTextNode(String(children)));
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
function createComponentFromDef(def, props, key) {
|
|
1173
|
+
if (!def.template) {
|
|
1174
|
+
throw new Error("[BarefootJS] createComponent with ComponentDef requires a template function");
|
|
1175
|
+
}
|
|
1176
|
+
const unwrappedProps = unwrapPropsForTemplate(props);
|
|
1177
|
+
const html = def.template(unwrappedProps);
|
|
1178
|
+
const element = parseHTML(html.trim()).firstChild;
|
|
1179
|
+
if (!element) {
|
|
1180
|
+
const el = document.createElement("div");
|
|
1181
|
+
el.textContent = "[ComponentDef]";
|
|
1182
|
+
el.style.cssText = "color: red; border: 1px dashed red; padding: 4px;";
|
|
1183
|
+
return el;
|
|
1184
|
+
}
|
|
1185
|
+
const name = def.name || def.init.name?.replace(/^init/, "") || "Component";
|
|
1186
|
+
const scopeId = `${name}_${generateId()}`;
|
|
1187
|
+
element.setAttribute(BF_SCOPE, scopeId);
|
|
1188
|
+
if (key !== undefined) {
|
|
1189
|
+
element.setAttribute(BF_KEY, String(key));
|
|
1190
|
+
}
|
|
1191
|
+
def.init(element, props);
|
|
1192
|
+
hydratedScopes.add(element);
|
|
1193
|
+
propsMap.set(element, props);
|
|
1194
|
+
return element;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// src/runtime/portal.ts
|
|
1198
|
+
function isSSRPortal(element) {
|
|
1199
|
+
return element.closest(`[${BF_PORTAL_ID}]`) !== null;
|
|
1200
|
+
}
|
|
1201
|
+
function findSiblingSlot(el, slotSelector) {
|
|
1202
|
+
const direct = el.parentElement?.querySelector(slotSelector);
|
|
1203
|
+
if (direct)
|
|
1204
|
+
return direct;
|
|
1205
|
+
const portalWrapper = el.closest(`[${BF_PORTAL_ID}]`);
|
|
1206
|
+
if (!portalWrapper)
|
|
1207
|
+
return null;
|
|
1208
|
+
const ownerScopeId = portalWrapper.getAttribute(BF_PORTAL_OWNER);
|
|
1209
|
+
if (!ownerScopeId)
|
|
1210
|
+
return null;
|
|
1211
|
+
const ownerScope = document.querySelector(`[${BF_SCOPE}="${ownerScopeId}"]`);
|
|
1212
|
+
if (!ownerScope)
|
|
1213
|
+
return null;
|
|
1214
|
+
return ownerScope.querySelector(slotSelector);
|
|
1215
|
+
}
|
|
1216
|
+
function cleanupPortalPlaceholder(portalId) {
|
|
1217
|
+
const placeholder = document.querySelector(`template[${BF_PORTAL_PLACEHOLDER}="${portalId}"]`);
|
|
1218
|
+
placeholder?.remove();
|
|
1219
|
+
}
|
|
1220
|
+
function createPortal(children, container = document.body, options) {
|
|
1221
|
+
let element;
|
|
1222
|
+
if (children instanceof HTMLElement) {
|
|
1223
|
+
element = children;
|
|
1224
|
+
} else {
|
|
1225
|
+
const html = typeof children === "string" ? children : children.toString();
|
|
1226
|
+
const parsed = parseHTML(html).firstElementChild;
|
|
1227
|
+
if (!parsed) {
|
|
1228
|
+
throw new Error("createPortal: Invalid HTML provided");
|
|
1229
|
+
}
|
|
1230
|
+
element = parsed;
|
|
1231
|
+
}
|
|
1232
|
+
if (options?.ownerScope) {
|
|
1233
|
+
let scopeId = options.ownerScope.getAttribute?.(BF_SCOPE) ?? null;
|
|
1234
|
+
if (!scopeId) {
|
|
1235
|
+
scopeId = getPortalScopeId(options.ownerScope) ?? null;
|
|
1236
|
+
}
|
|
1237
|
+
if (scopeId) {
|
|
1238
|
+
element.setAttribute(BF_PORTAL_OWNER, scopeId);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
container.appendChild(element);
|
|
1242
|
+
return {
|
|
1243
|
+
element,
|
|
1244
|
+
unmount() {
|
|
1245
|
+
if (element.parentNode) {
|
|
1246
|
+
element.parentNode.removeChild(element);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
// src/runtime/reconcile-elements.ts
|
|
1252
|
+
function findLoopMarkers(container, markerId) {
|
|
1253
|
+
let startMarker = null;
|
|
1254
|
+
let endMarker = null;
|
|
1255
|
+
if (markerId) {
|
|
1256
|
+
const startVal = loopStartMarker(markerId);
|
|
1257
|
+
const endVal = loopEndMarker(markerId);
|
|
1258
|
+
for (const node of Array.from(container.childNodes)) {
|
|
1259
|
+
if (node.nodeType !== Node.COMMENT_NODE)
|
|
1260
|
+
continue;
|
|
1261
|
+
const value = node.nodeValue;
|
|
1262
|
+
if (value === startVal)
|
|
1263
|
+
startMarker = node;
|
|
1264
|
+
else if (value === endVal)
|
|
1265
|
+
endMarker = node;
|
|
1266
|
+
}
|
|
1267
|
+
} else {
|
|
1268
|
+
const startPrefix = `${BF_LOOP_START}:`;
|
|
1269
|
+
const endPrefix = `${BF_LOOP_END}:`;
|
|
1270
|
+
for (const node of Array.from(container.childNodes)) {
|
|
1271
|
+
if (node.nodeType !== Node.COMMENT_NODE)
|
|
1272
|
+
continue;
|
|
1273
|
+
const value = node.nodeValue ?? "";
|
|
1274
|
+
if (!startMarker && (value === BF_LOOP_START || value.startsWith(startPrefix))) {
|
|
1275
|
+
startMarker = node;
|
|
1276
|
+
} else if (!endMarker && (value === BF_LOOP_END || value.startsWith(endPrefix))) {
|
|
1277
|
+
endMarker = node;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
if (startMarker && endMarker)
|
|
1282
|
+
return { startMarker, endMarker };
|
|
1283
|
+
return { startMarker: null, endMarker: null };
|
|
1284
|
+
}
|
|
1285
|
+
function getElementsBetweenMarkers(start, end) {
|
|
1286
|
+
const elements = [];
|
|
1287
|
+
let node = start.nextSibling;
|
|
1288
|
+
while (node && node !== end) {
|
|
1289
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
1290
|
+
elements.push(node);
|
|
1291
|
+
}
|
|
1292
|
+
node = node.nextSibling;
|
|
1293
|
+
}
|
|
1294
|
+
return elements;
|
|
1295
|
+
}
|
|
1296
|
+
function removeElementsBetweenMarkers(start, end) {
|
|
1297
|
+
let node = start.nextSibling;
|
|
1298
|
+
while (node && node !== end) {
|
|
1299
|
+
const next = node.nextSibling;
|
|
1300
|
+
node.parentNode?.removeChild(node);
|
|
1301
|
+
node = next;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
function getLoopChildren(container, markerId) {
|
|
1305
|
+
const { startMarker, endMarker } = findLoopMarkers(container, markerId);
|
|
1306
|
+
if (startMarker && endMarker) {
|
|
1307
|
+
return getElementsBetweenMarkers(startMarker, endMarker);
|
|
1308
|
+
}
|
|
1309
|
+
return Array.from(container.children);
|
|
1310
|
+
}
|
|
1311
|
+
function getLoopNodes(container, markerId) {
|
|
1312
|
+
const { startMarker, endMarker } = findLoopMarkers(container, markerId);
|
|
1313
|
+
const nodes = [];
|
|
1314
|
+
if (startMarker && endMarker) {
|
|
1315
|
+
let node = startMarker.nextSibling;
|
|
1316
|
+
while (node && node !== endMarker) {
|
|
1317
|
+
nodes.push(node);
|
|
1318
|
+
node = node.nextSibling;
|
|
1319
|
+
}
|
|
1320
|
+
return nodes;
|
|
1321
|
+
}
|
|
1322
|
+
return Array.from(container.childNodes);
|
|
1323
|
+
}
|
|
1324
|
+
function reconcileElements(container, items, getKey, renderItem, firstElement, markerId) {
|
|
1325
|
+
if (!container || !items)
|
|
1326
|
+
return;
|
|
1327
|
+
const { startMarker, endMarker } = findLoopMarkers(container, markerId);
|
|
1328
|
+
const existingByKey = new Map;
|
|
1329
|
+
let hasKeyedChildren = false;
|
|
1330
|
+
const loopChildren = startMarker ? getElementsBetweenMarkers(startMarker, endMarker) : Array.from(container.children);
|
|
1331
|
+
for (const child of loopChildren) {
|
|
1332
|
+
const el = child;
|
|
1333
|
+
const key = el.dataset?.key;
|
|
1334
|
+
if (key !== undefined) {
|
|
1335
|
+
existingByKey.set(key, el);
|
|
1336
|
+
hasKeyedChildren = true;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (!hasKeyedChildren) {
|
|
1340
|
+
if (items.length === 0) {
|
|
1341
|
+
if (startMarker) {
|
|
1342
|
+
removeElementsBetweenMarkers(startMarker, endMarker);
|
|
1343
|
+
} else {
|
|
1344
|
+
container.innerHTML = "";
|
|
1345
|
+
}
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const fragment = document.createDocumentFragment();
|
|
1349
|
+
for (let i = 0;i < items.length; i++) {
|
|
1350
|
+
const el = i === 0 && firstElement ? firstElement : renderItem(items[i], i);
|
|
1351
|
+
const key = getKey ? getKey(items[i], i) : String(i);
|
|
1352
|
+
if (!el.dataset.key)
|
|
1353
|
+
el.setAttribute(BF_KEY, key);
|
|
1354
|
+
fragment.appendChild(el);
|
|
1355
|
+
}
|
|
1356
|
+
if (startMarker) {
|
|
1357
|
+
removeElementsBetweenMarkers(startMarker, endMarker);
|
|
1358
|
+
endMarker.parentNode.insertBefore(fragment, endMarker);
|
|
1359
|
+
} else {
|
|
1360
|
+
container.innerHTML = "";
|
|
1361
|
+
container.appendChild(fragment);
|
|
1362
|
+
}
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
let insertAnchor = endMarker ?? null;
|
|
1366
|
+
if (!startMarker) {
|
|
1367
|
+
let foundKeyed = false;
|
|
1368
|
+
for (const child of Array.from(container.childNodes)) {
|
|
1369
|
+
if (child.nodeType === Node.ELEMENT_NODE && child.dataset.key !== undefined) {
|
|
1370
|
+
foundKeyed = true;
|
|
1371
|
+
} else if (foundKeyed) {
|
|
1372
|
+
insertAnchor = child;
|
|
1373
|
+
break;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
let focusedKey = null;
|
|
1378
|
+
const activeEl = document.activeElement;
|
|
1379
|
+
if (activeEl && activeEl !== document.body) {
|
|
1380
|
+
const tag = activeEl.tagName;
|
|
1381
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || activeEl.isContentEditable) {
|
|
1382
|
+
for (const [key, el] of existingByKey) {
|
|
1383
|
+
if (el.contains(activeEl)) {
|
|
1384
|
+
focusedKey = key;
|
|
1385
|
+
break;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
const desiredElements = [];
|
|
1391
|
+
const toRemove = [];
|
|
1392
|
+
let focusTarget = null;
|
|
1393
|
+
for (let i = 0;i < items.length; i++) {
|
|
1394
|
+
const item = items[i];
|
|
1395
|
+
const key = getKey ? getKey(item, i) : String(i);
|
|
1396
|
+
const createEl = () => i === 0 && firstElement ? firstElement : renderItem(item, i);
|
|
1397
|
+
const existing = existingByKey.get(key);
|
|
1398
|
+
if (existing) {
|
|
1399
|
+
existingByKey.delete(key);
|
|
1400
|
+
if (existing.getAttribute(BF_SCOPE) && !hydratedScopes.has(existing)) {
|
|
1401
|
+
const newEl = createEl();
|
|
1402
|
+
if (!newEl.dataset.key)
|
|
1403
|
+
newEl.setAttribute(BF_KEY, key);
|
|
1404
|
+
desiredElements.push(newEl);
|
|
1405
|
+
toRemove.push(existing);
|
|
1406
|
+
} else if (focusedKey === key) {
|
|
1407
|
+
const newEl = createEl();
|
|
1408
|
+
if (!newEl.dataset.key)
|
|
1409
|
+
newEl.setAttribute(BF_KEY, key);
|
|
1410
|
+
focusTarget = prepareInputTransfer(existing, newEl);
|
|
1411
|
+
desiredElements.push(newEl);
|
|
1412
|
+
toRemove.push(existing);
|
|
1413
|
+
} else {
|
|
1414
|
+
const newEl = createEl();
|
|
1415
|
+
if (!newEl.dataset.key)
|
|
1416
|
+
newEl.setAttribute(BF_KEY, key);
|
|
1417
|
+
desiredElements.push(newEl);
|
|
1418
|
+
toRemove.push(existing);
|
|
1419
|
+
}
|
|
1420
|
+
} else {
|
|
1421
|
+
const el = createEl();
|
|
1422
|
+
if (!el.dataset.key)
|
|
1423
|
+
el.setAttribute(BF_KEY, key);
|
|
1424
|
+
desiredElements.push(el);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
for (const el of existingByKey.values()) {
|
|
1428
|
+
toRemove.push(el);
|
|
1429
|
+
}
|
|
1430
|
+
for (const el of toRemove) {
|
|
1431
|
+
if (el.parentNode)
|
|
1432
|
+
el.remove();
|
|
1433
|
+
}
|
|
1434
|
+
for (const el of desiredElements) {
|
|
1435
|
+
container.insertBefore(el, insertAnchor);
|
|
1436
|
+
}
|
|
1437
|
+
if (focusTarget) {
|
|
1438
|
+
focusTarget.target.focus();
|
|
1439
|
+
if (typeof focusTarget.selectionStart === "number") {
|
|
1440
|
+
focusTarget.target.selectionStart = focusTarget.selectionStart;
|
|
1441
|
+
focusTarget.target.selectionEnd = focusTarget.selectionEnd;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
function prepareInputTransfer(oldEl, newEl) {
|
|
1446
|
+
const focused = oldEl.contains(document.activeElement) ? document.activeElement : null;
|
|
1447
|
+
if (!focused)
|
|
1448
|
+
return null;
|
|
1449
|
+
const tag = focused.tagName;
|
|
1450
|
+
const oldInputs = Array.from(oldEl.querySelectorAll(tag));
|
|
1451
|
+
const idx = oldInputs.indexOf(focused);
|
|
1452
|
+
if (idx < 0)
|
|
1453
|
+
return null;
|
|
1454
|
+
const newInputs = Array.from(newEl.querySelectorAll(tag));
|
|
1455
|
+
const target = newInputs[idx];
|
|
1456
|
+
if (!target)
|
|
1457
|
+
return null;
|
|
1458
|
+
target.value = focused.value;
|
|
1459
|
+
return {
|
|
1460
|
+
target,
|
|
1461
|
+
selectionStart: focused.selectionStart,
|
|
1462
|
+
selectionEnd: focused.selectionEnd
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// src/runtime/list.ts
|
|
1467
|
+
function reconcileList(container, items, getKey, renderItem) {
|
|
1468
|
+
if (!container || !items)
|
|
1469
|
+
return;
|
|
1470
|
+
if (items.length === 0) {
|
|
1471
|
+
container.innerHTML = "";
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
const firstElement = renderItem(items[0], 0);
|
|
1475
|
+
reconcileElements(container, items, getKey, renderItem, firstElement);
|
|
1476
|
+
}
|
|
1477
|
+
// src/runtime/qsa-item.ts
|
|
1478
|
+
function* itemRootElements(primaryEl) {
|
|
1479
|
+
yield primaryEl;
|
|
1480
|
+
const startPrefix = `${BF_LOOP_START}:`;
|
|
1481
|
+
const endPrefix = `${BF_LOOP_END}:`;
|
|
1482
|
+
let n = primaryEl.nextSibling;
|
|
1483
|
+
while (n) {
|
|
1484
|
+
if (n.nodeType === Node.COMMENT_NODE) {
|
|
1485
|
+
const v = n.nodeValue ?? "";
|
|
1486
|
+
if (v === BF_LOOP_ITEM || v === BF_LOOP_START || v.startsWith(startPrefix) || v === BF_LOOP_END || v.startsWith(endPrefix)) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
} else if (n.nodeType === Node.ELEMENT_NODE) {
|
|
1490
|
+
yield n;
|
|
1491
|
+
}
|
|
1492
|
+
n = n.nextSibling;
|
|
1493
|
+
}
|
|
1494
|
+
const stashed = primaryEl.__bfExtras;
|
|
1495
|
+
if (stashed) {
|
|
1496
|
+
for (const ex of stashed)
|
|
1497
|
+
yield ex;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
function qsaItem(primaryEl, selector) {
|
|
1501
|
+
if (!primaryEl)
|
|
1502
|
+
return null;
|
|
1503
|
+
for (const root of itemRootElements(primaryEl)) {
|
|
1504
|
+
if (root.matches(selector))
|
|
1505
|
+
return root;
|
|
1506
|
+
const inner = root.querySelector(selector);
|
|
1507
|
+
if (inner)
|
|
1508
|
+
return inner;
|
|
1509
|
+
}
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
function upsertChildItem(primaryEl, name, slotId, props, key, anchorScope) {
|
|
1513
|
+
let ssr = null;
|
|
1514
|
+
if (slotId) {
|
|
1515
|
+
for (const root of itemRootElements(primaryEl)) {
|
|
1516
|
+
const found = findSsrScopeBySlotIn(root, slotId, anchorScope, true);
|
|
1517
|
+
if (found) {
|
|
1518
|
+
ssr = found;
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
} else {
|
|
1523
|
+
ssr = qsaItem(primaryEl, `[bf-s^="${name}_"]`);
|
|
1524
|
+
}
|
|
1525
|
+
if (ssr) {
|
|
1526
|
+
initChild(name, ssr, props);
|
|
1527
|
+
return ssr;
|
|
1528
|
+
}
|
|
1529
|
+
const phId = slotId ?? name;
|
|
1530
|
+
const ph = qsaItem(primaryEl, `[data-bf-ph="${phId}"]`);
|
|
1531
|
+
if (ph) {
|
|
1532
|
+
const slot = slotId ? buildSlotInfo(primaryEl, slotId, anchorScope) : undefined;
|
|
1533
|
+
const comp = createComponent(name, props, key, slot);
|
|
1534
|
+
ph.replaceWith(comp);
|
|
1535
|
+
return comp;
|
|
1536
|
+
}
|
|
1537
|
+
return null;
|
|
1538
|
+
}
|
|
1539
|
+
// src/runtime/map-array.ts
|
|
1540
|
+
function findLoopMarkers2(container, markerId) {
|
|
1541
|
+
let start = null;
|
|
1542
|
+
let end = null;
|
|
1543
|
+
if (markerId) {
|
|
1544
|
+
const startVal = loopStartMarker(markerId);
|
|
1545
|
+
const endVal = loopEndMarker(markerId);
|
|
1546
|
+
for (const node of Array.from(container.childNodes)) {
|
|
1547
|
+
if (node.nodeType !== Node.COMMENT_NODE)
|
|
1548
|
+
continue;
|
|
1549
|
+
const value = node.nodeValue;
|
|
1550
|
+
if (value === startVal)
|
|
1551
|
+
start = node;
|
|
1552
|
+
else if (value === endVal)
|
|
1553
|
+
end = node;
|
|
1554
|
+
}
|
|
1555
|
+
} else {
|
|
1556
|
+
const startPrefix = `${BF_LOOP_START}:`;
|
|
1557
|
+
const endPrefix = `${BF_LOOP_END}:`;
|
|
1558
|
+
for (const node of Array.from(container.childNodes)) {
|
|
1559
|
+
if (node.nodeType !== Node.COMMENT_NODE)
|
|
1560
|
+
continue;
|
|
1561
|
+
const value = node.nodeValue ?? "";
|
|
1562
|
+
if (!start && (value === BF_LOOP_START || value.startsWith(startPrefix))) {
|
|
1563
|
+
start = node;
|
|
1564
|
+
} else if (!end && (value === BF_LOOP_END || value.startsWith(endPrefix))) {
|
|
1565
|
+
end = node;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
if (start && end)
|
|
1570
|
+
return { start, end };
|
|
1571
|
+
return { start: null, end: null };
|
|
1572
|
+
}
|
|
1573
|
+
function findItemRanges(start, end) {
|
|
1574
|
+
const ranges = [];
|
|
1575
|
+
let current = null;
|
|
1576
|
+
let sawItemMarker = false;
|
|
1577
|
+
let node = start.nextSibling;
|
|
1578
|
+
while (node && node !== end) {
|
|
1579
|
+
if (node.nodeType === Node.COMMENT_NODE && node.nodeValue === BF_LOOP_ITEM) {
|
|
1580
|
+
sawItemMarker = true;
|
|
1581
|
+
current = { startMarker: node, primaryEl: null, extras: [] };
|
|
1582
|
+
ranges.push(current);
|
|
1583
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
1584
|
+
const el = node;
|
|
1585
|
+
if (sawItemMarker) {
|
|
1586
|
+
if (!current.primaryEl)
|
|
1587
|
+
current.primaryEl = el;
|
|
1588
|
+
else
|
|
1589
|
+
current.extras.push(el);
|
|
1590
|
+
} else {
|
|
1591
|
+
ranges.push({ startMarker: null, primaryEl: el, extras: [] });
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
node = node.nextSibling;
|
|
1595
|
+
}
|
|
1596
|
+
return ranges.filter((r) => r.primaryEl !== null);
|
|
1597
|
+
}
|
|
1598
|
+
function insertScope(scope, container, anchor) {
|
|
1599
|
+
if (scope.startMarker)
|
|
1600
|
+
container.insertBefore(scope.startMarker, anchor);
|
|
1601
|
+
container.insertBefore(scope.primaryEl, anchor);
|
|
1602
|
+
for (const ex of scope.extras)
|
|
1603
|
+
container.insertBefore(ex, anchor);
|
|
1604
|
+
}
|
|
1605
|
+
function removeScope(scope) {
|
|
1606
|
+
if (scope.startMarker?.parentNode)
|
|
1607
|
+
scope.startMarker.remove();
|
|
1608
|
+
if (scope.primaryEl.parentNode)
|
|
1609
|
+
scope.primaryEl.remove();
|
|
1610
|
+
for (const ex of scope.extras) {
|
|
1611
|
+
if (ex.parentNode)
|
|
1612
|
+
ex.remove();
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
function createItemScope(item, index, renderItem, existingPrimary, existingExtras, existingStart) {
|
|
1616
|
+
let primaryEl;
|
|
1617
|
+
let dispose;
|
|
1618
|
+
let setItem;
|
|
1619
|
+
let extras = [];
|
|
1620
|
+
let startMarker = null;
|
|
1621
|
+
createRoot((d) => {
|
|
1622
|
+
dispose = d;
|
|
1623
|
+
const [itemAccessor, itemSetter] = createSignal(item);
|
|
1624
|
+
setItem = itemSetter;
|
|
1625
|
+
primaryEl = renderItem(itemAccessor, index, existingPrimary);
|
|
1626
|
+
if (existingPrimary) {
|
|
1627
|
+
extras = existingExtras ?? [];
|
|
1628
|
+
startMarker = existingStart ?? null;
|
|
1629
|
+
} else {
|
|
1630
|
+
const stashed = primaryEl.__bfExtras;
|
|
1631
|
+
if (stashed && stashed.length > 0) {
|
|
1632
|
+
extras = stashed;
|
|
1633
|
+
startMarker = document.createComment(BF_LOOP_ITEM);
|
|
1634
|
+
}
|
|
1635
|
+
delete primaryEl.__bfExtras;
|
|
1636
|
+
}
|
|
1637
|
+
return;
|
|
1638
|
+
});
|
|
1639
|
+
return { startMarker, primaryEl, extras, dispose, setItem };
|
|
1640
|
+
}
|
|
1641
|
+
function mapArray(accessor, container, getKey, renderItem, markerId) {
|
|
1642
|
+
if (!container)
|
|
1643
|
+
return;
|
|
1644
|
+
const scopes = new Map;
|
|
1645
|
+
let hydrated = false;
|
|
1646
|
+
createEffect(() => {
|
|
1647
|
+
const items = accessor();
|
|
1648
|
+
if (!items)
|
|
1649
|
+
return;
|
|
1650
|
+
const { start: startMarker, end: endMarker } = findLoopMarkers2(container, markerId);
|
|
1651
|
+
const anchor = endMarker ?? null;
|
|
1652
|
+
if (!hydrated) {
|
|
1653
|
+
hydrated = true;
|
|
1654
|
+
const existingRanges = startMarker ? findItemRanges(startMarker, endMarker) : Array.from(container.children).map((el) => ({ startMarker: null, primaryEl: el, extras: [] }));
|
|
1655
|
+
const needsHydration = existingRanges.length > 0 && (!existingRanges[0]?.primaryEl.hasAttribute("data-key") || scopes.size === 0);
|
|
1656
|
+
if (needsHydration) {
|
|
1657
|
+
for (let i = 0;i < existingRanges.length && i < items.length; i++) {
|
|
1658
|
+
const range = existingRanges[i];
|
|
1659
|
+
const item = items[i];
|
|
1660
|
+
const key = getKey ? getKey(item, i) : String(i);
|
|
1661
|
+
range.primaryEl.setAttribute(BF_KEY, key);
|
|
1662
|
+
const scope = createItemScope(item, i, renderItem, range.primaryEl, range.extras, range.startMarker);
|
|
1663
|
+
scopes.set(key, scope);
|
|
1664
|
+
hydratedScopes.add(range.primaryEl);
|
|
1665
|
+
}
|
|
1666
|
+
for (let i = existingRanges.length;i < items.length; i++) {
|
|
1667
|
+
const item = items[i];
|
|
1668
|
+
const key = getKey ? getKey(item, i) : String(i);
|
|
1669
|
+
const scope = createItemScope(item, i, renderItem);
|
|
1670
|
+
if (!scope.primaryEl.dataset.key)
|
|
1671
|
+
scope.primaryEl.setAttribute(BF_KEY, key);
|
|
1672
|
+
scopes.set(key, scope);
|
|
1673
|
+
insertScope(scope, container, anchor);
|
|
1674
|
+
}
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
if (scopes.size === 0) {
|
|
1679
|
+
const loopRanges = startMarker ? findItemRanges(startMarker, endMarker) : Array.from(container.children).map((el) => ({ startMarker: null, primaryEl: el, extras: [] }));
|
|
1680
|
+
for (const range of loopRanges) {
|
|
1681
|
+
const existingKey = range.primaryEl.dataset?.key;
|
|
1682
|
+
if (existingKey && !scopes.has(existingKey)) {
|
|
1683
|
+
scopes.set(existingKey, {
|
|
1684
|
+
startMarker: range.startMarker,
|
|
1685
|
+
primaryEl: range.primaryEl,
|
|
1686
|
+
extras: range.extras,
|
|
1687
|
+
dispose: () => {},
|
|
1688
|
+
setItem: () => {}
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
const newKeys = new Set;
|
|
1694
|
+
const warnedKeys = new Set;
|
|
1695
|
+
const desiredOrder = [];
|
|
1696
|
+
for (let i = 0;i < items.length; i++) {
|
|
1697
|
+
const item = items[i];
|
|
1698
|
+
const key = getKey ? getKey(item, i) : String(i);
|
|
1699
|
+
if (newKeys.has(key) && !warnedKeys.has(key)) {
|
|
1700
|
+
warnedKeys.add(key);
|
|
1701
|
+
console.warn(`[BarefootJS] mapArray: duplicate key "${key}" — items with this key collapse to a single DOM scope, ` + `so only the last one renders. Use a per-item identifier (e.g. \`key={item.id}\`) for correct reconciliation.`);
|
|
1702
|
+
}
|
|
1703
|
+
newKeys.add(key);
|
|
1704
|
+
const existing = scopes.get(key);
|
|
1705
|
+
if (existing) {
|
|
1706
|
+
existing.setItem(item);
|
|
1707
|
+
desiredOrder.push(existing);
|
|
1708
|
+
} else {
|
|
1709
|
+
const scope = createItemScope(item, i, renderItem);
|
|
1710
|
+
if (!scope.primaryEl.dataset.key)
|
|
1711
|
+
scope.primaryEl.setAttribute(BF_KEY, key);
|
|
1712
|
+
scopes.set(key, scope);
|
|
1713
|
+
desiredOrder.push(scope);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
for (const [key, scope] of scopes) {
|
|
1717
|
+
if (!newKeys.has(key)) {
|
|
1718
|
+
scope.dispose();
|
|
1719
|
+
removeScope(scope);
|
|
1720
|
+
scopes.delete(key);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
let inOrder = true;
|
|
1724
|
+
let checkNode = startMarker ? startMarker.nextSibling : container.firstChild;
|
|
1725
|
+
for (const scope of desiredOrder) {
|
|
1726
|
+
while (checkNode && checkNode.nodeType !== Node.ELEMENT_NODE)
|
|
1727
|
+
checkNode = checkNode.nextSibling;
|
|
1728
|
+
if (checkNode !== scope.primaryEl) {
|
|
1729
|
+
inOrder = false;
|
|
1730
|
+
break;
|
|
1731
|
+
}
|
|
1732
|
+
checkNode = checkNode.nextSibling;
|
|
1733
|
+
for (let i = 0;i < scope.extras.length; i++) {
|
|
1734
|
+
while (checkNode && checkNode.nodeType !== Node.ELEMENT_NODE)
|
|
1735
|
+
checkNode = checkNode.nextSibling;
|
|
1736
|
+
if (checkNode !== scope.extras[i]) {
|
|
1737
|
+
inOrder = false;
|
|
1738
|
+
break;
|
|
1739
|
+
}
|
|
1740
|
+
checkNode = checkNode.nextSibling;
|
|
1741
|
+
}
|
|
1742
|
+
if (!inOrder)
|
|
1743
|
+
break;
|
|
1744
|
+
}
|
|
1745
|
+
if (!inOrder) {
|
|
1746
|
+
for (const scope of desiredOrder) {
|
|
1747
|
+
insertScope(scope, container, anchor);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
// src/runtime/style.ts
|
|
1753
|
+
function styleToCss(value) {
|
|
1754
|
+
if (value == null)
|
|
1755
|
+
return null;
|
|
1756
|
+
if (typeof value !== "object")
|
|
1757
|
+
return String(value);
|
|
1758
|
+
const parts = [];
|
|
1759
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1760
|
+
if (v == null)
|
|
1761
|
+
continue;
|
|
1762
|
+
const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
1763
|
+
parts.push(`${prop}:${v}`);
|
|
1764
|
+
}
|
|
1765
|
+
return parts.join(";") || null;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
// src/runtime/apply-rest-attrs.ts
|
|
1769
|
+
function toAttrName(key) {
|
|
1770
|
+
if (key === "className")
|
|
1771
|
+
return "class";
|
|
1772
|
+
if (key === "htmlFor")
|
|
1773
|
+
return "for";
|
|
1774
|
+
return key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
1775
|
+
}
|
|
1776
|
+
var jsxToDomEventMap = { doubleclick: "dblclick" };
|
|
1777
|
+
function toEventName(jsxPropName) {
|
|
1778
|
+
const raw = (jsxPropName[2].toLowerCase() + jsxPropName.slice(3)).toLowerCase();
|
|
1779
|
+
return jsxToDomEventMap[raw] ?? raw;
|
|
1780
|
+
}
|
|
1781
|
+
function applyRestAttrs(el, source, excludeKeys) {
|
|
1782
|
+
const exclude = new Set(excludeKeys);
|
|
1783
|
+
for (const key of Object.keys(source)) {
|
|
1784
|
+
if (exclude.has(key))
|
|
1785
|
+
continue;
|
|
1786
|
+
if (key === "ref") {
|
|
1787
|
+
const ref = source[key];
|
|
1788
|
+
if (typeof ref === "function")
|
|
1789
|
+
ref(el);
|
|
1790
|
+
continue;
|
|
1791
|
+
}
|
|
1792
|
+
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase()) {
|
|
1793
|
+
const handler = source[key];
|
|
1794
|
+
if (typeof handler === "function") {
|
|
1795
|
+
el.addEventListener(toEventName(key), handler);
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
createEffect(() => {
|
|
1800
|
+
for (const key of Object.keys(source)) {
|
|
1801
|
+
if (exclude.has(key))
|
|
1802
|
+
continue;
|
|
1803
|
+
if (key === "ref")
|
|
1804
|
+
continue;
|
|
1805
|
+
if (key === "children")
|
|
1806
|
+
continue;
|
|
1807
|
+
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
|
|
1808
|
+
continue;
|
|
1809
|
+
const value = source[key];
|
|
1810
|
+
const attr = toAttrName(key);
|
|
1811
|
+
if (value != null && value !== false) {
|
|
1812
|
+
if (attr === "value" && "value" in el) {
|
|
1813
|
+
const strVal = String(value);
|
|
1814
|
+
if (el.value !== strVal)
|
|
1815
|
+
el.value = strVal;
|
|
1816
|
+
} else if (attr === "checked" && "checked" in el) {
|
|
1817
|
+
el.checked = !!value;
|
|
1818
|
+
} else if (attr === "style") {
|
|
1819
|
+
const css = styleToCss(value);
|
|
1820
|
+
if (css == null)
|
|
1821
|
+
el.removeAttribute("style");
|
|
1822
|
+
else
|
|
1823
|
+
el.setAttribute("style", css);
|
|
1824
|
+
} else {
|
|
1825
|
+
el.setAttribute(attr, String(value));
|
|
1826
|
+
}
|
|
1827
|
+
} else {
|
|
1828
|
+
if (attr === "checked" && "checked" in el) {
|
|
1829
|
+
el.checked = false;
|
|
1830
|
+
} else {
|
|
1831
|
+
el.removeAttribute(attr);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
// src/runtime/spread-attrs.ts
|
|
1838
|
+
var SVG_CAMEL_CASE_ATTRS = new Set([
|
|
1839
|
+
"allowReorder",
|
|
1840
|
+
"attributeName",
|
|
1841
|
+
"attributeType",
|
|
1842
|
+
"autoReverse",
|
|
1843
|
+
"baseFrequency",
|
|
1844
|
+
"baseProfile",
|
|
1845
|
+
"calcMode",
|
|
1846
|
+
"clipPathUnits",
|
|
1847
|
+
"contentScriptType",
|
|
1848
|
+
"contentStyleType",
|
|
1849
|
+
"diffuseConstant",
|
|
1850
|
+
"edgeMode",
|
|
1851
|
+
"externalResourcesRequired",
|
|
1852
|
+
"filterRes",
|
|
1853
|
+
"filterUnits",
|
|
1854
|
+
"glyphRef",
|
|
1855
|
+
"gradientTransform",
|
|
1856
|
+
"gradientUnits",
|
|
1857
|
+
"kernelMatrix",
|
|
1858
|
+
"kernelUnitLength",
|
|
1859
|
+
"keyPoints",
|
|
1860
|
+
"keySplines",
|
|
1861
|
+
"keyTimes",
|
|
1862
|
+
"lengthAdjust",
|
|
1863
|
+
"limitingConeAngle",
|
|
1864
|
+
"markerHeight",
|
|
1865
|
+
"markerUnits",
|
|
1866
|
+
"markerWidth",
|
|
1867
|
+
"maskContentUnits",
|
|
1868
|
+
"maskUnits",
|
|
1869
|
+
"numOctaves",
|
|
1870
|
+
"pathLength",
|
|
1871
|
+
"patternContentUnits",
|
|
1872
|
+
"patternTransform",
|
|
1873
|
+
"patternUnits",
|
|
1874
|
+
"pointsAtX",
|
|
1875
|
+
"pointsAtY",
|
|
1876
|
+
"pointsAtZ",
|
|
1877
|
+
"preserveAlpha",
|
|
1878
|
+
"preserveAspectRatio",
|
|
1879
|
+
"primitiveUnits",
|
|
1880
|
+
"refX",
|
|
1881
|
+
"refY",
|
|
1882
|
+
"repeatCount",
|
|
1883
|
+
"repeatDur",
|
|
1884
|
+
"requiredExtensions",
|
|
1885
|
+
"requiredFeatures",
|
|
1886
|
+
"specularConstant",
|
|
1887
|
+
"specularExponent",
|
|
1888
|
+
"spreadMethod",
|
|
1889
|
+
"startOffset",
|
|
1890
|
+
"stdDeviation",
|
|
1891
|
+
"stitchTiles",
|
|
1892
|
+
"surfaceScale",
|
|
1893
|
+
"systemLanguage",
|
|
1894
|
+
"tableValues",
|
|
1895
|
+
"targetX",
|
|
1896
|
+
"targetY",
|
|
1897
|
+
"textLength",
|
|
1898
|
+
"viewBox",
|
|
1899
|
+
"viewTarget",
|
|
1900
|
+
"xChannelSelector",
|
|
1901
|
+
"yChannelSelector",
|
|
1902
|
+
"zoomAndPan"
|
|
1903
|
+
]);
|
|
1904
|
+
function spreadAttrs(obj) {
|
|
1905
|
+
if (!obj || typeof obj !== "object")
|
|
1906
|
+
return "";
|
|
1907
|
+
const parts = [];
|
|
1908
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1909
|
+
if (value == null || value === false)
|
|
1910
|
+
continue;
|
|
1911
|
+
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
|
|
1912
|
+
continue;
|
|
1913
|
+
if (key === "children")
|
|
1914
|
+
continue;
|
|
1915
|
+
if (key === "style") {
|
|
1916
|
+
const css = styleToCss(value);
|
|
1917
|
+
if (css != null)
|
|
1918
|
+
parts.push(`style="${css}"`);
|
|
1919
|
+
continue;
|
|
1920
|
+
}
|
|
1921
|
+
const attr = key === "className" ? "class" : key === "htmlFor" ? "for" : SVG_CAMEL_CASE_ATTRS.has(key) ? key : key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
1922
|
+
parts.push(value === true ? attr : `${attr}="${value}"`);
|
|
1923
|
+
}
|
|
1924
|
+
return parts.join(" ");
|
|
1925
|
+
}
|
|
1926
|
+
// src/runtime/insert.ts
|
|
1927
|
+
var EMPTY_SLOTS = [];
|
|
1928
|
+
function normalizeTemplate(value) {
|
|
1929
|
+
return typeof value === "string" ? { html: value, slots: EMPTY_SLOTS } : value;
|
|
1930
|
+
}
|
|
1931
|
+
function evalBranchTemplate(branch) {
|
|
1932
|
+
return untrack(() => normalizeTemplate(branch.template()));
|
|
1933
|
+
}
|
|
1934
|
+
function insert(scope, id, conditionFn, whenTrue, whenFalse) {
|
|
1935
|
+
if (!scope)
|
|
1936
|
+
return;
|
|
1937
|
+
const parentScopeId = scope.getAttribute(BF_SCOPE);
|
|
1938
|
+
let isFragmentCond = false;
|
|
1939
|
+
try {
|
|
1940
|
+
const sampleTrue = evalBranchTemplate(whenTrue);
|
|
1941
|
+
isFragmentCond = sampleTrue.html.includes(`<!--bf-cond-start:${id}-->`);
|
|
1942
|
+
} catch (err) {
|
|
1943
|
+
if (!(err instanceof TypeError))
|
|
1944
|
+
throw err;
|
|
1945
|
+
}
|
|
1946
|
+
if (!isFragmentCond) {
|
|
1947
|
+
try {
|
|
1948
|
+
const sampleFalse = evalBranchTemplate(whenFalse);
|
|
1949
|
+
isFragmentCond = sampleFalse.html.includes(`<!--bf-cond-start:${id}-->`);
|
|
1950
|
+
} catch (err) {
|
|
1951
|
+
if (!(err instanceof TypeError))
|
|
1952
|
+
throw err;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
let prevCond;
|
|
1956
|
+
let branchCleanup = null;
|
|
1957
|
+
createEffect(() => {
|
|
1958
|
+
let currCond;
|
|
1959
|
+
try {
|
|
1960
|
+
currCond = Boolean(conditionFn());
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
if (err instanceof TypeError) {
|
|
1963
|
+
currCond = false;
|
|
1964
|
+
} else {
|
|
1965
|
+
throw err;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
const isFirstRun = prevCond === undefined;
|
|
1969
|
+
const prevVal = prevCond;
|
|
1970
|
+
prevCond = currCond;
|
|
1971
|
+
const branch = currCond ? whenTrue : whenFalse;
|
|
1972
|
+
if (isFirstRun) {
|
|
1973
|
+
setParentScopeId(parentScopeId);
|
|
1974
|
+
let result2;
|
|
1975
|
+
try {
|
|
1976
|
+
result2 = evalBranchTemplate(branch);
|
|
1977
|
+
} finally {
|
|
1978
|
+
setParentScopeId(null);
|
|
1979
|
+
}
|
|
1980
|
+
const existingEl = find(scope, `[${BF_COND}="${id}"]`);
|
|
1981
|
+
if (existingEl) {
|
|
1982
|
+
const expectedSig = getTemplateRootSignature(result2.html);
|
|
1983
|
+
const existingSig = existingEl.outerHTML.match(/^<[^>]+>/)?.[0] ?? null;
|
|
1984
|
+
if (isFragmentCond && (!expectedSig || existingSig !== expectedSig)) {
|
|
1985
|
+
updateFragmentConditional(scope, id, result2);
|
|
1986
|
+
} else if (!isFragmentCond && expectedSig && existingSig && expectedSig !== existingSig) {
|
|
1987
|
+
updateElementConditional(scope, id, result2);
|
|
1988
|
+
} else if (result2.slots.length > 0) {
|
|
1989
|
+
updateElementConditional(scope, id, result2);
|
|
1990
|
+
}
|
|
1991
|
+
} else if (isFragmentCond) {
|
|
1992
|
+
updateFragmentConditional(scope, id, result2);
|
|
1993
|
+
}
|
|
1994
|
+
const cleanup2 = branch.bindEvents(scope, { isFirstRun: true });
|
|
1995
|
+
branchCleanup = typeof cleanup2 === "function" ? cleanup2 : null;
|
|
1996
|
+
autoFocusConditionalElement(scope, id);
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
if (currCond === prevVal) {
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
if (branchCleanup) {
|
|
2003
|
+
branchCleanup();
|
|
2004
|
+
branchCleanup = null;
|
|
2005
|
+
}
|
|
2006
|
+
setParentScopeId(parentScopeId);
|
|
2007
|
+
let result;
|
|
2008
|
+
try {
|
|
2009
|
+
result = evalBranchTemplate(branch);
|
|
2010
|
+
} finally {
|
|
2011
|
+
setParentScopeId(null);
|
|
2012
|
+
}
|
|
2013
|
+
if (isFragmentCond) {
|
|
2014
|
+
updateFragmentConditional(scope, id, result);
|
|
2015
|
+
} else {
|
|
2016
|
+
updateElementConditional(scope, id, result);
|
|
2017
|
+
}
|
|
2018
|
+
const cleanup = branch.bindEvents(scope, { isFirstRun: false });
|
|
2019
|
+
branchCleanup = typeof cleanup === "function" ? cleanup : null;
|
|
2020
|
+
autoFocusConditionalElement(scope, id);
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
function autoFocusConditionalElement(scope, id) {
|
|
2024
|
+
requestAnimationFrame(() => {
|
|
2025
|
+
const condEl = scope.querySelector(`[${BF_COND}="${id}"]`);
|
|
2026
|
+
if (condEl) {
|
|
2027
|
+
const autofocusEl = condEl.matches("[autofocus]") ? condEl : condEl.querySelector("[autofocus]");
|
|
2028
|
+
if (autofocusEl && typeof autofocusEl.focus === "function") {
|
|
2029
|
+
autofocusEl.focus();
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
function getTemplateRootSignature(template) {
|
|
2035
|
+
const match = template.match(/^<[^>]+>/);
|
|
2036
|
+
return match ? match[0] : null;
|
|
2037
|
+
}
|
|
2038
|
+
function spliceSlots(fragment, slots) {
|
|
2039
|
+
if (slots.length === 0)
|
|
2040
|
+
return fragment;
|
|
2041
|
+
const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_COMMENT);
|
|
2042
|
+
const replacements = [];
|
|
2043
|
+
while (walker.nextNode()) {
|
|
2044
|
+
const c = walker.currentNode;
|
|
2045
|
+
const m = c.nodeValue?.match(/^bf-slot:(\d+)$/);
|
|
2046
|
+
if (m) {
|
|
2047
|
+
const idx = Number(m[1]);
|
|
2048
|
+
const node = slots[idx];
|
|
2049
|
+
if (node)
|
|
2050
|
+
replacements.push([c, node]);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
for (const [marker, node] of replacements) {
|
|
2054
|
+
marker.parentNode?.replaceChild(node, marker);
|
|
2055
|
+
}
|
|
2056
|
+
return fragment;
|
|
2057
|
+
}
|
|
2058
|
+
function updateFragmentConditional(scope, id, result) {
|
|
2059
|
+
const { html, slots } = result;
|
|
2060
|
+
const startMarker = `bf-cond-start:${id}`;
|
|
2061
|
+
let startComment = null;
|
|
2062
|
+
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_COMMENT);
|
|
2063
|
+
while (walker.nextNode()) {
|
|
2064
|
+
if (walker.currentNode.nodeValue === startMarker) {
|
|
2065
|
+
startComment = walker.currentNode;
|
|
2066
|
+
break;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
const condEl = scope.querySelector(`[${BF_COND}="${id}"]`);
|
|
2070
|
+
const endMarker = `bf-cond-end:${id}`;
|
|
2071
|
+
if (startComment) {
|
|
2072
|
+
const nodesToRemove = [];
|
|
2073
|
+
let node = startComment.nextSibling;
|
|
2074
|
+
while (node && !(node.nodeType === 8 && node.nodeValue === endMarker)) {
|
|
2075
|
+
nodesToRemove.push(node);
|
|
2076
|
+
node = node.nextSibling;
|
|
2077
|
+
}
|
|
2078
|
+
const endComment = node;
|
|
2079
|
+
nodesToRemove.forEach((n) => n.parentNode?.removeChild(n));
|
|
2080
|
+
const insertParent = startComment.parentNode instanceof Element ? startComment.parentNode : null;
|
|
2081
|
+
const fragment = spliceSlots(parseHTML(html, insertParent), slots);
|
|
2082
|
+
let child = fragment.firstChild;
|
|
2083
|
+
while (child) {
|
|
2084
|
+
const next = child.nextSibling;
|
|
2085
|
+
if (!(child.nodeType === 8 && child.nodeValue?.startsWith("bf-cond-"))) {
|
|
2086
|
+
startComment.parentNode?.insertBefore(child, endComment);
|
|
2087
|
+
}
|
|
2088
|
+
child = next;
|
|
2089
|
+
}
|
|
2090
|
+
} else if (condEl) {
|
|
2091
|
+
const insertParent = condEl.parentNode instanceof Element ? condEl.parentNode : null;
|
|
2092
|
+
const parsed = spliceSlots(parseHTML(html, insertParent), slots);
|
|
2093
|
+
const firstChild = parsed.firstChild;
|
|
2094
|
+
if (firstChild?.nodeType === 8 && firstChild?.nodeValue === `bf-cond-start:${id}`) {
|
|
2095
|
+
const parent = condEl.parentNode;
|
|
2096
|
+
let n = parsed.firstChild;
|
|
2097
|
+
while (n) {
|
|
2098
|
+
const next = n.nextSibling;
|
|
2099
|
+
parent?.insertBefore(n, condEl);
|
|
2100
|
+
n = next;
|
|
2101
|
+
}
|
|
2102
|
+
condEl.remove();
|
|
2103
|
+
} else if (firstChild) {
|
|
2104
|
+
condEl.replaceWith(firstChild);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
function updateElementConditional(scope, id, result) {
|
|
2109
|
+
const condEl = scope.querySelector(`[${BF_COND}="${id}"]`);
|
|
2110
|
+
if (!condEl)
|
|
2111
|
+
return;
|
|
2112
|
+
const { html, slots } = result;
|
|
2113
|
+
const insertParent = condEl.parentNode instanceof Element ? condEl.parentNode : null;
|
|
2114
|
+
const fragment = spliceSlots(parseHTML(html, insertParent), slots);
|
|
2115
|
+
const newEl = fragment.firstChild;
|
|
2116
|
+
if (newEl) {
|
|
2117
|
+
condEl.replaceWith(newEl);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
// src/runtime/branch-slot.ts
|
|
2121
|
+
function __bfSlot(value, slots) {
|
|
2122
|
+
if (value == null || value === false || value === true)
|
|
2123
|
+
return "";
|
|
2124
|
+
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
2125
|
+
const idx = slots.length;
|
|
2126
|
+
slots.push(value);
|
|
2127
|
+
return `<!--bf-slot:${idx}-->`;
|
|
2128
|
+
}
|
|
2129
|
+
if (Array.isArray(value)) {
|
|
2130
|
+
return value.map((v) => __bfSlot(v, slots)).join("");
|
|
2131
|
+
}
|
|
2132
|
+
return String(value);
|
|
2133
|
+
}
|
|
2134
|
+
// src/runtime/client-marker.ts
|
|
2135
|
+
function updateClientMarker(scope, id, value) {
|
|
2136
|
+
if (!scope)
|
|
2137
|
+
return;
|
|
2138
|
+
const marker = `bf-client:${id}`;
|
|
2139
|
+
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_COMMENT);
|
|
2140
|
+
while (walker.nextNode()) {
|
|
2141
|
+
if (walker.currentNode.nodeValue === marker) {
|
|
2142
|
+
const comment = walker.currentNode;
|
|
2143
|
+
let textNode = comment.nextSibling;
|
|
2144
|
+
if (textNode?.nodeType !== Node.TEXT_NODE || !textNode.nodeValue?.startsWith("")) {
|
|
2145
|
+
textNode = document.createTextNode("" + String(value ?? ""));
|
|
2146
|
+
comment.parentNode?.insertBefore(textNode, comment.nextSibling);
|
|
2147
|
+
} else {
|
|
2148
|
+
textNode.nodeValue = "" + String(value ?? "");
|
|
2149
|
+
}
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
// src/runtime/render.ts
|
|
2155
|
+
function render(container, nameOrDef, props = {}) {
|
|
2156
|
+
let name;
|
|
2157
|
+
let init;
|
|
2158
|
+
let template;
|
|
2159
|
+
if (typeof nameOrDef === "string") {
|
|
2160
|
+
name = nameOrDef;
|
|
2161
|
+
init = getComponentInit(name);
|
|
2162
|
+
template = getTemplate(name);
|
|
2163
|
+
if (!init || !template) {
|
|
2164
|
+
throw new Error(`[BarefootJS] Component "${name}" is not registered. ` + `Did you import its .client.js file before calling render()?`);
|
|
2165
|
+
}
|
|
2166
|
+
} else {
|
|
2167
|
+
init = nameOrDef.init;
|
|
2168
|
+
template = nameOrDef.template;
|
|
2169
|
+
name = nameOrDef.name || init.name?.replace(/^init/, "") || "Component";
|
|
2170
|
+
if (!template) {
|
|
2171
|
+
throw new Error("[BarefootJS] render(): ComponentDef requires a template function");
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
const scopeId = `${name}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2175
|
+
setParentScopeId(scopeId);
|
|
2176
|
+
let html;
|
|
2177
|
+
try {
|
|
2178
|
+
html = template(props).trim();
|
|
2179
|
+
} finally {
|
|
2180
|
+
setParentScopeId(null);
|
|
2181
|
+
}
|
|
2182
|
+
const tpl = document.createElement("template");
|
|
2183
|
+
tpl.innerHTML = html;
|
|
2184
|
+
const element = tpl.content.firstChild;
|
|
2185
|
+
if (!element) {
|
|
2186
|
+
throw new Error("[BarefootJS] render(): template returned empty HTML");
|
|
2187
|
+
}
|
|
2188
|
+
if (!element.getAttribute(BF_SCOPE)) {
|
|
2189
|
+
element.setAttribute(BF_SCOPE, scopeId);
|
|
2190
|
+
}
|
|
2191
|
+
container.innerHTML = "";
|
|
2192
|
+
container.appendChild(element);
|
|
2193
|
+
init(element, props);
|
|
2194
|
+
hydratedScopes.add(element);
|
|
2195
|
+
}
|
|
2196
|
+
// src/runtime/streaming.ts
|
|
2197
|
+
function __bf_swap(id) {
|
|
2198
|
+
const slot = document.querySelector(`[${BF_ASYNC}="${id}"]`);
|
|
2199
|
+
const tmpl = document.querySelector(`template[${BF_ASYNC_RESOLVE}="${id}"]`);
|
|
2200
|
+
if (!slot || !tmpl)
|
|
2201
|
+
return;
|
|
2202
|
+
slot.replaceChildren(tmpl.content.cloneNode(true));
|
|
2203
|
+
slot.removeAttribute(BF_ASYNC);
|
|
2204
|
+
tmpl.remove();
|
|
2205
|
+
rehydrateAll();
|
|
2206
|
+
}
|
|
2207
|
+
function setupStreaming() {
|
|
2208
|
+
if (typeof window === "undefined")
|
|
2209
|
+
return;
|
|
2210
|
+
const w = window;
|
|
2211
|
+
w.__bf_swap = __bf_swap;
|
|
2212
|
+
w.__bf_hydrate = rehydrateAll;
|
|
2213
|
+
}
|
|
2214
|
+
export {
|
|
2215
|
+
useContext,
|
|
2216
|
+
upsertChildItem,
|
|
2217
|
+
upsertChild,
|
|
2218
|
+
updateClientMarker,
|
|
2219
|
+
unwrap,
|
|
2220
|
+
untrack,
|
|
2221
|
+
styleToCss,
|
|
2222
|
+
spreadAttrs,
|
|
2223
|
+
splitProps,
|
|
2224
|
+
setupStreaming,
|
|
2225
|
+
setCurrentScope,
|
|
2226
|
+
renderChild,
|
|
2227
|
+
render,
|
|
2228
|
+
rehydrateAll,
|
|
2229
|
+
registerTemplate,
|
|
2230
|
+
registerComponent,
|
|
2231
|
+
reconcileList,
|
|
2232
|
+
reconcileElements,
|
|
2233
|
+
qsaItem,
|
|
2234
|
+
qsaChildScopes,
|
|
2235
|
+
qsaChildScope,
|
|
2236
|
+
qsa,
|
|
2237
|
+
provideContext,
|
|
2238
|
+
parseHTML,
|
|
2239
|
+
onMount,
|
|
2240
|
+
onCleanup,
|
|
2241
|
+
mapArray,
|
|
2242
|
+
isSSRPortal,
|
|
2243
|
+
insert,
|
|
2244
|
+
initChild,
|
|
2245
|
+
hydratedScopes,
|
|
2246
|
+
hydrate,
|
|
2247
|
+
hasTemplate,
|
|
2248
|
+
getTemplate,
|
|
2249
|
+
getRegisteredDef,
|
|
2250
|
+
getPropsUpdateFn,
|
|
2251
|
+
getLoopNodes,
|
|
2252
|
+
getLoopChildren,
|
|
2253
|
+
getComponentProps,
|
|
2254
|
+
getComponentInit,
|
|
2255
|
+
forwardProps,
|
|
2256
|
+
flushHydration,
|
|
2257
|
+
findSiblingSlot,
|
|
2258
|
+
findScope,
|
|
2259
|
+
find,
|
|
2260
|
+
cssEscape,
|
|
2261
|
+
createSignal,
|
|
2262
|
+
createRoot,
|
|
2263
|
+
createPortal,
|
|
2264
|
+
createMemo,
|
|
2265
|
+
createEffect,
|
|
2266
|
+
createDisposableEffect,
|
|
2267
|
+
createContext,
|
|
2268
|
+
createComponent,
|
|
2269
|
+
cleanupPortalPlaceholder,
|
|
2270
|
+
batch,
|
|
2271
|
+
applyRestAttrs,
|
|
2272
|
+
__slot,
|
|
2273
|
+
__bf_swap,
|
|
2274
|
+
__bfSlot,
|
|
2275
|
+
$t,
|
|
2276
|
+
$c,
|
|
2277
|
+
$
|
|
2278
|
+
};
|