@b9g/crank 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/crank.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CustomEventTarget } from "./event-target.js";
1
2
  /**
2
3
  * A type which represents all valid values for an element tag.
3
4
  */
@@ -9,11 +10,41 @@ export type Tag = string | symbol | Component;
9
10
  * or a component function.
10
11
  */
11
12
  export type TagProps<TTag extends Tag> = TTag extends string ? JSX.IntrinsicElements[TTag] : TTag extends Component<infer TProps> ? TProps & JSX.IntrinsicAttributes : Record<string, unknown> & JSX.IntrinsicAttributes;
12
- /***
13
- * SPECIAL TAGS
13
+ /**
14
+ * Describes all valid values of an element tree, excluding iterables.
15
+ *
16
+ * Arbitrary objects can also be safely rendered, but will be converted to a
17
+ * string using the toString() method. We exclude them from this type to catch
18
+ * potential mistakes.
19
+ */
20
+ export type Child = Element | string | number | boolean | null | undefined;
21
+ /**
22
+ * An arbitrarily nested iterable of Child values.
23
+ *
24
+ * We use a recursive interface here rather than making the Children type
25
+ * directly recursive because recursive type aliases were added in TypeScript
26
+ * 3.7.
27
+ *
28
+ * You should avoid referencing this type directly, as it is mainly exported to
29
+ * prevent TypeScript errors.
30
+ */
31
+ export interface ChildIterable extends Iterable<Child | ChildIterable> {
32
+ }
33
+ /**
34
+ * Describes all valid values for an element tree, including arbitrarily nested
35
+ * iterables of such values.
14
36
  *
15
- * Crank provides a couple tags which have special meaning for the renderer.
16
- ***/
37
+ * This type can be used to represent the type of the children prop for an
38
+ * element or the return/yield type of a component.
39
+ */
40
+ export type Children = Child | ChildIterable;
41
+ /**
42
+ * Represents all functions which can be used as a component.
43
+ *
44
+ * @template [TProps=*] - The expected props for the component.
45
+ */
46
+ export type Component<TProps extends Record<string, unknown> = any> = (this: Context<TProps>, props: TProps, ctx: Context<TProps>) => Children | PromiseLike<Children> | Iterator<Children, Children | void, any> | AsyncIterator<Children, Children | void, any>;
47
+ /*** SPECIAL TAGS ***/
17
48
  /**
18
49
  * A special tag for grouping multiple children within the same parent.
19
50
  *
@@ -32,64 +63,39 @@ export type Fragment = typeof Fragment;
32
63
  * This tag is useful for creating element trees with multiple roots, for
33
64
  * things like modals or tooltips.
34
65
  *
35
- * Renderer.prototype.render() will implicitly wrap top-level element trees in
36
- * a Portal element.
66
+ * Renderer.prototype.render() implicitly wraps top-level in a Portal element
67
+ * with the root set to the second argument passed in.
37
68
  */
38
- export declare const Portal: any;
69
+ export declare const Portal: Component<{
70
+ root?: object;
71
+ }> & symbol;
39
72
  export type Portal = typeof Portal;
40
73
  /**
41
74
  * A special tag which preserves whatever was previously rendered in the
42
- * elements position.
75
+ * element's position.
43
76
  *
44
77
  * Copy elements are useful for when you want to prevent a subtree from
45
78
  * rerendering as a performance optimization. Copy elements can also be keyed,
46
79
  * in which case the previously rendered keyed element will be copied.
47
80
  */
48
- export declare const Copy: any;
81
+ export declare const Copy: Component<{}> & symbol;
49
82
  export type Copy = typeof Copy;
50
83
  /**
51
- * A special tag for injecting raw nodes or strings via a value prop.
84
+ * A special tag for rendering text nodes.
52
85
  *
53
- * Renderer.prototype.raw() is called with the value prop.
86
+ * Strings in the element tree are implicitly wrapped in a Text element with
87
+ * value set to the string.
54
88
  */
55
- export declare const Raw: any;
89
+ export declare const Text: Component<{
90
+ value: string;
91
+ }> & symbol;
92
+ export type Text = typeof Text;
93
+ /** A special tag for injecting raw nodes or strings via a value prop. */
94
+ export declare const Raw: Component<{
95
+ value: string | object;
96
+ }> & symbol;
56
97
  export type Raw = typeof Raw;
57
- /**
58
- * Describes all valid values of an element tree, excluding iterables.
59
- *
60
- * Arbitrary objects can also be safely rendered, but will be converted to a
61
- * string using the toString() method. We exclude them from this type to catch
62
- * potential mistakes.
63
- */
64
- export type Child = Element | string | number | boolean | null | undefined;
65
- /**
66
- * An arbitrarily nested iterable of Child values.
67
- *
68
- * We use a recursive interface here rather than making the Children type
69
- * directly recursive because recursive type aliases were added in TypeScript
70
- * 3.7.
71
- *
72
- * You should avoid referencing this type directly, as it is mainly exported to
73
- * prevent TypeScript errors.
74
- */
75
- export interface ChildIterable extends Iterable<Child | ChildIterable> {
76
- }
77
- /**
78
- * Describes all valid values of an element tree, including arbitrarily nested
79
- * iterables of such values.
80
- */
81
- export type Children = Child | ChildIterable;
82
- /**
83
- * Represents all functions which can be used as a component.
84
- *
85
- * @template [TProps=*] - The expected props for the component.
86
- */
87
- export type Component<TProps extends Record<string, unknown> = any> = (this: Context<TProps>, props: TProps, ctx: Context<TProps>) => Children | PromiseLike<Children> | Iterator<Children, Children | void, any> | AsyncIterator<Children, Children | void, any>;
88
- /**
89
- * A type to keep track of keys. Any value can be a key, though null and
90
- * undefined are ignored.
91
- */
92
- type Key = unknown;
98
+ type ChildrenIteratorResult = IteratorResult<Children, Children | void>;
93
99
  declare const ElementSymbol: unique symbol;
94
100
  export interface Element<TTag extends Tag = Tag> {
95
101
  /**
@@ -134,9 +140,6 @@ export interface Element<TTag extends Tag = Tag> {
134
140
  */
135
141
  export declare class Element<TTag extends Tag = Tag> {
136
142
  constructor(tag: TTag, props: TagProps<TTag>);
137
- get key(): Key;
138
- get ref(): unknown;
139
- get copy(): boolean;
140
143
  }
141
144
  export declare function isElement(value: any): value is Element;
142
145
  /**
@@ -144,7 +147,7 @@ export declare function isElement(value: any): value is Element;
144
147
  *
145
148
  * This function is usually used as a transpilation target for JSX transpilers,
146
149
  * but it can also be called directly. It additionally extracts special props so
147
- * they arent accessible to renderer methods or components, and assigns the
150
+ * they aren't accessible to renderer methods or components, and assigns the
148
151
  * children prop according to any additional arguments passed to the function.
149
152
  */
150
153
  export declare function createElement<TTag extends Tag>(tag: TTag, props?: TagProps<TTag> | null | undefined, ...children: Array<unknown>): Element<TTag>;
@@ -153,155 +156,386 @@ export declare function cloneElement<TTag extends Tag>(el: Element<TTag>): Eleme
153
156
  /**
154
157
  * A helper type which repesents all possible rendered values of an element.
155
158
  *
156
- * @template TNode - The node type for the element provided by the renderer.
159
+ * @template TNode - The type of node produced by the associated renderer.
157
160
  *
158
161
  * When asking the question, what is the "value" of a specific element, the
159
162
  * answer varies depending on the tag:
160
163
  *
161
- * For host elements, the value is the nodes created for the element, e.g. the
162
- * DOM node in the case of the DOMRenderer.
163
- *
164
- * For fragments, the value is the value of the
164
+ * For intrinsic elements, the value is the node created for the element, e.g.
165
+ * the DOM node in the case of the DOMRenderer.
165
166
  *
166
- * For portals, the value is undefined, because a Portal elements root and
167
+ * For portals, the value is undefined, because a Portal element's root and
167
168
  * children are opaque to its parent.
168
169
  *
169
- * For components, the value can be any of the above, because the value of a
170
- * component is determined by its immediate children.
171
- *
172
- * Rendered values can also be strings or arrays of nodes and strings, in the
173
- * case of component or fragment elements with strings or multiple children.
174
- *
175
- * All of these possible values are reflected in this utility type.
170
+ * For component or fragment elements the value can be a node or an array of
171
+ * nodes, depending on how many children they have.
176
172
  */
177
- export type ElementValue<TNode> = Array<TNode | string> | TNode | string | undefined;
173
+ export type ElementValue<TNode> = Array<TNode> | TNode | undefined;
178
174
  /**
179
175
  * @internal
180
- * The internal nodes which are cached and diffed against new elements when
181
- * rendering element trees.
176
+ * Retainers are objects which act as the internal representation of elements,
177
+ * mirroring the element tree.
178
+ */
179
+ declare class Retainer<TNode, TScope = unknown> {
180
+ /** A bitmask. See RETAINER FLAGS above. */
181
+ f: number;
182
+ el: Element;
183
+ ctx: ContextState<TNode, TScope, any> | undefined;
184
+ children: Array<Retainer<TNode, TScope> | undefined> | Retainer<TNode, TScope> | undefined;
185
+ fallback: Retainer<TNode, TScope> | undefined;
186
+ value: ElementValue<TNode> | undefined;
187
+ scope: TScope | undefined;
188
+ oldProps: Record<string, any> | undefined;
189
+ pendingDiff: Promise<undefined> | undefined;
190
+ onNextDiff: Function | undefined;
191
+ graveyard: Array<Retainer<TNode, TScope>> | undefined;
192
+ lingerers: Array<Set<Retainer<TNode, TScope>> | undefined> | undefined;
193
+ constructor(el: Element);
194
+ }
195
+ /**
196
+ * Interface for adapting the rendering process to a specific target environment.
197
+ *
198
+ * The RenderAdapter defines how Crank elements are mapped to nodes in your target
199
+ * rendering environment (DOM, Canvas, WebGL, Terminal, etc.). Each method handles
200
+ * a specific part of the element lifecycle, from creation to removal.
201
+ *
202
+ * @template TNode - The type representing a node in your target environment
203
+ * @template TScope - Additional context data passed down the component tree
204
+ * @template TRoot - The type of the root container (defaults to TNode)
205
+ * @template TResult - The type returned when reading element values (defaults to ElementValue<TNode>)
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const adapter: RenderAdapter<MyNode, MyScope> = {
210
+ * create: ({ tag, props }) => new MyNode(tag, props),
211
+ * patch: ({ node, props }) => node.update(props),
212
+ * arrange: ({ node, children }) => node.replaceChildren(children),
213
+ * // ... other methods
214
+ * };
215
+ * ```
182
216
  */
183
- declare class Retainer<TNode> {
217
+ export interface RenderAdapter<TNode, TScope, TRoot extends TNode | undefined = TNode, TResult = ElementValue<TNode>> {
184
218
  /**
185
- * The element associated with this retainer.
219
+ * Creates a new node for the given element tag and props.
220
+ *
221
+ * This method is called when Crank encounters a new element that needs to be
222
+ * rendered for the first time. You should create and return a node appropriate
223
+ * for your target environment.
224
+ *
225
+ * @param data.tag - The element tag (e.g., "div", "sprite", or a symbol)
226
+ * @param data.tagName - String representation of the tag for debugging
227
+ * @param data.props - The element's props object
228
+ * @param data.scope - Current scope context (can be undefined)
229
+ * @returns A new node instance
230
+ *
231
+ * @example
232
+ * ```typescript
233
+ * create: ({ tag, props, scope }) => {
234
+ * if (tag === "sprite") {
235
+ * return new PIXI.Sprite(props.texture);
236
+ * }
237
+ * throw new Error(`Unknown tag: ${tag}`);
238
+ * }
239
+ * ```
186
240
  */
187
- el: Element;
241
+ create(data: {
242
+ tag: string | symbol;
243
+ tagName: string;
244
+ props: Record<string, any>;
245
+ scope: TScope | undefined;
246
+ }): TNode;
188
247
  /**
189
- * The context associated with this element. Will only be defined for
190
- * component elements.
248
+ * Adopts existing nodes during hydration.
249
+ *
250
+ * Called when hydrating server-rendered content or reusing existing nodes.
251
+ * Should return an array of child nodes if the provided node matches the
252
+ * expected tag, or undefined if hydration should fail.
253
+ *
254
+ * @param data.tag - The element tag being hydrated
255
+ * @param data.tagName - String representation of the tag
256
+ * @param data.props - The element's props
257
+ * @param data.node - The existing node to potentially adopt
258
+ * @param data.scope - Current scope context
259
+ * @returns Array of child nodes to hydrate, or undefined if adoption fails
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * adopt: ({ tag, node }) => {
264
+ * if (node && node.tagName.toLowerCase() === tag) {
265
+ * return Array.from(node.children);
266
+ * }
267
+ * return undefined; // Hydration mismatch
268
+ * }
269
+ * ```
191
270
  */
192
- ctx: ContextImpl<TNode> | undefined;
271
+ adopt(data: {
272
+ tag: string | symbol;
273
+ tagName: string;
274
+ props: Record<string, any>;
275
+ node: TNode | undefined;
276
+ scope: TScope | undefined;
277
+ }): Array<TNode> | undefined;
193
278
  /**
194
- * The retainer children of this element. Retainers form a tree which mirrors
195
- * elements. Can be a single child or undefined as a memory optimization.
279
+ * Creates or updates a text node.
280
+ *
281
+ * Called when rendering text content. Should create a new text node or
282
+ * update an existing one with the provided value.
283
+ *
284
+ * @param data.value - The text content to render
285
+ * @param data.scope - Current scope context
286
+ * @param data.oldNode - Previous text node to potentially reuse
287
+ * @param data.hydrationNodes - Nodes available during hydration
288
+ * @returns A text node containing the given value
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * text: ({ value, oldNode }) => {
293
+ * if (oldNode && oldNode.text !== value) {
294
+ * oldNode.text = value;
295
+ * return oldNode;
296
+ * }
297
+ * return new TextNode(value);
298
+ * }
299
+ * ```
196
300
  */
197
- children: Array<RetainerChild<TNode>> | RetainerChild<TNode>;
301
+ text(data: {
302
+ value: string;
303
+ scope: TScope | undefined;
304
+ oldNode: TNode | undefined;
305
+ hydrationNodes: Array<TNode> | undefined;
306
+ }): TNode;
198
307
  /**
199
- * The value associated with this element.
308
+ * Computes scope context for child elements.
309
+ *
310
+ * Called to determine what scope context should be passed to child elements.
311
+ * The scope can be used to pass rendering context like theme, coordinate systems,
312
+ * or namespaces down the component tree.
313
+ *
314
+ * @param data.tag - The element tag
315
+ * @param data.tagName - String representation of the tag
316
+ * @param data.props - The element's props
317
+ * @param data.scope - Current scope context
318
+ * @returns New scope for children, or undefined to inherit current scope
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * scope: ({ tag, props, scope }) => {
323
+ * if (tag === "svg") {
324
+ * return { ...scope, namespace: "http://www.w3.org/2000/svg" };
325
+ * }
326
+ * return scope;
327
+ * }
328
+ * ```
200
329
  */
201
- value: ElementValue<TNode>;
330
+ scope(data: {
331
+ tag: string | symbol;
332
+ tagName: string;
333
+ props: Record<string, any>;
334
+ scope: TScope | undefined;
335
+ }): TScope | undefined;
202
336
  /**
203
- * The cached child values of this element. Only host and component elements
204
- * will use this property.
337
+ * Handles raw values (strings or nodes) that bypass normal element processing.
338
+ *
339
+ * Called when rendering Raw elements or other direct node insertions.
340
+ * Should convert string values to appropriate nodes for your environment.
341
+ *
342
+ * @param data.value - Raw string or node value to render
343
+ * @param data.scope - Current scope context
344
+ * @param data.hydrationNodes - Nodes available during hydration
345
+ * @returns ElementValue that can be handled by arrange()
346
+ *
347
+ * @example
348
+ * ```typescript
349
+ * raw: ({ value, scope }) => {
350
+ * if (typeof value === "string") {
351
+ * const container = new Container();
352
+ * container.innerHTML = value;
353
+ * return Array.from(container.children);
354
+ * }
355
+ * return value;
356
+ * }
357
+ * ```
205
358
  */
206
- cachedChildValues: ElementValue<TNode>;
359
+ raw(data: {
360
+ value: string | TNode;
361
+ scope: TScope | undefined;
362
+ hydrationNodes: Array<TNode> | undefined;
363
+ }): ElementValue<TNode>;
207
364
  /**
208
- * The child which this retainer replaces. This property is used when an
209
- * async retainer tree replaces previously rendered elements, so that the
210
- * previously rendered elements can remain visible until the async tree
211
- * fulfills. Will be set to undefined once this subtree fully renders.
365
+ * Updates a node's properties.
366
+ *
367
+ * Called when element props change. Should efficiently update only the
368
+ * properties that have changed. This is where you implement prop-to-attribute
369
+ * mapping, event listener binding, and other property synchronization.
370
+ *
371
+ * @param data.tag - The element tag
372
+ * @param data.tagName - String representation of the tag
373
+ * @param data.node - The node to update
374
+ * @param data.props - New props object
375
+ * @param data.oldProps - Previous props object (undefined for initial render)
376
+ * @param data.scope - Current scope context
377
+ * @param data.copyProps - Props to skip (used for copying between renderers)
378
+ * @param data.isHydrating - Whether currently hydrating
379
+ * @param data.quietProps - Props to not warn about during hydration
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * patch: ({ node, props, oldProps }) => {
384
+ * for (const [key, value] of Object.entries(props)) {
385
+ * if (oldProps?.[key] !== value) {
386
+ * if (key.startsWith("on")) {
387
+ * node.addEventListener(key.slice(2), value);
388
+ * } else {
389
+ * node[key] = value;
390
+ * }
391
+ * }
392
+ * }
393
+ * }
394
+ * ```
212
395
  */
213
- fallbackValue: RetainerChild<TNode>;
214
- inflightValue: Promise<ElementValue<TNode>> | undefined;
215
- onNextValues: Function | undefined;
216
- constructor(el: Element);
217
- }
218
- /**
219
- * The retainer equivalent of ElementValue
220
- */
221
- type RetainerChild<TNode> = Retainer<TNode> | string | undefined;
222
- export interface HydrationData<TNode> {
223
- props: Record<string, unknown>;
224
- children: Array<TNode | string>;
225
- }
226
- export interface RendererImpl<TNode, TScope, TRoot extends TNode = TNode, TResult = ElementValue<TNode>> {
227
- scope<TTag extends string | symbol>(scope: TScope | undefined, tag: TTag, props: TagProps<TTag>): TScope | undefined;
228
- create<TTag extends string | symbol>(tag: TTag, props: TagProps<TTag>, scope: TScope | undefined): TNode;
229
- hydrate<TTag extends string | symbol>(tag: TTag, node: TNode | TRoot, props: TagProps<TTag>): HydrationData<TNode> | undefined;
396
+ patch(data: {
397
+ tag: string | symbol;
398
+ tagName: string;
399
+ node: TNode;
400
+ props: Record<string, any>;
401
+ oldProps: Record<string, any> | undefined;
402
+ scope: TScope | undefined;
403
+ copyProps: Set<string> | undefined;
404
+ isHydrating: boolean;
405
+ quietProps: Set<string> | undefined;
406
+ }): void;
230
407
  /**
231
- * Called when an element’s rendered value is exposed via render, schedule,
232
- * refresh, refs, or generator yield expressions.
408
+ * Arranges child nodes within their parent.
233
409
  *
234
- * @param value - The value of the element being read. Can be a node, a
235
- * string, undefined, or an array of nodes and strings, depending on the
236
- * element.
410
+ * Called after child elements are rendered to organize them within their
411
+ * parent node. Should efficiently insert, move, or remove child nodes to
412
+ * match the provided children array.
237
413
  *
238
- * @returns Varies according to the specific renderer subclass. By default,
239
- * it exposes the element’s value.
414
+ * @param data.tag - The parent element tag
415
+ * @param data.tagName - String representation of the tag
416
+ * @param data.node - The parent node
417
+ * @param data.props - The parent element's props
418
+ * @param data.children - Array of child nodes in correct order
419
+ * @param data.oldProps - Previous props (for reference)
240
420
  *
241
- * This is useful for renderers which don’t want to expose their internal
242
- * nodes. For instance, the HTML renderer will convert all internal nodes to
243
- * strings.
421
+ * @example
422
+ * ```typescript
423
+ * arrange: ({ node, children }) => {
424
+ * // Remove existing children
425
+ * node.removeChildren();
426
+ * // Add new children in order
427
+ * for (const child of children) {
428
+ * node.addChild(child);
429
+ * }
430
+ * }
431
+ * ```
244
432
  */
245
- read(value: ElementValue<TNode>): TResult;
433
+ arrange(data: {
434
+ tag: string | symbol;
435
+ tagName: string;
436
+ node: TNode;
437
+ props: Record<string, any>;
438
+ children: Array<TNode>;
439
+ oldProps: Record<string, any> | undefined;
440
+ }): void;
246
441
  /**
247
- * Called for each string in an element tree.
442
+ * Removes a node from its parent.
248
443
  *
249
- * @param text - The string child.
250
- * @param scope - The current scope.
444
+ * Called when an element is being unmounted. Should clean up the node
445
+ * and remove it from its parent if appropriate.
251
446
  *
252
- * @returns A string to be passed to arrange.
447
+ * @param data.node - The node to remove
448
+ * @param data.parentNode - The parent node
449
+ * @param data.isNested - Whether this is a nested removal (child of removed element)
253
450
  *
254
- * Rather than returning Text nodes as we would in the DOM case, for example,
255
- * we delay that step for Renderer.prototype.arrange. We do this so that
256
- * adjacent strings can be concatenated, and the actual element tree can be
257
- * rendered in normalized form.
451
+ * @example
452
+ * ```typescript
453
+ * remove: ({ node, parentNode, isNested }) => {
454
+ * // Clean up event listeners, resources, etc.
455
+ * node.cleanup?.();
456
+ * // Remove from parent unless it's a nested removal
457
+ * if (!isNested && parentNode.contains(node)) {
458
+ * parentNode.removeChild(node);
459
+ * }
460
+ * }
461
+ * ```
258
462
  */
259
- text(text: string, scope: TScope | undefined, hydration: HydrationData<TNode> | undefined): string;
463
+ remove(data: {
464
+ node: TNode;
465
+ parentNode: TNode;
466
+ isNested: boolean;
467
+ }): void;
260
468
  /**
261
- * Called for each Raw element whose value prop is a string.
469
+ * Reads the final rendered value from an ElementValue.
262
470
  *
263
- * @param text - The string child.
264
- * @param scope - The current scope.
471
+ * Called to extract the final result from rendered elements. This allows
472
+ * you to transform the internal node representation into the public API
473
+ * that users of your renderer will see.
265
474
  *
266
- * @returns The parsed node or string.
475
+ * @param value - The ElementValue to read (array, single node, or undefined)
476
+ * @returns The public representation of the rendered value
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * read: (value) => {
481
+ * if (Array.isArray(value)) {
482
+ * return value.map(node => node.publicAPI);
483
+ * }
484
+ * return value?.publicAPI;
485
+ * }
486
+ * ```
267
487
  */
268
- raw(value: string | TNode, scope: TScope | undefined, hydration: HydrationData<TNode> | undefined): ElementValue<TNode>;
269
- patch<TTag extends string | symbol, TName extends string>(tag: TTag, node: TNode, name: TName, value: unknown, oldValue: unknown, scope: TScope): unknown;
270
- arrange<TTag extends string | symbol>(tag: TTag, node: TNode, props: Record<string, unknown>, children: Array<TNode | string>, oldProps: Record<string, unknown> | undefined, oldChildren: Array<TNode | string> | undefined): unknown;
271
- dispose<TTag extends string | symbol>(tag: TTag, node: TNode, props: Record<string, unknown>): unknown;
272
- flush(root: TRoot): unknown;
488
+ read(value: ElementValue<TNode>): TResult;
489
+ /**
490
+ * Performs final rendering to the root container.
491
+ *
492
+ * Called after the entire render cycle is complete. This is where you
493
+ * trigger the actual rendering/presentation in your target environment
494
+ * (e.g., calling render() on a canvas, flushing to the screen, etc.).
495
+ *
496
+ * @param root - The root container
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * finalize: (root) => {
501
+ * // Trigger actual rendering
502
+ * if (root instanceof PIXIApplication) {
503
+ * root.render();
504
+ * }
505
+ * }
506
+ * ```
507
+ */
508
+ finalize(root: TRoot): void;
273
509
  }
274
- declare const _RendererImpl: unique symbol;
275
510
  /**
276
511
  * An abstract class which is subclassed to render to different target
277
- * environments. Subclasses will typically call super() with a custom
278
- * RendererImpl. This class is responsible for kicking off the rendering
279
- * process and caching previous trees by root.
512
+ * environments. Subclasses call super() with a custom RenderAdapter object.
513
+ * This class is responsible for kicking off the rendering process and caching
514
+ * previous trees by root.
280
515
  *
281
516
  * @template TNode - The type of the node for a rendering environment.
282
517
  * @template TScope - Data which is passed down the tree.
283
518
  * @template TRoot - The type of the root for a rendering environment.
284
519
  * @template TResult - The type of exposed values.
285
520
  */
286
- export declare class Renderer<TNode extends object = object, TScope = unknown, TRoot extends TNode = TNode, TResult = ElementValue<TNode>> {
521
+ export declare class Renderer<TNode extends object, TScope, TRoot extends TNode | undefined = TNode, TResult = ElementValue<TNode>> {
287
522
  /**
288
523
  * @internal
289
524
  * A weakmap which stores element trees by root.
290
525
  */
291
- cache: WeakMap<object, Retainer<TNode>>;
292
- [_RendererImpl]: RendererImpl<TNode, TScope, TRoot, TResult>;
293
- constructor(impl: Partial<RendererImpl<TNode, TScope, TRoot, TResult>>);
526
+ cache: WeakMap<object, Retainer<TNode, TScope>>;
527
+ adapter: RenderAdapter<TNode, TScope, TRoot, TResult>;
528
+ constructor(adapter: Partial<RenderAdapter<TNode, TScope, TRoot, TResult>>);
294
529
  /**
295
530
  * Renders an element tree into a specific root.
296
531
  *
297
- * @param children - An element tree. You can render null with a previously
298
- * used root to delete the previously rendered element tree from the cache.
299
- * @param root - The node to be rendered into. The renderer will cache
300
- * element trees per root.
301
- * @param bridge - An optional context that will be the ancestor context of all
302
- * elements in the tree. Useful for connecting different renderers so that
303
- * events/provisions properly propagate. The context for a given root must be
304
- * the same or an error will be thrown.
532
+ * @param children - An element tree. Rendering null deletes cached renders.
533
+ * @param root - The root to be rendered into. The renderer caches renders
534
+ * per root.
535
+ * @param bridge - An optional context that will be the ancestor context of
536
+ * all elements in the tree. Useful for connecting different renderers so
537
+ * that events/provisions/errors properly propagate. The context for a given
538
+ * root must be the same between renders.
305
539
  *
306
540
  * @returns The result of rendering the children, or a possible promise of
307
541
  * the result if the element tree renders asynchronously.
@@ -309,65 +543,65 @@ export declare class Renderer<TNode extends object = object, TScope = unknown, T
309
543
  render(children: Children, root?: TRoot | undefined, bridge?: Context | undefined): Promise<TResult> | TResult;
310
544
  hydrate(children: Children, root: TRoot, bridge?: Context | undefined): Promise<TResult> | TResult;
311
545
  }
312
- export interface Context extends Crank.Context {
546
+ interface PullController {
547
+ iterationP: Promise<ChildrenIteratorResult> | undefined;
548
+ diff: Promise<undefined> | undefined;
549
+ onChildError: ((err: unknown) => void) | undefined;
313
550
  }
314
- /**
315
- * An interface which can be extended to provide strongly typed provisions.
316
- * See Context.prototype.consume and Context.prototype.provide.
317
- */
318
- export interface ProvisionMap extends Crank.ProvisionMap {
551
+ interface ScheduleController {
552
+ promise: Promise<unknown>;
553
+ onAbort: () => void;
319
554
  }
320
555
  /**
321
556
  * @internal
322
557
  * The internal class which holds context data.
323
558
  */
324
- declare class ContextImpl<TNode = unknown, TScope = unknown, TRoot extends TNode = TNode, TResult = unknown> {
325
- /** A bitmask. See CONTEXT FLAGS above. */
326
- f: number;
327
- /** The actual context associated with this impl. */
328
- owner: Context<unknown, TResult>;
329
- /**
330
- * The renderer which created this context.
331
- */
332
- renderer: RendererImpl<TNode, TScope, TRoot, TResult>;
559
+ declare class ContextState<TNode = unknown, TScope = unknown, TRoot extends TNode | undefined = TNode | undefined, TResult = unknown> {
560
+ /** The adapter of the renderer which created this context. */
561
+ adapter: RenderAdapter<TNode, TScope, TRoot, TResult>;
333
562
  /** The root node as set by the nearest ancestor portal. */
334
563
  root: TRoot | undefined;
335
564
  /**
336
565
  * The nearest ancestor host or portal retainer.
337
566
  *
338
567
  * When refresh is called, the host element will be arranged as the last step
339
- * of the commit, to make sure the parents children properly reflects the
340
- * componentss children.
568
+ * of the commit, to make sure the parent's children properly reflects the
569
+ * components's childrenk
341
570
  */
342
571
  host: Retainer<TNode>;
343
- /** The parent context impl. */
344
- parent: ContextImpl<TNode, TScope, TRoot, TResult> | undefined;
345
- /** The value of the scope at the point of element’s creation. */
572
+ /** The parent context state. */
573
+ parent: ContextState | undefined;
574
+ /** The actual context associated with this state. */
575
+ ctx: Context<unknown, TResult>;
576
+ /** The value of the scope at the point of element's creation. */
346
577
  scope: TScope | undefined;
347
578
  /** The internal node associated with this context. */
348
579
  ret: Retainer<TNode>;
349
580
  /**
350
- * The iterator returned by the component function.
581
+ * Any iterator returned by a component function.
351
582
  *
352
583
  * Existence of this property implies that the component is a generator
353
584
  * component. It is deleted when a component is returned.
354
585
  */
355
586
  iterator: Iterator<Children, Children | void, unknown> | AsyncIterator<Children, Children | void, unknown> | undefined;
356
- inflightBlock: Promise<unknown> | undefined;
357
- inflightValue: Promise<ElementValue<TNode>> | undefined;
358
- enqueuedBlock: Promise<unknown> | undefined;
359
- enqueuedValue: Promise<ElementValue<TNode>> | undefined;
360
- onProps: ((props: Record<string, any>) => unknown) | undefined;
361
- onPropsRequested: Function | undefined;
362
- constructor(renderer: RendererImpl<TNode, TScope, TRoot, TResult>, root: TRoot | undefined, host: Retainer<TNode>, parent: ContextImpl<TNode, TScope, TRoot, TResult> | undefined, scope: TScope | undefined, ret: Retainer<TNode>);
587
+ inflight: [Promise<undefined>, Promise<undefined>] | undefined;
588
+ enqueued: [Promise<undefined>, Promise<undefined>] | undefined;
589
+ pull: PullController | undefined;
590
+ onPropsProvided: ((props: unknown) => unknown) | undefined;
591
+ onPropsRequested: (() => unknown) | undefined;
592
+ index: number;
593
+ schedule: ScheduleController | undefined;
594
+ constructor(adapter: RenderAdapter<TNode, TScope, TRoot, TResult>, root: TRoot, host: Retainer<TNode>, parent: ContextState | undefined, scope: TScope | undefined, ret: Retainer<TNode>);
363
595
  }
364
- declare const _ContextImpl: unique symbol;
365
- type ComponentProps<T> = T extends () => any ? {} : T extends (props: infer U) => any ? U : T;
596
+ export type ComponentProps<T> = T extends () => unknown ? {} : T extends (props: infer U) => unknown ? U : never;
597
+ export type ComponentPropsOrProps<T> = T extends Function ? ComponentProps<T> : T;
598
+ declare const _ContextState: unique symbol;
366
599
  /**
367
600
  * A class which is instantiated and passed to every component as its this
368
- * value. Contexts form a tree just like elements and all components in the
369
- * element tree are connected via contexts. Components can use this tree to
370
- * communicate data upwards via events and downwards via provisions.
601
+ * value/second parameter. Contexts form a tree just like elements and all
602
+ * components in the element tree are connected via contexts. Components can
603
+ * use this tree to communicate data upwards via events and downwards via
604
+ * provisions.
371
605
  *
372
606
  * @template [T=*] - The expected shape of the props passed to the component,
373
607
  * or a component function. Used to strongly type the Context iterator methods.
@@ -375,74 +609,86 @@ type ComponentProps<T> = T extends () => any ? {} : T extends (props: infer U) =
375
609
  * places such as the return value of refresh and the argument passed to
376
610
  * schedule and cleanup callbacks.
377
611
  */
378
- export declare class Context<T = any, TResult = any> implements EventTarget {
612
+ export declare class Context<T = any, TResult = any> extends CustomEventTarget<Context> {
379
613
  /**
380
614
  * @internal
615
+ * DO NOT USE READ THIS PROPERTY.
381
616
  */
382
- [_ContextImpl]: ContextImpl<unknown, unknown, unknown, TResult>;
383
- constructor(impl: ContextImpl<unknown, unknown, unknown, TResult>);
617
+ [_ContextState]: ContextState<unknown, unknown, unknown, TResult>;
618
+ constructor(state: ContextState<unknown, unknown, unknown, TResult>);
384
619
  /**
385
620
  * The current props of the associated element.
386
621
  */
387
- get props(): ComponentProps<T>;
622
+ get props(): ComponentPropsOrProps<T>;
388
623
  /**
389
624
  * The current value of the associated element.
390
625
  *
391
626
  * @deprecated
392
627
  */
393
628
  get value(): TResult;
394
- [Symbol.iterator](): Generator<ComponentProps<T>>;
395
- [Symbol.asyncIterator](): AsyncGenerator<ComponentProps<T>>;
629
+ get isExecuting(): boolean;
630
+ get isUnmounted(): boolean;
631
+ [Symbol.iterator](): Generator<ComponentPropsOrProps<T>, undefined>;
632
+ [Symbol.asyncIterator](): AsyncGenerator<ComponentPropsOrProps<T>, undefined>;
396
633
  /**
397
634
  * Re-executes a component.
398
635
  *
399
- * @returns The rendered value of the component or a promise thereof if the
636
+ * @param callback - Optional callback to execute before refresh
637
+ * @returns The rendered result of the component or a promise thereof if the
400
638
  * component or its children execute asynchronously.
401
- *
402
- * The refresh method works a little differently for async generator
403
- * components, in that it will resume the Context’s props async iterator
404
- * rather than resuming execution. This is because async generator components
405
- * are perpetually resumed independent of updates, and rely on the props
406
- * async iterator to suspend.
407
639
  */
408
- refresh(): Promise<TResult> | TResult;
640
+ refresh(callback?: () => unknown): Promise<TResult> | TResult;
409
641
  /**
410
- * Registers a callback which fires when the component commits. Will only
411
- * fire once per callback and update.
642
+ * Registers a callback which fires when the component's children are
643
+ * created. Will only fire once per callback and update.
412
644
  */
645
+ schedule(): Promise<TResult>;
413
646
  schedule(callback: (value: TResult) => unknown): void;
414
647
  /**
415
- * Registers a callback which fires when the components children are
416
- * rendered into the root. Will only fire once per callback and render.
648
+ * Registers a callback which fires when the component's children are fully
649
+ * rendered. Will only fire once per callback and update.
417
650
  */
651
+ after(): Promise<TResult>;
652
+ after(callback: (value: TResult) => unknown): void;
653
+ /**
654
+ * @deprecated the flush() method has been renamed to after().
655
+ */
656
+ flush(): Promise<TResult>;
418
657
  flush(callback: (value: TResult) => unknown): void;
419
658
  /**
420
- * Registers a callback which fires when the component unmounts. Will only
421
- * fire once per callback.
659
+ * Registers a callback which fires when the component unmounts.
660
+ *
661
+ * The callback can be async to defer the unmounting of a component's children.
422
662
  */
663
+ cleanup(): Promise<TResult>;
423
664
  cleanup(callback: (value: TResult) => unknown): void;
424
665
  consume<TKey extends keyof ProvisionMap>(key: TKey): ProvisionMap[TKey];
425
666
  consume(key: unknown): any;
426
667
  provide<TKey extends keyof ProvisionMap>(key: TKey, value: ProvisionMap[TKey]): void;
427
668
  provide(key: unknown, value: any): void;
428
- addEventListener<T extends string>(type: T, listener: MappedEventListenerOrEventListenerObject<T> | null, options?: boolean | AddEventListenerOptions): void;
429
- removeEventListener<T extends string>(type: T, listener: MappedEventListenerOrEventListenerObject<T> | null, options?: EventListenerOptions | boolean): void;
430
- dispatchEvent(ev: Event): boolean;
669
+ [CustomEventTarget.dispatchEventOnSelf](ev: Event): void;
431
670
  }
432
671
  /**
433
- * A map of event type strings to Event subclasses. Can be extended via
434
- * TypeScript module augmentation to have strongly typed event listeners.
672
+ * An interface which can be extended to provide strongly typed provisions.
673
+ * See Context.prototype.consume and Context.prototype.provide.
435
674
  */
675
+ export interface ProvisionMap extends Crank.ProvisionMap {
676
+ }
436
677
  export interface EventMap extends Crank.EventMap {
437
- [type: string]: Event;
438
678
  }
439
- type MappedEventListener<T extends string> = (ev: EventMap[T]) => unknown;
679
+ type MappedEventListener<T extends string> = (ev: Crank.EventMap[T]) => unknown;
440
680
  type MappedEventListenerOrEventListenerObject<T extends string> = MappedEventListener<T> | {
441
681
  handleEvent: MappedEventListener<T>;
442
682
  };
683
+ export interface Context extends Crank.Context {
684
+ addEventListener<T extends string>(type: T, listener: MappedEventListenerOrEventListenerObject<T> | null, options?: boolean | AddEventListenerOptions): void;
685
+ removeEventListener<T extends string>(type: T, listener: MappedEventListenerOrEventListenerObject<T> | null, options?: EventListenerOptions | boolean): void;
686
+ dispatchEvent<T extends string>(ev: EventMap[T] | Event): boolean;
687
+ }
443
688
  declare global {
444
689
  namespace Crank {
445
690
  interface EventMap {
691
+ [tag: string]: Event;
446
692
  }
447
693
  interface ProvisionMap {
448
694
  }
@@ -458,32 +704,19 @@ declare global {
458
704
  key?: unknown;
459
705
  ref?: unknown;
460
706
  copy?: unknown;
461
- /** @deprecated */
462
- ["static"]?: unknown;
463
- /** @deprecated */
464
- ["crank-key"]?: unknown;
465
- /** @deprecated */
466
- ["crank-ref"]?: unknown;
467
- /** @deprecated */
468
- ["crank-static"]?: unknown;
469
- /** @deprecated */
470
- ["c-key"]?: unknown;
471
- /** @deprecated */
472
- ["c-ref"]?: unknown;
473
- /** @deprecated */
474
- ["c-static"]?: unknown;
475
- /** @deprecated */
476
- $key?: unknown;
477
- /** @deprecated */
478
- $ref?: unknown;
479
- /** @deprecated */
480
- $static?: unknown;
707
+ hydrate?: unknown;
481
708
  }
482
709
  interface ElementChildrenAttribute {
483
710
  children: {};
484
711
  }
485
712
  }
486
713
  }
714
+ /**
715
+ * A re-export of some Crank exports as the default export.
716
+ *
717
+ * Some JSX tools expect things like createElement/Fragment to be defined on
718
+ * the default export. Prefer using the named exports directly.
719
+ */
487
720
  declare const _default: {
488
721
  createElement: typeof createElement;
489
722
  Fragment: string;