@getforma/core 0.6.1 → 0.8.2
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 +125 -15
- package/dist/chunk-3U57L2TY.cjs +38 -0
- package/dist/chunk-3U57L2TY.cjs.map +1 -0
- package/dist/{chunk-TKGUHASG.js → chunk-N522P3G6.js} +20 -12
- package/dist/chunk-N522P3G6.js.map +1 -0
- package/dist/chunk-OZCHIVAZ.js +35 -0
- package/dist/chunk-OZCHIVAZ.js.map +1 -0
- package/dist/{chunk-YSKF3VRA.cjs → chunk-YMIMKO4W.cjs} +51 -20
- package/dist/chunk-YMIMKO4W.cjs.map +1 -0
- package/dist/forma-runtime-csp.js +1 -1
- package/dist/forma-runtime.js +1 -1
- package/dist/formajs-runtime-hardened.global.js +1 -1
- package/dist/formajs-runtime-hardened.global.js.map +1 -1
- package/dist/formajs-runtime.global.js +1 -1
- package/dist/formajs-runtime.global.js.map +1 -1
- package/dist/formajs.global.js +1 -1
- package/dist/formajs.global.js.map +1 -1
- package/dist/index.cjs +112 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -21
- package/dist/index.d.ts +30 -21
- package/dist/index.js +25 -50
- package/dist/index.js.map +1 -1
- package/dist/runtime-hardened.cjs +106 -27
- package/dist/runtime-hardened.cjs.map +1 -1
- package/dist/runtime-hardened.js +107 -28
- package/dist/runtime-hardened.js.map +1 -1
- package/dist/runtime.cjs +128 -50
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +102 -24
- package/dist/runtime.js.map +1 -1
- package/dist/signal-B4_wQJHs.d.cts +53 -0
- package/dist/signal-B4_wQJHs.d.ts +53 -0
- package/dist/ssr/index.cjs +19 -2
- package/dist/ssr/index.cjs.map +1 -1
- package/dist/ssr/index.js +19 -2
- package/dist/ssr/index.js.map +1 -1
- package/dist/tc39-compat.cjs +4 -12
- package/dist/tc39-compat.cjs.map +1 -1
- package/dist/tc39-compat.d.cts +1 -1
- package/dist/tc39-compat.d.ts +1 -1
- package/dist/tc39-compat.js +3 -11
- package/dist/tc39-compat.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-DPSAVBCP.js +0 -26
- package/dist/chunk-DPSAVBCP.js.map +0 -1
- package/dist/chunk-KH3F5NRU.cjs +0 -29
- package/dist/chunk-KH3F5NRU.cjs.map +0 -1
- package/dist/chunk-TKGUHASG.js.map +0 -1
- package/dist/chunk-YSKF3VRA.cjs.map +0 -1
- package/dist/signal-CfLDwMyg.d.cts +0 -29
- package/dist/signal-CfLDwMyg.d.ts +0 -29
package/README.md
CHANGED
|
@@ -162,14 +162,39 @@ mount(() => <Counter />, '#app');
|
|
|
162
162
|
|
|
163
163
|
## CDN Usage
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
### Script tag (IIFE — auto-initializes)
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
```html
|
|
168
|
+
<!-- unpkg -->
|
|
169
|
+
<script src="https://unpkg.com/@getforma/core@0.8.1/dist/formajs-runtime.global.js"></script>
|
|
170
|
+
|
|
171
|
+
<!-- jsDelivr (faster globally) -->
|
|
172
|
+
<script src="https://cdn.jsdelivr.net/npm/@getforma/core@0.8.1/dist/formajs-runtime.global.js"></script>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### ESM import (no bundler, modern browsers)
|
|
176
|
+
|
|
177
|
+
```html
|
|
178
|
+
<script type="module">
|
|
179
|
+
import { createSignal, h, mount } from 'https://cdn.jsdelivr.net/npm/@getforma/core@0.8.1/dist/index.js';
|
|
180
|
+
|
|
181
|
+
const [count, setCount] = createSignal(0);
|
|
182
|
+
mount(() => h('button', { onClick: () => setCount(count() + 1) }, () => `${count()}`), '#app');
|
|
183
|
+
</script>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### All CDN builds
|
|
187
|
+
|
|
188
|
+
| Build | Filename |
|
|
189
|
+
|-------|----------|
|
|
190
|
+
| **Standard** (recommended) | `formajs-runtime.global.js` |
|
|
191
|
+
| **CSP-safe** (no `new Function`) | `formajs-runtime-hardened.global.js` |
|
|
192
|
+
| Standard (short alias) | `forma-runtime.js` |
|
|
193
|
+
| CSP-safe (short alias) | `forma-runtime-csp.js` |
|
|
194
|
+
|
|
195
|
+
Available from both `unpkg.com/@getforma/core@VERSION/dist/` and `cdn.jsdelivr.net/npm/@getforma/core@VERSION/dist/`.
|
|
196
|
+
|
|
197
|
+
For production, always pin the version (e.g., `@0.8.1`). Unversioned URLs resolve to latest.
|
|
173
198
|
|
|
174
199
|
> The CSP build uses a hand-written expression parser and never calls `new Function`.
|
|
175
200
|
> It supports most common patterns. See [examples/csp](./examples/csp) for a working demo.
|
|
@@ -192,6 +217,45 @@ batch(() => {
|
|
|
192
217
|
});
|
|
193
218
|
```
|
|
194
219
|
|
|
220
|
+
#### Custom Equality
|
|
221
|
+
|
|
222
|
+
Skip updates when the new value is equal to the current value:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const [pos, setPos] = createSignal(
|
|
226
|
+
{ x: 0, y: 0 },
|
|
227
|
+
{ equals: (a, b) => a.x === b.x && a.y === b.y },
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
setPos({ x: 0, y: 0 }); // skipped — values are equal
|
|
231
|
+
setPos({ x: 1, y: 0 }); // applied — values differ
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Computed with Previous Value
|
|
235
|
+
|
|
236
|
+
The computed getter receives the previous value for efficient diffing:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
const changes = createComputed((prev) => {
|
|
240
|
+
const current = items();
|
|
241
|
+
if (prev) console.log(`${prev.length} → ${current.length} items`);
|
|
242
|
+
return current;
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### Reactive Introspection
|
|
247
|
+
|
|
248
|
+
Type guards and utilities from alien-signals 3.x:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { isSignal, isComputed, getBatchDepth, trigger } from '@getforma/core';
|
|
252
|
+
|
|
253
|
+
isSignal(count); // true — is this a signal getter?
|
|
254
|
+
isComputed(doubled); // true — is this a computed value?
|
|
255
|
+
getBatchDepth(); // 0 outside batch, 1+ inside
|
|
256
|
+
trigger(doubled); // force recomputation even if deps unchanged
|
|
257
|
+
```
|
|
258
|
+
|
|
195
259
|
### Conditional Rendering
|
|
196
260
|
|
|
197
261
|
```typescript
|
|
@@ -240,12 +304,17 @@ const [state, setState] = createStore({
|
|
|
240
304
|
items: [1, 2, 3],
|
|
241
305
|
});
|
|
242
306
|
|
|
243
|
-
// Read reactively
|
|
307
|
+
// Read reactively — tracked at the exact property path
|
|
244
308
|
state.user.name; // 'Alice'
|
|
309
|
+
state.items[0]; // 1
|
|
310
|
+
|
|
311
|
+
// Setter API — partial object merge (batched)
|
|
312
|
+
setState({ user: { ...state.user, name: 'Bob' } });
|
|
313
|
+
setState(prev => ({ items: [...prev.items, 4] }));
|
|
245
314
|
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
315
|
+
// Or mutate directly via proxy — only affected subscribers update
|
|
316
|
+
state.user.name = 'Bob'; // only "user.name" subscribers notified
|
|
317
|
+
state.items.push(4); // array mutation batched automatically
|
|
249
318
|
```
|
|
250
319
|
|
|
251
320
|
### Components
|
|
@@ -332,6 +401,40 @@ provide(ThemeCtx, 'dark');
|
|
|
332
401
|
const theme = inject(ThemeCtx); // 'dark'
|
|
333
402
|
```
|
|
334
403
|
|
|
404
|
+
### History (undo/redo)
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
import { createHistory } from '@getforma/core';
|
|
408
|
+
|
|
409
|
+
const [state, setState, { undo, redo, canUndo, canRedo }] = createHistory({ text: '' });
|
|
410
|
+
|
|
411
|
+
setState({ text: 'hello' });
|
|
412
|
+
setState({ text: 'hello world' });
|
|
413
|
+
|
|
414
|
+
undo(); // state.text === 'hello'
|
|
415
|
+
canUndo(); // true
|
|
416
|
+
redo(); // state.text === 'hello world'
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Reducer
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
import { createReducer } from '@getforma/core';
|
|
423
|
+
|
|
424
|
+
const [state, dispatch] = createReducer(
|
|
425
|
+
(state, action) => {
|
|
426
|
+
switch (action.type) {
|
|
427
|
+
case 'INCREMENT': return { count: state.count + 1 };
|
|
428
|
+
case 'DECREMENT': return { count: state.count - 1 };
|
|
429
|
+
default: return state;
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
{ count: 0 },
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
dispatch({ type: 'INCREMENT' }); // state() === { count: 1 }
|
|
436
|
+
```
|
|
437
|
+
|
|
335
438
|
## Islands Architecture
|
|
336
439
|
|
|
337
440
|
For server-rendered HTML, activate independent interactive regions. Each island callback receives the root DOM element and parsed props, then returns a component tree — the same `h()` calls you'd use for client-side rendering. The hydration system walks the descriptor tree against the existing SSR DOM, attaching event handlers and reactive bindings without recreating elements.
|
|
@@ -432,11 +535,14 @@ FormaJS shares Solid's core insight — fine-grained signals updating the real D
|
|
|
432
535
|
| **CSP** | Relies on compiler output | Hand-written expression parser; hardened build has no `new Function()` |
|
|
433
536
|
| **Islands** | Via [solid-start](https://start.solidjs.com/) meta-framework | Built-in `activateIslands()` — no meta-framework needed |
|
|
434
537
|
| **Ecosystem** | Mature (router, meta-framework, devtools) | Minimal — reactive core only, you bring the architecture |
|
|
538
|
+
| **SSR runtime** | Node.js required | Node.js via `renderToString`, or Rust walker (no JS runtime on the server) |
|
|
435
539
|
| **Size** | ~7KB | ~15KB (includes runtime parser, stores, SSR) |
|
|
436
540
|
|
|
437
|
-
**When to choose FormaJS:** You want
|
|
541
|
+
**When to choose FormaJS:** You want islands hydration built into the library, not bolted on through a meta-framework. You need CSP compliance without a build step. You want three entry points (CDN, hyperscript, JSX) sharing one signal graph. Or you're building on a Rust backend and want your frontend reactive layer to integrate natively with the server stack.
|
|
542
|
+
|
|
543
|
+
**When to choose Solid:** You want a mature JavaScript ecosystem with routing, SSR meta-framework (SolidStart), devtools, and community-built component libraries. Your backend is Node.js and you want SSR in the same language as your frontend.
|
|
438
544
|
|
|
439
|
-
|
|
545
|
+
> FormaJS is the reactive layer of the [Forma stack](https://getforma.dev). The full pipeline compiles components to a binary IR (FMIR), renders them in Rust via `forma-ir`, and serves pages through `forma-server` — SSR without Node.js, binary IR over the wire, deployed for ~$18/month.
|
|
440
546
|
|
|
441
547
|
## Stability
|
|
442
548
|
|
|
@@ -444,7 +550,8 @@ Some features are more battle-tested than others:
|
|
|
444
550
|
|
|
445
551
|
| Feature | Status | Notes |
|
|
446
552
|
|---------|--------|-------|
|
|
447
|
-
| Signals (`createSignal`, `createEffect`, `createComputed`, `batch`) | **Stable** | Core primitive, well-tested |
|
|
553
|
+
| Signals (`createSignal`, `createEffect`, `createComputed`, `batch`) | **Stable** | Core primitive, well-tested. Custom `equals` option supported. |
|
|
554
|
+
| Reactive introspection (`isSignal`, `isComputed`, `trigger`, `getBatchDepth`) | **Stable** | alien-signals 3.x type guards |
|
|
448
555
|
| `h()` / JSX rendering | **Stable** | |
|
|
449
556
|
| `mount()`, `createShow`, `createSwitch`, `createList` | **Stable** | |
|
|
450
557
|
| HTML Runtime (`data-*` directives) | **Stable** | Expression parser covers common patterns |
|
|
@@ -452,7 +559,10 @@ Some features are more battle-tested than others:
|
|
|
452
559
|
| `createStore` (deep reactivity) | **Stable** | |
|
|
453
560
|
| Components (`defineComponent`, lifecycle) | **Stable** | |
|
|
454
561
|
| Context (`createContext`, `provide`, `inject`) | **Stable** | |
|
|
455
|
-
| Islands (`activateIslands
|
|
562
|
+
| Islands (`activateIslands`, disposal, triggers) | **Stable** | 10 activation + 88 hydration + 10 trigger tests |
|
|
563
|
+
| `createHistory` (undo/redo) | **Stable** | |
|
|
564
|
+
| `createReducer` | **Stable** | 8 tests |
|
|
565
|
+
| `data-fetch`, `data-transition:*` | **Stable** | Fully implemented in HTML Runtime |
|
|
456
566
|
| SSR (`renderToString`, `renderToStream`) | **Beta** | Functional, API may evolve |
|
|
457
567
|
| TC39 Signals compat (`Signal.State`, `Signal.Computed`) | **Beta** | 9 tests, but tracks an evolving TC39 proposal |
|
|
458
568
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var alienSignals = require('alien-signals');
|
|
4
|
+
|
|
5
|
+
// src/reactive/signal.ts
|
|
6
|
+
function applySignalSet(s, v, equals) {
|
|
7
|
+
if (typeof v !== "function") {
|
|
8
|
+
if (equals) {
|
|
9
|
+
const prevSub2 = alienSignals.setActiveSub(void 0);
|
|
10
|
+
const prev2 = s();
|
|
11
|
+
alienSignals.setActiveSub(prevSub2);
|
|
12
|
+
if (equals(prev2, v)) return;
|
|
13
|
+
}
|
|
14
|
+
s(v);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const prevSub = alienSignals.setActiveSub(void 0);
|
|
18
|
+
const prev = s();
|
|
19
|
+
alienSignals.setActiveSub(prevSub);
|
|
20
|
+
const next = v(prev);
|
|
21
|
+
if (equals && equals(prev, next)) return;
|
|
22
|
+
s(next);
|
|
23
|
+
}
|
|
24
|
+
function createSignal(initialValue, options) {
|
|
25
|
+
const s = alienSignals.signal(initialValue);
|
|
26
|
+
const getter = s;
|
|
27
|
+
const eq = options?.equals;
|
|
28
|
+
const setter = (v) => applySignalSet(s, v, eq);
|
|
29
|
+
return [getter, setter];
|
|
30
|
+
}
|
|
31
|
+
function createComputed(fn) {
|
|
32
|
+
return alienSignals.computed(fn);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.createComputed = createComputed;
|
|
36
|
+
exports.createSignal = createSignal;
|
|
37
|
+
//# sourceMappingURL=chunk-3U57L2TY.cjs.map
|
|
38
|
+
//# sourceMappingURL=chunk-3U57L2TY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reactive/signal.ts","../src/reactive/computed.ts"],"names":["prevSub","setActiveSub","prev","createRawSignal","rawComputed"],"mappings":";;;;;AAkEA,SAAS,cAAA,CACP,CAAA,EACA,CAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,OAAO,MAAM,UAAA,EAAY;AAC3B,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,MAAMA,QAAAA,GAAUC,0BAAa,MAAS,CAAA;AACtC,MAAA,MAAMC,QAAO,CAAA,EAAE;AACf,MAAAD,yBAAA,CAAaD,QAAO,CAAA;AACpB,MAAA,IAAI,MAAA,CAAOE,KAAAA,EAAM,CAAC,CAAA,EAAG;AAAA,IACvB;AACA,IAAA,CAAA,CAAE,CAAC,CAAA;AACH,IAAA;AAAA,EACF;AAGA,EAAA,MAAM,OAAA,GAAUD,0BAAa,MAAS,CAAA;AACtC,EAAA,MAAM,OAAO,CAAA,EAAE;AACf,EAAAA,yBAAA,CAAa,OAAO,CAAA;AACpB,EAAA,MAAM,IAAA,GAAQ,EAAqB,IAAI,CAAA;AACvC,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,IAAA,EAAM,IAAI,CAAA,EAAG;AAClC,EAAA,CAAA,CAAE,IAAI,CAAA;AACR;AAqBO,SAAS,YAAA,CAAgB,cAAiB,OAAA,EAA0E;AACzH,EAAA,MAAM,CAAA,GAAIE,oBAAmB,YAAY,CAAA;AACzC,EAAA,MAAM,MAAA,GAAS,CAAA;AACf,EAAA,MAAM,KAAK,OAAA,EAAS,MAAA;AACpB,EAAA,MAAM,SAA0B,CAAC,CAAA,KAA4B,cAAA,CAAe,CAAA,EAAG,GAAG,EAAE,CAAA;AAEpF,EAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AACxB;AC7EO,SAAS,eAAkB,EAAA,EAAuC;AACvE,EAAA,OAAOC,sBAAY,EAAE,CAAA;AACvB","file":"chunk-3U57L2TY.cjs","sourcesContent":["/**\n * Forma Reactive - Signal\n *\n * Fine-grained reactive primitive backed by alien-signals.\n * API: createSignal returns [getter, setter] tuple following SolidJS conventions.\n *\n * TC39 Signals equivalent: Signal.State\n */\n\nimport { signal as createRawSignal, setActiveSub } from 'alien-signals';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport type SignalGetter<T> = () => T;\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;\n\nexport interface SignalOptions<T> {\n /** Debug name — attached to getter in dev mode for devtools inspection. */\n name?: string;\n /**\n * Custom equality check. When provided, the setter will read the current\n * value and only update the signal if `equals(prev, next)` returns `false`.\n *\n * Default: none (alien-signals uses strict inequality `!==` internally).\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n *\n * setPos({ x: 0, y: 0 }); // skipped — equals returns true\n * setPos({ x: 1, y: 0 }); // applied — equals returns false\n * ```\n */\n equals?: (prev: T, next: T) => boolean;\n}\n\n/**\n * Wrap a value so the setter treats it as a literal value, not a functional updater.\n *\n * When `T` is itself a function type, passing a function to the setter is\n * ambiguous -- it looks like a functional update (`prev => next`). Use\n * `value()` to disambiguate:\n *\n * ```ts\n * const [getFn, setFn] = createSignal<() => void>(() => console.log('a'));\n *\n * // BUG: interpreted as a functional update -- calls the arrow with prev\n * // setFn(() => console.log('b'));\n *\n * // Correct: wraps in a thunk so the setter stores it as-is\n * setFn(value(() => console.log('b')));\n * ```\n */\nexport function value<T>(v: T): () => T {\n return () => v;\n}\n\ntype RawSignal<T> = {\n (): T;\n (value: T): void;\n};\n\nfunction applySignalSet<T>(\n s: RawSignal<T>,\n v: T | ((prev: T) => T),\n equals?: (prev: T, next: T) => boolean,\n): void {\n if (typeof v !== 'function') {\n if (equals) {\n // Read current value without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n if (equals(prev, v)) return; // skip — values are equal\n }\n s(v);\n return;\n }\n\n // Functional update: read prev without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n const next = (v as (prev: T) => T)(prev);\n if (equals && equals(prev, next)) return; // skip — values are equal\n s(next);\n}\n\n/**\n * Create a reactive signal.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * console.log(count()); // 0\n * setCount(1);\n * setCount(prev => prev + 1);\n * ```\n *\n * With custom equality:\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n * ```\n */\nexport function createSignal<T>(initialValue: T, options?: SignalOptions<T>): [get: SignalGetter<T>, set: SignalSetter<T>] {\n const s = createRawSignal<T>(initialValue) as RawSignal<T>;\n const getter = s as unknown as SignalGetter<T>;\n const eq = options?.equals;\n const setter: SignalSetter<T> = (v: T | ((prev: T) => T)) => applySignalSet(s, v, eq);\n\n return [getter, setter];\n}\n","/**\n * Forma Reactive - Computed\n *\n * Lazy, cached derived value that participates in the reactive graph.\n * Backed by alien-signals for automatic dependency tracking\n * and cache invalidation.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { computed as rawComputed } from 'alien-signals';\n\n/**\n * Create a lazy, cached computed value.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), this is a lazy cached derivation — equivalent to\n * SolidJS's createMemo. Both createComputed and createMemo in FormaJS\n * are identical.\n *\n * The getter receives the previous value as an argument, enabling\n * efficient diffing patterns without a separate signal:\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createComputed(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n *\n * With previous value (for diffing):\n *\n * ```ts\n * const changes = createComputed((prev) => {\n * const next = items();\n * if (prev) console.log(`changed from ${prev.length} to ${next.length} items`);\n * return next;\n * });\n * ```\n */\nexport function createComputed<T>(fn: (previousValue?: T) => T): () => T {\n return rawComputed(fn);\n}\n"]}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import { createComputed, createSignal } from './chunk-
|
|
2
|
-
import { effect, startBatch, endBatch,
|
|
1
|
+
import { createComputed, createSignal } from './chunk-OZCHIVAZ.js';
|
|
2
|
+
import { effect, effectScope, startBatch, endBatch, setActiveSub } from 'alien-signals';
|
|
3
|
+
export { getBatchDepth, isComputed, isEffect, isEffectScope, isSignal, trigger } from 'alien-signals';
|
|
3
4
|
|
|
4
|
-
// src/reactive/root.ts
|
|
5
5
|
var currentRoot = null;
|
|
6
6
|
var rootStack = [];
|
|
7
7
|
function createRoot(fn) {
|
|
8
|
-
const scope = { disposers: [] };
|
|
8
|
+
const scope = { disposers: [], scopeDispose: null };
|
|
9
9
|
rootStack.push(currentRoot);
|
|
10
10
|
currentRoot = scope;
|
|
11
11
|
const dispose = () => {
|
|
12
|
+
if (scope.scopeDispose) {
|
|
13
|
+
try {
|
|
14
|
+
scope.scopeDispose();
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
scope.scopeDispose = null;
|
|
18
|
+
}
|
|
12
19
|
for (const d of scope.disposers) {
|
|
13
20
|
try {
|
|
14
21
|
d();
|
|
@@ -17,14 +24,15 @@ function createRoot(fn) {
|
|
|
17
24
|
}
|
|
18
25
|
scope.disposers.length = 0;
|
|
19
26
|
};
|
|
27
|
+
let result;
|
|
20
28
|
try {
|
|
21
|
-
|
|
29
|
+
scope.scopeDispose = effectScope(() => {
|
|
30
|
+
result = fn(dispose);
|
|
31
|
+
});
|
|
22
32
|
} finally {
|
|
23
33
|
currentRoot = rootStack.pop() ?? null;
|
|
24
|
-
if (rootStack.length === 0) {
|
|
25
|
-
rootStack.length = 0;
|
|
26
|
-
}
|
|
27
34
|
}
|
|
35
|
+
return result;
|
|
28
36
|
}
|
|
29
37
|
function registerDisposer(dispose) {
|
|
30
38
|
if (currentRoot) {
|
|
@@ -237,11 +245,11 @@ function batch(fn) {
|
|
|
237
245
|
}
|
|
238
246
|
}
|
|
239
247
|
function untrack(fn) {
|
|
240
|
-
|
|
248
|
+
const prev = setActiveSub(void 0);
|
|
241
249
|
try {
|
|
242
250
|
return fn();
|
|
243
251
|
} finally {
|
|
244
|
-
|
|
252
|
+
setActiveSub(prev);
|
|
245
253
|
}
|
|
246
254
|
}
|
|
247
255
|
|
|
@@ -1815,5 +1823,5 @@ function createList(items, keyFn, renderFn, options) {
|
|
|
1815
1823
|
}
|
|
1816
1824
|
|
|
1817
1825
|
export { Fragment, __DEV__, batch, cleanup, createEffect, createList, createMemo, createReducer, createRef, createResource, createRoot, createShow, fragment, h, hydrateIsland, internalEffect, on, onCleanup, onError, popSuspenseContext, pushSuspenseContext, reconcileList, reportError, untrack };
|
|
1818
|
-
//# sourceMappingURL=chunk-
|
|
1819
|
-
//# sourceMappingURL=chunk-
|
|
1826
|
+
//# sourceMappingURL=chunk-N522P3G6.js.map
|
|
1827
|
+
//# sourceMappingURL=chunk-N522P3G6.js.map
|