ilha 0.14.8 → 0.14.10
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/define.d.ts +2 -3
- package/dist/define.js +1 -1
- package/dist/index.d.ts +16 -16
- package/dist/index.js +31 -25
- package/dist/jsx-runtime.d.ts +4 -4
- package/dist/{mount-BQ-zcg2x.js → mount-BzNrfVW4.js} +328 -68
- package/package.json +4 -4
package/dist/define.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { i as Component } from "./types-CJF2qMK6.js";
|
|
2
2
|
//#region src/define.d.ts
|
|
3
|
-
declare const define: (name: string, component: Component) => void;
|
|
4
|
-
//#endregion
|
|
5
|
-
export { define };
|
|
3
|
+
export declare const define: (name: string, component: Component) => void;
|
|
4
|
+
//#endregion
|
package/dist/define.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -16,9 +16,9 @@ interface IlhaContext<A> {
|
|
|
16
16
|
readonly defaultValue: A;
|
|
17
17
|
readonly Provider: (props: ContextProviderProps<A>) => View;
|
|
18
18
|
}
|
|
19
|
-
declare const createContext: <A>(defaultValue: A) => IlhaContext<A>;
|
|
19
|
+
export declare const createContext: <A>(defaultValue: A) => IlhaContext<A>;
|
|
20
20
|
/** Read a context value as an atom handle. Subscribes the active fiber on read. */
|
|
21
|
-
declare const context: <A>(ctx: IlhaContext<A>) => AtomHandle<A>;
|
|
21
|
+
export declare const context: <A>(ctx: IlhaContext<A>) => AtomHandle<A>;
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/error-boundary.d.ts
|
|
24
24
|
interface ErrorFallbackProps {
|
|
@@ -32,7 +32,7 @@ interface ErrorBoundaryProps {
|
|
|
32
32
|
children?: View;
|
|
33
33
|
}
|
|
34
34
|
/** Catch subtree failures and paint a fallback. Supports reset(). */
|
|
35
|
-
declare const ErrorBoundary: (props: ErrorBoundaryProps) => View;
|
|
35
|
+
export declare const ErrorBoundary: (props: ErrorBoundaryProps) => View;
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/watch.d.ts
|
|
38
38
|
/** Values delivered to watch callbacks. */
|
|
@@ -44,30 +44,30 @@ interface WatchFn {
|
|
|
44
44
|
<A extends WatchValue>(source: AtomHandle<A> | Atom.Atom<A> | Stream$1.Stream<A, unknown, unknown>, fn: WatchCallback<A>): Instruction<undefined>;
|
|
45
45
|
once: (fn: (ctx: WatchContext) => WatchOnceCleanup | undefined | Promise<WatchOnceCleanup | undefined>) => Instruction<undefined>;
|
|
46
46
|
}
|
|
47
|
-
declare const watch: WatchFn;
|
|
47
|
+
export declare const watch: WatchFn;
|
|
48
48
|
//#endregion
|
|
49
49
|
//#region src/atom.d.ts
|
|
50
50
|
/** Key-order-insensitive deep equality for JSON-shaped values. */
|
|
51
|
-
declare const structuralEqual: typeof Equal.equals;
|
|
51
|
+
export declare const structuralEqual: typeof Equal.equals;
|
|
52
52
|
/** Read atoms inside `fn` without subscribing the active render. Sync only. */
|
|
53
|
-
declare const untrack: <A>(fn: () => A) => A;
|
|
53
|
+
export declare const untrack: <A>(fn: () => A) => A;
|
|
54
54
|
interface AtomFn {
|
|
55
55
|
<A>(init: A | Atom.Atom<A> | Effect$1.Effect<A, unknown, AtomRegistry> | Stream$1.Stream<A, unknown, AtomRegistry>, options?: AtomOptions<A>): AtomHandle<A>;
|
|
56
56
|
lazy: <A>(init: () => A) => AtomHandle<A>;
|
|
57
57
|
}
|
|
58
|
-
declare const atom: AtomFn;
|
|
59
|
-
declare const batch: (f: () => void) => void;
|
|
58
|
+
export declare const atom: AtomFn;
|
|
59
|
+
export declare const batch: (f: () => void) => void;
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region src/resource.d.ts
|
|
62
62
|
/** Drop the cached value for `key` and refetch it in live components. */
|
|
63
|
-
declare const invalidate: (key: string) => void;
|
|
63
|
+
export declare const invalidate: (key: string) => void;
|
|
64
64
|
/**
|
|
65
65
|
* Fetch-once, share-everywhere async state for `key`. Concurrent mounts
|
|
66
66
|
* dedupe on one in-flight request; remounts seed from the shared cache
|
|
67
67
|
* (and revalidate when `staleWhileRevalidate` holds). Call unconditionally
|
|
68
68
|
* at the top level of a sync component, before any `await`.
|
|
69
69
|
*/
|
|
70
|
-
declare const resource: <T>(key: string, fetcher: ResourceFetcher<T>, opts?: ResourceOptions) => Resource<T>;
|
|
70
|
+
export declare const resource: <T>(key: string, fetcher: ResourceFetcher<T>, opts?: ResourceOptions) => Resource<T>;
|
|
71
71
|
//#endregion
|
|
72
72
|
//#region src/sse.d.ts
|
|
73
73
|
/**
|
|
@@ -76,10 +76,10 @@ declare const resource: <T>(key: string, fetcher: ResourceFetcher<T>, opts?: Res
|
|
|
76
76
|
* an empty stream with status `"closed"`. Call unconditionally at the top
|
|
77
77
|
* level of a component.
|
|
78
78
|
*/
|
|
79
|
-
declare const fromEventSource: <T = string>(url: string, opts?: EventSourceOptions<T>) => EventSourceFeed<T>;
|
|
79
|
+
export declare const fromEventSource: <T = string>(url: string, opts?: EventSourceOptions<T>) => EventSourceFeed<T>;
|
|
80
80
|
//#endregion
|
|
81
81
|
//#region src/when.d.ts
|
|
82
|
-
declare const when: <A, E = never, R = never>(stream: Stream$1.Stream<A, E, R>, body: (value: A) => Generator<Yielded, View | undefined, View>) => Instruction<undefined, E>;
|
|
82
|
+
export declare const when: <A, E = never, R = never>(stream: Stream$1.Stream<A, E, R>, body: (value: A) => Generator<Yielded, View | undefined, View>) => Instruction<undefined, E>;
|
|
83
83
|
//#endregion
|
|
84
84
|
//#region src/mount.d.ts
|
|
85
85
|
interface RenderToStringOptions {
|
|
@@ -92,8 +92,8 @@ interface MountOptions {
|
|
|
92
92
|
hydrate?: boolean;
|
|
93
93
|
onError?: <E>(error: E) => void;
|
|
94
94
|
}
|
|
95
|
-
declare const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void);
|
|
96
|
-
declare const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>;
|
|
95
|
+
export declare const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void);
|
|
96
|
+
export declare const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>;
|
|
97
97
|
//#endregion
|
|
98
98
|
//#region src/unsafe.d.ts
|
|
99
99
|
/**
|
|
@@ -104,6 +104,6 @@ declare const renderToString: (fn: Component, opts?: RenderToStringOptions) => P
|
|
|
104
104
|
* scripts inserted this way do not run, but event attributes and other
|
|
105
105
|
* markup still apply.
|
|
106
106
|
*/
|
|
107
|
-
declare const unsafe: (html: string) => UnsafeHtml;
|
|
107
|
+
export declare const unsafe: (html: string) => UnsafeHtml;
|
|
108
108
|
//#endregion
|
|
109
|
-
export { type AtomEquality, type AtomHandle, type AtomOptions, type Component, type ContextProviderProps,
|
|
109
|
+
export { type AtomEquality, type AtomHandle, type AtomOptions, type Component, type ContextProviderProps, type ErrorBoundaryProps, type ErrorFallback, type ErrorFallbackProps, type EventSourceFeed, type EventSourceOptions, type EventSourceStatus, Fragment, type IlhaContext, type MountOptions, type RenderToStringOptions, type Resource, type ResourceFetcher, type ResourceOptions, type UnsafeHtml, type View, type WatchCallback, type WatchContext, type WatchOnceCleanup, h };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as makeFiber, a as interpret, c as handleOwner, d as structuralEqual, f as untrack, g as getFiber, h as closeFiber, i as runSetup, l as instr, m as clearFiberView, n as renderToString, o as atom, p as wrapHandle, r as unsafe, s as batch, t as mount, u as isAtomHandle } from "./mount-
|
|
1
|
+
import { _ as makeFiber, a as interpret, c as handleOwner, d as structuralEqual, f as untrack, g as getFiber, h as closeFiber, i as runSetup, l as instr, m as clearFiberView, n as renderToString, o as atom, p as wrapHandle, r as unsafe, s as batch, t as mount, u as isAtomHandle } from "./mount-BzNrfVW4.js";
|
|
2
2
|
import { d as errorView, g as isString, i as Fragment, p as isFunction, t as h } from "./vnode-M-oJMKcv.js";
|
|
3
3
|
import * as Atom from "effect/reactivity/Atom";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
@@ -241,6 +241,18 @@ const watch = Object.assign(watchSource, { once: watchOnce });
|
|
|
241
241
|
const sharedCache = /* @__PURE__ */ new Map();
|
|
242
242
|
const liveRefetchers = /* @__PURE__ */ new Map();
|
|
243
243
|
const cells$1 = /* @__PURE__ */ new WeakMap();
|
|
244
|
+
/** Unmount: stop every client cell of one fiber (all keys it ever used). */
|
|
245
|
+
const releaseCells = (byKey) => {
|
|
246
|
+
for (const [key, entry] of byKey) {
|
|
247
|
+
const c = entry;
|
|
248
|
+
c.alive = false;
|
|
249
|
+
c.ctrl?.abort();
|
|
250
|
+
const live = liveRefetchers.get(key);
|
|
251
|
+
live?.delete(c.onInvalidate);
|
|
252
|
+
if (live && live.size === 0) liveRefetchers.delete(key);
|
|
253
|
+
}
|
|
254
|
+
byKey.clear();
|
|
255
|
+
};
|
|
244
256
|
const entryFor = (key) => sharedCache.get(key);
|
|
245
257
|
/** Drop the cached value for `key` and refetch it in live components. */
|
|
246
258
|
const invalidate = (key) => {
|
|
@@ -325,10 +337,13 @@ const resource = (key, fetcher, opts) => {
|
|
|
325
337
|
}
|
|
326
338
|
let cell = byKey.get(key);
|
|
327
339
|
if (!cell) {
|
|
328
|
-
|
|
340
|
+
const fresh = {
|
|
329
341
|
alive: true,
|
|
330
342
|
ctrl: null,
|
|
331
|
-
|
|
343
|
+
onInvalidate: () => {
|
|
344
|
+
fresh.revalidate();
|
|
345
|
+
},
|
|
346
|
+
revalidate: () => {},
|
|
332
347
|
sink: {
|
|
333
348
|
data,
|
|
334
349
|
error,
|
|
@@ -336,7 +351,14 @@ const resource = (key, fetcher, opts) => {
|
|
|
336
351
|
},
|
|
337
352
|
started: false
|
|
338
353
|
};
|
|
354
|
+
cell = fresh;
|
|
339
355
|
byKey.set(key, cell);
|
|
356
|
+
let live = liveRefetchers.get(key);
|
|
357
|
+
if (!live) {
|
|
358
|
+
live = /* @__PURE__ */ new Set();
|
|
359
|
+
liveRefetchers.set(key, live);
|
|
360
|
+
}
|
|
361
|
+
live.add(cell.onInvalidate);
|
|
340
362
|
}
|
|
341
363
|
cell.sink = {
|
|
342
364
|
data,
|
|
@@ -411,6 +433,9 @@ const resource = (key, fetcher, opts) => {
|
|
|
411
433
|
await start();
|
|
412
434
|
} catch {}
|
|
413
435
|
};
|
|
436
|
+
c.revalidate = () => {
|
|
437
|
+
settleStart();
|
|
438
|
+
};
|
|
414
439
|
if (!c.started) {
|
|
415
440
|
c.started = true;
|
|
416
441
|
const swr = opts?.staleWhileRevalidate ?? true;
|
|
@@ -439,28 +464,9 @@ const resource = (key, fetcher, opts) => {
|
|
|
439
464
|
}
|
|
440
465
|
}
|
|
441
466
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
settleStart();
|
|
446
|
-
};
|
|
447
|
-
watch.once(() => {
|
|
448
|
-
let live = liveRefetchers.get(key);
|
|
449
|
-
if (!live) {
|
|
450
|
-
live = /* @__PURE__ */ new Set();
|
|
451
|
-
liveRefetchers.set(key, live);
|
|
452
|
-
}
|
|
453
|
-
live.add(onInvalidate);
|
|
454
|
-
return () => {
|
|
455
|
-
c.alive = false;
|
|
456
|
-
c.ctrl?.abort();
|
|
457
|
-
const s = liveRefetchers.get(key);
|
|
458
|
-
s?.delete(onInvalidate);
|
|
459
|
-
if (s && s.size === 0) liveRefetchers.delete(key);
|
|
460
|
-
if (fiberCells.get(key) === c) fiberCells.delete(key);
|
|
461
|
-
};
|
|
462
|
-
});
|
|
463
|
-
}
|
|
467
|
+
watch.once(() => () => {
|
|
468
|
+
releaseCells(fiberCells);
|
|
469
|
+
});
|
|
464
470
|
return {
|
|
465
471
|
data,
|
|
466
472
|
error,
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as ComponentFn, d as JsxComponent, f as PropBag, l as Fragment, v as View } from "./types-CJF2qMK6.js";
|
|
2
2
|
import { n as JSX, t as h } from "./vnode-CUTNGblA.js";
|
|
3
3
|
//#region src/jsx-runtime.d.ts
|
|
4
|
-
declare const jsx: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
5
|
-
declare const jsxs:
|
|
6
|
-
declare const jsxDEV:
|
|
4
|
+
export declare const jsx: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
5
|
+
export declare const jsxs: typeof jsx;
|
|
6
|
+
export declare const jsxDEV: typeof jsx;
|
|
7
7
|
//#endregion
|
|
8
|
-
export { Fragment, type JSX, type View, h
|
|
8
|
+
export { Fragment, type JSX, type View, h };
|
|
@@ -512,39 +512,71 @@ const eventTypeFromProp = (key) => {
|
|
|
512
512
|
return type.length >= 3 ? type : void 0;
|
|
513
513
|
};
|
|
514
514
|
const isEventProp = (key) => eventTypeFromProp(key) !== void 0;
|
|
515
|
+
const dispatch = (el, type, ev) => {
|
|
516
|
+
const fiber = el.__ilhaFiber;
|
|
517
|
+
if (!fiber || fiber.closed) return;
|
|
518
|
+
const fn = el.__ilhaHandlers?.get(type);
|
|
519
|
+
if (!isFunction(fn)) return;
|
|
520
|
+
const out = fn(ev);
|
|
521
|
+
if (Effect$1.isEffect(out)) fiber.run(out);
|
|
522
|
+
};
|
|
523
|
+
/** One native listener per type; it reads the latest handler at dispatch. */
|
|
524
|
+
const listen = (el, type) => {
|
|
525
|
+
el.__ilhaEvents ??= /* @__PURE__ */ new Set();
|
|
526
|
+
if (el.__ilhaEvents.has(type)) return;
|
|
527
|
+
el.__ilhaEvents.add(type);
|
|
528
|
+
el.addEventListener(type, (ev) => {
|
|
529
|
+
dispatch(el, type, ev);
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
const bindSsrActions = (el, props, fiber) => {
|
|
533
|
+
const seen = /* @__PURE__ */ new Set();
|
|
534
|
+
for (const key of Object.keys(props)) {
|
|
535
|
+
const type = eventTypeFromProp(key);
|
|
536
|
+
if (!type || seen.has(type)) continue;
|
|
537
|
+
seen.add(type);
|
|
538
|
+
const fn = props[key];
|
|
539
|
+
if (!isFunction(fn)) continue;
|
|
540
|
+
const branded = fn[ACTION_CALL$1];
|
|
541
|
+
const rec = branded?.k ? {
|
|
542
|
+
a: branded.a ?? [],
|
|
543
|
+
k: branded.k
|
|
544
|
+
} : void 0;
|
|
545
|
+
if (!rec) continue;
|
|
546
|
+
const id = `${type}:${fiber.runtime.ssrEventI}`;
|
|
547
|
+
fiber.runtime.ssrEventI += 1;
|
|
548
|
+
fiber.runtime.ssrActions[id] = rec;
|
|
549
|
+
const existing = el.dataset.ilhaOn;
|
|
550
|
+
el.dataset.ilhaOn = existing ? `${existing},${id}` : id;
|
|
551
|
+
}
|
|
552
|
+
};
|
|
515
553
|
const bindEvents = (node, props, fiber) => {
|
|
516
554
|
const el = node;
|
|
517
|
-
|
|
518
|
-
|
|
555
|
+
if (fiber.runtime.ssr) {
|
|
556
|
+
bindSsrActions(el, props, fiber);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
519
560
|
for (const key of Object.keys(props)) {
|
|
520
561
|
const type = eventTypeFromProp(key);
|
|
521
|
-
if (!type)
|
|
522
|
-
if (el.__ilhaEvents.has(type)) continue;
|
|
523
|
-
el.__ilhaEvents.add(type);
|
|
524
|
-
if (fiber.runtime.ssr) {
|
|
525
|
-
const fn = props[key];
|
|
526
|
-
if (!isFunction(fn)) continue;
|
|
527
|
-
const branded = fn[ACTION_CALL$1];
|
|
528
|
-
const rec = branded?.k ? {
|
|
529
|
-
a: branded.a ?? [],
|
|
530
|
-
k: branded.k
|
|
531
|
-
} : void 0;
|
|
532
|
-
if (!rec) continue;
|
|
533
|
-
const id = `${type}:${fiber.runtime.ssrEventI}`;
|
|
534
|
-
fiber.runtime.ssrEventI += 1;
|
|
535
|
-
fiber.runtime.ssrActions[id] = rec;
|
|
536
|
-
const existing = el.dataset.ilhaOn;
|
|
537
|
-
el.dataset.ilhaOn = existing ? `${existing},${id}` : id;
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
el.addEventListener(type, (ev) => {
|
|
541
|
-
if (fiber.closed) return;
|
|
542
|
-
const fn = el.__ilhaProps?.[key];
|
|
543
|
-
if (!isFunction(fn)) return;
|
|
544
|
-
const out = fn(ev);
|
|
545
|
-
if (Effect$1.isEffect(out)) fiber.run(out);
|
|
546
|
-
});
|
|
562
|
+
if (type && !handlers.has(type)) handlers.set(type, props[key]);
|
|
547
563
|
}
|
|
564
|
+
el.__ilhaHandlers = handlers;
|
|
565
|
+
el.__ilhaFiber = fiber;
|
|
566
|
+
for (const type of handlers.keys()) listen(el, type);
|
|
567
|
+
};
|
|
568
|
+
/**
|
|
569
|
+
* The morph kept `live` in place of the freshly rendered `fresh`: hand the
|
|
570
|
+
* render's handlers to the live node, so closures never go stale and handlers
|
|
571
|
+
* added on a later render still fire.
|
|
572
|
+
*/
|
|
573
|
+
const adoptEvents = (live, fresh) => {
|
|
574
|
+
const from = fresh;
|
|
575
|
+
if (!from.__ilhaFiber) return;
|
|
576
|
+
const to = live;
|
|
577
|
+
to.__ilhaHandlers = from.__ilhaHandlers;
|
|
578
|
+
to.__ilhaFiber = from.__ilhaFiber;
|
|
579
|
+
for (const type of from.__ilhaHandlers?.keys() ?? []) listen(to, type);
|
|
548
580
|
};
|
|
549
581
|
|
|
550
582
|
//#endregion
|
|
@@ -556,14 +588,17 @@ const morphKeyOf = (el) => {
|
|
|
556
588
|
const s = el.getAttribute(SLOT_ATTR);
|
|
557
589
|
return s === null ? null : `s:${s}`;
|
|
558
590
|
};
|
|
591
|
+
/** Whether `data-morph-preserve` on `el` lists `token`. */
|
|
592
|
+
const hasPreserveToken = (el, token) => {
|
|
593
|
+
const custom = el.getAttribute(PRESERVE_ATTR);
|
|
594
|
+
if (custom === null) return false;
|
|
595
|
+
for (const listed of custom.split(/\s+/u)) if (listed === token) return true;
|
|
596
|
+
return false;
|
|
597
|
+
};
|
|
559
598
|
const shouldPreserveMorphAttr = (el, name) => {
|
|
560
599
|
if (name === "value" || name === "checked" || name === "selected") return true;
|
|
561
600
|
if (name === PRESERVE_ATTR) return el.hasAttribute(PRESERVE_ATTR);
|
|
562
|
-
|
|
563
|
-
if (custom !== null) {
|
|
564
|
-
for (const token of custom.split(/\s+/u)) if (token === name) return true;
|
|
565
|
-
}
|
|
566
|
-
return false;
|
|
601
|
+
return hasPreserveToken(el, name);
|
|
567
602
|
};
|
|
568
603
|
const syncAttributes = (from, to) => {
|
|
569
604
|
for (const { name, value } of to.attributes) {
|
|
@@ -578,9 +613,26 @@ const syncAttributes = (from, to) => {
|
|
|
578
613
|
if (!to.hasAttribute(name)) from.removeAttribute(name);
|
|
579
614
|
}
|
|
580
615
|
};
|
|
616
|
+
/** Deepest focused element, looking through open shadow roots. */
|
|
617
|
+
const deepActiveElement = () => {
|
|
618
|
+
let active = document.activeElement;
|
|
619
|
+
while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
|
|
620
|
+
return active;
|
|
621
|
+
};
|
|
622
|
+
const snapshotRanges = (active) => {
|
|
623
|
+
if (!active.isContentEditable) return null;
|
|
624
|
+
const sel = document.getSelection();
|
|
625
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
626
|
+
const ranges = [];
|
|
627
|
+
for (let i = 0; i < sel.rangeCount; i += 1) {
|
|
628
|
+
const range = sel.getRangeAt(i);
|
|
629
|
+
if (active.contains(range.startContainer)) ranges.push(range.cloneRange());
|
|
630
|
+
}
|
|
631
|
+
return ranges.length > 0 ? ranges : null;
|
|
632
|
+
};
|
|
581
633
|
const snapshotFocus = () => {
|
|
582
634
|
if (globalThis.document === void 0) return null;
|
|
583
|
-
const active =
|
|
635
|
+
const active = deepActiveElement();
|
|
584
636
|
if (!(active instanceof HTMLElement) || active === document.body) return null;
|
|
585
637
|
let selection = null;
|
|
586
638
|
try {
|
|
@@ -592,13 +644,23 @@ const snapshotFocus = () => {
|
|
|
592
644
|
} catch {}
|
|
593
645
|
return {
|
|
594
646
|
active,
|
|
647
|
+
ranges: snapshotRanges(active),
|
|
595
648
|
selection
|
|
596
649
|
};
|
|
597
650
|
};
|
|
651
|
+
const restoreRanges = (ranges) => {
|
|
652
|
+
const sel = document.getSelection();
|
|
653
|
+
if (!sel || !ranges.every((r) => r.startContainer.isConnected)) return;
|
|
654
|
+
sel.removeAllRanges();
|
|
655
|
+
for (const r of ranges) sel.addRange(r);
|
|
656
|
+
};
|
|
598
657
|
const restoreFocus = (snapshot) => {
|
|
599
658
|
if (!snapshot || !snapshot.active.isConnected) return;
|
|
600
659
|
try {
|
|
601
|
-
if (
|
|
660
|
+
if (deepActiveElement() !== snapshot.active) {
|
|
661
|
+
snapshot.active.focus({ preventScroll: true });
|
|
662
|
+
if (snapshot.ranges) restoreRanges(snapshot.ranges);
|
|
663
|
+
}
|
|
602
664
|
const sel = snapshot.selection;
|
|
603
665
|
if (sel && sel.start !== null) {
|
|
604
666
|
const el = snapshot.active;
|
|
@@ -606,6 +668,122 @@ const restoreFocus = (snapshot) => {
|
|
|
606
668
|
}
|
|
607
669
|
} catch {}
|
|
608
670
|
};
|
|
671
|
+
const STAND_IN_ATTR = "data-ilha-reuse";
|
|
672
|
+
const standIns = /* @__PURE__ */ new WeakMap();
|
|
673
|
+
/** Live nodes with an outstanding stand-in: the morph must not consume them. */
|
|
674
|
+
const claimed = /* @__PURE__ */ new WeakSet();
|
|
675
|
+
/** Placeholder for a connected live node inside a scratch render tree. */
|
|
676
|
+
const standInFor = (live) => {
|
|
677
|
+
const el = document.createElementNS(live.namespaceURI, live.localName);
|
|
678
|
+
for (const name of [SLOT_ATTR, KEY_ATTR]) {
|
|
679
|
+
const v = live.getAttribute(name);
|
|
680
|
+
if (v !== null) el.setAttribute(name, v);
|
|
681
|
+
}
|
|
682
|
+
el.setAttribute(STAND_IN_ATTR, "");
|
|
683
|
+
standIns.set(el, live);
|
|
684
|
+
claimed.add(live);
|
|
685
|
+
return el;
|
|
686
|
+
};
|
|
687
|
+
const liveOf = (node) => {
|
|
688
|
+
const live = standIns.get(node);
|
|
689
|
+
if (!live) return node;
|
|
690
|
+
claimed.delete(live);
|
|
691
|
+
return live;
|
|
692
|
+
};
|
|
693
|
+
/**
|
|
694
|
+
* Insert `node` before `ref`. Connected nodes move with `moveBefore` where the
|
|
695
|
+
* browser has it, so they keep focus, iframe, dialog, and element state.
|
|
696
|
+
*/
|
|
697
|
+
const place = (parent, node, ref) => {
|
|
698
|
+
if (node === ref || node.parentNode === parent && node.nextSibling === ref) return;
|
|
699
|
+
if (node.isConnected && parent.isConnected && parent.moveBefore) try {
|
|
700
|
+
parent.moveBefore(node, ref);
|
|
701
|
+
return;
|
|
702
|
+
} catch {}
|
|
703
|
+
if (ref) ref.before(node);
|
|
704
|
+
else parent.append(node);
|
|
705
|
+
};
|
|
706
|
+
/** Swap stand-ins nested in `node` (now in the document) for live nodes. */
|
|
707
|
+
const resolveNested = (node) => {
|
|
708
|
+
if (!(node instanceof Element) || !node.firstElementChild) return;
|
|
709
|
+
const nested = node.querySelectorAll(`[${STAND_IN_ATTR}]`);
|
|
710
|
+
for (const s of nested) {
|
|
711
|
+
const live = liveOf(s);
|
|
712
|
+
if (live !== s && s.parentNode) {
|
|
713
|
+
place(s.parentNode, live, s);
|
|
714
|
+
s.remove();
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
/**
|
|
719
|
+
* Put a rendered node into the live tree: stand-ins become their live nodes,
|
|
720
|
+
* and stand-ins nested in fresh subtrees resolve once the subtree is attached.
|
|
721
|
+
*/
|
|
722
|
+
const insertRendered = (parent, node, ref) => {
|
|
723
|
+
const live = liveOf(node);
|
|
724
|
+
place(parent, live, ref);
|
|
725
|
+
if (live === node) resolveNested(node);
|
|
726
|
+
};
|
|
727
|
+
/** Longest increasing run of old indexes: those nodes never move. */
|
|
728
|
+
const stableSet = (nodes, oldIndex) => {
|
|
729
|
+
const tails = [];
|
|
730
|
+
const prev = [];
|
|
731
|
+
for (let i = 0; i < nodes.length; i += 1) {
|
|
732
|
+
const node = nodes[i];
|
|
733
|
+
const idx = node ? oldIndex.get(node) : void 0;
|
|
734
|
+
if (idx === void 0) {
|
|
735
|
+
prev.push(-1);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
let lo = 0;
|
|
739
|
+
let hi = tails.length;
|
|
740
|
+
while (lo < hi) {
|
|
741
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
742
|
+
const tail = nodes[tails[mid] ?? 0];
|
|
743
|
+
if ((tail ? oldIndex.get(tail) ?? 0 : 0) < idx) lo = mid + 1;
|
|
744
|
+
else hi = mid;
|
|
745
|
+
}
|
|
746
|
+
prev.push(lo > 0 ? tails[lo - 1] ?? -1 : -1);
|
|
747
|
+
tails[lo] = i;
|
|
748
|
+
}
|
|
749
|
+
const stable = /* @__PURE__ */ new Set();
|
|
750
|
+
let k = tails.length > 0 ? tails.at(-1) ?? -1 : -1;
|
|
751
|
+
while (k >= 0) {
|
|
752
|
+
const node = nodes[k];
|
|
753
|
+
if (node) stable.add(node);
|
|
754
|
+
k = prev[k] ?? -1;
|
|
755
|
+
}
|
|
756
|
+
return stable;
|
|
757
|
+
};
|
|
758
|
+
/**
|
|
759
|
+
* Make `parent`'s children exactly `nodes` with the fewest moves. Nodes that
|
|
760
|
+
* keep their relative order stay attached; removed nodes leave first.
|
|
761
|
+
*/
|
|
762
|
+
const placeChildren = (parent, rendered) => {
|
|
763
|
+
const focus = snapshotFocus();
|
|
764
|
+
const nodes = rendered.map(liveOf);
|
|
765
|
+
const wanted = new Set(nodes);
|
|
766
|
+
const oldIndex = /* @__PURE__ */ new Map();
|
|
767
|
+
let child = parent.firstChild;
|
|
768
|
+
while (child) {
|
|
769
|
+
const next = child.nextSibling;
|
|
770
|
+
if (wanted.has(child)) oldIndex.set(child, oldIndex.size);
|
|
771
|
+
else child.remove();
|
|
772
|
+
child = next;
|
|
773
|
+
}
|
|
774
|
+
const stable = stableSet(nodes, oldIndex);
|
|
775
|
+
let next = null;
|
|
776
|
+
for (let i = nodes.length - 1; i >= 0; i -= 1) {
|
|
777
|
+
const node = nodes[i];
|
|
778
|
+
if (!node) continue;
|
|
779
|
+
if (!stable.has(node)) {
|
|
780
|
+
place(parent, node, next);
|
|
781
|
+
if (!oldIndex.has(node)) resolveNested(node);
|
|
782
|
+
}
|
|
783
|
+
next = node;
|
|
784
|
+
}
|
|
785
|
+
restoreFocus(focus);
|
|
786
|
+
};
|
|
609
787
|
const buildKeyedIndex = (parent) => {
|
|
610
788
|
let fromKeyed = null;
|
|
611
789
|
for (const child of parent.children) {
|
|
@@ -667,18 +845,43 @@ const morphSelect = (fromEl, toEl, api) => {
|
|
|
667
845
|
if (prev && o.selected !== prev.live) o.selected = prev.live;
|
|
668
846
|
}
|
|
669
847
|
};
|
|
848
|
+
/** Rendered element → the live element the morph kept in its place. */
|
|
849
|
+
const adoptedBy = /* @__PURE__ */ new WeakMap();
|
|
850
|
+
/** The element a rendered element ended up as in the document. */
|
|
851
|
+
const committedElement = (el) => adoptedBy.get(el) ?? el;
|
|
852
|
+
/** `live` stays in the document for `fresh`: move the render's bindings. */
|
|
853
|
+
const adopt = (live, fresh) => {
|
|
854
|
+
adoptedBy.set(fresh, live);
|
|
855
|
+
adoptEvents(live, fresh);
|
|
856
|
+
};
|
|
857
|
+
/**
|
|
858
|
+
* A contenteditable the render leaves empty is uncontrolled: the user's
|
|
859
|
+
* content (and caret) survives, like an uncontrolled textarea.
|
|
860
|
+
*/
|
|
861
|
+
const isUncontrolledEditable = (from, to) => {
|
|
862
|
+
const mode = to.getAttribute("contenteditable");
|
|
863
|
+
return mode !== null && mode !== "false" && !to.hasChildNodes() && from.getAttribute("contenteditable") === mode;
|
|
864
|
+
};
|
|
865
|
+
/** Swap `fromNode` for a rendered node without ever detaching live nodes. */
|
|
866
|
+
const replaceRendered = (fromNode, toNode) => {
|
|
867
|
+
const parent = fromNode.parentNode;
|
|
868
|
+
if (!parent) return;
|
|
869
|
+
insertRendered(parent, toNode, fromNode);
|
|
870
|
+
fromNode.remove();
|
|
871
|
+
};
|
|
670
872
|
const morphElementPair = (fromEl, toEl, api) => {
|
|
671
873
|
if (fromEl.localName !== toEl.localName) {
|
|
672
|
-
fromEl
|
|
874
|
+
replaceRendered(fromEl, toEl);
|
|
673
875
|
return;
|
|
674
876
|
}
|
|
675
877
|
const toSlot = toEl.getAttribute(SLOT_ATTR);
|
|
676
878
|
const fromSlot = fromEl.getAttribute(SLOT_ATTR);
|
|
677
879
|
if (toSlot !== null && fromSlot === toSlot) return;
|
|
678
880
|
if (toSlot !== null) {
|
|
679
|
-
fromEl
|
|
881
|
+
replaceRendered(fromEl, toEl);
|
|
680
882
|
return;
|
|
681
883
|
}
|
|
884
|
+
adopt(fromEl, toEl);
|
|
682
885
|
if (fromEl.localName === "input") {
|
|
683
886
|
morphInput(fromEl, toEl);
|
|
684
887
|
return;
|
|
@@ -687,10 +890,18 @@ const morphElementPair = (fromEl, toEl, api) => {
|
|
|
687
890
|
morphSelect(fromEl, toEl, api);
|
|
688
891
|
return;
|
|
689
892
|
}
|
|
893
|
+
const keepChildren = hasPreserveToken(fromEl, "children") || hasPreserveToken(toEl, "children") || isUncontrolledEditable(fromEl, toEl);
|
|
690
894
|
syncAttributes(fromEl, toEl);
|
|
895
|
+
if (keepChildren) return;
|
|
691
896
|
if (fromEl.localName === "textarea") morphTextarea(fromEl, toEl);
|
|
692
897
|
else api.morphChildren(fromEl, toEl);
|
|
693
898
|
};
|
|
899
|
+
/** Keyed node the new render drops and no stand-in still needs. */
|
|
900
|
+
const isStaleKeyed = (node, toKeys) => {
|
|
901
|
+
if (!(node instanceof Element) || claimed.has(node)) return false;
|
|
902
|
+
const key = morphKeyOf(node);
|
|
903
|
+
return key !== null && !toKeys.has(key);
|
|
904
|
+
};
|
|
694
905
|
const alignKeyedNode = (fromParent, fromNode, toNode, fromKeyed, toKeys) => {
|
|
695
906
|
const toKey = toNode.nodeType === 1 ? morphKeyOf(toNode) : null;
|
|
696
907
|
let current = fromNode;
|
|
@@ -698,9 +909,13 @@ const alignKeyedNode = (fromParent, fromNode, toNode, fromKeyed, toKeys) => {
|
|
|
698
909
|
const match = fromKeyed.get(toKey);
|
|
699
910
|
if (match) {
|
|
700
911
|
fromKeyed.delete(toKey);
|
|
912
|
+
while (current && current !== match && isStaleKeyed(current, toKeys)) {
|
|
913
|
+
const next = current.nextSibling;
|
|
914
|
+
current.remove();
|
|
915
|
+
current = next ?? void 0;
|
|
916
|
+
}
|
|
701
917
|
if (match !== current) {
|
|
702
|
-
|
|
703
|
-
if (!current) fromParent.append(match);
|
|
918
|
+
place(fromParent, match, current ?? null);
|
|
704
919
|
current = match;
|
|
705
920
|
}
|
|
706
921
|
}
|
|
@@ -708,12 +923,31 @@ const alignKeyedNode = (fromParent, fromNode, toNode, fromKeyed, toKeys) => {
|
|
|
708
923
|
if (current instanceof Element) {
|
|
709
924
|
const fromKey = morphKeyOf(current);
|
|
710
925
|
if (fromKey !== null && fromKey !== toKey && toKeys.has(fromKey)) {
|
|
711
|
-
|
|
926
|
+
insertRendered(fromParent, toNode, current);
|
|
712
927
|
return "continue";
|
|
713
928
|
}
|
|
714
929
|
}
|
|
715
930
|
return current;
|
|
716
931
|
};
|
|
932
|
+
const morphChild = ({ api, fromParent, fromNode, toNode }) => {
|
|
933
|
+
if (standIns.has(toNode)) {
|
|
934
|
+
insertRendered(fromParent, toNode, fromNode ?? null);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (!fromNode || claimed.has(fromNode)) {
|
|
938
|
+
insertRendered(fromParent, toNode, fromNode ?? null);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (fromNode.nodeType !== toNode.nodeType) {
|
|
942
|
+
replaceRendered(fromNode, toNode);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
if (fromNode.nodeType === 3 || fromNode.nodeType === 8) {
|
|
946
|
+
if (fromNode.nodeValue !== toNode.nodeValue) fromNode.nodeValue = toNode.nodeValue;
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (fromNode.nodeType === 1) morphElementPair(fromNode, toNode, api);
|
|
950
|
+
};
|
|
717
951
|
const api = { morphChildren: (fromParent, toParent) => {
|
|
718
952
|
const toNodes = [...toParent.childNodes];
|
|
719
953
|
const fromKeyed = buildKeyedIndex(fromParent);
|
|
@@ -727,19 +961,12 @@ const api = { morphChildren: (fromParent, toParent) => {
|
|
|
727
961
|
if (aligned === "continue") continue;
|
|
728
962
|
fromNode = aligned;
|
|
729
963
|
}
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
if (fromNode.nodeType === 3 || fromNode.nodeType === 8) {
|
|
739
|
-
if (fromNode.nodeValue !== toNode.nodeValue) fromNode.nodeValue = toNode.nodeValue;
|
|
740
|
-
continue;
|
|
741
|
-
}
|
|
742
|
-
if (fromNode.nodeType === 1) morphElementPair(fromNode, toNode, api);
|
|
964
|
+
morphChild({
|
|
965
|
+
api,
|
|
966
|
+
fromNode,
|
|
967
|
+
fromParent,
|
|
968
|
+
toNode
|
|
969
|
+
});
|
|
743
970
|
}
|
|
744
971
|
while (fromParent.childNodes.length > toNodes.length) fromParent.lastChild?.remove();
|
|
745
972
|
} };
|
|
@@ -948,14 +1175,28 @@ const isSkippedPropKey = (k) => k === "children" || k === "key" || k === "ref" |
|
|
|
948
1175
|
* keyed reconciliation. Host differences live in `PaintOps`.
|
|
949
1176
|
*/
|
|
950
1177
|
const createPainter = (ops) => {
|
|
1178
|
+
let paintDepth = 0;
|
|
1179
|
+
const pendingRefs = [];
|
|
1180
|
+
const commit = (fn) => {
|
|
1181
|
+
paintDepth += 1;
|
|
1182
|
+
try {
|
|
1183
|
+
fn();
|
|
1184
|
+
} finally {
|
|
1185
|
+
paintDepth -= 1;
|
|
1186
|
+
if (paintDepth === 0) for (const run of pendingRefs.splice(0)) run();
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
951
1189
|
const applyFormControl = (el, key, v, fiber) => {
|
|
952
|
-
const setProp = (x) => ops.setFormControl(el, key, x);
|
|
1190
|
+
const setProp = (x) => ops.setFormControl(ops.committed(el), key, x);
|
|
953
1191
|
if (isAtomHandle(v)) {
|
|
954
1192
|
const memo = el;
|
|
955
1193
|
if (memo.__ilhaVal === v) return;
|
|
956
1194
|
memo.__ilhaVal = v;
|
|
957
1195
|
const unsub = fiber.registry.subscribe(v.atom, setProp, { immediate: true });
|
|
958
|
-
fiber.holes.push({ dispose:
|
|
1196
|
+
fiber.holes.push({ dispose: () => {
|
|
1197
|
+
unsub();
|
|
1198
|
+
if (memo.__ilhaVal === v) memo.__ilhaVal = void 0;
|
|
1199
|
+
} });
|
|
959
1200
|
} else setProp(v);
|
|
960
1201
|
};
|
|
961
1202
|
const trackHole = (parent, hole, extra, meta) => {
|
|
@@ -1001,7 +1242,9 @@ const createPainter = (ops) => {
|
|
|
1001
1242
|
const { ref } = props;
|
|
1002
1243
|
if (isFunction(ref)) {
|
|
1003
1244
|
const refFn = ref;
|
|
1004
|
-
refFn(ops.asElement(el));
|
|
1245
|
+
const attach = () => refFn(ops.asElement(ops.committed(el)));
|
|
1246
|
+
if (paintDepth > 0) pendingRefs.push(attach);
|
|
1247
|
+
else attach();
|
|
1005
1248
|
fiber.holes.push({ dispose: () => refFn(null) });
|
|
1006
1249
|
}
|
|
1007
1250
|
};
|
|
@@ -1030,7 +1273,7 @@ const createPainter = (ops) => {
|
|
|
1030
1273
|
nodes: [host]
|
|
1031
1274
|
};
|
|
1032
1275
|
},
|
|
1033
|
-
paintHole: (fiber, view) => {
|
|
1276
|
+
paintHole: (fiber, view) => commit(() => {
|
|
1034
1277
|
if (view === KEEP) return;
|
|
1035
1278
|
let frame = fiber.islandFrame;
|
|
1036
1279
|
if (!frame) {
|
|
@@ -1051,7 +1294,7 @@ const createPainter = (ops) => {
|
|
|
1051
1294
|
}
|
|
1052
1295
|
cframe.i = 0;
|
|
1053
1296
|
const list = Array.isArray(view) ? view : null;
|
|
1054
|
-
if (list && list.length > 0 && list.every((v) => isVNode(v) && v.key !== null && v.key !== void 0)) {
|
|
1297
|
+
if (list && list.length > 0 && list.every((v) => isVNode(v) && isFunction(v.type) && v.key !== null && v.key !== void 0)) {
|
|
1055
1298
|
paintFns.keyedPaintHole(fiber, list);
|
|
1056
1299
|
sweepComponentSlots(fiber);
|
|
1057
1300
|
sweepIslandSlots(fiber);
|
|
@@ -1080,11 +1323,11 @@ const createPainter = (ops) => {
|
|
|
1080
1323
|
}
|
|
1081
1324
|
sweepComponentSlots(fiber);
|
|
1082
1325
|
sweepIslandSlots(fiber);
|
|
1083
|
-
}
|
|
1326
|
+
})
|
|
1084
1327
|
};
|
|
1085
1328
|
const materializeAtom = (view, fiber) => {
|
|
1086
1329
|
const reused = findReusableAtomHost(fiber, view.atom);
|
|
1087
|
-
if (reused) return [ops.
|
|
1330
|
+
if (reused) return [ops.reuseNode(reused.host)];
|
|
1088
1331
|
const { fiber: hole, nodes } = api.openHole(fiber);
|
|
1089
1332
|
const [host] = nodes;
|
|
1090
1333
|
if (!host) return nodes;
|
|
@@ -1133,7 +1376,7 @@ const createPainter = (ops) => {
|
|
|
1133
1376
|
const existing = frame.slots[i];
|
|
1134
1377
|
if (existing && existing.type === type && existing.host.isConnected && isFunction(existing.updateProps)) {
|
|
1135
1378
|
existing.updateProps(props);
|
|
1136
|
-
return [ops.
|
|
1379
|
+
return [ops.reuseNode(existing.host)];
|
|
1137
1380
|
}
|
|
1138
1381
|
if (existing) {
|
|
1139
1382
|
const idx = fiber.holes.findIndex((h) => h.islandSlot === existing);
|
|
@@ -1185,7 +1428,7 @@ const createPainter = (ops) => {
|
|
|
1185
1428
|
if (existing.type === type && !hole.closed) {
|
|
1186
1429
|
hole.propsBox = { current: props };
|
|
1187
1430
|
runSetup(hole, () => run(props));
|
|
1188
|
-
return [ops.
|
|
1431
|
+
return [ops.reuseNode(hole.root)];
|
|
1189
1432
|
}
|
|
1190
1433
|
if (!hole.closed) {
|
|
1191
1434
|
const idx = fiber.holes.findIndex((h) => h.holeFiber === hole);
|
|
@@ -1226,7 +1469,7 @@ const createPainter = (ops) => {
|
|
|
1226
1469
|
if (reuse.propsBox) reuse.propsBox.current = props;
|
|
1227
1470
|
const next = withFiber(fiber, () => run(reuse.propsBox?.current ?? props));
|
|
1228
1471
|
if (next && !isThenable(next) && !isSetupFn(next)) reuse.paint(next);
|
|
1229
|
-
return [ops.
|
|
1472
|
+
return [ops.reuseNode(reuse.root)];
|
|
1230
1473
|
}
|
|
1231
1474
|
if (!k) return materializeUnkeyedComponent(run, type, props, fiber);
|
|
1232
1475
|
const { fiber: khole, nodes: knodes } = api.openHole(fiber);
|
|
@@ -1302,11 +1545,11 @@ const createPainter = (ops) => {
|
|
|
1302
1545
|
nodes.push(...made);
|
|
1303
1546
|
}
|
|
1304
1547
|
fiber.keyedHoles = next;
|
|
1305
|
-
ops.
|
|
1306
|
-
api.insert(fiber, nodes);
|
|
1548
|
+
ops.placeChildren(fiber.root, nodes);
|
|
1307
1549
|
};
|
|
1308
1550
|
return {
|
|
1309
1551
|
applyProps: api.applyProps,
|
|
1552
|
+
commit,
|
|
1310
1553
|
disposeHoles: (fiber, opts) => disposeHoles(fiber, opts),
|
|
1311
1554
|
insert: api.insert,
|
|
1312
1555
|
materialize: api.materialize,
|
|
@@ -1318,7 +1561,7 @@ const createPainter = (ops) => {
|
|
|
1318
1561
|
//#region src/paint.ts
|
|
1319
1562
|
const noopDisconnect = () => {};
|
|
1320
1563
|
const core$1 = createPainter({
|
|
1321
|
-
appendRoot: (root, node) => root
|
|
1564
|
+
appendRoot: (root, node) => insertRendered(root, node, null),
|
|
1322
1565
|
asElement: (el) => el,
|
|
1323
1566
|
asNode: (host) => host,
|
|
1324
1567
|
asRoot: (el) => el,
|
|
@@ -1326,6 +1569,7 @@ const core$1 = createPainter({
|
|
|
1326
1569
|
clearRoot: (root) => {
|
|
1327
1570
|
if (root instanceof Element) root.replaceChildren();
|
|
1328
1571
|
},
|
|
1572
|
+
committed: committedElement,
|
|
1329
1573
|
createElement: (tag, ns) => ns ? document.createElementNS(ns, tag) : document.createElement(tag),
|
|
1330
1574
|
createRaw: (html, parent) => {
|
|
1331
1575
|
const range = document.createRange();
|
|
@@ -1340,6 +1584,10 @@ const core$1 = createPainter({
|
|
|
1340
1584
|
},
|
|
1341
1585
|
createText: (text) => document.createTextNode(text),
|
|
1342
1586
|
disconnect: noopDisconnect,
|
|
1587
|
+
placeChildren: (root, nodes) => {
|
|
1588
|
+
if (root instanceof Element) placeChildren(root, nodes);
|
|
1589
|
+
},
|
|
1590
|
+
reuseNode: (host) => host instanceof Element && host.isConnected ? standInFor(host) : host,
|
|
1343
1591
|
setFormControl: (el, key, v) => {
|
|
1344
1592
|
const node = el;
|
|
1345
1593
|
if (key === "value") {
|
|
@@ -1398,7 +1646,7 @@ const paintHydrate = (fiber, view) => {
|
|
|
1398
1646
|
root: el
|
|
1399
1647
|
};
|
|
1400
1648
|
el.replaceChildren();
|
|
1401
|
-
for (const c of view.children) for (const n of core$1.materialize(c, childFiber)) el
|
|
1649
|
+
for (const c of view.children) for (const n of core$1.materialize(c, childFiber)) insertRendered(el, n, null);
|
|
1402
1650
|
};
|
|
1403
1651
|
const paintMorphLive = (fiber, view) => {
|
|
1404
1652
|
if (!fiber.liveEl) return;
|
|
@@ -1416,7 +1664,7 @@ const paintMorphLive = (fiber, view) => {
|
|
|
1416
1664
|
refreshAllAtomHosts(fiber);
|
|
1417
1665
|
pruneDisconnectedAtomHoles(fiber);
|
|
1418
1666
|
};
|
|
1419
|
-
const
|
|
1667
|
+
const paintRoot = (fiber, view) => {
|
|
1420
1668
|
fiber.islandFrame ??= {
|
|
1421
1669
|
i: 0,
|
|
1422
1670
|
slots: []
|
|
@@ -1447,6 +1695,11 @@ const paint$1 = (fiber, view) => {
|
|
|
1447
1695
|
const first = fiber.root instanceof Element ? fiber.root.firstElementChild : null;
|
|
1448
1696
|
if (first) fiber.liveEl = first;
|
|
1449
1697
|
};
|
|
1698
|
+
const paint$1 = (fiber, view) => {
|
|
1699
|
+
core$1.commit(() => {
|
|
1700
|
+
paintRoot(fiber, view);
|
|
1701
|
+
});
|
|
1702
|
+
};
|
|
1450
1703
|
const paintError$1 = (fiber, e) => {
|
|
1451
1704
|
console.error(e);
|
|
1452
1705
|
paint$1(fiber, errorView(e));
|
|
@@ -1669,6 +1922,7 @@ const ssrOps = {
|
|
|
1669
1922
|
asRoot: (el) => ssrAs(el),
|
|
1670
1923
|
bindEvents: bindSsrEvents,
|
|
1671
1924
|
clearRoot: (root) => ssrAs(root).replaceChildren(),
|
|
1925
|
+
committed: (el) => el,
|
|
1672
1926
|
createElement: createSsrElement,
|
|
1673
1927
|
createRaw: (html, _parent) => [createSsrRaw(html)],
|
|
1674
1928
|
createSlotHost: (slotId) => {
|
|
@@ -1681,6 +1935,12 @@ const ssrOps = {
|
|
|
1681
1935
|
disconnect: (el) => {
|
|
1682
1936
|
el.isConnected = false;
|
|
1683
1937
|
},
|
|
1938
|
+
placeChildren: (root, nodes) => {
|
|
1939
|
+
const host = ssrAs(root);
|
|
1940
|
+
host.replaceChildren();
|
|
1941
|
+
for (const n of nodes) host.append(n);
|
|
1942
|
+
},
|
|
1943
|
+
reuseNode: (host) => ssrAs(host),
|
|
1684
1944
|
setFormControl: (el, key, v) => {
|
|
1685
1945
|
if (key === "value") el.setAttribute("value", String(v ?? ""));
|
|
1686
1946
|
else if (v) el.setAttribute(key, "");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ilha",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.10",
|
|
4
4
|
"description": "Generator-first island UI on Effect",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect",
|
|
@@ -64,10 +64,10 @@
|
|
|
64
64
|
"typecheck": "tsc -p tsconfig.types.json --noEmit"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@happy-dom/global-registrator": "^20.
|
|
68
|
-
"effect": "^4.0.0
|
|
67
|
+
"@happy-dom/global-registrator": "^20.14.5",
|
|
68
|
+
"effect": "^4.0.0"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"effect": "^4.0.0
|
|
71
|
+
"effect": "^4.0.0"
|
|
72
72
|
}
|
|
73
73
|
}
|