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/README.md
CHANGED
|
@@ -55,10 +55,12 @@ import * as Atom from "effect/unstable/reactivity/Atom";
|
|
|
55
55
|
import { atom } from "ilha";
|
|
56
56
|
|
|
57
57
|
const items = atom([{ n: 1 }, { n: 2 }]);
|
|
58
|
-
const total = atom(
|
|
58
|
+
const total = atom(
|
|
59
|
+
Atom.map(items.atom, (list) => list.reduce((sum, item) => sum + item.n, 0))
|
|
60
|
+
);
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
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`.
|
|
62
64
|
|
|
63
65
|
Use `atom.lazy(() => …)` for one-time initialization or to store a function value.
|
|
64
66
|
|
package/dist/define.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Component } from "./types-
|
|
1
|
+
import { n as Component } from "./types-CUQdA6hR.js";
|
|
2
2
|
//#region src/define.d.ts
|
|
3
|
-
declare
|
|
3
|
+
declare const define: (name: string, component: Component) => void;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { define };
|
package/dist/define.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { t as mount } from "./mount-
|
|
1
|
+
import { t as mount } from "./mount-C5idXX3H.js";
|
|
2
2
|
|
|
3
3
|
//#region src/define.ts
|
|
4
|
-
|
|
4
|
+
const define = (name, component) => {
|
|
5
5
|
customElements.define(name, class extends HTMLElement {
|
|
6
6
|
#unmount;
|
|
7
7
|
connectedCallback() {
|
|
8
|
-
this.#unmount = mount(this, component, { hydrate: this.
|
|
8
|
+
this.#unmount = mount(this, component, { hydrate: this.matches("[data-ilha]") });
|
|
9
9
|
}
|
|
10
10
|
disconnectedCallback() {
|
|
11
11
|
this.#unmount?.();
|
|
12
12
|
this.#unmount = void 0;
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
18
|
export { define };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,37 +1,77 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as h } from "./vnode-
|
|
1
|
+
import { a as Instruction, i as Fragment, l as View, n as Component, t as AtomHandle, u as Yielded } from "./types-CUQdA6hR.js";
|
|
2
|
+
import { t as h } from "./vnode-Bwx8ffNO.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";
|
|
6
6
|
import "effect/Scope";
|
|
7
7
|
import { AtomRegistry } from "effect/unstable/reactivity/AtomRegistry";
|
|
8
8
|
//#region src/watch.d.ts
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/** Values delivered to watch callbacks. */
|
|
10
|
+
type WatchValue = string | number | boolean | bigint | null | undefined | readonly WatchValue[] | WatchRecord;
|
|
11
|
+
interface WatchRecord {
|
|
12
|
+
readonly [key: string]: WatchValue | undefined;
|
|
13
|
+
}
|
|
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;
|
|
11
21
|
//#endregion
|
|
12
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;
|
|
13
25
|
interface AtomFn {
|
|
14
|
-
<A>(init: A | Atom.Atom<A> | Effect.Effect<A,
|
|
15
|
-
lazy<A>(init: () => A)
|
|
26
|
+
<A>(init: A | Atom.Atom<A> | Effect.Effect<A, unknown, AtomRegistry> | Stream.Stream<A, unknown, AtomRegistry>): AtomHandle<A>;
|
|
27
|
+
lazy: <A>(init: () => A) => AtomHandle<A>;
|
|
16
28
|
}
|
|
17
29
|
declare const atom: AtomFn;
|
|
18
30
|
declare const batch: (f: () => void) => void;
|
|
19
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
|
|
20
60
|
//#region src/when.d.ts
|
|
21
|
-
declare
|
|
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>;
|
|
22
62
|
//#endregion
|
|
23
63
|
//#region src/mount.d.ts
|
|
24
|
-
|
|
64
|
+
interface RenderToStringOptions {
|
|
25
65
|
snapshot?: boolean;
|
|
26
66
|
markers?: boolean;
|
|
27
67
|
timeout?: number;
|
|
28
68
|
captureActions?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
69
|
+
}
|
|
70
|
+
interface MountOptions {
|
|
31
71
|
hydrate?: boolean;
|
|
32
|
-
onError?: (error:
|
|
33
|
-
}
|
|
34
|
-
declare
|
|
35
|
-
declare
|
|
72
|
+
onError?: <E>(error: E) => void;
|
|
73
|
+
}
|
|
74
|
+
declare const mount: (el: Element, fn: Component, opts?: MountOptions) => (() => void);
|
|
75
|
+
declare const renderToString: (fn: Component, opts?: RenderToStringOptions) => Promise<string>;
|
|
36
76
|
//#endregion
|
|
37
|
-
export { type AtomHandle, type Component, Fragment, type MountOptions, type RenderToStringOptions, type View, atom, batch, h, mount, renderToString, watch, when };
|
|
77
|
+
export { type AtomHandle, type Component, type ContextProviderProps, ErrorBoundary, type ErrorBoundaryProps, type ErrorFallback, type ErrorFallbackProps, Fragment, type IlhaContext, type MountOptions, type RenderToStringOptions, type View, type WatchOnceCleanup, atom, batch, context, createContext, h, mount, renderToString, untrack, watch, when };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,83 @@
|
|
|
1
|
-
import { a as atom, c as instr, d as
|
|
2
|
-
import { i as Fragment, t as h } from "./vnode-
|
|
1
|
+
import { a as atom, c as instr, d as wrapHandle, f as clearFiberView, h as makeFiber, i as interpret, l as isAtomHandle, m as getFiber, n as renderToString, o as batch, p as closeFiber, r as runSetup, s as handleOwner, t as mount, u as untrack } from "./mount-C5idXX3H.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
|
|
11
|
-
|
|
79
|
+
const WATCH_ONCE = Symbol("ilha.watch.once");
|
|
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));
|
|
14
83
|
const fork = Effect.runFork(provided);
|
|
@@ -16,31 +85,32 @@ function runStreamWatch(fiber, effect) {
|
|
|
16
85
|
return () => {
|
|
17
86
|
Effect.runFork(Scope.close(scope, Exit.void));
|
|
18
87
|
};
|
|
19
|
-
}
|
|
20
|
-
|
|
88
|
+
};
|
|
89
|
+
const useWatchSlot = (fiber, key, mount, fn) => {
|
|
21
90
|
const i = fiber.watchI ?? 0;
|
|
22
91
|
fiber.watchI = i + 1;
|
|
23
92
|
fiber.watchSlots ??= [];
|
|
24
93
|
const existing = fiber.watchSlots[i];
|
|
25
94
|
if (existing) {
|
|
26
|
-
if (existing.key
|
|
27
|
-
existing.
|
|
28
|
-
fiber.watchSlots[i] = void 0;
|
|
29
|
-
} else {
|
|
30
|
-
existing.fnRef.current = fn;
|
|
95
|
+
if (existing.key === key) {
|
|
96
|
+
if (existing.fnRef) existing.fnRef.current = fn;
|
|
31
97
|
return;
|
|
32
98
|
}
|
|
99
|
+
existing.dispose();
|
|
100
|
+
fiber.watchSlots[i] = void 0;
|
|
33
101
|
}
|
|
34
102
|
const fnRef = { current: fn };
|
|
35
|
-
const unsub = mount((value) =>
|
|
103
|
+
const unsub = mount((value) => {
|
|
104
|
+
fnRef.current(value);
|
|
105
|
+
});
|
|
36
106
|
const dispose = () => unsub();
|
|
37
107
|
fiber.watchSlots[i] = {
|
|
38
|
-
|
|
108
|
+
dispose,
|
|
39
109
|
fnRef,
|
|
40
|
-
|
|
110
|
+
key
|
|
41
111
|
};
|
|
42
|
-
}
|
|
43
|
-
|
|
112
|
+
};
|
|
113
|
+
const registerWatch = (fiber, source, fn) => {
|
|
44
114
|
if (Stream.isStream(source)) {
|
|
45
115
|
useWatchSlot(fiber, source, (run) => {
|
|
46
116
|
let active = true;
|
|
@@ -56,32 +126,58 @@ function registerWatch(fiber, source, fn) {
|
|
|
56
126
|
}
|
|
57
127
|
const atom = isAtomHandle(source) ? source.atom : source;
|
|
58
128
|
useWatchSlot(fiber, atom, (run) => fiber.registry.subscribe(atom, run, { immediate: true }), fn);
|
|
59
|
-
}
|
|
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
|
+
};
|
|
60
153
|
/** Run `fn` when `source` changes — and once on mount. Sync, async, and generator components. */
|
|
61
|
-
|
|
62
|
-
|
|
154
|
+
const watchSource = (source, fn) => {
|
|
155
|
+
const fiber = (isAtomHandle(source) ? handleOwner.get(source) : void 0) ?? getFiber();
|
|
156
|
+
registerWatch(fiber, source, fn);
|
|
63
157
|
return instr(Effect.void);
|
|
64
|
-
}
|
|
158
|
+
};
|
|
159
|
+
const watch = Object.assign(watchSource, { once: watchOnce });
|
|
65
160
|
|
|
66
161
|
//#endregion
|
|
67
162
|
//#region src/when.ts
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
163
|
+
const when = (stream, body) => instr(Effect.gen(function* whenBody() {
|
|
164
|
+
const parent = getFiber();
|
|
165
|
+
let child;
|
|
166
|
+
parent.holes.push({ dispose() {
|
|
167
|
+
if (child) closeFiber(child);
|
|
168
|
+
child = void 0;
|
|
169
|
+
} });
|
|
170
|
+
const base = stream;
|
|
171
|
+
const src = parent.runtime.ssr ? base.pipe(Stream.take(1)) : base;
|
|
172
|
+
yield* Stream.runForEach(src, (value) => Effect.sync(() => {
|
|
173
|
+
if (child) closeFiber(child);
|
|
174
|
+
child = makeFiber(parent.runtime, parent.root, parent.paintFn, {
|
|
175
|
+
onFail: parent.fail,
|
|
176
|
+
parent
|
|
177
|
+
});
|
|
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, untrack, watch, when };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as JSX } from "./vnode-
|
|
1
|
+
import { i as Fragment } from "./types-CUQdA6hR.js";
|
|
2
|
+
import { n as JSX } from "./vnode-Bwx8ffNO.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, l as View, o as JsxComponent, r as ComponentFn, s as PropBag } from "./types-CUQdA6hR.js";
|
|
2
|
+
import { n as JSX, t as h } from "./vnode-Bwx8ffNO.js";
|
|
3
3
|
//#region src/jsx-runtime.d.ts
|
|
4
|
-
declare const jsx: (type: string |
|
|
5
|
-
declare const jsxs: (type: string |
|
|
6
|
-
declare const jsxDEV: (type: string |
|
|
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