@vertz/ui 0.2.0 → 0.2.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.
Files changed (35) hide show
  1. package/README.md +339 -857
  2. package/dist/css/public.d.ts +24 -27
  3. package/dist/css/public.js +5 -1
  4. package/dist/form/public.d.ts +94 -38
  5. package/dist/form/public.js +5 -3
  6. package/dist/index.d.ts +696 -167
  7. package/dist/index.js +461 -84
  8. package/dist/internals.d.ts +192 -23
  9. package/dist/internals.js +151 -102
  10. package/dist/jsx-runtime/index.d.ts +44 -17
  11. package/dist/jsx-runtime/index.js +26 -7
  12. package/dist/query/public.d.ts +62 -7
  13. package/dist/query/public.js +12 -4
  14. package/dist/router/public.d.ts +186 -26
  15. package/dist/router/public.js +22 -7
  16. package/dist/shared/{chunk-f1ynwam4.js → chunk-0p5f7gmg.js} +155 -32
  17. package/dist/shared/{chunk-j8vzvne3.js → chunk-9e92w0wt.js} +4 -1
  18. package/dist/shared/{chunk-xd9d7q5p.js → chunk-cq7xg4xe.js} +59 -10
  19. package/dist/shared/chunk-g4rch80a.js +33 -0
  20. package/dist/shared/{chunk-pgymxpn1.js → chunk-hrd0mft1.js} +136 -34
  21. package/dist/shared/chunk-nmjyj8p9.js +290 -0
  22. package/dist/shared/chunk-pp3a6xbn.js +483 -0
  23. package/dist/shared/chunk-prj7nm08.js +67 -0
  24. package/dist/shared/chunk-q6cpe5k7.js +230 -0
  25. package/dist/shared/chunk-ryb49346.js +374 -0
  26. package/dist/shared/chunk-v3yyf79g.js +48 -0
  27. package/dist/shared/chunk-vx0kzack.js +103 -0
  28. package/dist/shared/chunk-wv6kkj1w.js +464 -0
  29. package/dist/test/index.d.ts +67 -6
  30. package/dist/test/index.js +4 -3
  31. package/package.json +13 -8
  32. package/dist/shared/chunk-bp3v6s9j.js +0 -62
  33. package/dist/shared/chunk-d8h2eh8d.js +0 -141
  34. package/dist/shared/chunk-tsdpgmks.js +0 -98
  35. package/dist/shared/chunk-zbbvx05f.js +0 -202
@@ -1,3 +1,58 @@
1
+ /**
2
+ * A reactive signal that holds a value and notifies subscribers on change.
3
+ */
4
+ interface Signal<T> {
5
+ /** Get the current value and subscribe to changes (when inside a tracking context). */
6
+ get value(): T;
7
+ /** Set the current value and notify subscribers if changed. */
8
+ set value(newValue: T);
9
+ /** Read the current value without subscribing (no tracking). */
10
+ peek(): T;
11
+ /** Manually notify all subscribers (useful after mutating the value in place). */
12
+ notify(): void;
13
+ }
14
+ /** Dispose function returned by effect(). */
15
+ type DisposeFn = () => void;
16
+ /**
17
+ * A snapshot of context values at a point in time.
18
+ * Each Provider creates a new scope that inherits from the parent.
19
+ * Effects capture this scope so that useContext works in async callbacks.
20
+ */
21
+ type ContextScope = Map<Context<unknown>, unknown>;
22
+ /**
23
+ * Props for the JSX pattern of Context.Provider.
24
+ *
25
+ * `children` accepts both raw values (what TypeScript sees in JSX) and
26
+ * thunks (what the compiler produces). At compile time the compiler wraps
27
+ * JSX children in `() => ...`, but TypeScript checks the pre-compilation
28
+ * source where children are plain elements.
29
+ */
30
+ interface ProviderJsxProps<T> {
31
+ value: T;
32
+ children: (() => unknown) | unknown;
33
+ }
34
+ /** A context object created by `createContext`. */
35
+ interface Context<T> {
36
+ /** Provide a value via callback pattern. */
37
+ Provider(value: T, fn: () => void): void;
38
+ /** Provide a value via JSX pattern (single-arg object with children thunk). */
39
+ Provider(props: ProviderJsxProps<T>): HTMLElement;
40
+ /** @internal — current value stack */
41
+ _stack: T[];
42
+ /** @internal — default value */
43
+ _default: T | undefined;
44
+ }
45
+ /**
46
+ * Get the current context scope for capture by effects.
47
+ * @internal
48
+ */
49
+ declare function getContextScope(): ContextScope | null;
50
+ /**
51
+ * Set the current context scope (used by effects to restore captured context).
52
+ * Returns the previous scope for restoration.
53
+ * @internal
54
+ */
55
+ declare function setContextScope(scope: ContextScope | null): ContextScope | null;
1
56
  /** Color tokens: a map of color names to their raw/contextual values. */
2
57
  type ColorTokens = Record<string, Record<string, string>>;
3
58
  /** Spacing tokens: a flat map of names to CSS values. */
@@ -60,7 +115,7 @@ declare const KEYWORD_MAP: Record<string, CSSDeclarationEntry[]>;
60
115
  declare const DISPLAY_MAP: Record<string, string>;
61
116
  /** Spacing scale: number -> rem. 1=0.25rem, 2=0.5rem, 4=1rem, 8=2rem, etc. */
62
117
  declare const SPACING_SCALE: Record<string, string>;
63
- /** Border radius scale. */
118
+ /** Border radius scale — matches Tailwind v4 / shadcn. */
64
119
  declare const RADIUS_SCALE: Record<string, string>;
65
120
  /** Shadow scale. */
66
121
  declare const SHADOW_SCALE: Record<string, string>;
@@ -87,20 +142,60 @@ declare const PSEUDO_PREFIXES: ReadonlySet<string>;
87
142
  /** Map pseudo shorthand names to CSS pseudo-selectors. */
88
143
  declare const PSEUDO_MAP: Record<string, string>;
89
144
  /**
90
- * A reactive signal that holds a value and notifies subscribers on change.
145
+ * Brand symbol for render nodes.
146
+ * SSR nodes add this to their prototype for fast identification.
147
+ * Browser DOM nodes use the `instanceof Node` fallback in `isRenderNode`.
91
148
  */
92
- interface Signal<T> {
93
- /** Get the current value and subscribe to changes (when inside a tracking context). */
94
- get value(): T;
95
- /** Set the current value and notify subscribers if changed. */
96
- set value(newValue: T);
97
- /** Read the current value without subscribing (no tracking). */
98
- peek(): T;
99
- /** Manually notify all subscribers (useful after mutating the value in place). */
100
- notify(): void;
149
+ declare const RENDER_NODE_BRAND: unique symbol;
150
+ interface RenderNode {}
151
+ interface RenderElement extends RenderNode {
152
+ setAttribute(name: string, value: string): void;
153
+ removeAttribute(name: string): void;
154
+ getAttribute(name: string): string | null;
155
+ style: {
156
+ display: string;
157
+ [key: string]: any;
158
+ };
159
+ classList: {
160
+ add(cls: string): void;
161
+ remove(cls: string): void;
162
+ };
163
+ addEventListener(event: string, handler: EventListener): void;
164
+ removeEventListener(event: string, handler: EventListener): void;
101
165
  }
102
- /** Dispose function returned by effect(). */
103
- type DisposeFn = () => void;
166
+ interface RenderText extends RenderNode {
167
+ data: string;
168
+ }
169
+ interface RenderAdapter {
170
+ createElement(tag: string): RenderElement;
171
+ createElementNS(ns: string, tag: string): RenderElement;
172
+ createTextNode(text: string): RenderText;
173
+ createComment(text: string): RenderNode;
174
+ createDocumentFragment(): RenderNode;
175
+ isNode(value: unknown): value is RenderNode;
176
+ }
177
+ /**
178
+ * Type guard: checks if a value is a RenderNode.
179
+ * Fast path: brand check for SSR nodes.
180
+ * Fallback: instanceof Node for browser DOM nodes.
181
+ */
182
+ declare function isRenderNode(value: unknown): value is RenderNode;
183
+ /**
184
+ * Get the current render adapter.
185
+ * Auto-detects DOMAdapter if document exists and no adapter has been set.
186
+ */
187
+ declare function getAdapter(): RenderAdapter;
188
+ /**
189
+ * Set the current render adapter.
190
+ * Pass null to reset to auto-detect.
191
+ */
192
+ declare function setAdapter(adapter: RenderAdapter | null): void;
193
+ /**
194
+ * Wait for all CSS animations on an element to complete, then call back.
195
+ * If no animations are running, calls back immediately.
196
+ * Respects prefers-reduced-motion by skipping the wait.
197
+ */
198
+ declare function onAnimationsComplete(el: HTMLElement, callback: () => void): void;
104
199
  /**
105
200
  * Create a reactive attribute binding.
106
201
  * When the value returned by `fn` changes, the attribute is updated.
@@ -109,7 +204,7 @@ type DisposeFn = () => void;
109
204
  * Compiler output target for reactive attribute expressions.
110
205
  * Returns a dispose function to stop the reactive binding.
111
206
  */
112
- declare function __attr(el: HTMLElement, name: string, fn: () => string | null | undefined): DisposeFn;
207
+ declare function __attr(el: HTMLElement, name: string, fn: () => string | boolean | null | undefined): DisposeFn;
113
208
  /**
114
209
  * Reactive display toggle.
115
210
  * When fn() returns false, the element is hidden (display: none).
@@ -139,9 +234,16 @@ interface DisposableNode extends Node {
139
234
  *
140
235
  * Compiler output target for ternary expressions and if/else in JSX.
141
236
  *
142
- * Returns a Node (DocumentFragment) with a `dispose` property attached.
237
+ * Returns a DisposableNode: a DocumentFragment (CSR) or the claimed
238
+ * comment anchor (hydration), with a `dispose` property attached.
143
239
  */
144
240
  declare function __conditional(condFn: () => boolean, trueFn: () => Node | null, falseFn: () => Node | null): DisposableNode;
241
+ /**
242
+ * Create a DOM adapter that delegates to real browser DOM APIs.
243
+ * Zero overhead — no branding, no wrapping.
244
+ * Browser `Node` instances pass `isRenderNode()` via the `instanceof Node` fallback.
245
+ */
246
+ declare function createDOMAdapter(): RenderAdapter;
145
247
  /** A Text node that also carries a dispose function for cleanup. */
146
248
  interface DisposableText extends Text {
147
249
  dispose: DisposeFn;
@@ -174,17 +276,45 @@ declare function __child(fn: () => Node | string | number | boolean | null | und
174
276
  * This is used for static JSX expression children to avoid the performance
175
277
  * overhead of effect() when reactivity isn't needed.
176
278
  *
177
- * Handles Node values (appended directly), primitives (converted to text),
178
- * and nullish/boolean values (skipped).
279
+ * Functions and arrays are resolved unconditionally before branching on
280
+ * hydration state, ensuring all inner __element/__on calls execute
281
+ * regardless of mode.
179
282
  */
180
- declare function __insert(parent: Node, value: Node | string | number | boolean | null | undefined): void;
283
+ declare function __insert(parent: Node, value: Node | string | number | boolean | null | undefined | (() => unknown) | unknown[]): void;
181
284
  /**
182
285
  * Create a DOM element with optional static properties.
183
286
  *
184
287
  * This is a compiler output target — the compiler generates calls
185
288
  * to __element for each JSX element.
186
289
  */
187
- declare function __element(tag: string, props?: Record<string, string>): HTMLElement;
290
+ declare function __element<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Record<string, string>): HTMLElementTagNameMap[K];
291
+ declare function __element(tag: string, props?: Record<string, string>): Element;
292
+ /**
293
+ * Append a child to a parent node.
294
+ * During hydration, this is a no-op — the child is already in the DOM.
295
+ * During CSR, delegates to appendChild.
296
+ *
297
+ * Compiler output target — replaces direct `parent.appendChild(child)`.
298
+ */
299
+ declare function __append(parent: Node, child: Node): void;
300
+ /**
301
+ * Create a static text node.
302
+ * During hydration, claims an existing text node from the SSR output.
303
+ * During CSR, creates a new text node.
304
+ *
305
+ * Compiler output target — replaces `document.createTextNode(str)`.
306
+ */
307
+ declare function __staticText(text: string): Text;
308
+ /**
309
+ * Push the hydration cursor into an element's children.
310
+ * Compiler output target — emitted around child construction.
311
+ */
312
+ declare function __enterChildren(el: Element): void;
313
+ /**
314
+ * Pop the hydration cursor back to the parent scope.
315
+ * Compiler output target — emitted after all children are appended.
316
+ */
317
+ declare function __exitChildren(): void;
188
318
  /**
189
319
  * Bind an event handler to an element.
190
320
  * Returns a cleanup function to remove the listener.
@@ -216,11 +346,11 @@ declare function clearChildren(container: Node): void;
216
346
  * @param items - A signal or getter function containing the array of items.
217
347
  * The compiler generates `() => signal.value` as a getter; the runtime
218
348
  * also accepts a raw Signal for direct use in tests.
219
- * @param keyFn - Extracts a unique key from each item
349
+ * @param keyFn - Extracts a unique key from each item (receives item and index)
220
350
  * @param renderFn - Creates a DOM node for an item (called once per key)
221
351
  * @returns A dispose function to stop the reactive list reconciliation
222
352
  */
223
- declare function __list<T>(container: HTMLElement, items: Signal<T[]> | (() => T[]), keyFn: (item: T) => string | number, renderFn: (item: T) => Node): DisposeFn;
353
+ declare function __list<T>(container: HTMLElement, items: Signal<T[]> | (() => T[]), keyFn: (item: T, index: number) => string | number, renderFn: (item: T) => Node): DisposeFn;
224
354
  /** A function returning a dynamic import of a component module. */
225
355
  type ComponentLoader = () => Promise<{
226
356
  default: ComponentFunction;
@@ -248,6 +378,7 @@ interface CacheStore<T = unknown> {
248
378
  get(key: string): T | undefined;
249
379
  set(key: string, value: T): void;
250
380
  delete(key: string): void;
381
+ clear?(): void;
251
382
  }
252
383
  /**
253
384
  * Default in-memory cache backed by a Map.
@@ -257,6 +388,7 @@ declare class MemoryCache<T = unknown> implements CacheStore<T> {
257
388
  get(key: string): T | undefined;
258
389
  set(key: string, value: T): void;
259
390
  delete(key: string): void;
391
+ clear(): void;
260
392
  }
261
393
  /**
262
394
  * Derive a cache key from a thunk function.
@@ -294,7 +426,13 @@ type ExtractParams<T extends string> = [ExtractParamsFromSegments<WithoutWildcar
294
426
  } : { [K in ExtractParamsFromSegments<WithoutWildcard<T>>] : string };
295
427
  /** Simple schema interface for search param parsing. */
296
428
  interface SearchParamSchema<T> {
297
- parse(data: unknown): T;
429
+ parse(data: unknown): {
430
+ ok: true;
431
+ data: T;
432
+ } | {
433
+ ok: false;
434
+ error: unknown;
435
+ };
298
436
  }
299
437
  /** A route configuration for a single path. */
300
438
  interface RouteConfig<
@@ -398,6 +536,20 @@ interface MatchResult {
398
536
  */
399
537
  declare function matchPath(pattern: string, path: string): MatchResult | null;
400
538
  /**
539
+ * Register a cleanup function with the current disposal scope.
540
+ * Throws `DisposalScopeError` if no scope is active — fail-fast
541
+ * so developers know their cleanup callback was not registered.
542
+ */
543
+ declare function onCleanup(fn: DisposeFn): void;
544
+ /**
545
+ * Try to register a cleanup function with the current disposal scope.
546
+ * If no scope is active, the callback is silently discarded.
547
+ *
548
+ * @internal — Used by runtime primitives (effect, watch, __list) that
549
+ * optionally register with a parent scope but work fine without one.
550
+ */
551
+ declare function _tryOnCleanup(fn: DisposeFn): void;
552
+ /**
401
553
  * Push a new cleanup scope. All onCleanup calls within this scope
402
554
  * will be collected and returned when the scope is popped.
403
555
  */
@@ -411,4 +563,21 @@ declare function popScope(): void;
411
563
  * Reverse order matches try/finally semantics — last registered, first cleaned up.
412
564
  */
413
565
  declare function runCleanups(cleanups: DisposeFn[]): void;
414
- export { runCleanups, resolveComponent, removeNode, pushScope, popScope, matchRoute, matchPath, insertBefore, executeLoaders, deserializeProps, deriveKey, compileTheme, clearChildren, __text, __show, __on, __list, __insert, __element, __conditional, __classList, __child, __attr, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RADIUS_SCALE, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
566
+ declare function startSignalCollection(): void;
567
+ declare function stopSignalCollection(): Signal<unknown>[];
568
+ /**
569
+ * Create a reactive effect for DOM population.
570
+ * During CSR: runs immediately and tracks dependencies (full reactivity).
571
+ * During SSR: runs callback once synchronously WITHOUT signal tracking
572
+ * (populates initial DOM state, then discards).
573
+ * Returns a dispose function to stop the effect.
574
+ */
575
+ declare function domEffect(fn: () => void): DisposeFn;
576
+ /**
577
+ * Create a reactive effect for lifecycle concerns (data fetching, side effects).
578
+ * During CSR: runs immediately and tracks dependencies (full reactivity).
579
+ * During SSR: complete no-op (lifecycle effects are irrelevant for static HTML).
580
+ * Returns a dispose function to stop the effect.
581
+ */
582
+ declare function lifecycleEffect(fn: () => void): DisposeFn;
583
+ export { stopSignalCollection, startSignalCollection, setContextScope, setAdapter, runCleanups, resolveComponent, removeNode, pushScope, popScope, onCleanup, onAnimationsComplete, matchRoute, matchPath, lifecycleEffect, isRenderNode, insertBefore, getContextScope, getAdapter, executeLoaders, domEffect, deserializeProps, deriveKey, createDOMAdapter, compileTheme, clearChildren, _tryOnCleanup, __text, __staticText, __show, __on, __list, __insert, __exitChildren, __enterChildren, __element, __conditional, __classList, __child, __attr, __append, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RenderText, RenderNode, RenderElement, RenderAdapter, RENDER_NODE_BRAND, RADIUS_SCALE, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
package/dist/internals.js CHANGED
@@ -1,23 +1,24 @@
1
1
  import {
2
2
  deserializeProps,
3
+ onAnimationsComplete,
3
4
  resolveComponent
4
- } from "./shared/chunk-d8h2eh8d.js";
5
+ } from "./shared/chunk-pp3a6xbn.js";
6
+ import {
7
+ __attr,
8
+ __classList,
9
+ __on,
10
+ __show
11
+ } from "./shared/chunk-v3yyf79g.js";
5
12
  import {
6
13
  executeLoaders,
7
14
  matchPath,
8
15
  matchRoute
9
- } from "./shared/chunk-j8vzvne3.js";
16
+ } from "./shared/chunk-9e92w0wt.js";
10
17
  import {
11
18
  MemoryCache,
12
19
  deriveKey
13
- } from "./shared/chunk-zbbvx05f.js";
14
- import {
15
- _tryOnCleanup,
16
- effect,
17
- popScope,
18
- pushScope,
19
- runCleanups
20
- } from "./shared/chunk-pgymxpn1.js";
20
+ } from "./shared/chunk-wv6kkj1w.js";
21
+ import"./shared/chunk-vx0kzack.js";
21
22
  import {
22
23
  ALIGNMENT_MAP,
23
24
  COLOR_NAMESPACES,
@@ -37,55 +38,123 @@ import {
37
38
  SIZE_KEYWORDS,
38
39
  SPACING_SCALE,
39
40
  compileTheme
40
- } from "./shared/chunk-f1ynwam4.js";
41
- // src/dom/attributes.ts
42
- function __attr(el, name, fn) {
43
- return effect(() => {
44
- const value = fn();
45
- if (value == null) {
46
- el.removeAttribute(name);
47
- } else {
48
- el.setAttribute(name, value);
49
- }
50
- });
51
- }
52
- function __show(el, fn) {
53
- const originalDisplay = el.style.display;
54
- return effect(() => {
55
- el.style.display = fn() ? originalDisplay : "none";
56
- });
41
+ } from "./shared/chunk-0p5f7gmg.js";
42
+ import {
43
+ __append,
44
+ __child,
45
+ __element,
46
+ __enterChildren,
47
+ __exitChildren,
48
+ __insert,
49
+ __staticText,
50
+ __text,
51
+ claimComment,
52
+ claimText,
53
+ getIsHydrating
54
+ } from "./shared/chunk-ryb49346.js";
55
+ import {
56
+ RENDER_NODE_BRAND,
57
+ createDOMAdapter,
58
+ getAdapter,
59
+ isRenderNode,
60
+ setAdapter
61
+ } from "./shared/chunk-g4rch80a.js";
62
+ import {
63
+ _tryOnCleanup,
64
+ domEffect,
65
+ getContextScope,
66
+ lifecycleEffect,
67
+ onCleanup,
68
+ popScope,
69
+ pushScope,
70
+ runCleanups,
71
+ setContextScope,
72
+ startSignalCollection,
73
+ stopSignalCollection
74
+ } from "./shared/chunk-hrd0mft1.js";
75
+ import"./shared/chunk-prj7nm08.js";
76
+ // src/dom/conditional.ts
77
+ function __conditional(condFn, trueFn, falseFn) {
78
+ if (getIsHydrating()) {
79
+ return hydrateConditional(condFn, trueFn, falseFn);
80
+ }
81
+ return csrConditional(condFn, trueFn, falseFn);
57
82
  }
58
- function __classList(el, classMap) {
59
- const disposers = [];
60
- for (const [className, fn] of Object.entries(classMap)) {
61
- disposers.push(effect(() => {
62
- if (fn()) {
63
- el.classList.add(className);
83
+ function hydrateConditional(condFn, trueFn, falseFn) {
84
+ const anchor = claimComment() ?? getAdapter().createComment("conditional");
85
+ let currentNode = null;
86
+ let branchCleanups = [];
87
+ const outerScope = pushScope();
88
+ let isFirstRun = true;
89
+ domEffect(() => {
90
+ const show = condFn();
91
+ if (isFirstRun) {
92
+ isFirstRun = false;
93
+ const scope2 = pushScope();
94
+ const branchResult2 = show ? trueFn() : falseFn();
95
+ popScope();
96
+ branchCleanups = scope2;
97
+ if (branchResult2 == null || typeof branchResult2 === "boolean") {
98
+ currentNode = getAdapter().createComment("empty");
99
+ } else if (isRenderNode(branchResult2)) {
100
+ currentNode = branchResult2;
64
101
  } else {
65
- el.classList.remove(className);
102
+ const claimed = claimText();
103
+ currentNode = claimed ?? getAdapter().createTextNode(String(branchResult2));
66
104
  }
67
- }));
68
- }
69
- return () => {
70
- for (const dispose of disposers) {
71
- dispose();
105
+ return;
106
+ }
107
+ runCleanups(branchCleanups);
108
+ const scope = pushScope();
109
+ const branchResult = show ? trueFn() : falseFn();
110
+ popScope();
111
+ branchCleanups = scope;
112
+ let newNode;
113
+ if (branchResult == null || typeof branchResult === "boolean") {
114
+ newNode = getAdapter().createComment("empty");
115
+ } else if (isRenderNode(branchResult)) {
116
+ newNode = branchResult;
117
+ } else {
118
+ newNode = getAdapter().createTextNode(String(branchResult));
72
119
  }
120
+ if (currentNode?.parentNode) {
121
+ currentNode.parentNode.replaceChild(newNode, currentNode);
122
+ } else if (anchor.parentNode) {
123
+ anchor.parentNode.insertBefore(newNode, anchor.nextSibling);
124
+ }
125
+ currentNode = newNode;
126
+ });
127
+ popScope();
128
+ const wrapper = () => {
129
+ runCleanups(branchCleanups);
130
+ runCleanups(outerScope);
73
131
  };
132
+ _tryOnCleanup(wrapper);
133
+ const result = Object.assign(anchor, {
134
+ dispose: wrapper
135
+ });
136
+ return result;
74
137
  }
75
- // src/dom/conditional.ts
76
- function __conditional(condFn, trueFn, falseFn) {
77
- const anchor = document.createComment("conditional");
138
+ function csrConditional(condFn, trueFn, falseFn) {
139
+ const anchor = getAdapter().createComment("conditional");
78
140
  let currentNode = null;
79
141
  let branchCleanups = [];
80
142
  const outerScope = pushScope();
81
- effect(() => {
143
+ domEffect(() => {
82
144
  const show = condFn();
83
145
  runCleanups(branchCleanups);
84
146
  const scope = pushScope();
85
147
  const branchResult = show ? trueFn() : falseFn();
86
148
  popScope();
87
149
  branchCleanups = scope;
88
- const newNode = branchResult ?? document.createComment("empty");
150
+ let newNode;
151
+ if (branchResult == null || typeof branchResult === "boolean") {
152
+ newNode = getAdapter().createComment("empty");
153
+ } else if (isRenderNode(branchResult)) {
154
+ newNode = branchResult;
155
+ } else {
156
+ newNode = getAdapter().createTextNode(String(branchResult));
157
+ }
89
158
  if (currentNode?.parentNode) {
90
159
  currentNode.parentNode.replaceChild(newNode, currentNode);
91
160
  } else if (anchor.parentNode) {
@@ -99,7 +168,7 @@ function __conditional(condFn, trueFn, falseFn) {
99
168
  runCleanups(outerScope);
100
169
  };
101
170
  _tryOnCleanup(wrapper);
102
- const fragment = document.createDocumentFragment();
171
+ const fragment = getAdapter().createDocumentFragment();
103
172
  fragment.appendChild(anchor);
104
173
  if (currentNode) {
105
174
  fragment.appendChild(currentNode);
@@ -107,59 +176,6 @@ function __conditional(condFn, trueFn, falseFn) {
107
176
  const result = Object.assign(fragment, { dispose: wrapper });
108
177
  return result;
109
178
  }
110
- // src/dom/element.ts
111
- function __text(fn) {
112
- const node = document.createTextNode("");
113
- node.dispose = effect(() => {
114
- node.data = fn();
115
- });
116
- return node;
117
- }
118
- function __child(fn) {
119
- const wrapper = document.createElement("span");
120
- wrapper.style.display = "contents";
121
- wrapper.dispose = effect(() => {
122
- const value = fn();
123
- while (wrapper.firstChild) {
124
- wrapper.removeChild(wrapper.firstChild);
125
- }
126
- if (value == null || typeof value === "boolean") {
127
- return;
128
- }
129
- if (value instanceof Node) {
130
- wrapper.appendChild(value);
131
- return;
132
- }
133
- const textValue = typeof value === "string" ? value : String(value);
134
- wrapper.appendChild(document.createTextNode(textValue));
135
- });
136
- return wrapper;
137
- }
138
- function __insert(parent, value) {
139
- if (value == null || typeof value === "boolean") {
140
- return;
141
- }
142
- if (value instanceof Node) {
143
- parent.appendChild(value);
144
- return;
145
- }
146
- const textValue = typeof value === "string" ? value : String(value);
147
- parent.appendChild(document.createTextNode(textValue));
148
- }
149
- function __element(tag, props) {
150
- const el = document.createElement(tag);
151
- if (props) {
152
- for (const [key, value] of Object.entries(props)) {
153
- el.setAttribute(key, value);
154
- }
155
- }
156
- return el;
157
- }
158
- // src/dom/events.ts
159
- function __on(el, event, handler) {
160
- el.addEventListener(event, handler);
161
- return () => el.removeEventListener(event, handler);
162
- }
163
179
  // src/dom/insert.ts
164
180
  function insertBefore(container, node, reference) {
165
181
  container.insertBefore(node, reference);
@@ -177,10 +193,25 @@ function __list(container, items, keyFn, renderFn) {
177
193
  const getItems = typeof items === "function" ? items : () => items.value;
178
194
  const nodeMap = new Map;
179
195
  const scopeMap = new Map;
196
+ const isHydrationRun = getIsHydrating();
180
197
  const outerScope = pushScope();
181
- effect(() => {
198
+ let isFirstRun = true;
199
+ domEffect(() => {
182
200
  const newItems = getItems();
183
- const newKeySet = new Set(newItems.map(keyFn));
201
+ if (isFirstRun && isHydrationRun) {
202
+ isFirstRun = false;
203
+ for (const [i, item] of newItems.entries()) {
204
+ const key = keyFn(item, i);
205
+ const scope = pushScope();
206
+ const node = renderFn(item);
207
+ popScope();
208
+ nodeMap.set(key, node);
209
+ scopeMap.set(key, scope);
210
+ }
211
+ return;
212
+ }
213
+ isFirstRun = false;
214
+ const newKeySet = new Set(newItems.map((item, i) => keyFn(item, i)));
184
215
  for (const [key, node] of nodeMap) {
185
216
  if (!newKeySet.has(key)) {
186
217
  const scope = scopeMap.get(key);
@@ -193,8 +224,8 @@ function __list(container, items, keyFn, renderFn) {
193
224
  }
194
225
  }
195
226
  const desiredNodes = [];
196
- for (const item of newItems) {
197
- const key = keyFn(item);
227
+ for (const [i, item] of newItems.entries()) {
228
+ const key = keyFn(item, i);
198
229
  let node = nodeMap.get(key);
199
230
  if (!node) {
200
231
  const scope = pushScope();
@@ -224,32 +255,50 @@ function __list(container, items, keyFn, renderFn) {
224
255
  return wrapper;
225
256
  }
226
257
  export {
258
+ stopSignalCollection,
259
+ startSignalCollection,
260
+ setContextScope,
261
+ setAdapter,
227
262
  runCleanups,
228
263
  resolveComponent,
229
264
  removeNode,
230
265
  pushScope,
231
266
  popScope,
267
+ onCleanup,
268
+ onAnimationsComplete,
232
269
  matchRoute,
233
270
  matchPath,
271
+ lifecycleEffect,
272
+ isRenderNode,
234
273
  insertBefore,
274
+ getContextScope,
275
+ getAdapter,
235
276
  executeLoaders,
277
+ domEffect,
236
278
  deserializeProps,
237
279
  deriveKey,
280
+ createDOMAdapter,
238
281
  compileTheme,
239
282
  clearChildren,
283
+ _tryOnCleanup,
240
284
  __text,
285
+ __staticText,
241
286
  __show,
242
287
  __on,
243
288
  __list,
244
289
  __insert,
290
+ __exitChildren,
291
+ __enterChildren,
245
292
  __element,
246
293
  __conditional,
247
294
  __classList,
248
295
  __child,
249
296
  __attr,
297
+ __append,
250
298
  SPACING_SCALE,
251
299
  SIZE_KEYWORDS,
252
300
  SHADOW_SCALE,
301
+ RENDER_NODE_BRAND,
253
302
  RADIUS_SCALE,
254
303
  PSEUDO_PREFIXES,
255
304
  PSEUDO_MAP,