@hedystia/view 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.cjs +13 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.mjs +13 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/context/context.cjs +51 -0
- package/dist/context/context.cjs.map +1 -0
- package/dist/context/context.d.cts +25 -0
- package/dist/context/context.d.mts +25 -0
- package/dist/context/context.mjs +50 -0
- package/dist/context/context.mjs.map +1 -0
- package/dist/fetch/resource.cjs +89 -0
- package/dist/fetch/resource.cjs.map +1 -0
- package/dist/fetch/resource.d.cts +14 -0
- package/dist/fetch/resource.d.mts +14 -0
- package/dist/fetch/resource.mjs +88 -0
- package/dist/fetch/resource.mjs.map +1 -0
- package/dist/index.cjs +58 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.mts +15 -0
- package/dist/index.mjs +14 -0
- package/dist/jsx/element.cjs +201 -0
- package/dist/jsx/element.cjs.map +1 -0
- package/dist/jsx/element.d.cts +48 -0
- package/dist/jsx/element.d.mts +48 -0
- package/dist/jsx/element.mjs +199 -0
- package/dist/jsx/element.mjs.map +1 -0
- package/dist/jsx-dev-runtime.cjs +40 -0
- package/dist/jsx-dev-runtime.cjs.map +1 -0
- package/dist/jsx-dev-runtime.d.cts +21 -0
- package/dist/jsx-dev-runtime.d.mts +21 -0
- package/dist/jsx-dev-runtime.mjs +36 -0
- package/dist/jsx-dev-runtime.mjs.map +1 -0
- package/dist/jsx-runtime.cjs +5 -0
- package/dist/jsx-runtime.d.cts +3 -0
- package/dist/jsx-runtime.d.mts +3 -0
- package/dist/jsx-runtime.mjs +2 -0
- package/dist/jsx.d.cts +942 -0
- package/dist/jsx.d.mts +942 -0
- package/dist/lifecycle/hooks.cjs +56 -0
- package/dist/lifecycle/hooks.cjs.map +1 -0
- package/dist/lifecycle/hooks.d.cts +37 -0
- package/dist/lifecycle/hooks.d.mts +37 -0
- package/dist/lifecycle/hooks.mjs +54 -0
- package/dist/lifecycle/hooks.mjs.map +1 -0
- package/dist/render/engine.cjs +52 -0
- package/dist/render/engine.cjs.map +1 -0
- package/dist/render/engine.d.cts +31 -0
- package/dist/render/engine.d.mts +31 -0
- package/dist/render/engine.mjs +51 -0
- package/dist/render/engine.mjs.map +1 -0
- package/dist/render/flow.cjs +286 -0
- package/dist/render/flow.cjs.map +1 -0
- package/dist/render/flow.d.cts +64 -0
- package/dist/render/flow.d.mts +64 -0
- package/dist/render/flow.mjs +279 -0
- package/dist/render/flow.mjs.map +1 -0
- package/dist/scheduler/scheduler.cjs +61 -0
- package/dist/scheduler/scheduler.cjs.map +1 -0
- package/dist/scheduler/scheduler.d.cts +31 -0
- package/dist/scheduler/scheduler.d.mts +31 -0
- package/dist/scheduler/scheduler.mjs +59 -0
- package/dist/scheduler/scheduler.mjs.map +1 -0
- package/dist/signal/signal.cjs +387 -0
- package/dist/signal/signal.cjs.map +1 -0
- package/dist/signal/signal.d.cts +44 -0
- package/dist/signal/signal.d.mts +44 -0
- package/dist/signal/signal.mjs +370 -0
- package/dist/signal/signal.mjs.map +1 -0
- package/dist/store/index.cjs +1 -0
- package/dist/store/index.mjs +2 -0
- package/dist/store/store.cjs +94 -0
- package/dist/store/store.cjs.map +1 -0
- package/dist/store/store.d.cts +22 -0
- package/dist/store/store.d.mts +22 -0
- package/dist/store/store.mjs +91 -0
- package/dist/store/store.mjs.map +1 -0
- package/dist/style/computed.cjs +65 -0
- package/dist/style/computed.cjs.map +1 -0
- package/dist/style/computed.d.cts +18 -0
- package/dist/style/computed.d.mts +18 -0
- package/dist/style/computed.mjs +63 -0
- package/dist/style/computed.mjs.map +1 -0
- package/dist/text/text.cjs +74 -0
- package/dist/text/text.cjs.map +1 -0
- package/dist/text/text.d.cts +31 -0
- package/dist/text/text.d.mts +31 -0
- package/dist/text/text.mjs +72 -0
- package/dist/text/text.mjs.map +1 -0
- package/dist/types.d.cts +185 -0
- package/dist/types.d.mts +185 -0
- package/dist/utils/index.cjs +34 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.mjs +33 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/watch/watcher.cjs +71 -0
- package/dist/watch/watcher.cjs.map +1 -0
- package/dist/watch/watcher.d.cts +17 -0
- package/dist/watch/watcher.d.mts +17 -0
- package/dist/watch/watcher.mjs +70 -0
- package/dist/watch/watcher.mjs.map +1 -0
- package/package.json +34 -0
- package/readme.md +395 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.cjs","names":["memo","sig","val"],"sources":["../../src/render/flow.ts"],"sourcesContent":["/**\n * Flow components for @hedystia/view\n *\n * Provides Show, For, Index, Switch, Match, Portal, Suspense, ErrorBoundary.\n */\n\nimport { tick } from \"../scheduler\";\nimport { createRoot, memo, sig, onCleanup as signalOnCleanup, val } from \"../signal\";\nimport type { Accessor } from \"../types\";\n\n/**\n * Conditionally render children based on a condition\n */\nexport function Show<T>(props: { when: T | Accessor<T>; fallback?: any; children: any }): any {\n const container = document.createComment(\"show\");\n let rendered: HTMLElement | null = null;\n let fallbackNode: HTMLElement | null = null;\n const _initialized = false;\n\n const getCondition = (): any => {\n return typeof props.when === \"function\" ? (props.when as Accessor<T>)() : props.when;\n };\n\n const runEffect = () => {\n const cond = getCondition();\n if (cond) {\n if (fallbackNode) {\n fallbackNode.parentNode?.removeChild(fallbackNode);\n fallbackNode = null;\n }\n if (!rendered && props.children) {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered && !rendered.parentNode) {\n // Defer insertion until container has a parent\n if (container.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n } else {\n queueMicrotask(() => {\n if (rendered && !rendered.parentNode && container.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n }\n });\n }\n }\n }\n } else {\n if (rendered) {\n rendered.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (props.fallback && !fallbackNode) {\n fallbackNode =\n typeof props.fallback === \"function\"\n ? (props.fallback() as HTMLElement)\n : (props.fallback as HTMLElement);\n if (fallbackNode && !fallbackNode.parentNode) {\n if (container.parentNode) {\n container.parentNode.insertBefore(fallbackNode, container.nextSibling);\n } else {\n queueMicrotask(() => {\n if (fallbackNode && !fallbackNode.parentNode && container.parentNode) {\n container.parentNode.insertBefore(fallbackNode, container.nextSibling);\n }\n });\n }\n }\n }\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Render a list with keyed items for efficient updates\n */\nexport function For<T>(props: {\n each: T[] | Accessor<T[]>;\n key?: (item: T) => string | number;\n children: (item: Accessor<T>, index: Accessor<number>) => any;\n}): any {\n const container = document.createComment(\"for\");\n const nodes = new Map<string | number, HTMLElement>();\n const order: Array<string | number> = [];\n\n const getEach = (): T[] => {\n return typeof props.each === \"function\" ? (props.each as Accessor<T[]>)() : props.each;\n };\n\n const runEffect = () => {\n const items = getEach();\n const newOrder: Array<string | number> = [];\n const newNodes = new Map<string | number, HTMLElement>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n const key = props.key ? props.key(item) : i;\n newOrder.push(key);\n\n if (nodes.has(key)) {\n newNodes.set(key, nodes.get(key)!);\n } else {\n const itemSig = sig(item);\n const indexSig = sig(i);\n const child = props.children(\n () => val(itemSig),\n () => val(indexSig),\n ) as HTMLElement;\n newNodes.set(key, child);\n }\n }\n\n for (const key of order) {\n if (!newNodes.has(key)) {\n const node = nodes.get(key);\n if (node?.parentNode) {\n node.parentNode.removeChild(node);\n }\n }\n }\n\n const insertNodes = () => {\n if (container.parentNode) {\n let prevSibling = container.nextSibling;\n for (const key of newOrder) {\n const node = newNodes.get(key)!;\n if (!nodes.has(key) && !node.parentNode) {\n container.parentNode!.insertBefore(node, prevSibling);\n } else if (prevSibling !== node) {\n container.parentNode!.insertBefore(node, prevSibling);\n }\n prevSibling = node.nextSibling;\n }\n }\n };\n\n if (container.parentNode) {\n insertNodes();\n } else {\n queueMicrotask(insertNodes);\n }\n\n order.length = 0;\n order.push(...newOrder);\n nodes.clear();\n for (const [k, v] of newNodes) {\n nodes.set(k, v);\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Render a list with index-based tracking\n */\nexport function Index<T>(props: {\n each: T[] | Accessor<T[]>;\n children: (item: Accessor<T>, index: number) => any;\n}): any {\n const container = document.createComment(\"index\");\n const nodes: Array<HTMLElement | null> = [];\n\n const getEach = (): T[] => {\n return typeof props.each === \"function\" ? (props.each as Accessor<T[]>)() : props.each;\n };\n\n const runEffect = () => {\n const items = getEach();\n\n while (nodes.length > items.length) {\n const node = nodes.pop();\n if (node?.parentNode) {\n node.parentNode.removeChild(node);\n }\n }\n\n const insertNodes = () => {\n if (container.parentNode) {\n for (let i = 0; i < items.length; i++) {\n if (nodes[i] === undefined) {\n const itemSig = sig(items[i]!);\n const child = props.children(() => val(itemSig), i) as HTMLElement;\n nodes[i] = child;\n if (!child.parentNode) {\n container.parentNode.insertBefore(child, container.nextSibling);\n }\n }\n }\n }\n };\n\n if (container.parentNode) {\n insertNodes();\n } else {\n queueMicrotask(insertNodes);\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Switch component for mutually exclusive conditions\n */\nexport function Switch(props: { fallback?: any; children: any }): any {\n const container = document.createComment(\"switch\");\n let rendered: HTMLElement | null = null;\n\n const evaluate = (): any => {\n const children = props.children;\n if (Array.isArray(children)) {\n for (const child of children) {\n if (child && (child as any)._matchWhen) {\n const when = (child as any)._matchWhen;\n const condition = typeof when === \"function\" ? when() : when;\n if (condition) {\n return (child as any)._matchChildren;\n }\n }\n }\n }\n return props.fallback;\n };\n\n const runEffect = () => {\n const content = evaluate();\n if (rendered) {\n rendered.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (content) {\n rendered =\n typeof content === \"function\" ? (content() as HTMLElement) : (content as HTMLElement);\n if (rendered && !rendered.parentNode) {\n const insertNode = () => {\n if (rendered && container.parentNode && !rendered.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n }\n };\n if (container.parentNode) {\n insertNode();\n } else {\n queueMicrotask(insertNode);\n }\n }\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Match component for use inside Switch\n */\nexport function Match<T>(props: { when: T | Accessor<T>; children: any }): any {\n const marker = document.createComment(\"match\");\n (marker as any)._matchWhen = typeof props.when === \"function\" ? props.when : () => props.when;\n (marker as any)._matchChildren = props.children;\n return marker;\n}\n\n/**\n * Portal component for rendering outside the current DOM hierarchy\n */\nexport function Portal(props: { mount?: HTMLElement; children: any }): any {\n const container = document.createComment(\"portal\");\n const mountPoint = props.mount || document.body;\n let rendered: HTMLElement | null = null;\n\n createRoot(() => {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n mountPoint.appendChild(rendered);\n }\n\n signalOnCleanup(() => {\n if (rendered && rendered.parentNode === mountPoint) {\n mountPoint.removeChild(rendered);\n }\n });\n });\n\n return container;\n}\n\n/**\n * Suspense component for async loading states\n */\nexport function Suspense(props: { fallback?: any; children: any }): any {\n const container = document.createComment(\"suspense\");\n let rendered: HTMLElement | null = null;\n let fallbackNode: HTMLElement | null = null;\n\n tick(() => {\n try {\n if (fallbackNode) {\n container.parentNode?.removeChild(fallbackNode);\n fallbackNode = null;\n }\n if (!rendered && props.children) {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n } catch {\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (props.fallback && !fallbackNode) {\n fallbackNode =\n typeof props.fallback === \"function\"\n ? (props.fallback() as HTMLElement)\n : (props.fallback as HTMLElement);\n if (fallbackNode) {\n container.parentNode?.insertBefore(fallbackNode, container.nextSibling);\n }\n }\n }\n });\n\n return container;\n}\n\n/**\n * ErrorBoundary component for catching render errors\n */\nexport function ErrorBoundary(props: {\n fallback: (err: Error, reset: () => void) => any;\n children: any;\n}): any {\n const container = document.createComment(\"error-boundary\");\n let rendered: HTMLElement | null = null;\n let error: Error | null = null;\n\n const reset = () => {\n error = null;\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n tick(() => {\n try {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e));\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n const fallback = props.fallback(error, reset);\n rendered =\n typeof fallback === \"function\" ? (fallback() as HTMLElement) : (fallback as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n });\n };\n\n tick(() => {\n try {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e));\n const fallback = props.fallback(error, reset);\n rendered =\n typeof fallback === \"function\" ? (fallback() as HTMLElement) : (fallback as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n });\n\n return container;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Accessor } from "../types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/render/flow.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Conditionally render children based on a condition
|
|
6
|
+
*/
|
|
7
|
+
declare function Show<T>(props: {
|
|
8
|
+
when: T | Accessor<T>;
|
|
9
|
+
fallback?: any;
|
|
10
|
+
children: any;
|
|
11
|
+
}): any;
|
|
12
|
+
/**
|
|
13
|
+
* Render a list with keyed items for efficient updates
|
|
14
|
+
*/
|
|
15
|
+
declare function For<T>(props: {
|
|
16
|
+
each: T[] | Accessor<T[]>;
|
|
17
|
+
key?: (item: T) => string | number;
|
|
18
|
+
children: (item: Accessor<T>, index: Accessor<number>) => any;
|
|
19
|
+
}): any;
|
|
20
|
+
/**
|
|
21
|
+
* Render a list with index-based tracking
|
|
22
|
+
*/
|
|
23
|
+
declare function Index<T>(props: {
|
|
24
|
+
each: T[] | Accessor<T[]>;
|
|
25
|
+
children: (item: Accessor<T>, index: number) => any;
|
|
26
|
+
}): any;
|
|
27
|
+
/**
|
|
28
|
+
* Switch component for mutually exclusive conditions
|
|
29
|
+
*/
|
|
30
|
+
declare function Switch(props: {
|
|
31
|
+
fallback?: any;
|
|
32
|
+
children: any;
|
|
33
|
+
}): any;
|
|
34
|
+
/**
|
|
35
|
+
* Match component for use inside Switch
|
|
36
|
+
*/
|
|
37
|
+
declare function Match<T>(props: {
|
|
38
|
+
when: T | Accessor<T>;
|
|
39
|
+
children: any;
|
|
40
|
+
}): any;
|
|
41
|
+
/**
|
|
42
|
+
* Portal component for rendering outside the current DOM hierarchy
|
|
43
|
+
*/
|
|
44
|
+
declare function Portal(props: {
|
|
45
|
+
mount?: HTMLElement;
|
|
46
|
+
children: any;
|
|
47
|
+
}): any;
|
|
48
|
+
/**
|
|
49
|
+
* Suspense component for async loading states
|
|
50
|
+
*/
|
|
51
|
+
declare function Suspense(props: {
|
|
52
|
+
fallback?: any;
|
|
53
|
+
children: any;
|
|
54
|
+
}): any;
|
|
55
|
+
/**
|
|
56
|
+
* ErrorBoundary component for catching render errors
|
|
57
|
+
*/
|
|
58
|
+
declare function ErrorBoundary(props: {
|
|
59
|
+
fallback: (err: Error, reset: () => void) => any;
|
|
60
|
+
children: any;
|
|
61
|
+
}): any;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { ErrorBoundary, For, Index, Match, Portal, Show, Suspense, Switch };
|
|
64
|
+
//# sourceMappingURL=flow.d.cts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Accessor } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/render/flow.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Conditionally render children based on a condition
|
|
6
|
+
*/
|
|
7
|
+
declare function Show<T>(props: {
|
|
8
|
+
when: T | Accessor<T>;
|
|
9
|
+
fallback?: any;
|
|
10
|
+
children: any;
|
|
11
|
+
}): any;
|
|
12
|
+
/**
|
|
13
|
+
* Render a list with keyed items for efficient updates
|
|
14
|
+
*/
|
|
15
|
+
declare function For<T>(props: {
|
|
16
|
+
each: T[] | Accessor<T[]>;
|
|
17
|
+
key?: (item: T) => string | number;
|
|
18
|
+
children: (item: Accessor<T>, index: Accessor<number>) => any;
|
|
19
|
+
}): any;
|
|
20
|
+
/**
|
|
21
|
+
* Render a list with index-based tracking
|
|
22
|
+
*/
|
|
23
|
+
declare function Index<T>(props: {
|
|
24
|
+
each: T[] | Accessor<T[]>;
|
|
25
|
+
children: (item: Accessor<T>, index: number) => any;
|
|
26
|
+
}): any;
|
|
27
|
+
/**
|
|
28
|
+
* Switch component for mutually exclusive conditions
|
|
29
|
+
*/
|
|
30
|
+
declare function Switch(props: {
|
|
31
|
+
fallback?: any;
|
|
32
|
+
children: any;
|
|
33
|
+
}): any;
|
|
34
|
+
/**
|
|
35
|
+
* Match component for use inside Switch
|
|
36
|
+
*/
|
|
37
|
+
declare function Match<T>(props: {
|
|
38
|
+
when: T | Accessor<T>;
|
|
39
|
+
children: any;
|
|
40
|
+
}): any;
|
|
41
|
+
/**
|
|
42
|
+
* Portal component for rendering outside the current DOM hierarchy
|
|
43
|
+
*/
|
|
44
|
+
declare function Portal(props: {
|
|
45
|
+
mount?: HTMLElement;
|
|
46
|
+
children: any;
|
|
47
|
+
}): any;
|
|
48
|
+
/**
|
|
49
|
+
* Suspense component for async loading states
|
|
50
|
+
*/
|
|
51
|
+
declare function Suspense(props: {
|
|
52
|
+
fallback?: any;
|
|
53
|
+
children: any;
|
|
54
|
+
}): any;
|
|
55
|
+
/**
|
|
56
|
+
* ErrorBoundary component for catching render errors
|
|
57
|
+
*/
|
|
58
|
+
declare function ErrorBoundary(props: {
|
|
59
|
+
fallback: (err: Error, reset: () => void) => any;
|
|
60
|
+
children: any;
|
|
61
|
+
}): any;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { ErrorBoundary, For, Index, Match, Portal, Show, Suspense, Switch };
|
|
64
|
+
//# sourceMappingURL=flow.d.mts.map
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { createRoot, memo, onCleanup, sig, val } from "../signal/signal.mjs";
|
|
2
|
+
import { tick } from "../scheduler/scheduler.mjs";
|
|
3
|
+
//#region src/render/flow.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flow components for @hedystia/view
|
|
6
|
+
*
|
|
7
|
+
* Provides Show, For, Index, Switch, Match, Portal, Suspense, ErrorBoundary.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Conditionally render children based on a condition
|
|
11
|
+
*/
|
|
12
|
+
function Show(props) {
|
|
13
|
+
const container = document.createComment("show");
|
|
14
|
+
let rendered = null;
|
|
15
|
+
let fallbackNode = null;
|
|
16
|
+
const getCondition = () => {
|
|
17
|
+
return typeof props.when === "function" ? props.when() : props.when;
|
|
18
|
+
};
|
|
19
|
+
const runEffect = () => {
|
|
20
|
+
if (getCondition()) {
|
|
21
|
+
if (fallbackNode) {
|
|
22
|
+
fallbackNode.parentNode?.removeChild(fallbackNode);
|
|
23
|
+
fallbackNode = null;
|
|
24
|
+
}
|
|
25
|
+
if (!rendered && props.children) {
|
|
26
|
+
rendered = typeof props.children === "function" ? props.children() : props.children;
|
|
27
|
+
if (rendered && !rendered.parentNode) if (container.parentNode) container.parentNode.insertBefore(rendered, container.nextSibling);
|
|
28
|
+
else queueMicrotask(() => {
|
|
29
|
+
if (rendered && !rendered.parentNode && container.parentNode) container.parentNode.insertBefore(rendered, container.nextSibling);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
if (rendered) {
|
|
34
|
+
rendered.parentNode?.removeChild(rendered);
|
|
35
|
+
rendered = null;
|
|
36
|
+
}
|
|
37
|
+
if (props.fallback && !fallbackNode) {
|
|
38
|
+
fallbackNode = typeof props.fallback === "function" ? props.fallback() : props.fallback;
|
|
39
|
+
if (fallbackNode && !fallbackNode.parentNode) if (container.parentNode) container.parentNode.insertBefore(fallbackNode, container.nextSibling);
|
|
40
|
+
else queueMicrotask(() => {
|
|
41
|
+
if (fallbackNode && !fallbackNode.parentNode && container.parentNode) container.parentNode.insertBefore(fallbackNode, container.nextSibling);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
val(memo(() => {
|
|
47
|
+
runEffect();
|
|
48
|
+
return true;
|
|
49
|
+
}));
|
|
50
|
+
return container;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Render a list with keyed items for efficient updates
|
|
54
|
+
*/
|
|
55
|
+
function For(props) {
|
|
56
|
+
const container = document.createComment("for");
|
|
57
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
58
|
+
const order = [];
|
|
59
|
+
const getEach = () => {
|
|
60
|
+
return typeof props.each === "function" ? props.each() : props.each;
|
|
61
|
+
};
|
|
62
|
+
const runEffect = () => {
|
|
63
|
+
const items = getEach();
|
|
64
|
+
const newOrder = [];
|
|
65
|
+
const newNodes = /* @__PURE__ */ new Map();
|
|
66
|
+
for (let i = 0; i < items.length; i++) {
|
|
67
|
+
const item = items[i];
|
|
68
|
+
const key = props.key ? props.key(item) : i;
|
|
69
|
+
newOrder.push(key);
|
|
70
|
+
if (nodes.has(key)) newNodes.set(key, nodes.get(key));
|
|
71
|
+
else {
|
|
72
|
+
const itemSig = sig(item);
|
|
73
|
+
const indexSig = sig(i);
|
|
74
|
+
const child = props.children(() => val(itemSig), () => val(indexSig));
|
|
75
|
+
newNodes.set(key, child);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const key of order) if (!newNodes.has(key)) {
|
|
79
|
+
const node = nodes.get(key);
|
|
80
|
+
if (node?.parentNode) node.parentNode.removeChild(node);
|
|
81
|
+
}
|
|
82
|
+
const insertNodes = () => {
|
|
83
|
+
if (container.parentNode) {
|
|
84
|
+
let prevSibling = container.nextSibling;
|
|
85
|
+
for (const key of newOrder) {
|
|
86
|
+
const node = newNodes.get(key);
|
|
87
|
+
if (!nodes.has(key) && !node.parentNode) container.parentNode.insertBefore(node, prevSibling);
|
|
88
|
+
else if (prevSibling !== node) container.parentNode.insertBefore(node, prevSibling);
|
|
89
|
+
prevSibling = node.nextSibling;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
if (container.parentNode) insertNodes();
|
|
94
|
+
else queueMicrotask(insertNodes);
|
|
95
|
+
order.length = 0;
|
|
96
|
+
order.push(...newOrder);
|
|
97
|
+
nodes.clear();
|
|
98
|
+
for (const [k, v] of newNodes) nodes.set(k, v);
|
|
99
|
+
};
|
|
100
|
+
val(memo(() => {
|
|
101
|
+
runEffect();
|
|
102
|
+
return true;
|
|
103
|
+
}));
|
|
104
|
+
return container;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Render a list with index-based tracking
|
|
108
|
+
*/
|
|
109
|
+
function Index(props) {
|
|
110
|
+
const container = document.createComment("index");
|
|
111
|
+
const nodes = [];
|
|
112
|
+
const getEach = () => {
|
|
113
|
+
return typeof props.each === "function" ? props.each() : props.each;
|
|
114
|
+
};
|
|
115
|
+
const runEffect = () => {
|
|
116
|
+
const items = getEach();
|
|
117
|
+
while (nodes.length > items.length) {
|
|
118
|
+
const node = nodes.pop();
|
|
119
|
+
if (node?.parentNode) node.parentNode.removeChild(node);
|
|
120
|
+
}
|
|
121
|
+
const insertNodes = () => {
|
|
122
|
+
if (container.parentNode) {
|
|
123
|
+
for (let i = 0; i < items.length; i++) if (nodes[i] === void 0) {
|
|
124
|
+
const itemSig = sig(items[i]);
|
|
125
|
+
const child = props.children(() => val(itemSig), i);
|
|
126
|
+
nodes[i] = child;
|
|
127
|
+
if (!child.parentNode) container.parentNode.insertBefore(child, container.nextSibling);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
if (container.parentNode) insertNodes();
|
|
132
|
+
else queueMicrotask(insertNodes);
|
|
133
|
+
};
|
|
134
|
+
val(memo(() => {
|
|
135
|
+
runEffect();
|
|
136
|
+
return true;
|
|
137
|
+
}));
|
|
138
|
+
return container;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Switch component for mutually exclusive conditions
|
|
142
|
+
*/
|
|
143
|
+
function Switch(props) {
|
|
144
|
+
const container = document.createComment("switch");
|
|
145
|
+
let rendered = null;
|
|
146
|
+
const evaluate = () => {
|
|
147
|
+
const children = props.children;
|
|
148
|
+
if (Array.isArray(children)) {
|
|
149
|
+
for (const child of children) if (child && child._matchWhen) {
|
|
150
|
+
const when = child._matchWhen;
|
|
151
|
+
if (typeof when === "function" ? when() : when) return child._matchChildren;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return props.fallback;
|
|
155
|
+
};
|
|
156
|
+
const runEffect = () => {
|
|
157
|
+
const content = evaluate();
|
|
158
|
+
if (rendered) {
|
|
159
|
+
rendered.parentNode?.removeChild(rendered);
|
|
160
|
+
rendered = null;
|
|
161
|
+
}
|
|
162
|
+
if (content) {
|
|
163
|
+
rendered = typeof content === "function" ? content() : content;
|
|
164
|
+
if (rendered && !rendered.parentNode) {
|
|
165
|
+
const insertNode = () => {
|
|
166
|
+
if (rendered && container.parentNode && !rendered.parentNode) container.parentNode.insertBefore(rendered, container.nextSibling);
|
|
167
|
+
};
|
|
168
|
+
if (container.parentNode) insertNode();
|
|
169
|
+
else queueMicrotask(insertNode);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
val(memo(() => {
|
|
174
|
+
runEffect();
|
|
175
|
+
return true;
|
|
176
|
+
}));
|
|
177
|
+
return container;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Match component for use inside Switch
|
|
181
|
+
*/
|
|
182
|
+
function Match(props) {
|
|
183
|
+
const marker = document.createComment("match");
|
|
184
|
+
marker._matchWhen = typeof props.when === "function" ? props.when : () => props.when;
|
|
185
|
+
marker._matchChildren = props.children;
|
|
186
|
+
return marker;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Portal component for rendering outside the current DOM hierarchy
|
|
190
|
+
*/
|
|
191
|
+
function Portal(props) {
|
|
192
|
+
const container = document.createComment("portal");
|
|
193
|
+
const mountPoint = props.mount || document.body;
|
|
194
|
+
let rendered = null;
|
|
195
|
+
createRoot(() => {
|
|
196
|
+
rendered = typeof props.children === "function" ? props.children() : props.children;
|
|
197
|
+
if (rendered) mountPoint.appendChild(rendered);
|
|
198
|
+
onCleanup(() => {
|
|
199
|
+
if (rendered && rendered.parentNode === mountPoint) mountPoint.removeChild(rendered);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
return container;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Suspense component for async loading states
|
|
206
|
+
*/
|
|
207
|
+
function Suspense(props) {
|
|
208
|
+
const container = document.createComment("suspense");
|
|
209
|
+
let rendered = null;
|
|
210
|
+
let fallbackNode = null;
|
|
211
|
+
tick(() => {
|
|
212
|
+
try {
|
|
213
|
+
if (fallbackNode) {
|
|
214
|
+
container.parentNode?.removeChild(fallbackNode);
|
|
215
|
+
fallbackNode = null;
|
|
216
|
+
}
|
|
217
|
+
if (!rendered && props.children) {
|
|
218
|
+
rendered = typeof props.children === "function" ? props.children() : props.children;
|
|
219
|
+
if (rendered) container.parentNode?.insertBefore(rendered, container.nextSibling);
|
|
220
|
+
}
|
|
221
|
+
} catch {
|
|
222
|
+
if (rendered) {
|
|
223
|
+
container.parentNode?.removeChild(rendered);
|
|
224
|
+
rendered = null;
|
|
225
|
+
}
|
|
226
|
+
if (props.fallback && !fallbackNode) {
|
|
227
|
+
fallbackNode = typeof props.fallback === "function" ? props.fallback() : props.fallback;
|
|
228
|
+
if (fallbackNode) container.parentNode?.insertBefore(fallbackNode, container.nextSibling);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
return container;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* ErrorBoundary component for catching render errors
|
|
236
|
+
*/
|
|
237
|
+
function ErrorBoundary(props) {
|
|
238
|
+
const container = document.createComment("error-boundary");
|
|
239
|
+
let rendered = null;
|
|
240
|
+
let error = null;
|
|
241
|
+
const reset = () => {
|
|
242
|
+
error = null;
|
|
243
|
+
if (rendered) {
|
|
244
|
+
container.parentNode?.removeChild(rendered);
|
|
245
|
+
rendered = null;
|
|
246
|
+
}
|
|
247
|
+
tick(() => {
|
|
248
|
+
try {
|
|
249
|
+
rendered = typeof props.children === "function" ? props.children() : props.children;
|
|
250
|
+
if (rendered) container.parentNode?.insertBefore(rendered, container.nextSibling);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
253
|
+
if (rendered) {
|
|
254
|
+
container.parentNode?.removeChild(rendered);
|
|
255
|
+
rendered = null;
|
|
256
|
+
}
|
|
257
|
+
const fallback = props.fallback(error, reset);
|
|
258
|
+
rendered = typeof fallback === "function" ? fallback() : fallback;
|
|
259
|
+
if (rendered) container.parentNode?.insertBefore(rendered, container.nextSibling);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
tick(() => {
|
|
264
|
+
try {
|
|
265
|
+
rendered = typeof props.children === "function" ? props.children() : props.children;
|
|
266
|
+
if (rendered) container.parentNode?.insertBefore(rendered, container.nextSibling);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
269
|
+
const fallback = props.fallback(error, reset);
|
|
270
|
+
rendered = typeof fallback === "function" ? fallback() : fallback;
|
|
271
|
+
if (rendered) container.parentNode?.insertBefore(rendered, container.nextSibling);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
return container;
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
277
|
+
export { ErrorBoundary, For, Index, Match, Portal, Show, Suspense, Switch };
|
|
278
|
+
|
|
279
|
+
//# sourceMappingURL=flow.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.mjs","names":[],"sources":["../../src/render/flow.ts"],"sourcesContent":["/**\n * Flow components for @hedystia/view\n *\n * Provides Show, For, Index, Switch, Match, Portal, Suspense, ErrorBoundary.\n */\n\nimport { tick } from \"../scheduler\";\nimport { createRoot, memo, sig, onCleanup as signalOnCleanup, val } from \"../signal\";\nimport type { Accessor } from \"../types\";\n\n/**\n * Conditionally render children based on a condition\n */\nexport function Show<T>(props: { when: T | Accessor<T>; fallback?: any; children: any }): any {\n const container = document.createComment(\"show\");\n let rendered: HTMLElement | null = null;\n let fallbackNode: HTMLElement | null = null;\n const _initialized = false;\n\n const getCondition = (): any => {\n return typeof props.when === \"function\" ? (props.when as Accessor<T>)() : props.when;\n };\n\n const runEffect = () => {\n const cond = getCondition();\n if (cond) {\n if (fallbackNode) {\n fallbackNode.parentNode?.removeChild(fallbackNode);\n fallbackNode = null;\n }\n if (!rendered && props.children) {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered && !rendered.parentNode) {\n // Defer insertion until container has a parent\n if (container.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n } else {\n queueMicrotask(() => {\n if (rendered && !rendered.parentNode && container.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n }\n });\n }\n }\n }\n } else {\n if (rendered) {\n rendered.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (props.fallback && !fallbackNode) {\n fallbackNode =\n typeof props.fallback === \"function\"\n ? (props.fallback() as HTMLElement)\n : (props.fallback as HTMLElement);\n if (fallbackNode && !fallbackNode.parentNode) {\n if (container.parentNode) {\n container.parentNode.insertBefore(fallbackNode, container.nextSibling);\n } else {\n queueMicrotask(() => {\n if (fallbackNode && !fallbackNode.parentNode && container.parentNode) {\n container.parentNode.insertBefore(fallbackNode, container.nextSibling);\n }\n });\n }\n }\n }\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Render a list with keyed items for efficient updates\n */\nexport function For<T>(props: {\n each: T[] | Accessor<T[]>;\n key?: (item: T) => string | number;\n children: (item: Accessor<T>, index: Accessor<number>) => any;\n}): any {\n const container = document.createComment(\"for\");\n const nodes = new Map<string | number, HTMLElement>();\n const order: Array<string | number> = [];\n\n const getEach = (): T[] => {\n return typeof props.each === \"function\" ? (props.each as Accessor<T[]>)() : props.each;\n };\n\n const runEffect = () => {\n const items = getEach();\n const newOrder: Array<string | number> = [];\n const newNodes = new Map<string | number, HTMLElement>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n const key = props.key ? props.key(item) : i;\n newOrder.push(key);\n\n if (nodes.has(key)) {\n newNodes.set(key, nodes.get(key)!);\n } else {\n const itemSig = sig(item);\n const indexSig = sig(i);\n const child = props.children(\n () => val(itemSig),\n () => val(indexSig),\n ) as HTMLElement;\n newNodes.set(key, child);\n }\n }\n\n for (const key of order) {\n if (!newNodes.has(key)) {\n const node = nodes.get(key);\n if (node?.parentNode) {\n node.parentNode.removeChild(node);\n }\n }\n }\n\n const insertNodes = () => {\n if (container.parentNode) {\n let prevSibling = container.nextSibling;\n for (const key of newOrder) {\n const node = newNodes.get(key)!;\n if (!nodes.has(key) && !node.parentNode) {\n container.parentNode!.insertBefore(node, prevSibling);\n } else if (prevSibling !== node) {\n container.parentNode!.insertBefore(node, prevSibling);\n }\n prevSibling = node.nextSibling;\n }\n }\n };\n\n if (container.parentNode) {\n insertNodes();\n } else {\n queueMicrotask(insertNodes);\n }\n\n order.length = 0;\n order.push(...newOrder);\n nodes.clear();\n for (const [k, v] of newNodes) {\n nodes.set(k, v);\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Render a list with index-based tracking\n */\nexport function Index<T>(props: {\n each: T[] | Accessor<T[]>;\n children: (item: Accessor<T>, index: number) => any;\n}): any {\n const container = document.createComment(\"index\");\n const nodes: Array<HTMLElement | null> = [];\n\n const getEach = (): T[] => {\n return typeof props.each === \"function\" ? (props.each as Accessor<T[]>)() : props.each;\n };\n\n const runEffect = () => {\n const items = getEach();\n\n while (nodes.length > items.length) {\n const node = nodes.pop();\n if (node?.parentNode) {\n node.parentNode.removeChild(node);\n }\n }\n\n const insertNodes = () => {\n if (container.parentNode) {\n for (let i = 0; i < items.length; i++) {\n if (nodes[i] === undefined) {\n const itemSig = sig(items[i]!);\n const child = props.children(() => val(itemSig), i) as HTMLElement;\n nodes[i] = child;\n if (!child.parentNode) {\n container.parentNode.insertBefore(child, container.nextSibling);\n }\n }\n }\n }\n };\n\n if (container.parentNode) {\n insertNodes();\n } else {\n queueMicrotask(insertNodes);\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Switch component for mutually exclusive conditions\n */\nexport function Switch(props: { fallback?: any; children: any }): any {\n const container = document.createComment(\"switch\");\n let rendered: HTMLElement | null = null;\n\n const evaluate = (): any => {\n const children = props.children;\n if (Array.isArray(children)) {\n for (const child of children) {\n if (child && (child as any)._matchWhen) {\n const when = (child as any)._matchWhen;\n const condition = typeof when === \"function\" ? when() : when;\n if (condition) {\n return (child as any)._matchChildren;\n }\n }\n }\n }\n return props.fallback;\n };\n\n const runEffect = () => {\n const content = evaluate();\n if (rendered) {\n rendered.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (content) {\n rendered =\n typeof content === \"function\" ? (content() as HTMLElement) : (content as HTMLElement);\n if (rendered && !rendered.parentNode) {\n const insertNode = () => {\n if (rendered && container.parentNode && !rendered.parentNode) {\n container.parentNode.insertBefore(rendered, container.nextSibling);\n }\n };\n if (container.parentNode) {\n insertNode();\n } else {\n queueMicrotask(insertNode);\n }\n }\n }\n };\n\n const tracker = memo(() => {\n runEffect();\n return true;\n });\n\n // Run effect synchronously\n val(tracker);\n\n return container;\n}\n\n/**\n * Match component for use inside Switch\n */\nexport function Match<T>(props: { when: T | Accessor<T>; children: any }): any {\n const marker = document.createComment(\"match\");\n (marker as any)._matchWhen = typeof props.when === \"function\" ? props.when : () => props.when;\n (marker as any)._matchChildren = props.children;\n return marker;\n}\n\n/**\n * Portal component for rendering outside the current DOM hierarchy\n */\nexport function Portal(props: { mount?: HTMLElement; children: any }): any {\n const container = document.createComment(\"portal\");\n const mountPoint = props.mount || document.body;\n let rendered: HTMLElement | null = null;\n\n createRoot(() => {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n mountPoint.appendChild(rendered);\n }\n\n signalOnCleanup(() => {\n if (rendered && rendered.parentNode === mountPoint) {\n mountPoint.removeChild(rendered);\n }\n });\n });\n\n return container;\n}\n\n/**\n * Suspense component for async loading states\n */\nexport function Suspense(props: { fallback?: any; children: any }): any {\n const container = document.createComment(\"suspense\");\n let rendered: HTMLElement | null = null;\n let fallbackNode: HTMLElement | null = null;\n\n tick(() => {\n try {\n if (fallbackNode) {\n container.parentNode?.removeChild(fallbackNode);\n fallbackNode = null;\n }\n if (!rendered && props.children) {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n } catch {\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n if (props.fallback && !fallbackNode) {\n fallbackNode =\n typeof props.fallback === \"function\"\n ? (props.fallback() as HTMLElement)\n : (props.fallback as HTMLElement);\n if (fallbackNode) {\n container.parentNode?.insertBefore(fallbackNode, container.nextSibling);\n }\n }\n }\n });\n\n return container;\n}\n\n/**\n * ErrorBoundary component for catching render errors\n */\nexport function ErrorBoundary(props: {\n fallback: (err: Error, reset: () => void) => any;\n children: any;\n}): any {\n const container = document.createComment(\"error-boundary\");\n let rendered: HTMLElement | null = null;\n let error: Error | null = null;\n\n const reset = () => {\n error = null;\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n tick(() => {\n try {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e));\n if (rendered) {\n container.parentNode?.removeChild(rendered);\n rendered = null;\n }\n const fallback = props.fallback(error, reset);\n rendered =\n typeof fallback === \"function\" ? (fallback() as HTMLElement) : (fallback as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n });\n };\n\n tick(() => {\n try {\n rendered =\n typeof props.children === \"function\"\n ? (props.children() as HTMLElement)\n : (props.children as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e));\n const fallback = props.fallback(error, reset);\n rendered =\n typeof fallback === \"function\" ? (fallback() as HTMLElement) : (fallback as HTMLElement);\n if (rendered) {\n container.parentNode?.insertBefore(rendered, container.nextSibling);\n }\n }\n });\n\n return container;\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,KAAQ,OAAsE;CAC5F,MAAM,YAAY,SAAS,cAAc,OAAO;CAChD,IAAI,WAA+B;CACnC,IAAI,eAAmC;CAGvC,MAAM,qBAA0B;AAC9B,SAAO,OAAO,MAAM,SAAS,aAAc,MAAM,MAAsB,GAAG,MAAM;;CAGlF,MAAM,kBAAkB;AAEtB,MADa,cAAc,EACjB;AACR,OAAI,cAAc;AAChB,iBAAa,YAAY,YAAY,aAAa;AAClD,mBAAe;;AAEjB,OAAI,CAAC,YAAY,MAAM,UAAU;AAC/B,eACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,QAAI,YAAY,CAAC,SAAS,WAExB,KAAI,UAAU,WACZ,WAAU,WAAW,aAAa,UAAU,UAAU,YAAY;QAElE,sBAAqB;AACnB,SAAI,YAAY,CAAC,SAAS,cAAc,UAAU,WAChD,WAAU,WAAW,aAAa,UAAU,UAAU,YAAY;MAEpE;;SAIH;AACL,OAAI,UAAU;AACZ,aAAS,YAAY,YAAY,SAAS;AAC1C,eAAW;;AAEb,OAAI,MAAM,YAAY,CAAC,cAAc;AACnC,mBACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,QAAI,gBAAgB,CAAC,aAAa,WAChC,KAAI,UAAU,WACZ,WAAU,WAAW,aAAa,cAAc,UAAU,YAAY;QAEtE,sBAAqB;AACnB,SAAI,gBAAgB,CAAC,aAAa,cAAc,UAAU,WACxD,WAAU,WAAW,aAAa,cAAc,UAAU,YAAY;MAExE;;;;AAaZ,KANgB,WAAW;AACzB,aAAW;AACX,SAAO;GACP,CAGU;AAEZ,QAAO;;;;;AAMT,SAAgB,IAAO,OAIf;CACN,MAAM,YAAY,SAAS,cAAc,MAAM;CAC/C,MAAM,wBAAQ,IAAI,KAAmC;CACrD,MAAM,QAAgC,EAAE;CAExC,MAAM,gBAAqB;AACzB,SAAO,OAAO,MAAM,SAAS,aAAc,MAAM,MAAwB,GAAG,MAAM;;CAGpF,MAAM,kBAAkB;EACtB,MAAM,QAAQ,SAAS;EACvB,MAAM,WAAmC,EAAE;EAC3C,MAAM,2BAAW,IAAI,KAAmC;AAExD,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI,KAAK,GAAG;AAC1C,YAAS,KAAK,IAAI;AAElB,OAAI,MAAM,IAAI,IAAI,CAChB,UAAS,IAAI,KAAK,MAAM,IAAI,IAAI,CAAE;QAC7B;IACL,MAAM,UAAU,IAAI,KAAK;IACzB,MAAM,WAAW,IAAI,EAAE;IACvB,MAAM,QAAQ,MAAM,eACZ,IAAI,QAAQ,QACZ,IAAI,SAAS,CACpB;AACD,aAAS,IAAI,KAAK,MAAM;;;AAI5B,OAAK,MAAM,OAAO,MAChB,KAAI,CAAC,SAAS,IAAI,IAAI,EAAE;GACtB,MAAM,OAAO,MAAM,IAAI,IAAI;AAC3B,OAAI,MAAM,WACR,MAAK,WAAW,YAAY,KAAK;;EAKvC,MAAM,oBAAoB;AACxB,OAAI,UAAU,YAAY;IACxB,IAAI,cAAc,UAAU;AAC5B,SAAK,MAAM,OAAO,UAAU;KAC1B,MAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,SAAI,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,WAC3B,WAAU,WAAY,aAAa,MAAM,YAAY;cAC5C,gBAAgB,KACzB,WAAU,WAAY,aAAa,MAAM,YAAY;AAEvD,mBAAc,KAAK;;;;AAKzB,MAAI,UAAU,WACZ,cAAa;MAEb,gBAAe,YAAY;AAG7B,QAAM,SAAS;AACf,QAAM,KAAK,GAAG,SAAS;AACvB,QAAM,OAAO;AACb,OAAK,MAAM,CAAC,GAAG,MAAM,SACnB,OAAM,IAAI,GAAG,EAAE;;AAUnB,KANgB,WAAW;AACzB,aAAW;AACX,SAAO;GACP,CAGU;AAEZ,QAAO;;;;;AAMT,SAAgB,MAAS,OAGjB;CACN,MAAM,YAAY,SAAS,cAAc,QAAQ;CACjD,MAAM,QAAmC,EAAE;CAE3C,MAAM,gBAAqB;AACzB,SAAO,OAAO,MAAM,SAAS,aAAc,MAAM,MAAwB,GAAG,MAAM;;CAGpF,MAAM,kBAAkB;EACtB,MAAM,QAAQ,SAAS;AAEvB,SAAO,MAAM,SAAS,MAAM,QAAQ;GAClC,MAAM,OAAO,MAAM,KAAK;AACxB,OAAI,MAAM,WACR,MAAK,WAAW,YAAY,KAAK;;EAIrC,MAAM,oBAAoB;AACxB,OAAI,UAAU;SACP,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,KAAI,MAAM,OAAO,KAAA,GAAW;KAC1B,MAAM,UAAU,IAAI,MAAM,GAAI;KAC9B,MAAM,QAAQ,MAAM,eAAe,IAAI,QAAQ,EAAE,EAAE;AACnD,WAAM,KAAK;AACX,SAAI,CAAC,MAAM,WACT,WAAU,WAAW,aAAa,OAAO,UAAU,YAAY;;;;AAOzE,MAAI,UAAU,WACZ,cAAa;MAEb,gBAAe,YAAY;;AAU/B,KANgB,WAAW;AACzB,aAAW;AACX,SAAO;GACP,CAGU;AAEZ,QAAO;;;;;AAMT,SAAgB,OAAO,OAA+C;CACpE,MAAM,YAAY,SAAS,cAAc,SAAS;CAClD,IAAI,WAA+B;CAEnC,MAAM,iBAAsB;EAC1B,MAAM,WAAW,MAAM;AACvB,MAAI,MAAM,QAAQ,SAAS;QACpB,MAAM,SAAS,SAClB,KAAI,SAAU,MAAc,YAAY;IACtC,MAAM,OAAQ,MAAc;AAE5B,QADkB,OAAO,SAAS,aAAa,MAAM,GAAG,KAEtD,QAAQ,MAAc;;;AAK9B,SAAO,MAAM;;CAGf,MAAM,kBAAkB;EACtB,MAAM,UAAU,UAAU;AAC1B,MAAI,UAAU;AACZ,YAAS,YAAY,YAAY,SAAS;AAC1C,cAAW;;AAEb,MAAI,SAAS;AACX,cACE,OAAO,YAAY,aAAc,SAAS,GAAoB;AAChE,OAAI,YAAY,CAAC,SAAS,YAAY;IACpC,MAAM,mBAAmB;AACvB,SAAI,YAAY,UAAU,cAAc,CAAC,SAAS,WAChD,WAAU,WAAW,aAAa,UAAU,UAAU,YAAY;;AAGtE,QAAI,UAAU,WACZ,aAAY;QAEZ,gBAAe,WAAW;;;;AAYlC,KANgB,WAAW;AACzB,aAAW;AACX,SAAO;GACP,CAGU;AAEZ,QAAO;;;;;AAMT,SAAgB,MAAS,OAAsD;CAC7E,MAAM,SAAS,SAAS,cAAc,QAAQ;AAC7C,QAAe,aAAa,OAAO,MAAM,SAAS,aAAa,MAAM,aAAa,MAAM;AACxF,QAAe,iBAAiB,MAAM;AACvC,QAAO;;;;;AAMT,SAAgB,OAAO,OAAoD;CACzE,MAAM,YAAY,SAAS,cAAc,SAAS;CAClD,MAAM,aAAa,MAAM,SAAS,SAAS;CAC3C,IAAI,WAA+B;AAEnC,kBAAiB;AACf,aACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,MAAI,SACF,YAAW,YAAY,SAAS;AAGlC,kBAAsB;AACpB,OAAI,YAAY,SAAS,eAAe,WACtC,YAAW,YAAY,SAAS;IAElC;GACF;AAEF,QAAO;;;;;AAMT,SAAgB,SAAS,OAA+C;CACtE,MAAM,YAAY,SAAS,cAAc,WAAW;CACpD,IAAI,WAA+B;CACnC,IAAI,eAAmC;AAEvC,YAAW;AACT,MAAI;AACF,OAAI,cAAc;AAChB,cAAU,YAAY,YAAY,aAAa;AAC/C,mBAAe;;AAEjB,OAAI,CAAC,YAAY,MAAM,UAAU;AAC/B,eACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,QAAI,SACF,WAAU,YAAY,aAAa,UAAU,UAAU,YAAY;;UAGjE;AACN,OAAI,UAAU;AACZ,cAAU,YAAY,YAAY,SAAS;AAC3C,eAAW;;AAEb,OAAI,MAAM,YAAY,CAAC,cAAc;AACnC,mBACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,QAAI,aACF,WAAU,YAAY,aAAa,cAAc,UAAU,YAAY;;;GAI7E;AAEF,QAAO;;;;;AAMT,SAAgB,cAAc,OAGtB;CACN,MAAM,YAAY,SAAS,cAAc,iBAAiB;CAC1D,IAAI,WAA+B;CACnC,IAAI,QAAsB;CAE1B,MAAM,cAAc;AAClB,UAAQ;AACR,MAAI,UAAU;AACZ,aAAU,YAAY,YAAY,SAAS;AAC3C,cAAW;;AAEb,aAAW;AACT,OAAI;AACF,eACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,QAAI,SACF,WAAU,YAAY,aAAa,UAAU,UAAU,YAAY;YAE9D,GAAG;AACV,YAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC;AACrD,QAAI,UAAU;AACZ,eAAU,YAAY,YAAY,SAAS;AAC3C,gBAAW;;IAEb,MAAM,WAAW,MAAM,SAAS,OAAO,MAAM;AAC7C,eACE,OAAO,aAAa,aAAc,UAAU,GAAoB;AAClE,QAAI,SACF,WAAU,YAAY,aAAa,UAAU,UAAU,YAAY;;IAGvE;;AAGJ,YAAW;AACT,MAAI;AACF,cACE,OAAO,MAAM,aAAa,aACrB,MAAM,UAAU,GAChB,MAAM;AACb,OAAI,SACF,WAAU,YAAY,aAAa,UAAU,UAAU,YAAY;WAE9D,GAAG;AACV,WAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC;GACrD,MAAM,WAAW,MAAM,SAAS,OAAO,MAAM;AAC7C,cACE,OAAO,aAAa,aAAc,UAAU,GAAoB;AAClE,OAAI,SACF,WAAU,YAAY,aAAa,UAAU,UAAU,YAAY;;GAGvE;AAEF,QAAO"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/scheduler/scheduler.ts
|
|
2
|
+
/**
|
|
3
|
+
* Frame scheduler for @hedystia/view
|
|
4
|
+
*
|
|
5
|
+
* Provides requestAnimationFrame-based batching for visual updates.
|
|
6
|
+
*/
|
|
7
|
+
let scheduledRaf = null;
|
|
8
|
+
let rafCallbacks = [];
|
|
9
|
+
/**
|
|
10
|
+
* Schedule a callback for the next animation frame
|
|
11
|
+
* @param {() => void} fn - The callback to run on next frame
|
|
12
|
+
* @example
|
|
13
|
+
* tick(() => {
|
|
14
|
+
* // DOM updates here
|
|
15
|
+
* });
|
|
16
|
+
*/
|
|
17
|
+
function tick(fn) {
|
|
18
|
+
rafCallbacks.push(fn);
|
|
19
|
+
if (scheduledRaf === null) scheduledRaf = requestAnimationFrame(flushRaf);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wait for the next animation frame
|
|
23
|
+
* @returns {Promise<void>} A promise that resolves on next frame
|
|
24
|
+
* @example
|
|
25
|
+
* await nextFrame();
|
|
26
|
+
*/
|
|
27
|
+
function nextFrame() {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
tick(resolve);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** @internal */
|
|
33
|
+
function flushRaf() {
|
|
34
|
+
scheduledRaf = null;
|
|
35
|
+
const callbacks = rafCallbacks;
|
|
36
|
+
rafCallbacks = [];
|
|
37
|
+
for (let i = 0; i < callbacks.length; i++) callbacks[i]();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Force flush all pending RAF callbacks synchronously (for testing)
|
|
41
|
+
* @example
|
|
42
|
+
* await tick(); // forces flush
|
|
43
|
+
*/
|
|
44
|
+
function forceFlush() {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
if (scheduledRaf !== null) {
|
|
47
|
+
cancelAnimationFrame(scheduledRaf);
|
|
48
|
+
scheduledRaf = null;
|
|
49
|
+
}
|
|
50
|
+
const callbacks = rafCallbacks;
|
|
51
|
+
rafCallbacks = [];
|
|
52
|
+
for (let i = 0; i < callbacks.length; i++) callbacks[i]();
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
exports.forceFlush = forceFlush;
|
|
58
|
+
exports.nextFrame = nextFrame;
|
|
59
|
+
exports.tick = tick;
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=scheduler.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.cjs","names":[],"sources":["../../src/scheduler/scheduler.ts"],"sourcesContent":["/**\n * Frame scheduler for @hedystia/view\n *\n * Provides requestAnimationFrame-based batching for visual updates.\n */\n\nlet scheduledRaf: number | null = null;\nlet rafCallbacks: Array<() => void> = [];\n\n/**\n * Schedule a callback for the next animation frame\n * @param {() => void} fn - The callback to run on next frame\n * @example\n * tick(() => {\n * // DOM updates here\n * });\n */\nexport function tick(fn: () => void): void {\n rafCallbacks.push(fn);\n if (scheduledRaf === null) {\n scheduledRaf = requestAnimationFrame(flushRaf);\n }\n}\n\n/**\n * Wait for the next animation frame\n * @returns {Promise<void>} A promise that resolves on next frame\n * @example\n * await nextFrame();\n */\nexport function nextFrame(): Promise<void> {\n return new Promise((resolve) => {\n tick(resolve);\n });\n}\n\n/** @internal */\nfunction flushRaf(): void {\n scheduledRaf = null;\n const callbacks = rafCallbacks;\n rafCallbacks = [];\n for (let i = 0; i < callbacks.length; i++) {\n callbacks[i]!();\n }\n}\n\n/**\n * Force flush all pending RAF callbacks synchronously (for testing)\n * @example\n * await tick(); // forces flush\n */\nexport function forceFlush(): Promise<void> {\n return new Promise((resolve) => {\n if (scheduledRaf !== null) {\n cancelAnimationFrame(scheduledRaf);\n scheduledRaf = null;\n }\n const callbacks = rafCallbacks;\n rafCallbacks = [];\n for (let i = 0; i < callbacks.length; i++) {\n callbacks[i]!();\n }\n resolve();\n });\n}\n"],"mappings":";;;;;;AAMA,IAAI,eAA8B;AAClC,IAAI,eAAkC,EAAE;;;;;;;;;AAUxC,SAAgB,KAAK,IAAsB;AACzC,cAAa,KAAK,GAAG;AACrB,KAAI,iBAAiB,KACnB,gBAAe,sBAAsB,SAAS;;;;;;;;AAUlD,SAAgB,YAA2B;AACzC,QAAO,IAAI,SAAS,YAAY;AAC9B,OAAK,QAAQ;GACb;;;AAIJ,SAAS,WAAiB;AACxB,gBAAe;CACf,MAAM,YAAY;AAClB,gBAAe,EAAE;AACjB,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IACpC,WAAU,IAAK;;;;;;;AASnB,SAAgB,aAA4B;AAC1C,QAAO,IAAI,SAAS,YAAY;AAC9B,MAAI,iBAAiB,MAAM;AACzB,wBAAqB,aAAa;AAClC,kBAAe;;EAEjB,MAAM,YAAY;AAClB,iBAAe,EAAE;AACjB,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IACpC,WAAU,IAAK;AAEjB,WAAS;GACT"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/scheduler/scheduler.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Frame scheduler for @hedystia/view
|
|
4
|
+
*
|
|
5
|
+
* Provides requestAnimationFrame-based batching for visual updates.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Schedule a callback for the next animation frame
|
|
9
|
+
* @param {() => void} fn - The callback to run on next frame
|
|
10
|
+
* @example
|
|
11
|
+
* tick(() => {
|
|
12
|
+
* // DOM updates here
|
|
13
|
+
* });
|
|
14
|
+
*/
|
|
15
|
+
declare function tick(fn: () => void): void;
|
|
16
|
+
/**
|
|
17
|
+
* Wait for the next animation frame
|
|
18
|
+
* @returns {Promise<void>} A promise that resolves on next frame
|
|
19
|
+
* @example
|
|
20
|
+
* await nextFrame();
|
|
21
|
+
*/
|
|
22
|
+
declare function nextFrame(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Force flush all pending RAF callbacks synchronously (for testing)
|
|
25
|
+
* @example
|
|
26
|
+
* await tick(); // forces flush
|
|
27
|
+
*/
|
|
28
|
+
declare function forceFlush(): Promise<void>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { forceFlush, nextFrame, tick };
|
|
31
|
+
//# sourceMappingURL=scheduler.d.cts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/scheduler/scheduler.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Frame scheduler for @hedystia/view
|
|
4
|
+
*
|
|
5
|
+
* Provides requestAnimationFrame-based batching for visual updates.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Schedule a callback for the next animation frame
|
|
9
|
+
* @param {() => void} fn - The callback to run on next frame
|
|
10
|
+
* @example
|
|
11
|
+
* tick(() => {
|
|
12
|
+
* // DOM updates here
|
|
13
|
+
* });
|
|
14
|
+
*/
|
|
15
|
+
declare function tick(fn: () => void): void;
|
|
16
|
+
/**
|
|
17
|
+
* Wait for the next animation frame
|
|
18
|
+
* @returns {Promise<void>} A promise that resolves on next frame
|
|
19
|
+
* @example
|
|
20
|
+
* await nextFrame();
|
|
21
|
+
*/
|
|
22
|
+
declare function nextFrame(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Force flush all pending RAF callbacks synchronously (for testing)
|
|
25
|
+
* @example
|
|
26
|
+
* await tick(); // forces flush
|
|
27
|
+
*/
|
|
28
|
+
declare function forceFlush(): Promise<void>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { forceFlush, nextFrame, tick };
|
|
31
|
+
//# sourceMappingURL=scheduler.d.mts.map
|