ilha 0.14.4 → 0.14.6
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 +1 -1
- package/dist/define.d.ts +1 -1
- package/dist/define.js +1 -1
- package/dist/index.d.ts +51 -5
- package/dist/index.js +102 -6
- 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-hD-OyLIo.js → mount-DiIEX8s7.js} +147 -67
- package/dist/{types-DQVTD0ts.d.ts → types-CyoYWhJf.d.ts} +10 -3
- package/dist/{vnode-DHBqDHtZ.d.ts → vnode-C_BdUnIA.d.ts} +3 -3
- package/dist/{vnode-DP76Gn-b.js → vnode-DEMDQ0eA.js} +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ const total = atom(
|
|
|
60
60
|
);
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
Wrap multiple writes in `batch()`. Derived and mutation atoms use Effect's `Atom.map`, `Atom.transform`, and `Atom.fn` — pass `handle.atom`, then wrap in `atom()`. Use `watch(source, fn)` for side effects on atom changes.
|
|
63
|
+
Wrap multiple writes in `batch()`. Derived and mutation atoms use Effect's `Atom.map`, `Atom.transform`, and `Atom.fn` — pass `handle.atom`, then wrap in `atom()`. Use `watch(source, fn)` for side effects on atom changes. Use `watch.once(fn)` for mount-only work; return a cleanup function to run on unmount. Use `untrack(() => …)` to read without subscribing. Share values with `createContext` / `context()`. Catch subtree failures with `ErrorBoundary`.
|
|
64
64
|
|
|
65
65
|
Use `atom.lazy(() => …)` for one-time initialization or to store a function value.
|
|
66
66
|
|
package/dist/define.d.ts
CHANGED
package/dist/define.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as Instruction, c as
|
|
2
|
-
import { t as h } from "./vnode-
|
|
1
|
+
import { a as Instruction, c as UnsafeHtml, d as Yielded, i as Fragment, n as Component, t as AtomHandle, u as View } from "./types-CyoYWhJf.js";
|
|
2
|
+
import { t as h } from "./vnode-C_BdUnIA.js";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Stream from "effect/Stream";
|
|
5
5
|
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
@@ -11,10 +11,17 @@ type WatchValue = string | number | boolean | bigint | null | undefined | readon
|
|
|
11
11
|
interface WatchRecord {
|
|
12
12
|
readonly [key: string]: WatchValue | undefined;
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/** Optional disposer returned from `watch.once`. */
|
|
15
|
+
type WatchOnceCleanup = () => void;
|
|
16
|
+
interface WatchFn {
|
|
17
|
+
<A extends WatchValue>(source: AtomHandle<A> | Atom.Atom<A> | Stream.Stream<A, unknown, unknown>, fn: (value: A) => void): Instruction<undefined>;
|
|
18
|
+
once: (fn: () => WatchOnceCleanup | undefined) => Instruction<undefined>;
|
|
19
|
+
}
|
|
20
|
+
declare const watch: WatchFn;
|
|
16
21
|
//#endregion
|
|
17
22
|
//#region src/atom.d.ts
|
|
23
|
+
/** Read atoms inside `fn` without subscribing the active render. Sync only. */
|
|
24
|
+
declare const untrack: <A>(fn: () => A) => A;
|
|
18
25
|
interface AtomFn {
|
|
19
26
|
<A>(init: A | Atom.Atom<A> | Effect.Effect<A, unknown, AtomRegistry> | Stream.Stream<A, unknown, AtomRegistry>): AtomHandle<A>;
|
|
20
27
|
lazy: <A>(init: () => A) => AtomHandle<A>;
|
|
@@ -22,6 +29,34 @@ interface AtomFn {
|
|
|
22
29
|
declare const atom: AtomFn;
|
|
23
30
|
declare const batch: (f: () => void) => void;
|
|
24
31
|
//#endregion
|
|
32
|
+
//#region src/context.d.ts
|
|
33
|
+
interface ContextProviderProps<A> {
|
|
34
|
+
value: A;
|
|
35
|
+
children?: View;
|
|
36
|
+
}
|
|
37
|
+
interface IlhaContext<A> {
|
|
38
|
+
readonly id: symbol;
|
|
39
|
+
readonly defaultValue: A;
|
|
40
|
+
readonly Provider: (props: ContextProviderProps<A>) => View;
|
|
41
|
+
}
|
|
42
|
+
declare const createContext: <A>(defaultValue: A) => IlhaContext<A>;
|
|
43
|
+
/** Read a context value as an atom handle. Subscribes the active fiber on read. */
|
|
44
|
+
declare const context: <A>(ctx: IlhaContext<A>) => AtomHandle<A>;
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/error-boundary.d.ts
|
|
47
|
+
interface ErrorFallbackProps {
|
|
48
|
+
error: Error;
|
|
49
|
+
reset: () => void;
|
|
50
|
+
}
|
|
51
|
+
type ErrorFallback = (props: ErrorFallbackProps) => View;
|
|
52
|
+
interface ErrorBoundaryProps {
|
|
53
|
+
fallback?: ErrorFallback;
|
|
54
|
+
onError?: (error: Error) => void;
|
|
55
|
+
children?: View;
|
|
56
|
+
}
|
|
57
|
+
/** Catch subtree failures and paint a fallback. Supports reset(). */
|
|
58
|
+
declare const ErrorBoundary: (props: ErrorBoundaryProps) => View;
|
|
59
|
+
//#endregion
|
|
25
60
|
//#region src/when.d.ts
|
|
26
61
|
declare const when: <A, E = never, R = never>(stream: Stream.Stream<A, E, R>, body: (value: A) => Generator<Yielded, View | undefined, View>) => Instruction<undefined, E>;
|
|
27
62
|
//#endregion
|
|
@@ -39,4 +74,15 @@ interface MountOptions {
|
|
|
39
74
|
declare const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void);
|
|
40
75
|
declare const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>;
|
|
41
76
|
//#endregion
|
|
42
|
-
|
|
77
|
+
//#region src/unsafe.d.ts
|
|
78
|
+
/**
|
|
79
|
+
* Mark a string as pre-rendered HTML and paint it without escaping.
|
|
80
|
+
* Use it for markup you built or sanitized yourself — SVG from an external
|
|
81
|
+
* library, Markdown rendered to HTML, embed codes. Never pass untrusted
|
|
82
|
+
* user input: unlike interpolated strings, this content is not escaped and
|
|
83
|
+
* scripts inserted this way do not run, but event attributes and other
|
|
84
|
+
* markup still apply.
|
|
85
|
+
*/
|
|
86
|
+
declare const unsafe: (html: string) => UnsafeHtml;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { type AtomHandle, type Component, type ContextProviderProps, ErrorBoundary, type ErrorBoundaryProps, type ErrorFallback, type ErrorFallbackProps, Fragment, type IlhaContext, type MountOptions, type RenderToStringOptions, type UnsafeHtml, type View, type WatchOnceCleanup, atom, batch, context, createContext, h, mount, renderToString, unsafe, untrack, watch, when };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,82 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { i as Fragment, t as h } from "./vnode-
|
|
1
|
+
import { a as interpret, c as handleOwner, d as untrack, f as wrapHandle, g as makeFiber, h as getFiber, i as runSetup, l as instr, m as closeFiber, n as renderToString, o as atom, p as clearFiberView, r as unsafe, s as batch, t as mount, u as isAtomHandle } from "./mount-DiIEX8s7.js";
|
|
2
|
+
import { d as errorView, i as Fragment, p as isFunction, t as h } from "./vnode-DEMDQ0eA.js";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Stream from "effect/Stream";
|
|
5
|
+
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
5
6
|
import * as Exit from "effect/Exit";
|
|
6
7
|
import * as Fiber from "effect/Fiber";
|
|
7
8
|
import * as Scope from "effect/Scope";
|
|
8
9
|
import * as Registry from "effect/unstable/reactivity/AtomRegistry";
|
|
9
10
|
|
|
11
|
+
//#region src/context.ts
|
|
12
|
+
const defaults = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
const getDefaultAtom = (ctx) => {
|
|
14
|
+
const existing = defaults.get(ctx);
|
|
15
|
+
if (existing) return existing;
|
|
16
|
+
const made = Atom.make(ctx.defaultValue);
|
|
17
|
+
defaults.set(ctx, made);
|
|
18
|
+
return made;
|
|
19
|
+
};
|
|
20
|
+
const createContext = (defaultValue) => {
|
|
21
|
+
const id = Symbol("ilha.context");
|
|
22
|
+
const Provider = (props) => {
|
|
23
|
+
const fiber = getFiber();
|
|
24
|
+
const { value: next, children } = props;
|
|
25
|
+
const handle = atom(next);
|
|
26
|
+
if (!Object.is(untrack(() => handle()), next)) handle.set(next);
|
|
27
|
+
fiber.contexts ??= /* @__PURE__ */ new Map();
|
|
28
|
+
fiber.contexts.set(id, handle.atom);
|
|
29
|
+
return children;
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
Provider,
|
|
33
|
+
defaultValue,
|
|
34
|
+
id
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/** Read a context value as an atom handle. Subscribes the active fiber on read. */
|
|
38
|
+
const context = (ctx) => {
|
|
39
|
+
const fiber = getFiber();
|
|
40
|
+
let current = fiber;
|
|
41
|
+
while (current) {
|
|
42
|
+
const found = current.contexts?.get(ctx.id);
|
|
43
|
+
if (found) return wrapHandle(found, fiber);
|
|
44
|
+
current = current.parent;
|
|
45
|
+
}
|
|
46
|
+
return wrapHandle(getDefaultAtom(ctx), fiber);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/error-boundary.ts
|
|
51
|
+
/** Catch subtree failures and paint a fallback. Supports reset(). */
|
|
52
|
+
const ErrorBoundary = (props) => {
|
|
53
|
+
const fiber = getFiber();
|
|
54
|
+
const remount = () => {
|
|
55
|
+
if (fiber.closed) return;
|
|
56
|
+
clearFiberView(fiber);
|
|
57
|
+
const current = fiber.propsBox?.current ?? props;
|
|
58
|
+
runSetup(fiber, () => ErrorBoundary(current));
|
|
59
|
+
};
|
|
60
|
+
fiber.handleError = (error) => {
|
|
61
|
+
if (fiber.closed) return;
|
|
62
|
+
clearFiberView(fiber);
|
|
63
|
+
const { onError, fallback } = fiber.propsBox?.current ?? props;
|
|
64
|
+
if (isFunction(onError)) onError(error);
|
|
65
|
+
if (isFunction(fallback)) {
|
|
66
|
+
fiber.paint(fallback({
|
|
67
|
+
error,
|
|
68
|
+
reset: remount
|
|
69
|
+
}));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
fiber.paint(errorView(error));
|
|
73
|
+
};
|
|
74
|
+
return props.children;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
10
78
|
//#region src/watch.ts
|
|
79
|
+
const WATCH_ONCE = Symbol("ilha.watch.once");
|
|
11
80
|
const runStreamWatch = (fiber, effect) => {
|
|
12
81
|
const scope = Scope.forkUnsafe(fiber.scope);
|
|
13
82
|
const provided = effect.pipe(Effect.provideService(Registry.AtomRegistry, fiber.registry));
|
|
@@ -24,7 +93,7 @@ const useWatchSlot = (fiber, key, mount, fn) => {
|
|
|
24
93
|
const existing = fiber.watchSlots[i];
|
|
25
94
|
if (existing) {
|
|
26
95
|
if (existing.key === key) {
|
|
27
|
-
existing.fnRef.current = fn;
|
|
96
|
+
if (existing.fnRef) existing.fnRef.current = fn;
|
|
28
97
|
return;
|
|
29
98
|
}
|
|
30
99
|
existing.dispose();
|
|
@@ -58,12 +127,36 @@ const registerWatch = (fiber, source, fn) => {
|
|
|
58
127
|
const atom = isAtomHandle(source) ? source.atom : source;
|
|
59
128
|
useWatchSlot(fiber, atom, (run) => fiber.registry.subscribe(atom, run, { immediate: true }), fn);
|
|
60
129
|
};
|
|
130
|
+
/** Run `fn` once on mount. Return a function to clean up on unmount. */
|
|
131
|
+
const watchOnce = (fn) => {
|
|
132
|
+
const fiber = getFiber();
|
|
133
|
+
const i = fiber.watchI ?? 0;
|
|
134
|
+
fiber.watchI = i + 1;
|
|
135
|
+
fiber.watchSlots ??= [];
|
|
136
|
+
const existing = fiber.watchSlots[i];
|
|
137
|
+
if (existing) {
|
|
138
|
+
if (existing.key === WATCH_ONCE) return instr(Effect.void);
|
|
139
|
+
existing.dispose();
|
|
140
|
+
fiber.watchSlots[i] = void 0;
|
|
141
|
+
}
|
|
142
|
+
let cleanup = fn();
|
|
143
|
+
fiber.watchSlots[i] = {
|
|
144
|
+
dispose: () => {
|
|
145
|
+
const run = cleanup;
|
|
146
|
+
cleanup = void 0;
|
|
147
|
+
run?.();
|
|
148
|
+
},
|
|
149
|
+
key: WATCH_ONCE
|
|
150
|
+
};
|
|
151
|
+
return instr(Effect.void);
|
|
152
|
+
};
|
|
61
153
|
/** Run `fn` when `source` changes — and once on mount. Sync, async, and generator components. */
|
|
62
|
-
const
|
|
154
|
+
const watchSource = (source, fn) => {
|
|
63
155
|
const fiber = (isAtomHandle(source) ? handleOwner.get(source) : void 0) ?? getFiber();
|
|
64
156
|
registerWatch(fiber, source, fn);
|
|
65
157
|
return instr(Effect.void);
|
|
66
158
|
};
|
|
159
|
+
const watch = Object.assign(watchSource, { once: watchOnce });
|
|
67
160
|
|
|
68
161
|
//#endregion
|
|
69
162
|
//#region src/when.ts
|
|
@@ -78,10 +171,13 @@ const when = (stream, body) => instr(Effect.gen(function* whenBody() {
|
|
|
78
171
|
const src = parent.runtime.ssr ? base.pipe(Stream.take(1)) : base;
|
|
79
172
|
yield* Stream.runForEach(src, (value) => Effect.sync(() => {
|
|
80
173
|
if (child) closeFiber(child);
|
|
81
|
-
child = makeFiber(parent.runtime, parent.root, parent.paintFn, {
|
|
174
|
+
child = makeFiber(parent.runtime, parent.root, parent.paintFn, {
|
|
175
|
+
onFail: parent.fail,
|
|
176
|
+
parent
|
|
177
|
+
});
|
|
82
178
|
interpret((() => body(value)), child);
|
|
83
179
|
}));
|
|
84
180
|
}));
|
|
85
181
|
|
|
86
182
|
//#endregion
|
|
87
|
-
export { Fragment, atom, batch, h, mount, renderToString, watch, when };
|
|
183
|
+
export { ErrorBoundary, Fragment, atom, batch, context, createContext, h, mount, renderToString, unsafe, untrack, watch, when };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as Fragment } from "./types-
|
|
2
|
-
import { n as JSX } from "./vnode-
|
|
1
|
+
import { i as Fragment } from "./types-CyoYWhJf.js";
|
|
2
|
+
import { n as JSX } from "./vnode-C_BdUnIA.js";
|
|
3
3
|
import { jsx, jsxDEV, jsxs } from "./jsx-runtime.js";
|
|
4
4
|
export { Fragment, type JSX, jsx, jsxDEV, jsxs };
|
package/dist/jsx-dev-runtime.js
CHANGED
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as JSX, t as h } from "./vnode-
|
|
1
|
+
import { i as Fragment, o as JsxComponent, r as ComponentFn, s as PropBag, u as View } from "./types-CyoYWhJf.js";
|
|
2
|
+
import { n as JSX, t as h } from "./vnode-C_BdUnIA.js";
|
|
3
3
|
//#region src/jsx-runtime.d.ts
|
|
4
|
-
declare const jsx: (type: string | Fragment | ComponentFn, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
5
|
-
declare const jsxs: (type: string | Fragment | ComponentFn, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
6
|
-
declare const jsxDEV: (type: string | Fragment | ComponentFn, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
4
|
+
declare const jsx: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
5
|
+
declare const jsxs: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
6
|
+
declare const jsxDEV: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null, key?: string | number) => ReturnType<typeof h>;
|
|
7
7
|
//#endregion
|
|
8
8
|
export { Fragment, type JSX, type View, h, jsx, jsxDEV, jsxs };
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as skip, a as ISLAND, b as failureMessage, c as KEEP, d as errorView, f as isBigInt, g as isString, h as isObject, i as Fragment, l as KEY_ATTR, m as isNumber, n as isSetupFn, o as ISLAND_MOUNT_INTERNAL, p as isFunction, r as isVNode, s as ISLAND_SLOT_TAG, u as SLOT_ATTR, v as unwrap, y as asFailure } from "./vnode-
|
|
1
|
+
import { _ as skip, a as ISLAND, b as failureMessage, c as KEEP, d as errorView, f as isBigInt, g as isString, h as isObject, i as Fragment, l as KEY_ATTR, m as isNumber, n as isSetupFn, o as ISLAND_MOUNT_INTERNAL, p as isFunction, r as isVNode, s as ISLAND_SLOT_TAG, u as SLOT_ATTR, v as unwrap, x as toError, y as asFailure } from "./vnode-DEMDQ0eA.js";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Stream from "effect/Stream";
|
|
4
4
|
import * as Atom from "effect/unstable/reactivity/Atom";
|
|
@@ -34,17 +34,27 @@ const runInScope = (effect, registry, scope, onOk, onErr, onDone) => {
|
|
|
34
34
|
}))) : provided);
|
|
35
35
|
Effect.runSync(Scope.addFinalizer(scope, Fiber.interrupt(f)));
|
|
36
36
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
fiber.closed = true;
|
|
40
|
-
fiber.trackRestore?.();
|
|
41
|
-
fiber.trackRestore = void 0;
|
|
37
|
+
/** Clear render subscriptions and child holes without closing the fiber scope. */
|
|
38
|
+
const clearFiberView = (fiber) => {
|
|
42
39
|
fiber.renderSub?.();
|
|
43
40
|
fiber.renderSub = void 0;
|
|
44
41
|
for (const slot of fiber.watchSlots ?? []) slot?.dispose();
|
|
45
42
|
fiber.watchSlots = [];
|
|
43
|
+
fiber.watchI = 0;
|
|
44
|
+
fiber.primitives = void 0;
|
|
45
|
+
fiber.primitiveI = 0;
|
|
46
|
+
fiber.islandFrame = void 0;
|
|
47
|
+
fiber.keyedHoles = void 0;
|
|
46
48
|
for (const h of fiber.holes) h.dispose();
|
|
47
49
|
fiber.holes = [];
|
|
50
|
+
};
|
|
51
|
+
const closeFiber = (fiber) => {
|
|
52
|
+
if (fiber.closed) return;
|
|
53
|
+
fiber.closed = true;
|
|
54
|
+
fiber.trackRestore?.();
|
|
55
|
+
fiber.trackRestore = void 0;
|
|
56
|
+
fiber.handleError = void 0;
|
|
57
|
+
clearFiberView(fiber);
|
|
48
58
|
Effect.runFork(Scope.close(fiber.scope, Exit.void));
|
|
49
59
|
};
|
|
50
60
|
const makeRuntime = (opts) => {
|
|
@@ -107,6 +117,7 @@ const makeFiber = (runtime, root, paint, opts) => {
|
|
|
107
117
|
inFlight: false,
|
|
108
118
|
paint: (view) => paint(fiber, view),
|
|
109
119
|
paintFn: paint,
|
|
120
|
+
parent: opts?.parent,
|
|
110
121
|
registry: runtime.registry,
|
|
111
122
|
root,
|
|
112
123
|
run: (effect, onOk, onErr) => {
|
|
@@ -123,6 +134,19 @@ const makeFiber = (runtime, root, paint, opts) => {
|
|
|
123
134
|
};
|
|
124
135
|
return fiber;
|
|
125
136
|
};
|
|
137
|
+
/** Walk this fiber and ancestors for an error boundary handler. */
|
|
138
|
+
const reportFiberError = (fiber, error) => {
|
|
139
|
+
let current = fiber;
|
|
140
|
+
while (current) {
|
|
141
|
+
const { handleError } = current;
|
|
142
|
+
if (handleError) {
|
|
143
|
+
handleError(error);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
current = current.parent;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
};
|
|
126
150
|
|
|
127
151
|
//#endregion
|
|
128
152
|
//#region src/atom.ts
|
|
@@ -161,6 +185,16 @@ const instr = (effect) => {
|
|
|
161
185
|
const isAtomHandle = (x) => isFunction(x) && x.$$atom === 1;
|
|
162
186
|
let trackGet;
|
|
163
187
|
const trackStack = [];
|
|
188
|
+
/** Read atoms inside `fn` without subscribing the active render. Sync only. */
|
|
189
|
+
const untrack = (fn) => {
|
|
190
|
+
const prev = trackGet;
|
|
191
|
+
trackGet = void 0;
|
|
192
|
+
try {
|
|
193
|
+
return fn();
|
|
194
|
+
} finally {
|
|
195
|
+
trackGet = prev;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
164
198
|
const beginPrimitiveFrame = (fiber) => {
|
|
165
199
|
const used = fiber.primitiveI ?? 0;
|
|
166
200
|
const slots = fiber.primitives?.length ?? 0;
|
|
@@ -377,6 +411,60 @@ const interpret = (gen, fiber) => {
|
|
|
377
411
|
resume();
|
|
378
412
|
};
|
|
379
413
|
|
|
414
|
+
//#endregion
|
|
415
|
+
//#region src/start.ts
|
|
416
|
+
const isGen = (x) => {
|
|
417
|
+
if (x === null || x === void 0) return false;
|
|
418
|
+
const g = x;
|
|
419
|
+
return isFunction(g.next) && isFunction(g.throw);
|
|
420
|
+
};
|
|
421
|
+
const finish = (fiber, view) => {
|
|
422
|
+
if (fiber.closed) return;
|
|
423
|
+
if (view !== void 0) fiber.paint(view);
|
|
424
|
+
};
|
|
425
|
+
const runSetup = (fiber, fn) => {
|
|
426
|
+
const disposeRenderSub = () => {
|
|
427
|
+
fiber.renderSub?.();
|
|
428
|
+
fiber.renderSub = void 0;
|
|
429
|
+
};
|
|
430
|
+
const api = {
|
|
431
|
+
commit: (out, deps) => {
|
|
432
|
+
if (isGen(out)) {
|
|
433
|
+
disposeRenderSub();
|
|
434
|
+
interpret((() => out), fiber);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
disposeRenderSub();
|
|
438
|
+
if (!fiber.runtime.ssr) fiber.renderSub = subscribeRenderDeps(fiber, deps, () => api.render());
|
|
439
|
+
withFiber(fiber, () => {
|
|
440
|
+
finish(fiber, out);
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
render: () => {
|
|
444
|
+
if (fiber.closed) return;
|
|
445
|
+
fiber.runtime.begin();
|
|
446
|
+
beginPrimitiveFrame(fiber);
|
|
447
|
+
withTrackGetRun(fiber, () => fn(), ({ value: out, deps }) => {
|
|
448
|
+
try {
|
|
449
|
+
api.commit(out, deps);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
withFiber(fiber, () => fiber.fail(asFailure(error)));
|
|
452
|
+
} finally {
|
|
453
|
+
fiber.runtime.end();
|
|
454
|
+
}
|
|
455
|
+
}, (e) => {
|
|
456
|
+
withFiber(fiber, () => fiber.fail(asFailure(e)));
|
|
457
|
+
fiber.runtime.end();
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
try {
|
|
462
|
+
api.render();
|
|
463
|
+
} catch (error) {
|
|
464
|
+
fiber.fail(asFailure(error));
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
380
468
|
//#endregion
|
|
381
469
|
//#region src/events.ts
|
|
382
470
|
const ACTION_CALL$1 = Symbol.for("ilha.actionCall");
|
|
@@ -538,8 +626,13 @@ const morphElementPair = (fromEl, toEl, api) => {
|
|
|
538
626
|
fromEl.replaceWith(toEl);
|
|
539
627
|
return;
|
|
540
628
|
}
|
|
541
|
-
const
|
|
542
|
-
|
|
629
|
+
const toSlot = toEl.getAttribute(SLOT_ATTR);
|
|
630
|
+
const fromSlot = fromEl.getAttribute(SLOT_ATTR);
|
|
631
|
+
if (toSlot !== null && fromSlot === toSlot) return;
|
|
632
|
+
if (toSlot !== null) {
|
|
633
|
+
fromEl.replaceWith(toEl);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
543
636
|
if (fromEl.localName === "input") {
|
|
544
637
|
morphInput(fromEl, toEl);
|
|
545
638
|
return;
|
|
@@ -692,57 +785,22 @@ const serializeStyleAttr = (value) => {
|
|
|
692
785
|
};
|
|
693
786
|
|
|
694
787
|
//#endregion
|
|
695
|
-
//#region src/
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
commit: (out, deps) => {
|
|
712
|
-
if (isGen(out)) {
|
|
713
|
-
disposeRenderSub();
|
|
714
|
-
interpret((() => out), fiber);
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
disposeRenderSub();
|
|
718
|
-
if (!fiber.runtime.ssr) fiber.renderSub = subscribeRenderDeps(fiber, deps, () => api.render());
|
|
719
|
-
withFiber(fiber, () => {
|
|
720
|
-
finish(fiber, out);
|
|
721
|
-
});
|
|
722
|
-
},
|
|
723
|
-
render: () => {
|
|
724
|
-
if (fiber.closed) return;
|
|
725
|
-
fiber.runtime.begin();
|
|
726
|
-
beginPrimitiveFrame(fiber);
|
|
727
|
-
withTrackGetRun(fiber, () => fn(), ({ value: out, deps }) => {
|
|
728
|
-
try {
|
|
729
|
-
api.commit(out, deps);
|
|
730
|
-
} catch (error) {
|
|
731
|
-
withFiber(fiber, () => fiber.fail(asFailure(error)));
|
|
732
|
-
} finally {
|
|
733
|
-
fiber.runtime.end();
|
|
734
|
-
}
|
|
735
|
-
}, (e) => {
|
|
736
|
-
withFiber(fiber, () => fiber.fail(asFailure(e)));
|
|
737
|
-
fiber.runtime.end();
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
try {
|
|
742
|
-
api.render();
|
|
743
|
-
} catch (error) {
|
|
744
|
-
fiber.fail(asFailure(error));
|
|
745
|
-
}
|
|
788
|
+
//#region src/unsafe.ts
|
|
789
|
+
/**
|
|
790
|
+
* Mark a string as pre-rendered HTML and paint it without escaping.
|
|
791
|
+
* Use it for markup you built or sanitized yourself — SVG from an external
|
|
792
|
+
* library, Markdown rendered to HTML, embed codes. Never pass untrusted
|
|
793
|
+
* user input: unlike interpolated strings, this content is not escaped and
|
|
794
|
+
* scripts inserted this way do not run, but event attributes and other
|
|
795
|
+
* markup still apply.
|
|
796
|
+
*/
|
|
797
|
+
const unsafe = (html) => ({
|
|
798
|
+
$$ilhaUnsafe: 1,
|
|
799
|
+
html
|
|
800
|
+
});
|
|
801
|
+
const isUnsafeHtml = (x) => {
|
|
802
|
+
if (!isObject(x)) return false;
|
|
803
|
+
return x.$$ilhaUnsafe === 1;
|
|
746
804
|
};
|
|
747
805
|
|
|
748
806
|
//#endregion
|
|
@@ -862,10 +920,15 @@ const createPainter = (ops) => {
|
|
|
862
920
|
openHole: (parent) => {
|
|
863
921
|
const id = parent.runtime.nextHole();
|
|
864
922
|
const host = ops.createSlotHost(String(id));
|
|
865
|
-
const child = makeFiber(parent.runtime, ops.asRoot(host), (f, v) => api.paintHole(f, v), {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
923
|
+
const child = makeFiber(parent.runtime, ops.asRoot(host), (f, v) => api.paintHole(f, v), {
|
|
924
|
+
onFail: (e) => {
|
|
925
|
+
const error = toError(e);
|
|
926
|
+
if (reportFiberError(child, error)) return;
|
|
927
|
+
console.error(error);
|
|
928
|
+
api.paintHole(child, errorView(error));
|
|
929
|
+
},
|
|
930
|
+
parent
|
|
931
|
+
});
|
|
869
932
|
return {
|
|
870
933
|
fiber: child,
|
|
871
934
|
nodes: [host]
|
|
@@ -979,9 +1042,10 @@ const createPainter = (ops) => {
|
|
|
979
1042
|
if (branded[ISLAND] === true) return materializeIsland(branded, props, fiber);
|
|
980
1043
|
const k = view.key === null || view.key === void 0 ? void 0 : String(view.key);
|
|
981
1044
|
const reuse = k ? fiber.keyedHoles?.get(k) : void 0;
|
|
1045
|
+
const run = type;
|
|
982
1046
|
if (reuse && !reuse.closed) {
|
|
983
1047
|
if (reuse.propsBox) reuse.propsBox.current = props;
|
|
984
|
-
const next = withFiber(fiber, () =>
|
|
1048
|
+
const next = withFiber(fiber, () => run(reuse.propsBox?.current ?? props));
|
|
985
1049
|
if (next && !isThenable(next) && !isSetupFn(next)) reuse.paint(next);
|
|
986
1050
|
return [ops.asNode(reuse.root)];
|
|
987
1051
|
}
|
|
@@ -995,7 +1059,7 @@ const createPainter = (ops) => {
|
|
|
995
1059
|
if (hole.closed) return;
|
|
996
1060
|
const box = hole.propsBox;
|
|
997
1061
|
if (!box) return;
|
|
998
|
-
runSetup(hole, () =>
|
|
1062
|
+
runSetup(hole, () => run(box.current));
|
|
999
1063
|
});
|
|
1000
1064
|
trackHole(fiber, hole, void 0, k ? { keyed: true } : void 0);
|
|
1001
1065
|
return nodes;
|
|
@@ -1021,6 +1085,7 @@ const createPainter = (ops) => {
|
|
|
1021
1085
|
};
|
|
1022
1086
|
paintFns.materialize = (view, fiber) => {
|
|
1023
1087
|
if (skip(view)) return [];
|
|
1088
|
+
if (isUnsafeHtml(view)) return ops.createRaw(view.html, fiber.root);
|
|
1024
1089
|
if (isTextish(view)) return [ops.createText(String(view))];
|
|
1025
1090
|
if (isAtomHandle(view)) return materializeAtom(view, fiber);
|
|
1026
1091
|
if (Stream.isStream(view)) return materializeStream(view, fiber);
|
|
@@ -1081,6 +1146,11 @@ const core$1 = createPainter({
|
|
|
1081
1146
|
if (root instanceof Element) root.replaceChildren();
|
|
1082
1147
|
},
|
|
1083
1148
|
createElement: (tag) => document.createElement(tag),
|
|
1149
|
+
createRaw: (html, parent) => {
|
|
1150
|
+
const range = document.createRange();
|
|
1151
|
+
range.selectNodeContents(parent);
|
|
1152
|
+
return [...range.createContextualFragment(html).childNodes];
|
|
1153
|
+
},
|
|
1084
1154
|
createSlotHost: (slotId) => {
|
|
1085
1155
|
const host = document.createElement("span");
|
|
1086
1156
|
if (slotId !== null) host.setAttribute(SLOT_ATTR, slotId);
|
|
@@ -1253,6 +1323,10 @@ const VOID = /* @__PURE__ */ new Set([
|
|
|
1253
1323
|
const RAW_TEXT = /* @__PURE__ */ new Set(["script", "style"]);
|
|
1254
1324
|
const escapeText = (s) => s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1255
1325
|
const escapeAttr = (s) => escapeText(s).replaceAll("\"", """);
|
|
1326
|
+
const createSsrRaw = (html) => ({
|
|
1327
|
+
html,
|
|
1328
|
+
kind: "raw"
|
|
1329
|
+
});
|
|
1256
1330
|
const createSsrText = (text) => ({
|
|
1257
1331
|
kind: "text",
|
|
1258
1332
|
text
|
|
@@ -1263,6 +1337,7 @@ const serializeRawText = (tag, text) => {
|
|
|
1263
1337
|
};
|
|
1264
1338
|
const serializeNode = (node) => {
|
|
1265
1339
|
if (node.kind === "text") return escapeText(node.text);
|
|
1340
|
+
if (node.kind === "raw") return node.html;
|
|
1266
1341
|
const parts = [];
|
|
1267
1342
|
for (const [name, value] of node.attrs) parts.push(`${name}="${escapeAttr(value)}"`);
|
|
1268
1343
|
const attr = parts.length > 0 ? ` ${parts.join(" ")}` : "";
|
|
@@ -1319,7 +1394,11 @@ const createSsrElement = (tag) => {
|
|
|
1319
1394
|
tag: lower,
|
|
1320
1395
|
tagName: lower.toUpperCase(),
|
|
1321
1396
|
get textContent() {
|
|
1322
|
-
return children.map((n) =>
|
|
1397
|
+
return children.map((n) => {
|
|
1398
|
+
if (n.kind === "text") return n.text;
|
|
1399
|
+
if (n.kind === "raw") return n.html;
|
|
1400
|
+
return n.textContent;
|
|
1401
|
+
}).join("");
|
|
1323
1402
|
},
|
|
1324
1403
|
set textContent(value) {
|
|
1325
1404
|
children.length = 0;
|
|
@@ -1390,6 +1469,7 @@ const ssrOps = {
|
|
|
1390
1469
|
bindEvents: bindSsrEvents,
|
|
1391
1470
|
clearRoot: (root) => ssrAs(root).replaceChildren(),
|
|
1392
1471
|
createElement: createSsrElement,
|
|
1472
|
+
createRaw: (html, _parent) => [createSsrRaw(html)],
|
|
1393
1473
|
createSlotHost: (slotId) => {
|
|
1394
1474
|
const host = createSsrElement("span");
|
|
1395
1475
|
if (slotId !== null) host.setAttribute(SLOT_ATTR, slotId);
|
|
@@ -1516,4 +1596,4 @@ const renderToString = async (fn, opts) => {
|
|
|
1516
1596
|
};
|
|
1517
1597
|
|
|
1518
1598
|
//#endregion
|
|
1519
|
-
export {
|
|
1599
|
+
export { interpret as a, handleOwner as c, untrack as d, wrapHandle as f, makeFiber as g, getFiber as h, runSetup as i, instr as l, closeFiber as m, renderToString as n, atom as o, clearFiberView as p, unsafe as r, batch as s, mount as t, isAtomHandle as u };
|
|
@@ -12,13 +12,20 @@ type EventHandler = (event: Event) => void;
|
|
|
12
12
|
interface PropBag {
|
|
13
13
|
readonly [key: string]: PropValue | undefined;
|
|
14
14
|
}
|
|
15
|
-
type View = VNode | JsonText | AtomHandle<unknown> | Stream.Stream<View, unknown, unknown> | GeneratorFn | Component | View[] | Iterable<View>;
|
|
15
|
+
type View = VNode | UnsafeHtml | JsonText | AtomHandle<unknown> | Stream.Stream<View, unknown, unknown> | GeneratorFn | Component | View[] | Iterable<View>;
|
|
16
16
|
declare const Fragment: unique symbol;
|
|
17
17
|
type Fragment = typeof Fragment;
|
|
18
18
|
type ComponentFn = (props: PropBag) => View | Promise<View | undefined> | undefined;
|
|
19
|
+
/** JSX/tag component with its own props shape (Provider, ErrorBoundary, …). */
|
|
20
|
+
type JsxComponent = (props: never) => View | Promise<View | undefined> | Generator<View, View | undefined, View> | undefined;
|
|
21
|
+
/** Raw HTML view produced by `unsafe()` — painted without escaping. */
|
|
22
|
+
interface UnsafeHtml {
|
|
23
|
+
readonly $$ilhaUnsafe: 1;
|
|
24
|
+
readonly html: string;
|
|
25
|
+
}
|
|
19
26
|
interface VNode {
|
|
20
27
|
readonly $$ilha: 1;
|
|
21
|
-
readonly type: string | Fragment | ComponentFn;
|
|
28
|
+
readonly type: string | Fragment | ComponentFn | JsxComponent;
|
|
22
29
|
readonly props: PropBag;
|
|
23
30
|
readonly children: View[];
|
|
24
31
|
readonly key?: string | number;
|
|
@@ -38,4 +45,4 @@ interface AtomHandle<A> {
|
|
|
38
45
|
update: (f: (current: A) => A) => void;
|
|
39
46
|
}
|
|
40
47
|
//#endregion
|
|
41
|
-
export { Instruction as a,
|
|
48
|
+
export { Instruction as a, UnsafeHtml as c, Yielded as d, Fragment as i, VNode as l, Component as n, JsxComponent as o, ComponentFn as r, PropBag as s, AtomHandle as t, View as u };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as Fragment, l as VNode, o as JsxComponent, r as ComponentFn, s as PropBag, t as AtomHandle, u as View } from "./types-CyoYWhJf.js";
|
|
2
2
|
//#region src/jsx-types.d.ts
|
|
3
3
|
declare namespace JSX {
|
|
4
4
|
export type Element = View;
|
|
5
|
-
export type ElementType = string | ((props:
|
|
5
|
+
export type ElementType = string | ((props: never) => View | Promise<View | undefined> | Generator<View, View | undefined, View> | undefined);
|
|
6
6
|
export interface ElementChildrenAttribute {
|
|
7
7
|
children: View;
|
|
8
8
|
}
|
|
@@ -580,6 +580,6 @@ declare namespace JSX {
|
|
|
580
580
|
}
|
|
581
581
|
//#endregion
|
|
582
582
|
//#region src/vnode.d.ts
|
|
583
|
-
declare const h: (type: string | Fragment | ComponentFn, props: PropBag | null | undefined, ...rest: View[]) => VNode;
|
|
583
|
+
declare const h: (type: string | Fragment | ComponentFn | JsxComponent, props: PropBag | null | undefined, ...rest: View[]) => VNode;
|
|
584
584
|
//#endregion
|
|
585
585
|
export { JSX as n, h as t };
|
|
@@ -10,10 +10,12 @@ const asFailure = (e) => {
|
|
|
10
10
|
}
|
|
11
11
|
return Result.fail(e instanceof Error ? e : new Error(String(e)));
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/** Normalize any thrown failure into an `Error` instance. */
|
|
14
|
+
const toError = (e) => asFailure(e).pipe(Result.match({
|
|
15
|
+
onFailure: (err) => err,
|
|
16
|
+
onSuccess: () => /* @__PURE__ */ new Error("error")
|
|
16
17
|
}));
|
|
18
|
+
const failureMessage = (e) => toError(e).message;
|
|
17
19
|
|
|
18
20
|
//#endregion
|
|
19
21
|
//#region src/shared.ts
|
|
@@ -86,4 +88,4 @@ const isSetupFn = (x) => {
|
|
|
86
88
|
};
|
|
87
89
|
|
|
88
90
|
//#endregion
|
|
89
|
-
export { skip as _, ISLAND as a, failureMessage as b, KEEP as c, errorView as d, isBigInt as f, isString as g, isObject as h, Fragment as i, KEY_ATTR as l, isNumber as m, isSetupFn as n, ISLAND_MOUNT_INTERNAL as o, isFunction as p, isVNode as r, ISLAND_SLOT_TAG as s, h as t, SLOT_ATTR as u, unwrap as v, asFailure as y };
|
|
91
|
+
export { skip as _, ISLAND as a, failureMessage as b, KEEP as c, errorView as d, isBigInt as f, isString as g, isObject as h, Fragment as i, KEY_ATTR as l, isNumber as m, isSetupFn as n, ISLAND_MOUNT_INTERNAL as o, isFunction as p, isVNode as r, ISLAND_SLOT_TAG as s, h as t, SLOT_ATTR as u, unwrap as v, toError as x, asFailure as y };
|