ilha 0.14.3 → 0.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/define.d.ts +2 -2
- package/dist/define.js +4 -4
- package/dist/index.d.ts +55 -15
- package/dist/index.js +132 -36
- package/dist/jsx-dev-runtime.d.ts +2 -2
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +5 -5
- package/dist/jsx-runtime.js +1 -1
- package/dist/mount-C5idXX3H.js +1564 -0
- package/dist/types-CUQdA6hR.d.ts +43 -0
- package/dist/{vnode-15tImQ6O.d.ts → vnode-Bwx8ffNO.d.ts} +19 -16
- package/dist/vnode-DEMDQ0eA.js +91 -0
- package/package.json +1 -1
- package/dist/mount-CCMOkDSb.js +0 -1661
- package/dist/types-Cie0Ihl6.d.ts +0 -32
- package/dist/vnode-DHN2EFHi.js +0 -37
package/dist/mount-CCMOkDSb.js
DELETED
|
@@ -1,1661 +0,0 @@
|
|
|
1
|
-
import { i as Fragment, n as isSetupFn, r as isVNode } from "./vnode-DHN2EFHi.js";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as Stream from "effect/Stream";
|
|
4
|
-
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
5
|
-
import * as Cause from "effect/Cause";
|
|
6
|
-
import * as Exit from "effect/Exit";
|
|
7
|
-
import * as Fiber from "effect/Fiber";
|
|
8
|
-
import * as Scope from "effect/Scope";
|
|
9
|
-
import * as Registry from "effect/unstable/reactivity/AtomRegistry";
|
|
10
|
-
import * as Option from "effect/Option";
|
|
11
|
-
import * as Result from "effect/Result";
|
|
12
|
-
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
13
|
-
|
|
14
|
-
//#region src/runtime.ts
|
|
15
|
-
const stack = [];
|
|
16
|
-
const getFiber = () => {
|
|
17
|
-
const f = stack.findLast((x) => !x.closed);
|
|
18
|
-
if (!f) throw new Error("ilha: no fiber");
|
|
19
|
-
return f;
|
|
20
|
-
};
|
|
21
|
-
const getActiveFiber = () => stack.findLast((x) => !x.closed);
|
|
22
|
-
const withFiber = (fiber, fn) => {
|
|
23
|
-
stack.push(fiber);
|
|
24
|
-
try {
|
|
25
|
-
return fn();
|
|
26
|
-
} finally {
|
|
27
|
-
stack.pop();
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const provide = (effect, registry) => effect.pipe(Effect.provideService(Registry.AtomRegistry, registry));
|
|
31
|
-
const runInScope = (effect, registry, scope, onOk, onErr, onDone) => {
|
|
32
|
-
const provided = provide(effect, registry);
|
|
33
|
-
const f = Effect.runFork(onOk || onDone ? provided.pipe(Effect.onExit((ex) => Effect.sync(() => {
|
|
34
|
-
onDone?.();
|
|
35
|
-
if (Exit.isSuccess(ex)) onOk?.(ex.value);
|
|
36
|
-
else if (!Cause.hasInterruptsOnly(ex.cause)) onErr?.(Cause.squash(ex.cause));
|
|
37
|
-
}))) : provided);
|
|
38
|
-
Effect.runSync(Scope.addFinalizer(scope, Fiber.interrupt(f)));
|
|
39
|
-
};
|
|
40
|
-
function closeFiber(fiber) {
|
|
41
|
-
if (fiber.closed) return;
|
|
42
|
-
fiber.closed = true;
|
|
43
|
-
fiber.trackRestore?.();
|
|
44
|
-
fiber.trackRestore = void 0;
|
|
45
|
-
fiber.renderSub?.();
|
|
46
|
-
fiber.renderSub = void 0;
|
|
47
|
-
for (const slot of fiber.watchSlots ?? []) slot?.dispose();
|
|
48
|
-
fiber.watchSlots = [];
|
|
49
|
-
for (const h of fiber.holes) h.dispose();
|
|
50
|
-
fiber.holes = [];
|
|
51
|
-
Effect.runFork(Scope.close(fiber.scope, Exit.void));
|
|
52
|
-
}
|
|
53
|
-
function makeRuntime(opts) {
|
|
54
|
-
const registry = Registry.make();
|
|
55
|
-
const scope = Scope.makeUnsafe();
|
|
56
|
-
let holeSeq = 0;
|
|
57
|
-
let pending = 0;
|
|
58
|
-
let onIdle;
|
|
59
|
-
const runtime = {
|
|
60
|
-
registry,
|
|
61
|
-
scope,
|
|
62
|
-
ssr: opts?.ssr === true,
|
|
63
|
-
ssrValues: [],
|
|
64
|
-
ssrActions: {},
|
|
65
|
-
ssrEventI: 0,
|
|
66
|
-
ssrCapture: opts?.ssrCapture === true,
|
|
67
|
-
hydrateValues: opts?.hydrate,
|
|
68
|
-
hydrateI: 0,
|
|
69
|
-
nextHole: () => ++holeSeq,
|
|
70
|
-
begin() {
|
|
71
|
-
pending++;
|
|
72
|
-
},
|
|
73
|
-
end() {
|
|
74
|
-
pending--;
|
|
75
|
-
if (pending === 0) onIdle?.();
|
|
76
|
-
},
|
|
77
|
-
later(fn) {
|
|
78
|
-
runtime.begin();
|
|
79
|
-
queueMicrotask(() => {
|
|
80
|
-
try {
|
|
81
|
-
fn();
|
|
82
|
-
} finally {
|
|
83
|
-
runtime.end();
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
setIdle(cb) {
|
|
88
|
-
onIdle = cb;
|
|
89
|
-
if (pending === 0) cb();
|
|
90
|
-
},
|
|
91
|
-
close() {
|
|
92
|
-
onIdle = void 0;
|
|
93
|
-
Effect.runFork(Scope.close(scope, Exit.void));
|
|
94
|
-
registry.dispose();
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
return runtime;
|
|
98
|
-
}
|
|
99
|
-
function makeFiber(runtime, root, paint, opts) {
|
|
100
|
-
const scope = Scope.forkUnsafe(runtime.scope);
|
|
101
|
-
const fiber = {
|
|
102
|
-
root,
|
|
103
|
-
registry: runtime.registry,
|
|
104
|
-
scope,
|
|
105
|
-
runtime,
|
|
106
|
-
holes: [],
|
|
107
|
-
inFlight: false,
|
|
108
|
-
closed: false,
|
|
109
|
-
paint: (view) => paint(fiber, view),
|
|
110
|
-
run(effect, onOk, onErr) {
|
|
111
|
-
if (fiber.closed) return;
|
|
112
|
-
if (onOk) fiber.runtime.begin();
|
|
113
|
-
runInScope(effect, fiber.registry, fiber.scope, onOk && ((a) => {
|
|
114
|
-
if (!fiber.closed) withFiber(fiber, () => onOk(a));
|
|
115
|
-
}), onErr && ((e) => {
|
|
116
|
-
if (!fiber.closed) withFiber(fiber, () => onErr(e));
|
|
117
|
-
}), onOk && (() => fiber.runtime.end()));
|
|
118
|
-
},
|
|
119
|
-
fail(e) {
|
|
120
|
-
opts?.onFail?.(e);
|
|
121
|
-
},
|
|
122
|
-
park() {}
|
|
123
|
-
};
|
|
124
|
-
return fiber;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/atom.ts
|
|
129
|
-
const handleOwner = /* @__PURE__ */ new WeakMap();
|
|
130
|
-
function guardHandleFiber(handle) {
|
|
131
|
-
const owner = handleOwner.get(handle);
|
|
132
|
-
if (!owner) return;
|
|
133
|
-
const active = getActiveFiber();
|
|
134
|
-
if (!active || active.registry === owner.registry) return;
|
|
135
|
-
throw new Error("ilha: atom handle used from a different island");
|
|
136
|
-
}
|
|
137
|
-
function instr(effect) {
|
|
138
|
-
const fiber = getFiber();
|
|
139
|
-
const out = {
|
|
140
|
-
$$ilhaOp: 1,
|
|
141
|
-
effect,
|
|
142
|
-
*[Symbol.iterator]() {
|
|
143
|
-
return yield out;
|
|
144
|
-
},
|
|
145
|
-
then(onFulfilled, onRejected) {
|
|
146
|
-
return new Promise((res, rej) => {
|
|
147
|
-
fiber.run(out.effect, (a) => {
|
|
148
|
-
withFiber(fiber, () => res(a));
|
|
149
|
-
}, rej);
|
|
150
|
-
}).then(onFulfilled, onRejected);
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
return out;
|
|
154
|
-
}
|
|
155
|
-
function isAtomHandle(x) {
|
|
156
|
-
return typeof x === "function" && x.$$atom === 1;
|
|
157
|
-
}
|
|
158
|
-
let trackGet;
|
|
159
|
-
const trackStack = [];
|
|
160
|
-
function beginPrimitiveFrame(fiber) {
|
|
161
|
-
const used = fiber.primitiveI ?? 0;
|
|
162
|
-
const slots = fiber.primitives?.length ?? 0;
|
|
163
|
-
if (used > 0 && used !== slots) console.warn(`ilha: atom/watch slot count changed between renders (${slots} → ${used}); keep primitive order stable`);
|
|
164
|
-
fiber.primitiveI = 0;
|
|
165
|
-
fiber.watchI = 0;
|
|
166
|
-
const islandFrame = fiber.islandFrame ??= {
|
|
167
|
-
i: 0,
|
|
168
|
-
slots: []
|
|
169
|
-
};
|
|
170
|
-
const usedIslands = islandFrame.i;
|
|
171
|
-
if (usedIslands < islandFrame.slots.length) {
|
|
172
|
-
for (let j = usedIslands; j < islandFrame.slots.length; j++) {
|
|
173
|
-
const slot = islandFrame.slots[j];
|
|
174
|
-
if (slot) {
|
|
175
|
-
slot.unmount?.();
|
|
176
|
-
islandFrame.slots[j] = void 0;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
islandFrame.slots.length = usedIslands;
|
|
180
|
-
}
|
|
181
|
-
islandFrame.i = 0;
|
|
182
|
-
}
|
|
183
|
-
function readTracked(atom, registry) {
|
|
184
|
-
const frame = trackStack.at(-1);
|
|
185
|
-
const active = getActiveFiber();
|
|
186
|
-
if (trackGet && frame && active === frame.fiber) return trackGet(atom);
|
|
187
|
-
return registry.get(atom);
|
|
188
|
-
}
|
|
189
|
-
function usePrimitiveSlot(fiber, make) {
|
|
190
|
-
const i = fiber.primitiveI ?? 0;
|
|
191
|
-
fiber.primitiveI = i + 1;
|
|
192
|
-
fiber.primitives ??= [];
|
|
193
|
-
const existing = fiber.primitives[i];
|
|
194
|
-
if (existing) return {
|
|
195
|
-
atom: existing,
|
|
196
|
-
fresh: false
|
|
197
|
-
};
|
|
198
|
-
const a = make();
|
|
199
|
-
fiber.primitives[i] = a;
|
|
200
|
-
return {
|
|
201
|
-
atom: a,
|
|
202
|
-
fresh: true
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function withTrackGetRun(fiber, fn, onOk, onErr) {
|
|
206
|
-
const deps = /* @__PURE__ */ new Set();
|
|
207
|
-
const get = (a) => {
|
|
208
|
-
deps.add(a);
|
|
209
|
-
return fiber.registry.get(a);
|
|
210
|
-
};
|
|
211
|
-
const restore = () => {
|
|
212
|
-
if (fiber.trackRestore !== restore) return;
|
|
213
|
-
const top = trackStack.pop();
|
|
214
|
-
if (top?.get !== get) {
|
|
215
|
-
if (top) trackStack.push(top);
|
|
216
|
-
const i = trackStack.findIndex((frame) => frame.get === get);
|
|
217
|
-
if (i >= 0) trackStack.splice(i, 1);
|
|
218
|
-
}
|
|
219
|
-
trackGet = trackStack.at(-1)?.get;
|
|
220
|
-
fiber.trackRestore = void 0;
|
|
221
|
-
};
|
|
222
|
-
trackStack.push({
|
|
223
|
-
fiber,
|
|
224
|
-
deps,
|
|
225
|
-
get
|
|
226
|
-
});
|
|
227
|
-
trackGet = get;
|
|
228
|
-
fiber.trackRestore = restore;
|
|
229
|
-
try {
|
|
230
|
-
const result = withFiber(fiber, () => fn());
|
|
231
|
-
if (result instanceof Promise) {
|
|
232
|
-
restore();
|
|
233
|
-
result.then((value) => {
|
|
234
|
-
if (fiber.closed) return;
|
|
235
|
-
onOk({
|
|
236
|
-
value,
|
|
237
|
-
deps
|
|
238
|
-
});
|
|
239
|
-
}).catch((e) => {
|
|
240
|
-
if (fiber.closed) return;
|
|
241
|
-
onErr(e);
|
|
242
|
-
});
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
restore();
|
|
246
|
-
onOk({
|
|
247
|
-
value: result,
|
|
248
|
-
deps
|
|
249
|
-
});
|
|
250
|
-
} catch (e) {
|
|
251
|
-
restore();
|
|
252
|
-
onErr(e);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
function subscribeRenderDeps(fiber, deps, run) {
|
|
256
|
-
if (deps.size === 0) return () => {};
|
|
257
|
-
let scheduled = false;
|
|
258
|
-
const schedule = () => {
|
|
259
|
-
if (scheduled) return;
|
|
260
|
-
scheduled = true;
|
|
261
|
-
fiber.runtime.later(() => {
|
|
262
|
-
scheduled = false;
|
|
263
|
-
run();
|
|
264
|
-
});
|
|
265
|
-
};
|
|
266
|
-
const unsubs = [];
|
|
267
|
-
for (const dep of deps) unsubs.push(fiber.registry.subscribe(dep, schedule));
|
|
268
|
-
return () => {
|
|
269
|
-
for (const unsub of unsubs) unsub();
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
function wrapHandle(atom, fiber) {
|
|
273
|
-
const registry = fiber.registry;
|
|
274
|
-
const read = (() => {
|
|
275
|
-
guardHandleFiber(read);
|
|
276
|
-
return readTracked(atom, registry);
|
|
277
|
-
});
|
|
278
|
-
handleOwner.set(read, fiber);
|
|
279
|
-
Object.defineProperties(read, {
|
|
280
|
-
$$atom: { value: 1 },
|
|
281
|
-
atom: { value: atom },
|
|
282
|
-
set: { value: (n) => {
|
|
283
|
-
guardHandleFiber(read);
|
|
284
|
-
if (Atom.isWritable(atom)) registry.set(atom, n);
|
|
285
|
-
} },
|
|
286
|
-
update: { value: (f) => {
|
|
287
|
-
guardHandleFiber(read);
|
|
288
|
-
if (Atom.isWritable(atom)) registry.update(atom, f);
|
|
289
|
-
} }
|
|
290
|
-
});
|
|
291
|
-
return read;
|
|
292
|
-
}
|
|
293
|
-
function makeAtom(init) {
|
|
294
|
-
const fiber = getFiber();
|
|
295
|
-
const snap = fiber.runtime.hydrateValues;
|
|
296
|
-
const { atom: a, fresh } = usePrimitiveSlot(fiber, () => {
|
|
297
|
-
let seed = init;
|
|
298
|
-
if (snap && !Atom.isAtom(init) && !Effect.isEffect(init) && !Stream.isStream(init)) {
|
|
299
|
-
const v = snap[fiber.runtime.hydrateI++];
|
|
300
|
-
if (v !== void 0) seed = v;
|
|
301
|
-
}
|
|
302
|
-
if (Atom.isAtom(seed)) return seed;
|
|
303
|
-
if (Effect.isEffect(seed) || Stream.isStream(seed)) return Atom.make(seed);
|
|
304
|
-
return Atom.make(seed);
|
|
305
|
-
});
|
|
306
|
-
const handle = wrapHandle(a, fiber);
|
|
307
|
-
if (fresh && fiber.runtime.ssr) fiber.runtime.ssrValues.push(fiber.registry.get(a));
|
|
308
|
-
return handle;
|
|
309
|
-
}
|
|
310
|
-
function atomLazy(init) {
|
|
311
|
-
const fiber = getFiber();
|
|
312
|
-
const snap = fiber.runtime.hydrateValues;
|
|
313
|
-
const { atom: a, fresh } = usePrimitiveSlot(fiber, () => {
|
|
314
|
-
let seed = init();
|
|
315
|
-
if (snap) {
|
|
316
|
-
const v = snap[fiber.runtime.hydrateI++];
|
|
317
|
-
if (v !== void 0) seed = v;
|
|
318
|
-
}
|
|
319
|
-
return Atom.make(seed);
|
|
320
|
-
});
|
|
321
|
-
const handle = wrapHandle(a, fiber);
|
|
322
|
-
if (fresh && fiber.runtime.ssr) fiber.runtime.ssrValues.push(fiber.registry.get(a));
|
|
323
|
-
return handle;
|
|
324
|
-
}
|
|
325
|
-
const atom = Object.assign(makeAtom, { lazy: atomLazy });
|
|
326
|
-
const batch = Atom.batch;
|
|
327
|
-
|
|
328
|
-
//#endregion
|
|
329
|
-
//#region src/errors.ts
|
|
330
|
-
function asFailure(e) {
|
|
331
|
-
if (Result.isResult(e) && Result.isFailure(e)) {
|
|
332
|
-
const v = Option.getOrUndefined(Result.getFailure(e));
|
|
333
|
-
return Result.fail(v instanceof Error ? v : new Error(String(v)));
|
|
334
|
-
}
|
|
335
|
-
return Result.fail(e instanceof Error ? e : new Error(String(e)));
|
|
336
|
-
}
|
|
337
|
-
function failureMessage(e) {
|
|
338
|
-
return asFailure(e).pipe(Result.match({
|
|
339
|
-
onSuccess: () => "error",
|
|
340
|
-
onFailure: (err) => err.message
|
|
341
|
-
}));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
//#endregion
|
|
345
|
-
//#region src/interpret.ts
|
|
346
|
-
function isInstruction(x) {
|
|
347
|
-
return typeof x === "object" && x !== null && x.$$ilhaOp === 1;
|
|
348
|
-
}
|
|
349
|
-
function interpret(gen, fiber) {
|
|
350
|
-
const iter = gen();
|
|
351
|
-
const resume = (send, thrown) => {
|
|
352
|
-
if (fiber.closed) return;
|
|
353
|
-
withFiber(fiber, () => {
|
|
354
|
-
if (fiber.inFlight) throw new Error("ilha: re-enter while Instruction in flight");
|
|
355
|
-
let step;
|
|
356
|
-
try {
|
|
357
|
-
step = thrown === void 0 ? iter.next(send) : iter.throw(thrown);
|
|
358
|
-
} catch (err) {
|
|
359
|
-
fiber.fail(asFailure(err));
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
if (step.done) {
|
|
363
|
-
if (step.value !== void 0) fiber.paint(step.value);
|
|
364
|
-
fiber.park();
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
const effect = isInstruction(step.value) ? step.value.effect : Effect.isEffect(step.value) ? step.value : void 0;
|
|
368
|
-
if (effect) {
|
|
369
|
-
fiber.inFlight = true;
|
|
370
|
-
fiber.run(effect, (a) => {
|
|
371
|
-
fiber.inFlight = false;
|
|
372
|
-
resume(a);
|
|
373
|
-
}, (e) => {
|
|
374
|
-
fiber.inFlight = false;
|
|
375
|
-
resume(void 0, new Error(failureMessage(e)));
|
|
376
|
-
});
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
fiber.paint(step.value);
|
|
380
|
-
resume(void 0);
|
|
381
|
-
});
|
|
382
|
-
};
|
|
383
|
-
resume(void 0);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
//#endregion
|
|
387
|
-
//#region src/events.ts
|
|
388
|
-
function eventTypeFromProp(key) {
|
|
389
|
-
if (key.length < 4) return void 0;
|
|
390
|
-
let type;
|
|
391
|
-
if (/^on[A-Z]/.test(key)) type = key.slice(2).toLowerCase();
|
|
392
|
-
else if (/^on[a-z]{3,}$/.test(key)) type = key.slice(2).toLowerCase();
|
|
393
|
-
else return void 0;
|
|
394
|
-
return type.length >= 3 ? type : void 0;
|
|
395
|
-
}
|
|
396
|
-
function isEventProp(key) {
|
|
397
|
-
return eventTypeFromProp(key) !== void 0;
|
|
398
|
-
}
|
|
399
|
-
function bindEvents(node, props, fiber) {
|
|
400
|
-
const el = node;
|
|
401
|
-
el.__ilhaProps = props;
|
|
402
|
-
el.__ilhaEvents ??= /* @__PURE__ */ new Set();
|
|
403
|
-
for (const key of Object.keys(props)) {
|
|
404
|
-
const type = eventTypeFromProp(key);
|
|
405
|
-
if (!type) continue;
|
|
406
|
-
if (el.__ilhaEvents.has(type)) continue;
|
|
407
|
-
el.__ilhaEvents.add(type);
|
|
408
|
-
if (fiber.runtime.ssr) {
|
|
409
|
-
const fn = props[key];
|
|
410
|
-
if (typeof fn !== "function") continue;
|
|
411
|
-
const branded = fn[Symbol.for("ilha.actionCall")];
|
|
412
|
-
const rec = branded?.k ? {
|
|
413
|
-
k: branded.k,
|
|
414
|
-
a: branded.a ?? []
|
|
415
|
-
} : void 0;
|
|
416
|
-
if (!rec) continue;
|
|
417
|
-
const id = `${type}:${fiber.runtime.ssrEventI++}`;
|
|
418
|
-
fiber.runtime.ssrActions[id] = rec;
|
|
419
|
-
const existing = el.getAttribute("data-ilha-on");
|
|
420
|
-
el.setAttribute("data-ilha-on", existing ? `${existing},${id}` : id);
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
el.addEventListener(type, (ev) => {
|
|
424
|
-
if (fiber.closed) return;
|
|
425
|
-
const fn = el.__ilhaProps?.[key];
|
|
426
|
-
if (typeof fn !== "function") return;
|
|
427
|
-
const out = fn(ev);
|
|
428
|
-
if (Effect.isEffect(out)) fiber.run(out);
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
//#endregion
|
|
434
|
-
//#region src/morph.ts
|
|
435
|
-
const PRESERVE_ATTR = "data-morph-preserve";
|
|
436
|
-
const KEY_ATTR$1 = "data-ilha-key";
|
|
437
|
-
const SLOT_ATTR$1 = "data-ilha-slot";
|
|
438
|
-
function morphKeyOf(el) {
|
|
439
|
-
const k = el.getAttribute(KEY_ATTR$1);
|
|
440
|
-
if (k !== null) return `k:${k}`;
|
|
441
|
-
const s = el.getAttribute(SLOT_ATTR$1);
|
|
442
|
-
return s === null ? null : `s:${s}`;
|
|
443
|
-
}
|
|
444
|
-
function shouldPreserveMorphAttr(el, name) {
|
|
445
|
-
if (name === "value" || name === "checked" || name === "selected") return true;
|
|
446
|
-
if (name === PRESERVE_ATTR) return el.hasAttribute(PRESERVE_ATTR);
|
|
447
|
-
const custom = el.getAttribute(PRESERVE_ATTR);
|
|
448
|
-
if (custom !== null) {
|
|
449
|
-
for (const token of custom.split(/\s+/)) if (token === name) return true;
|
|
450
|
-
}
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
function syncAttributes(from, to) {
|
|
454
|
-
for (const { name, value } of to.attributes) {
|
|
455
|
-
if (shouldPreserveMorphAttr(from, name)) continue;
|
|
456
|
-
if (from.getAttribute(name) !== value) from.setAttribute(name, value);
|
|
457
|
-
}
|
|
458
|
-
for (const { name } of Array.from(from.attributes)) {
|
|
459
|
-
if (shouldPreserveMorphAttr(from, name)) continue;
|
|
460
|
-
if (!to.hasAttribute(name)) from.removeAttribute(name);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
function snapshotFocus() {
|
|
464
|
-
if (typeof document === "undefined") return null;
|
|
465
|
-
const active = document.activeElement;
|
|
466
|
-
if (!(active instanceof HTMLElement) || active === document.body) return null;
|
|
467
|
-
let selection = null;
|
|
468
|
-
try {
|
|
469
|
-
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) selection = {
|
|
470
|
-
start: active.selectionStart,
|
|
471
|
-
end: active.selectionEnd,
|
|
472
|
-
dir: active.selectionDirection
|
|
473
|
-
};
|
|
474
|
-
} catch {}
|
|
475
|
-
return {
|
|
476
|
-
active,
|
|
477
|
-
selection
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
function restoreFocus(snapshot) {
|
|
481
|
-
if (!snapshot || !snapshot.active.isConnected) return;
|
|
482
|
-
try {
|
|
483
|
-
if (document.activeElement !== snapshot.active) snapshot.active.focus({ preventScroll: true });
|
|
484
|
-
const sel = snapshot.selection;
|
|
485
|
-
if (sel && sel.start !== null) {
|
|
486
|
-
const el = snapshot.active;
|
|
487
|
-
if (el.selectionStart !== sel.start || el.selectionEnd !== sel.end) el.setSelectionRange(sel.start, sel.end, sel.dir ?? "none");
|
|
488
|
-
}
|
|
489
|
-
} catch {}
|
|
490
|
-
}
|
|
491
|
-
function morphChildren(fromParent, toParent) {
|
|
492
|
-
const toNodes = Array.from(toParent.childNodes);
|
|
493
|
-
let fromKeyed = null;
|
|
494
|
-
for (const child of fromParent.children) {
|
|
495
|
-
const k = morphKeyOf(child);
|
|
496
|
-
if (k !== null && !(fromKeyed ??= /* @__PURE__ */ new Map()).has(k)) fromKeyed.set(k, child);
|
|
497
|
-
}
|
|
498
|
-
let toKeys = null;
|
|
499
|
-
if (fromKeyed !== null) {
|
|
500
|
-
toKeys = /* @__PURE__ */ new Set();
|
|
501
|
-
for (const child of toParent.children) {
|
|
502
|
-
const k = morphKeyOf(child);
|
|
503
|
-
if (k !== null) toKeys.add(k);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
for (let i = 0; i < toNodes.length; i++) {
|
|
507
|
-
const toNode = toNodes[i];
|
|
508
|
-
let fromNode = fromParent.childNodes[i];
|
|
509
|
-
if (fromKeyed !== null) {
|
|
510
|
-
const toKey = toNode.nodeType === 1 ? morphKeyOf(toNode) : null;
|
|
511
|
-
if (toKey !== null) {
|
|
512
|
-
const match = fromKeyed.get(toKey);
|
|
513
|
-
if (match) {
|
|
514
|
-
fromKeyed.delete(toKey);
|
|
515
|
-
if (match !== fromNode) {
|
|
516
|
-
fromParent.insertBefore(match, fromNode ?? null);
|
|
517
|
-
fromNode = match;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
if (fromNode instanceof Element) {
|
|
522
|
-
const fromKey = morphKeyOf(fromNode);
|
|
523
|
-
if (fromKey !== null && fromKey !== toKey && toKeys.has(fromKey)) {
|
|
524
|
-
fromParent.insertBefore(toNode, fromNode);
|
|
525
|
-
continue;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (!fromNode) {
|
|
530
|
-
fromParent.appendChild(toNode);
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
if (fromNode.nodeType !== toNode.nodeType) {
|
|
534
|
-
fromParent.replaceChild(toNode, fromNode);
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
if (fromNode.nodeType === 3 || fromNode.nodeType === 8) {
|
|
538
|
-
if (fromNode.nodeValue !== toNode.nodeValue) fromNode.nodeValue = toNode.nodeValue;
|
|
539
|
-
continue;
|
|
540
|
-
}
|
|
541
|
-
if (fromNode.nodeType === 1) {
|
|
542
|
-
const fromEl = fromNode;
|
|
543
|
-
const toEl = toNode;
|
|
544
|
-
if (fromEl.localName !== toEl.localName) {
|
|
545
|
-
fromParent.replaceChild(toEl, fromEl);
|
|
546
|
-
continue;
|
|
547
|
-
}
|
|
548
|
-
const slotId = toEl.getAttribute(SLOT_ATTR$1);
|
|
549
|
-
if (slotId !== null && fromEl.getAttribute("data-ilha-slot") === slotId) continue;
|
|
550
|
-
if (fromEl.localName === "input") {
|
|
551
|
-
const hadChecked = fromEl.hasAttribute("checked");
|
|
552
|
-
const hadValue = fromEl.getAttribute("value");
|
|
553
|
-
syncAttributes(fromEl, toEl);
|
|
554
|
-
const hasChecked = toEl.hasAttribute("checked");
|
|
555
|
-
if (hasChecked !== hadChecked) fromEl.checked = hasChecked;
|
|
556
|
-
const newValue = toEl.getAttribute("value");
|
|
557
|
-
if (newValue !== hadValue) fromEl.value = newValue ?? "";
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
if (fromEl.localName === "select") {
|
|
561
|
-
const before = /* @__PURE__ */ new Map();
|
|
562
|
-
for (const o of fromEl.options) before.set(o, {
|
|
563
|
-
attr: o.hasAttribute("selected"),
|
|
564
|
-
live: o.selected
|
|
565
|
-
});
|
|
566
|
-
syncAttributes(fromEl, toEl);
|
|
567
|
-
morphChildren(fromEl, toEl);
|
|
568
|
-
const options = Array.from(fromEl.options);
|
|
569
|
-
if (options.some((o) => o.hasAttribute("selected") !== (before.get(o)?.attr ?? false))) for (const o of options) o.selected = o.hasAttribute("selected");
|
|
570
|
-
else for (const o of options) {
|
|
571
|
-
const prev = before.get(o);
|
|
572
|
-
if (prev && o.selected !== prev.live) o.selected = prev.live;
|
|
573
|
-
}
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
syncAttributes(fromEl, toEl);
|
|
577
|
-
if (fromEl.localName === "textarea") {
|
|
578
|
-
const newText = toEl.textContent ?? "";
|
|
579
|
-
if (fromEl.textContent !== newText) {
|
|
580
|
-
fromEl.textContent = newText;
|
|
581
|
-
fromEl.value = newText;
|
|
582
|
-
}
|
|
583
|
-
} else morphChildren(fromEl, toEl);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
while (fromParent.childNodes.length > toNodes.length) fromParent.lastChild.remove();
|
|
587
|
-
}
|
|
588
|
-
function morphInner(from, to) {
|
|
589
|
-
const focus = snapshotFocus();
|
|
590
|
-
morphChildren(from, to);
|
|
591
|
-
restoreFocus(focus);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
//#endregion
|
|
595
|
-
//#region src/security.ts
|
|
596
|
-
const SAFE_CSS_PROP_RE = /^(-{2}[a-zA-Z][a-zA-Z0-9-]*|-?[a-zA-Z][a-zA-Z0-9-]*)$/;
|
|
597
|
-
const URL_ATTRS = /* @__PURE__ */ new Set([
|
|
598
|
-
"href",
|
|
599
|
-
"src",
|
|
600
|
-
"srcset",
|
|
601
|
-
"imagesrcset",
|
|
602
|
-
"action",
|
|
603
|
-
"formaction",
|
|
604
|
-
"cite",
|
|
605
|
-
"data",
|
|
606
|
-
"poster"
|
|
607
|
-
]);
|
|
608
|
-
const SAFE_DATA_IMAGE_RE = /^data:image\/(png|jpe?g|gif|webp|avif)[;,]/i;
|
|
609
|
-
const UNSAFE_SCHEME_RE = /^(?:javascript|vbscript):/i;
|
|
610
|
-
const DATA_IMAGE_CONTEXTS = /* @__PURE__ */ new Set([
|
|
611
|
-
"img:src",
|
|
612
|
-
"source:srcset",
|
|
613
|
-
"link:imagesrcset"
|
|
614
|
-
]);
|
|
615
|
-
const URL_WHITESPACE_RE = /[\u0000-\u0020\u00a0\u1680\u2000-\u200d\u2028\u2029\u202f\u205f\u3000\ufeff]/g;
|
|
616
|
-
function normalizeUrl(value) {
|
|
617
|
-
return value.replace(URL_WHITESPACE_RE, "");
|
|
618
|
-
}
|
|
619
|
-
function checkUrl(normalized, allowDataImage) {
|
|
620
|
-
if (UNSAFE_SCHEME_RE.test(normalized)) return false;
|
|
621
|
-
if (/^data:/i.test(normalized)) return allowDataImage && SAFE_DATA_IMAGE_RE.test(normalized);
|
|
622
|
-
return true;
|
|
623
|
-
}
|
|
624
|
-
function isUrlAttributeName(name) {
|
|
625
|
-
const lower = name.toLowerCase();
|
|
626
|
-
return URL_ATTRS.has(lower) || /:(href|src|srcset|imagesrcset|action|formaction|cite|data|poster)$/.test(lower);
|
|
627
|
-
}
|
|
628
|
-
function isSafeUrlAttrValue(tagName, attrName, value) {
|
|
629
|
-
const attr = attrName.toLowerCase();
|
|
630
|
-
const allowDataImage = DATA_IMAGE_CONTEXTS.has(`${tagName.toLowerCase()}:${attr}`) && !attr.startsWith("srcset") && attr !== "imagesrcset";
|
|
631
|
-
if (/^(?:srcset|imagesrcset)$/i.test(attr)) return value.split(",").every((candidate) => {
|
|
632
|
-
const url = candidate.trim().split(/\s+/)[0] ?? "";
|
|
633
|
-
return url === "" || checkUrl(normalizeUrl(url), false);
|
|
634
|
-
});
|
|
635
|
-
return checkUrl(normalizeUrl(value), allowDataImage);
|
|
636
|
-
}
|
|
637
|
-
function isSafeStyleValue(str) {
|
|
638
|
-
if (/[<>{};]/.test(str) || /expression\(/i.test(str) || /javascript:/i.test(str) || /data:/i.test(str)) return false;
|
|
639
|
-
if (/\\/.test(str)) return false;
|
|
640
|
-
const urlRe = /url\s*\(\s*([^)]+)\s*\)/gi;
|
|
641
|
-
let m;
|
|
642
|
-
while ((m = urlRe.exec(str)) !== null) if (!checkUrl(normalizeUrl(m[1].trim().replace(/^['"]|['"]$/g, "")), false)) return false;
|
|
643
|
-
return true;
|
|
644
|
-
}
|
|
645
|
-
function serializeStyleEntries(value) {
|
|
646
|
-
return Object.entries(value).map(([k, v]) => {
|
|
647
|
-
if (!SAFE_CSS_PROP_RE.test(k)) return "";
|
|
648
|
-
const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
649
|
-
const str = String(v);
|
|
650
|
-
if (!isSafeStyleValue(str)) return "";
|
|
651
|
-
return `${prop}:${str}`;
|
|
652
|
-
}).filter(Boolean).join(";");
|
|
653
|
-
}
|
|
654
|
-
function serializeStyleAttr(value) {
|
|
655
|
-
if (typeof value === "string") {
|
|
656
|
-
const obj = {};
|
|
657
|
-
for (const decl of value.split(";")) {
|
|
658
|
-
const colon = decl.indexOf(":");
|
|
659
|
-
if (colon < 0) continue;
|
|
660
|
-
const prop = decl.slice(0, colon).trim();
|
|
661
|
-
const val = decl.slice(colon + 1).trim();
|
|
662
|
-
if (prop) obj[prop] = val;
|
|
663
|
-
}
|
|
664
|
-
return serializeStyleEntries(obj);
|
|
665
|
-
}
|
|
666
|
-
return serializeStyleEntries(value);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
//#endregion
|
|
670
|
-
//#region src/start.ts
|
|
671
|
-
function isGen(x) {
|
|
672
|
-
return typeof x === "object" && x !== null && typeof x.next === "function" && typeof x.throw === "function";
|
|
673
|
-
}
|
|
674
|
-
function finish(fiber, view) {
|
|
675
|
-
if (fiber.closed) return;
|
|
676
|
-
if (view !== void 0) fiber.paint(view);
|
|
677
|
-
fiber.park();
|
|
678
|
-
}
|
|
679
|
-
function runSetup(fiber, fn) {
|
|
680
|
-
const disposeRenderSub = () => {
|
|
681
|
-
fiber.renderSub?.();
|
|
682
|
-
fiber.renderSub = void 0;
|
|
683
|
-
};
|
|
684
|
-
const commit = (out, deps) => {
|
|
685
|
-
if (isGen(out)) {
|
|
686
|
-
disposeRenderSub();
|
|
687
|
-
interpret((() => out), fiber);
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
disposeRenderSub();
|
|
691
|
-
if (!fiber.runtime.ssr) fiber.renderSub = subscribeRenderDeps(fiber, deps, render);
|
|
692
|
-
withFiber(fiber, () => finish(fiber, out));
|
|
693
|
-
};
|
|
694
|
-
const render = () => {
|
|
695
|
-
if (fiber.closed) return;
|
|
696
|
-
fiber.runtime.begin();
|
|
697
|
-
beginPrimitiveFrame(fiber);
|
|
698
|
-
withTrackGetRun(fiber, () => fn(), ({ value: out, deps }) => {
|
|
699
|
-
try {
|
|
700
|
-
commit(out, deps);
|
|
701
|
-
} catch (e) {
|
|
702
|
-
withFiber(fiber, () => fiber.fail(asFailure(e)));
|
|
703
|
-
} finally {
|
|
704
|
-
fiber.runtime.end();
|
|
705
|
-
}
|
|
706
|
-
}, (e) => {
|
|
707
|
-
withFiber(fiber, () => fiber.fail(asFailure(e)));
|
|
708
|
-
fiber.runtime.end();
|
|
709
|
-
});
|
|
710
|
-
};
|
|
711
|
-
try {
|
|
712
|
-
render();
|
|
713
|
-
} catch (e) {
|
|
714
|
-
fiber.fail(asFailure(e));
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
//#endregion
|
|
719
|
-
//#region src/paint.ts
|
|
720
|
-
const ISLAND$1 = Symbol.for("ilha.island");
|
|
721
|
-
const ISLAND_MOUNT_INTERNAL$1 = Symbol.for("ilha.islandMountInternal");
|
|
722
|
-
const ISLAND_SLOT_TAG$1 = Symbol.for("ilha.islandSlotTag");
|
|
723
|
-
function insert$1(fiber, nodes) {
|
|
724
|
-
for (const n of nodes) fiber.root.appendChild(n);
|
|
725
|
-
}
|
|
726
|
-
function disposeHoles$1(fiber, opts) {
|
|
727
|
-
const keep = [];
|
|
728
|
-
for (const h of fiber.holes) {
|
|
729
|
-
if (opts?.morph && h.keepOnMorph) {
|
|
730
|
-
keep.push(h);
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
h.dispose();
|
|
734
|
-
}
|
|
735
|
-
fiber.holes = keep;
|
|
736
|
-
}
|
|
737
|
-
function skip$1(x) {
|
|
738
|
-
return x === null || x === void 0 || typeof x === "boolean";
|
|
739
|
-
}
|
|
740
|
-
function applyProps$1(el, props, fiber) {
|
|
741
|
-
for (const [k, v] of Object.entries(props)) {
|
|
742
|
-
if (k === "children" || k === "key" || k === "ref") continue;
|
|
743
|
-
if (k === "className") {
|
|
744
|
-
el.setAttribute("class", String(v ?? ""));
|
|
745
|
-
continue;
|
|
746
|
-
}
|
|
747
|
-
if (k === "htmlFor") {
|
|
748
|
-
el.setAttribute("for", String(v ?? ""));
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
if (k.toLowerCase() === "srcdoc") continue;
|
|
752
|
-
if (k === "style" && v != null && v !== false) {
|
|
753
|
-
const css = typeof v === "string" || typeof v === "object" ? serializeStyleAttr(v) : "";
|
|
754
|
-
if (css) el.style.cssText = css;
|
|
755
|
-
continue;
|
|
756
|
-
}
|
|
757
|
-
if (isEventProp(k)) continue;
|
|
758
|
-
if (/^on[A-Z]/.test(k)) continue;
|
|
759
|
-
if (k === "value" || k === "checked" || k === "selected") {
|
|
760
|
-
const setProp = (x) => {
|
|
761
|
-
const node = el;
|
|
762
|
-
if (k === "value") node.value = String(x ?? "");
|
|
763
|
-
else if (k === "checked") {
|
|
764
|
-
node.checked = Boolean(x);
|
|
765
|
-
if (fiber.runtime.ssr) {
|
|
766
|
-
if (x) el.setAttribute("checked", "");
|
|
767
|
-
else el.removeAttribute("checked");
|
|
768
|
-
}
|
|
769
|
-
} else node.selected = Boolean(x);
|
|
770
|
-
};
|
|
771
|
-
if (isAtomHandle(v)) {
|
|
772
|
-
const elAny = el;
|
|
773
|
-
if (elAny.__ilhaVal === v) continue;
|
|
774
|
-
elAny.__ilhaVal = v;
|
|
775
|
-
const unsub = fiber.registry.subscribe(v.atom, setProp, { immediate: true });
|
|
776
|
-
fiber.holes.push({ dispose: unsub });
|
|
777
|
-
} else setProp(v);
|
|
778
|
-
continue;
|
|
779
|
-
}
|
|
780
|
-
if (typeof v === "function") continue;
|
|
781
|
-
if (v === false || v === null || v === void 0) el.removeAttribute(k);
|
|
782
|
-
else {
|
|
783
|
-
const str = v === true ? "" : String(v);
|
|
784
|
-
if (isUrlAttributeName(k) && !isSafeUrlAttrValue(el.tagName, k, str)) continue;
|
|
785
|
-
el.setAttribute(k, str);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
bindEvents(el, props, fiber);
|
|
789
|
-
const ref = props.ref;
|
|
790
|
-
if (typeof ref === "function") {
|
|
791
|
-
ref(el);
|
|
792
|
-
fiber.holes.push({ dispose: () => ref(null) });
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
const KEEP$1 = Symbol("keep");
|
|
796
|
-
function unwrap$1(value, keep) {
|
|
797
|
-
if (AsyncResult.isAsyncResult(value)) {
|
|
798
|
-
if (AsyncResult.isWaiting(value) && keep !== void 0) return KEEP$1;
|
|
799
|
-
if (AsyncResult.isFailure(value) && !AsyncResult.isWaiting(value)) return String(AsyncResult.error(value) ?? "error");
|
|
800
|
-
const v = AsyncResult.value(value);
|
|
801
|
-
if (v._tag === "Some") return v.value;
|
|
802
|
-
return "";
|
|
803
|
-
}
|
|
804
|
-
return value;
|
|
805
|
-
}
|
|
806
|
-
function paintHole$1(fiber, view) {
|
|
807
|
-
if (view === KEEP$1) return;
|
|
808
|
-
const frame = fiber.islandFrame ??= {
|
|
809
|
-
i: 0,
|
|
810
|
-
slots: []
|
|
811
|
-
};
|
|
812
|
-
frame.i = 0;
|
|
813
|
-
const list = Array.isArray(view) ? view : null;
|
|
814
|
-
if (list && list.length > 0 && list.every((v) => isVNode(v) && v.key != null)) {
|
|
815
|
-
keyedPaintHole$1(fiber, list);
|
|
816
|
-
return;
|
|
817
|
-
}
|
|
818
|
-
disposeHoles$1(fiber);
|
|
819
|
-
if (fiber.root instanceof Element) fiber.root.replaceChildren();
|
|
820
|
-
insert$1(fiber, materialize$1(view, fiber));
|
|
821
|
-
}
|
|
822
|
-
function keyedPaintHole$1(fiber, views) {
|
|
823
|
-
const prev = fiber.keyedHoles ?? /* @__PURE__ */ new Map();
|
|
824
|
-
const keep = new Set(views.map((v) => String(v.key)));
|
|
825
|
-
for (const [k, h] of prev) if (!keep.has(k)) closeFiber(h);
|
|
826
|
-
const next = /* @__PURE__ */ new Map();
|
|
827
|
-
const nodes = [];
|
|
828
|
-
for (const v of views) {
|
|
829
|
-
const k = String(v.key);
|
|
830
|
-
const reuse = prev.get(k);
|
|
831
|
-
if (reuse && !reuse.closed) {
|
|
832
|
-
next.set(k, reuse);
|
|
833
|
-
nodes.push(reuse.root);
|
|
834
|
-
continue;
|
|
835
|
-
}
|
|
836
|
-
const made = materialize$1(v, fiber);
|
|
837
|
-
const hole = fiber.keyedHoles?.get(k);
|
|
838
|
-
if (hole) next.set(k, hole);
|
|
839
|
-
nodes.push(...made);
|
|
840
|
-
}
|
|
841
|
-
fiber.keyedHoles = next;
|
|
842
|
-
if (fiber.root instanceof Element) fiber.root.replaceChildren();
|
|
843
|
-
insert$1(fiber, nodes);
|
|
844
|
-
}
|
|
845
|
-
function openHole$1(parent) {
|
|
846
|
-
const id = parent.runtime.nextHole();
|
|
847
|
-
const host = document.createElement("span");
|
|
848
|
-
host.setAttribute(SLOT_ATTR$1, String(id));
|
|
849
|
-
host.style.display = "contents";
|
|
850
|
-
const child = makeFiber(parent.runtime, host, (f, v) => {
|
|
851
|
-
disposeHoles$1(f);
|
|
852
|
-
if (f.root instanceof Element) f.root.replaceChildren();
|
|
853
|
-
insert$1(f, materialize$1(v, f));
|
|
854
|
-
}, { onFail: (e) => {
|
|
855
|
-
console.error(e);
|
|
856
|
-
paintHole$1(child, errorView$1(e));
|
|
857
|
-
} });
|
|
858
|
-
return {
|
|
859
|
-
fiber: child,
|
|
860
|
-
nodes: [host]
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function errorView$1(e) {
|
|
864
|
-
return {
|
|
865
|
-
$$ilha: 1,
|
|
866
|
-
type: "pre",
|
|
867
|
-
props: { "data-ilha-error": "" },
|
|
868
|
-
children: [failureMessage(e)]
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
function findReusableAtomHost$1(fiber, atom) {
|
|
872
|
-
for (const h of fiber.holes) if (h.atom === atom && h.host?.isConnected && h.holeFiber && !h.holeFiber.closed) return {
|
|
873
|
-
host: h.host,
|
|
874
|
-
hole: h.holeFiber
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
function refreshAtomHost(fiber, atom, host, hole) {
|
|
878
|
-
if (hole.closed || !host.isConnected) return;
|
|
879
|
-
const next = unwrap$1(fiber.registry.get(atom), void 0);
|
|
880
|
-
if (next === KEEP$1) return;
|
|
881
|
-
paintHole$1(hole, next);
|
|
882
|
-
}
|
|
883
|
-
function refreshAllAtomHosts(fiber) {
|
|
884
|
-
for (const h of fiber.holes) if (h.atom && h.host && h.holeFiber) refreshAtomHost(fiber, h.atom, h.host, h.holeFiber);
|
|
885
|
-
}
|
|
886
|
-
function pruneDisconnectedAtomHoles(fiber) {
|
|
887
|
-
fiber.holes = fiber.holes.filter((h) => {
|
|
888
|
-
if (!h.atom || !h.host || !h.holeFiber) return true;
|
|
889
|
-
if (h.host.isConnected) return true;
|
|
890
|
-
h.dispose();
|
|
891
|
-
return false;
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
function atomHostPlaceholder$1(host) {
|
|
895
|
-
const placeholder = document.createElement("span");
|
|
896
|
-
const slot = host.getAttribute(SLOT_ATTR$1);
|
|
897
|
-
if (slot !== null) placeholder.setAttribute(SLOT_ATTR$1, slot);
|
|
898
|
-
placeholder.style.display = "contents";
|
|
899
|
-
return placeholder;
|
|
900
|
-
}
|
|
901
|
-
function trackHole$1(parent, hole, extra, meta) {
|
|
902
|
-
parent.holes.push({
|
|
903
|
-
keepOnMorph: !!(meta?.atom && meta?.host) || !!meta?.keyed,
|
|
904
|
-
atom: meta?.atom,
|
|
905
|
-
host: meta?.host,
|
|
906
|
-
holeFiber: hole,
|
|
907
|
-
dispose() {
|
|
908
|
-
extra?.();
|
|
909
|
-
closeFiber(hole);
|
|
910
|
-
}
|
|
911
|
-
});
|
|
912
|
-
}
|
|
913
|
-
function materialize$1(view, fiber) {
|
|
914
|
-
if (skip$1(view)) return [];
|
|
915
|
-
if (typeof view === "string" || typeof view === "number" || typeof view === "bigint") return [document.createTextNode(String(view))];
|
|
916
|
-
if (isAtomHandle(view)) {
|
|
917
|
-
const reused = findReusableAtomHost$1(fiber, view.atom);
|
|
918
|
-
if (reused) return [atomHostPlaceholder$1(reused.host)];
|
|
919
|
-
const { fiber: hole, nodes } = openHole$1(fiber);
|
|
920
|
-
const host = nodes[0];
|
|
921
|
-
let unsub = () => {};
|
|
922
|
-
fiber.runtime.later(() => {
|
|
923
|
-
if (hole.closed) return;
|
|
924
|
-
let keep;
|
|
925
|
-
unsub = fiber.registry.subscribe(view.atom, (v) => {
|
|
926
|
-
if (hole.closed) return;
|
|
927
|
-
const next = unwrap$1(v, keep);
|
|
928
|
-
if (next === KEEP$1) return;
|
|
929
|
-
keep = next;
|
|
930
|
-
paintHole$1(hole, next);
|
|
931
|
-
}, { immediate: true });
|
|
932
|
-
});
|
|
933
|
-
trackHole$1(fiber, hole, () => unsub(), {
|
|
934
|
-
atom: view.atom,
|
|
935
|
-
host
|
|
936
|
-
});
|
|
937
|
-
return nodes;
|
|
938
|
-
}
|
|
939
|
-
if (Stream.isStream(view)) {
|
|
940
|
-
const { fiber: hole, nodes } = openHole$1(fiber);
|
|
941
|
-
const src = fiber.runtime.ssr ? view.pipe(Stream.take(1)) : view;
|
|
942
|
-
hole.run(Stream.runForEach(src, (v) => Effect.sync(() => {
|
|
943
|
-
if (!hole.closed) paintHole$1(hole, v);
|
|
944
|
-
})).pipe(Effect.catch((e) => Effect.sync(() => {
|
|
945
|
-
if (!hole.closed) paintHole$1(hole, String(e));
|
|
946
|
-
}))), fiber.runtime.ssr ? () => {} : void 0);
|
|
947
|
-
trackHole$1(fiber, hole);
|
|
948
|
-
return nodes;
|
|
949
|
-
}
|
|
950
|
-
if (isSetupFn(view)) {
|
|
951
|
-
const { fiber: hole, nodes } = openHole$1(fiber);
|
|
952
|
-
fiber.runtime.later(() => {
|
|
953
|
-
if (!hole.closed) runSetup(hole, view);
|
|
954
|
-
});
|
|
955
|
-
trackHole$1(fiber, hole);
|
|
956
|
-
return nodes;
|
|
957
|
-
}
|
|
958
|
-
if (isVNode(view)) {
|
|
959
|
-
if (view.type === Fragment) return view.children.flatMap((c) => materialize$1(c, fiber));
|
|
960
|
-
if (typeof view.type === "function") {
|
|
961
|
-
const props = {
|
|
962
|
-
...view.props,
|
|
963
|
-
children: view.children
|
|
964
|
-
};
|
|
965
|
-
const type = view.type;
|
|
966
|
-
if (type[ISLAND$1] === true) {
|
|
967
|
-
const frame = fiber.islandFrame ??= {
|
|
968
|
-
i: 0,
|
|
969
|
-
slots: []
|
|
970
|
-
};
|
|
971
|
-
const i = frame.i++;
|
|
972
|
-
const existing = frame.slots[i];
|
|
973
|
-
if (existing && existing.type === type && existing.host.isConnected && typeof existing.updateProps === "function") {
|
|
974
|
-
existing.updateProps(props);
|
|
975
|
-
return [existing.host];
|
|
976
|
-
}
|
|
977
|
-
existing?.unmount?.();
|
|
978
|
-
const tag = typeof type[ISLAND_SLOT_TAG$1] === "string" ? type[ISLAND_SLOT_TAG$1] : "div";
|
|
979
|
-
const el = document.createElement(tag);
|
|
980
|
-
el.setAttribute("data-ilha", "");
|
|
981
|
-
const mountFn = type[ISLAND_MOUNT_INTERNAL$1];
|
|
982
|
-
if (typeof mountFn === "function") {
|
|
983
|
-
const handle = mountFn(el, props);
|
|
984
|
-
const slot = {
|
|
985
|
-
type,
|
|
986
|
-
host: el,
|
|
987
|
-
updateProps: handle?.updateProps,
|
|
988
|
-
unmount: handle?.unmount
|
|
989
|
-
};
|
|
990
|
-
frame.slots[i] = slot;
|
|
991
|
-
fiber.holes.push({
|
|
992
|
-
keepOnMorph: true,
|
|
993
|
-
dispose: () => {
|
|
994
|
-
handle?.unmount?.();
|
|
995
|
-
if (frame.slots[i] === slot) frame.slots[i] = void 0;
|
|
996
|
-
}
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
return [el];
|
|
1000
|
-
}
|
|
1001
|
-
const k = view.key == null ? void 0 : String(view.key);
|
|
1002
|
-
const reuse = k ? fiber.keyedHoles?.get(k) : void 0;
|
|
1003
|
-
if (reuse && !reuse.closed) {
|
|
1004
|
-
if (reuse.propsBox) reuse.propsBox.current = props;
|
|
1005
|
-
const next = withFiber(fiber, () => type(reuse.propsBox?.current ?? props));
|
|
1006
|
-
if (next && typeof next.then !== "function" && !isSetupFn(next)) reuse.paint(next);
|
|
1007
|
-
return [reuse.root];
|
|
1008
|
-
}
|
|
1009
|
-
const { fiber: hole, nodes } = openHole$1(fiber);
|
|
1010
|
-
hole.propsBox = { current: props };
|
|
1011
|
-
if (k) {
|
|
1012
|
-
fiber.keyedHoles ??= /* @__PURE__ */ new Map();
|
|
1013
|
-
fiber.keyedHoles.set(k, hole);
|
|
1014
|
-
}
|
|
1015
|
-
fiber.runtime.later(() => {
|
|
1016
|
-
if (!hole.closed) runSetup(hole, () => type(hole.propsBox.current));
|
|
1017
|
-
});
|
|
1018
|
-
trackHole$1(fiber, hole, void 0, k ? { keyed: true } : void 0);
|
|
1019
|
-
return nodes;
|
|
1020
|
-
}
|
|
1021
|
-
const el = document.createElement(view.type);
|
|
1022
|
-
if (view.key != null) el.setAttribute(KEY_ATTR$1, String(view.key));
|
|
1023
|
-
applyProps$1(el, view.props, fiber);
|
|
1024
|
-
fiber.keyedHoles ??= /* @__PURE__ */ new Map();
|
|
1025
|
-
const childFiber = {
|
|
1026
|
-
...fiber,
|
|
1027
|
-
root: el,
|
|
1028
|
-
holes: fiber.holes,
|
|
1029
|
-
keyedHoles: fiber.keyedHoles
|
|
1030
|
-
};
|
|
1031
|
-
for (const c of view.children) for (const n of materialize$1(c, childFiber)) el.appendChild(n);
|
|
1032
|
-
return [el];
|
|
1033
|
-
}
|
|
1034
|
-
if (Array.isArray(view) || view && typeof view === "object" && Symbol.iterator in Object(view)) return [...view].flatMap((c) => materialize$1(c, fiber));
|
|
1035
|
-
return [document.createTextNode(String(view))];
|
|
1036
|
-
}
|
|
1037
|
-
function canHydrate(fiber, view) {
|
|
1038
|
-
if (!isVNode(view) || typeof view.type !== "string") return false;
|
|
1039
|
-
const el = fiber.root.firstElementChild;
|
|
1040
|
-
return !!el && el.tagName === view.type.toUpperCase();
|
|
1041
|
-
}
|
|
1042
|
-
function paint$1(fiber, view) {
|
|
1043
|
-
fiber.islandFrame ??= {
|
|
1044
|
-
i: 0,
|
|
1045
|
-
slots: []
|
|
1046
|
-
};
|
|
1047
|
-
if (fiber.hydrate) {
|
|
1048
|
-
if (canHydrate(fiber, view)) {
|
|
1049
|
-
const el = fiber.root.firstElementChild;
|
|
1050
|
-
fiber.hydrate = false;
|
|
1051
|
-
fiber.liveEl = el;
|
|
1052
|
-
applyProps$1(el, view.props, fiber);
|
|
1053
|
-
const childFiber = {
|
|
1054
|
-
...fiber,
|
|
1055
|
-
root: el,
|
|
1056
|
-
holes: fiber.holes
|
|
1057
|
-
};
|
|
1058
|
-
el.replaceChildren();
|
|
1059
|
-
for (const c of view.children) for (const n of materialize$1(c, childFiber)) el.appendChild(n);
|
|
1060
|
-
return;
|
|
1061
|
-
} else {
|
|
1062
|
-
console.warn("[ilha] hydrate mismatch, full mount");
|
|
1063
|
-
fiber.hydrate = false;
|
|
1064
|
-
if (fiber.root instanceof Element) fiber.root.replaceChildren();
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
if (fiber.liveEl && isVNode(view) && typeof view.type === "string" && fiber.liveEl.localName === view.type) {
|
|
1068
|
-
disposeHoles$1(fiber, { morph: true });
|
|
1069
|
-
applyProps$1(fiber.liveEl, view.props, fiber);
|
|
1070
|
-
const tmp = document.createElement(fiber.liveEl.localName);
|
|
1071
|
-
for (const c of view.children) for (const n of materialize$1(c, fiber)) tmp.appendChild(n);
|
|
1072
|
-
morphInner(fiber.liveEl, tmp);
|
|
1073
|
-
refreshAllAtomHosts(fiber);
|
|
1074
|
-
pruneDisconnectedAtomHoles(fiber);
|
|
1075
|
-
return;
|
|
1076
|
-
}
|
|
1077
|
-
disposeHoles$1(fiber);
|
|
1078
|
-
if (fiber.root instanceof Element && fiber.root.childNodes.length > 0) {
|
|
1079
|
-
const tmp = document.createElement("div");
|
|
1080
|
-
for (const n of materialize$1(view, fiber)) tmp.appendChild(n);
|
|
1081
|
-
morphInner(fiber.root, tmp);
|
|
1082
|
-
const first = fiber.root.firstElementChild;
|
|
1083
|
-
if (first) fiber.liveEl = first;
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
insert$1(fiber, materialize$1(view, fiber));
|
|
1087
|
-
const first = fiber.root instanceof Element ? fiber.root.firstElementChild : null;
|
|
1088
|
-
if (first) fiber.liveEl = first;
|
|
1089
|
-
}
|
|
1090
|
-
function paintError$1(fiber, e) {
|
|
1091
|
-
console.error(e);
|
|
1092
|
-
paint$1(fiber, errorView$1(e));
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
//#endregion
|
|
1096
|
-
//#region src/snapshot.ts
|
|
1097
|
-
const MAX_SNAPSHOT_CHARS = 262144;
|
|
1098
|
-
const MAX_SNAPSHOT_DEPTH = 32;
|
|
1099
|
-
const UNSAFE_SNAPSHOT_KEYS = /* @__PURE__ */ new Set([
|
|
1100
|
-
"__proto__",
|
|
1101
|
-
"constructor",
|
|
1102
|
-
"prototype"
|
|
1103
|
-
]);
|
|
1104
|
-
function exceedsMaxDepth(value, depth) {
|
|
1105
|
-
if (depth > MAX_SNAPSHOT_DEPTH) return true;
|
|
1106
|
-
if (value === null || typeof value !== "object") return false;
|
|
1107
|
-
if (Array.isArray(value)) {
|
|
1108
|
-
for (const item of value) if (exceedsMaxDepth(item, depth + 1)) return true;
|
|
1109
|
-
return false;
|
|
1110
|
-
}
|
|
1111
|
-
for (const key of Object.keys(value)) if (exceedsMaxDepth(value[key], depth + 1)) return true;
|
|
1112
|
-
return false;
|
|
1113
|
-
}
|
|
1114
|
-
function stripUnsafeKeys(value) {
|
|
1115
|
-
if (value === null || typeof value !== "object") return;
|
|
1116
|
-
if (Array.isArray(value)) {
|
|
1117
|
-
for (const item of value) stripUnsafeKeys(item);
|
|
1118
|
-
return;
|
|
1119
|
-
}
|
|
1120
|
-
for (const key of Object.getOwnPropertyNames(value)) if (UNSAFE_SNAPSHOT_KEYS.has(key)) delete value[key];
|
|
1121
|
-
else stripUnsafeKeys(value[key]);
|
|
1122
|
-
}
|
|
1123
|
-
function safeParseSnapshot(raw) {
|
|
1124
|
-
if (raw.length > MAX_SNAPSHOT_CHARS) return void 0;
|
|
1125
|
-
let parsed;
|
|
1126
|
-
try {
|
|
1127
|
-
parsed = JSON.parse(raw);
|
|
1128
|
-
} catch {
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
|
-
if (exceedsMaxDepth(parsed, 1)) return void 0;
|
|
1132
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
1133
|
-
stripUnsafeKeys(parsed);
|
|
1134
|
-
return parsed;
|
|
1135
|
-
}
|
|
1136
|
-
function encodeSnapshot(values) {
|
|
1137
|
-
return JSON.stringify({ v: values });
|
|
1138
|
-
}
|
|
1139
|
-
function decodeSnapshot(raw) {
|
|
1140
|
-
const parsed = safeParseSnapshot(raw);
|
|
1141
|
-
return Array.isArray(parsed?.v) ? parsed.v : void 0;
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
//#endregion
|
|
1145
|
-
//#region src/ssr-dom.ts
|
|
1146
|
-
const VOID = /* @__PURE__ */ new Set([
|
|
1147
|
-
"area",
|
|
1148
|
-
"base",
|
|
1149
|
-
"br",
|
|
1150
|
-
"col",
|
|
1151
|
-
"embed",
|
|
1152
|
-
"hr",
|
|
1153
|
-
"img",
|
|
1154
|
-
"input",
|
|
1155
|
-
"link",
|
|
1156
|
-
"meta",
|
|
1157
|
-
"param",
|
|
1158
|
-
"source",
|
|
1159
|
-
"track",
|
|
1160
|
-
"wbr"
|
|
1161
|
-
]);
|
|
1162
|
-
/** Tags whose children are raw text — do not HTML-escape content. */
|
|
1163
|
-
const RAW_TEXT = /* @__PURE__ */ new Set(["script", "style"]);
|
|
1164
|
-
function escapeText(s) {
|
|
1165
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1166
|
-
}
|
|
1167
|
-
function escapeAttr(s) {
|
|
1168
|
-
return escapeText(s).replace(/"/g, """);
|
|
1169
|
-
}
|
|
1170
|
-
function createSsrText(text) {
|
|
1171
|
-
return {
|
|
1172
|
-
kind: "text",
|
|
1173
|
-
text
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
function createSsrElement(tag) {
|
|
1177
|
-
const lower = tag.toLowerCase();
|
|
1178
|
-
const children = [];
|
|
1179
|
-
const el = {
|
|
1180
|
-
kind: "element",
|
|
1181
|
-
tag: lower,
|
|
1182
|
-
attrs: /* @__PURE__ */ new Map(),
|
|
1183
|
-
children,
|
|
1184
|
-
isConnected: true,
|
|
1185
|
-
tagName: lower.toUpperCase(),
|
|
1186
|
-
localName: lower,
|
|
1187
|
-
setAttribute(name, value) {
|
|
1188
|
-
el.attrs.set(name, value);
|
|
1189
|
-
},
|
|
1190
|
-
getAttribute(name) {
|
|
1191
|
-
return el.attrs.has(name) ? el.attrs.get(name) : null;
|
|
1192
|
-
},
|
|
1193
|
-
removeAttribute(name) {
|
|
1194
|
-
el.attrs.delete(name);
|
|
1195
|
-
},
|
|
1196
|
-
hasAttribute(name) {
|
|
1197
|
-
return el.attrs.has(name);
|
|
1198
|
-
},
|
|
1199
|
-
replaceChildren(...nodes) {
|
|
1200
|
-
children.length = 0;
|
|
1201
|
-
children.push(...nodes);
|
|
1202
|
-
},
|
|
1203
|
-
appendChild(node) {
|
|
1204
|
-
children.push(node);
|
|
1205
|
-
},
|
|
1206
|
-
get textContent() {
|
|
1207
|
-
return children.map((n) => n.kind === "text" ? n.text : n.textContent).join("");
|
|
1208
|
-
},
|
|
1209
|
-
set textContent(value) {
|
|
1210
|
-
children.length = 0;
|
|
1211
|
-
children.push(createSsrText(value));
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
return el;
|
|
1215
|
-
}
|
|
1216
|
-
function createSsrRoot() {
|
|
1217
|
-
const children = [];
|
|
1218
|
-
return {
|
|
1219
|
-
kind: "root",
|
|
1220
|
-
children,
|
|
1221
|
-
appendChild(node) {
|
|
1222
|
-
children.push(node);
|
|
1223
|
-
},
|
|
1224
|
-
replaceChildren() {
|
|
1225
|
-
children.length = 0;
|
|
1226
|
-
},
|
|
1227
|
-
get innerHTML() {
|
|
1228
|
-
return children.map(serializeNode).join("");
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
}
|
|
1232
|
-
function serializeRawText(tag, text) {
|
|
1233
|
-
if (new RegExp(`</${tag}\\b`, "i").test(text)) throw new Error(`ilha: unsafe raw text in <${tag}> (contains "</${tag}")`);
|
|
1234
|
-
return text;
|
|
1235
|
-
}
|
|
1236
|
-
function serializeNode(node) {
|
|
1237
|
-
if (node.kind === "text") return escapeText(node.text);
|
|
1238
|
-
const parts = [];
|
|
1239
|
-
for (const [name, value] of node.attrs) parts.push(`${name}="${escapeAttr(value)}"`);
|
|
1240
|
-
const attr = parts.length > 0 ? ` ${parts.join(" ")}` : "";
|
|
1241
|
-
const tag = node.tag;
|
|
1242
|
-
if (VOID.has(tag)) return `<${tag}${attr}>`;
|
|
1243
|
-
if (RAW_TEXT.has(tag)) return `<${tag}${attr}>${serializeRawText(tag, node.textContent)}</${tag}>`;
|
|
1244
|
-
return `<${tag}${attr}>${node.children.map(serializeNode).join("")}</${tag}>`;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
//#endregion
|
|
1248
|
-
//#region src/ssr-paint.ts
|
|
1249
|
-
const KEY_ATTR = "data-ilha-key";
|
|
1250
|
-
const SLOT_ATTR = "data-ilha-slot";
|
|
1251
|
-
const ISLAND = Symbol.for("ilha.island");
|
|
1252
|
-
const ISLAND_MOUNT_INTERNAL = Symbol.for("ilha.islandMountInternal");
|
|
1253
|
-
const ISLAND_SLOT_TAG = Symbol.for("ilha.islandSlotTag");
|
|
1254
|
-
function insert(fiber, nodes) {
|
|
1255
|
-
const root = fiber.root;
|
|
1256
|
-
for (const n of nodes) root.appendChild(n);
|
|
1257
|
-
}
|
|
1258
|
-
function disposeHoles(fiber) {
|
|
1259
|
-
for (const h of fiber.holes) h.dispose();
|
|
1260
|
-
fiber.holes = [];
|
|
1261
|
-
}
|
|
1262
|
-
function skip(x) {
|
|
1263
|
-
return x === null || x === void 0 || typeof x === "boolean";
|
|
1264
|
-
}
|
|
1265
|
-
function bindSsrEvents(el, props, fiber) {
|
|
1266
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1267
|
-
for (const key of Object.keys(props)) {
|
|
1268
|
-
const type = eventTypeFromProp(key);
|
|
1269
|
-
if (!type || seen.has(type)) continue;
|
|
1270
|
-
seen.add(type);
|
|
1271
|
-
const fn = props[key];
|
|
1272
|
-
if (typeof fn !== "function") continue;
|
|
1273
|
-
const branded = fn[Symbol.for("ilha.actionCall")];
|
|
1274
|
-
const rec = branded?.k ? {
|
|
1275
|
-
k: branded.k,
|
|
1276
|
-
a: branded.a ?? []
|
|
1277
|
-
} : void 0;
|
|
1278
|
-
if (!rec) continue;
|
|
1279
|
-
const id = `${type}:${fiber.runtime.ssrEventI++}`;
|
|
1280
|
-
fiber.runtime.ssrActions[id] = rec;
|
|
1281
|
-
const existing = el.getAttribute("data-ilha-on");
|
|
1282
|
-
el.setAttribute("data-ilha-on", existing ? `${existing},${id}` : id);
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
function applyProps(el, props, fiber) {
|
|
1286
|
-
for (const [k, v] of Object.entries(props)) {
|
|
1287
|
-
if (k === "children" || k === "key" || k === "ref") continue;
|
|
1288
|
-
if (k === "className") {
|
|
1289
|
-
el.setAttribute("class", String(v ?? ""));
|
|
1290
|
-
continue;
|
|
1291
|
-
}
|
|
1292
|
-
if (k === "htmlFor") {
|
|
1293
|
-
el.setAttribute("for", String(v ?? ""));
|
|
1294
|
-
continue;
|
|
1295
|
-
}
|
|
1296
|
-
if (k.toLowerCase() === "srcdoc") continue;
|
|
1297
|
-
if (k === "style" && v != null && v !== false) {
|
|
1298
|
-
const css = typeof v === "string" || typeof v === "object" ? serializeStyleAttr(v) : "";
|
|
1299
|
-
if (css) el.setAttribute("style", css);
|
|
1300
|
-
continue;
|
|
1301
|
-
}
|
|
1302
|
-
if (isEventProp(k)) continue;
|
|
1303
|
-
if (/^on[A-Z]/.test(k)) continue;
|
|
1304
|
-
if (k === "value" || k === "checked" || k === "selected") {
|
|
1305
|
-
const setProp = (x) => {
|
|
1306
|
-
if (k === "value") el.setAttribute("value", String(x ?? ""));
|
|
1307
|
-
else if (k === "checked") {
|
|
1308
|
-
if (x) el.setAttribute("checked", "");
|
|
1309
|
-
else el.removeAttribute("checked");
|
|
1310
|
-
} else if (x) el.setAttribute("selected", "");
|
|
1311
|
-
else el.removeAttribute("selected");
|
|
1312
|
-
};
|
|
1313
|
-
if (isAtomHandle(v)) {
|
|
1314
|
-
const unsub = fiber.registry.subscribe(v.atom, setProp, { immediate: true });
|
|
1315
|
-
fiber.holes.push({ dispose: unsub });
|
|
1316
|
-
} else setProp(v);
|
|
1317
|
-
continue;
|
|
1318
|
-
}
|
|
1319
|
-
if (typeof v === "function") continue;
|
|
1320
|
-
if (v === false || v === null || v === void 0) el.removeAttribute(k);
|
|
1321
|
-
else {
|
|
1322
|
-
const str = v === true ? "" : String(v);
|
|
1323
|
-
if (isUrlAttributeName(k) && !isSafeUrlAttrValue(el.tagName, k, str)) continue;
|
|
1324
|
-
el.setAttribute(k, str);
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
bindSsrEvents(el, props, fiber);
|
|
1328
|
-
const ref = props.ref;
|
|
1329
|
-
if (typeof ref === "function") {
|
|
1330
|
-
ref(el);
|
|
1331
|
-
fiber.holes.push({ dispose: () => ref(null) });
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
const KEEP = Symbol("keep");
|
|
1335
|
-
function unwrap(value, keep) {
|
|
1336
|
-
if (AsyncResult.isAsyncResult(value)) {
|
|
1337
|
-
if (AsyncResult.isWaiting(value) && keep !== void 0) return KEEP;
|
|
1338
|
-
if (AsyncResult.isFailure(value) && !AsyncResult.isWaiting(value)) return String(AsyncResult.error(value) ?? "error");
|
|
1339
|
-
const v = AsyncResult.value(value);
|
|
1340
|
-
if (v._tag === "Some") return v.value;
|
|
1341
|
-
return "";
|
|
1342
|
-
}
|
|
1343
|
-
return value;
|
|
1344
|
-
}
|
|
1345
|
-
function paintHole(fiber, view) {
|
|
1346
|
-
if (view === KEEP) return;
|
|
1347
|
-
const frame = fiber.islandFrame ??= {
|
|
1348
|
-
i: 0,
|
|
1349
|
-
slots: []
|
|
1350
|
-
};
|
|
1351
|
-
frame.i = 0;
|
|
1352
|
-
const list = Array.isArray(view) ? view : null;
|
|
1353
|
-
if (list && list.length > 0 && list.every((v) => isVNode(v) && v.key != null)) {
|
|
1354
|
-
keyedPaintHole(fiber, list);
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
disposeHoles(fiber);
|
|
1358
|
-
fiber.root.replaceChildren();
|
|
1359
|
-
insert(fiber, materialize(view, fiber));
|
|
1360
|
-
}
|
|
1361
|
-
function keyedPaintHole(fiber, views) {
|
|
1362
|
-
const prev = fiber.keyedHoles ?? /* @__PURE__ */ new Map();
|
|
1363
|
-
const keep = new Set(views.map((v) => String(v.key)));
|
|
1364
|
-
for (const [k, h] of prev) if (!keep.has(k)) closeFiber(h);
|
|
1365
|
-
const next = /* @__PURE__ */ new Map();
|
|
1366
|
-
const nodes = [];
|
|
1367
|
-
for (const v of views) {
|
|
1368
|
-
const k = String(v.key);
|
|
1369
|
-
const reuse = prev.get(k);
|
|
1370
|
-
if (reuse && !reuse.closed) {
|
|
1371
|
-
next.set(k, reuse);
|
|
1372
|
-
nodes.push(reuse.root);
|
|
1373
|
-
continue;
|
|
1374
|
-
}
|
|
1375
|
-
const made = materialize(v, fiber);
|
|
1376
|
-
const hole = fiber.keyedHoles?.get(k);
|
|
1377
|
-
if (hole) next.set(k, hole);
|
|
1378
|
-
nodes.push(...made);
|
|
1379
|
-
}
|
|
1380
|
-
fiber.keyedHoles = next;
|
|
1381
|
-
fiber.root.replaceChildren();
|
|
1382
|
-
insert(fiber, nodes);
|
|
1383
|
-
}
|
|
1384
|
-
function openHole(parent) {
|
|
1385
|
-
const id = parent.runtime.nextHole();
|
|
1386
|
-
const host = createSsrElement("span");
|
|
1387
|
-
host.setAttribute(SLOT_ATTR, String(id));
|
|
1388
|
-
host.setAttribute("style", "display:contents");
|
|
1389
|
-
const child = makeFiber(parent.runtime, host, paint, { onFail: (e) => {
|
|
1390
|
-
console.error(e);
|
|
1391
|
-
paintHole(child, errorView(e));
|
|
1392
|
-
} });
|
|
1393
|
-
return {
|
|
1394
|
-
fiber: child,
|
|
1395
|
-
nodes: [host]
|
|
1396
|
-
};
|
|
1397
|
-
}
|
|
1398
|
-
function errorView(e) {
|
|
1399
|
-
return {
|
|
1400
|
-
$$ilha: 1,
|
|
1401
|
-
type: "pre",
|
|
1402
|
-
props: { "data-ilha-error": "" },
|
|
1403
|
-
children: [failureMessage(e)]
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
function findReusableAtomHost(fiber, atom) {
|
|
1407
|
-
for (const h of fiber.holes) {
|
|
1408
|
-
const host = h.host;
|
|
1409
|
-
if (h.atom === atom && host?.isConnected && h.holeFiber && !h.holeFiber.closed) return {
|
|
1410
|
-
host,
|
|
1411
|
-
hole: h.holeFiber
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
function atomHostPlaceholder(host) {
|
|
1416
|
-
const placeholder = createSsrElement("span");
|
|
1417
|
-
const slot = host.getAttribute(SLOT_ATTR);
|
|
1418
|
-
if (slot !== null) placeholder.setAttribute(SLOT_ATTR, slot);
|
|
1419
|
-
placeholder.setAttribute("style", "display:contents");
|
|
1420
|
-
return placeholder;
|
|
1421
|
-
}
|
|
1422
|
-
function trackHole(parent, hole, extra, meta) {
|
|
1423
|
-
parent.holes.push({
|
|
1424
|
-
keepOnMorph: !!(meta?.atom && meta?.host) || !!meta?.keyed,
|
|
1425
|
-
atom: meta?.atom,
|
|
1426
|
-
host: meta?.host,
|
|
1427
|
-
holeFiber: hole,
|
|
1428
|
-
dispose() {
|
|
1429
|
-
extra?.();
|
|
1430
|
-
if (meta?.host) meta.host.isConnected = false;
|
|
1431
|
-
closeFiber(hole);
|
|
1432
|
-
}
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
function materialize(view, fiber) {
|
|
1436
|
-
if (skip(view)) return [];
|
|
1437
|
-
if (typeof view === "string" || typeof view === "number" || typeof view === "bigint") return [createSsrText(String(view))];
|
|
1438
|
-
if (isAtomHandle(view)) {
|
|
1439
|
-
const reused = findReusableAtomHost(fiber, view.atom);
|
|
1440
|
-
if (reused) return [atomHostPlaceholder(reused.host)];
|
|
1441
|
-
const { fiber: hole, nodes } = openHole(fiber);
|
|
1442
|
-
const host = nodes[0];
|
|
1443
|
-
let unsub = () => {};
|
|
1444
|
-
fiber.runtime.later(() => {
|
|
1445
|
-
if (hole.closed) return;
|
|
1446
|
-
let keep;
|
|
1447
|
-
unsub = fiber.registry.subscribe(view.atom, (v) => {
|
|
1448
|
-
if (hole.closed) return;
|
|
1449
|
-
const next = unwrap(v, keep);
|
|
1450
|
-
if (next === KEEP) return;
|
|
1451
|
-
keep = next;
|
|
1452
|
-
paintHole(hole, next);
|
|
1453
|
-
}, { immediate: true });
|
|
1454
|
-
});
|
|
1455
|
-
trackHole(fiber, hole, () => unsub(), {
|
|
1456
|
-
atom: view.atom,
|
|
1457
|
-
host
|
|
1458
|
-
});
|
|
1459
|
-
return nodes;
|
|
1460
|
-
}
|
|
1461
|
-
if (Stream.isStream(view)) {
|
|
1462
|
-
const { fiber: hole, nodes } = openHole(fiber);
|
|
1463
|
-
hole.run(Stream.runForEach(view.pipe(Stream.take(1)), (v) => Effect.sync(() => {
|
|
1464
|
-
if (!hole.closed) paintHole(hole, v);
|
|
1465
|
-
})).pipe(Effect.catch((e) => Effect.sync(() => {
|
|
1466
|
-
if (!hole.closed) paintHole(hole, String(e));
|
|
1467
|
-
}))), () => {});
|
|
1468
|
-
trackHole(fiber, hole);
|
|
1469
|
-
return nodes;
|
|
1470
|
-
}
|
|
1471
|
-
if (isSetupFn(view)) {
|
|
1472
|
-
const { fiber: hole, nodes } = openHole(fiber);
|
|
1473
|
-
fiber.runtime.later(() => {
|
|
1474
|
-
if (!hole.closed) runSetup(hole, view);
|
|
1475
|
-
});
|
|
1476
|
-
trackHole(fiber, hole);
|
|
1477
|
-
return nodes;
|
|
1478
|
-
}
|
|
1479
|
-
if (isVNode(view)) {
|
|
1480
|
-
if (view.type === Fragment) return view.children.flatMap((c) => materialize(c, fiber));
|
|
1481
|
-
if (typeof view.type === "function") {
|
|
1482
|
-
const props = {
|
|
1483
|
-
...view.props,
|
|
1484
|
-
children: view.children
|
|
1485
|
-
};
|
|
1486
|
-
const type = view.type;
|
|
1487
|
-
if (type[ISLAND] === true) {
|
|
1488
|
-
const frame = fiber.islandFrame ??= {
|
|
1489
|
-
i: 0,
|
|
1490
|
-
slots: []
|
|
1491
|
-
};
|
|
1492
|
-
const i = frame.i++;
|
|
1493
|
-
const existing = frame.slots[i];
|
|
1494
|
-
if (existing && existing.type === type && existing.host.isConnected && typeof existing.updateProps === "function") {
|
|
1495
|
-
existing.updateProps(props);
|
|
1496
|
-
return [existing.host];
|
|
1497
|
-
}
|
|
1498
|
-
existing?.unmount?.();
|
|
1499
|
-
const tag = typeof type[ISLAND_SLOT_TAG] === "string" ? type[ISLAND_SLOT_TAG] : "div";
|
|
1500
|
-
const el = createSsrElement(tag);
|
|
1501
|
-
el.setAttribute("data-ilha", "");
|
|
1502
|
-
const mountFn = type[ISLAND_MOUNT_INTERNAL];
|
|
1503
|
-
if (typeof mountFn === "function") {
|
|
1504
|
-
const handle = mountFn(el, props);
|
|
1505
|
-
const slot = {
|
|
1506
|
-
type,
|
|
1507
|
-
host: el,
|
|
1508
|
-
updateProps: handle?.updateProps,
|
|
1509
|
-
unmount: handle?.unmount
|
|
1510
|
-
};
|
|
1511
|
-
frame.slots[i] = slot;
|
|
1512
|
-
fiber.holes.push({
|
|
1513
|
-
keepOnMorph: true,
|
|
1514
|
-
dispose: () => {
|
|
1515
|
-
el.isConnected = false;
|
|
1516
|
-
handle?.unmount?.();
|
|
1517
|
-
if (frame.slots[i] === slot) frame.slots[i] = void 0;
|
|
1518
|
-
}
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
return [el];
|
|
1522
|
-
}
|
|
1523
|
-
const k = view.key == null ? void 0 : String(view.key);
|
|
1524
|
-
const reuse = k ? fiber.keyedHoles?.get(k) : void 0;
|
|
1525
|
-
if (reuse && !reuse.closed) {
|
|
1526
|
-
if (reuse.propsBox) reuse.propsBox.current = props;
|
|
1527
|
-
const next = withFiber(fiber, () => type(reuse.propsBox?.current ?? props));
|
|
1528
|
-
if (next && typeof next.then !== "function" && !isSetupFn(next)) reuse.paint(next);
|
|
1529
|
-
return [reuse.root];
|
|
1530
|
-
}
|
|
1531
|
-
const { fiber: hole, nodes } = openHole(fiber);
|
|
1532
|
-
hole.propsBox = { current: props };
|
|
1533
|
-
if (k) {
|
|
1534
|
-
fiber.keyedHoles ??= /* @__PURE__ */ new Map();
|
|
1535
|
-
fiber.keyedHoles.set(k, hole);
|
|
1536
|
-
}
|
|
1537
|
-
fiber.runtime.later(() => {
|
|
1538
|
-
if (!hole.closed) runSetup(hole, () => type(hole.propsBox.current));
|
|
1539
|
-
});
|
|
1540
|
-
trackHole(fiber, hole, void 0, k ? { keyed: true } : void 0);
|
|
1541
|
-
return nodes;
|
|
1542
|
-
}
|
|
1543
|
-
const el = createSsrElement(view.type);
|
|
1544
|
-
if (view.key != null) el.setAttribute(KEY_ATTR, String(view.key));
|
|
1545
|
-
applyProps(el, view.props, fiber);
|
|
1546
|
-
fiber.keyedHoles ??= /* @__PURE__ */ new Map();
|
|
1547
|
-
const childFiber = {
|
|
1548
|
-
...fiber,
|
|
1549
|
-
root: el,
|
|
1550
|
-
holes: fiber.holes,
|
|
1551
|
-
keyedHoles: fiber.keyedHoles
|
|
1552
|
-
};
|
|
1553
|
-
for (const c of view.children) for (const n of materialize(c, childFiber)) el.appendChild(n);
|
|
1554
|
-
return [el];
|
|
1555
|
-
}
|
|
1556
|
-
if (Array.isArray(view) || view && typeof view === "object" && Symbol.iterator in Object(view)) return [...view].flatMap((c) => materialize(c, fiber));
|
|
1557
|
-
return [createSsrText(String(view))];
|
|
1558
|
-
}
|
|
1559
|
-
function paint(fiber, view) {
|
|
1560
|
-
fiber.islandFrame ??= {
|
|
1561
|
-
i: 0,
|
|
1562
|
-
slots: []
|
|
1563
|
-
};
|
|
1564
|
-
disposeHoles(fiber);
|
|
1565
|
-
fiber.root.replaceChildren();
|
|
1566
|
-
insert(fiber, materialize(view, fiber));
|
|
1567
|
-
}
|
|
1568
|
-
function paintError(fiber, e) {
|
|
1569
|
-
console.error(e);
|
|
1570
|
-
paint(fiber, errorView(e));
|
|
1571
|
-
}
|
|
1572
|
-
function attachSsr(fn, opts) {
|
|
1573
|
-
const root = createSsrRoot();
|
|
1574
|
-
const runtime = makeRuntime({
|
|
1575
|
-
ssr: true,
|
|
1576
|
-
ssrCapture: opts?.ssrCapture === true
|
|
1577
|
-
});
|
|
1578
|
-
let resolve;
|
|
1579
|
-
const ready = new Promise((r) => {
|
|
1580
|
-
resolve = r;
|
|
1581
|
-
});
|
|
1582
|
-
const fiber = makeFiber(runtime, root, paint, { onFail: (e) => {
|
|
1583
|
-
opts?.onError?.(e);
|
|
1584
|
-
paintError(fiber, e);
|
|
1585
|
-
resolve();
|
|
1586
|
-
} });
|
|
1587
|
-
runtime.begin();
|
|
1588
|
-
runtime.setIdle(resolve);
|
|
1589
|
-
runSetup(fiber, fn);
|
|
1590
|
-
runtime.end();
|
|
1591
|
-
return {
|
|
1592
|
-
root,
|
|
1593
|
-
ready,
|
|
1594
|
-
runtime,
|
|
1595
|
-
unmount() {
|
|
1596
|
-
closeFiber(fiber);
|
|
1597
|
-
runtime.close();
|
|
1598
|
-
root.replaceChildren();
|
|
1599
|
-
}
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
//#endregion
|
|
1604
|
-
//#region src/mount.ts
|
|
1605
|
-
function readHydrate(el) {
|
|
1606
|
-
const raw = (el.hasAttribute("data-ilha") ? el : el.querySelector("[data-ilha]"))?.getAttribute("data-ilha-state");
|
|
1607
|
-
if (raw) return decodeSnapshot(raw);
|
|
1608
|
-
const first = el.firstElementChild;
|
|
1609
|
-
if (first?.tagName === "TEMPLATE" && first.hasAttribute("data-ilha-state")) {
|
|
1610
|
-
const tplRaw = first.getAttribute("data-ilha-state");
|
|
1611
|
-
first.remove();
|
|
1612
|
-
return tplRaw ? decodeSnapshot(tplRaw) : void 0;
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
function attach(el, fn, opts) {
|
|
1616
|
-
if (!opts?.hydrate) el.innerHTML = "";
|
|
1617
|
-
const runtime = makeRuntime({ hydrate: opts?.hydrate ? readHydrate(el) : void 0 });
|
|
1618
|
-
let resolve;
|
|
1619
|
-
const ready = new Promise((r) => {
|
|
1620
|
-
resolve = r;
|
|
1621
|
-
});
|
|
1622
|
-
const fiber = makeFiber(runtime, el, paint$1, { onFail: (e) => {
|
|
1623
|
-
opts?.onError?.(e);
|
|
1624
|
-
paintError$1(fiber, e);
|
|
1625
|
-
resolve();
|
|
1626
|
-
} });
|
|
1627
|
-
if (opts?.hydrate) fiber.hydrate = true;
|
|
1628
|
-
runtime.begin();
|
|
1629
|
-
runtime.setIdle(resolve);
|
|
1630
|
-
runSetup(fiber, fn);
|
|
1631
|
-
runtime.end();
|
|
1632
|
-
return {
|
|
1633
|
-
ready,
|
|
1634
|
-
runtime,
|
|
1635
|
-
unmount() {
|
|
1636
|
-
closeFiber(fiber);
|
|
1637
|
-
runtime.close();
|
|
1638
|
-
if (!opts?.hydrate) el.innerHTML = "";
|
|
1639
|
-
}
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
function mount(el, fn, opts) {
|
|
1643
|
-
return attach(el, fn, opts).unmount;
|
|
1644
|
-
}
|
|
1645
|
-
async function renderToString(fn, opts) {
|
|
1646
|
-
const snapshot = opts?.snapshot !== false;
|
|
1647
|
-
const markers = opts?.markers !== false;
|
|
1648
|
-
const { unmount, ready, runtime, root } = attachSsr(fn, { ssrCapture: opts?.captureActions === true });
|
|
1649
|
-
if (opts?.timeout == null) await ready;
|
|
1650
|
-
else await Promise.race([ready, new Promise((r) => setTimeout(r, opts.timeout))]);
|
|
1651
|
-
let inner = root.innerHTML;
|
|
1652
|
-
const actions = runtime.ssrActions;
|
|
1653
|
-
if (Object.keys(actions).length > 0) inner = `<template data-ilha-actions="${escapeAttr(JSON.stringify(actions))}"></template>${inner}`;
|
|
1654
|
-
const snap = snapshot ? encodeSnapshot(runtime.ssrValues) : void 0;
|
|
1655
|
-
unmount();
|
|
1656
|
-
if (!markers) return snap ? `<template data-ilha-state="${escapeAttr(snap)}"></template>${inner}` : inner;
|
|
1657
|
-
return `<div data-ilha${snap ? ` data-ilha-state="${escapeAttr(snap)}"` : ""}>${inner}</div>`;
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
//#endregion
|
|
1661
|
-
export { atom as a, instr as c, getFiber as d, makeFiber as f, interpret as i, isAtomHandle as l, renderToString as n, batch as o, paint$1 as r, handleOwner as s, mount as t, closeFiber as u };
|