@calmdown/pyxis 1.0.0-rc.2 → 1.0.0-rc.4

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.
@@ -1,3 +1,10 @@
1
+ //#region src/symbols.d.ts
2
+ export declare const S_ATOM: unique symbol;
3
+ export declare const S_COMPONENT: unique symbol;
4
+ export declare const S_TAG_NAME: unique symbol;
5
+ /** used as a key to attach and access dev info on JSX objects */
6
+ export declare const S_DEV_INFO: unique symbol;
7
+ //#endregion
1
8
  //#region src/support/types.d.ts
2
9
  /**
3
10
  * Puts `T` into a union with `null` and `undefined`.
@@ -17,32 +24,47 @@ type PropsType = { readonly [_ in string]?: any; };
17
24
  */
18
25
  declare const S_NODE_TYPE: unique symbol;
19
26
  /**
20
- * Infers the specific Node type from its props typings.
27
+ * Infers the specific Node type from its props typings, if available.
21
28
  */
22
29
  type NodeType<P> = P extends {
23
30
  readonly [S_NODE_TYPE]?: infer N;
24
31
  } ? N : unknown;
25
32
  /**
26
- * A tuple of up to 2 arguments.
33
+ * A symbol to include in props typings containing the element name.
34
+ * @deprecated **Type only, does not exist at runtime!**
27
35
  */
28
- type ArgsMax2<A0 = any, A1 = any> = [a0?: A0, a1?: A1];
36
+ declare const S_ELEM_NAME: unique symbol;
29
37
  /**
30
- * Describes a callback with up to two stored arguments.
38
+ * Infers the specific element name from its props typings, if available.
31
39
  */
32
- interface Callback<TArgs extends ArgsMax2 = ArgsMax2, TReturn = void> {}
33
- //#endregion
34
- //#region src/data/Dependency.d.ts
40
+ type ElemName<P> = P extends {
41
+ readonly [S_ELEM_NAME]?: infer N extends string;
42
+ } ? N : string;
35
43
  /**
36
- * A dependency callback of an Atom. The callback will be run whenever the relevant Atom changes.
44
+ * Flattens an intersection of objects into a single object.
45
+ *
46
+ * Note: The extra `& {}` appendix causes TypeScript to display the resulting type in its expanded
47
+ * form, rather than showing `Flatten<...>`.
48
+ */
49
+ type Flatten<T> = { [K in keyof T]: T[K]; } & {};
50
+ /**
51
+ * A tuple of up to 3 arguments.
52
+ */
53
+ type ArgsMax3<A0 = any, A1 = any, A2 = any> = [a0?: A0, a1?: A1, a2?: A2];
54
+ /**
55
+ * Describes a callback with up to two stored arguments.
37
56
  */
38
- interface Dependency<TArgs extends ArgsMax2 = ArgsMax2> extends Callback<TArgs> {}
39
- interface DependencyList<TArgs extends ArgsMax2 = ArgsMax2> {}
40
- declare function bind(lifecycle: Lifecycle, target: DependencyList, block: () => void): void;
57
+ interface Callback<TArgs extends ArgsMax3 = ArgsMax3, TReturn = void> {
58
+ fn: (this: any, ...args: TArgs) => TReturn;
59
+ a0?: TArgs[0];
60
+ a1?: TArgs[1];
61
+ a2?: TArgs[2];
62
+ }
41
63
  //#endregion
42
64
  //#region src/data/Lifecycle.d.ts
43
65
  interface Lifecycle extends DependencyList {
44
- /** whether this Lifecycle is currently mounted or not */
45
- mounted: boolean;
66
+ /** gets a boolean indicating whether this Lifecycle is currently mounted or not */
67
+ readonly mounted: boolean;
46
68
  }
47
69
  interface MountBlock {
48
70
  (): (() => void) | void;
@@ -51,28 +73,205 @@ interface UnmountBlock {
51
73
  (): void;
52
74
  }
53
75
  /**
54
- * Registers a callback to run just after the current Component has mounted.
76
+ * Registers a block of code to run once the current Component has mounted.
55
77
  *
56
78
  * If a teardown callback is returned, it will be run just before the Component unmounts (equivalent
57
79
  * to adding a separate `unmounted` block).
58
80
  * @see {@link unmounted}
59
81
  */
60
- declare function mounted(block: MountBlock, lifecycle?: Lifecycle): void;
82
+ export declare function mounted(block: MountBlock, lifecycle?: Lifecycle): void;
83
+ /**
84
+ * Similar to {@link mounted}, but instead accepts a {@link Callback} object. Useful in hot paths
85
+ * where it may be desirable to reuse callback objects, avoid closures, or {@link Lifecycle} needs
86
+ * to be tightly controlled.
87
+ * @see {@link mounted}
88
+ */
89
+ export declare function onceMounted<TArgs extends ArgsMax3>(lifecycle: Lifecycle, callback: Callback<TArgs>): void;
61
90
  /**
62
- * Registers a callback to run once the current Component is just about to unmount.
91
+ * Registers a block of code to run once the current Component is just about to unmount.
63
92
  * @see {@link mounted}
64
93
  */
65
- declare function unmounted(block: UnmountBlock, lifecycle?: Lifecycle): void;
94
+ export declare function unmounted(block: UnmountBlock, lifecycle?: Lifecycle): void;
95
+ /**
96
+ * Similar to {@link unmounted}, but instead accepts a {@link Callback} object. Useful in hot paths
97
+ * where it may be desirable to reuse callback objects, avoid closures, or {@link Lifecycle} needs
98
+ * to be tightly controlled.
99
+ * @see {@link unmounted}
100
+ */
101
+ export declare function onceUnmounted<TArgs extends ArgsMax3>(lifecycle: Lifecycle, callback: Callback<TArgs>): void;
66
102
  /**
67
103
  * Gets the Lifecycle of the calling component.
68
104
  */
69
- declare function getLifecycle(): Lifecycle;
105
+ export declare function getLifecycle(): Lifecycle;
70
106
  /**
71
107
  * Runs a block of code with the provided Lifecycle. Calls to `getLifecycle` within the block will
72
108
  * return the specified object.
73
109
  * @see {@link getLifecycle}
74
110
  */
75
- declare function withLifecycle<TArgs extends [arg?: any], TReturn>(lifecycle: Lifecycle, block: (...args: TArgs) => TReturn, ...args: TArgs): TReturn;
111
+ export declare function withLifecycle<TArgs extends ArgsMax3, TReturn>(lifecycle: Lifecycle, block: (...args: TArgs) => TReturn, ...args: TArgs): TReturn;
112
+ //#endregion
113
+ //#region src/data/Dependency.d.ts
114
+ /**
115
+ * A dependency callback of an Atom. The callback will be run whenever the relevant Atom changes.
116
+ */
117
+ interface Dependency<TArgs extends ArgsMax3 = ArgsMax3> extends Callback<TArgs> {}
118
+ /**
119
+ * Represents an object capable of holding links to Dependencies and dispatching notifications
120
+ * to them.
121
+ */
122
+ interface DependencyList<TArgs extends ArgsMax3 = ArgsMax3> {
123
+ /**
124
+ * In chained data relations (proxy and context atoms), tracks the upstream atom forwarding
125
+ * notifications to this atom.
126
+ */
127
+ $upstream?: Nil<DependencyList>;
128
+ }
129
+ /**
130
+ * Invokes the provided {@link Dependency} and binds it to run again with each notification emitted
131
+ * by the specified target. The return value of the initial run is forwarded.
132
+ */
133
+ export declare function bind<TArgs extends ArgsMax3, TResult>(lifecycle: Lifecycle, target: DependencyList, dependency: Dependency & Callback<TArgs, TResult>): TResult;
134
+ /**
135
+ * Links a {@link Dependency} to an {@link Atom} and {@link Lifecycle}.
136
+ */
137
+ export declare function link<TArgs extends ArgsMax3>(lifecycle: Lifecycle, target: DependencyList, dep: Dependency<TArgs>): void;
138
+ /**
139
+ * Unlinks a Dependency from the Atom and Lifecycle it has been linked to.
140
+ */
141
+ export declare function unlink(dep: Dependency): void;
142
+ //#endregion
143
+ //#region src/data/Atom.d.ts
144
+ /**
145
+ * Holds any single value, managing reactions to its changes. A bare Atom is read-only. Use the
146
+ * `read` and `peek` functions to access its value.
147
+ * @see {@link read}
148
+ * @see {@link peek}
149
+ * @see {@link WriteAtom}
150
+ */
151
+ interface Atom<out T = unknown> extends DependencyList {
152
+ /** Pyxis Atom type guard marker. */
153
+ readonly [S_ATOM]: true;
154
+ /**
155
+ * Gets the value of this Atom. Only use this method when the target is guaranteed to be an
156
+ * Atom, otherwise it is recommended to use the `read` or `peek` functions.
157
+ *
158
+ * This method does *not* report access, thus within effects it is analogous to `peek`.
159
+ * @see {@link read}
160
+ * @see {@link peek}
161
+ */
162
+ get: () => T;
163
+ }
164
+ /**
165
+ * Holds any single value, managing reactions to its changes. Values of WriteAtom are mutable and
166
+ * can be freely changed at any time. Use the `read`, `peek`, `write` or `update` functions to
167
+ * access or manipulate its value.
168
+ * @see {@link read}
169
+ * @see {@link peek}
170
+ * @see {@link write}
171
+ * @see {@link update}
172
+ * @see {@link Atom}
173
+ */
174
+ interface WriteAtom<T = unknown> extends Atom<T> {
175
+ /**
176
+ * Sets the value of this Atom. Does nothing if this Atom is readonly. This method does *not*
177
+ * emit any change notification to the Atom's observers; Using it recklessly can leave observers
178
+ * out of date with stale state! Please make sure you know exactly what you're doing; It is
179
+ * *strongly* recommended to use the `write` or `update` functions instead.
180
+ *
181
+ * @returns Boolean indicating whether the value of this Atom changed.
182
+ * @see {@link write}
183
+ * @see {@link update}
184
+ */
185
+ set: (value: T) => boolean;
186
+ }
187
+ /**
188
+ * Union of the given type or an Atom of that type. Use the `read`, `peek` or `isAtom` functions to
189
+ * interact with such values.
190
+ * @see {@link read}
191
+ * @see {@link peek}
192
+ * @see {@link isAtom}
193
+ */
194
+ type MaybeAtom<T> = Atom<T> | T;
195
+ /**
196
+ * Union of the given type or a WriteAtom of that type. Use the `read`, `peek`, `write`, `update` or
197
+ * `isAtom` functions to interact with such values.
198
+ * @see {@link read}
199
+ * @see {@link peek}
200
+ * @see {@link write}
201
+ * @see {@link update}
202
+ * @see {@link isAtom}
203
+ */
204
+ type MaybeWriteAtom<T> = WriteAtom<T> | T;
205
+ /**
206
+ * Creates an empty WriteAtom; i.e. value set to `undefined`.
207
+ */
208
+ export declare function atomOf<T>(): WriteAtom<T | undefined>;
209
+ /**
210
+ * Creates a WriteAtom initialized to the provided value.
211
+ *
212
+ * If the provided initial value is itself an Atom, its value is automatically unwrapped.
213
+ *
214
+ * If you're intentionally creating an Atom intended to hold other Atoms, create an empty Atom first
215
+ * and write it separately, e.g.:
216
+ *
217
+ * ```ts
218
+ * const atom = atomOf<Atom<number>>();
219
+ * write(atom, otherAtom);
220
+ * ```
221
+ */
222
+ export declare function atomOf<T>(initialValue: MaybeAtom<T>, lifecycle?: Lifecycle, devId?: string): WriteAtom<T>;
223
+ /**
224
+ * Atom type guard, checks if the provided input is an Atom.
225
+ */
226
+ export declare function isAtom<T = unknown>(input: Nil<MaybeWriteAtom<T>>): input is WriteAtom<T>;
227
+ export declare function isAtom<T = unknown>(input: Nil<MaybeAtom<T>>): input is Atom<T>;
228
+ export declare function isAtom<T = unknown>(input: unknown): input is WriteAtom<T>;
229
+ /**
230
+ * Checks if the provided input is an Atom and reads its value. Non-atom inputs are returned as-is.
231
+ * Reports read access when inside an effect.
232
+ * @see {@link isAtom}
233
+ * @see {@link peek}
234
+ * @see {@link write}
235
+ * @see {@link update}
236
+ */
237
+ export declare function read<A>(input: A): A extends MaybeAtom<infer T> ? T : never;
238
+ /**
239
+ * Checks if the provided input is an Atom and reads its value. Non-atom inputs are returned as-is.
240
+ * Does NOT report read access when inside an effect.
241
+ * @see {@link isAtom}
242
+ * @see {@link read}
243
+ * @see {@link write}
244
+ * @see {@link update}
245
+ */
246
+ export declare function peek<A>(input: A): A extends MaybeAtom<infer T> ? T : never;
247
+ /**
248
+ * Checks if the provided input is an Atom, writes its value and returns the new value.
249
+ *
250
+ * Writing readonly Atoms is simply a no-op. Their current value will be returned and the provided
251
+ * new value discarded.
252
+ *
253
+ * Non-atom inputs are never modified in any way. Instead the provided new value is discarded and
254
+ * the input is returned as-is.
255
+ * @see {@link isAtom}
256
+ * @see {@link read}
257
+ * @see {@link peek}
258
+ * @see {@link update}
259
+ */
260
+ export declare function write<A>(input: A, value: A extends WriteAtom<infer T> ? T : never, force?: boolean): A extends MaybeWriteAtom<infer T> ? T : never;
261
+ /**
262
+ * Checks if the provided input is an Atom, updates its value using the provided transform function
263
+ * and returns the new value.
264
+ *
265
+ * Updating readonly Atoms is simply a no-op. Their current value will be returned and the
266
+ * transformed new value discarded.
267
+ *
268
+ * Non-atom inputs are never modified in any way and the input is returned as-is.
269
+ * @see {@link isAtom}
270
+ * @see {@link read}
271
+ * @see {@link peek}
272
+ * @see {@link write}
273
+ */
274
+ export declare function update<A>(input: A, transform: A extends WriteAtom<infer T> ? (value: T) => T : never, force?: boolean): A extends MaybeWriteAtom<infer T> ? T : never;
76
275
  //#endregion
77
276
  //#region src/data/Scheduler.d.ts
78
277
  /**
@@ -83,30 +282,48 @@ interface TickFn {
83
282
  (onTick: () => void): void;
84
283
  }
85
284
  /**
86
- * Runs a block of code on the next tick of the scheduler, synchronized with other updates. If a
87
- * tick is not currently pending, a new one is scheduled.
285
+ * Runs a block of code on the next tick of the scheduler, synchronized with other updates. Unless
286
+ * a tick is already pending, a new one is scheduled.
287
+ *
288
+ * Atoms written within the block will deliver their update notifications synchronously within the
289
+ * same tick.
290
+ */
291
+ export declare function tick(block: () => void, lifecycle?: Lifecycle): void;
292
+ /**
293
+ * Similar to {@link tick}, but instead accepts a {@link Callback} object. Useful in hot paths
294
+ * where it may be desirable to reuse callback objects and/or avoid closures.
295
+ * @see {@link tick}
88
296
  */
89
- declare function tick(block: () => void, lifecycle?: Lifecycle): void;
297
+ export declare function scheduleTick<TArgs extends ArgsMax3>(lifecycle: Lifecycle, callback: Callback<TArgs>): void;
90
298
  /**
91
- * Runs a block of code after the next tick of the scheduler, once all regular updates finished.
92
- * If a tick is not currently pending, a new one is scheduled.
299
+ * Runs a block of code immediately after the next tick of the scheduler, once all regular updates
300
+ * have finished. Unless a tick is already pending, a new one is scheduled.
301
+ *
302
+ * While it is possible to write Atoms within the block, their update notifications are
303
+ * no longer delivered in the same scheduler tick - they're postponed to the next one.
93
304
  */
94
- declare function tock(block: () => void, lifecycle?: Lifecycle): void;
305
+ export declare function tock(block: () => void, lifecycle?: Lifecycle): void;
306
+ /**
307
+ * Similar to {@link tock}, but instead accepts a {@link Callback} object. Useful in hot paths
308
+ * where it may be desirable to reuse callback objects and/or avoid closures.
309
+ * @see {@link tock}
310
+ */
311
+ export declare function scheduleTock<TArgs extends ArgsMax3>(lifecycle: Lifecycle, callback: Callback<TArgs>): void;
95
312
  //#endregion
96
313
  //#region src/Adapter.d.ts
97
- interface Adapter<TNode, TIntrinsicElements extends ElementsType = ElementsType> {
314
+ interface Adapter<TNode, TElements extends ElementsType = ElementsType> {
98
315
  /**
99
316
  * Carries information about the available intrinsic elements when using this Adapter.
100
317
  * @deprecated **Type only, does not exist at runtime!**
101
318
  */
102
- readonly $elements?: TIntrinsicElements;
319
+ readonly $elements?: TElements;
103
320
  /**
104
321
  * A function able to schedule a callback to be executed at a later time, e.g. `queueMicrotask`.
105
322
  * The function must guarantee that the callback will be eventually executed.
106
323
  */
107
324
  readonly tick: TickFn;
108
325
  /**
109
- * Creates a native (intrinsic) element node by its name.
326
+ * Creates a native (intrinsic) element node by the element name.
110
327
  */
111
328
  readonly element: (name: string) => TNode;
112
329
  /**
@@ -127,8 +344,8 @@ interface Adapter<TNode, TIntrinsicElements extends ElementsType = ElementsType>
127
344
  readonly batch?: () => TNode;
128
345
  /**
129
346
  * Inserts the given `node` as a child of the `parent`. If `before` is provided, the child will
130
- * be inserted just before the referenced node, otherwise the child is inserted as the new last
131
- * child.
347
+ * be inserted just before the referenced node (which itself must be a child of the parent),
348
+ * otherwise the child is inserted at the end, becoming the new last child of the parent.
132
349
  */
133
350
  readonly insert: (node: TNode, parent: TNode, before: TNode | null) => void;
134
351
  /**
@@ -138,134 +355,149 @@ interface Adapter<TNode, TIntrinsicElements extends ElementsType = ElementsType>
138
355
  /**
139
356
  * Sets a named property of the given node.
140
357
  */
141
- readonly set: (node: TNode, prop: string, value: any) => void;
358
+ readonly set: (elem: TNode, prop: string, value: any) => void;
142
359
  }
143
- interface Extension<TNode, TExtensionKey extends string = string, TIntrinsicElements extends ElementsType = ElementsType, TExtendedIntrinsicElements extends ElementsType = ElementsType> {
360
+ type ExtensionsType<TNode> = { [_ in string]?: Extension<TNode>; };
361
+ interface Extension<TNode, TPropMapping extends ExtensionPropMapping<unknown> = ExtensionPropMapping<unknown>> {
144
362
  /**
145
- * Infers prop types to decorate existing types with extensions.
146
- * Type only, this call signature does not exist at runtime!
363
+ * Carries a mapping type used to infer the props this extension adds to native elements.
364
+ * @deprecated **Type only, does not exist at runtime!**
147
365
  */
148
- (extensionKey: TExtensionKey, intrinsicElements: TIntrinsicElements): TExtendedIntrinsicElements;
366
+ readonly $mapping?: TPropMapping;
149
367
  /**
150
- * Sets a named extension property of the given node.
368
+ * Sets a named extension property of the given element. The prop name arrives unprefixed, i.e.
369
+ * without any extension key prefix.
151
370
  */
152
371
  readonly set: (node: TNode, prop: string, value: any, group: MountingGroup<TNode>) => void;
153
372
  }
154
- type ExtensionsType<TNode> = { [_ in string]?: Extension<TNode>; };
155
- type ExtensionProps<TExtensionKey extends string, TProps extends PropsType> = { readonly [TExtPropKey in `${TExtensionKey}:${keyof TProps & string}`]?: (TExtPropKey extends `${TExtensionKey}:${infer TPropKey}` ? TProps[TPropKey] : never); };
156
- //#endregion
157
- //#region src/data/Atom.d.ts
158
- /**
159
- * Pyxis Atom type guard marker.
160
- */
161
- declare const S_ATOM: unique symbol;
162
- /** Contract for Atoms where they need to be read. */
163
- interface ReadAtom<out T> extends DependencyList {
164
- /** Pyxis Atom type guard marker. */
165
- readonly [S_ATOM]: true;
373
+ interface ExtensionPropMapping<TNode> {
374
+ /** Will contain a concrete type of the element for which props are being mapped. */
375
+ node: TNode;
376
+ /** Will contain a name of the element for which props are being mapped. */
377
+ name: string;
166
378
  /**
167
- * Gets the value of this Atom. Only use this method when the target is guaranteed to be an
168
- * Atom, otherwise it is recommended to use the `read` or `peek` functions.
379
+ * Override this field with an inferred object containing typed extension props. Prop names
380
+ * should be plain, do not include their extension prefix. It will be added automatically.
169
381
  *
170
- * This method does *not* report access, thus within effects it is analogous to `peek`.
171
- * @see {@link read}
172
- * @see {@link peek}
382
+ * To infer concrete types, you may use:
383
+ *
384
+ * - `this["node"]` ... concrete type of the element node
385
+ * - `this["name"]` ... the name of the element, as used in JSX
173
386
  */
174
- get: () => T;
387
+ extension: {};
175
388
  }
389
+ /** Creates an extension with a shared-runtime ID independent of its registered JSX prefix. */
390
+ export declare function extension<TNode, TPropMapping extends ExtensionPropMapping<TNode>>(propSetter: Extension<TNode>["set"]): Extension<TNode, TPropMapping>;
176
391
  /**
177
- * Holds any single value, managing reactions to its changes. Use the `read`, `write` functions to
178
- * access its value.
179
- * @see {@link read}
180
- * @see {@link write}
392
+ * Builds a set of extension props using an Extension reference rather than relying on a globally
393
+ * registered prefixed extension props. The resulting object is intended to be ...spread directly
394
+ * onto JSX elements.
395
+ *
396
+ * Typically used in libraries where relying on a specific prefix convention would limit the users.
397
+ * Does not require an active component lifecycle. Repeated spreads use the last value for each
398
+ * extension/prop pair, while props from different extensions remain independent.
181
399
  */
182
- interface Atom<T = unknown> extends ReadAtom<T> {
400
+ export declare function ext<TMapping extends ExtensionPropMapping<any>, TNodeType, TElemName>(extension: Extension<any, TMapping>, extensionProps: (TMapping & {
401
+ node: TNodeType;
402
+ name: TElemName;
403
+ })["extension"], targetPropsObject?: { [_ in string]?: any; }): {
404
+ readonly [S_NODE_TYPE]?: TNodeType;
405
+ readonly [S_ELEM_NAME]?: TElemName;
406
+ };
407
+ //#endregion
408
+ //#region src/Renderer.d.ts
409
+ interface Renderer<TNode, TElements extends ElementsType = ElementsType> extends Lifecycle {
183
410
  /**
184
- * Sets the value of this Atom. Does nothing if this Atom is readonly. Only use this method when
185
- * the target is guaranteed to be an Atom, otherwise it is recommended to use the `write` or
186
- * `update` functions.
187
- *
188
- * This method does *not* send out any change notifications to observers!
189
- * @returns Boolean indicating whether the value of this Atom changed.
190
- * @see {@link write}
191
- * @see {@link update}
411
+ * Carries information about the available intrinsic elements when using this Renderer.
412
+ * @deprecated **Type only, does not exist at runtime!**
192
413
  */
193
- set: (value: T) => boolean;
414
+ readonly $elements?: TElements;
415
+ mount: (root: TNode, jsx: JsxResult) => MountingGroup<TNode>;
416
+ unmount: (group: MountingGroup<TNode>) => void;
417
+ }
418
+ /** Extracts the typings of intrinsic elements supported by the given Renderer. */
419
+ type ElementsOf<TRenderer, TFallback extends ElementsType = {}> = (TRenderer extends {
420
+ readonly $elements?: infer TElements extends ElementsType;
421
+ } ? TElements : TFallback);
422
+ interface MountingGroup<TNode> extends Lifecycle, Hierarchy<TNode> {
423
+ /** the Adapter rendering this MountingGroup */
424
+ readonly adapter: Adapter<TNode>;
425
+ }
426
+ interface NativeNode<TNode> extends Hierarchy<TNode> {}
427
+ interface Hierarchy<TNode> {
428
+ /**
429
+ * tracks whether unmounting is in progress for this node, guarding against duplicate or cyclic
430
+ * unmount attempts
431
+ */
432
+ $isUnmounting?: boolean;
194
433
  }
434
+ type HNode<TNode> = MountingGroup<TNode> | NativeNode<TNode>;
195
435
  /**
196
- * Union of the given type or an Atom of that type. Use the `read`, `peek`, `write`, `update` or
197
- * `isAtom` functions to interact with such values.
198
- * @see {@link read}
199
- * @see {@link peek}
200
- * @see {@link write}
201
- * @see {@link update}
202
- * @see {@link isAtom}
436
+ * Unmounts a MountingGroup and removes it from the hierarchy. The removal is guaranteed even if
437
+ * user code throws during unmount. Also clears refs to its original parent node. Destroyed groups
438
+ * cannot be reused.
203
439
  */
204
- type MaybeAtom<T> = Atom<T> | T;
440
+ export declare function destroy<TNode>(hGroup: MountingGroup<TNode>): void;
205
441
  /**
206
- * Union of the given type or the ReadAtom contract of that type. Use the `read`, `peek` or `isAtom`
207
- * functions to interact with such values.
208
- * @see {@link read}
209
- * @see {@link peek}
210
- * @see {@link isAtom}
442
+ * Creates a sub-group within the provided MountingGroup. Needed whenever a subtree needs to mount
443
+ * or unmount dynamically.
211
444
  */
212
- type MaybeReadAtom<T> = ReadAtom<T> | T;
445
+ export declare function fork<TNode>(hParent: HNode<TNode>, hBefore?: HNode<TNode> | null): MountingGroup<TNode>;
213
446
  /**
214
- * Creates an empty Atom; i.e. value set to `undefined`.
447
+ * Inserts a HNode to the hierarchy. When reusing nodes, callers must make sure `untrack` has been
448
+ * previously called on the node to be re-inserted.
449
+ * @see {@link untrack}
215
450
  */
216
- declare function atomOf<T>(): Atom<T | undefined>;
451
+ export declare function track<TNode>(hNode: HNode<TNode>, hParent: HNode<TNode>, hBefore?: HNode<TNode> | null): void;
217
452
  /**
218
- * Creates an Atom initialized to the provided value. If the provided value is already an Atom, it
219
- * is returned as-is.
220
- * @see {@link isAtom}
453
+ * Removes a HNode from the tracking hierarchy. Removed nodes may be reused and re-inserted using
454
+ * the `track` function.
455
+ * @see {@link track}
221
456
  */
222
- declare function atomOf<T>(initialValue: MaybeAtom<T>, lifecycle?: Lifecycle, devId?: string): Atom<T>;
457
+ export declare function untrack<TNode>(hNode: HNode<TNode>): void;
223
458
  /**
224
- * Atom type guard, checks if the provided input is an Atom.
459
+ * Creates a reusable callback for a complete render operation, including reactive reads, nested
460
+ * mounts and batch commits. Each invocation defers conflicting unmounts until the outermost render
461
+ * finishes, preserves the caller's reactive tracking, and returns the block's result unchanged.
462
+ *
463
+ * Deferred teardown errors are reported by the outermost render, after all requests are processed.
225
464
  */
226
- declare function isAtom<T = unknown>(input: Nil<MaybeAtom<T>>): input is Atom<T>;
227
- declare function isAtom<T = unknown>(input: Nil<MaybeReadAtom<T>>): input is ReadAtom<T>;
228
- declare function isAtom<T = unknown>(input: unknown): input is Atom<T>;
465
+ export declare function willMount<TNode, TArgs extends ArgsMax3, TResult>(hGroup: MountingGroup<TNode>, block: (...args: TArgs) => TResult): (...args: TArgs) => TResult;
229
466
  /**
230
- * Checks if the provided input is an Atom and reads its value. Non-atom inputs are returned as-is.
231
- * Reports read access when inside an effect.
232
- * @see {@link isAtom}
233
- * @see {@link write}
234
- * @see {@link peek}
235
- * @see {@link update}
467
+ * Mounts JSX into a group that is not already mounted. When rendering into an externally owned
468
+ * batch, enclose the complete operation (including the commit and `flush`) in {@link willMount}.
236
469
  */
237
- declare function read<A>(input: A): A extends MaybeReadAtom<infer T> ? T : never;
470
+ export declare function mount<TNode>(jsx: any, hParent: MountingGroup<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, nRealParent: TNode, isBatch: boolean): void;
238
471
  /**
239
- * Checks if the provided input is an Atom and reads its value. Non-atom inputs are returned as-is.
240
- * Does NOT report read access when inside an effect.
241
- * @see {@link isAtom}
242
- * @see {@link read}
243
- * @see {@link write}
244
- * @see {@link update}
472
+ * Marks the provided hGroup and all of its descendants as mounted and dispatches notifications
473
+ * where appropriate.
474
+ *
475
+ * Normally this happens automatically as part of calling {@link mount}, but it is necessary to
476
+ * flush manually when rendering into a batch. Batch owners are responsible for calling this
477
+ * function once the batch has been committed.
245
478
  */
246
- declare function peek<A>(input: A): A extends MaybeReadAtom<infer T> ? T : never;
479
+ export declare function flush<TNode>(hGroup: MountingGroup<TNode>): void;
247
480
  /**
248
- * Checks if the provided input is an Atom, writes its value and returns the new value.
481
+ * Unmounts the contents of a MountingGroup from the node tree. The group itself, though empty,
482
+ * remains usable and can be remounted later.
249
483
  *
250
- * Non-atom inputs are never modified in any way. Instead the provided new value is discarded and
251
- * the input is returned as-is.
252
- * @see {@link isAtom}
253
- * @see {@link read}
254
- * @see {@link write}
255
- * @see {@link update}
484
+ * If teardown would interrupt an active render, it is deferred until the outermost render
485
+ * operation finishes. Any teardown errors are then reported by that operation.
256
486
  */
257
- declare function write<A>(input: A, value: A extends Atom<infer T> ? T : never, force?: boolean): A extends MaybeAtom<infer T> ? T : never;
487
+ export declare function unmount<TNode>(hGroup: MountingGroup<TNode>): void;
258
488
  /**
259
- * Checks if the provided input is an Atom, updates its value using the provided transform function
260
- * and returns the new value.
261
- *
262
- * Non-atom inputs are never modified in any way and the input is returned as-is.
263
- * @see {@link isAtom}
264
- * @see {@link read}
265
- * @see {@link peek}
266
- * @see {@link write}
489
+ * Mounts components described by JSX to the specified location in the node tree.
267
490
  */
268
- declare function update<A>(input: A, transform: A extends Atom<infer T> ? (value: T) => T : never, force?: boolean): A extends MaybeAtom<infer T> ? T : never;
491
+ export declare function mountJsx<TNode>(jsx: any, hParent: HNode<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, nRealParent: TNode, isBatch: boolean): void;
492
+ /**
493
+ * Inserts a native node and adds it to the tracking hierarchy. Necessary to preserve render order.
494
+ * Returns the newly created tracking node, or null when tracking is skipped. Only a direct child
495
+ * of hParent is used as a tracking insertion point; an outer anchor means appending within hParent.
496
+ * Batched native insertions append, while hBefore still determines the tracking position.
497
+ * Should only be called by component handlers!
498
+ */
499
+ export declare function insert<TNode>(nNode: TNode, children: any, hParent: HNode<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, isBatch: boolean, forceTrack: true): NativeNode<TNode>;
500
+ export declare function insert<TNode>(nNode: TNode, children: any, hParent: HNode<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, isBatch: boolean, forceTrack?: boolean): NativeNode<TNode> | null;
269
501
  //#endregion
270
502
  //#region src/Component.d.ts
271
503
  /**
@@ -282,10 +514,7 @@ type PropsOf<T> = T extends Component<infer TProps> ? TProps : unknown;
282
514
  interface DataTemplate<TData> {
283
515
  (data: TData): JsxResult;
284
516
  }
285
- interface ComponentBlock {
286
- (props: PropsType): JsxResult;
287
- }
288
- declare function component<TPropsArg extends [{}]>(block: (...args: TPropsArg) => JsxResult, devId?: string): (...args: [props: JsxProps<TPropsArg[0]>]) => JsxResult;
517
+ export declare function component<TPropsArg extends [{}]>(block: (...args: TPropsArg) => JsxResult, devId?: string): (...args: [props: JsxProps<TPropsArg[0]>]) => JsxResult;
289
518
  /**
290
519
  * Infers the props object for use with JSX. Because Pyxis always supplies components with child
291
520
  * arrays (or tuples), the type needs to be adjusted to reflect the internal mechanics.
@@ -305,23 +534,32 @@ type JsxProps<T> = { readonly [K in keyof T]: K extends "children" ? JsxChildren
305
534
  */
306
535
  type JsxChildrenProp<T> = T extends readonly [any, any, ...any[]] ? T extends readonly [...infer C] ? readonly [...C] : T : T extends readonly [infer SC] ? SC : T extends readonly (infer C)[] ? readonly C[] | C : T;
307
536
  /**
308
- * Primitive types accepted to render as text.
537
+ * Primitive values (or Atoms of such primitives) accepted as text children. Nil and boolean values
538
+ * do not render any text.
309
539
  */
310
- type JsxText = MaybeReadAtom<Nil<string | number | boolean | bigint>>;
540
+ type JsxText = MaybeAtom<Nil<string | number | boolean | bigint>>;
311
541
  /**
312
542
  * Describes the objects returned by JSX factories.
313
543
  *
314
- * Pyxis uses very lightweight factories returning the props object directly,
315
- * adding a few extra props:
316
- *
317
- * - S_COMPONENT ... hidden, contains a reference to the ComponentHandler function
318
- * - S_TAG_NAME ... hidden, specifies the tag name, only populated for native elements
319
- * - children ... always present and always an array, empty array for childless components
544
+ * Pyxis uses lightweight factories returning the props object directly, only adding a few extra
545
+ * symbol-keyed props.
320
546
  */
321
547
  interface JsxObject {
322
548
  [propName: string]: unknown;
549
+ /** specifies the ComponentHandler function used to render this object */
550
+ readonly [S_COMPONENT]: ComponentHandler;
551
+ /** specifies the native element tag name, only populated for native elements */
552
+ readonly [S_TAG_NAME]?: string;
553
+ /** holds source code location of individual JSX nodes, only populated in dev mode */
554
+ readonly [S_DEV_INFO]?: JsxDevSourceInfo;
555
+ /** always present and always an array, empty array for childless components */
323
556
  readonly children: readonly unknown[];
324
557
  }
558
+ interface JsxDevSourceInfo {
559
+ readonly fileName: string;
560
+ readonly lineNumber: number;
561
+ readonly columnNumber: number;
562
+ }
325
563
  /**
326
564
  * Union of all admissible values within JSX.
327
565
  */
@@ -336,117 +574,21 @@ type JsxChildren = JsxResult | readonly JsxChildren[];
336
574
  type WithChildren<T extends PropsType> = T & {
337
575
  children?: JsxChildren;
338
576
  };
339
- //#endregion
340
- //#region src/Renderer.d.ts
341
- interface Renderer<TNode, TIntrinsicElements extends ElementsType = ElementsType> {
342
- /**
343
- * Carries information about the available intrinsic elements when using this Renderer.
344
- * @deprecated **Type only, does not exist at runtime!**
345
- */
346
- readonly $elements?: TIntrinsicElements;
347
- mount: (root: TNode, jsx: JsxResult) => void;
348
- unmount: () => void;
349
- }
350
- type ElementsOf<TRenderer> = TRenderer extends {
351
- readonly $elements?: infer TElements;
352
- } ? TElements : {};
353
- interface MountingGroup<TNode> extends Lifecycle, Hierarchy<TNode> {
354
- readonly $isGroup: true;
355
- readonly $isNative?: never;
356
- /** the Adapter rendering this MountingGroup */
357
- readonly adapter: Adapter<TNode>;
358
- }
359
- interface NativeNode<TNode> extends Hierarchy<TNode> {
360
- readonly $isNative: true;
361
- readonly $isGroup?: never;
362
- readonly $nn: TNode;
363
- }
364
- interface Hierarchy<TNode> {}
365
- type HNode<TNode> = MountingGroup<TNode> | NativeNode<TNode>;
366
- /**
367
- * Creates a sub-group within the provided MountingGroup. Needed whenever a subtree needs to mount
368
- * or unmount dynamically.
369
- */
370
- declare function fork<TNode>(hParent: HNode<TNode>, hBefore?: HNode<TNode> | null): MountingGroup<TNode>;
371
- /**
372
- * Adds a HNode to the hierarchy.
373
- */
374
- declare function track<TNode>(hNode: HNode<TNode>, hParent: HNode<TNode>, hBefore?: HNode<TNode> | null): void;
375
- /**
376
- * Removes a HNode from the tracking hierarchy.
377
- */
378
- declare function untrack<TNode>(hNode: HNode<TNode>): void;
379
- /**
380
- * Mounts a MountingGroup to the specified location in the node tree. If the group is already
381
- * mounted (i.e. its native nodes are already rendered somewhere), it is moved to the new location
382
- * without re-mounting Pyxis components.
383
- *
384
- * Note that for successfully moving a group within the tree, you should first `untrack` the group,
385
- * then re-`track` it to the new location and only then call `mount` to commit the move.
386
- * @see {@link track}
387
- * @see {@link untrack}
388
- */
389
- declare function mount<TNode>(jsx: any, hGroup: MountingGroup<TNode>, nUsedParent: TNode, nRealParent: TNode, nBefore: TNode | null, isBatch: boolean): void;
390
- /**
391
- * Unmounts the contents of a MountingGroup from the node tree. The group itself, though empty,
392
- * remains usable and can be remounted later.
393
- */
394
- declare function unmount<TNode>(group: MountingGroup<TNode>): void;
395
- /**
396
- * Mounts components described by the JsxResult to the specified location in the node tree.
397
- */
398
- declare function mountJsx<TNode>(jsx: any, hParent: HNode<TNode>, nUsedParent: TNode, nRealParent: TNode, nBefore: TNode | null, isBatch: boolean): void;
399
577
  /**
400
- * Inserts a native node and adds it to the tracking hierarchy. Necessary to preserve render order.
401
- * Should only be called by component handlers!
578
+ * A handler function rendering a specific Component type. This is the real shape of Pyxis
579
+ * components used internally by the framework. `hBefore` is a tracked native anchor. When
580
+ * `isBatch` is true, native insertions append while `hBefore` still determines the position in the
581
+ * tracking hierarchy.
402
582
  */
403
- declare function insert<TNode>(nNode: TNode, children: any, hParent: HNode<TNode>, nUsedParent: TNode, nBefore: TNode | null, isBatch: boolean): void;
404
- //#endregion
405
- //#region src/dev/ComponentRegistry.d.ts
406
- declare global {
407
- function queueMicrotask(callback: () => void): void;
408
- }
409
- interface HotComponentEntry {
410
- component: ComponentBlock;
411
- dirty: boolean;
412
- lh?: HotComponentListener | null;
413
- lt?: HotComponentListener | null;
414
- }
415
- interface HotComponentListener {
416
- readonly fn: HotComponentListenerFn;
417
- readonly entry: HotComponentEntry;
418
- lp?: HotComponentListener | null;
419
- ln?: HotComponentListener | null;
420
- }
421
- interface HotComponentListenerFn {
422
- (component: ComponentBlock): void;
423
- }
424
- declare class ComponentRegistry {
425
- private readonly components;
426
- private isPendingUpdate;
427
- on(id: string, fn: HotComponentListenerFn): HotComponentListener;
428
- off(listener: HotComponentListener): void;
429
- subscribe(id: string, fn: HotComponentListenerFn): () => void;
430
- upsert(id: string, component: ComponentBlock): void;
431
- private readonly update;
432
- }
433
- //#endregion
434
- //#region src/dev/StateRegistry.d.ts
435
- declare class StateRegistry {
436
- private readonly state;
437
- preserve(handle: WeakKey | undefined, devId: string | undefined, value: any): void;
438
- restore<T = any>(handle: WeakKey | undefined, devId: string | undefined): T;
439
- restore<T>(handle: WeakKey | undefined, devId: string | undefined, block: (value: any) => T): T | undefined;
440
- }
441
- //#endregion
442
- //#region src/dev/PyxisHotReload.d.ts
443
- interface PyxisHotReload {
444
- readonly component: ComponentRegistry;
445
- readonly state: StateRegistry;
583
+ interface ComponentHandler {
584
+ <TNode>(jsx: JsxObject, hParent: HNode<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, nRealParent: TNode, isBatch: boolean): void;
446
585
  }
447
586
  declare global {
448
- var __PYXIS_HMR__: PyxisHotReload;
449
- var __PYXIS_ROOT__: MountingGroup<any>;
587
+ namespace JSX {
588
+ interface ElementChildrenAttribute {
589
+ children: {};
590
+ }
591
+ }
450
592
  }
451
593
  //#endregion
452
594
  //#region src/component/Fragment.d.ts
@@ -456,38 +598,40 @@ interface FragmentProps {
456
598
  /**
457
599
  * The built-in Fragment Component wrapping multiple Components.
458
600
  */
459
- declare function Fragment(props: JsxProps<FragmentProps>): JsxResult;
601
+ export declare function Fragment(props: JsxProps<FragmentProps>): JsxResult;
460
602
  //#endregion
461
603
  //#region src/data/ListDelta.d.ts
462
- declare enum ChangeKind {
463
- Change = 1,
464
- Insert = 2,
465
- Remove = 3,
466
- Clear = 4
467
- }
604
+ export declare const LC_CHANGE = 1;
605
+ export declare const LC_INSERT = 2;
606
+ export declare const LC_REMOVE = 3;
607
+ export declare const LC_CLEAR = 4;
468
608
  interface ListDelta<T> {
469
- readonly changes: ListChange<T>[];
470
- lengthChange: number;
609
+ /** raw snapshot of the List as observed at the time this ListDelta was emitted */
610
+ readonly snapshot: readonly T[];
611
+ /** changes made to the List since its last update */
612
+ readonly changes: readonly ListChange<T>[];
613
+ /** the relative change of the List size (its item count) */
614
+ readonly relSize: number;
471
615
  }
472
616
  type ListChange<T> = ListItemChanged<T> | ListItemInserted<T> | ListItemRemoved<T> | ListCleared;
473
617
  interface ListItemChanged<T> {
474
- kind: ChangeKind.Change;
618
+ kind: typeof LC_CHANGE;
475
619
  index: number;
476
620
  oldItem: T;
477
621
  newItem: T;
478
622
  }
479
623
  interface ListItemInserted<T> {
480
- kind: ChangeKind.Insert;
624
+ kind: typeof LC_INSERT;
481
625
  index: number;
482
626
  newItem: T;
483
627
  }
484
628
  interface ListItemRemoved<T> {
485
- kind: ChangeKind.Remove;
629
+ kind: typeof LC_REMOVE;
486
630
  index: number;
487
631
  oldItem: T;
488
632
  }
489
633
  interface ListCleared {
490
- kind: ChangeKind.Clear;
634
+ kind: typeof LC_CLEAR;
491
635
  index: number;
492
636
  }
493
637
  interface Equals<T> {
@@ -498,31 +642,54 @@ interface Equals<T> {
498
642
  interface ReadonlyList<T> extends Iterable<T>, DependencyList {
499
643
  /**
500
644
  * Gets the size of this List.
645
+ *
501
646
  * Reactive in effects and derivations.
502
647
  */
503
648
  size(): number;
504
649
  /**
505
650
  * Gets the item at the specified index. Return undefined when outside of the List's bounds.
651
+ *
506
652
  * Reactive in effects and derivations.
507
653
  */
508
654
  get(index: number): T | undefined;
509
655
  /**
510
- * Gets a set of changes made to this List within the current tick. Returns null when no changes
511
- * were made.
512
- * Reactive in effects and derivations.
656
+ * Gets a boolean indicating whether changes have been made to this List that have not yet been
657
+ * delivered to its observers.
658
+ *
659
+ * Non-reactive in effects and derivations.
513
660
  */
514
- delta(): ListDelta<T> | null;
661
+ dirty(): boolean;
515
662
  /**
516
- * Gets the underlying array of items. The array is read-only, mutating it will cause observers
517
- * to go out of sync.
663
+ * Registers a callback to run whenever one or more changes are made to this List. The callback
664
+ * receives a ListDelta object describing all changes made since the last notification.
665
+ *
518
666
  * Non-reactive in effects and derivations.
519
667
  */
668
+ delta(block: (delta: ListDelta<T>) => void, lifecycle?: Lifecycle): void;
669
+ /**
670
+ * Gets the underlying array of items of this List. The array is read-only, but may change when
671
+ * the List itself is mutated.
672
+ *
673
+ * Non-reactive in effects and derivations.
674
+ *
675
+ * *Mutating the array directly (e.g. in unchecked JS code) will cause any and all observers to
676
+ * go out of sync, breaking the rendered state in unpredictable ways!*
677
+ */
520
678
  raw(): readonly T[];
521
679
  /**
522
- * Runs the provided callback for each item of this List.
680
+ * Runs a block of code for each item of this List.
681
+ *
523
682
  * Reactive in effects and derivations.
524
683
  */
525
- forEach(callback: (item: T, index: number) => void, thisArg?: any): void;
684
+ forEach(block: (item: T, index: number) => void): void;
685
+ /**
686
+ * Runs a block of code with a stable, immutable snapshot of the items within this List. The
687
+ * List itself may be mutated as a result of running this code, but the provided snapshot will
688
+ * not reflect any such changes.
689
+ *
690
+ * Non-reactive in effects and derivations.
691
+ */
692
+ stable<R>(block: (snapshot: readonly T[]) => R): R;
526
693
  }
527
694
  interface List<T> extends ReadonlyList<T> {
528
695
  /**
@@ -582,36 +749,37 @@ interface List<T> extends ReadonlyList<T> {
582
749
  * Creates an empty List. This List emits deltas with each mutation which can be observed by
583
750
  * Components to efficiently update the rendered state.
584
751
  */
585
- declare function listOf<T>(): List<T>;
586
- declare function listOf<T>(source: Nil<never>, lifecycle?: Lifecycle, devId?: string): List<T>;
752
+ export declare function listOf<T>(): List<T>;
753
+ export declare function listOf<T>(source: Nil<never>, lifecycle?: Lifecycle, devId?: string): List<T>;
587
754
  /**
588
755
  * Creates a List initialized with items copied from the provided Iterable. This List emits deltas
589
756
  * with each mutation which can be observed by Components to efficiently update the rendered state.
590
757
  */
591
- declare function listOf<T>(source: Iterable<T>, lifecycle?: Lifecycle, devId?: string): List<T>;
758
+ export declare function listOf<T>(source: Iterable<T>, lifecycle?: Lifecycle, devId?: string): List<T>;
592
759
  /**
593
760
  * Synchronizes the provided List with the given data source. After this operation, the list will
594
761
  * contain an exact copy of the source.
595
762
  *
596
- * Note: This function is separated instead of being a List method since the underlying diff
597
- * algorithm (Myers) is a relatively large chunk of code which would otherwise always get included
598
- * into bundled builds. This way, tools like Terser can eliminate the extra code when unused.
763
+ * Note: This function is separated instead of being a List method as the underlying diff algorithm
764
+ * (Myers) is a relatively large chunk of code which would otherwise always get bundled into
765
+ * applications. This way, tools like Terser can easily eliminate the extra code when unused.
599
766
  */
600
- declare function sync<T>(list: List<T>, source: readonly T[], eq?: Equals<T>): void;
767
+ export declare function sync<T>(list: List<T>, source: Iterable<T>, eq?: Equals<T>): void;
601
768
  //#endregion
602
769
  //#region src/data/ProxyAtom.d.ts
603
- interface ProxyAtom<T> extends Atom<T> {
770
+ interface ProxyAtom<T> extends WriteAtom<T> {
604
771
  /**
605
772
  * Binds this ProxyAtom to a new value. If it is an Atom, the proxy will mirror it, otherwise it
606
773
  * will be a read-only atom with a static value until rebound.
774
+ * Binding a proxy to itself throws in development and is ignored in production.
607
775
  */
608
776
  use(value: MaybeAtom<T>): void;
609
777
  }
610
778
  /**
611
779
  * Creates a ProxyAtom bound to the provided initial value. If it is an Atom, the proxy will mirror
612
- * it, otherwise it will be a read-only atom with a static value until rebound.
780
+ * it, otherwise it will be a read-only atom with a static value until rebound via its `use` method.
613
781
  */
614
- declare function proxyOf<T>(initialValue: MaybeAtom<T>, lifecycle?: Lifecycle): ProxyAtom<T>;
782
+ export declare function proxyOf<T>(initialValue: MaybeAtom<T>, lifecycle?: Lifecycle): ProxyAtom<T>;
615
783
  type Proxied<T, P extends readonly (keyof T)[]> = {
616
784
  readonly proxied: T;
617
785
  } & { readonly [K in P[number]]: ProxyAtom<T[K] extends MaybeAtom<infer V> ? V : T[K]>; };
@@ -624,18 +792,18 @@ interface RemountIteratorProps<T> {
624
792
  }
625
793
  interface ProxyIteratorProps<T, P extends readonly (keyof T)[]> {
626
794
  source: ReadonlyList<T>;
627
- proxy: P;
795
+ proxy: P & ("proxied" extends P[number] ? never : unknown);
628
796
  children: [template: DataTemplate<Proxied<T, P>>];
629
797
  }
630
798
  /**
631
799
  * The built-in Iterator Component efficiently rendering collections of items
632
800
  * based on updates from a Pyxis `list`.
633
801
  */
634
- declare function Iterator<T>(props: JsxProps<RemountIteratorProps<T>>): JsxResult;
635
- declare function Iterator<T, P extends readonly (keyof T)[]>(props: JsxProps<ProxyIteratorProps<T, P>>): JsxResult;
802
+ export declare function Iterator<T>(props: JsxProps<RemountIteratorProps<T>>): JsxResult;
803
+ export declare function Iterator<T, P extends readonly (keyof T)[]>(props: JsxProps<ProxyIteratorProps<T, P>>): JsxResult;
636
804
  //#endregion
637
805
  //#region src/component/Native.d.ts
638
- declare function Native<TNode>(jsx: JsxObject, hParent: HNode<TNode>, nUsedParent: TNode, _nRealParent: TNode, nBefore: TNode | null, isBatch: boolean): void;
806
+ export declare function Native<TNode>(jsx: JsxObject, hParent: HNode<TNode>, hBefore: HNode<TNode> | null, nUsedParent: TNode, _nRealParent: TNode, isBatch: boolean): TNode;
639
807
  //#endregion
640
808
  //#region src/component/Show.d.ts
641
809
  interface ShowProps {
@@ -646,145 +814,225 @@ interface ShowDataProps<T> {
646
814
  when?: MaybeAtom<boolean>;
647
815
  proxy?: never;
648
816
  data: MaybeAtom<T>;
649
- children: [template: DataTemplate<T> | ReadAtom<Nil<DataTemplate<T>>>];
817
+ children: [template: DataTemplate<T> | Atom<Nil<DataTemplate<T>>>];
650
818
  }
651
819
  interface ShowProxyDataProps<T, P extends readonly (keyof T)[]> {
652
820
  when?: MaybeAtom<boolean>;
653
- proxy: P;
821
+ proxy: P & ("proxied" extends P[number] ? never : unknown);
654
822
  data: MaybeAtom<T>;
655
- children: [template: DataTemplate<Proxied<T, P>> | ReadAtom<Nil<DataTemplate<Proxied<T, P>>>>];
823
+ children: [template: DataTemplate<Proxied<T, P>> | Atom<Nil<DataTemplate<Proxied<T, P>>>>];
656
824
  }
657
825
  /**
658
826
  * The built-in Show Component dynamically mounting and unmounting a Template
659
827
  * based on a reactive condition result.
660
828
  */
661
- declare function Show(props: JsxProps<ShowProps>): JsxResult;
662
- declare function Show<T>(props: JsxProps<ShowDataProps<T>>): JsxResult;
663
- declare function Show<T, P extends readonly (keyof T)[]>(props: JsxProps<ShowProxyDataProps<T, P>>): JsxResult;
829
+ export declare function Show(props: JsxProps<ShowProps>): JsxResult;
830
+ export declare function Show<T>(props: JsxProps<ShowDataProps<T>>): JsxResult;
831
+ export declare function Show<T, P extends readonly (keyof T)[]>(props: JsxProps<ShowProxyDataProps<T, P>>): JsxResult;
664
832
  //#endregion
665
833
  //#region src/data/Context.d.ts
666
834
  /**
667
- * Describes a Context distributing data throughout the Component hierarchy.
668
- * @see {@link createContext}
835
+ * Describes a Context propagating data throughout the Component hierarchy.
836
+ * @see {@link contextOf}
669
837
  */
670
838
  interface Context<T> {
671
839
  /**
672
- * A fake property kept for TypeScript to properly type-check Context compatibility.
840
+ * Carries typings of the data propagated by this Context. Typed as a function to enforce
841
+ * correct variance of the generic value type.
673
842
  * @deprecated **Type only, does not exist at runtime!**
674
843
  */
675
- readonly $contract?: (value: T) => void;
844
+ readonly $contract?: (value: T) => T;
676
845
  }
677
846
  /**
678
- * Creates a typed Context that can be used to propagate observable data throughout entire component
679
- * trees without "prop drilling."
680
- * @see {@link context}
847
+ * Creates a typed Context allowing propagation of observable data throughout entire component trees
848
+ * without "prop drilling."
681
849
  */
682
- declare function createContext<T>(devId?: string): Context<T>;
683
- interface ContextAtom<T> extends Atom<T> {
684
- $dep?: Nil<Dependency>;
685
- $ancestor?: Nil<Atom<T>>;
686
- $value?: T;
687
- }
850
+ export declare function contextOf<T>(devId?: string): Context<T>;
688
851
  /**
689
- * Gets a consumer Atom for the given Context. This atom will be read-only.
852
+ * Augments the current Component to act as a host (aka provider) of the given Context. Returns a
853
+ * mutable Atom carrying the contextual value propagated to all descendant Components that consume
854
+ * the Context.
855
+ *
856
+ * When a default value is specified, it will immediately be used as the hosted value, overriding
857
+ * any value hosted by ancestors of this Component.
858
+ *
859
+ * Without a default value specified, the Context initializes as "transparent," forwarding values
860
+ * hosted by ancestors of this Component. Once the returned Atom is written into for the first time,
861
+ * it breaks this link and begins hosting the new value from that point onwards. In forwarding mode,
862
+ * if no ancestor hosts the Context, the value is not well defined and reading the Atom fails until
863
+ * at least one of the hosts define a value.
864
+ *
865
+ * Descendants of this Component are able to consume the hosted value via `contextual(context)`
866
+ * receiving a readonly Atom.
867
+ *
868
+ * Note that due to how JavaScript arguments are handled, `undefined` is always treated as no
869
+ * default provided, even if it is an allowed value of the Context. To explicitly initialize hosts
870
+ * to the literal value `undefined`, you need to write the Atom separately, e.g.:
871
+ *
872
+ * ```ts
873
+ * const MyContext = contextOf<number | undefined>();
874
+ *
875
+ * // ...then, within a component:
876
+ * const value = host(MyContext);
877
+ * write(value, undefined);
878
+ * ```
879
+ * @see {@link contextual}
880
+ */
881
+ export declare function host<C>(context: C, defaultValue?: C extends Context<infer T> ? T : never, lifecycle?: Lifecycle, devId?: string): C extends Context<infer T> ? WriteAtom<T> : never;
882
+ /**
883
+ * Gets a readonly Atom carrying the value inherited from the nearest ancestor of the current
884
+ * Component hosting the specified Context. This call fails if no ancestor is hosting the Context.
690
885
  * @see {@link host}
691
886
  */
692
- declare function consumerOf<T>(context: Context<T>): Atom<T> | null;
887
+ export declare function contextual<T>(context: Context<T>): Atom<T>;
888
+ //#endregion
889
+ //#region src/data/Derivation.d.ts
890
+ /**
891
+ * Holds a value derived from values of other Atoms, managing reactions to their changes.
892
+ * Derivations are read-only. Use the `read` function to access its value.
893
+ * @see {@link read}
894
+ */
895
+ interface Derivation<T = unknown> extends Atom<T> {}
693
896
  /**
694
- * Marks the current component as a host for the given context. Returns a mutable ContextAtom;
695
- * Values written to it will be propagated to any descendant component that consumes the context via
696
- * `consumerOf(context)`.
697
- * @see {@link consumerOf}
897
+ * Creates a Derivation - an Atom with its value computed from other Atoms. The block runs once
898
+ * eagerly to compute the initial value, then re-runs within scheduler ticks whenever its source
899
+ * Atoms change. Observers are only notified if the new value differs from the previous.
698
900
  */
699
- declare function host<C>(context: C, defaultValue?: C extends Context<infer T> ? T : never, devId?: string): C extends Context<infer T> ? ContextAtom<T> : never;
901
+ export declare function derived<T>(block: () => T, lifecycle?: Lifecycle): Derivation<T>;
700
902
  //#endregion
701
903
  //#region src/data/Effect.d.ts
702
904
  interface EffectBlock {
703
905
  (): (() => void) | void;
704
906
  }
705
- interface Effect<T> {}
706
907
  /**
707
908
  * Creates an Effect - a block of logic executed each time any of the Atoms accessed within it
708
- * change. The block is first synchronously executed when the Effect is created.
909
+ * change. The block is first synchronously executed when the Effect is created. Atoms may be
910
+ * written or even created within the block, but note that writing an Atom this Effect depends on
911
+ * may cause an infinite update loop when the state doesn't converge to a point where no more
912
+ * re-runs of this Effect are required.
709
913
  *
710
- * If a teardown callback is returned, it will be run before the next effect re-run, or on component
711
- * unmount.
914
+ * When a teardown callback is returned, it will be run before the next re-run of this Effect, or
915
+ * once the enclosing Component unmounts, whichever comes first.
712
916
  */
713
- declare function effect(block: EffectBlock, lifecycle?: Lifecycle): void;
917
+ export declare function effect(block: EffectBlock, lifecycle?: Lifecycle): void;
714
918
  /**
715
919
  * Runs a block of code removed from any effects. Accessing atoms within this block will be ignored
716
920
  * by any effect that may otherwise be observing this code.
717
921
  */
718
- declare function noEffect<T>(block: () => T): T;
719
- //#endregion
720
- //#region src/data/Derivation.d.ts
721
- /**
722
- * Holds a value derived from values of other Atoms, managing reactions to their changes.
723
- * Derivations are read-only. Use the `read` function to access its value.
724
- * @see {@link read}
725
- */
726
- interface Derivation<T = unknown> extends Atom<T>, Effect<T> {}
727
- /**
728
- * Creates a Derivation - an Atom with its value computed from other Atoms. The block runs once
729
- * eagerly to compute the initial value, then re-runs within scheduler ticks whenever its source
730
- * Atoms change. Observers are only notified if the new value differs from the previous.
731
- */
732
- declare function derived<T>(block: () => T, lifecycle?: Lifecycle): Derivation<T>;
922
+ export declare function noEffect<TArgs extends ArgsMax3, TReturn>(block: (...args: TArgs) => TReturn, ...args: TArgs): TReturn;
733
923
  //#endregion
734
924
  //#region src/extension/RefExtension.d.ts
735
- interface RefExtensionType {
736
- <TExtensionKey extends string, TElements extends ElementsType>(extensionKey: TExtensionKey, elements: TElements): { [TElementName in keyof TElements]: TElements[TElementName] & ExtensionProps<TExtensionKey, {
737
- readonly atom?: Atom<NodeType<TElements[TElementName]> | null>;
738
- readonly call?: RefFn<NodeType<TElements[TElementName]>>;
739
- }>; };
740
- set: (node: any, prop: string, value: any, group?: MountingGroup<any>) => void;
925
+ interface RefPropMapping extends ExtensionPropMapping<unknown> {
926
+ extension: RefProps<this["node"]>;
927
+ }
928
+ interface RefProps<TNode> {
929
+ readonly atom?: WriteAtom<TNode | null>;
930
+ readonly call?: RefFn<TNode>;
741
931
  }
742
932
  interface RefFn<TNode> {
743
- (node: TNode | null): void;
933
+ (node: TNode): (() => void) | void;
744
934
  }
745
935
  /**
746
- * Extension adding direct reference access to any element. Recommended prefix:
747
- * `"ref"`
936
+ * Extension adding direct reference access to any element. Recommended prefix: `"ref"`
937
+ *
938
+ * References can be stored into Atoms:
748
939
  *
749
- * References can be stored into atoms:
750
940
  * ```tsx
751
- * const wrapperRef = atomOf<HTMLDivElement>();
941
+ * const wrapperRef = atomOf<HTMLDivElement | null>(null);
752
942
  * <div ref:atom={wrapperRef} />
753
943
  * ```
754
- * or handled with a custom callback:
944
+ *
945
+ * The Atom will be set to the referenced node once it mounts. Later, when the node unmounts, the
946
+ * Atom is set back to `null`.
947
+ *
948
+ * References can also be received via callbacks:
949
+ *
755
950
  * ```tsx
756
- * const onWrapperRef = (node: HTMLDivElement) => { ... };
951
+ * const onWrapperRef = (node: HTMLDivElement) => {
952
+ * // ...
953
+ * };
954
+ *
757
955
  * <div ref:call={onWrapperRef} />
758
956
  * ```
957
+ *
958
+ * Ref callbacks are only called when the node mounts, they never receive `null`. Instead,
959
+ * unmounted nodes may be handled by returning a teardown callback.
759
960
  */
760
- declare const RefExtension: RefExtensionType;
961
+ export declare const RefExtension: Extension<any, RefPropMapping>;
761
962
  //#endregion
762
- //#region src/support/text.d.ts
963
+ //#region src/support/common.d.ts
763
964
  /**
764
- * A template literal tag that automatically wraps each substitution in a `read` call.
765
- * @see {@link read}
965
+ * Invokes a {@link Callback} passing stored arguments and forwarding its return value.
766
966
  */
767
- declare function reads(strings: TemplateStringsArray, ...values: JsxText[]): string;
967
+ export declare function invoke<TArgs extends ArgsMax3, TReturn>(callback: Callback<TArgs, TReturn>): TReturn;
968
+ //#endregion
969
+ //#region src/support/atoms.d.ts
768
970
  /**
769
- * A template literal tag that automatically wraps each substitution in a `peek` call.
770
- * @see {@link peek}
971
+ * A template string tag that creates a Derivation Atom from the tagged template. The derivation
972
+ * automatically observes any Atoms among substitutions and updates the resulting string whenever
973
+ * one or more of these Atoms change.
974
+ *
975
+ * Substitutions use String conversion; Failed conversions get replaced with `[error]`. Ideally,
976
+ * you'd want to make sure `String(yourValue)` never fails.
771
977
  */
772
- declare function peeks(strings: TemplateStringsArray, ...values: JsxText[]): string;
773
- //#endregion
774
- //#region src/Builder.d.ts
775
- interface PyxisBuilder<TNode, TIntrinsicElements extends ElementsType> {
776
- build: () => Renderer<TNode, TIntrinsicElements>;
777
- extend: <TExtensionKey extends string, TExtendedIntrinsicElements extends ElementsType>(extensionKey: TExtensionKey, extension: (extensionKey: TExtensionKey, intrinsicElements: TIntrinsicElements) => TExtendedIntrinsicElements) => PyxisBuilder<TNode, Merged<TExtendedIntrinsicElements>>;
778
- }
779
- type MergeIntersection<T> = { [K in keyof T]: T[K]; } & {};
780
- type Merged<T> = { [K in keyof T]: MergeIntersection<T[K]>; };
781
- declare function pyxis<TNode, TIntrinsicElements extends ElementsType>(adapter: Adapter<TNode, TIntrinsicElements>): PyxisBuilder<TNode, TIntrinsicElements>;
978
+ export declare function text(strings: TemplateStringsArray, ...values: unknown[]): Derivation<string>;
979
+ /**
980
+ * Creates a callback wrapping a call to the {@link write} function. Useful for decluttering inline
981
+ * event handlers in JSX templates.
982
+ * @see {@link write}
983
+ */
984
+ export declare function writes<A>(input: A, value: A extends WriteAtom<infer T> ? T : never, force?: boolean): () => void;
985
+ /**
986
+ * Creates a callback wrapping a call to the {@link update} function. Useful for decluttering inline
987
+ * event handlers in JSX templates.
988
+ * @see {@link update}
989
+ */
990
+ export declare function updates<A>(input: A, transform: A extends WriteAtom<infer T> ? (value: T) => T : never, force?: boolean): () => void;
991
+ /**
992
+ * Extracts the type of value represented by the given type, unwrapping Atoms if they're part of the
993
+ * type.
994
+ */
995
+ type ValueType<T> = T extends Atom<infer V> ? V : T;
996
+ /**
997
+ * Infers an object with its fields' values wrapped in Atoms. Optionally, if a specific TKeys union
998
+ * is provided, only select fields will be wrapped.
999
+ */
1000
+ type AtomsOf<TData extends { readonly [K in string]: any; }, TKeys extends (keyof TData & (string | number)) | undefined = undefined> = (undefined extends TKeys ? { [K in keyof TData as K extends string | number ? K : never]: undefined extends TData[K] ? MaybeWriteAtom<ValueType<TData[K]>> : WriteAtom<ValueType<TData[K]>>; } : Flatten<({ [K in TKeys & keyof TData & (string | number)]-?: WriteAtom<ValueType<TData[K]>>; } & Omit<Pick<TData, keyof TData & (string | number)>, TKeys & keyof TData>)>);
1001
+ /**
1002
+ * Creates a new data object mapped from the one provided, with its fields' values wrapped in
1003
+ * mutable Atoms. Optionally, a tuple of keys can be given to only wrap the select fields, copying
1004
+ * others as-is.
1005
+ */
1006
+ export declare function atomsOf<TData extends { readonly [K in string]: any; }>(data: TData, lifecycle?: Lifecycle): AtomsOf<TData>;
1007
+ export declare function atomsOf<TData extends { readonly [K in string]: any; }, const TKeys extends readonly (keyof TData & (string | number))[]>(data: TData, keys: TKeys & (number extends TKeys["length"] ? never : unknown), lifecycle?: Lifecycle): AtomsOf<TData, TKeys[number]>;
1008
+ /**
1009
+ * Assigns values taken from the provided data object to the store (typically previously created
1010
+ * via {@link atomsOf}). Optionally, a tuple of keys can be given to treat select fields as
1011
+ * guaranteed Atoms while copying others as-is. Typically, you'd pass the same keys tuple to both
1012
+ * `atomsOf` and later `assign` calls.
1013
+ */
1014
+ export declare function assign<TData extends { readonly [K in string]: any; }, TStore extends AtomsOf<TData>>(store: TStore, data: TData, lifecycle?: Lifecycle): TStore;
1015
+ export declare function assign<TData extends { readonly [K in string]: any; }, const TKeys extends readonly (keyof TData & (string | number))[], TStore extends AtomsOf<TData, TKeys[number]>>(store: TStore, data: TData, keys: TKeys & (number extends TKeys["length"] ? never : unknown), lifecycle?: Lifecycle): TStore;
782
1016
  //#endregion
783
1017
  //#region src/jsx.d.ts
784
- declare function jsx(tagName: string, props: PropsType, key?: any): JsxResult;
785
- declare function jsx<TProps extends PropsType>(component: Component<TProps>, props: TProps, key?: any): JsxResult;
786
- declare function jsxs(tagName: string, props: PropsType, key?: any): JsxResult;
787
- declare function jsxs<TProps extends PropsType>(component: Component<TProps>, props: TProps, key?: any): JsxResult;
1018
+ export declare function jsx(tagName: string, props: PropsType, key?: any): JsxResult;
1019
+ export declare function jsx<TProps extends PropsType>(component: Component<TProps>, props: TProps, key?: any): JsxResult;
1020
+ export declare function jsxs(tagName: string, props: PropsType, key?: any): JsxResult;
1021
+ export declare function jsxs<TProps extends PropsType>(component: Component<TProps>, props: TProps, key?: any): JsxResult;
1022
+ //#endregion
1023
+ //#region src/RendererBuilder.d.ts
1024
+ interface RendererBuilder<TNode, TElements extends ElementsType, TUsedPrefixes extends string = never> {
1025
+ create: () => Renderer<TNode, TElements>;
1026
+ extend: <TPrefix extends string, TExtension extends Extension<TNode>>(prefix: TPrefix & (TPrefix extends TUsedPrefixes ? never : unknown), extension: TExtension) => RendererBuilder<TNode, ExtendedElements<TNode, TElements, TExtension, TPrefix>, TUsedPrefixes | TPrefix>;
1027
+ }
1028
+ type ExtendedElements<TNode, TElements extends ElementsType, TExtension extends Extension<TNode>, TPrefix extends string> = (TExtension extends {
1029
+ readonly $mapping?: infer TMapping extends ExtensionPropMapping<unknown>;
1030
+ } ? { [TElementName in keyof TElements]: ((TMapping & {
1031
+ node: NodeType<TElements[TElementName]>;
1032
+ name: TElementName;
1033
+ })["extension"] extends (infer TExtensionProps extends PropsType) ? [keyof TExtensionProps] extends [never] ? TElements[TElementName] : Flatten<TElements[TElementName] & PrefixedProps<TExtensionProps, TPrefix>> : TElements[TElementName]); } : TElements);
1034
+ type PrefixedProps<TProps extends PropsType, TPrefix extends string> = { readonly [TPrefixed in `${TPrefix}:${keyof TProps & string}`]?: (TPrefixed extends `${TPrefix}:${infer TName extends (keyof TProps & string)}` ? TProps[TName] : never); };
1035
+ export declare function renderer<TNode, TElements extends ElementsType>(adapter: Adapter<TNode, TElements>): RendererBuilder<TNode, TElements, never>;
788
1036
  //#endregion
789
- export { type Adapter, type Atom, ChangeKind, type Component, type Context, type DataTemplate, type Derivation, type EffectBlock, type ElementsOf, type ElementsType, type Equals, type Extension, type ExtensionProps, type ExtensionsType, Fragment, type FragmentProps, type HNode, Iterator, type JsxChildren, type JsxChildrenProp, type JsxObject, type JsxProps, type JsxResult, type JsxText, type Lifecycle, type List, type ListChange, type ListCleared, type ListDelta, type ListItemChanged, type ListItemInserted, type ListItemRemoved, type MaybeAtom, type MaybeReadAtom, type MountBlock, type MountingGroup, Native, type Nil, type NodeType, type PropsOf, type PropsType, type Proxied, type ProxyAtom, type ProxyIteratorProps, type PyxisBuilder, type ReadAtom, type ReadonlyList, RefExtension, type RefExtensionType, type RefFn, type RemountIteratorProps, type Renderer, type S_ATOM, type S_NODE_TYPE, Show, type ShowProps, type TickFn, type UnmountBlock, type WithChildren, atomOf, bind, component, consumerOf, createContext, derived, effect, fork, getLifecycle, host, insert, isAtom, jsx, jsxs, listOf, mount, mountJsx, mounted, noEffect, peek, peeks, proxyOf, pyxis, read, reads, sync, tick, tock, track, unmount, unmounted, untrack, update, withLifecycle, write };
1037
+ export type { Adapter, ArgsMax3, Atom, AtomsOf, Callback, Component, ComponentHandler, Context, DataTemplate, Dependency, DependencyList, Derivation, EffectBlock, ElemName, ElementsOf, ElementsType, Equals, Extension, ExtensionPropMapping, ExtensionsType, Flatten, FragmentProps, HNode, JsxChildren, JsxChildrenProp, JsxDevSourceInfo, JsxObject, JsxProps, JsxResult, JsxText, Lifecycle, List, ListChange, ListCleared, ListDelta, ListItemChanged, ListItemInserted, ListItemRemoved, MaybeAtom, MaybeWriteAtom, MountBlock, MountingGroup, Nil, NodeType, PropsOf, PropsType, Proxied, ProxyAtom, ProxyIteratorProps, ReadonlyList, RefFn, RemountIteratorProps, Renderer, RendererBuilder, S_ELEM_NAME, S_NODE_TYPE, ShowDataProps, ShowProps, ShowProxyDataProps, TickFn, UnmountBlock, ValueType, WithChildren, WriteAtom };
790
1038
  //# sourceMappingURL=core-dev.d.ts.map