@askrjs/askr 0.0.35 → 0.0.36
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/dist/bench/components/benchmark-row.js.map +1 -1
- package/dist/bench/components/benchmark-table.js.map +1 -1
- package/dist/benchmark.js +2 -2
- package/dist/benchmark.js.map +1 -1
- package/dist/bin/askr-ssg.js.map +1 -1
- package/dist/boot/index.d.ts.map +1 -1
- package/dist/boot/index.js +9 -29
- package/dist/boot/index.js.map +1 -1
- package/dist/common/control.js.map +1 -1
- package/dist/common/env.js.map +1 -1
- package/dist/common/ssr-errors.js.map +1 -1
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/control/case.js.map +1 -1
- package/dist/control/for.js.map +1 -1
- package/dist/control/shared.js.map +1 -1
- package/dist/control/show.js.map +1 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +165 -23
- package/dist/data/index.js.map +1 -1
- package/dist/dev/invariant.js.map +1 -1
- package/dist/dev/logger.js.map +1 -1
- package/dist/foundations/icon/icon.js.map +1 -1
- package/dist/foundations/interactions/dismissable.js.map +1 -1
- package/dist/foundations/interactions/focusable.js.map +1 -1
- package/dist/foundations/interactions/hoverable.js.map +1 -1
- package/dist/foundations/interactions/interaction-policy.js.map +1 -1
- package/dist/foundations/interactions/pressable.js.map +1 -1
- package/dist/foundations/interactions/roving-focus.js.map +1 -1
- package/dist/foundations/state/controllable.js.map +1 -1
- package/dist/foundations/structures/collection.js.map +1 -1
- package/dist/foundations/structures/layer.js.map +1 -1
- package/dist/foundations/structures/layout.js.map +1 -1
- package/dist/foundations/structures/portal.js.map +1 -1
- package/dist/foundations/structures/presence.js.map +1 -1
- package/dist/foundations/structures/slot.js.map +1 -1
- package/dist/foundations/utilities/aria.js.map +1 -1
- package/dist/foundations/utilities/compose-handlers.js.map +1 -1
- package/dist/foundations/utilities/compose-ref.js.map +1 -1
- package/dist/foundations/utilities/merge-props.js.map +1 -1
- package/dist/foundations/utilities/use-id.js.map +1 -1
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/timing.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/jsx/utils.js.map +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/dom.js +128 -53
- package/dist/renderer/dom.js.map +1 -1
- package/dist/renderer/evaluate.js +7 -0
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyed.js +1 -1
- package/dist/renderer/keyed.js.map +1 -1
- package/dist/renderer/reconcile.js.map +1 -1
- package/dist/renderer/utils.js.map +1 -1
- package/dist/router/index.d.ts +2 -2
- package/dist/router/index.js +2 -2
- package/dist/router/match.js.map +1 -1
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +4 -2
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/policy.js.map +1 -1
- package/dist/router/route-context.js.map +1 -1
- package/dist/router/route.d.ts +1 -1
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/route.js +3 -34
- package/dist/router/route.js.map +1 -1
- package/dist/runtime/child-scope.d.ts +1 -0
- package/dist/runtime/child-scope.d.ts.map +1 -1
- package/dist/runtime/child-scope.js +2 -0
- package/dist/runtime/child-scope.js.map +1 -1
- package/dist/runtime/component.js +1 -1
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/derive.d.ts +2 -1
- package/dist/runtime/derive.d.ts.map +1 -1
- package/dist/runtime/derive.js +15 -10
- package/dist/runtime/derive.js.map +1 -1
- package/dist/runtime/dev-namespace.js.map +1 -1
- package/dist/runtime/effect.d.ts.map +1 -1
- package/dist/runtime/effect.js +34 -9
- package/dist/runtime/effect.js.map +1 -1
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/execution-model.js.map +1 -1
- package/dist/runtime/fastlane.js.map +1 -1
- package/dist/runtime/for-bench.d.ts +1 -1
- package/dist/runtime/for-bench.d.ts.map +1 -1
- package/dist/runtime/for-bench.js +15 -14
- package/dist/runtime/for-bench.js.map +1 -1
- package/dist/runtime/for.d.ts +1 -0
- package/dist/runtime/for.d.ts.map +1 -1
- package/dist/runtime/for.js +63 -16
- package/dist/runtime/for.js.map +1 -1
- package/dist/runtime/operations.d.ts.map +1 -1
- package/dist/runtime/operations.js +9 -7
- package/dist/runtime/operations.js.map +1 -1
- package/dist/runtime/perf-metrics.js +8 -2
- package/dist/runtime/perf-metrics.js.map +1 -1
- package/dist/runtime/readable.js.map +1 -1
- package/dist/runtime/resource-cell.js +3 -2
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/scheduler.d.ts +0 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +6 -19
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector.d.ts.map +1 -1
- package/dist/runtime/selector.js +6 -4
- package/dist/runtime/selector.js.map +1 -1
- package/dist/runtime/snapshot-source.d.ts +10 -0
- package/dist/runtime/snapshot-source.d.ts.map +1 -0
- package/dist/runtime/snapshot-source.js +17 -0
- package/dist/runtime/snapshot-source.js.map +1 -0
- package/dist/runtime/ssr-bridge.js.map +1 -1
- package/dist/runtime/state.d.ts.map +1 -1
- package/dist/runtime/state.js +1 -5
- package/dist/runtime/state.js.map +1 -1
- package/dist/ssg/batch-render.js.map +1 -1
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/generate-metadata.js.map +1 -1
- package/dist/ssg/incremental-manifest.js.map +1 -1
- package/dist/ssg/resolve-ssg-data.js.map +1 -1
- package/dist/ssg/route-utils.js.map +1 -1
- package/dist/ssg/write-static-files.js.map +1 -1
- package/dist/ssr/attrs.js.map +1 -1
- package/dist/ssr/context.d.ts +1 -0
- package/dist/ssr/context.d.ts.map +1 -1
- package/dist/ssr/context.js +3 -0
- package/dist/ssr/context.js.map +1 -1
- package/dist/ssr/escape.js +56 -16
- package/dist/ssr/escape.js.map +1 -1
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +15 -3
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/render-keys.js.map +1 -1
- package/dist/ssr/sink.js.map +1 -1
- package/dist/ssr/stream-render.js +14 -2
- package/dist/ssr/stream-render.js.map +1 -1
- package/package.json +8 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controllable.js","names":[],"sources":["../../../src/foundations/state/controllable.ts"],"sourcesContent":["/**\n * controllable\n *\n * Small utilities for controlled vs uncontrolled components. These helpers are\n * intentionally minimal and do not manage state themselves; they help component\n * implementations make correct decisions about when to call `onChange` vs\n * update internal state.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Controlled Detection\n * A value is \"controlled\" if it is not `undefined`.\n * This matches React conventions and is SSR-safe.\n *\n * 2. onChange Timing\n * - Controlled mode: onChange called immediately, no internal update\n * - Uncontrolled mode: internal state updated first, then onChange called\n * This ensures onChange sees the new value in both modes.\n *\n * 3. Value Equality\n * controllableState uses Object.is() to prevent unnecessary onChange calls.\n * This is intentional — strict equality, no deep comparison.\n */\n\nimport { state, type State } from '../../runtime/state';\n\nexport function isControlled<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n\nexport function resolveControllable<T>(\n value: T | undefined,\n defaultValue: T\n): { value: T; isControlled: boolean } {\n const controlled = isControlled(value);\n return {\n value: controlled ? (value as T) : defaultValue,\n isControlled: controlled,\n };\n}\n\nexport function makeControllable<T>(options: {\n value: T | undefined;\n defaultValue: T;\n onChange?: (next: T) => void;\n setInternal?: (next: T) => void;\n}) {\n const { value, defaultValue, onChange, setInternal } = options;\n const { isControlled } = resolveControllable(value, defaultValue);\n\n function set(next: T) {\n if (isControlled) {\n onChange?.(next);\n } else {\n setInternal?.(next);\n onChange?.(next);\n }\n }\n\n return { set, isControlled };\n}\n\nexport type ControllableState<T> = State<T> & { isControlled: boolean };\n\n/**\n * controllableState\n *\n * Hook-like primitive that mirrors `state()` semantics while supporting\n * controlled/uncontrolled behavior.\n */\nexport function controllableState<T>(options: {\n value: T | undefined;\n defaultValue: T;\n onChange?: (next: T) => void;\n}): ControllableState<T> {\n const isControlled = options.value !== undefined;\n const internal = isControlled ? null : state<T>(options.defaultValue);\n\n function read(): T {\n if (isControlled) {\n return options.value as T;\n }\n\n return internal!();\n }\n\n read.set = (nextOrUpdater: T | ((prev: T) => T)) => {\n const prev = read();\n const next =\n typeof nextOrUpdater === 'function'\n ? (nextOrUpdater as (p: T) => T)(prev)\n : (nextOrUpdater as T);\n\n if (Object.is(prev, next)) return;\n\n if (isControlled) {\n options.onChange?.(next);\n return;\n }\n\n internal!.set(nextOrUpdater as never);\n options.onChange?.(next);\n };\n\n (read as ControllableState<T>).isControlled = isControlled;\n return read as ControllableState<T>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,aAAgB,OAAkC;
|
|
1
|
+
{"version":3,"file":"controllable.js","names":[],"sources":["../../../src/foundations/state/controllable.ts"],"sourcesContent":["/**\n * controllable\n *\n * Small utilities for controlled vs uncontrolled components. These helpers are\n * intentionally minimal and do not manage state themselves; they help component\n * implementations make correct decisions about when to call `onChange` vs\n * update internal state.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Controlled Detection\n * A value is \"controlled\" if it is not `undefined`.\n * This matches React conventions and is SSR-safe.\n *\n * 2. onChange Timing\n * - Controlled mode: onChange called immediately, no internal update\n * - Uncontrolled mode: internal state updated first, then onChange called\n * This ensures onChange sees the new value in both modes.\n *\n * 3. Value Equality\n * controllableState uses Object.is() to prevent unnecessary onChange calls.\n * This is intentional — strict equality, no deep comparison.\n */\n\nimport { state, type State } from '../../runtime/state';\n\nexport function isControlled<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n\nexport function resolveControllable<T>(\n value: T | undefined,\n defaultValue: T\n): { value: T; isControlled: boolean } {\n const controlled = isControlled(value);\n return {\n value: controlled ? (value as T) : defaultValue,\n isControlled: controlled,\n };\n}\n\nexport function makeControllable<T>(options: {\n value: T | undefined;\n defaultValue: T;\n onChange?: (next: T) => void;\n setInternal?: (next: T) => void;\n}) {\n const { value, defaultValue, onChange, setInternal } = options;\n const { isControlled } = resolveControllable(value, defaultValue);\n\n function set(next: T) {\n if (isControlled) {\n onChange?.(next);\n } else {\n setInternal?.(next);\n onChange?.(next);\n }\n }\n\n return { set, isControlled };\n}\n\nexport type ControllableState<T> = State<T> & { isControlled: boolean };\n\n/**\n * controllableState\n *\n * Hook-like primitive that mirrors `state()` semantics while supporting\n * controlled/uncontrolled behavior.\n */\nexport function controllableState<T>(options: {\n value: T | undefined;\n defaultValue: T;\n onChange?: (next: T) => void;\n}): ControllableState<T> {\n const isControlled = options.value !== undefined;\n const internal = isControlled ? null : state<T>(options.defaultValue);\n\n function read(): T {\n if (isControlled) {\n return options.value as T;\n }\n\n return internal!();\n }\n\n read.set = (nextOrUpdater: T | ((prev: T) => T)) => {\n const prev = read();\n const next =\n typeof nextOrUpdater === 'function'\n ? (nextOrUpdater as (p: T) => T)(prev)\n : (nextOrUpdater as T);\n\n if (Object.is(prev, next)) return;\n\n if (isControlled) {\n options.onChange?.(next);\n return;\n }\n\n internal!.set(nextOrUpdater as never);\n options.onChange?.(next);\n };\n\n (read as ControllableState<T>).isControlled = isControlled;\n return read as ControllableState<T>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,aAAgB,OAAkC;CAChE,OAAO,UAAU;;AAGnB,SAAgB,oBACd,OACA,cACqC;CACrC,MAAM,aAAa,aAAa,MAAM;CACtC,OAAO;EACL,OAAO,aAAc,QAAc;EACnC,cAAc;EACf;;AAGH,SAAgB,iBAAoB,SAKjC;CACD,MAAM,EAAE,OAAO,cAAc,UAAU,gBAAgB;CACvD,MAAM,EAAE,iBAAiB,oBAAoB,OAAO,aAAa;CAEjE,SAAS,IAAI,MAAS;EACpB,IAAI,cACF,WAAW,KAAK;OACX;GACL,cAAc,KAAK;GACnB,WAAW,KAAK;;;CAIpB,OAAO;EAAE;EAAK;EAAc;;;;;;;;AAW9B,SAAgB,kBAAqB,SAIZ;CACvB,MAAM,eAAe,QAAQ,UAAU;CACvC,MAAM,WAAW,eAAe,OAAO,MAAS,QAAQ,aAAa;CAErE,SAAS,OAAU;EACjB,IAAI,cACF,OAAO,QAAQ;EAGjB,OAAO,UAAW;;CAGpB,KAAK,OAAO,kBAAwC;EAClD,MAAM,OAAO,MAAM;EACnB,MAAM,OACJ,OAAO,kBAAkB,aACpB,cAA8B,KAAK,GACnC;EAEP,IAAI,OAAO,GAAG,MAAM,KAAK,EAAE;EAE3B,IAAI,cAAc;GAChB,QAAQ,WAAW,KAAK;GACxB;;EAGF,SAAU,IAAI,cAAuB;EACrC,QAAQ,WAAW,KAAK;;CAG1B,KAA+B,eAAe;CAC9C,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.js","names":[],"sources":["../../../src/foundations/structures/collection.ts"],"sourcesContent":["/**\n * createCollection\n *\n * Ordered descendant registry for coordinating items without DOM queries.\n *\n * INVARIANTS:\n * 1. Registration order determines item order (no DOM queries)\n * 2. Stable ordering across renders (insertion order preserved)\n * 3. Each item may have metadata (type-safe, user-defined)\n * 4. No implicit global state (explicit collection instances)\n * 5. No automatic cleanup (caller controls lifecycle)\n *\n * DESIGN:\n * - Returns a registry API ({ register, items, clear })\n * - Items are stored in insertion order\n * - Registration returns an unregister function\n * - No side effects on registration (pure data structure)\n *\n * USAGE:\n * const collection = createCollection<HTMLElement, { disabled: boolean }>();\n * const unregister = collection.register(element, { disabled: false });\n * const allItems = collection.items();\n * unregister();\n */\n\nexport type CollectionItem<TNode, TMetadata = unknown> = {\n node: TNode;\n metadata: TMetadata;\n};\n\nexport interface Collection<TNode, TMetadata = unknown> {\n /**\n * Register a node with optional metadata.\n * Returns an unregister function.\n */\n register(node: TNode, metadata: TMetadata): () => void;\n\n /**\n * Get all registered items in insertion order.\n */\n items(): ReadonlyArray<CollectionItem<TNode, TMetadata>>;\n\n /**\n * Clear all registered items.\n */\n clear(): void;\n\n /**\n * Get the count of registered items.\n */\n size(): number;\n}\n\nexport function createCollection<TNode, TMetadata = unknown>(): Collection<\n TNode,\n TMetadata\n> {\n const registry = new Map<TNode, CollectionItem<TNode, TMetadata>>();\n\n function register(node: TNode, metadata: TMetadata): () => void {\n const item: CollectionItem<TNode, TMetadata> = { node, metadata };\n registry.set(node, item);\n\n return () => {\n registry.delete(node);\n };\n }\n\n function items(): ReadonlyArray<CollectionItem<TNode, TMetadata>> {\n return Array.from(registry.values());\n }\n\n function clear(): void {\n registry.clear();\n }\n\n function size(): number {\n return registry.size;\n }\n\n return {\n register,\n items,\n clear,\n size,\n };\n}\n\n/**\n * USAGE EXAMPLE:\n *\n * // Create a collection for menu items\n * const menuItems = createCollection<HTMLElement, { disabled: boolean }>();\n *\n * // Register items\n * const unregister1 = menuItems.register(element1, { disabled: false });\n * const unregister2 = menuItems.register(element2, { disabled: true });\n *\n * // Query items\n * const allItems = menuItems.items();\n * const enabledItems = allItems.filter(item => !item.metadata.disabled);\n *\n * // Cleanup\n * unregister1();\n * unregister2();\n */\n"],"mappings":";AAqDA,SAAgB,mBAGd;CACA,MAAM,2BAAW,IAAI,KAA8C;CAEnE,SAAS,SAAS,MAAa,UAAiC;EAC9D,MAAM,OAAyC;GAAE;GAAM;GAAU;
|
|
1
|
+
{"version":3,"file":"collection.js","names":[],"sources":["../../../src/foundations/structures/collection.ts"],"sourcesContent":["/**\n * createCollection\n *\n * Ordered descendant registry for coordinating items without DOM queries.\n *\n * INVARIANTS:\n * 1. Registration order determines item order (no DOM queries)\n * 2. Stable ordering across renders (insertion order preserved)\n * 3. Each item may have metadata (type-safe, user-defined)\n * 4. No implicit global state (explicit collection instances)\n * 5. No automatic cleanup (caller controls lifecycle)\n *\n * DESIGN:\n * - Returns a registry API ({ register, items, clear })\n * - Items are stored in insertion order\n * - Registration returns an unregister function\n * - No side effects on registration (pure data structure)\n *\n * USAGE:\n * const collection = createCollection<HTMLElement, { disabled: boolean }>();\n * const unregister = collection.register(element, { disabled: false });\n * const allItems = collection.items();\n * unregister();\n */\n\nexport type CollectionItem<TNode, TMetadata = unknown> = {\n node: TNode;\n metadata: TMetadata;\n};\n\nexport interface Collection<TNode, TMetadata = unknown> {\n /**\n * Register a node with optional metadata.\n * Returns an unregister function.\n */\n register(node: TNode, metadata: TMetadata): () => void;\n\n /**\n * Get all registered items in insertion order.\n */\n items(): ReadonlyArray<CollectionItem<TNode, TMetadata>>;\n\n /**\n * Clear all registered items.\n */\n clear(): void;\n\n /**\n * Get the count of registered items.\n */\n size(): number;\n}\n\nexport function createCollection<TNode, TMetadata = unknown>(): Collection<\n TNode,\n TMetadata\n> {\n const registry = new Map<TNode, CollectionItem<TNode, TMetadata>>();\n\n function register(node: TNode, metadata: TMetadata): () => void {\n const item: CollectionItem<TNode, TMetadata> = { node, metadata };\n registry.set(node, item);\n\n return () => {\n registry.delete(node);\n };\n }\n\n function items(): ReadonlyArray<CollectionItem<TNode, TMetadata>> {\n return Array.from(registry.values());\n }\n\n function clear(): void {\n registry.clear();\n }\n\n function size(): number {\n return registry.size;\n }\n\n return {\n register,\n items,\n clear,\n size,\n };\n}\n\n/**\n * USAGE EXAMPLE:\n *\n * // Create a collection for menu items\n * const menuItems = createCollection<HTMLElement, { disabled: boolean }>();\n *\n * // Register items\n * const unregister1 = menuItems.register(element1, { disabled: false });\n * const unregister2 = menuItems.register(element2, { disabled: true });\n *\n * // Query items\n * const allItems = menuItems.items();\n * const enabledItems = allItems.filter(item => !item.metadata.disabled);\n *\n * // Cleanup\n * unregister1();\n * unregister2();\n */\n"],"mappings":";AAqDA,SAAgB,mBAGd;CACA,MAAM,2BAAW,IAAI,KAA8C;CAEnE,SAAS,SAAS,MAAa,UAAiC;EAC9D,MAAM,OAAyC;GAAE;GAAM;GAAU;EACjE,SAAS,IAAI,MAAM,KAAK;EAExB,aAAa;GACX,SAAS,OAAO,KAAK;;;CAIzB,SAAS,QAAyD;EAChE,OAAO,MAAM,KAAK,SAAS,QAAQ,CAAC;;CAGtC,SAAS,QAAc;EACrB,SAAS,OAAO;;CAGlB,SAAS,OAAe;EACtB,OAAO,SAAS;;CAGlB,OAAO;EACL;EACA;EACA;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer.js","names":[],"sources":["../../../src/foundations/structures/layer.ts"],"sourcesContent":["/**\n * createLayer\n *\n * Manages stacking order and coordination for overlays (modals, popovers, etc).\n *\n * INVARIANTS:\n * 1. Layers are ordered by registration time (FIFO)\n * 2. Only the top layer handles Escape key\n * 3. Only the top layer handles outside pointer events\n * 4. Nested layers are supported\n * 5. Does not implement portals (orthogonal concern)\n * 6. No automatic DOM insertion (caller controls mounting)\n *\n * DESIGN:\n * - Returns a layer manager with register/unregister API\n * - Each layer has a unique ID and can query if it's the top layer\n * - Escape and outside pointer coordination via callbacks\n * - No z-index management (CSS concern)\n *\n * USAGE:\n * const manager = createLayer();\n *\n * const layer = manager.register({\n * onEscape: () => { ... },\n * onOutsidePointer: () => { ... }\n * });\n *\n * layer.isTop(); // true if this is the topmost layer\n * layer.unregister();\n */\n\nexport interface LayerOptions {\n /**\n * Called when Escape is pressed and this is the top layer\n */\n onEscape?: () => void;\n\n /**\n * Called when pointer event occurs outside and this is the top layer\n */\n onOutsidePointer?: (e: PointerEvent) => void;\n\n /**\n * Optional node reference for outside pointer detection\n */\n node?: Node | null;\n}\n\nexport interface Layer {\n /**\n * Unique layer ID\n */\n id: number;\n\n /**\n * Check if this layer is the topmost\n */\n isTop(): boolean;\n\n /**\n * Remove this layer from the stack\n */\n unregister(): void;\n}\n\nexport interface LayerManager {\n /**\n * Register a new layer\n */\n register(options: LayerOptions): Layer;\n\n /**\n * Get all active layers in order\n */\n layers(): ReadonlyArray<Layer>;\n\n /**\n * Manually trigger escape handling on the top layer\n */\n handleEscape(): void;\n\n /**\n * Manually trigger outside pointer handling on the top layer\n */\n handleOutsidePointer(e: PointerEvent): void;\n}\n\nexport function createLayer(): LayerManager {\n const stack: Array<{\n id: number;\n options: LayerOptions;\n }> = [];\n\n let nextId = 1;\n\n function register(options: LayerOptions): Layer {\n const id = nextId++;\n const entry = { id, options };\n stack.push(entry);\n\n function isTop(): boolean {\n return stack[stack.length - 1]?.id === id;\n }\n\n function unregister(): void {\n const index = stack.findIndex((e) => e.id === id);\n if (index !== -1) {\n stack.splice(index, 1);\n }\n }\n\n return {\n id,\n isTop,\n unregister,\n };\n }\n\n function layers(): ReadonlyArray<Layer> {\n return stack.map((entry) => ({\n id: entry.id,\n isTop: () => stack[stack.length - 1]?.id === entry.id,\n unregister: () => {\n const index = stack.findIndex((e) => e.id === entry.id);\n if (index !== -1) {\n stack.splice(index, 1);\n }\n },\n }));\n }\n\n function handleEscape(): void {\n const top = stack[stack.length - 1];\n if (top) {\n top.options.onEscape?.();\n }\n }\n\n function handleOutsidePointer(e: PointerEvent): void {\n const top = stack[stack.length - 1];\n if (!top) return;\n\n const node = top.options.node;\n if (node && e.target instanceof Node) {\n // Check if the event target is outside the layer node\n if (!node.contains(e.target)) {\n top.options.onOutsidePointer?.(e);\n }\n } else {\n // No node provided, always trigger\n top.options.onOutsidePointer?.(e);\n }\n }\n\n return {\n register,\n layers,\n handleEscape,\n handleOutsidePointer,\n };\n}\n\n/**\n * USAGE EXAMPLE:\n *\n * const layerManager = createLayer();\n *\n * function Modal({ onClose }) {\n * const modalRef = ref<HTMLDivElement>();\n *\n * const layer = layerManager.register({\n * node: modalRef.current,\n * onEscape: onClose,\n * onOutsidePointer: onClose,\n * });\n *\n * onUnmount(() => layer.unregister());\n *\n * return (\n * <div ref={modalRef}>\n * <h1>Modal</h1>\n * {layer.isTop() && <p>I am on top!</p>}\n * </div>\n * );\n * }\n */\n"],"mappings":";AAuFA,SAAgB,cAA4B;CAC1C,MAAM,QAGD,EAAE;CAEP,IAAI,SAAS;CAEb,SAAS,SAAS,SAA8B;EAC9C,MAAM,KAAK;EACX,MAAM,QAAQ;GAAE;GAAI;GAAS;
|
|
1
|
+
{"version":3,"file":"layer.js","names":[],"sources":["../../../src/foundations/structures/layer.ts"],"sourcesContent":["/**\n * createLayer\n *\n * Manages stacking order and coordination for overlays (modals, popovers, etc).\n *\n * INVARIANTS:\n * 1. Layers are ordered by registration time (FIFO)\n * 2. Only the top layer handles Escape key\n * 3. Only the top layer handles outside pointer events\n * 4. Nested layers are supported\n * 5. Does not implement portals (orthogonal concern)\n * 6. No automatic DOM insertion (caller controls mounting)\n *\n * DESIGN:\n * - Returns a layer manager with register/unregister API\n * - Each layer has a unique ID and can query if it's the top layer\n * - Escape and outside pointer coordination via callbacks\n * - No z-index management (CSS concern)\n *\n * USAGE:\n * const manager = createLayer();\n *\n * const layer = manager.register({\n * onEscape: () => { ... },\n * onOutsidePointer: () => { ... }\n * });\n *\n * layer.isTop(); // true if this is the topmost layer\n * layer.unregister();\n */\n\nexport interface LayerOptions {\n /**\n * Called when Escape is pressed and this is the top layer\n */\n onEscape?: () => void;\n\n /**\n * Called when pointer event occurs outside and this is the top layer\n */\n onOutsidePointer?: (e: PointerEvent) => void;\n\n /**\n * Optional node reference for outside pointer detection\n */\n node?: Node | null;\n}\n\nexport interface Layer {\n /**\n * Unique layer ID\n */\n id: number;\n\n /**\n * Check if this layer is the topmost\n */\n isTop(): boolean;\n\n /**\n * Remove this layer from the stack\n */\n unregister(): void;\n}\n\nexport interface LayerManager {\n /**\n * Register a new layer\n */\n register(options: LayerOptions): Layer;\n\n /**\n * Get all active layers in order\n */\n layers(): ReadonlyArray<Layer>;\n\n /**\n * Manually trigger escape handling on the top layer\n */\n handleEscape(): void;\n\n /**\n * Manually trigger outside pointer handling on the top layer\n */\n handleOutsidePointer(e: PointerEvent): void;\n}\n\nexport function createLayer(): LayerManager {\n const stack: Array<{\n id: number;\n options: LayerOptions;\n }> = [];\n\n let nextId = 1;\n\n function register(options: LayerOptions): Layer {\n const id = nextId++;\n const entry = { id, options };\n stack.push(entry);\n\n function isTop(): boolean {\n return stack[stack.length - 1]?.id === id;\n }\n\n function unregister(): void {\n const index = stack.findIndex((e) => e.id === id);\n if (index !== -1) {\n stack.splice(index, 1);\n }\n }\n\n return {\n id,\n isTop,\n unregister,\n };\n }\n\n function layers(): ReadonlyArray<Layer> {\n return stack.map((entry) => ({\n id: entry.id,\n isTop: () => stack[stack.length - 1]?.id === entry.id,\n unregister: () => {\n const index = stack.findIndex((e) => e.id === entry.id);\n if (index !== -1) {\n stack.splice(index, 1);\n }\n },\n }));\n }\n\n function handleEscape(): void {\n const top = stack[stack.length - 1];\n if (top) {\n top.options.onEscape?.();\n }\n }\n\n function handleOutsidePointer(e: PointerEvent): void {\n const top = stack[stack.length - 1];\n if (!top) return;\n\n const node = top.options.node;\n if (node && e.target instanceof Node) {\n // Check if the event target is outside the layer node\n if (!node.contains(e.target)) {\n top.options.onOutsidePointer?.(e);\n }\n } else {\n // No node provided, always trigger\n top.options.onOutsidePointer?.(e);\n }\n }\n\n return {\n register,\n layers,\n handleEscape,\n handleOutsidePointer,\n };\n}\n\n/**\n * USAGE EXAMPLE:\n *\n * const layerManager = createLayer();\n *\n * function Modal({ onClose }) {\n * const modalRef = ref<HTMLDivElement>();\n *\n * const layer = layerManager.register({\n * node: modalRef.current,\n * onEscape: onClose,\n * onOutsidePointer: onClose,\n * });\n *\n * onUnmount(() => layer.unregister());\n *\n * return (\n * <div ref={modalRef}>\n * <h1>Modal</h1>\n * {layer.isTop() && <p>I am on top!</p>}\n * </div>\n * );\n * }\n */\n"],"mappings":";AAuFA,SAAgB,cAA4B;CAC1C,MAAM,QAGD,EAAE;CAEP,IAAI,SAAS;CAEb,SAAS,SAAS,SAA8B;EAC9C,MAAM,KAAK;EACX,MAAM,QAAQ;GAAE;GAAI;GAAS;EAC7B,MAAM,KAAK,MAAM;EAEjB,SAAS,QAAiB;GACxB,OAAO,MAAM,MAAM,SAAS,IAAI,OAAO;;EAGzC,SAAS,aAAmB;GAC1B,MAAM,QAAQ,MAAM,WAAW,MAAM,EAAE,OAAO,GAAG;GACjD,IAAI,UAAU,IACZ,MAAM,OAAO,OAAO,EAAE;;EAI1B,OAAO;GACL;GACA;GACA;GACD;;CAGH,SAAS,SAA+B;EACtC,OAAO,MAAM,KAAK,WAAW;GAC3B,IAAI,MAAM;GACV,aAAa,MAAM,MAAM,SAAS,IAAI,OAAO,MAAM;GACnD,kBAAkB;IAChB,MAAM,QAAQ,MAAM,WAAW,MAAM,EAAE,OAAO,MAAM,GAAG;IACvD,IAAI,UAAU,IACZ,MAAM,OAAO,OAAO,EAAE;;GAG3B,EAAE;;CAGL,SAAS,eAAqB;EAC5B,MAAM,MAAM,MAAM,MAAM,SAAS;EACjC,IAAI,KACF,IAAI,QAAQ,YAAY;;CAI5B,SAAS,qBAAqB,GAAuB;EACnD,MAAM,MAAM,MAAM,MAAM,SAAS;EACjC,IAAI,CAAC,KAAK;EAEV,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,QAAQ,EAAE,kBAAkB,MAE9B;OAAI,CAAC,KAAK,SAAS,EAAE,OAAO,EAC1B,IAAI,QAAQ,mBAAmB,EAAE;SAInC,IAAI,QAAQ,mBAAmB,EAAE;;CAIrC,OAAO;EACL;EACA;EACA;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","names":[],"sources":["../../../src/foundations/structures/layout.tsx"],"sourcesContent":["/**\n * Layout helper.\n *\n * A layout is just a normal component that wraps children.\n * Persistence and reuse are handled by the runtime via component identity.\n *\n * This helper exists purely for readability and convention.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Return Type is Opaque (unknown)\n * Layout components return `unknown` to remain runtime-agnostic.\n * The runtime owns concrete JSX element types.\n *\n * 2. Children Positioning\n * Layout receives children as first argument (router-friendly).\n * Props come second. This matches route layout conventions where\n * children represent the nested route content.\n *\n * 3. Props Spreading\n * Props are spread into the layout component. This is intentional\n * and deterministic — no merging or composition.\n */\n\nexport type LayoutComponent<P = object> = (\n props: P & { children?: unknown }\n) => unknown;\n\nexport function layout<P = object>(Layout: LayoutComponent<P>) {\n return (children?: unknown, props?: P) => {\n const mergedProps = { ...props, children } as P & { children?: unknown };\n return Layout(mergedProps);\n };\n}\n"],"mappings":";AA4BA,SAAgB,OAAmB,QAA4B;
|
|
1
|
+
{"version":3,"file":"layout.js","names":[],"sources":["../../../src/foundations/structures/layout.tsx"],"sourcesContent":["/**\n * Layout helper.\n *\n * A layout is just a normal component that wraps children.\n * Persistence and reuse are handled by the runtime via component identity.\n *\n * This helper exists purely for readability and convention.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Return Type is Opaque (unknown)\n * Layout components return `unknown` to remain runtime-agnostic.\n * The runtime owns concrete JSX element types.\n *\n * 2. Children Positioning\n * Layout receives children as first argument (router-friendly).\n * Props come second. This matches route layout conventions where\n * children represent the nested route content.\n *\n * 3. Props Spreading\n * Props are spread into the layout component. This is intentional\n * and deterministic — no merging or composition.\n */\n\nexport type LayoutComponent<P = object> = (\n props: P & { children?: unknown }\n) => unknown;\n\nexport function layout<P = object>(Layout: LayoutComponent<P>) {\n return (children?: unknown, props?: P) => {\n const mergedProps = { ...props, children } as P & { children?: unknown };\n return Layout(mergedProps);\n };\n}\n"],"mappings":";AA4BA,SAAgB,OAAmB,QAA4B;CAC7D,QAAQ,UAAoB,UAAc;EAExC,OAAO,OAAO;GADQ,GAAG;GAAO;GAClB,CAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.js","names":[],"sources":["../../../src/foundations/structures/portal.tsx"],"sourcesContent":["/**\n * Portal / Host primitive.\n *\n * Foundations remain runtime-agnostic: a portal is an explicit read/write slot.\n * Scheduling and attachment are owned by the runtime when `createPortalSlot`\n * exists; otherwise this falls back to a local slot (deterministic, but does\n * not schedule updates).\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Local Mutable State\n * Foundations may use local mutable state ONLY to model deterministic slots,\n * never to coordinate timing, effects, or ordering. The fallback mode uses\n * closure-local `mounted` and `value` variables which are non-escaping and\n * deterministic.\n *\n * 2. Return Type Philosophy\n * Portal call signatures return `unknown` (intentionally opaque). The runtime\n * owns the concrete type. This prevents foundations from assuming JSX.Element\n * or DOM node types, maintaining runtime-agnostic portability.\n */\n\nimport {\n markReactivePropsDirtySource,\n markReadableDerivedSubscribersDirty,\n notifyReadableReaders,\n recordReadableRead,\n type ReadableSource,\n} from '../../runtime/readable';\n\nexport interface Portal<T = unknown> {\n /** Mount point — rendered exactly once */\n (): unknown;\n\n /** Render content into the portal */\n render(props: { children?: T }): unknown;\n}\n\nexport interface PortalProps {\n children?: unknown;\n}\n\nfunction createPortalSlot<T>(): {\n read(): unknown;\n write(value: T | undefined): void;\n} {\n let currentValue: T | undefined;\n\n const source = (() => {\n recordReadableRead(source);\n return currentValue;\n }) as ReadableSource<T | undefined>;\n\n return {\n read() {\n return source();\n },\n write(value: T | undefined) {\n if (Object.is(currentValue, value)) {\n return;\n }\n\n currentValue = value;\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n },\n };\n}\n\nexport function definePortal<T = unknown>(): Portal<T> {\n // Using `typeof createPortalSlot` is safe even if the identifier is not\n // defined at runtime (it returns 'undefined' rather than throwing).\n if (typeof createPortalSlot === 'function') {\n const slot = createPortalSlot<T>();\n\n function PortalHost() {\n return slot.read();\n }\n\n PortalHost.render = function PortalRender(props: { children?: T }) {\n slot.write(props.children);\n return null;\n };\n\n return PortalHost as Portal<T>;\n }\n\n // Deterministic local fallback (SSR/tests). No runtime scheduling.\n // Writes are accepted only after the host has rendered at least once.\n //\n // CRITICAL BEHAVIOR:\n // - Writes update local state but do NOT trigger re-renders\n // - The portal host will reflect changes only when the component tree\n // re-renders for other reasons (e.g., parent state change)\n // - This is safe for SSR and tests where rendering is synchronous\n // and externally controlled\n // - In runtime mode, createPortalSlot handles scheduling automatically\n let mounted = false;\n let value: T | undefined;\n\n function PortalHostFallback() {\n mounted = true;\n return value as unknown;\n }\n\n PortalHostFallback.render = function PortalRenderFallback(props: {\n children?: T;\n }) {\n if (!mounted) return null;\n value = props.children;\n return null;\n };\n\n return PortalHostFallback as Portal<T>;\n}\n\n/**\n * Default Portal Singleton\n *\n * POLICY (LOCKED):\n * There is exactly one default portal per runtime.\n * Tests must reset it explicitly using _resetDefaultPortal().\n * This ensures consistent portal behavior across the application\n * while maintaining test isolation.\n */\nlet _defaultPortal: Portal<unknown> | undefined;\n\nexport function _resetDefaultPortal(): void {\n _defaultPortal = undefined;\n}\n\nfunction ensureDefaultPortal(): Portal<unknown> {\n if (!_defaultPortal) _defaultPortal = definePortal<unknown>();\n return _defaultPortal;\n}\n\nexport const DefaultPortal: Portal<unknown> = (() => {\n function Host() {\n const v = ensureDefaultPortal()();\n return v === undefined ? null : v;\n }\n Host.render = function Render(props: { children?: unknown }) {\n ensureDefaultPortal().render(props);\n return null;\n };\n return Host as Portal<unknown>;\n})();\n\nexport function Portal(props: PortalProps): null {\n DefaultPortal.render(props);\n return null;\n}\n\n/**\n * NOTE:\n * createPortalSlot is a runtime primitive.\n * It owns scheduling, consistency, and SSR behavior.\n */\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAS,mBAGP;CACA,IAAI;CAEJ,MAAM,gBAAgB;
|
|
1
|
+
{"version":3,"file":"portal.js","names":[],"sources":["../../../src/foundations/structures/portal.tsx"],"sourcesContent":["/**\n * Portal / Host primitive.\n *\n * Foundations remain runtime-agnostic: a portal is an explicit read/write slot.\n * Scheduling and attachment are owned by the runtime when `createPortalSlot`\n * exists; otherwise this falls back to a local slot (deterministic, but does\n * not schedule updates).\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Local Mutable State\n * Foundations may use local mutable state ONLY to model deterministic slots,\n * never to coordinate timing, effects, or ordering. The fallback mode uses\n * closure-local `mounted` and `value` variables which are non-escaping and\n * deterministic.\n *\n * 2. Return Type Philosophy\n * Portal call signatures return `unknown` (intentionally opaque). The runtime\n * owns the concrete type. This prevents foundations from assuming JSX.Element\n * or DOM node types, maintaining runtime-agnostic portability.\n */\n\nimport {\n markReactivePropsDirtySource,\n markReadableDerivedSubscribersDirty,\n notifyReadableReaders,\n recordReadableRead,\n type ReadableSource,\n} from '../../runtime/readable';\n\nexport interface Portal<T = unknown> {\n /** Mount point — rendered exactly once */\n (): unknown;\n\n /** Render content into the portal */\n render(props: { children?: T }): unknown;\n}\n\nexport interface PortalProps {\n children?: unknown;\n}\n\nfunction createPortalSlot<T>(): {\n read(): unknown;\n write(value: T | undefined): void;\n} {\n let currentValue: T | undefined;\n\n const source = (() => {\n recordReadableRead(source);\n return currentValue;\n }) as ReadableSource<T | undefined>;\n\n return {\n read() {\n return source();\n },\n write(value: T | undefined) {\n if (Object.is(currentValue, value)) {\n return;\n }\n\n currentValue = value;\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n },\n };\n}\n\nexport function definePortal<T = unknown>(): Portal<T> {\n // Using `typeof createPortalSlot` is safe even if the identifier is not\n // defined at runtime (it returns 'undefined' rather than throwing).\n if (typeof createPortalSlot === 'function') {\n const slot = createPortalSlot<T>();\n\n function PortalHost() {\n return slot.read();\n }\n\n PortalHost.render = function PortalRender(props: { children?: T }) {\n slot.write(props.children);\n return null;\n };\n\n return PortalHost as Portal<T>;\n }\n\n // Deterministic local fallback (SSR/tests). No runtime scheduling.\n // Writes are accepted only after the host has rendered at least once.\n //\n // CRITICAL BEHAVIOR:\n // - Writes update local state but do NOT trigger re-renders\n // - The portal host will reflect changes only when the component tree\n // re-renders for other reasons (e.g., parent state change)\n // - This is safe for SSR and tests where rendering is synchronous\n // and externally controlled\n // - In runtime mode, createPortalSlot handles scheduling automatically\n let mounted = false;\n let value: T | undefined;\n\n function PortalHostFallback() {\n mounted = true;\n return value as unknown;\n }\n\n PortalHostFallback.render = function PortalRenderFallback(props: {\n children?: T;\n }) {\n if (!mounted) return null;\n value = props.children;\n return null;\n };\n\n return PortalHostFallback as Portal<T>;\n}\n\n/**\n * Default Portal Singleton\n *\n * POLICY (LOCKED):\n * There is exactly one default portal per runtime.\n * Tests must reset it explicitly using _resetDefaultPortal().\n * This ensures consistent portal behavior across the application\n * while maintaining test isolation.\n */\nlet _defaultPortal: Portal<unknown> | undefined;\n\nexport function _resetDefaultPortal(): void {\n _defaultPortal = undefined;\n}\n\nfunction ensureDefaultPortal(): Portal<unknown> {\n if (!_defaultPortal) _defaultPortal = definePortal<unknown>();\n return _defaultPortal;\n}\n\nexport const DefaultPortal: Portal<unknown> = (() => {\n function Host() {\n const v = ensureDefaultPortal()();\n return v === undefined ? null : v;\n }\n Host.render = function Render(props: { children?: unknown }) {\n ensureDefaultPortal().render(props);\n return null;\n };\n return Host as Portal<unknown>;\n})();\n\nexport function Portal(props: PortalProps): null {\n DefaultPortal.render(props);\n return null;\n}\n\n/**\n * NOTE:\n * createPortalSlot is a runtime primitive.\n * It owns scheduling, consistency, and SSR behavior.\n */\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAS,mBAGP;CACA,IAAI;CAEJ,MAAM,gBAAgB;EACpB,mBAAmB,OAAO;EAC1B,OAAO;;CAGT,OAAO;EACL,OAAO;GACL,OAAO,QAAQ;;EAEjB,MAAM,OAAsB;GAC1B,IAAI,OAAO,GAAG,cAAc,MAAM,EAChC;GAGF,eAAe;GACf,oCAAoC,OAAO;GAC3C,6BAA6B,OAAO;GACpC,sBAAsB,OAAO;;EAEhC;;AAGH,SAAgB,eAAuC;CAGrD,IAAI,OAAO,qBAAqB,YAAY;EAC1C,MAAM,OAAO,kBAAqB;EAElC,SAAS,aAAa;GACpB,OAAO,KAAK,MAAM;;EAGpB,WAAW,SAAS,SAAS,aAAa,OAAyB;GACjE,KAAK,MAAM,MAAM,SAAS;GAC1B,OAAO;;EAGT,OAAO;;CAaT,IAAI,UAAU;CACd,IAAI;CAEJ,SAAS,qBAAqB;EAC5B,UAAU;EACV,OAAO;;CAGT,mBAAmB,SAAS,SAAS,qBAAqB,OAEvD;EACD,IAAI,CAAC,SAAS,OAAO;EACrB,QAAQ,MAAM;EACd,OAAO;;CAGT,OAAO;;;;;;;;;;;AAYT,IAAI;AAMJ,SAAS,sBAAuC;CAC9C,IAAI,CAAC,gBAAgB,iBAAiB,cAAuB;CAC7D,OAAO;;AAGT,MAAa,uBAAwC;CACnD,SAAS,OAAO;EACd,MAAM,IAAI,qBAAqB,EAAE;EACjC,OAAO,MAAM,SAAY,OAAO;;CAElC,KAAK,SAAS,SAAS,OAAO,OAA+B;EAC3D,qBAAqB,CAAC,OAAO,MAAM;EACnC,OAAO;;CAET,OAAO;IACL;AAEJ,SAAgB,OAAO,OAA0B;CAC/C,cAAc,OAAO,MAAM;CAC3B,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence.js","names":[],"sources":["../../../src/foundations/structures/presence.ts"],"sourcesContent":["import { ELEMENT_TYPE, Fragment } from '../../jsx';\nimport type { JSXElement } from '../../jsx';\n\nexport interface PresenceProps {\n present: boolean | (() => boolean);\n children?: unknown;\n}\n\n/**\n * Presence\n *\n * Structural policy primitive for conditional mount/unmount.\n * - No timers\n * - No animation coupling\n * - No DOM side-effects\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Present as Function\n * Accepts boolean OR function to support lazy evaluation patterns.\n * Function is called once per render. Use boolean form for static values.\n *\n * 2. Children Type\n * `children` is intentionally `unknown` to remain runtime-agnostic.\n * The runtime owns child normalization and validation.\n *\n * 3. Immediate Mount/Unmount\n * No exit animations or transitions. When `present` becomes false,\n * children are removed immediately. Animation must be layered above\n * this primitive.\n */\nexport function Presence({\n present,\n children,\n}: PresenceProps): JSXElement | null {\n const isPresent =\n typeof present === 'function' ? present() : Boolean(present);\n if (!isPresent) return null;\n\n const element: JSXElement = {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children },\n key: null,\n };\n return element;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,SAAS,EACvB,SACA,YACmC;
|
|
1
|
+
{"version":3,"file":"presence.js","names":[],"sources":["../../../src/foundations/structures/presence.ts"],"sourcesContent":["import { ELEMENT_TYPE, Fragment } from '../../jsx';\nimport type { JSXElement } from '../../jsx';\n\nexport interface PresenceProps {\n present: boolean | (() => boolean);\n children?: unknown;\n}\n\n/**\n * Presence\n *\n * Structural policy primitive for conditional mount/unmount.\n * - No timers\n * - No animation coupling\n * - No DOM side-effects\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Present as Function\n * Accepts boolean OR function to support lazy evaluation patterns.\n * Function is called once per render. Use boolean form for static values.\n *\n * 2. Children Type\n * `children` is intentionally `unknown` to remain runtime-agnostic.\n * The runtime owns child normalization and validation.\n *\n * 3. Immediate Mount/Unmount\n * No exit animations or transitions. When `present` becomes false,\n * children are removed immediately. Animation must be layered above\n * this primitive.\n */\nexport function Presence({\n present,\n children,\n}: PresenceProps): JSXElement | null {\n const isPresent =\n typeof present === 'function' ? present() : Boolean(present);\n if (!isPresent) return null;\n\n const element: JSXElement = {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children },\n key: null,\n };\n return element;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,SAAS,EACvB,SACA,YACmC;CAGnC,IAAI,EADF,OAAO,YAAY,aAAa,SAAS,GAAG,QAAQ,QAAQ,GAC9C,OAAO;CAQvB,OAAO;EALL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU;EACnB,KAAK;EAEA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot.js","names":[],"sources":["../../../src/foundations/structures/slot.tsx"],"sourcesContent":["import { Fragment, cloneElement, isElement, ELEMENT_TYPE } from '../../jsx';\nimport type { JSXElement } from '../../jsx';\n\nexport type SlotProps =\n | {\n asChild: true;\n children: JSXElement;\n [key: string]: unknown;\n }\n | {\n asChild?: false;\n children?: unknown;\n };\n\n/**\n * Slot\n *\n * Structural primitive for prop forwarding patterns.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. asChild Pattern\n * When asChild=true, merges props into the single child element.\n * Child must be a valid JSXElement; non-element children return null.\n * **Slot props override child props** (injection pattern).\n *\n * 2. Fallback Behavior\n * When asChild=false, returns a Fragment (structural no-op).\n * No DOM element is introduced.\n *\n * 3. Type Safety\n * asChild=true requires exactly one JSXElement child (enforced by type).\n * Runtime validates with isElement() check.\n */\nexport function Slot(props: SlotProps): JSXElement | null {\n if (props.asChild) {\n const { children, asChild: _asChild, ...rest } = props;\n\n if (isElement(children)) {\n return cloneElement(children, rest);\n }\n return null;\n }\n\n // Structural no-op: Slot does not introduce DOM\n // Return a vnode object for the fragment with the internal element marker.\n const element: JSXElement = {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: props.children },\n key: null,\n };\n return element;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,KAAK,OAAqC;
|
|
1
|
+
{"version":3,"file":"slot.js","names":[],"sources":["../../../src/foundations/structures/slot.tsx"],"sourcesContent":["import { Fragment, cloneElement, isElement, ELEMENT_TYPE } from '../../jsx';\nimport type { JSXElement } from '../../jsx';\n\nexport type SlotProps =\n | {\n asChild: true;\n children: JSXElement;\n [key: string]: unknown;\n }\n | {\n asChild?: false;\n children?: unknown;\n };\n\n/**\n * Slot\n *\n * Structural primitive for prop forwarding patterns.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. asChild Pattern\n * When asChild=true, merges props into the single child element.\n * Child must be a valid JSXElement; non-element children return null.\n * **Slot props override child props** (injection pattern).\n *\n * 2. Fallback Behavior\n * When asChild=false, returns a Fragment (structural no-op).\n * No DOM element is introduced.\n *\n * 3. Type Safety\n * asChild=true requires exactly one JSXElement child (enforced by type).\n * Runtime validates with isElement() check.\n */\nexport function Slot(props: SlotProps): JSXElement | null {\n if (props.asChild) {\n const { children, asChild: _asChild, ...rest } = props;\n\n if (isElement(children)) {\n return cloneElement(children, rest);\n }\n return null;\n }\n\n // Structural no-op: Slot does not introduce DOM\n // Return a vnode object for the fragment with the internal element marker.\n const element: JSXElement = {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: props.children },\n key: null,\n };\n return element;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,KAAK,OAAqC;CACxD,IAAI,MAAM,SAAS;EACjB,MAAM,EAAE,UAAU,SAAS,UAAU,GAAG,SAAS;EAEjD,IAAI,UAAU,SAAS,EACrB,OAAO,aAAa,UAAU,KAAK;EAErC,OAAO;;CAWT,OAAO;EALL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,MAAM,UAAU;EACnC,KAAK;EAEA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aria.js","names":[],"sources":["../../../src/foundations/utilities/aria.ts"],"sourcesContent":["/**\n * Tiny aria helpers\n */\n\nexport function ariaDisabled(disabled?: boolean): { 'aria-disabled'?: 'true' } {\n return disabled ? { 'aria-disabled': 'true' } : {};\n}\n\nexport function ariaExpanded(expanded?: boolean): {\n 'aria-expanded'?: 'true' | 'false';\n} {\n return expanded === undefined\n ? {}\n : { 'aria-expanded': String(expanded) as 'true' | 'false' };\n}\n\nexport function ariaSelected(selected?: boolean): {\n 'aria-selected'?: 'true' | 'false';\n} {\n return selected === undefined\n ? {}\n : { 'aria-selected': String(selected) as 'true' | 'false' };\n}\n"],"mappings":";;;;AAIA,SAAgB,aAAa,UAAkD;
|
|
1
|
+
{"version":3,"file":"aria.js","names":[],"sources":["../../../src/foundations/utilities/aria.ts"],"sourcesContent":["/**\n * Tiny aria helpers\n */\n\nexport function ariaDisabled(disabled?: boolean): { 'aria-disabled'?: 'true' } {\n return disabled ? { 'aria-disabled': 'true' } : {};\n}\n\nexport function ariaExpanded(expanded?: boolean): {\n 'aria-expanded'?: 'true' | 'false';\n} {\n return expanded === undefined\n ? {}\n : { 'aria-expanded': String(expanded) as 'true' | 'false' };\n}\n\nexport function ariaSelected(selected?: boolean): {\n 'aria-selected'?: 'true' | 'false';\n} {\n return selected === undefined\n ? {}\n : { 'aria-selected': String(selected) as 'true' | 'false' };\n}\n"],"mappings":";;;;AAIA,SAAgB,aAAa,UAAkD;CAC7E,OAAO,WAAW,EAAE,iBAAiB,QAAQ,GAAG,EAAE;;AAGpD,SAAgB,aAAa,UAE3B;CACA,OAAO,aAAa,SAChB,EAAE,GACF,EAAE,iBAAiB,OAAO,SAAS,EAAsB;;AAG/D,SAAgB,aAAa,UAE3B;CACA,OAAO,aAAa,SAChB,EAAE,GACF,EAAE,iBAAiB,OAAO,SAAS,EAAsB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-handlers.js","names":[],"sources":["../../../src/foundations/utilities/compose-handlers.ts"],"sourcesContent":["/**\n * composeHandlers\n *\n * Compose two event handlers into one. The first handler runs, and unless it\n * calls `event.preventDefault()` (or sets `defaultPrevented`), the second\n * handler runs. This prevents accidental clobbering of child handlers when\n * injecting props.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Execution Order\n * First handler runs before second (injected before base).\n * This allows injected handlers to prevent default behavior.\n *\n * 2. Default Prevention Check\n * By default, checks `defaultPrevented` on first argument.\n * Can be disabled via options.checkDefaultPrevented = false.\n *\n * 3. Undefined Handler Support\n * Undefined handlers are skipped (no-op). This simplifies usage\n * where handlers are optional.\n *\n * 4. Type Safety\n * Args are readonly to prevent mutation. Return type matches input.\n */\n\nexport interface ComposeHandlersOptions {\n /**\n * When true (default), do not run the second handler if the first prevented default.\n * When false, always run both handlers.\n */\n checkDefaultPrevented?: boolean;\n}\n\nfunction isDefaultPrevented(\n value: unknown\n): value is { defaultPrevented: true } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'defaultPrevented' in value &&\n (value as { defaultPrevented?: boolean }).defaultPrevented === true\n );\n}\n\nexport function composeHandlers<A extends readonly unknown[]>(\n first?: (...args: A) => void,\n second?: (...args: A) => void,\n options?: ComposeHandlersOptions\n): (...args: A) => void {\n // Fast path: if neither handler exists, return stable no-op\n if (!first && !second) {\n return noop as (...args: A) => void;\n }\n\n // Fast path: if only one handler exists, return it directly\n if (!first) return second!;\n if (!second) return first;\n\n // Composition path: both handlers exist\n const checkDefaultPrevented = options?.checkDefaultPrevented !== false;\n\n return function composed(...args: A) {\n first(...args);\n\n if (checkDefaultPrevented && isDefaultPrevented(args[0])) {\n return;\n }\n\n second(...args);\n } as (...args: A) => void;\n}\n\n// Stable no-op for fast path\nfunction noop() {}\n"],"mappings":";AAkCA,SAAS,mBACP,OACqC;
|
|
1
|
+
{"version":3,"file":"compose-handlers.js","names":[],"sources":["../../../src/foundations/utilities/compose-handlers.ts"],"sourcesContent":["/**\n * composeHandlers\n *\n * Compose two event handlers into one. The first handler runs, and unless it\n * calls `event.preventDefault()` (or sets `defaultPrevented`), the second\n * handler runs. This prevents accidental clobbering of child handlers when\n * injecting props.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Execution Order\n * First handler runs before second (injected before base).\n * This allows injected handlers to prevent default behavior.\n *\n * 2. Default Prevention Check\n * By default, checks `defaultPrevented` on first argument.\n * Can be disabled via options.checkDefaultPrevented = false.\n *\n * 3. Undefined Handler Support\n * Undefined handlers are skipped (no-op). This simplifies usage\n * where handlers are optional.\n *\n * 4. Type Safety\n * Args are readonly to prevent mutation. Return type matches input.\n */\n\nexport interface ComposeHandlersOptions {\n /**\n * When true (default), do not run the second handler if the first prevented default.\n * When false, always run both handlers.\n */\n checkDefaultPrevented?: boolean;\n}\n\nfunction isDefaultPrevented(\n value: unknown\n): value is { defaultPrevented: true } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'defaultPrevented' in value &&\n (value as { defaultPrevented?: boolean }).defaultPrevented === true\n );\n}\n\nexport function composeHandlers<A extends readonly unknown[]>(\n first?: (...args: A) => void,\n second?: (...args: A) => void,\n options?: ComposeHandlersOptions\n): (...args: A) => void {\n // Fast path: if neither handler exists, return stable no-op\n if (!first && !second) {\n return noop as (...args: A) => void;\n }\n\n // Fast path: if only one handler exists, return it directly\n if (!first) return second!;\n if (!second) return first;\n\n // Composition path: both handlers exist\n const checkDefaultPrevented = options?.checkDefaultPrevented !== false;\n\n return function composed(...args: A) {\n first(...args);\n\n if (checkDefaultPrevented && isDefaultPrevented(args[0])) {\n return;\n }\n\n second(...args);\n } as (...args: A) => void;\n}\n\n// Stable no-op for fast path\nfunction noop() {}\n"],"mappings":";AAkCA,SAAS,mBACP,OACqC;CACrC,OACE,OAAO,UAAU,YACjB,UAAU,QACV,sBAAsB,SACrB,MAAyC,qBAAqB;;AAInE,SAAgB,gBACd,OACA,QACA,SACsB;CAEtB,IAAI,CAAC,SAAS,CAAC,QACb,OAAO;CAIT,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,CAAC,QAAQ,OAAO;CAGpB,MAAM,wBAAwB,SAAS,0BAA0B;CAEjE,OAAO,SAAS,SAAS,GAAG,MAAS;EACnC,MAAM,GAAG,KAAK;EAEd,IAAI,yBAAyB,mBAAmB,KAAK,GAAG,EACtD;EAGF,OAAO,GAAG,KAAK;;;AAKnB,SAAS,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-ref.js","names":[],"sources":["../../../src/foundations/utilities/compose-ref.ts"],"sourcesContent":["/**\n * Ref composition utilities\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Ref Types Supported\n * - Callback refs: (value: T | null) => void\n * - Object refs: { current: T | null }\n * - null/undefined (no-op)\n *\n * 2. Write Failure Handling\n * setRef catches write failures (readonly refs) and ignores them.\n * This is intentional — refs may be readonly in some contexts.\n *\n * 3. Composition Order\n * composeRefs applies refs in array order (left to right).\n * All refs are called even if one fails.\n */\n\nexport type Ref<T> =\n | ((value: T | null) => void)\n | { current: T | null }\n | null\n | undefined;\n\nexport function setRef<T>(ref: Ref<T>, value: T | null): void {\n if (!ref) return;\n if (typeof ref === 'function') {\n ref(value);\n return;\n }\n // Fast path: use Object.isExtensible check instead of try/catch for better performance\n if (Object.isExtensible(ref)) {\n (ref as { current: T | null }).current = value;\n }\n}\n\nexport function composeRefs<T>(\n ...refs: Array<Ref<T>>\n): (value: T | null) => void {\n return (value: T | null) => {\n for (const ref of refs) setRef(ref, value);\n };\n}\n"],"mappings":";AAyBA,SAAgB,OAAU,KAAa,OAAuB;
|
|
1
|
+
{"version":3,"file":"compose-ref.js","names":[],"sources":["../../../src/foundations/utilities/compose-ref.ts"],"sourcesContent":["/**\n * Ref composition utilities\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Ref Types Supported\n * - Callback refs: (value: T | null) => void\n * - Object refs: { current: T | null }\n * - null/undefined (no-op)\n *\n * 2. Write Failure Handling\n * setRef catches write failures (readonly refs) and ignores them.\n * This is intentional — refs may be readonly in some contexts.\n *\n * 3. Composition Order\n * composeRefs applies refs in array order (left to right).\n * All refs are called even if one fails.\n */\n\nexport type Ref<T> =\n | ((value: T | null) => void)\n | { current: T | null }\n | null\n | undefined;\n\nexport function setRef<T>(ref: Ref<T>, value: T | null): void {\n if (!ref) return;\n if (typeof ref === 'function') {\n ref(value);\n return;\n }\n // Fast path: use Object.isExtensible check instead of try/catch for better performance\n if (Object.isExtensible(ref)) {\n (ref as { current: T | null }).current = value;\n }\n}\n\nexport function composeRefs<T>(\n ...refs: Array<Ref<T>>\n): (value: T | null) => void {\n return (value: T | null) => {\n for (const ref of refs) setRef(ref, value);\n };\n}\n"],"mappings":";AAyBA,SAAgB,OAAU,KAAa,OAAuB;CAC5D,IAAI,CAAC,KAAK;CACV,IAAI,OAAO,QAAQ,YAAY;EAC7B,IAAI,MAAM;EACV;;CAGF,IAAI,OAAO,aAAa,IAAI,EAC1B,IAA+B,UAAU;;AAI7C,SAAgB,YACd,GAAG,MACwB;CAC3B,QAAQ,UAAoB;EAC1B,KAAK,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-props.js","names":[],"sources":["../../../src/foundations/utilities/merge-props.ts"],"sourcesContent":["/**\n * mergeProps\n *\n * Deterministic props merging.\n * - For non-handlers: `base` overwrites `injected`.\n * - For handlers present in both: handlers are composed with `injected` running\n * first; it may call `preventDefault()` to suppress the `base` handler.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Merge Strategy\n * Base props overwrite injected props (base wins).\n * Exception: Event handlers are composed, not overwritten.\n *\n * 2. Event Handler Detection\n * Keys starting with \"on\" are treated as event handlers.\n * This matches JSX conventions.\n *\n * 3. Handler Composition Order\n * Injected handler runs first, base handler second.\n * This allows injected handlers to prevent default.\n *\n * 4. Return Type\n * Returns intersection type (TInjected & TBase) for type safety.\n */\nimport { composeHandlers } from './compose-handlers';\n\ntype Fn = (...args: readonly unknown[]) => void;\n\nfunction isEventHandlerKey(key: string): boolean {\n return key.startsWith('on');\n}\n\nexport function mergeProps<TBase extends object, TInjected extends object>(\n base: TBase,\n injected: TInjected\n): TInjected & TBase {\n // Fast path: if base is empty, return injected as-is\n const baseKeys = Object.keys(base);\n if (baseKeys.length === 0) {\n return injected as TInjected & TBase;\n }\n\n const out = { ...(injected as object) } as TInjected & TBase;\n\n for (const key of baseKeys as Array<Extract<keyof TBase, string>>) {\n const baseValue = (base as Record<string, unknown>)[key];\n const injectedValue = (injected as Record<string, unknown>)[key];\n\n if (\n isEventHandlerKey(key) &&\n typeof baseValue === 'function' &&\n typeof injectedValue === 'function'\n ) {\n // Invariant: injected runs first; it may call preventDefault() to\n // suppress base behaviour.\n (out as Record<string, unknown>)[key] = composeHandlers(\n injectedValue as unknown as Fn,\n baseValue as unknown as Fn\n );\n continue;\n }\n\n (out as Record<string, unknown>)[key] = baseValue;\n }\n\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAS,kBAAkB,KAAsB;
|
|
1
|
+
{"version":3,"file":"merge-props.js","names":[],"sources":["../../../src/foundations/utilities/merge-props.ts"],"sourcesContent":["/**\n * mergeProps\n *\n * Deterministic props merging.\n * - For non-handlers: `base` overwrites `injected`.\n * - For handlers present in both: handlers are composed with `injected` running\n * first; it may call `preventDefault()` to suppress the `base` handler.\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Merge Strategy\n * Base props overwrite injected props (base wins).\n * Exception: Event handlers are composed, not overwritten.\n *\n * 2. Event Handler Detection\n * Keys starting with \"on\" are treated as event handlers.\n * This matches JSX conventions.\n *\n * 3. Handler Composition Order\n * Injected handler runs first, base handler second.\n * This allows injected handlers to prevent default.\n *\n * 4. Return Type\n * Returns intersection type (TInjected & TBase) for type safety.\n */\nimport { composeHandlers } from './compose-handlers';\n\ntype Fn = (...args: readonly unknown[]) => void;\n\nfunction isEventHandlerKey(key: string): boolean {\n return key.startsWith('on');\n}\n\nexport function mergeProps<TBase extends object, TInjected extends object>(\n base: TBase,\n injected: TInjected\n): TInjected & TBase {\n // Fast path: if base is empty, return injected as-is\n const baseKeys = Object.keys(base);\n if (baseKeys.length === 0) {\n return injected as TInjected & TBase;\n }\n\n const out = { ...(injected as object) } as TInjected & TBase;\n\n for (const key of baseKeys as Array<Extract<keyof TBase, string>>) {\n const baseValue = (base as Record<string, unknown>)[key];\n const injectedValue = (injected as Record<string, unknown>)[key];\n\n if (\n isEventHandlerKey(key) &&\n typeof baseValue === 'function' &&\n typeof injectedValue === 'function'\n ) {\n // Invariant: injected runs first; it may call preventDefault() to\n // suppress base behaviour.\n (out as Record<string, unknown>)[key] = composeHandlers(\n injectedValue as unknown as Fn,\n baseValue as unknown as Fn\n );\n continue;\n }\n\n (out as Record<string, unknown>)[key] = baseValue;\n }\n\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAS,kBAAkB,KAAsB;CAC/C,OAAO,IAAI,WAAW,KAAK;;AAG7B,SAAgB,WACd,MACA,UACmB;CAEnB,MAAM,WAAW,OAAO,KAAK,KAAK;CAClC,IAAI,SAAS,WAAW,GACtB,OAAO;CAGT,MAAM,MAAM,EAAE,GAAI,UAAqB;CAEvC,KAAK,MAAM,OAAO,UAAiD;EACjE,MAAM,YAAa,KAAiC;EACpD,MAAM,gBAAiB,SAAqC;EAE5D,IACE,kBAAkB,IAAI,IACtB,OAAO,cAAc,cACrB,OAAO,kBAAkB,YACzB;GAGA,IAAiC,OAAO,gBACtC,eACA,UACD;GACD;;EAGF,IAAiC,OAAO;;CAG1C,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-id.js","names":[],"sources":["../../../src/foundations/utilities/use-id.ts"],"sourcesContent":["export interface FormatIdOptions {\n /** Defaults to 'askr' */\n prefix?: string;\n /** Stable, caller-provided identity */\n id: string | number;\n}\n\n/**\n * formatId\n *\n * Formats a stable ID from a caller-provided identity.\n * - Pure and deterministic (no time/randomness/global counters)\n * - SSR-safe\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. No Auto-Generation\n * Caller must provide the `id`. No random/sequential generation.\n * This ensures determinism and SSR safety.\n *\n * 2. Format Convention\n * IDs are formatted as `{prefix}-{id}`.\n * Default prefix is \"askr\".\n *\n * 3. Type Coercion\n * Numbers are coerced to strings via String().\n * This is deterministic and consistent.\n */\nexport function formatId(options: FormatIdOptions): string {\n const prefix = options.prefix ?? 'askr';\n return `${prefix}-${String(options.id)}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,SAAS,SAAkC;
|
|
1
|
+
{"version":3,"file":"use-id.js","names":[],"sources":["../../../src/foundations/utilities/use-id.ts"],"sourcesContent":["export interface FormatIdOptions {\n /** Defaults to 'askr' */\n prefix?: string;\n /** Stable, caller-provided identity */\n id: string | number;\n}\n\n/**\n * formatId\n *\n * Formats a stable ID from a caller-provided identity.\n * - Pure and deterministic (no time/randomness/global counters)\n * - SSR-safe\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. No Auto-Generation\n * Caller must provide the `id`. No random/sequential generation.\n * This ensures determinism and SSR safety.\n *\n * 2. Format Convention\n * IDs are formatted as `{prefix}-{id}`.\n * Default prefix is \"askr\".\n *\n * 3. Type Coercion\n * Numbers are coerced to strings via String().\n * This is deterministic and consistent.\n */\nexport function formatId(options: FormatIdOptions): string {\n const prefix = options.prefix ?? 'askr';\n return `${prefix}-${String(options.id)}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,SAAS,SAAkC;CAEzD,OAAO,GADQ,QAAQ,UAAU,OAChB,GAAG,OAAO,QAAQ,GAAG"}
|
package/dist/fx/fx.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx.js","names":[],"sources":["../../src/fx/fx.ts"],"sourcesContent":["import { globalScheduler } from '../runtime/scheduler';\nimport { getCurrentComponentInstance } from '../runtime/component';\nimport { logger } from '../dev/logger';\nimport { noopEventListener, noopEventListenerWithFlush } from './noop';\n\nexport type CancelFn = () => void;\n\n// Platform-specific timer handle types\ntype TimeoutHandle = ReturnType<typeof setTimeout> | null;\n// rAF may fall back to setTimeout in some environments/tests, include both\ntype RafHandle =\n | ReturnType<typeof requestAnimationFrame>\n | ReturnType<typeof setTimeout>\n | null;\n// requestIdleCallback may be unavailable; allow setTimeout fallback handle\ntype IdleHandle =\n | ReturnType<typeof requestIdleCallback>\n | ReturnType<typeof setTimeout>\n | null;\n\nfunction throwIfDuringRender(): void {\n const inst = getCurrentComponentInstance();\n if (inst !== null) {\n throw new Error(\n '[Askr] calling FX handler during render is not allowed. Move calls to event handlers or effects.'\n );\n }\n}\n\n/**\n * Helper: schedule a user callback through the global scheduler\n */\nfunction enqueueUserCallback(fn: () => void) {\n globalScheduler.enqueue(() => {\n try {\n fn();\n } catch (err) {\n // Keep behavior consistent with other scheduler-queued work\n logger.error('[Askr] FX handler error:', err);\n }\n });\n}\n\n// ---------- Event handlers ----------\n\nexport function debounceEvent(\n ms: number,\n handler: EventListener,\n options?: { leading?: boolean; trailing?: boolean }\n): EventListener & { cancel(): void; flush(): void } {\n const { leading = false, trailing = true } = options || {};\n\n const inst = getCurrentComponentInstance();\n // On SSR, event handlers are inert\n if (inst && inst.ssr) {\n return noopEventListenerWithFlush;\n }\n\n let timeoutId: TimeoutHandle = null;\n let lastEvent: Event | null = null;\n let lastCallTime = 0;\n\n const debounced = function (this: unknown, ev: Event) {\n // Disallow using returned handler during render\n throwIfDuringRender();\n\n const now = Date.now();\n lastEvent = ev;\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (leading && now - lastCallTime >= ms) {\n enqueueUserCallback(() => handler.call(null, ev));\n lastCallTime = now;\n }\n\n if (trailing) {\n timeoutId = setTimeout(() => {\n // Schedule through scheduler\n if (lastEvent) {\n enqueueUserCallback(() => handler.call(null, lastEvent!));\n }\n timeoutId = null;\n lastCallTime = Date.now();\n }, ms);\n }\n } as EventListener & { cancel(): void; flush(): void };\n\n debounced.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastEvent = null;\n };\n\n debounced.flush = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n const ev = lastEvent;\n lastEvent = null;\n timeoutId = null;\n if (ev) enqueueUserCallback(() => handler.call(null, ev));\n }\n };\n\n // Auto-cleanup on component unmount\n if (inst) {\n (inst.cleanupFns ??= []).push(() => {\n debounced.cancel();\n });\n }\n\n return debounced;\n}\n\nexport function throttleEvent(\n ms: number,\n handler: EventListener,\n options?: { leading?: boolean; trailing?: boolean }\n): EventListener & { cancel(): void } {\n const { leading = true, trailing = true } = options || {};\n\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return noopEventListener;\n }\n\n let lastCallTime = 0;\n let timeoutId: TimeoutHandle = null;\n let lastEvent: Event | null = null;\n\n const throttled = function (this: unknown, ev: Event) {\n throwIfDuringRender();\n\n const now = Date.now();\n lastEvent = ev;\n\n if (leading && now - lastCallTime >= ms) {\n enqueueUserCallback(() => handler.call(null, ev));\n lastCallTime = now;\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n } else if (!leading && lastCallTime === 0) {\n lastCallTime = now;\n }\n\n if (trailing && timeoutId === null) {\n const wait = ms - (now - lastCallTime);\n timeoutId = setTimeout(\n () => {\n if (lastEvent)\n enqueueUserCallback(() => handler.call(null, lastEvent!));\n lastCallTime = Date.now();\n timeoutId = null;\n },\n Math.max(0, wait)\n );\n }\n } as EventListener & { cancel(): void };\n\n throttled.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastEvent = null;\n };\n\n if (inst) {\n (inst.cleanupFns ??= []).push(() => throttled.cancel());\n }\n\n return throttled;\n}\n\nexport function rafEvent(\n handler: EventListener\n): EventListener & { cancel(): void } {\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return noopEventListener;\n }\n\n let frameId: RafHandle = null;\n let lastEvent: Event | null = null;\n\n const scheduleFrame = () => {\n const rAF =\n typeof requestAnimationFrame !== 'undefined'\n ? requestAnimationFrame\n : (cb: FrameRequestCallback) => setTimeout(() => cb(Date.now()), 16);\n\n frameId = rAF(() => {\n frameId = null;\n if (lastEvent) {\n const ev = lastEvent;\n lastEvent = null;\n enqueueUserCallback(() => handler.call(null, ev));\n }\n });\n };\n\n const fn = function (this: unknown, ev: Event) {\n throwIfDuringRender();\n lastEvent = ev;\n if (frameId === null) scheduleFrame();\n } as EventListener & { cancel(): void };\n\n fn.cancel = () => {\n if (frameId !== null) {\n // If frameId is numeric and cancelAnimationFrame is available, use it;\n // otherwise fall back to clearTimeout for the setTimeout fallback.\n if (\n typeof cancelAnimationFrame !== 'undefined' &&\n typeof frameId === 'number'\n ) {\n cancelAnimationFrame(frameId);\n } else {\n clearTimeout(frameId as ReturnType<typeof setTimeout>);\n }\n frameId = null;\n }\n lastEvent = null;\n };\n\n if (inst) (inst.cleanupFns ??= []).push(() => fn.cancel());\n\n return fn;\n}\n\n// ---------- Scheduled work ----------\n\nexport function scheduleTimeout(ms: number, fn: () => void): CancelFn {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return () => {};\n }\n\n let id: TimeoutHandle = setTimeout(() => {\n id = null;\n enqueueUserCallback(fn);\n }, ms);\n\n const cancel = () => {\n if (id !== null) {\n clearTimeout(id);\n id = null;\n }\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return cancel;\n}\n\nexport function scheduleIdle(\n fn: () => void,\n options?: { timeout?: number }\n): CancelFn {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) return () => {};\n\n let id: IdleHandle = null;\n let usingRIC = false;\n\n if (typeof requestIdleCallback !== 'undefined') {\n usingRIC = true;\n id = requestIdleCallback(() => {\n id = null;\n enqueueUserCallback(fn);\n }, options);\n } else {\n // Fallback: schedule on next macrotask\n id = setTimeout(() => {\n id = null;\n enqueueUserCallback(fn);\n }, 0);\n }\n\n const cancel = () => {\n if (id !== null) {\n // If using requestIdleCallback and available, call cancelIdleCallback for numeric ids.\n if (\n usingRIC &&\n typeof cancelIdleCallback !== 'undefined' &&\n typeof id === 'number'\n ) {\n cancelIdleCallback(id);\n } else {\n clearTimeout(id as ReturnType<typeof setTimeout>);\n }\n id = null;\n }\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return cancel;\n}\n\nexport interface RetryOptions {\n maxAttempts?: number;\n delayMs?: number;\n backoff?: (attemptIndex: number) => number;\n}\n\nexport function scheduleRetry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): { cancel(): void } {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) return { cancel: () => {} };\n\n const {\n maxAttempts = 3,\n delayMs = 100,\n backoff = (i: number) => delayMs * Math.pow(2, i),\n } = options || {};\n\n let cancelled = false;\n\n const attempt = (index: number) => {\n if (cancelled) return;\n // Run user fn inside scheduler\n globalScheduler.enqueue(() => {\n if (cancelled) return;\n // Call fn (it may be async)\n const p = fn();\n p.then(\n () => {\n // Completed successfully\n },\n () => {\n if (cancelled) return;\n if (index + 1 < maxAttempts) {\n const delay = backoff(index);\n // Schedule next attempt via setTimeout so it gets enqueued through scheduleTimeout\n setTimeout(() => {\n attempt(index + 1);\n }, delay);\n }\n }\n ).catch((e) => {\n logger.error('[Askr] scheduleRetry error:', e);\n });\n });\n };\n\n // Start first attempt\n attempt(0);\n\n const cancel = () => {\n cancelled = true;\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return { cancel };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fx.js","names":[],"sources":["../../src/fx/fx.ts"],"sourcesContent":["import { globalScheduler } from '../runtime/scheduler';\nimport { getCurrentComponentInstance } from '../runtime/component';\nimport { logger } from '../dev/logger';\nimport { noopEventListener, noopEventListenerWithFlush } from './noop';\n\nexport type CancelFn = () => void;\n\n// Platform-specific timer handle types\ntype TimeoutHandle = ReturnType<typeof setTimeout> | null;\n// rAF may fall back to setTimeout in some environments/tests, include both\ntype RafHandle =\n | ReturnType<typeof requestAnimationFrame>\n | ReturnType<typeof setTimeout>\n | null;\n// requestIdleCallback may be unavailable; allow setTimeout fallback handle\ntype IdleHandle =\n | ReturnType<typeof requestIdleCallback>\n | ReturnType<typeof setTimeout>\n | null;\n\nfunction throwIfDuringRender(): void {\n const inst = getCurrentComponentInstance();\n if (inst !== null) {\n throw new Error(\n '[Askr] calling FX handler during render is not allowed. Move calls to event handlers or effects.'\n );\n }\n}\n\n/**\n * Helper: schedule a user callback through the global scheduler\n */\nfunction enqueueUserCallback(fn: () => void) {\n globalScheduler.enqueue(() => {\n try {\n fn();\n } catch (err) {\n // Keep behavior consistent with other scheduler-queued work\n logger.error('[Askr] FX handler error:', err);\n }\n });\n}\n\n// ---------- Event handlers ----------\n\nexport function debounceEvent(\n ms: number,\n handler: EventListener,\n options?: { leading?: boolean; trailing?: boolean }\n): EventListener & { cancel(): void; flush(): void } {\n const { leading = false, trailing = true } = options || {};\n\n const inst = getCurrentComponentInstance();\n // On SSR, event handlers are inert\n if (inst && inst.ssr) {\n return noopEventListenerWithFlush;\n }\n\n let timeoutId: TimeoutHandle = null;\n let lastEvent: Event | null = null;\n let lastCallTime = 0;\n\n const debounced = function (this: unknown, ev: Event) {\n // Disallow using returned handler during render\n throwIfDuringRender();\n\n const now = Date.now();\n lastEvent = ev;\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (leading && now - lastCallTime >= ms) {\n enqueueUserCallback(() => handler.call(null, ev));\n lastCallTime = now;\n }\n\n if (trailing) {\n timeoutId = setTimeout(() => {\n // Schedule through scheduler\n if (lastEvent) {\n enqueueUserCallback(() => handler.call(null, lastEvent!));\n }\n timeoutId = null;\n lastCallTime = Date.now();\n }, ms);\n }\n } as EventListener & { cancel(): void; flush(): void };\n\n debounced.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastEvent = null;\n };\n\n debounced.flush = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n const ev = lastEvent;\n lastEvent = null;\n timeoutId = null;\n if (ev) enqueueUserCallback(() => handler.call(null, ev));\n }\n };\n\n // Auto-cleanup on component unmount\n if (inst) {\n (inst.cleanupFns ??= []).push(() => {\n debounced.cancel();\n });\n }\n\n return debounced;\n}\n\nexport function throttleEvent(\n ms: number,\n handler: EventListener,\n options?: { leading?: boolean; trailing?: boolean }\n): EventListener & { cancel(): void } {\n const { leading = true, trailing = true } = options || {};\n\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return noopEventListener;\n }\n\n let lastCallTime = 0;\n let timeoutId: TimeoutHandle = null;\n let lastEvent: Event | null = null;\n\n const throttled = function (this: unknown, ev: Event) {\n throwIfDuringRender();\n\n const now = Date.now();\n lastEvent = ev;\n\n if (leading && now - lastCallTime >= ms) {\n enqueueUserCallback(() => handler.call(null, ev));\n lastCallTime = now;\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n } else if (!leading && lastCallTime === 0) {\n lastCallTime = now;\n }\n\n if (trailing && timeoutId === null) {\n const wait = ms - (now - lastCallTime);\n timeoutId = setTimeout(\n () => {\n if (lastEvent)\n enqueueUserCallback(() => handler.call(null, lastEvent!));\n lastCallTime = Date.now();\n timeoutId = null;\n },\n Math.max(0, wait)\n );\n }\n } as EventListener & { cancel(): void };\n\n throttled.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastEvent = null;\n };\n\n if (inst) {\n (inst.cleanupFns ??= []).push(() => throttled.cancel());\n }\n\n return throttled;\n}\n\nexport function rafEvent(\n handler: EventListener\n): EventListener & { cancel(): void } {\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return noopEventListener;\n }\n\n let frameId: RafHandle = null;\n let lastEvent: Event | null = null;\n\n const scheduleFrame = () => {\n const rAF =\n typeof requestAnimationFrame !== 'undefined'\n ? requestAnimationFrame\n : (cb: FrameRequestCallback) => setTimeout(() => cb(Date.now()), 16);\n\n frameId = rAF(() => {\n frameId = null;\n if (lastEvent) {\n const ev = lastEvent;\n lastEvent = null;\n enqueueUserCallback(() => handler.call(null, ev));\n }\n });\n };\n\n const fn = function (this: unknown, ev: Event) {\n throwIfDuringRender();\n lastEvent = ev;\n if (frameId === null) scheduleFrame();\n } as EventListener & { cancel(): void };\n\n fn.cancel = () => {\n if (frameId !== null) {\n // If frameId is numeric and cancelAnimationFrame is available, use it;\n // otherwise fall back to clearTimeout for the setTimeout fallback.\n if (\n typeof cancelAnimationFrame !== 'undefined' &&\n typeof frameId === 'number'\n ) {\n cancelAnimationFrame(frameId);\n } else {\n clearTimeout(frameId as ReturnType<typeof setTimeout>);\n }\n frameId = null;\n }\n lastEvent = null;\n };\n\n if (inst) (inst.cleanupFns ??= []).push(() => fn.cancel());\n\n return fn;\n}\n\n// ---------- Scheduled work ----------\n\nexport function scheduleTimeout(ms: number, fn: () => void): CancelFn {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) {\n return () => {};\n }\n\n let id: TimeoutHandle = setTimeout(() => {\n id = null;\n enqueueUserCallback(fn);\n }, ms);\n\n const cancel = () => {\n if (id !== null) {\n clearTimeout(id);\n id = null;\n }\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return cancel;\n}\n\nexport function scheduleIdle(\n fn: () => void,\n options?: { timeout?: number }\n): CancelFn {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) return () => {};\n\n let id: IdleHandle = null;\n let usingRIC = false;\n\n if (typeof requestIdleCallback !== 'undefined') {\n usingRIC = true;\n id = requestIdleCallback(() => {\n id = null;\n enqueueUserCallback(fn);\n }, options);\n } else {\n // Fallback: schedule on next macrotask\n id = setTimeout(() => {\n id = null;\n enqueueUserCallback(fn);\n }, 0);\n }\n\n const cancel = () => {\n if (id !== null) {\n // If using requestIdleCallback and available, call cancelIdleCallback for numeric ids.\n if (\n usingRIC &&\n typeof cancelIdleCallback !== 'undefined' &&\n typeof id === 'number'\n ) {\n cancelIdleCallback(id);\n } else {\n clearTimeout(id as ReturnType<typeof setTimeout>);\n }\n id = null;\n }\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return cancel;\n}\n\nexport interface RetryOptions {\n maxAttempts?: number;\n delayMs?: number;\n backoff?: (attemptIndex: number) => number;\n}\n\nexport function scheduleRetry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): { cancel(): void } {\n throwIfDuringRender();\n const inst = getCurrentComponentInstance();\n if (inst && inst.ssr) return { cancel: () => {} };\n\n const {\n maxAttempts = 3,\n delayMs = 100,\n backoff = (i: number) => delayMs * Math.pow(2, i),\n } = options || {};\n\n let cancelled = false;\n\n const attempt = (index: number) => {\n if (cancelled) return;\n // Run user fn inside scheduler\n globalScheduler.enqueue(() => {\n if (cancelled) return;\n // Call fn (it may be async)\n const p = fn();\n p.then(\n () => {\n // Completed successfully\n },\n () => {\n if (cancelled) return;\n if (index + 1 < maxAttempts) {\n const delay = backoff(index);\n // Schedule next attempt via setTimeout so it gets enqueued through scheduleTimeout\n setTimeout(() => {\n attempt(index + 1);\n }, delay);\n }\n }\n ).catch((e) => {\n logger.error('[Askr] scheduleRetry error:', e);\n });\n });\n };\n\n // Start first attempt\n attempt(0);\n\n const cancel = () => {\n cancelled = true;\n };\n\n if (inst) (inst.cleanupFns ??= []).push(cancel);\n return { cancel };\n}\n"],"mappings":";;;;;AAoBA,SAAS,sBAA4B;CAEnC,IADa,6BACT,KAAS,MACX,MAAM,IAAI,MACR,mGACD;;;;;AAOL,SAAS,oBAAoB,IAAgB;CAC3C,gBAAgB,cAAc;EAC5B,IAAI;GACF,IAAI;WACG,KAAK;GAEZ,OAAO,MAAM,4BAA4B,IAAI;;GAE/C;;AAKJ,SAAgB,cACd,IACA,SACA,SACmD;CACnD,MAAM,EAAE,UAAU,OAAO,WAAW,SAAS,WAAW,EAAE;CAE1D,MAAM,OAAO,6BAA6B;CAE1C,IAAI,QAAQ,KAAK,KACf,OAAO;CAGT,IAAI,YAA2B;CAC/B,IAAI,YAA0B;CAC9B,IAAI,eAAe;CAEnB,MAAM,YAAY,SAAyB,IAAW;EAEpD,qBAAqB;EAErB,MAAM,MAAM,KAAK,KAAK;EACtB,YAAY;EAEZ,IAAI,cAAc,MAAM;GACtB,aAAa,UAAU;GACvB,YAAY;;EAGd,IAAI,WAAW,MAAM,gBAAgB,IAAI;GACvC,0BAA0B,QAAQ,KAAK,MAAM,GAAG,CAAC;GACjD,eAAe;;EAGjB,IAAI,UACF,YAAY,iBAAiB;GAE3B,IAAI,WACF,0BAA0B,QAAQ,KAAK,MAAM,UAAW,CAAC;GAE3D,YAAY;GACZ,eAAe,KAAK,KAAK;KACxB,GAAG;;CAIV,UAAU,eAAe;EACvB,IAAI,cAAc,MAAM;GACtB,aAAa,UAAU;GACvB,YAAY;;EAEd,YAAY;;CAGd,UAAU,cAAc;EACtB,IAAI,cAAc,MAAM;GACtB,aAAa,UAAU;GACvB,MAAM,KAAK;GACX,YAAY;GACZ,YAAY;GACZ,IAAI,IAAI,0BAA0B,QAAQ,KAAK,MAAM,GAAG,CAAC;;;CAK7D,IAAI,MACF,CAAC,KAAK,eAAe,EAAE,EAAE,WAAW;EAClC,UAAU,QAAQ;GAClB;CAGJ,OAAO;;AAGT,SAAgB,cACd,IACA,SACA,SACoC;CACpC,MAAM,EAAE,UAAU,MAAM,WAAW,SAAS,WAAW,EAAE;CAEzD,MAAM,OAAO,6BAA6B;CAC1C,IAAI,QAAQ,KAAK,KACf,OAAO;CAGT,IAAI,eAAe;CACnB,IAAI,YAA2B;CAC/B,IAAI,YAA0B;CAE9B,MAAM,YAAY,SAAyB,IAAW;EACpD,qBAAqB;EAErB,MAAM,MAAM,KAAK,KAAK;EACtB,YAAY;EAEZ,IAAI,WAAW,MAAM,gBAAgB,IAAI;GACvC,0BAA0B,QAAQ,KAAK,MAAM,GAAG,CAAC;GACjD,eAAe;GACf,IAAI,cAAc,MAAM;IACtB,aAAa,UAAU;IACvB,YAAY;;SAET,IAAI,CAAC,WAAW,iBAAiB,GACtC,eAAe;EAGjB,IAAI,YAAY,cAAc,MAAM;GAClC,MAAM,OAAO,MAAM,MAAM;GACzB,YAAY,iBACJ;IACJ,IAAI,WACF,0BAA0B,QAAQ,KAAK,MAAM,UAAW,CAAC;IAC3D,eAAe,KAAK,KAAK;IACzB,YAAY;MAEd,KAAK,IAAI,GAAG,KAAK,CAClB;;;CAIL,UAAU,eAAe;EACvB,IAAI,cAAc,MAAM;GACtB,aAAa,UAAU;GACvB,YAAY;;EAEd,YAAY;;CAGd,IAAI,MACF,CAAC,KAAK,eAAe,EAAE,EAAE,WAAW,UAAU,QAAQ,CAAC;CAGzD,OAAO;;AAGT,SAAgB,SACd,SACoC;CACpC,MAAM,OAAO,6BAA6B;CAC1C,IAAI,QAAQ,KAAK,KACf,OAAO;CAGT,IAAI,UAAqB;CACzB,IAAI,YAA0B;CAE9B,MAAM,sBAAsB;EAM1B,WAJE,OAAO,0BAA0B,cAC7B,yBACC,OAA6B,iBAAiB,GAAG,KAAK,KAAK,CAAC,EAAE,GAAG,QAEpD;GAClB,UAAU;GACV,IAAI,WAAW;IACb,MAAM,KAAK;IACX,YAAY;IACZ,0BAA0B,QAAQ,KAAK,MAAM,GAAG,CAAC;;IAEnD;;CAGJ,MAAM,KAAK,SAAyB,IAAW;EAC7C,qBAAqB;EACrB,YAAY;EACZ,IAAI,YAAY,MAAM,eAAe;;CAGvC,GAAG,eAAe;EAChB,IAAI,YAAY,MAAM;GAGpB,IACE,OAAO,yBAAyB,eAChC,OAAO,YAAY,UAEnB,qBAAqB,QAAQ;QAE7B,aAAa,QAAyC;GAExD,UAAU;;EAEZ,YAAY;;CAGd,IAAI,MAAM,CAAC,KAAK,eAAe,EAAE,EAAE,WAAW,GAAG,QAAQ,CAAC;CAE1D,OAAO;;AAKT,SAAgB,gBAAgB,IAAY,IAA0B;CACpE,qBAAqB;CACrB,MAAM,OAAO,6BAA6B;CAC1C,IAAI,QAAQ,KAAK,KACf,aAAa;CAGf,IAAI,KAAoB,iBAAiB;EACvC,KAAK;EACL,oBAAoB,GAAG;IACtB,GAAG;CAEN,MAAM,eAAe;EACnB,IAAI,OAAO,MAAM;GACf,aAAa,GAAG;GAChB,KAAK;;;CAIT,IAAI,MAAM,CAAC,KAAK,eAAe,EAAE,EAAE,KAAK,OAAO;CAC/C,OAAO;;AAGT,SAAgB,aACd,IACA,SACU;CACV,qBAAqB;CACrB,MAAM,OAAO,6BAA6B;CAC1C,IAAI,QAAQ,KAAK,KAAK,aAAa;CAEnC,IAAI,KAAiB;CACrB,IAAI,WAAW;CAEf,IAAI,OAAO,wBAAwB,aAAa;EAC9C,WAAW;EACX,KAAK,0BAA0B;GAC7B,KAAK;GACL,oBAAoB,GAAG;KACtB,QAAQ;QAGX,KAAK,iBAAiB;EACpB,KAAK;EACL,oBAAoB,GAAG;IACtB,EAAE;CAGP,MAAM,eAAe;EACnB,IAAI,OAAO,MAAM;GAEf,IACE,YACA,OAAO,uBAAuB,eAC9B,OAAO,OAAO,UAEd,mBAAmB,GAAG;QAEtB,aAAa,GAAoC;GAEnD,KAAK;;;CAIT,IAAI,MAAM,CAAC,KAAK,eAAe,EAAE,EAAE,KAAK,OAAO;CAC/C,OAAO;;AAST,SAAgB,cACd,IACA,SACoB;CACpB,qBAAqB;CACrB,MAAM,OAAO,6BAA6B;CAC1C,IAAI,QAAQ,KAAK,KAAK,OAAO,EAAE,cAAc,IAAI;CAEjD,MAAM,EACJ,cAAc,GACd,UAAU,KACV,WAAW,MAAc,UAAU,KAAK,IAAI,GAAG,EAAE,KAC/C,WAAW,EAAE;CAEjB,IAAI,YAAY;CAEhB,MAAM,WAAW,UAAkB;EACjC,IAAI,WAAW;EAEf,gBAAgB,cAAc;GAC5B,IAAI,WAAW;GAGf,AADU,IACV,CAAE,WACM,UAGA;IACJ,IAAI,WAAW;IACf,IAAI,QAAQ,IAAI,aAAa;KAC3B,MAAM,QAAQ,QAAQ,MAAM;KAE5B,iBAAiB;MACf,QAAQ,QAAQ,EAAE;QACjB,MAAM;;KAGd,CAAC,OAAO,MAAM;IACb,OAAO,MAAM,+BAA+B,EAAE;KAC9C;IACF;;CAIJ,QAAQ,EAAE;CAEV,MAAM,eAAe;EACnB,YAAY;;CAGd,IAAI,MAAM,CAAC,KAAK,eAAe,EAAE,EAAE,KAAK,OAAO;CAC/C,OAAO,EAAE,QAAQ"}
|
package/dist/fx/timing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.js","names":[],"sources":["../../src/fx/timing.ts"],"sourcesContent":["/**\n * Timing utilities — pure helpers for common async patterns\n * No framework coupling. No lifecycle awareness.\n */\n\nexport interface DebounceOptions {\n leading?: boolean;\n trailing?: boolean;\n}\n\nexport interface ThrottleOptions {\n leading?: boolean;\n trailing?: boolean;\n}\n\nexport interface RetryOptions {\n maxAttempts?: number;\n delayMs?: number;\n backoff?: (attemptIndex: number) => number;\n}\n\n/**\n * Debounce — delay execution, coalesce rapid calls\n *\n * Useful for: text input, resize, autosave\n *\n * @param fn Function to debounce\n * @param ms Delay in milliseconds\n * @param options trailing (default true), leading\n * @returns Debounced function with cancel() method\n *\n * @example\n * ```ts\n * const save = debounce((text) => api.save(text), 500);\n * input.addEventListener('input', (e) => save(e.target.value));\n * save.cancel(); // stop any pending execution\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n fn: T,\n ms: number,\n options?: DebounceOptions\n): T & { cancel(): void } {\n let timeoutId: NodeJS.Timeout | null = null;\n const { leading = false, trailing = true } = options || {};\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n let lastCallTime = 0;\n\n const debounced = function (this: unknown, ...args: unknown[]) {\n const callTime = Date.now();\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n if (leading && callTime - lastCallTime >= ms) {\n fn.apply(this, args);\n lastCallTime = callTime;\n }\n\n if (trailing) {\n timeoutId = setTimeout(() => {\n fn.apply(lastThis, lastArgs!);\n timeoutId = null;\n lastCallTime = Date.now();\n }, ms);\n }\n };\n\n debounced.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n return debounced as T & { cancel(): void };\n}\n\n/**\n * Throttle — rate-limit execution, keep first/last\n *\n * Useful for: scroll, mouse move, high-frequency events\n *\n * @param fn Function to throttle\n * @param ms Minimum interval between calls in milliseconds\n * @param options leading (default true), trailing (default true)\n * @returns Throttled function with cancel() method\n *\n * @example\n * ```ts\n * const handleScroll = throttle(updateUI, 100);\n * window.addEventListener('scroll', handleScroll);\n * handleScroll.cancel();\n * ```\n */\nexport function throttle<T extends (...args: unknown[]) => unknown>(\n fn: T,\n ms: number,\n options?: ThrottleOptions\n): T & { cancel(): void } {\n let lastCallTime = 0;\n let timeoutId: NodeJS.Timeout | null = null;\n const { leading = true, trailing = true } = options || {};\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n\n const throttled = function (this: unknown, ...args: unknown[]) {\n const callTime = Date.now();\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (leading && callTime - lastCallTime >= ms) {\n fn.apply(this, args);\n lastCallTime = callTime;\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n } else if (!leading && lastCallTime === 0) {\n lastCallTime = callTime;\n }\n\n if (trailing && timeoutId === null) {\n timeoutId = setTimeout(\n () => {\n fn.apply(lastThis, lastArgs!);\n lastCallTime = Date.now();\n timeoutId = null;\n },\n ms - (callTime - lastCallTime)\n );\n }\n };\n\n throttled.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n return throttled as T & { cancel(): void };\n}\n\n/**\n * Once — guard against double execution\n *\n * Useful for: init logic, event safety\n *\n * @param fn Function to call at most once\n * @returns Function that executes fn only on first call\n *\n * @example\n * ```ts\n * const init = once(setup);\n * init(); // runs\n * init(); // does nothing\n * init(); // does nothing\n * ```\n */\nexport function once<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let called = false;\n let result: unknown;\n\n return ((...args: unknown[]) => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n }) as T;\n}\n\n/**\n * Defer — schedule on microtask queue\n *\n * Useful for: run-after-current-stack logic\n * More reliable than setTimeout(..., 0)\n *\n * @param fn Function to defer\n *\n * @example\n * ```ts\n * defer(() => update()); // runs after current stack, before next macrotask\n * ```\n */\nexport function defer(fn: () => void): void {\n Promise.resolve().then(fn);\n}\n\n/**\n * RAF — coalesce multiple updates into single frame\n *\n * Useful for: animation, layout work, render updates\n *\n * @param fn Function to schedule on next animation frame\n * @returns Function that schedules fn on requestAnimationFrame\n *\n * @example\n * ```ts\n * const update = raf(render);\n * update(); // schedules on next frame\n * update(); // same frame, no duplicate\n * ```\n */\nexport function raf<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let frameId: number | null = null;\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n\n return function (this: unknown, ...args: unknown[]) {\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (frameId === null) {\n frameId = requestAnimationFrame(() => {\n fn.apply(lastThis, lastArgs!);\n frameId = null;\n });\n }\n } as T;\n}\n\n/**\n * Idle — schedule low-priority work\n *\n * Useful for: background prep, non-urgent updates\n * Falls back to setTimeout if requestIdleCallback unavailable\n *\n * @param fn Function to call when idle\n * @param options timeout for fallback\n *\n * @example\n * ```ts\n * idle(() => prefetchData());\n * ```\n */\nexport function idle(fn: () => void, options?: { timeout?: number }): void {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(fn, options ? { timeout: options.timeout } : undefined);\n } else {\n // Fallback: defer to microtask, then use setTimeout\n Promise.resolve().then(() => {\n setTimeout(fn, 0);\n });\n }\n}\n\n/**\n * Timeout — Promise-based delay\n *\n * Useful for: readable async code, waiting between retries\n *\n * @param ms Milliseconds to wait\n * @returns Promise that resolves after delay\n *\n * @example\n * ```ts\n * await timeout(300);\n * console.log('300ms later');\n * ```\n */\nexport function timeout(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retry — attempt function with backoff\n *\n * Useful for: network calls, transient failures\n *\n * @param fn Async function to retry\n * @param options maxAttempts, delayMs, backoff function\n * @returns Promise with final result or error\n *\n * @example\n * ```ts\n * const data = await retry(() => fetch(url), {\n * maxAttempts: 3,\n * delayMs: 100,\n * });\n * ```\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): Promise<T> {\n const {\n maxAttempts = 3,\n delayMs = 100,\n backoff = (i: number) => delayMs * Math.pow(2, i),\n } = options || {};\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n if (attempt < maxAttempts - 1) {\n const delay = backoff(attempt);\n await timeout(delay);\n }\n }\n }\n\n throw lastError || new Error('Retry failed');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timing.js","names":[],"sources":["../../src/fx/timing.ts"],"sourcesContent":["/**\n * Timing utilities — pure helpers for common async patterns\n * No framework coupling. No lifecycle awareness.\n */\n\nexport interface DebounceOptions {\n leading?: boolean;\n trailing?: boolean;\n}\n\nexport interface ThrottleOptions {\n leading?: boolean;\n trailing?: boolean;\n}\n\nexport interface RetryOptions {\n maxAttempts?: number;\n delayMs?: number;\n backoff?: (attemptIndex: number) => number;\n}\n\n/**\n * Debounce — delay execution, coalesce rapid calls\n *\n * Useful for: text input, resize, autosave\n *\n * @param fn Function to debounce\n * @param ms Delay in milliseconds\n * @param options trailing (default true), leading\n * @returns Debounced function with cancel() method\n *\n * @example\n * ```ts\n * const save = debounce((text) => api.save(text), 500);\n * input.addEventListener('input', (e) => save(e.target.value));\n * save.cancel(); // stop any pending execution\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n fn: T,\n ms: number,\n options?: DebounceOptions\n): T & { cancel(): void } {\n let timeoutId: NodeJS.Timeout | null = null;\n const { leading = false, trailing = true } = options || {};\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n let lastCallTime = 0;\n\n const debounced = function (this: unknown, ...args: unknown[]) {\n const callTime = Date.now();\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n if (leading && callTime - lastCallTime >= ms) {\n fn.apply(this, args);\n lastCallTime = callTime;\n }\n\n if (trailing) {\n timeoutId = setTimeout(() => {\n fn.apply(lastThis, lastArgs!);\n timeoutId = null;\n lastCallTime = Date.now();\n }, ms);\n }\n };\n\n debounced.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n return debounced as T & { cancel(): void };\n}\n\n/**\n * Throttle — rate-limit execution, keep first/last\n *\n * Useful for: scroll, mouse move, high-frequency events\n *\n * @param fn Function to throttle\n * @param ms Minimum interval between calls in milliseconds\n * @param options leading (default true), trailing (default true)\n * @returns Throttled function with cancel() method\n *\n * @example\n * ```ts\n * const handleScroll = throttle(updateUI, 100);\n * window.addEventListener('scroll', handleScroll);\n * handleScroll.cancel();\n * ```\n */\nexport function throttle<T extends (...args: unknown[]) => unknown>(\n fn: T,\n ms: number,\n options?: ThrottleOptions\n): T & { cancel(): void } {\n let lastCallTime = 0;\n let timeoutId: NodeJS.Timeout | null = null;\n const { leading = true, trailing = true } = options || {};\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n\n const throttled = function (this: unknown, ...args: unknown[]) {\n const callTime = Date.now();\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (leading && callTime - lastCallTime >= ms) {\n fn.apply(this, args);\n lastCallTime = callTime;\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n } else if (!leading && lastCallTime === 0) {\n lastCallTime = callTime;\n }\n\n if (trailing && timeoutId === null) {\n timeoutId = setTimeout(\n () => {\n fn.apply(lastThis, lastArgs!);\n lastCallTime = Date.now();\n timeoutId = null;\n },\n ms - (callTime - lastCallTime)\n );\n }\n };\n\n throttled.cancel = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n return throttled as T & { cancel(): void };\n}\n\n/**\n * Once — guard against double execution\n *\n * Useful for: init logic, event safety\n *\n * @param fn Function to call at most once\n * @returns Function that executes fn only on first call\n *\n * @example\n * ```ts\n * const init = once(setup);\n * init(); // runs\n * init(); // does nothing\n * init(); // does nothing\n * ```\n */\nexport function once<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let called = false;\n let result: unknown;\n\n return ((...args: unknown[]) => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n }) as T;\n}\n\n/**\n * Defer — schedule on microtask queue\n *\n * Useful for: run-after-current-stack logic\n * More reliable than setTimeout(..., 0)\n *\n * @param fn Function to defer\n *\n * @example\n * ```ts\n * defer(() => update()); // runs after current stack, before next macrotask\n * ```\n */\nexport function defer(fn: () => void): void {\n Promise.resolve().then(fn);\n}\n\n/**\n * RAF — coalesce multiple updates into single frame\n *\n * Useful for: animation, layout work, render updates\n *\n * @param fn Function to schedule on next animation frame\n * @returns Function that schedules fn on requestAnimationFrame\n *\n * @example\n * ```ts\n * const update = raf(render);\n * update(); // schedules on next frame\n * update(); // same frame, no duplicate\n * ```\n */\nexport function raf<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let frameId: number | null = null;\n let lastArgs: unknown[] | null = null;\n let lastThis: unknown = null;\n\n return function (this: unknown, ...args: unknown[]) {\n lastArgs = args;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n lastThis = this;\n\n if (frameId === null) {\n frameId = requestAnimationFrame(() => {\n fn.apply(lastThis, lastArgs!);\n frameId = null;\n });\n }\n } as T;\n}\n\n/**\n * Idle — schedule low-priority work\n *\n * Useful for: background prep, non-urgent updates\n * Falls back to setTimeout if requestIdleCallback unavailable\n *\n * @param fn Function to call when idle\n * @param options timeout for fallback\n *\n * @example\n * ```ts\n * idle(() => prefetchData());\n * ```\n */\nexport function idle(fn: () => void, options?: { timeout?: number }): void {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(fn, options ? { timeout: options.timeout } : undefined);\n } else {\n // Fallback: defer to microtask, then use setTimeout\n Promise.resolve().then(() => {\n setTimeout(fn, 0);\n });\n }\n}\n\n/**\n * Timeout — Promise-based delay\n *\n * Useful for: readable async code, waiting between retries\n *\n * @param ms Milliseconds to wait\n * @returns Promise that resolves after delay\n *\n * @example\n * ```ts\n * await timeout(300);\n * console.log('300ms later');\n * ```\n */\nexport function timeout(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retry — attempt function with backoff\n *\n * Useful for: network calls, transient failures\n *\n * @param fn Async function to retry\n * @param options maxAttempts, delayMs, backoff function\n * @returns Promise with final result or error\n *\n * @example\n * ```ts\n * const data = await retry(() => fetch(url), {\n * maxAttempts: 3,\n * delayMs: 100,\n * });\n * ```\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): Promise<T> {\n const {\n maxAttempts = 3,\n delayMs = 100,\n backoff = (i: number) => delayMs * Math.pow(2, i),\n } = options || {};\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n if (attempt < maxAttempts - 1) {\n const delay = backoff(attempt);\n await timeout(delay);\n }\n }\n }\n\n throw lastError || new Error('Retry failed');\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,8 +16,8 @@ import { Derived, derive } from "./runtime/derive.js";
|
|
|
16
16
|
import { Selector, selector } from "./runtime/selector.js";
|
|
17
17
|
import { ResourceResult, resource } from "./runtime/operations.js";
|
|
18
18
|
import { Mutation, Query, QueryConsistency, createMutation, createQuery, invalidate } from "./data/index.js";
|
|
19
|
-
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes,
|
|
19
|
+
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes, route } from "./router/route.js";
|
|
20
20
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./router/policy.js";
|
|
21
21
|
import { Link, LinkProps } from "./components/link.js";
|
|
22
22
|
import { ErrorBoundary, ErrorBoundaryFallbackRender, ErrorBoundaryProps } from "./components/error-boundary.js";
|
|
23
|
-
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, Case, type CaseProps, type Context, DefaultPortal, type Derived, ErrorBoundary, type ErrorBoundaryFallbackRender, type ErrorBoundaryProps, For, type ForProps, Fragment, type GroupHelperOptions, type HistoryScrollBehavior, type HydrateSPAConfig, type IslandConfig, type IslandsConfig, Link, type LinkProps, Match, type MatchProps, type Mutation, type NavigateOptions, type NavigationScrollBehavior, Outlet, type PageHelperOptions, type PageScopeRecord, Portal, type PortalProps, type Props, type Query, type QueryConsistency, type RegisterRoutesOptions, type ResourceResult, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type SPAConfig, type ScrollRestorationOptions, type Selector, Show, type ShowProps, Slot, type SlotProps, type State, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole,
|
|
23
|
+
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, Case, type CaseProps, type Context, DefaultPortal, type Derived, ErrorBoundary, type ErrorBoundaryFallbackRender, type ErrorBoundaryProps, For, type ForProps, Fragment, type GroupHelperOptions, type HistoryScrollBehavior, type HydrateSPAConfig, type IslandConfig, type IslandsConfig, Link, type LinkProps, Match, type MatchProps, type Mutation, type NavigateOptions, type NavigationScrollBehavior, Outlet, type PageHelperOptions, type PageScopeRecord, Portal, type PortalProps, type Props, type Query, type QueryConsistency, type RegisterRoutesOptions, type ResourceResult, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type SPAConfig, type ScrollRestorationOptions, type Selector, Show, type ShowProps, Slot, type SlotProps, type State, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resource, route, selector, state, unauthorized };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { selector } from "./runtime/selector.js";
|
|
|
10
10
|
import { resource } from "./runtime/operations.js";
|
|
11
11
|
import { createMutation, createQuery, invalidate } from "./data/index.js";
|
|
12
12
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./router/policy.js";
|
|
13
|
-
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes,
|
|
13
|
+
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes, route } from "./router/route.js";
|
|
14
14
|
import { DefaultPortal, Portal, definePortal } from "./foundations/structures/portal.js";
|
|
15
15
|
import { navigate } from "./router/navigate.js";
|
|
16
16
|
import { cleanupApp, createIsland, createIslands, createSPA, hasApp, hydrateSPA } from "./boot/index.js";
|
|
@@ -31,6 +31,6 @@ import "./foundations/structures.js";
|
|
|
31
31
|
*/
|
|
32
32
|
installRendererBridge();
|
|
33
33
|
//#endregion
|
|
34
|
-
export { Case, DefaultPortal, ErrorBoundary, For, Fragment, Link, Match, Outlet, Portal, Show, Slot, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole,
|
|
34
|
+
export { Case, DefaultPortal, ErrorBoundary, For, Fragment, Link, Match, Outlet, Portal, Show, Slot, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resource, route, selector, state, unauthorized };
|
|
35
35
|
|
|
36
36
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Askr: Actor-backed deterministic UI framework\n *\n * Public API surface — only users should import from here\n */\n\nimport { installRendererBridge } from './renderer';\n\ninstallRendererBridge();\n\n// Runtime primitives\nexport { state } from './runtime/state';\nexport type { State } from './runtime/state';\nexport { derive } from './runtime/derive';\nexport type { Derived } from './runtime/derive';\nexport { getSignal } from './runtime/component';\nexport { selector } from './runtime/selector';\nexport type { Selector } from './runtime/selector';\n\n// Context\nexport { defineContext, readContext } from './runtime/context';\nexport type { Context } from './runtime/context';\n\n// Resources\nexport { resource } from './runtime/operations';\nexport type { ResourceResult } from './runtime/operations';\n\n// Data\nexport { createQuery, createMutation, invalidate } from './data';\nexport type { Query, Mutation, QueryConsistency } from './data';\n\n// App bootstrap\nexport {\n createIsland,\n createIslands,\n createSPA,\n hydrateSPA,\n cleanupApp,\n hasApp,\n} from './boot';\nexport type {\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n HydrateSPAConfig,\n} from './boot';\n\n// Routing\nexport {\n registerRoutes,\n route,\n page,\n index,\n Outlet,\n currentRoute,\n group,\n fallback,\n lazy,\n allow,\n redirect,\n deny,\n unauthorized,\n forbidden,\n notFound,\n requireAuth,\n requireRole,\n requirePermission,\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Askr: Actor-backed deterministic UI framework\n *\n * Public API surface — only users should import from here\n */\n\nimport { installRendererBridge } from './renderer';\n\ninstallRendererBridge();\n\n// Runtime primitives\nexport { state } from './runtime/state';\nexport type { State } from './runtime/state';\nexport { derive } from './runtime/derive';\nexport type { Derived } from './runtime/derive';\nexport { getSignal } from './runtime/component';\nexport { selector } from './runtime/selector';\nexport type { Selector } from './runtime/selector';\n\n// Context\nexport { defineContext, readContext } from './runtime/context';\nexport type { Context } from './runtime/context';\n\n// Resources\nexport { resource } from './runtime/operations';\nexport type { ResourceResult } from './runtime/operations';\n\n// Data\nexport { createQuery, createMutation, invalidate } from './data';\nexport type { Query, Mutation, QueryConsistency } from './data';\n\n// App bootstrap\nexport {\n createIsland,\n createIslands,\n createSPA,\n hydrateSPA,\n cleanupApp,\n hasApp,\n} from './boot';\nexport type {\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n HydrateSPAConfig,\n} from './boot';\n\n// Routing\nexport {\n registerRoutes,\n route,\n page,\n index,\n Outlet,\n currentRoute,\n group,\n fallback,\n lazy,\n allow,\n redirect,\n deny,\n unauthorized,\n forbidden,\n notFound,\n requireAuth,\n requireRole,\n requirePermission,\n type RouteSnapshot,\n type RouteMatch,\n type RouteComponent,\n type RouteMode,\n type RouteAuthMode,\n type RouteContext,\n type RoutePolicy,\n type RouteOptions,\n type RouteRecord,\n type RouteManifest,\n type PageScopeRecord,\n type AccessDecision,\n type AccessDenyDecision,\n type AccessRedirectDecision,\n type GroupHelperOptions,\n type PageHelperOptions,\n type RegisterRoutesOptions,\n type RouteDefinition,\n type RouteAuthOptions,\n type RouteAuthResolver,\n type RouteAuthState,\n type RouteRenderResult,\n type RouteRequestOptions,\n type RouteRequestResult,\n} from './router';\nexport { navigate } from './router/navigate';\nexport type {\n NavigateOptions,\n NavigationScrollBehavior,\n HistoryScrollBehavior,\n ScrollRestorationOptions,\n} from './router/navigate';\n\n// Components\nexport { Link } from './components/link';\nexport type { LinkProps } from './components/link';\nexport { ErrorBoundary } from './components/error-boundary';\nexport type {\n ErrorBoundaryProps,\n ErrorBoundaryFallbackRender,\n} from './components/error-boundary';\nexport { Case, For, Match, Show } from './control';\nexport type { CaseProps, ForProps, MatchProps, ShowProps } from './control';\nexport {\n Slot,\n definePortal,\n DefaultPortal,\n Portal,\n} from './foundations/structures';\nexport type { SlotProps, PortalProps } from './foundations/structures';\n\n// Re-export JSX runtime for tsconfig jsxImportSource\nexport { jsx, jsxs, Fragment } from './jsx-runtime';\n\n// Public types\nexport type { Props } from './common/props';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,uBAAuB"}
|
package/dist/jsx/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/jsx/utils.ts"],"sourcesContent":["import { ELEMENT_TYPE, JSXElement } from './types';\n\nexport function isElement(value: unknown): value is JSXElement {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as JSXElement).$$typeof === ELEMENT_TYPE\n );\n}\n\nexport function cloneElement(\n element: JSXElement,\n props: Record<string, unknown>\n): JSXElement {\n return {\n ...element,\n props: { ...element.props, ...props },\n };\n}\n"],"mappings":";;;AAEA,SAAgB,UAAU,OAAqC;
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/jsx/utils.ts"],"sourcesContent":["import { ELEMENT_TYPE, JSXElement } from './types';\n\nexport function isElement(value: unknown): value is JSXElement {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as JSXElement).$$typeof === ELEMENT_TYPE\n );\n}\n\nexport function cloneElement(\n element: JSXElement,\n props: Record<string, unknown>\n): JSXElement {\n return {\n ...element,\n props: { ...element.props, ...props },\n };\n}\n"],"mappings":";;;AAEA,SAAgB,UAAU,OAAqC;CAC7D,OACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqB,aAAa;;AAIvC,SAAgB,aACd,SACA,OACY;CACZ,OAAO;EACL,GAAG;EACH,OAAO;GAAE,GAAG,QAAQ;GAAO,GAAG;GAAO;EACtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-dev-runtime.js","names":[],"sources":["../src/jsx/jsx-dev-runtime.ts"],"sourcesContent":["/**\n * JSX dev runtime factory\n * Same element shape as production runtime, with room for dev warnings.\n */\nimport type { Props } from '../common/props';\nimport {\n isEagerControlPrimitive,\n type EagerControlPrimitive,\n} from '../common/control';\nimport {\n ELEMENT_TYPE,\n Fragment,\n STATIC_CHILDREN,\n type JSXElement,\n} from './types';\nimport { markReadableUsage } from '../runtime/readable';\n\nfunction annotatePropsUsage(props: Record<string, unknown> | null): Props {\n const normalizedProps = (props ?? {}) as Props;\n\n for (const value of Object.values(normalizedProps)) {\n markReadableUsage(value);\n }\n\n return normalizedProps;\n}\n\nfunction markStaticChildren(props: Props): Props {\n if (Array.isArray(props.children)) {\n Object.defineProperty(props.children, STATIC_CHILDREN, {\n value: true,\n configurable: true,\n });\n }\n\n return props;\n}\n\nexport function jsxDEV(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): unknown;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): JSXElement;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren = false\n): JSXElement | unknown {\n const normalizedProps = annotatePropsUsage(props);\n const preparedProps = isStaticChildren\n ? markStaticChildren(normalizedProps)\n : normalizedProps;\n\n if (isEagerControlPrimitive(type)) {\n return type(preparedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: preparedProps,\n key: key ?? null,\n };\n}\n\n// Re-export Fragment for JSX\nexport { Fragment };\n"],"mappings":";;;;;AAiBA,SAAS,mBAAmB,OAA8C;CACxE,MAAM,kBAAmB,SAAS,EAAE;
|
|
1
|
+
{"version":3,"file":"jsx-dev-runtime.js","names":[],"sources":["../src/jsx/jsx-dev-runtime.ts"],"sourcesContent":["/**\n * JSX dev runtime factory\n * Same element shape as production runtime, with room for dev warnings.\n */\nimport type { Props } from '../common/props';\nimport {\n isEagerControlPrimitive,\n type EagerControlPrimitive,\n} from '../common/control';\nimport {\n ELEMENT_TYPE,\n Fragment,\n STATIC_CHILDREN,\n type JSXElement,\n} from './types';\nimport { markReadableUsage } from '../runtime/readable';\n\nfunction annotatePropsUsage(props: Record<string, unknown> | null): Props {\n const normalizedProps = (props ?? {}) as Props;\n\n for (const value of Object.values(normalizedProps)) {\n markReadableUsage(value);\n }\n\n return normalizedProps;\n}\n\nfunction markStaticChildren(props: Props): Props {\n if (Array.isArray(props.children)) {\n Object.defineProperty(props.children, STATIC_CHILDREN, {\n value: true,\n configurable: true,\n });\n }\n\n return props;\n}\n\nexport function jsxDEV(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): unknown;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): JSXElement;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren = false\n): JSXElement | unknown {\n const normalizedProps = annotatePropsUsage(props);\n const preparedProps = isStaticChildren\n ? markStaticChildren(normalizedProps)\n : normalizedProps;\n\n if (isEagerControlPrimitive(type)) {\n return type(preparedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: preparedProps,\n key: key ?? null,\n };\n}\n\n// Re-export Fragment for JSX\nexport { Fragment };\n"],"mappings":";;;;;AAiBA,SAAS,mBAAmB,OAA8C;CACxE,MAAM,kBAAmB,SAAS,EAAE;CAEpC,KAAK,MAAM,SAAS,OAAO,OAAO,gBAAgB,EAChD,kBAAkB,MAAM;CAG1B,OAAO;;AAGT,SAAS,mBAAmB,OAAqB;CAC/C,IAAI,MAAM,QAAQ,MAAM,SAAS,EAC/B,OAAO,eAAe,MAAM,UAAU,iBAAiB;EACrD,OAAO;EACP,cAAc;EACf,CAAC;CAGJ,OAAO;;AAeT,SAAgB,OACd,MACA,OACA,KACA,mBAAmB,OACG;CACtB,MAAM,kBAAkB,mBAAmB,MAAM;CACjD,MAAM,gBAAgB,mBAClB,mBAAmB,gBAAgB,GACnC;CAEJ,IAAI,wBAAwB,KAAK,EAC/B,OAAO,KAAK,cAAc;CAG5B,OAAO;EACL,UAAU;EACJ;EACN,OAAO;EACP,KAAK,OAAO;EACb"}
|
package/dist/jsx-runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx/jsx-runtime.ts"],"sourcesContent":["/**\n * JSX runtime factory\n * Same element shape as production runtime.\n */\n\nimport type { Props } from '../common/props';\nimport {\n isEagerControlPrimitive,\n type EagerControlPrimitive,\n} from '../common/control';\nimport {\n ELEMENT_TYPE,\n Fragment,\n STATIC_CHILDREN,\n type JSXElement,\n} from './types';\nimport { markReadableUsage } from '../runtime/readable';\n\nfunction annotatePropsUsage(props: Record<string, unknown> | null): Props {\n const normalizedProps = (props ?? {}) as Props;\n\n for (const value of Object.values(normalizedProps)) {\n markReadableUsage(value);\n }\n\n return normalizedProps;\n}\n\nfunction markStaticChildren(props: Props): Props {\n if (Array.isArray(props.children)) {\n Object.defineProperty(props.children, STATIC_CHILDREN, {\n value: true,\n configurable: true,\n });\n }\n\n return props;\n}\n\nexport function jsxDEV(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): unknown;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): JSXElement;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren = false\n): JSXElement | unknown {\n const normalizedProps = annotatePropsUsage(props);\n const preparedProps = isStaticChildren\n ? markStaticChildren(normalizedProps)\n : normalizedProps;\n\n if (isEagerControlPrimitive(type)) {\n return type(preparedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: preparedProps,\n key: key ?? null,\n };\n}\n\n// Production-style helpers: alias to the DEV factory for now\nexport function jsx(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number\n): unknown;\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement;\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\nexport function jsxs(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number\n): unknown;\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement;\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n const normalizedProps = markStaticChildren(annotatePropsUsage(props));\n\n if (isEagerControlPrimitive(type)) {\n return type(normalizedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: normalizedProps,\n key: key ?? null,\n } as JSXElement;\n}\n\n// Re-export Fragment for JSX.\nexport { Fragment };\n"],"mappings":";;;;;AAkBA,SAAS,mBAAmB,OAA8C;CACxE,MAAM,kBAAmB,SAAS,EAAE;
|
|
1
|
+
{"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx/jsx-runtime.ts"],"sourcesContent":["/**\n * JSX runtime factory\n * Same element shape as production runtime.\n */\n\nimport type { Props } from '../common/props';\nimport {\n isEagerControlPrimitive,\n type EagerControlPrimitive,\n} from '../common/control';\nimport {\n ELEMENT_TYPE,\n Fragment,\n STATIC_CHILDREN,\n type JSXElement,\n} from './types';\nimport { markReadableUsage } from '../runtime/readable';\n\nfunction annotatePropsUsage(props: Record<string, unknown> | null): Props {\n const normalizedProps = (props ?? {}) as Props;\n\n for (const value of Object.values(normalizedProps)) {\n markReadableUsage(value);\n }\n\n return normalizedProps;\n}\n\nfunction markStaticChildren(props: Props): Props {\n if (Array.isArray(props.children)) {\n Object.defineProperty(props.children, STATIC_CHILDREN, {\n value: true,\n configurable: true,\n });\n }\n\n return props;\n}\n\nexport function jsxDEV(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): unknown;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren?: boolean\n): JSXElement;\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number,\n isStaticChildren = false\n): JSXElement | unknown {\n const normalizedProps = annotatePropsUsage(props);\n const preparedProps = isStaticChildren\n ? markStaticChildren(normalizedProps)\n : normalizedProps;\n\n if (isEagerControlPrimitive(type)) {\n return type(preparedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: preparedProps,\n key: key ?? null,\n };\n}\n\n// Production-style helpers: alias to the DEV factory for now\nexport function jsx(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number\n): unknown;\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement;\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\nexport function jsxs(\n type: EagerControlPrimitive,\n props: Record<string, unknown> | null,\n key?: string | number\n): unknown;\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement;\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n const normalizedProps = markStaticChildren(annotatePropsUsage(props));\n\n if (isEagerControlPrimitive(type)) {\n return type(normalizedProps);\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as string | ((props: Props) => unknown) | symbol,\n props: normalizedProps,\n key: key ?? null,\n } as JSXElement;\n}\n\n// Re-export Fragment for JSX.\nexport { Fragment };\n"],"mappings":";;;;;AAkBA,SAAS,mBAAmB,OAA8C;CACxE,MAAM,kBAAmB,SAAS,EAAE;CAEpC,KAAK,MAAM,SAAS,OAAO,OAAO,gBAAgB,EAChD,kBAAkB,MAAM;CAG1B,OAAO;;AAGT,SAAS,mBAAmB,OAAqB;CAC/C,IAAI,MAAM,QAAQ,MAAM,SAAS,EAC/B,OAAO,eAAe,MAAM,UAAU,iBAAiB;EACrD,OAAO;EACP,cAAc;EACf,CAAC;CAGJ,OAAO;;AAeT,SAAgB,OACd,MACA,OACA,KACA,mBAAmB,OACG;CACtB,MAAM,kBAAkB,mBAAmB,MAAM;CACjD,MAAM,gBAAgB,mBAClB,mBAAmB,gBAAgB,GACnC;CAEJ,IAAI,wBAAwB,KAAK,EAC/B,OAAO,KAAK,cAAc;CAG5B,OAAO;EACL,UAAU;EACJ;EACN,OAAO;EACP,KAAK,OAAO;EACb;;AAcH,SAAgB,IACd,MACA,OACA,KACA;CACA,OAAO,OAAO,MAAM,OAAO,IAAI;;AAajC,SAAgB,KACd,MACA,OACA,KACA;CACA,MAAM,kBAAkB,mBAAmB,mBAAmB,MAAM,CAAC;CAErE,IAAI,wBAAwB,KAAK,EAC/B,OAAO,KAAK,gBAAgB;CAG9B,OAAO;EACL,UAAU;EACJ;EACN,OAAO;EACP,KAAK,OAAO;EACb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"children.js","names":[],"sources":["../../src/renderer/children.ts"],"sourcesContent":["import { setDevValue, incDevCounter } from '../runtime/dev-namespace';\nimport { getRuntimeEnv } from './env';\nimport { keyedElements } from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { createDOMNode, updateElementFromVnode } from './dom';\nimport { _isDOMElement, type DOMElement, type VNode } from './types';\nimport {\n hasNonTrivialProps,\n logFastPathDebug,\n now,\n recordDOMReplace,\n recordFastPathStats,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nfunction upperCommonTagName(tag: string): string | null {\n switch (tag) {\n case 'div':\n return 'DIV';\n case 'span':\n return 'SPAN';\n case 'p':\n return 'P';\n case 'a':\n return 'A';\n case 'button':\n return 'BUTTON';\n case 'input':\n return 'INPUT';\n case 'ul':\n return 'UL';\n case 'ol':\n return 'OL';\n case 'li':\n return 'LI';\n default:\n return null;\n }\n}\n\nfunction tagsEqualIgnoreCase(\n elementTagName: string,\n vnodeType: string\n): boolean {\n if (elementTagName === vnodeType) return true;\n\n const upperCommon = upperCommonTagName(vnodeType);\n if (upperCommon !== null && elementTagName === upperCommon) return true;\n\n return tagNamesEqualIgnoreCase(elementTagName, vnodeType);\n}\n\nexport function performBulkPositionalKeyedTextUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n) {\n const total = keyedVnodes.length;\n let reused = 0;\n let updatedKeys = 0;\n const start = now();\n const env = getRuntimeEnv();\n const debugFastPath =\n env.ASKR_FASTPATH_DEBUG === '1' || env.ASKR_FASTPATH_DEBUG === 'true';\n\n for (let index = 0; index < total; index += 1) {\n const { key, vnode } = keyedVnodes[index];\n const child = parent.children[index] as Element | undefined;\n\n if (\n child &&\n _isDOMElement(vnode) &&\n typeof (vnode as DOMElement).type === 'string'\n ) {\n const vnodeType = (vnode as DOMElement).type as string;\n\n if (tagsEqualIgnoreCase(child.tagName, vnodeType)) {\n const children =\n (vnode as DOMElement).children ||\n (vnode as DOMElement).props?.children;\n\n if (debugFastPath) {\n logFastPathDebug('positional idx', index, {\n chTag: child.tagName,\n vnodeType,\n chChildNodes: child.childNodes.length,\n childrenType: Array.isArray(children) ? 'array' : typeof children,\n });\n }\n\n updateTextContent(child, children, vnode as DOMElement);\n setDataKey(child, key, () => (updatedKeys += 1));\n reused += 1;\n continue;\n }\n\n if (debugFastPath) {\n logFastPathDebug('positional tag mismatch', index, {\n chTag: child.tagName,\n vnodeType,\n });\n }\n } else if (debugFastPath) {\n logFastPathDebug('positional missing or invalid', index, { ch: !!child });\n }\n\n replaceNodeAtPosition(parent, index, vnode);\n }\n\n const elapsed = now() - start;\n updateKeyedElementsMap(parent, keyedVnodes);\n\n const stats = { n: total, reused, updatedKeys, t: elapsed } as const;\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n return stats;\n}\n\nfunction updateTextContent(\n el: Element,\n children: unknown,\n vnode: DOMElement\n): void {\n if (typeof children === 'string' || typeof children === 'number') {\n setTextNodeData(el, String(children));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n setTextNodeData(el, String(children[0]));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (!tryUpdateTwoChildTextPattern(el, vnode)) {\n updateElementFromVnode(el, vnode);\n }\n}\n\nfunction tryUpdateTwoChildTextPattern(\n parentEl: Element,\n vnode: DOMElement\n): boolean {\n const vnodeChildren = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;\n\n const firstChild = vnodeChildren[0];\n const secondChild = vnodeChildren[1];\n if (!_isDOMElement(firstChild) || !_isDOMElement(secondChild)) return false;\n if (\n typeof firstChild.type !== 'string' ||\n typeof secondChild.type !== 'string'\n ) {\n return false;\n }\n\n const firstElement = parentEl.children[0] as Element | undefined;\n const secondElement = parentEl.children[1] as Element | undefined;\n if (!firstElement || !secondElement) return false;\n if (parentEl.children.length !== 2 || parentEl.childNodes.length !== 2) {\n return false;\n }\n\n if (!tagsEqualIgnoreCase(firstElement.tagName, firstChild.type)) return false;\n if (!tagsEqualIgnoreCase(secondElement.tagName, secondChild.type))\n return false;\n\n const firstText = (firstChild.children ||\n firstChild.props?.children) as unknown;\n const secondText = (secondChild.children ||\n secondChild.props?.children) as unknown;\n\n if (typeof firstText === 'string' || typeof firstText === 'number') {\n setTextNodeData(firstElement, String(firstText));\n } else if (\n Array.isArray(firstText) &&\n firstText.length === 1 &&\n (typeof firstText[0] === 'string' || typeof firstText[0] === 'number')\n ) {\n setTextNodeData(firstElement, String(firstText[0]));\n } else {\n return false;\n }\n\n if (typeof secondText === 'string' || typeof secondText === 'number') {\n setTextNodeData(secondElement, String(secondText));\n } else if (\n Array.isArray(secondText) &&\n secondText.length === 1 &&\n (typeof secondText[0] === 'string' || typeof secondText[0] === 'number')\n ) {\n setTextNodeData(secondElement, String(secondText[0]));\n } else {\n return false;\n }\n\n return true;\n}\n\nfunction setTextNodeData(el: Element, text: string): void {\n if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {\n const textNode = el.firstChild as Text;\n if (textNode.data !== text) textNode.data = text;\n } else {\n el.textContent = text;\n }\n}\n\nfunction setDataKey(\n el: Element,\n key: string | number,\n onSet: () => void\n): void {\n try {\n const next = String(key);\n if (el.getAttribute('data-key') === next) return;\n el.setAttribute('data-key', next);\n onSet();\n } catch {\n // Ignore errors setting data-key\n }\n}\n\nfunction replaceNodeAtPosition(\n parent: Element,\n index: number,\n vnode: VNode\n): void {\n const dom = createDOMNode(vnode);\n if (dom) {\n const existing = parent.children[index];\n if (existing) {\n teardownNodeSubtree(existing);\n parent.replaceChild(dom, existing);\n } else {\n parent.appendChild(dom);\n }\n }\n}\n\nfunction updateKeyedElementsMap(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): void {\n try {\n const existing = keyedElements.get(parent);\n const newKeyMap = existing\n ? (existing.clear(), existing)\n : new Map<string | number, Element>();\n\n for (let index = 0; index < keyedVnodes.length; index += 1) {\n const key = keyedVnodes[index].key;\n const child = parent.children[index] as Element | undefined;\n if (child) newKeyMap.set(key, child);\n }\n\n keyedElements.set(parent, newKeyMap);\n } catch {\n // Ignore errors updating key map\n }\n}\n\nexport function performBulkTextReplace(parent: Element, newChildren: VNode[]) {\n const start = now();\n const existing = Array.from(parent.childNodes);\n const finalNodes: Node[] = [];\n let reused = 0;\n let created = 0;\n\n for (let index = 0; index < newChildren.length; index += 1) {\n const result = processChildNode(\n newChildren[index],\n existing[index],\n finalNodes\n );\n if (result === 'reused') reused += 1;\n else if (result === 'created') created += 1;\n }\n\n const tBuild = now() - start;\n const tCommit = commitBulkReplace(parent, finalNodes);\n\n keyedElements.delete(parent);\n\n const stats = {\n n: newChildren.length,\n reused,\n created,\n tBuild,\n tCommit,\n } as const;\n recordBulkTextStats(stats);\n\n return stats;\n}\n\nfunction processChildNode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n if (typeof vnode === 'string' || typeof vnode === 'number') {\n return processTextVnode(String(vnode), existingNode, finalNodes);\n }\n\n if (typeof vnode === 'object' && vnode !== null && 'type' in vnode) {\n return processElementVnode(vnode, existingNode, finalNodes);\n }\n\n return 'skipped';\n}\n\nfunction processTextVnode(\n text: string,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' {\n if (existingNode && existingNode.nodeType === 3) {\n (existingNode as Text).data = text;\n finalNodes.push(existingNode);\n return 'reused';\n }\n\n finalNodes.push(document.createTextNode(text));\n return 'created';\n}\n\nfunction processElementVnode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n const vnodeObj = vnode as unknown as { type?: unknown };\n\n if (typeof vnodeObj.type === 'string') {\n const tag = vnodeObj.type;\n if (\n existingNode &&\n existingNode.nodeType === 1 &&\n tagsEqualIgnoreCase((existingNode as Element).tagName, tag)\n ) {\n updateElementFromVnode(existingNode as Element, vnode);\n finalNodes.push(existingNode);\n return 'reused';\n }\n }\n\n const dom = createDOMNode(vnode);\n if (dom) {\n finalNodes.push(dom);\n return 'created';\n }\n\n return 'skipped';\n}\n\nfunction commitBulkReplace(parent: Element, nodes: Node[]): number {\n const startedAt = Date.now();\n const fragment = document.createDocumentFragment();\n\n for (let index = 0; index < nodes.length; index += 1) {\n fragment.appendChild(nodes[index]);\n }\n\n try {\n for (let node = parent.firstChild; node; ) {\n const next = node.nextSibling;\n teardownNodeSubtree(node);\n node = next;\n }\n } catch {\n // SLOW PATH: cleanup failure\n }\n\n recordDOMReplace('bulk-text-replace');\n parent.replaceChildren(fragment);\n return Date.now() - startedAt;\n}\n\nfunction recordBulkTextStats(stats: {\n n: number;\n reused: number;\n created: number;\n tBuild: number;\n tCommit: number;\n}): void {\n try {\n setDevValue('__LAST_BULK_TEXT_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 1);\n incDevCounter('bulkTextFastpathHits');\n } catch {\n // Ignore stats errors\n }\n}\n\nexport function isBulkTextFastPathEligible(\n parent: Element,\n newChildren: VNode[]\n) {\n const env = getRuntimeEnv();\n const threshold = Number(env.ASKR_BULK_TEXT_THRESHOLD) || 1024;\n const requiredFraction = 0.8;\n\n const total = Array.isArray(newChildren) ? newChildren.length : 0;\n\n if (total < threshold) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'too-small',\n total,\n threshold,\n });\n return false;\n }\n\n const result = countSimpleChildren(newChildren);\n if (result.componentFound !== undefined) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'component-child',\n index: result.componentFound,\n });\n return false;\n }\n\n const fraction = result.simple / total;\n const eligible =\n fraction >= requiredFraction && parent.childNodes.length >= total;\n\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n total,\n simple: result.simple,\n fraction,\n requiredFraction,\n eligible,\n });\n\n return eligible;\n}\n\nfunction countSimpleChildren(children: VNode[]): {\n simple: number;\n componentFound?: number;\n} {\n let simple = 0;\n\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index];\n\n if (typeof child === 'string' || typeof child === 'number') {\n simple += 1;\n continue;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const dom = child as DOMElement;\n\n if (typeof dom.type === 'function') {\n return { simple, componentFound: index };\n }\n\n if (typeof dom.type === 'string' && isSimpleElement(dom)) {\n simple += 1;\n }\n }\n }\n\n return { simple };\n}\n\nfunction isSimpleElement(dom: DOMElement): boolean {\n const children = dom.props?.children ?? dom.children;\n\n if (children === null || children === undefined) return true;\n\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction recordBulkDiag(data: Record<string, unknown>): void {\n const env = getRuntimeEnv();\n if (env.NODE_ENV !== 'production' || env.ASKR_FASTPATH_DEBUG === '1') {\n try {\n setDevValue('__BULK_DIAG', data);\n } catch {\n // Ignore\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAeA,SAAS,mBAAmB,KAA4B;AACtD,SAAQ,KAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,IACH,QAAO;EACT,KAAK,IACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,KAAK,KACH,QAAO;EACT,KAAK,KACH,QAAO;EACT,KAAK,KACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,oBACP,gBACA,WACS;AACT,KAAI,mBAAmB,UAAW,QAAO;CAEzC,MAAM,cAAc,mBAAmB,UAAU;AACjD,KAAI,gBAAgB,QAAQ,mBAAmB,YAAa,QAAO;AAEnE,QAAO,wBAAwB,gBAAgB,UAAU;;AAG3D,SAAgB,qCACd,QACA,aACA;CACA,MAAM,QAAQ,YAAY;CAC1B,IAAI,SAAS;CACb,IAAI,cAAc;CAClB,MAAM,QAAQ,KAAK;CACnB,MAAM,MAAM,eAAe;CAC3B,MAAM,gBACJ,IAAI,wBAAwB,OAAO,IAAI,wBAAwB;AAEjE,MAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;EAC7C,MAAM,EAAE,KAAK,UAAU,YAAY;EACnC,MAAM,QAAQ,OAAO,SAAS;AAE9B,MACE,SACA,cAAc,MAAM,IACpB,OAAQ,MAAqB,SAAS,UACtC;GACA,MAAM,YAAa,MAAqB;AAExC,OAAI,oBAAoB,MAAM,SAAS,UAAU,EAAE;IACjD,MAAM,WACH,MAAqB,YACrB,MAAqB,OAAO;AAE/B,QAAI,cACF,kBAAiB,kBAAkB,OAAO;KACxC,OAAO,MAAM;KACb;KACA,cAAc,MAAM,WAAW;KAC/B,cAAc,MAAM,QAAQ,SAAS,GAAG,UAAU,OAAO;KAC1D,CAAC;AAGJ,sBAAkB,OAAO,UAAU,MAAoB;AACvD,eAAW,OAAO,WAAY,eAAe,EAAG;AAChD,cAAU;AACV;;AAGF,OAAI,cACF,kBAAiB,2BAA2B,OAAO;IACjD,OAAO,MAAM;IACb;IACD,CAAC;aAEK,cACT,kBAAiB,iCAAiC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC;AAG3E,wBAAsB,QAAQ,OAAO,MAAM;;CAG7C,MAAM,UAAU,KAAK,GAAG;AACxB,wBAAuB,QAAQ,YAAY;CAE3C,MAAM,QAAQ;EAAE,GAAG;EAAO;EAAQ;EAAa,GAAG;EAAS;AAC3D,qBAAoB,OAAO,0BAA0B;AAErD,QAAO;;AAGT,SAAS,kBACP,IACA,UACA,OACM;AACN,KAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UAAU;AAChE,kBAAgB,IAAI,OAAO,SAAS,CAAC;AACrC,MAAI,MAAM,SAAS,mBAAmB,MAAM,MAAM,CAChD,wBAAuB,IAAI,OAAO,MAAM;AAE1C;;AAGF,KACE,MAAM,QAAQ,SAAS,IACvB,SAAS,WAAW,MACnB,OAAO,SAAS,OAAO,YAAY,OAAO,SAAS,OAAO,WAC3D;AACA,kBAAgB,IAAI,OAAO,SAAS,GAAG,CAAC;AACxC,MAAI,MAAM,SAAS,mBAAmB,MAAM,MAAM,CAChD,wBAAuB,IAAI,OAAO,MAAM;AAE1C;;AAGF,KAAI,CAAC,6BAA6B,IAAI,MAAM,CAC1C,wBAAuB,IAAI,MAAM;;AAIrC,SAAS,6BACP,UACA,OACS;CACT,MAAM,gBAAgB,MAAM,OAAO,YAAY,MAAM;AACrD,KAAI,CAAC,MAAM,QAAQ,cAAc,IAAI,cAAc,WAAW,EAAG,QAAO;CAExE,MAAM,aAAa,cAAc;CACjC,MAAM,cAAc,cAAc;AAClC,KAAI,CAAC,cAAc,WAAW,IAAI,CAAC,cAAc,YAAY,CAAE,QAAO;AACtE,KACE,OAAO,WAAW,SAAS,YAC3B,OAAO,YAAY,SAAS,SAE5B,QAAO;CAGT,MAAM,eAAe,SAAS,SAAS;CACvC,MAAM,gBAAgB,SAAS,SAAS;AACxC,KAAI,CAAC,gBAAgB,CAAC,cAAe,QAAO;AAC5C,KAAI,SAAS,SAAS,WAAW,KAAK,SAAS,WAAW,WAAW,EACnE,QAAO;AAGT,KAAI,CAAC,oBAAoB,aAAa,SAAS,WAAW,KAAK,CAAE,QAAO;AACxE,KAAI,CAAC,oBAAoB,cAAc,SAAS,YAAY,KAAK,CAC/D,QAAO;CAET,MAAM,YAAa,WAAW,YAC5B,WAAW,OAAO;CACpB,MAAM,aAAc,YAAY,YAC9B,YAAY,OAAO;AAErB,KAAI,OAAO,cAAc,YAAY,OAAO,cAAc,SACxD,iBAAgB,cAAc,OAAO,UAAU,CAAC;UAEhD,MAAM,QAAQ,UAAU,IACxB,UAAU,WAAW,MACpB,OAAO,UAAU,OAAO,YAAY,OAAO,UAAU,OAAO,UAE7D,iBAAgB,cAAc,OAAO,UAAU,GAAG,CAAC;KAEnD,QAAO;AAGT,KAAI,OAAO,eAAe,YAAY,OAAO,eAAe,SAC1D,iBAAgB,eAAe,OAAO,WAAW,CAAC;UAElD,MAAM,QAAQ,WAAW,IACzB,WAAW,WAAW,MACrB,OAAO,WAAW,OAAO,YAAY,OAAO,WAAW,OAAO,UAE/D,iBAAgB,eAAe,OAAO,WAAW,GAAG,CAAC;KAErD,QAAO;AAGT,QAAO;;AAGT,SAAS,gBAAgB,IAAa,MAAoB;AACxD,KAAI,GAAG,WAAW,WAAW,KAAK,GAAG,YAAY,aAAa,GAAG;EAC/D,MAAM,WAAW,GAAG;AACpB,MAAI,SAAS,SAAS,KAAM,UAAS,OAAO;OAE5C,IAAG,cAAc;;AAIrB,SAAS,WACP,IACA,KACA,OACM;AACN,KAAI;EACF,MAAM,OAAO,OAAO,IAAI;AACxB,MAAI,GAAG,aAAa,WAAW,KAAK,KAAM;AAC1C,KAAG,aAAa,YAAY,KAAK;AACjC,SAAO;SACD;;AAKV,SAAS,sBACP,QACA,OACA,OACM;CACN,MAAM,MAAM,cAAc,MAAM;AAChC,KAAI,KAAK;EACP,MAAM,WAAW,OAAO,SAAS;AACjC,MAAI,UAAU;AACZ,uBAAoB,SAAS;AAC7B,UAAO,aAAa,KAAK,SAAS;QAElC,QAAO,YAAY,IAAI;;;AAK7B,SAAS,uBACP,QACA,aACM;AACN,KAAI;EACF,MAAM,WAAW,cAAc,IAAI,OAAO;EAC1C,MAAM,YAAY,YACb,SAAS,OAAO,EAAE,4BACnB,IAAI,KAA+B;AAEvC,OAAK,IAAI,QAAQ,GAAG,QAAQ,YAAY,QAAQ,SAAS,GAAG;GAC1D,MAAM,MAAM,YAAY,OAAO;GAC/B,MAAM,QAAQ,OAAO,SAAS;AAC9B,OAAI,MAAO,WAAU,IAAI,KAAK,MAAM;;AAGtC,gBAAc,IAAI,QAAQ,UAAU;SAC9B;;AAKV,SAAgB,uBAAuB,QAAiB,aAAsB;CAC5E,MAAM,QAAQ,KAAK;CACnB,MAAM,WAAW,MAAM,KAAK,OAAO,WAAW;CAC9C,MAAM,aAAqB,EAAE;CAC7B,IAAI,SAAS;CACb,IAAI,UAAU;AAEd,MAAK,IAAI,QAAQ,GAAG,QAAQ,YAAY,QAAQ,SAAS,GAAG;EAC1D,MAAM,SAAS,iBACb,YAAY,QACZ,SAAS,QACT,WACD;AACD,MAAI,WAAW,SAAU,WAAU;WAC1B,WAAW,UAAW,YAAW;;CAG5C,MAAM,SAAS,KAAK,GAAG;CACvB,MAAM,UAAU,kBAAkB,QAAQ,WAAW;AAErD,eAAc,OAAO,OAAO;CAE5B,MAAM,QAAQ;EACZ,GAAG,YAAY;EACf;EACA;EACA;EACA;EACD;AACD,qBAAoB,MAAM;AAE1B,QAAO;;AAGT,SAAS,iBACP,OACA,cACA,YACkC;AAClC,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAChD,QAAO,iBAAiB,OAAO,MAAM,EAAE,cAAc,WAAW;AAGlE,KAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,MAC3D,QAAO,oBAAoB,OAAO,cAAc,WAAW;AAG7D,QAAO;;AAGT,SAAS,iBACP,MACA,cACA,YACsB;AACtB,KAAI,gBAAgB,aAAa,aAAa,GAAG;AAC9C,eAAsB,OAAO;AAC9B,aAAW,KAAK,aAAa;AAC7B,SAAO;;AAGT,YAAW,KAAK,SAAS,eAAe,KAAK,CAAC;AAC9C,QAAO;;AAGT,SAAS,oBACP,OACA,cACA,YACkC;CAClC,MAAM,WAAW;AAEjB,KAAI,OAAO,SAAS,SAAS,UAAU;EACrC,MAAM,MAAM,SAAS;AACrB,MACE,gBACA,aAAa,aAAa,KAC1B,oBAAqB,aAAyB,SAAS,IAAI,EAC3D;AACA,0BAAuB,cAAyB,MAAM;AACtD,cAAW,KAAK,aAAa;AAC7B,UAAO;;;CAIX,MAAM,MAAM,cAAc,MAAM;AAChC,KAAI,KAAK;AACP,aAAW,KAAK,IAAI;AACpB,SAAO;;AAGT,QAAO;;AAGT,SAAS,kBAAkB,QAAiB,OAAuB;CACjE,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,WAAW,SAAS,wBAAwB;AAElD,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,EACjD,UAAS,YAAY,MAAM,OAAO;AAGpC,KAAI;AACF,OAAK,IAAI,OAAO,OAAO,YAAY,OAAQ;GACzC,MAAM,OAAO,KAAK;AAClB,uBAAoB,KAAK;AACzB,UAAO;;SAEH;AAIR,kBAAiB,oBAAoB;AACrC,QAAO,gBAAgB,SAAS;AAChC,QAAO,KAAK,KAAK,GAAG;;AAGtB,SAAS,oBAAoB,OAMpB;AACP,KAAI;AACF,cAAY,mCAAmC,MAAM;AACrD,cAAY,yBAAyB,MAAM;AAC3C,cAAY,gCAAgC,EAAE;AAC9C,gBAAc,uBAAuB;SAC/B;;AAKV,SAAgB,2BACd,QACA,aACA;CACA,MAAM,MAAM,eAAe;CAC3B,MAAM,YAAY,OAAO,IAAI,yBAAyB,IAAI;CAC1D,MAAM,mBAAmB;CAEzB,MAAM,QAAQ,MAAM,QAAQ,YAAY,GAAG,YAAY,SAAS;AAEhE,KAAI,QAAQ,WAAW;AACrB,iBAAe;GACb,OAAO;GACP,QAAQ;GACR;GACA;GACD,CAAC;AACF,SAAO;;CAGT,MAAM,SAAS,oBAAoB,YAAY;AAC/C,KAAI,OAAO,mBAAmB,QAAW;AACvC,iBAAe;GACb,OAAO;GACP,QAAQ;GACR,OAAO,OAAO;GACf,CAAC;AACF,SAAO;;CAGT,MAAM,WAAW,OAAO,SAAS;CACjC,MAAM,WACJ,YAAY,oBAAoB,OAAO,WAAW,UAAU;AAE9D,gBAAe;EACb,OAAO;EACP;EACA,QAAQ,OAAO;EACf;EACA;EACA;EACD,CAAC;AAEF,QAAO;;AAGT,SAAS,oBAAoB,UAG3B;CACA,IAAI,SAAS;AAEb,MAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GAAG;EACvD,MAAM,QAAQ,SAAS;AAEvB,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC1D,aAAU;AACV;;AAGF,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,OAAO;GAClE,MAAM,MAAM;AAEZ,OAAI,OAAO,IAAI,SAAS,WACtB,QAAO;IAAE;IAAQ,gBAAgB;IAAO;AAG1C,OAAI,OAAO,IAAI,SAAS,YAAY,gBAAgB,IAAI,CACtD,WAAU;;;AAKhB,QAAO,EAAE,QAAQ;;AAGnB,SAAS,gBAAgB,KAA0B;CACjD,MAAM,WAAW,IAAI,OAAO,YAAY,IAAI;AAE5C,KAAI,aAAa,QAAQ,aAAa,OAAW,QAAO;AAExD,KAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SACtD,QAAO;AAGT,KACE,MAAM,QAAQ,SAAS,IACvB,SAAS,WAAW,MACnB,OAAO,SAAS,OAAO,YAAY,OAAO,SAAS,OAAO,UAE3D,QAAO;AAGT,QAAO;;AAGT,SAAS,eAAe,MAAqC;CAC3D,MAAM,MAAM,eAAe;AAC3B,KAAI,IAAI,aAAa,gBAAgB,IAAI,wBAAwB,IAC/D,KAAI;AACF,cAAY,eAAe,KAAK;SAC1B"}
|
|
1
|
+
{"version":3,"file":"children.js","names":[],"sources":["../../src/renderer/children.ts"],"sourcesContent":["import { setDevValue, incDevCounter } from '../runtime/dev-namespace';\nimport { getRuntimeEnv } from './env';\nimport { keyedElements } from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { createDOMNode, updateElementFromVnode } from './dom';\nimport { _isDOMElement, type DOMElement, type VNode } from './types';\nimport {\n hasNonTrivialProps,\n logFastPathDebug,\n now,\n recordDOMReplace,\n recordFastPathStats,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nfunction upperCommonTagName(tag: string): string | null {\n switch (tag) {\n case 'div':\n return 'DIV';\n case 'span':\n return 'SPAN';\n case 'p':\n return 'P';\n case 'a':\n return 'A';\n case 'button':\n return 'BUTTON';\n case 'input':\n return 'INPUT';\n case 'ul':\n return 'UL';\n case 'ol':\n return 'OL';\n case 'li':\n return 'LI';\n default:\n return null;\n }\n}\n\nfunction tagsEqualIgnoreCase(\n elementTagName: string,\n vnodeType: string\n): boolean {\n if (elementTagName === vnodeType) return true;\n\n const upperCommon = upperCommonTagName(vnodeType);\n if (upperCommon !== null && elementTagName === upperCommon) return true;\n\n return tagNamesEqualIgnoreCase(elementTagName, vnodeType);\n}\n\nexport function performBulkPositionalKeyedTextUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n) {\n const total = keyedVnodes.length;\n let reused = 0;\n let updatedKeys = 0;\n const start = now();\n const env = getRuntimeEnv();\n const debugFastPath =\n env.ASKR_FASTPATH_DEBUG === '1' || env.ASKR_FASTPATH_DEBUG === 'true';\n\n for (let index = 0; index < total; index += 1) {\n const { key, vnode } = keyedVnodes[index];\n const child = parent.children[index] as Element | undefined;\n\n if (\n child &&\n _isDOMElement(vnode) &&\n typeof (vnode as DOMElement).type === 'string'\n ) {\n const vnodeType = (vnode as DOMElement).type as string;\n\n if (tagsEqualIgnoreCase(child.tagName, vnodeType)) {\n const children =\n (vnode as DOMElement).children ||\n (vnode as DOMElement).props?.children;\n\n if (debugFastPath) {\n logFastPathDebug('positional idx', index, {\n chTag: child.tagName,\n vnodeType,\n chChildNodes: child.childNodes.length,\n childrenType: Array.isArray(children) ? 'array' : typeof children,\n });\n }\n\n updateTextContent(child, children, vnode as DOMElement);\n setDataKey(child, key, () => (updatedKeys += 1));\n reused += 1;\n continue;\n }\n\n if (debugFastPath) {\n logFastPathDebug('positional tag mismatch', index, {\n chTag: child.tagName,\n vnodeType,\n });\n }\n } else if (debugFastPath) {\n logFastPathDebug('positional missing or invalid', index, { ch: !!child });\n }\n\n replaceNodeAtPosition(parent, index, vnode);\n }\n\n const elapsed = now() - start;\n updateKeyedElementsMap(parent, keyedVnodes);\n\n const stats = { n: total, reused, updatedKeys, t: elapsed } as const;\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n return stats;\n}\n\nfunction updateTextContent(\n el: Element,\n children: unknown,\n vnode: DOMElement\n): void {\n if (typeof children === 'string' || typeof children === 'number') {\n setTextNodeData(el, String(children));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n setTextNodeData(el, String(children[0]));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (!tryUpdateTwoChildTextPattern(el, vnode)) {\n updateElementFromVnode(el, vnode);\n }\n}\n\nfunction tryUpdateTwoChildTextPattern(\n parentEl: Element,\n vnode: DOMElement\n): boolean {\n const vnodeChildren = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;\n\n const firstChild = vnodeChildren[0];\n const secondChild = vnodeChildren[1];\n if (!_isDOMElement(firstChild) || !_isDOMElement(secondChild)) return false;\n if (\n typeof firstChild.type !== 'string' ||\n typeof secondChild.type !== 'string'\n ) {\n return false;\n }\n\n const firstElement = parentEl.children[0] as Element | undefined;\n const secondElement = parentEl.children[1] as Element | undefined;\n if (!firstElement || !secondElement) return false;\n if (parentEl.children.length !== 2 || parentEl.childNodes.length !== 2) {\n return false;\n }\n\n if (!tagsEqualIgnoreCase(firstElement.tagName, firstChild.type)) return false;\n if (!tagsEqualIgnoreCase(secondElement.tagName, secondChild.type))\n return false;\n\n const firstText = (firstChild.children ||\n firstChild.props?.children) as unknown;\n const secondText = (secondChild.children ||\n secondChild.props?.children) as unknown;\n\n if (typeof firstText === 'string' || typeof firstText === 'number') {\n setTextNodeData(firstElement, String(firstText));\n } else if (\n Array.isArray(firstText) &&\n firstText.length === 1 &&\n (typeof firstText[0] === 'string' || typeof firstText[0] === 'number')\n ) {\n setTextNodeData(firstElement, String(firstText[0]));\n } else {\n return false;\n }\n\n if (typeof secondText === 'string' || typeof secondText === 'number') {\n setTextNodeData(secondElement, String(secondText));\n } else if (\n Array.isArray(secondText) &&\n secondText.length === 1 &&\n (typeof secondText[0] === 'string' || typeof secondText[0] === 'number')\n ) {\n setTextNodeData(secondElement, String(secondText[0]));\n } else {\n return false;\n }\n\n return true;\n}\n\nfunction setTextNodeData(el: Element, text: string): void {\n if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {\n const textNode = el.firstChild as Text;\n if (textNode.data !== text) textNode.data = text;\n } else {\n el.textContent = text;\n }\n}\n\nfunction setDataKey(\n el: Element,\n key: string | number,\n onSet: () => void\n): void {\n try {\n const next = String(key);\n if (el.getAttribute('data-key') === next) return;\n el.setAttribute('data-key', next);\n onSet();\n } catch {\n // Ignore errors setting data-key\n }\n}\n\nfunction replaceNodeAtPosition(\n parent: Element,\n index: number,\n vnode: VNode\n): void {\n const dom = createDOMNode(vnode);\n if (dom) {\n const existing = parent.children[index];\n if (existing) {\n teardownNodeSubtree(existing);\n parent.replaceChild(dom, existing);\n } else {\n parent.appendChild(dom);\n }\n }\n}\n\nfunction updateKeyedElementsMap(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): void {\n try {\n const existing = keyedElements.get(parent);\n const newKeyMap = existing\n ? (existing.clear(), existing)\n : new Map<string | number, Element>();\n\n for (let index = 0; index < keyedVnodes.length; index += 1) {\n const key = keyedVnodes[index].key;\n const child = parent.children[index] as Element | undefined;\n if (child) newKeyMap.set(key, child);\n }\n\n keyedElements.set(parent, newKeyMap);\n } catch {\n // Ignore errors updating key map\n }\n}\n\nexport function performBulkTextReplace(parent: Element, newChildren: VNode[]) {\n const start = now();\n const existing = Array.from(parent.childNodes);\n const finalNodes: Node[] = [];\n let reused = 0;\n let created = 0;\n\n for (let index = 0; index < newChildren.length; index += 1) {\n const result = processChildNode(\n newChildren[index],\n existing[index],\n finalNodes\n );\n if (result === 'reused') reused += 1;\n else if (result === 'created') created += 1;\n }\n\n const tBuild = now() - start;\n const tCommit = commitBulkReplace(parent, finalNodes);\n\n keyedElements.delete(parent);\n\n const stats = {\n n: newChildren.length,\n reused,\n created,\n tBuild,\n tCommit,\n } as const;\n recordBulkTextStats(stats);\n\n return stats;\n}\n\nfunction processChildNode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n if (typeof vnode === 'string' || typeof vnode === 'number') {\n return processTextVnode(String(vnode), existingNode, finalNodes);\n }\n\n if (typeof vnode === 'object' && vnode !== null && 'type' in vnode) {\n return processElementVnode(vnode, existingNode, finalNodes);\n }\n\n return 'skipped';\n}\n\nfunction processTextVnode(\n text: string,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' {\n if (existingNode && existingNode.nodeType === 3) {\n (existingNode as Text).data = text;\n finalNodes.push(existingNode);\n return 'reused';\n }\n\n finalNodes.push(document.createTextNode(text));\n return 'created';\n}\n\nfunction processElementVnode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n const vnodeObj = vnode as unknown as { type?: unknown };\n\n if (typeof vnodeObj.type === 'string') {\n const tag = vnodeObj.type;\n if (\n existingNode &&\n existingNode.nodeType === 1 &&\n tagsEqualIgnoreCase((existingNode as Element).tagName, tag)\n ) {\n updateElementFromVnode(existingNode as Element, vnode);\n finalNodes.push(existingNode);\n return 'reused';\n }\n }\n\n const dom = createDOMNode(vnode);\n if (dom) {\n finalNodes.push(dom);\n return 'created';\n }\n\n return 'skipped';\n}\n\nfunction commitBulkReplace(parent: Element, nodes: Node[]): number {\n const startedAt = Date.now();\n const fragment = document.createDocumentFragment();\n\n for (let index = 0; index < nodes.length; index += 1) {\n fragment.appendChild(nodes[index]);\n }\n\n try {\n for (let node = parent.firstChild; node; ) {\n const next = node.nextSibling;\n teardownNodeSubtree(node);\n node = next;\n }\n } catch {\n // SLOW PATH: cleanup failure\n }\n\n recordDOMReplace('bulk-text-replace');\n parent.replaceChildren(fragment);\n return Date.now() - startedAt;\n}\n\nfunction recordBulkTextStats(stats: {\n n: number;\n reused: number;\n created: number;\n tBuild: number;\n tCommit: number;\n}): void {\n try {\n setDevValue('__LAST_BULK_TEXT_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 1);\n incDevCounter('bulkTextFastpathHits');\n } catch {\n // Ignore stats errors\n }\n}\n\nexport function isBulkTextFastPathEligible(\n parent: Element,\n newChildren: VNode[]\n) {\n const env = getRuntimeEnv();\n const threshold = Number(env.ASKR_BULK_TEXT_THRESHOLD) || 1024;\n const requiredFraction = 0.8;\n\n const total = Array.isArray(newChildren) ? newChildren.length : 0;\n\n if (total < threshold) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'too-small',\n total,\n threshold,\n });\n return false;\n }\n\n const result = countSimpleChildren(newChildren);\n if (result.componentFound !== undefined) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'component-child',\n index: result.componentFound,\n });\n return false;\n }\n\n const fraction = result.simple / total;\n const eligible =\n fraction >= requiredFraction && parent.childNodes.length >= total;\n\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n total,\n simple: result.simple,\n fraction,\n requiredFraction,\n eligible,\n });\n\n return eligible;\n}\n\nfunction countSimpleChildren(children: VNode[]): {\n simple: number;\n componentFound?: number;\n} {\n let simple = 0;\n\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index];\n\n if (typeof child === 'string' || typeof child === 'number') {\n simple += 1;\n continue;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const dom = child as DOMElement;\n\n if (typeof dom.type === 'function') {\n return { simple, componentFound: index };\n }\n\n if (typeof dom.type === 'string' && isSimpleElement(dom)) {\n simple += 1;\n }\n }\n }\n\n return { simple };\n}\n\nfunction isSimpleElement(dom: DOMElement): boolean {\n const children = dom.props?.children ?? dom.children;\n\n if (children === null || children === undefined) return true;\n\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction recordBulkDiag(data: Record<string, unknown>): void {\n const env = getRuntimeEnv();\n if (env.NODE_ENV !== 'production' || env.ASKR_FASTPATH_DEBUG === '1') {\n try {\n setDevValue('__BULK_DIAG', data);\n } catch {\n // Ignore\n }\n }\n}\n"],"mappings":"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"}
|