@torpor/view 0.4.17 → 1.0.0

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.
Files changed (72) hide show
  1. package/README.md +41 -16
  2. package/dist/Cleanup-D0wvGW5d.d.cts +9 -0
  3. package/dist/Cleanup-D0wvGW5d.d.cts.map +1 -0
  4. package/dist/Cleanup-D0wvGW5d.d.mts +9 -0
  5. package/dist/Cleanup-D0wvGW5d.d.mts.map +1 -0
  6. package/dist/Component-0MH0zd-m.d.cts +11 -0
  7. package/dist/Component-0MH0zd-m.d.cts.map +1 -0
  8. package/dist/Component-0MH0zd-m.d.mts +11 -0
  9. package/dist/Component-0MH0zd-m.d.mts.map +1 -0
  10. package/dist/Effect-BTKurOpr.d.mts +381 -0
  11. package/dist/Effect-BTKurOpr.d.mts.map +1 -0
  12. package/dist/Effect-COl3aRJV.d.cts +381 -0
  13. package/dist/Effect-COl3aRJV.d.cts.map +1 -0
  14. package/dist/compile.cjs +1728 -740
  15. package/dist/compile.d.cts +85 -50
  16. package/dist/compile.d.cts.map +1 -1
  17. package/dist/compile.d.mts +85 -50
  18. package/dist/compile.d.mts.map +1 -1
  19. package/dist/compile.mjs +1731 -742
  20. package/dist/compile.mjs.map +1 -1
  21. package/dist/dev.cjs +62 -63
  22. package/dist/dev.d.cts +4 -3
  23. package/dist/dev.d.cts.map +1 -1
  24. package/dist/dev.d.mts +4 -3
  25. package/dist/dev.d.mts.map +1 -1
  26. package/dist/dev.mjs +61 -62
  27. package/dist/dev.mjs.map +1 -1
  28. package/dist/{devContext-B3yskfhA.cjs → devContext-BulTn3U5.cjs} +6 -9
  29. package/dist/{devContext-CQ8RhBX-.mjs → devContext-ZNsPyOgB.mjs} +3 -4
  30. package/dist/devContext-ZNsPyOgB.mjs.map +1 -0
  31. package/dist/fromWebSocket-1QOjcrHE.cjs +182 -0
  32. package/dist/fromWebSocket-B52kN3-W.d.mts +91 -0
  33. package/dist/fromWebSocket-B52kN3-W.d.mts.map +1 -0
  34. package/dist/fromWebSocket-DeB35Q4w.d.cts +91 -0
  35. package/dist/fromWebSocket-DeB35Q4w.d.cts.map +1 -0
  36. package/dist/fromWebSocket-Dxc_uwm1.mjs +137 -0
  37. package/dist/fromWebSocket-Dxc_uwm1.mjs.map +1 -0
  38. package/dist/index.cjs +2071 -508
  39. package/dist/index.d.cts +600 -112
  40. package/dist/index.d.cts.map +1 -1
  41. package/dist/index.d.mts +600 -112
  42. package/dist/index.d.mts.map +1 -1
  43. package/dist/index.mjs +2052 -505
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/ssr.cjs +78 -17
  46. package/dist/ssr.d.cts +64 -11
  47. package/dist/ssr.d.cts.map +1 -1
  48. package/dist/ssr.d.mts +64 -11
  49. package/dist/ssr.d.mts.map +1 -1
  50. package/dist/ssr.mjs +67 -14
  51. package/dist/ssr.mjs.map +1 -1
  52. package/package.json +21 -19
  53. package/dist/Cleanup-CYsytTEc.d.cts +0 -9
  54. package/dist/Cleanup-CYsytTEc.d.cts.map +0 -1
  55. package/dist/Cleanup-CgjyN0lW.d.mts +0 -9
  56. package/dist/Cleanup-CgjyN0lW.d.mts.map +0 -1
  57. package/dist/Component-DmWGMgak.d.mts +0 -11
  58. package/dist/Component-DmWGMgak.d.mts.map +0 -1
  59. package/dist/Component-kGLRFYg2.d.cts +0 -11
  60. package/dist/Component-kGLRFYg2.d.cts.map +0 -1
  61. package/dist/Region-Bb6HAb-F.d.cts +0 -201
  62. package/dist/Region-Bb6HAb-F.d.cts.map +0 -1
  63. package/dist/Region-CTchywkr.d.mts +0 -201
  64. package/dist/Region-CTchywkr.d.mts.map +0 -1
  65. package/dist/devContext-CQ8RhBX-.mjs.map +0 -1
  66. package/dist/formatText--9zsK5Nq.cjs +0 -59
  67. package/dist/formatText-B8u71S_K.mjs +0 -42
  68. package/dist/formatText-B8u71S_K.mjs.map +0 -1
  69. package/dist/formatText-BNP3P38F.d.cts +0 -17
  70. package/dist/formatText-BNP3P38F.d.cts.map +0 -1
  71. package/dist/formatText-D6Ov8Ub0.d.mts +0 -17
  72. package/dist/formatText-D6Ov8Ub0.d.mts.map +0 -1
package/dist/index.d.mts CHANGED
@@ -1,8 +1,7 @@
1
- import { n as SlotRender, t as Component } from "./Component-DmWGMgak.mjs";
2
- import { t as Cleanup } from "./Cleanup-CgjyN0lW.mjs";
3
- import { n as Effect, t as Region } from "./Region-CTchywkr.mjs";
4
- import { a as ClassValue, i as buildClasses, n as buildStyles, r as StyleValue, t as formatText } from "./formatText-D6Ov8Ub0.mjs";
5
-
1
+ import { n as SlotRender, t as Component } from "./Component-0MH0zd-m.mjs";
2
+ import { t as Cleanup } from "./Cleanup-D0wvGW5d.mjs";
3
+ import { n as Region, t as Effect } from "./Effect-BTKurOpr.mjs";
4
+ import { a as buildStyles, c as ClassValue, i as StreamSource, n as fromServer, o as StyleValue, r as fromElement, s as buildClasses, t as fromWebSocket } from "./fromWebSocket-B52kN3-W.mjs";
6
5
  //#region src/types/Animation.d.ts
7
6
  interface Animation {
8
7
  keyframes: Keyframe[] | PropertyIndexedKeyframes;
@@ -15,46 +14,154 @@ declare function addAnimation(el: HTMLElement, entry?: Animation, exit?: Animati
15
14
  //#region src/render/addEvent.d.ts
16
15
  declare function addEvent(el: Element, type: string, listener: ((this: Element, ev: any) => any) | undefined | null): void;
17
16
  //#endregion
17
+ //#region src/render/addElement.d.ts
18
+ /**
19
+ * Companion to `addFragment` for the single-root-element codegen path. Wires
20
+ * a cloned root element (produced by `getElementFragment`) into the live DOM
21
+ * tree, sets the active region's start/end nodes, and runs the same
22
+ * mount-time side effects as `addFragment` (`$onmount` effects, stashed event
23
+ * listeners, stashed animations).
24
+ *
25
+ * Differences from `addFragment`:
26
+ * - `node` is both the start and end of the region (no
27
+ * `fragment.firstChild`/`fragment.lastChild` indirection).
28
+ * - When hydrating, the existing DOM node is reused (the cloned `node` is
29
+ * discarded); `endNode` is still `node` because `nodeRootElement` returns
30
+ * the hydration cursor's node in that case, not the cloned one.
31
+ *
32
+ * @param node The root element (cloned by `getElementFragment`, or the
33
+ * hydration cursor's node when hydrating).
34
+ * @param parent The intended parent element.
35
+ * @param before The sibling to insert before (or `null` to append).
36
+ */
37
+ declare function addElement(node: Element, parent: ParentNode, before: Node | null): void;
38
+ //#endregion
18
39
  //#region src/render/addFragment.d.ts
19
- declare function addFragment(fragment: DocumentFragment, parent: ParentNode, before: Node | null, endNode?: ChildNode): void;
40
+ declare function addFragment(fragment: DocumentFragment, parent: ParentNode, before: Node | null, endNode?: ChildNode, startNode?: ChildNode): void;
20
41
  //#endregion
21
42
  //#region src/render/applyProps.d.ts
22
43
  declare function applyProps(el: Element, props: Record<string, any> | undefined, propNamesUsed: string[]): void;
23
44
  //#endregion
24
45
  //#region src/render/clearLayoutSlot.d.ts
46
+ /**
47
+ * Clears a region that was created by `fillLayoutSlot`: tears down the
48
+ * rendered content and its effects, leaving the surrounding layout intact
49
+ * so the slot can be refilled.
50
+ *
51
+ * @param region The region to clear
52
+ */
25
53
  declare function clearLayoutSlot(region: Region): void;
26
54
  //#endregion
27
55
  //#region src/render/fillLayoutSlot.d.ts
28
- declare function fillLayoutSlot(component: Component, slot: SlotRender, parent: ParentNode, anchor: Node | null, $props?: Record<string, string>, $context?: Record<PropertyKey, any>): Region;
56
+ /**
57
+ * Renders a component into a persistent layout slot, and returns the region
58
+ * it was rendered into. Used by the layout engine during navigation: the
59
+ * component is created inside `parent` at `anchor`, with `slot` as its child
60
+ * slot render, and the returned region can later be passed to
61
+ * `clearLayoutSlot` to tear the page down — leaving the layout itself
62
+ * intact — before refilling the slot.
63
+ *
64
+ * @param component The component to render into the slot
65
+ * @param slot The slot render to pass to the component
66
+ * @param parent The parent node to render into
67
+ * @param anchor The node to insert content before, or null to append
68
+ * @param $props Optional props to pass to the component
69
+ * @param $context Optional context to pass to the component
70
+ */
71
+ declare function fillLayoutSlot(component: Component, slot: SlotRender, parent: ParentNode, anchor: Node | null, $props?: Record<PropertyKey, any>, $context?: Record<PropertyKey, any>): Region;
72
+ //#endregion
73
+ //#region src/render/formatText.d.ts
74
+ declare function formatText(value: any): string;
29
75
  //#endregion
30
76
  //#region src/render/getFragment.d.ts
31
77
  declare function getFragment(document: Document, array: DocumentFragment[], index: number, html: string, ns?: boolean): DocumentFragment;
32
78
  //#endregion
79
+ //#region src/render/getElementFragment.d.ts
80
+ /**
81
+ * Returns a clone of the cached template's single root element, bypassing the
82
+ * `DocumentFragment` wrapper that `getFragment` produces.
83
+ *
84
+ * Used by the compiler-emitted `createListItem` for `@for` bodies (and other
85
+ * fragments) whose template has exactly one rendering root child — e.g.
86
+ * `<tr><td>...</td>...</tr>`. Cloning `template.content.firstElementChild`
87
+ * directly saves the per-row `DocumentFragment` allocation that `getFragment`'s
88
+ * `cloneNode(true)` on the cached template's content would otherwise produce,
89
+ * which dominates the cost of bulk-row creates (`run`/`add`/`runlots`).
90
+ *
91
+ * Contract: the compiler only emits `t_fragment_el` for fragment indices whose
92
+ * template has exactly one rendering root, and that root is an `Element`. The
93
+ * cache array (`t_fragment_els`) is separate from `t_fragments` so each helper
94
+ * only ever sees its own cached type at a given index.
95
+ *
96
+ * @param document The owner document (used to build the cached `<template>`).
97
+ * @param array The per-component `t_fragment_els` cache.
98
+ * @param index The fragment's index in the cache.
99
+ * @param html The fragment's HTML source, with `#` placeholders for reactive
100
+ * text and `<!>` for anchor comments.
101
+ * @param ns When true, the template is created in the SVG namespace (its
102
+ * `firstElementChild` is then an SVG element).
103
+ */
104
+ declare function getElementFragment(document: Document, array: Element[], index: number, html: string, ns?: boolean): Element;
105
+ //#endregion
33
106
  //#region src/render/hydrate.d.ts
34
107
  /**
35
- * Hydrates a component into an existing DOM tree
36
- * @param parent The parent node
37
- * @param component The component to mount
38
- * @param props An object containing component props
39
- */
108
+ * Hydrates a component into an existing DOM tree
109
+ * @param parent The parent node
110
+ * @param component The component to mount
111
+ * @param props An object containing component props
112
+ */
40
113
  declare function hydrate(parent: ParentNode, component: Component, props?: Record<string, any>, slots?: Record<string, SlotRender>): void;
41
114
  //#endregion
42
115
  //#region src/render/mount.d.ts
43
116
  /**
44
- * Mounts a component into a DOM node
45
- *
46
- * @param parent The node to mount the component into
47
- * @param component The component to mount
48
- * @param props An object containing component props
49
- */
117
+ * Mounts a component into a DOM node
118
+ *
119
+ * @param parent The node to mount the component into
120
+ * @param component The component to mount
121
+ * @param props An object containing component props
122
+ */
50
123
  declare function mount(parent: ParentNode, component: Component, props?: Record<string, any>, slots?: Record<string, SlotRender>): void;
51
124
  //#endregion
52
- //#region src/types/ListItem.d.ts
53
- interface ListItem extends Region {
54
- data: Record<string, any>;
125
+ //#region src/render/unmount.d.ts
126
+ /**
127
+ * Tears down the current UI: disposes the root region tree (running effect
128
+ * cleanups and detaching subscriptions), resets the render context, and
129
+ * removes any remaining child nodes from `parent`.
130
+ *
131
+ * Call this before `mount`ing a fresh component tree into the same container
132
+ * (e.g. when client-side navigating to a route whose layout chain differs
133
+ * from the previous one). `mount` refuses to mount into a non-empty parent
134
+ * and reuses an existing root region, so both must be cleared first.
135
+ *
136
+ * @param parent The container that the previous UI was mounted into
137
+ */
138
+ declare function unmount(parent: ParentNode): void;
139
+ //#endregion
140
+ //#region src/types/ListItemSpec.d.ts
141
+ /**
142
+ * A lightweight, per-row descriptor emitted by the compiler's `@for`
143
+ * `buildItems` callback: just the key (for reconciliation) and the data bag
144
+ * (the loop variables). Unlike a full {@link ListItem}, a spec carries no DOM
145
+ * nodes, no effects, and no sibling-chain pointers — so allocating one per row
146
+ * on every list update is cheap.
147
+ *
148
+ * The keyed-list reconciler (`runListItems`) maps each spec to either an
149
+ * existing `ListItem` (matched by key, reused wholesale) or a freshly mounted
150
+ * one (for genuinely new keys), keeping the per-update cost proportional to
151
+ * what actually changed instead of to the list size.
152
+ *
153
+ * NOTE: `data` is `any` rather than `Record<string, any>` -- when a `@for`
154
+ * body binds a single loop variable and is proxy-safe, the variable is stored
155
+ * directly (e.g. `data: page` for a number), not as a bag.
156
+ */
157
+ interface ListItemSpec {
55
158
  key: any;
159
+ data: any;
56
160
  }
57
161
  //#endregion
162
+ //#region src/types/ListItem.d.ts
163
+ interface ListItem extends Region, ListItemSpec {}
164
+ //#endregion
58
165
  //#region src/render/newListItem.d.ts
59
166
  declare function newListItem(data: Record<PropertyKey, any>, key?: any, name?: string): ListItem;
60
167
  //#endregion
@@ -63,62 +170,91 @@ declare function newRegion(name?: string): Region;
63
170
  //#endregion
64
171
  //#region src/render/nodeAnchor.d.ts
65
172
  /**
66
- * Gets the anchor node for a control statement or component.
67
- *
68
- * When mounting, this just returns the anchor node parameter (because it was
69
- * created).
70
- *
71
- * When hydrating, there should be matched <![> and <!]> comments in the HTML,
72
- * and the anchor node should be after the end comment. The matched comment
73
- * nodes will be deleted, and the hydration node set to the first node inside
74
- * the matched comments.
75
- *
76
- * @param node The potential anchor node.
77
- * @returns The anchor node.
78
- */
173
+ * Gets the anchor node for a control statement or component.
174
+ *
175
+ * When mounting, this just returns the anchor node parameter (because it was
176
+ * created).
177
+ *
178
+ * When hydrating, there should be matched <![> and <!]> comments in the HTML,
179
+ * and the anchor node should be after the end comment. The matched comment
180
+ * nodes will be deleted, and the hydration node set to the first node inside
181
+ * the matched comments.
182
+ *
183
+ * @param node The potential anchor node.
184
+ * @returns The anchor node.
185
+ */
79
186
  declare function nodeAnchor(node: ChildNode): ChildNode;
80
187
  //#endregion
81
188
  //#region src/render/nodeChild.d.ts
82
189
  /**
83
- * Gets the first child of a node.
84
- *
85
- * Sets the hydration node.
86
- *
87
- * @param parent The parent node.
88
- */
190
+ * Gets the first child of a node.
191
+ *
192
+ * Sets the hydration node.
193
+ *
194
+ * @param parent The parent node.
195
+ */
89
196
  declare function nodeChild(parent: Node): ChildNode;
90
197
  //#endregion
91
198
  //#region src/render/nodeNext.d.ts
92
199
  /**
93
- * Gets the next sibling of a node.
94
- *
95
- * When hydrating, sets the hydration node.
96
- *
97
- * @param node The node.
98
- * @param text Whether we require a text node.
99
- */
200
+ * Gets the next sibling of a node.
201
+ *
202
+ * When hydrating, sets the hydration node.
203
+ *
204
+ * @param node The node.
205
+ * @param text Whether we require a text node.
206
+ */
100
207
  declare function nodeNext(node: ChildNode, text?: boolean): ChildNode;
101
208
  //#endregion
209
+ //#region src/render/nodeRootElement.d.ts
210
+ /**
211
+ * Gets the root element of a single-root fragment built via `getElementFragment`.
212
+ *
213
+ * Companion to `nodeRoot`, for the codegen path where the compiler has emitted
214
+ * `t_fragment_el` (cloning the cached template's `firstElementChild` directly)
215
+ * instead of `t_fragment` (cloning into a `DocumentFragment`). In the
216
+ * non-hydrating case the cloned element is already the root, so this is a
217
+ * no-op pass-through. In the hydrating case we perform the same cursor walk as
218
+ * `nodeRoot`'s non-text branch so the region's `startNode` lands on the
219
+ * existing DOM node and the hydration cursor advances past any leading
220
+ * whitespace, branch-break markers, and auto-inserted `<tbody>` wrappers.
221
+ *
222
+ * @param node The cloned root element (ignored when hydrating).
223
+ */
224
+ declare function nodeRootElement(node: Element): ChildNode;
225
+ //#endregion
102
226
  //#region src/render/nodeRoot.d.ts
103
227
  /**
104
- * Gets the first child in a fragment.
105
- *
106
- * When hydrating, also sets the active range's start node, while we have it.
107
- *
108
- * @param parent The parent of the fragment.
109
- * @param text Whether we require a text node.
110
- */
228
+ * Gets the first child in a fragment.
229
+ *
230
+ * When hydrating, also sets the active region's start node, while we have it.
231
+ *
232
+ * If the hydration cursor is on a control-start marker (`<![>`), the node is
233
+ * left in place for `nodeAnchor` (called next as `t_anchor(t_root(...))`) to
234
+ * walk — it consumes the matched `<![>...<!]>` pair, removes the markers and
235
+ * sets the region's start node to the first node inside the block.
236
+ *
237
+ * For non-text fragments, leading branch-break markers (`<!^>`), empty anchor
238
+ * comments left by preceding siblings, and residual whitespace-only text nodes
239
+ * are skipped (break markers removed) so the region's start node lands on real
240
+ * content. This replaces the per-sibling `t_next` calls that the codegen used
241
+ * to emit when leading whitespace separated siblings; with whitespace trimmed
242
+ * those calls are gone, so the advancement happens here.
243
+ *
244
+ * @param parent The parent of the fragment.
245
+ * @param text Whether we require a text node.
246
+ */
111
247
  declare function nodeRoot(parent: Node, text?: boolean): ChildNode;
112
248
  //#endregion
113
249
  //#region src/render/nodeSkip.d.ts
114
250
  /**
115
- * Gets the sibling of a node, x nodes after it.
116
- *
117
- * When hydrating, sets the hydration node.
118
- *
119
- * @param node The node.
120
- * @param count The number of nodes to skip.
121
- */
251
+ * Gets the sibling of a node, x nodes after it.
252
+ *
253
+ * When hydrating, sets the hydration node.
254
+ *
255
+ * @param node The node.
256
+ * @param count The number of nodes to skip.
257
+ */
122
258
  declare function nodeSkip(node: ChildNode, count: number): ChildNode;
123
259
  //#endregion
124
260
  //#region src/render/popRegion.d.ts
@@ -127,11 +263,54 @@ declare function popRegion(oldRegion: Region): void;
127
263
  //#region src/render/pushRegion.d.ts
128
264
  declare function pushRegion(region: Region, toParent?: boolean): Region;
129
265
  //#endregion
266
+ //#region src/render/rerunRegionEffects.d.ts
267
+ /**
268
+ * Force re-runs every effect owned by `region` and its descendant regions
269
+ * that depends on at least one of the for-vars set in `changedMask`.
270
+ *
271
+ * Used by keyed-list `updateListItem` callbacks emitted by the compiler when
272
+ * the `@for` body has been classified "no-proxy safe" — i.e. the per-item
273
+ * data bag is *not* wrapped in a shallow `$watch` Proxy. Without that Proxy,
274
+ * a write such as `t_old_item.data.row = newRow` doesn't propagate through a
275
+ * signal, so any effects that read `data.row` must be re-run manually.
276
+ *
277
+ * `changedMask` is a bitmask of the for-var positions whose references
278
+ * actually changed in this update. Each effect carries `forVarMask`
279
+ * (computed at compile time) listing the for-vars its body reads; effects
280
+ * whose `forVarMask & changedMask === 0` are skipped. Mount callbacks
281
+ * (`isMountEffect` — `$onmount`/`onmount`) are always skipped: they run
282
+ * once per DOM mount and their bodies are untracked.
283
+ *
284
+ * Equivalent to what `checkEffect` does when a signal has propagated, but
285
+ * unconditional for the effects that do match: cleanup → deactivate sources
286
+ * → run → clear unused sources, for every matching effect on the region and
287
+ * on every descendant region (`depth > region.depth`, the same chain shape
288
+ * `clearRegion` walks).
289
+ */
290
+ declare function rerunRegionEffects(region: Region, changedMask: number): void;
291
+ //#endregion
292
+ //#region src/render/restoreHydration.d.ts
293
+ /**
294
+ * Restores the hydration cursor to a previously-snapshotted node. Used by
295
+ * `@try`/`@catch`: if the try branch throws partway through its hydration
296
+ * walk, the catch branch must resume hydrating from where the try group
297
+ * started, not from wherever the failed branch left the cursor.
298
+ *
299
+ * The cursor is set unconditionally: a failed try-branch build can walk the
300
+ * cursor past the last node (setting it to `null` via `nodeNext`), and the
301
+ * rewind must still restore it — otherwise the catch branch would think it
302
+ * isn't hydrating and insert fresh nodes alongside the server's. When not
303
+ * hydrating at all, the snapshot itself is `null`, so this is a no-op.
304
+ *
305
+ * @param node The snapshotted cursor node (from `saveHydration`).
306
+ */
307
+ declare function restoreHydration(node: ChildNode | null): void;
308
+ //#endregion
130
309
  //#region src/render/runControl.d.ts
131
310
  /**
132
- * Runs an `if`, `switch` or `await` control statement
133
- * @param create A function that creates the control statement's branches
134
- */
311
+ * Runs an `if`, `switch` or `await` control statement
312
+ * @param create A function that creates the control statement's branches
313
+ */
135
314
  declare function runControl(region: Region, anchor: Node | null, create: (anchor: Node | null) => void, name?: string): void;
136
315
  //#endregion
137
316
  //#region src/render/runControlBranch.d.ts
@@ -139,10 +318,103 @@ declare function runControlBranch(region: Region, oldIndex: number, index: numbe
139
318
  //#endregion
140
319
  //#region src/render/runList.d.ts
141
320
  /**
142
- * Runs a `for` control statement
143
- * @param create A function that creates the control statement's branches
144
- */
145
- declare function runList(region: Region, parent: ParentNode, anchor: Node | null, buildItems: () => ListItem[], create: (item: ListItem, anchor: Node | null) => void, update: (oldItem: ListItem, newItem: ListItem) => void): void;
321
+ * Runs a `for` control statement
322
+ * @param buildItems A function that returns the current list of lightweight
323
+ * `{key, data}` specs (one per row of the source data)
324
+ * @param create A function that creates the control statement's branches
325
+ * @param noWatch When true, the compiler has determined the `@for` body never
326
+ * writes to its loop variables, so each item's `data` bag can be left
327
+ * unwrapped (skipping the per-item shallow `$watch` Proxy + ProxyData +
328
+ * signals Map allocations). The compiler-emitted `update` callback is then
329
+ * responsible for re-running item effects when a loop variable's reference
330
+ * actually changes (via `t_rerun_region_effects`).
331
+ */
332
+ declare function runList(region: Region, parent: ParentNode, anchor: Node | null, buildItems: () => ListItemSpec[], create: (item: ListItem, anchor: Node | null) => void, update: (oldItem: ListItem, newSpec: ListItemSpec) => void, noWatch?: boolean): void;
333
+ //#endregion
334
+ //#region src/render/runAwait.d.ts
335
+ /**
336
+ * Renders an `@await` boundary. On the first run, content is rendered
337
+ * speculatively; if any read inside suspends (`didSuspend`), the boundary
338
+ * discards the partial render and shows the `with` branch instead.
339
+ *
340
+ * Fine-grained updates: on subsequent runs the boundary only decides whether
341
+ * to SWITCH branches. It does so from its `pending` set — the suspended
342
+ * computeds recorded by `suspendRead` — dropping entries that resolved and
343
+ * re-subscribing the still-suspended ones (a re-run deactivates all of the
344
+ * effect's source subscriptions, so they must be re-tracked to survive
345
+ * `clearSources`). That check is O(pending reads), not O(all sources), and
346
+ * non-suspend dependency changes inside content are left to the child
347
+ * effects that read them — the boundary isn't re-run by them at all.
348
+ *
349
+ * Stale-while-revalidate (ASYNC.md §6.2): once content has been produced
350
+ * (`hasContent`), a subsequent suspend during a refresh does NOT switch to
351
+ * the `with` branch — the boundary keeps the stale content mounted. `$async`
352
+ * retains the previous resolved value (`Computed.staleValue`) and
353
+ * `suspendRead` returns it, so child effects keep displaying the old value
354
+ * until the new promise resolves and updates them in place. The `with` branch
355
+ * is shown only on the first load, before content has ever rendered
356
+ * successfully.
357
+ *
358
+ * @param renderContent Builds the content children (may read $async getters).
359
+ * @param renderWith Builds the `with`-branch children, or null for empty.
360
+ */
361
+ declare function runAwait(region: Region, anchor: Node | null, renderContent: (anchor: Node | null) => void, renderWith: ((anchor: Node | null) => void) | null, name?: string): void;
362
+ //#endregion
363
+ //#region src/render/runTry.d.ts
364
+ /**
365
+ * Renders a `@try`/`@catch` group, or a top-level `@error` block (which the
366
+ * compiler wraps around the whole render).
367
+ *
368
+ * Like `runAwait`, the boundary is a control effect that renders one branch
369
+ * at a time into a fresh child region (`runControlBranch` clears the old
370
+ * branch on switch). Unlike the old compiled form, the try/catch lives in
371
+ * this runtime, which gives it three capabilities the compiled form lacked:
372
+ *
373
+ * - **Effect-rerun error routing.** The boundary registers itself on its
374
+ * region (`region.errorBoundary`); when an effect inside the try content
375
+ * throws on a later re-run, `triggerEffects` → `routeEffectError` stores
376
+ * the error here and force re-runs the boundary effect, which renders the
377
+ * catch branch with it.
378
+ * - **Recovery outside direct reads.** Reactive reads wrapped in nested
379
+ * `$run` effects (text/attribute interpolation) are tracked by those
380
+ * effects, not the boundary. When an error is routed, the boundary holds
381
+ * the erroring effect's source signals (`heldSignals`) and re-subscribes
382
+ * to them on every run that shows the catch branch, so a later change
383
+ * re-attempts the try branch.
384
+ * - **Top-level `@error` recovery.** Because the whole render is a
385
+ * re-runnable branch, a later re-render error (from a nested control
386
+ * re-running after a prop change) is caught by the same routing, and a
387
+ * recovery re-render clears the error content and restores the normal
388
+ * content.
389
+ *
390
+ * Semantics preserved from the compiled form:
391
+ *
392
+ * - Synchronous build errors in the try content render the catch branch
393
+ * (rewinding the hydration cursor and restoring the control region, which
394
+ * the failed partial build left active).
395
+ * - While the try branch is showing, a boundary re-run with no routed error
396
+ * does NOT rebuild it (`runControlBranch` same-index skip) — exactly like
397
+ * `@if`/`@switch` branches.
398
+ * - While the catch branch is showing, any boundary re-run re-attempts the
399
+ * try branch (the recovery path for errors read directly by the boundary
400
+ * effect, e.g. via `@const`).
401
+ * - With no catch branch, errors propagate up to the nearest outer boundary
402
+ * and no boundary is registered on the region.
403
+ *
404
+ * @param renderTry Builds the try content. May read reactive state.
405
+ * @param renderCatch Builds the catch content, or null for `@try` without
406
+ * `@catch`. Receives the error (the `@catch (err)` variable).
407
+ */
408
+ declare function runTry(region: Region, anchor: Node | null, renderTry: (anchor: Node | null) => void, renderCatch: ((anchor: Node | null, error: any) => void) | null, name?: string): void;
409
+ //#endregion
410
+ //#region src/render/saveHydration.d.ts
411
+ /**
412
+ * Snapshots the hydration cursor so a `@try` branch's partial hydration walk
413
+ * can be rewound if the branch throws and the `@catch` branch renders instead.
414
+ *
415
+ * @returns The current hydration cursor node, or `null` when not hydrating.
416
+ */
417
+ declare function saveHydration(): ChildNode | null;
146
418
  //#endregion
147
419
  //#region src/render/setAttribute.d.ts
148
420
  declare function setAttribute(el: Element, name: string, value: any): void;
@@ -150,77 +422,293 @@ declare function setAttribute(el: Element, name: string, value: any): void;
150
422
  //#region src/render/setDynamicElement.d.ts
151
423
  declare function setDynamicElement(el: HTMLElement, tag: string): HTMLElement;
152
424
  //#endregion
425
+ //#region src/types/Bindable.d.ts
426
+ /**
427
+ * Type-level marker that documents a component prop as supporting two-way
428
+ * binding via the `&` prefix at the call site.
429
+ *
430
+ * `Bindable<T>` is structurally just `T` — it has no runtime effect. It tells
431
+ * component authors and consumers "this prop is intended to be bound with
432
+ * `&prop={expr}`." Inside the component, use `$bind($state, $props, [...])`
433
+ * to wire up the actual two-way sync.
434
+ *
435
+ * Example:
436
+ * ```ts
437
+ * interface MyProps {
438
+ * value: Bindable<string>;
439
+ * }
440
+ * ```
441
+ */
442
+ type Bindable<T> = T;
443
+ //#endregion
153
444
  //#region src/watch/$batch.d.ts
154
445
  /**
155
- * Runs updates to proxy values in a batch, where the updates are stored in
156
- * context, and dependent effects are run all at once at the end.
157
- *
158
- * @param fn The function containing the batched updates to run.
159
- */
446
+ * Runs updates to proxy values in a batch, where the updates are stored in
447
+ * context, and dependent effects are run all at once at the end.
448
+ *
449
+ * @param fn The function containing the batched updates to run.
450
+ */
160
451
  declare function $batch<T>(fn: () => T): T;
161
452
  //#endregion
453
+ //#region src/watch/$async.d.ts
454
+ /**
455
+ * Caches an async computed value from a thunk that returns a Promise. A peer
456
+ * of `$cache` for async getters: the returned Computed carries a `didSuspend`
457
+ * indicator that the proxy get trap reads to suspend callers until the promise
458
+ * resolves.
459
+ *
460
+ * The thenable check and `.then` wiring live inside `computed.run` (a closure
461
+ * over the computed object), so they fire on both the initial run and every
462
+ * recalculation — `runComputed` and `checkComputed` are unchanged.
463
+ *
464
+ * @param fn A thunk returning the Promise to await. Signal reads inside `fn`
465
+ * are tracked, so the fetch re-runs when dependencies change.
466
+ */
467
+ declare function $async<T>(fn: () => Promise<T>): T;
468
+ //#endregion
469
+ //#region src/watch/$bind.d.ts
470
+ /**
471
+ * Establishes two-way reactive sync between matching keys on a state object
472
+ * and a props object.
473
+ *
474
+ * For each key, `$bind` creates:
475
+ * - **Forward sync** (`props → state`): when the parent pushes a new value via
476
+ * `$props[key]`, it flows into `$state[key]`. Skips `undefined` values so
477
+ * that defaults set in the initial `$watch(...)` are preserved when the
478
+ * parent doesn't provide a value.
479
+ * - **Backward sync** (`state → props`): when the component mutates
480
+ * `$state[key]`, the new value is written back to `$props[key]`, which the
481
+ * call site's `&key={...}` binding picks up and propagates to the parent.
482
+ *
483
+ * Same-value writes are no-ops (handled by the proxy layer), so two-way sync
484
+ * stabilises without infinite loops.
485
+ *
486
+ * `$bind` syncs same-named keys, so the key must exist on the state object.
487
+ * A state key named differently from the prop (e.g. `values` against a
488
+ * `value` prop) would silently do nothing -- the binding reads and writes
489
+ * keys that nothing else touches -- which is almost impossible to debug. The
490
+ * key is therefore required to exist on the state object, and `$bind` throws
491
+ * at setup otherwise.
492
+ *
493
+ * The prop does *not* need to exist on `props` yet: when the parent doesn't
494
+ * pass an optional prop, the compiled props object has no key for it, and
495
+ * the binding is simply inert (uncontrolled mode) until a value is pushed.
496
+ *
497
+ * @param state The component's reactive state (created via `$watch`).
498
+ * @param props The component's `$props` proxy. When `undefined` (component
499
+ * called with no props), `$bind` does nothing.
500
+ * @param keys Keys to sync. Each key must exist on `state`.
501
+ * @throws When a key does not exist on the state object.
502
+ */
503
+ declare function $bind(state: Record<PropertyKey, any>, props: Record<PropertyKey, any> | undefined, ...keys: (string | string[])[]): void;
504
+ //#endregion
162
505
  //#region src/watch/$cache.d.ts
163
506
  /**
164
- * Caches a computed value from signals accessed in a property getter.
165
- *
166
- * @param fn The function containing the signals to compute and cache.
167
- */
507
+ * Caches a computed value from signals accessed in a property getter.
508
+ *
509
+ * @param fn The function containing the signals to compute and cache.
510
+ */
168
511
  declare function $cache<T>(fn: () => T): T;
169
512
  //#endregion
170
- //#region src/watch/$mount.d.ts
513
+ //#region src/watch/$onmount.d.ts
171
514
  /**
172
- * Runs and re-runs a function on component mount
173
- *
174
- * @param fn The function to run, which may return a cleanup function
175
- */
176
- declare function $mount(fn: () => Cleanup | void): void;
515
+ * Runs `fn` once after the component is mounted to the DOM. May return a
516
+ * cleanup function that runs on unmount / region clear.
517
+ *
518
+ * The callback is **not reactive**: it runs exactly once per mount, and
519
+ * reactive values it reads are not tracked. To set up something that should
520
+ * keep updating, wrap the reactive part in `$run`:
521
+ *
522
+ * ```ts
523
+ * $onmount(() => {
524
+ * $run(() => {
525
+ * label.textContent = $state.count > 0 ? "+" : "";
526
+ * });
527
+ * });
528
+ * ```
529
+ *
530
+ * The element-level equivalent is the `onmount` attribute:
531
+ * `<input onmount={(el) => el.focus()} />`.
532
+ *
533
+ * @param fn The function to run, which may return a cleanup function
534
+ */
535
+ declare function $onmount(fn: () => Cleanup | void): void;
177
536
  //#endregion
178
537
  //#region src/watch/$peek.d.ts
538
+ /**
539
+ * Runs a function without tracking the reactive values it reads: `$watch`'d
540
+ * state accessed inside `fn` does not become a dependency of the currently
541
+ * running effect or computed. Useful for reading state inside an effect
542
+ * without re-running it when that state changes.
543
+ *
544
+ * @param fn The function to run untracked.
545
+ */
179
546
  declare function $peek<T>(fn: () => T): T;
180
547
  //#endregion
548
+ //#region src/watch/$pending.d.ts
549
+ /**
550
+ * Returns `true` if any value read inside `fn` is currently suspended in a
551
+ * "loud" way — a `$async` getter whose promise hasn't resolved yet. A reactive
552
+ * query for inline "loading…" indicators: the calling effect subscribes to the
553
+ * same computeds, so `$pending` re-evaluates when they resolve.
554
+ *
555
+ * Uses a "peek mode" internally: reads during `fn` are tracked for
556
+ * subscription but don't propagate taint or notify a `@await` boundary.
557
+ * This lets `$pending` return a plain boolean without itself suspending.
558
+ *
559
+ * Quiet-on-refresh semantics (ASYNC.md §7.4): a suspend is *quiet* — and
560
+ * therefore `$pending` returns `false` for it — when the computed has resolved
561
+ * before and the re-fetch was a *silent* `$refresh(fn, { silent: true })` (a
562
+ * bare refresh with no tracked dependency change, used for background
563
+ * revalidation). This matches Solid's stale-while-revalidate default: quietly
564
+ * re-asking the same question shouldn't ping the user. First loads and
565
+ * dependency-change refreshes are loud (`true`), as is the default (loud)
566
+ * `$refresh(fn)`. Quiet-ness is captured per computed at suspend time via
567
+ * `suspendQuiet` (computed in `$async`'s run from `hasResolved` and `recalc`).
568
+ *
569
+ * @param fn A function that reads the reactive values to check.
570
+ */
571
+ declare function $pending(fn: () => any): boolean;
572
+ //#endregion
573
+ //#region src/watch/$refresh.d.ts
574
+ /**
575
+ * Options for `$refresh`.
576
+ */
577
+ interface RefreshOptions {
578
+ /**
579
+ * Re-fetch silently — stale-while-revalidate. The suspend is *quiet*
580
+ * (`$pending` stays `false`) and subscribers aren't notified until the new
581
+ * promise resolves. For background revalidation: polling, refetch-on-
582
+ * focus. Defaults to `false` — a refresh is loud, so `$pending` reads
583
+ * `true` and inline "updating…" indicators flip on at refresh start.
584
+ */
585
+ silent?: boolean;
586
+ }
587
+ /**
588
+ * Re-fetches the `$async` getters read inside `fn` without changing a
589
+ * dependency. A companion to `$pending` (ASYNC.md §6.2): pull-to-refresh,
590
+ * refresh buttons, refetch-on-focus, polling, retry-after-error.
591
+ *
592
+ * `fn` is run in a tracking context that collects every `$async` computed it
593
+ * reads (`$cache` computeds are ignored). Each collected computed is then
594
+ * re-run with `recalc` left true — a "bare refresh" — so the suspend is
595
+ * *loud*: `$pending(fn)` returns `true` while the re-fetch is in flight and
596
+ * subscribers are notified at suspend *start*, so an inline "updating…"
597
+ * indicator appears immediately. Readers keep displaying the previous
598
+ * resolved value (`Computed.staleValue`) until the new promise resolves and
599
+ * propagates through the reactive graph; an `@await` boundary keeps its
600
+ * content mounted instead of flashing fallback.
601
+ *
602
+ * Pass `{ silent: true }` to re-fetch quietly (stale-while-revalidate):
603
+ * `$pending(fn)` stays `false` and nothing re-runs until the new promise
604
+ * resolves. For background revalidation where feedback would be noise —
605
+ * polling, refetch-on-focus:
606
+ *
607
+ * ```torp
608
+ * // poll quietly every 30s
609
+ * $run(() => {
610
+ * const id = setInterval(() => $refresh(() => $state.data, { silent: true }), 30_000);
611
+ * return () => clearInterval(id);
612
+ * });
613
+ * ```
614
+ *
615
+ * A refresh is loud regardless of `silent` when the computed has never
616
+ * resolved — e.g. retrying after an error that left `didError` set on a first
617
+ * load — or when the re-fetch is triggered by a dependency change, which
618
+ * flows through the normal `recalc` path instead of here.
619
+ *
620
+ * If `fn` reads a getter the UI has never read, the collection read
621
+ * initializes it — and that fetch IS the refresh: the computed is not re-run
622
+ * (a second fetch would be a duplicate whose resolve the generation guard
623
+ * drops). Getters already read (pending, resolved, or errored) are re-run as
624
+ * usual.
625
+ *
626
+ * The returned value of `fn` is ignored; use `fn` to reference the getters.
627
+ */
628
+ declare function $refresh(fn: () => any, options?: RefreshOptions): void;
629
+ //#endregion
181
630
  //#region src/watch/$run.d.ts
182
631
  /**
183
- * Runs and re-runs a function that depends on a watched object
184
- *
185
- * @param fn The function to run, which may return a cleanup function.
186
- */
187
- declare function $run(fn: () => Cleanup | void, name?: string): Effect;
632
+ * Runs and re-runs a function that depends on a watched object
633
+ *
634
+ * @param fn The function to run, which may return a cleanup function.
635
+ * @param options Internal fields to set on the constructed Effect (e.g.
636
+ * `isMountEffect`, `forVarDeps`). Not part of the public API.
637
+ */
638
+ declare function $run(fn: () => Cleanup | void, name?: string, options?: Pick<Effect, "isMountEffect" | "forVarMask">): Effect;
639
+ //#endregion
640
+ //#region src/watch/$stream.d.ts
641
+ /**
642
+ * Subscribes to an external source of events — server-sent events,
643
+ * WebSockets, DOM events, or any custom `StreamSource` — and calls
644
+ * `handler` for each event it pushes. Events are typically written into
645
+ * reactive state, which keeps templates, computeds and effects updating
646
+ * through the normal reactivity model:
647
+ *
648
+ * ```torp
649
+ * let $state = $watch({ messages: [] as string[] });
650
+ *
651
+ * $stream(fromServer(`/sse/${$props.id}`), (e) => {
652
+ * $state.messages.push(e.data);
653
+ * });
654
+ * ```
655
+ *
656
+ * The subscription is managed by the framework:
657
+ *
658
+ * - It starts when the component is mounted to the DOM (so `&ref`-bound
659
+ * elements are available), and is unsubscribed when the component
660
+ * unmounts or its region is cleared.
661
+ * - Reactive state read *inside* the source is tracked: when it changes,
662
+ * the source is unsubscribed and re-subscribed with fresh values (e.g.
663
+ * re-opening a connection when a user id changes). A pending debounced
664
+ * call is dropped on re-subscribe.
665
+ * - The source is never invoked during a server render, so browser-only
666
+ * APIs are safe to use.
667
+ *
668
+ * Errors are values like any other: a source that can fail should push an
669
+ * error-shaped value and own its own reconnection (e.g. `EventSource`
670
+ * reconnects automatically).
671
+ *
672
+ * @param source The stream source to subscribe to
673
+ * @param handler Called for each event the source pushes
674
+ * @param options Timing options. `debounce` delays each handler call until
675
+ * the source has been quiet for that many milliseconds, resetting on
676
+ * every event (only the last event in a burst is handled).
677
+ */
678
+ declare function $stream<T>(source: StreamSource<T>, handler: (value: T) => void, options?: {
679
+ debounce?: number;
680
+ }): void;
188
681
  //#endregion
189
682
  //#region src/watch/$unwrap.d.ts
190
683
  /**
191
- * Returns the target object of a proxy
192
- *
193
- * @param object The proxy object
194
- */
684
+ * Returns the target object of a proxy
685
+ *
686
+ * @param object The proxy object
687
+ */
195
688
  declare function $unwrap<T extends Record<PropertyKey, any>>(object: T): T;
196
689
  //#endregion
197
690
  //#region src/types/WatchOptions.d.ts
198
691
  /**
199
- * Options for $watch.
200
- */
692
+ * Options for $watch.
693
+ */
201
694
  interface WatchOptions {
202
695
  /**
203
- * Only watch top-level properties, don't recursively watch children.
204
- */
696
+ * Only watch top-level properties, don't recursively watch children.
697
+ */
205
698
  shallow?: boolean;
206
699
  }
207
700
  //#endregion
208
701
  //#region src/watch/$watch.d.ts
209
702
  /**
210
- * Watches an object and runs effects when its properties are changed
211
- *
212
- * @param object The object to watch
213
- */
214
- declare function $watch<T extends Record<PropertyKey, any>>(object: T, options?: WatchOptions): T;
215
- //#endregion
216
- //#region src/wrappers/ReactiveDate.d.ts
217
- /**
218
- * Wraps a Date object for $watching.
219
- */
220
- declare class ReactiveDate extends Date {
221
- #private;
222
- constructor(...params: any[]);
223
- }
224
- //#endregion
225
- export { $batch, $cache, $mount, $peek, $run, $unwrap, $watch, type Animation, type ClassValue, type Component, type ListItem, ReactiveDate, type SlotRender, type StyleValue, clearLayoutSlot, fillLayoutSlot, hydrate, mount, addFragment as t_add_fragment, nodeAnchor as t_anchor, addAnimation as t_animate, applyProps as t_apply_props, setAttribute as t_attribute, nodeChild as t_child, buildClasses as t_class, setDynamicElement as t_dynamic, addEvent as t_event, formatText as t_fmt, getFragment as t_fragment, newListItem as t_list_item, nodeNext as t_next, popRegion as t_pop_region, pushRegion as t_push_region, newRegion as t_region, nodeRoot as t_root, runControlBranch as t_run_branch, runControl as t_run_control, runList as t_run_list, nodeSkip as t_skip, buildStyles as t_style };
703
+ * Watches an object and runs effects when its properties are changed.
704
+ *
705
+ * Dates, Maps and Sets are supported too: their methods are reactive (reads
706
+ * track, writes notify), so `new Date()`, `new Map()` and `new Set()` can be
707
+ * used in watched state directly.
708
+ *
709
+ * @param object The object to watch
710
+ */
711
+ declare function $watch<T extends object>(object: T, options?: WatchOptions): T;
712
+ //#endregion
713
+ export { $async, $batch, $bind, $cache, $onmount, $peek, $pending, $refresh, $run, $stream, $unwrap, $watch, type Animation, type Bindable, type ClassValue, type Component, type ListItem, type ListItemSpec, type SlotRender, type StreamSource, type StyleValue, clearLayoutSlot, fillLayoutSlot, fromElement, fromServer, fromWebSocket, hydrate, mount, addElement as t_add_element, addFragment as t_add_fragment, nodeAnchor as t_anchor, addAnimation as t_animate, applyProps as t_apply_props, setAttribute as t_attribute, nodeChild as t_child, buildClasses as t_class, setDynamicElement as t_dynamic, addEvent as t_event, formatText as t_fmt, getFragment as t_fragment, getElementFragment as t_fragment_el, newListItem as t_list_item, nodeNext as t_next, popRegion as t_pop_region, pushRegion as t_push_region, newRegion as t_region, rerunRegionEffects as t_rerun_region_effects, restoreHydration as t_restore_hydration, nodeRoot as t_root, nodeRootElement as t_root_el, runAwait as t_run_await, runControlBranch as t_run_branch, runControl as t_run_control, runList as t_run_list, runTry as t_run_try, saveHydration as t_save_hydration, nodeSkip as t_skip, buildStyles as t_style, unmount };
226
714
  //# sourceMappingURL=index.d.mts.map