@luna_ui/luna 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/dist/cli.mjs +1264 -27
  2. package/dist/css/index.d.ts +194 -0
  3. package/dist/css/index.js +721 -0
  4. package/dist/css/runtime.d.ts +92 -0
  5. package/dist/css/runtime.js +179 -0
  6. package/dist/index.js +1 -1
  7. package/dist/jsx-dev-runtime.js +1 -1
  8. package/dist/jsx-runtime.d.ts +5 -0
  9. package/dist/jsx-runtime.js +1 -1
  10. package/dist/src-CHiGeWfy.js +1 -0
  11. package/dist/vite-plugin.d.ts +122 -0
  12. package/dist/vite-plugin.js +1518 -0
  13. package/package.json +16 -2
  14. package/src/css/extract.ts +798 -0
  15. package/src/css/index.ts +10 -0
  16. package/src/css/inject.ts +205 -0
  17. package/src/css/inline.ts +182 -0
  18. package/src/css/minify.ts +70 -0
  19. package/src/css/optimizer.ts +6 -0
  20. package/src/css/runtime.ts +344 -0
  21. package/src/css-optimizer/README.md +353 -0
  22. package/src/css-optimizer/cooccurrence.ts +100 -0
  23. package/src/css-optimizer/core.ts +263 -0
  24. package/src/css-optimizer/extractors.ts +243 -0
  25. package/src/css-optimizer/hash.ts +54 -0
  26. package/src/css-optimizer/index.ts +129 -0
  27. package/src/css-optimizer/merge.ts +109 -0
  28. package/src/css-optimizer/moonbit-analyzer.ts +210 -0
  29. package/src/css-optimizer/parser.ts +120 -0
  30. package/src/css-optimizer/pattern.ts +171 -0
  31. package/src/css-optimizer/transformers.ts +301 -0
  32. package/src/css-optimizer/types.ts +128 -0
  33. package/src/event-utils.ts +227 -0
  34. package/src/index.ts +890 -0
  35. package/src/jsx-dev-runtime.ts +2 -0
  36. package/src/jsx-runtime.ts +398 -0
  37. package/src/vite-plugin.ts +718 -0
  38. package/tests/__screenshots__/context.test.ts/Context-API-context-with-reactive-effects-context-value-accessible-in-effect-1.png +0 -0
  39. package/tests/__screenshots__/dom.test.ts/DOM-API-For-component--SolidJS-style--For-updates-when-signal-changes-1.png +0 -0
  40. package/tests/__screenshots__/dom.test.ts/DOM-API-Show-component--SolidJS-style--Show-accepts-children-as-function-1.png +0 -0
  41. package/tests/__screenshots__/dom.test.ts/DOM-API-Show-component--SolidJS-style--Show-toggles-visibility-1.png +0 -0
  42. package/tests/__screenshots__/dom.test.ts/DOM-API-createElement-createElement-with-dynamic-attribute-1.png +0 -0
  43. package/tests/__screenshots__/dom.test.ts/DOM-API-createElement-createElement-with-dynamic-style-1.png +0 -0
  44. package/tests/__screenshots__/dom.test.ts/DOM-API-createElementNs--SVG-support--createElementNs-with-dynamic-attribute-1.png +0 -0
  45. package/tests/__screenshots__/dom.test.ts/DOM-API-effect-with-DOM-effect-tracks-signal-changes-1.png +0 -0
  46. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-handles-clear-to-empty-1.png +0 -0
  47. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-handles-empty-array-1.png +0 -0
  48. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-removes-items-1.png +0 -0
  49. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-renders-initial-list-1.png +0 -0
  50. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-updates-when-items-change-1.png +0 -0
  51. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-handles-empty-to-non-empty-transition-in-SVG-1.png +0 -0
  52. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-handles-reordering-in-SVG-1.png +0 -0
  53. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-updates-SVG-elements-when-signal-changes-1.png +0 -0
  54. package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-with-nested-SVG-groups-1.png +0 -0
  55. package/tests/__screenshots__/dom.test.ts/DOM-API-ref-callback--JSX-style--ref-callback-with-nested-elements-1.png +0 -0
  56. package/tests/__screenshots__/dom.test.ts/DOM-API-show--conditional-rendering--show-creates-a-node-1.png +0 -0
  57. package/tests/__screenshots__/dom.test.ts/DOM-API-show--conditional-rendering--show-with-false-condition-creates-placeholder-1.png +0 -0
  58. package/tests/__screenshots__/dom.test.ts/DOM-API-text-nodes-textDyn-creates-reactive-text-node-1.png +0 -0
  59. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-forEach-renders-correctly-without-show--initial-items--1.png +0 -0
  60. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-forEach-with-context-renders-correctly-without-show-1.png +0 -0
  61. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-nested-components-with-context--forEach--and-show-1.png +0 -0
  62. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-show-and-forEach-inherit-context-from-Owner--fixed--1.png +0 -0
  63. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-show-and-forEach-work-together--context-uses-default--1.png +0 -0
  64. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Context---ForEach-integration-forEach-items-can-access-context-1.png +0 -0
  65. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-renders-initial-list-1.png +0 -0
  66. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-updates-when-signal-changes-1.png +0 -0
  67. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-with-object-items-1.png +0 -0
  68. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-hides-when-condition-is-false-1.png +0 -0
  69. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-renders-when-condition-is-true-1.png +0 -0
  70. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-toggles-from-false-to-true-1.png +0 -0
  71. package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-toggles-reactively-1.png +0 -0
  72. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--event-listener-pattern--Solid-js-docs-example--1.png +0 -0
  73. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--multiple-cleanups-in-component-body--LIFO-order--1.png +0 -0
  74. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--onCleanup-in-component-body-runs-on-unmount-1.png +0 -0
  75. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--onCleanup-works-with-For-loop-items--component-body-style--1.png +0 -0
  76. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--timer-cleanup-pattern--Solid-js-style--1.png +0 -0
  77. package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Effects-effect-cleanup-runs-before-re-run-1.png +0 -0
  78. package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-large-list-update-1.png +0 -0
  79. package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-nested-batch-operations-1.png +0 -0
  80. package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-rapid-sequential-updates-1.png +0 -0
  81. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Conditional-Show-component---visible-1.png +0 -0
  82. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Conditional-show-hide-element---visible-1.png +0 -0
  83. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-fragment-with-list-1.png +0 -0
  84. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-nested-fragments-1.png +0 -0
  85. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-simple-fragment-1.png +0 -0
  86. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-conditional-toggle-updates-1.png +0 -0
  87. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-list-addition-updates-match-1.png +0 -0
  88. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-list-removal-updates-match-1.png +0 -0
  89. package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-text-updates-match-1.png +0 -0
  90. package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-dynamic-className-updates-1.png +0 -0
  91. package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-dynamic-style-updates-1.png +0 -0
  92. package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-multiple-dynamic-attributes-1.png +0 -0
  93. package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-deeply-nested-conditionals-1.png +0 -0
  94. package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-list-transitions-from-empty-to-populated-1.png +0 -0
  95. package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-list-transitions-from-populated-to-empty-1.png +0 -0
  96. package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-nested-effects-cleanup-order-1.png +0 -0
  97. package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-nested-effects-with-inner-signal-change-1.png +0 -0
  98. package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-onCleanup-is-called-when-effect-re-runs-1.png +0 -0
  99. package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-onCleanup-with-resource-simulation-1.png +0 -0
  100. package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-Fragment-with-multiple-children--no-wrapper--1.png +0 -0
  101. package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-Fragment-with-no-children-1.png +0 -0
  102. package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-fragment-with-list-1.png +0 -0
  103. package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-nested-Fragments-work-correctly-1.png +0 -0
  104. package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-complex-reordering-with-additions-and-removals-1.png +0 -0
  105. package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-insert-in-middle-1.png +0 -0
  106. package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-remove-from-middle-1.png +0 -0
  107. package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-reverse-list-order-1.png +0 -0
  108. package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-shuffle-list-1.png +0 -0
  109. package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-Show-component-renders-when-condition-is-true-1.png +0 -0
  110. package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-show-renders-content-when-initially-true-1.png +0 -0
  111. package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-show-toggles-visibility-dynamically-1.png +0 -0
  112. package/tests/__screenshots__/preact-signals-comparison.test.ts/Memo-Dependency-Chain-conditional-memo-dependencies-1.png +0 -0
  113. package/tests/__screenshots__/preact-signals-comparison.test.ts/Signal-Behavior-Comparison-basic-signal-get-set-produces-same-values-1.png +0 -0
  114. package/tests/__screenshots__/preact-signals-comparison.test.ts/Signal-Behavior-Comparison-batch-updates-produce-same-final-values-1.png +0 -0
  115. package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-peek-reads-value-without-tracking-1.png +0 -0
  116. package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-selective-tracking-with-untrack-1.png +0 -0
  117. package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-untrack-prevents-dependency-tracking-1.png +0 -0
  118. package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--reactivity-accessor-is-reactive-1.png +0 -0
  119. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateError-returns-empty-string-for-non-failure-1.png +0 -0
  120. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateError-returns-undefined-for-non-failure-1.png +0 -0
  121. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsFailure-and-stateError-1.png +0 -0
  122. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsPending-1.png +0 -0
  123. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsSuccess-and-stateValue-1.png +0 -0
  124. package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateValue-returns-undefined-for-non-success-1.png +0 -0
  125. package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-reject-transitions-to-failure-1.png +0 -0
  126. package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-resolve-transitions-to-success-1.png +0 -0
  127. package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-returns-resource--resolve--and-reject-functions-1.png +0 -0
  128. package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-starts-in-pending-state-1.png +0 -0
  129. package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-async-resolve-works-1.png +0 -0
  130. package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-starts-in-pending-state-1.png +0 -0
  131. package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-transitions-to-failure-on-reject-1.png +0 -0
  132. package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-transitions-to-success-on-resolve-1.png +0 -0
  133. package/tests/__screenshots__/resource.test.ts/Resource-API-integration-with-Promise-can-wrap-fetch-like-async-operations-1.png +0 -0
  134. package/tests/__screenshots__/resource.test.ts/Resource-API-integration-with-Promise-works-with-setTimeout-simulation-1.png +0 -0
  135. package/tests/__screenshots__/resource.test.ts/Resource-API-resourceGet-vs-resourcePeek-resourceGet-tracks-dependencies-1.png +0 -0
  136. package/tests/__screenshots__/resource.test.ts/Resource-API-resourceGet-vs-resourcePeek-resourcePeek-does-not-track-dependencies-1.png +0 -0
  137. package/tests/__screenshots__/resource.test.ts/Resource-API-resourceRefetch-refetch-resets-to-pending-and-re-runs-fetcher-1.png +0 -0
  138. package/tests/__screenshots__/solidjs-api.test.ts/Portal-component-Portal-renders-children-to-body-by-default-1.png +0 -0
  139. package/tests/__screenshots__/solidjs-api.test.ts/Portal-component-Portal-renders-to-selector-mount-target-1.png +0 -0
  140. package/tests/__screenshots__/solidjs-api.test.ts/SolidJS-API-compatibility-createEffect-tracks-dependencies-automatically-1.png +0 -0
  141. package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-accessor-condition-in-Match-1.png +0 -0
  142. package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-multiple-Match-components-1.png +0 -0
  143. package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-single-Match-and-fallback-1.png +0 -0
  144. package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-components-Switch-updates-DOM-when-signal-changes-1.png +0 -0
  145. package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-tracks-multiple-dependencies-1.png +0 -0
  146. package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-tracks-single-dependency-1.png +0 -0
  147. package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-with-defer-option-skips-initial-run-1.png +0 -0
  148. package/tests/__screenshots__/store.test.ts/createStore-Arrays-array-updates-work-1.png +0 -0
  149. package/tests/__screenshots__/store.test.ts/createStore-Reactivity-only-triggers-when-accessed-property-changes-1.png +0 -0
  150. package/tests/__screenshots__/store.test.ts/createStore-Reactivity-parent-path-change-notifies-child-accessors-1.png +0 -0
  151. package/tests/__screenshots__/store.test.ts/createStore-Reactivity-tracks-nested-property-access-1.png +0 -0
  152. package/tests/__screenshots__/store.test.ts/createStore-Reactivity-tracks-property-access-in-effects-1.png +0 -0
  153. package/tests/context.test.ts +118 -0
  154. package/tests/css-optimizer-extractors.test.ts +264 -0
  155. package/tests/css-optimizer-integration.test.ts +566 -0
  156. package/tests/css-optimizer-transformers.test.ts +301 -0
  157. package/tests/css-optimizer.test.ts +646 -0
  158. package/tests/css-runtime.bench.ts +442 -0
  159. package/tests/css-runtime.test.ts +342 -0
  160. package/tests/dom.test.ts +872 -0
  161. package/tests/integration.test.ts +405 -0
  162. package/tests/issue-5-for-infinite-loop.test.ts +516 -0
  163. package/tests/jsx-runtime.test.tsx +393 -0
  164. package/tests/lifecycle.test.ts +833 -0
  165. package/tests/move-before.bench.ts +304 -0
  166. package/tests/preact-signals-comparison.test.ts +1608 -0
  167. package/tests/resource.test.ts +160 -0
  168. package/tests/router.test.ts +117 -0
  169. package/tests/show-initial-mount-leak.test.tsx +182 -0
  170. package/tests/solidjs-api.test.ts +659 -0
  171. package/tests/static-perf.bench.ts +64 -0
  172. package/tests/store.test.ts +263 -0
  173. package/tests/tsx-syntax.test.tsx +404 -0
  174. package/dist/src-DGWY0NYx.js +0 -1
package/src/index.ts ADDED
@@ -0,0 +1,890 @@
1
+ // @ts-nocheck
2
+ // Re-export from MoonBit build output (api_js)
3
+ // This file wraps MoonBit APIs to provide SolidJS-compatible interface
4
+
5
+ // Type definitions for SolidJS-compatible API
6
+
7
+ /**
8
+ * Represents a node created by Luna's reactive system.
9
+ * This is an opaque type - the actual structure is managed by MoonBit.
10
+ */
11
+ export type LunaNode = unknown;
12
+
13
+ export type Accessor<T> = () => T;
14
+ export type Setter<T> = (value: T | ((prev: T) => T)) => void;
15
+ export type Signal<T> = [Accessor<T>, Setter<T>];
16
+
17
+ export interface ForProps<T> {
18
+ each: Accessor<T[]> | T[];
19
+ fallback?: LunaNode;
20
+ children: (item: T, index: Accessor<number>) => LunaNode;
21
+ }
22
+
23
+ export interface ShowProps<T> {
24
+ when: T | Accessor<T>;
25
+ fallback?: LunaNode;
26
+ /** Must be a function to ensure proper lifecycle (onCleanup/onMount) support */
27
+ children: (() => LunaNode) | ((item: NonNullable<T>) => LunaNode);
28
+ }
29
+
30
+ export interface IndexProps<T> {
31
+ each: Accessor<T[]> | T[];
32
+ fallback?: LunaNode;
33
+ children: (item: Accessor<T>, index: number) => LunaNode;
34
+ }
35
+
36
+ export interface Context<T> {
37
+ id: number;
38
+ default_value: () => T;
39
+ providers: unknown[];
40
+ }
41
+
42
+ export interface ProviderProps<T> {
43
+ context: Context<T>;
44
+ value: T;
45
+ /** Must be a function to ensure proper context access and lifecycle (onCleanup/onMount) support */
46
+ children: () => LunaNode;
47
+ }
48
+
49
+ export interface MatchProps<T> {
50
+ when: T | Accessor<T>;
51
+ /** Must be a function to ensure proper lifecycle (onCleanup/onMount) support */
52
+ children: (() => LunaNode) | ((item: NonNullable<T>) => LunaNode);
53
+ }
54
+
55
+ export interface SwitchProps {
56
+ fallback?: LunaNode;
57
+ children: LunaNode[];
58
+ }
59
+
60
+ export interface PortalProps {
61
+ mount?: Element | string;
62
+ useShadow?: boolean;
63
+ /** Must be a function to ensure proper lifecycle (onCleanup/onMount) support */
64
+ children: () => LunaNode;
65
+ }
66
+
67
+ export interface ResourceAccessor<T> {
68
+ (): T | undefined;
69
+ loading: boolean;
70
+ error: string | undefined;
71
+ state: 'pending' | 'ready' | 'errored' | 'unresolved';
72
+ latest: T | undefined;
73
+ }
74
+
75
+ export type SetStoreFunction<T> = (...args: any[]) => void;
76
+
77
+ import {
78
+ // Signal API (internal)
79
+ createSignal as _createSignal,
80
+ get as _get,
81
+ set as _set,
82
+ update as _update,
83
+ peek as _peek,
84
+ subscribe as _subscribe,
85
+ map as _map,
86
+ createMemo as _createMemo,
87
+ combine as _combine,
88
+ effect as _effect,
89
+ renderEffect as _renderEffect,
90
+ batchStart,
91
+ batchEnd,
92
+ runUntracked,
93
+ batch,
94
+ onCleanup,
95
+ createRoot,
96
+ getOwner,
97
+ runWithOwner,
98
+ hasOwner,
99
+ onMount,
100
+ // DOM API
101
+ text,
102
+ textDyn,
103
+ render,
104
+ mount,
105
+ show,
106
+ jsx,
107
+ jsxs,
108
+ Fragment as fragment, // MoonBit's fragment function (Array -> LunaNode)
109
+ createElement,
110
+ createElementNs,
111
+ svgNs,
112
+ mathmlNs,
113
+ events,
114
+ forEach,
115
+ // Timer utilities
116
+ debounced as _debounced,
117
+ // Route definitions
118
+ routePage,
119
+ routePageTitled,
120
+ routePageFull,
121
+ createRouter,
122
+ routerNavigate,
123
+ routerReplace,
124
+ routerGetPath,
125
+ routerGetMatch,
126
+ routerGetBase,
127
+ // Context API
128
+ createContext,
129
+ provide,
130
+ useContext,
131
+ // Resource API
132
+ createResource as _createResource,
133
+ createDeferred as _createDeferred,
134
+ resourceGet,
135
+ resourcePeek,
136
+ resourceRefetch,
137
+ resourceIsPending,
138
+ resourceIsSuccess,
139
+ resourceIsFailure,
140
+ resourceValue,
141
+ resourceError,
142
+ stateIsPending,
143
+ stateIsSuccess,
144
+ stateIsFailure,
145
+ stateValue,
146
+ stateError,
147
+ // Portal API
148
+ portalToBody,
149
+ portalToSelector,
150
+ portalWithShadow,
151
+ portalToElementWithShadow,
152
+ } from "../../../target/js/release/build/platform/js/api/api.js";
153
+
154
+ // ============================================================================
155
+ // SolidJS-compatible Signal API
156
+ // ============================================================================
157
+
158
+ /**
159
+ * Creates a reactive signal (SolidJS-style)
160
+ */
161
+ export function createSignal<T>(initialValue: T): Signal<T> {
162
+ const signal = _createSignal(initialValue);
163
+
164
+ const getter: Accessor<T> = () => _get(signal);
165
+
166
+ const setter: Setter<T> = (valueOrUpdater) => {
167
+ if (typeof valueOrUpdater === "function") {
168
+ _update(signal, valueOrUpdater);
169
+ } else {
170
+ _set(signal, valueOrUpdater);
171
+ }
172
+ };
173
+
174
+ return [getter, setter];
175
+ }
176
+
177
+ /**
178
+ * Creates a reactive effect (SolidJS-style)
179
+ * Deferred execution via microtask - runs after rendering completes
180
+ */
181
+ export function createEffect(fn: () => void): () => void {
182
+ return _effect(fn);
183
+ }
184
+
185
+ /**
186
+ * Creates a render effect (SolidJS-style)
187
+ * Immediate/synchronous execution - runs during rendering
188
+ */
189
+ export function createRenderEffect(fn: () => void): () => void {
190
+ return _renderEffect(fn);
191
+ }
192
+
193
+ /**
194
+ * Creates a memoized computed value (SolidJS-style)
195
+ */
196
+ export function createMemo<T>(fn: () => T): Accessor<T> {
197
+ return _createMemo(fn);
198
+ }
199
+
200
+ /**
201
+ * Runs a function without tracking dependencies (SolidJS-style alias)
202
+ */
203
+ export { runUntracked as untrack };
204
+
205
+ /**
206
+ * Explicit dependency tracking helper (SolidJS-style)
207
+ * Wraps a function to explicitly specify which signals to track
208
+ *
209
+ * @template T
210
+ * @template U
211
+ * @param {(() => T) | Array<() => any>} deps - Signal accessor(s) to track
212
+ * @param {(input: T, prevInput?: T, prevValue?: U) => U} fn - Function to run with dependency values
213
+ * @param {{ defer?: boolean }} [options] - Options (defer: don't run on initial)
214
+ * @returns {(prevValue?: U) => U | undefined}
215
+ */
216
+ export function on(deps, fn, options = {}) {
217
+ const { defer = false } = options;
218
+ const isArray = Array.isArray(deps);
219
+
220
+ let prevInput;
221
+ let prevValue;
222
+ let isFirst = true;
223
+
224
+ return (injectedPrevValue) => {
225
+ // Get current dependency values
226
+ const input = isArray ? deps.map((d) => d()) : deps();
227
+
228
+ // Handle deferred execution
229
+ if (defer && isFirst) {
230
+ isFirst = false;
231
+ prevInput = input;
232
+ return undefined;
233
+ }
234
+
235
+ // Run the function with current and previous values
236
+ const result = fn(input, prevInput, injectedPrevValue ?? prevValue);
237
+
238
+ // Store for next run
239
+ prevInput = input;
240
+ prevValue = result;
241
+ isFirst = false;
242
+
243
+ return result;
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Merge multiple props objects, with later objects taking precedence (SolidJS-style)
249
+ * Event handlers and refs are merged, other props are overwritten
250
+ *
251
+ * @template T
252
+ * @param {...T} sources - Props objects to merge
253
+ * @returns {T}
254
+ */
255
+ export function mergeProps(...sources) {
256
+ const result = {};
257
+
258
+ for (const source of sources) {
259
+ if (!source) continue;
260
+
261
+ for (const key of Object.keys(source)) {
262
+ const value = source[key];
263
+
264
+ // Merge event handlers (on* props)
265
+ if (key.startsWith("on") && typeof value === "function") {
266
+ const existing = result[key];
267
+ if (typeof existing === "function") {
268
+ result[key] = (...args) => {
269
+ existing(...args);
270
+ value(...args);
271
+ };
272
+ } else {
273
+ result[key] = value;
274
+ }
275
+ }
276
+ // Merge ref callbacks
277
+ else if (key === "ref" && typeof value === "function") {
278
+ const existing = result[key];
279
+ if (typeof existing === "function") {
280
+ result[key] = (el) => {
281
+ existing(el);
282
+ value(el);
283
+ };
284
+ } else {
285
+ result[key] = value;
286
+ }
287
+ }
288
+ // Merge class/className
289
+ else if (key === "class" || key === "className") {
290
+ const existing = result[key];
291
+ if (existing) {
292
+ result[key] = `${existing} ${value}`;
293
+ } else {
294
+ result[key] = value;
295
+ }
296
+ }
297
+ // Merge style objects
298
+ else if (key === "style" && typeof value === "object" && typeof result[key] === "object") {
299
+ result[key] = { ...result[key], ...value };
300
+ }
301
+ // Default: overwrite
302
+ else {
303
+ result[key] = value;
304
+ }
305
+ }
306
+ }
307
+
308
+ return result;
309
+ }
310
+
311
+ /**
312
+ * Split props into multiple objects based on key lists (SolidJS-style)
313
+ *
314
+ * @template T
315
+ * @template K
316
+ * @param {T} props - Props object to split
317
+ * @param {...K[]} keys - Arrays of keys to extract
318
+ * @returns {[Pick<T, K>, Omit<T, K>]}
319
+ */
320
+ export function splitProps(props, ...keys) {
321
+ const result = [];
322
+ const remaining = { ...props };
323
+
324
+ for (const keyList of keys) {
325
+ const extracted = {};
326
+ for (const key of keyList) {
327
+ if (key in remaining) {
328
+ extracted[key] = remaining[key];
329
+ delete remaining[key];
330
+ }
331
+ }
332
+ result.push(extracted);
333
+ }
334
+
335
+ result.push(remaining);
336
+ return result;
337
+ }
338
+
339
+ /**
340
+ * Creates a resource for async data (SolidJS-style)
341
+ */
342
+ export function createResource<T>(fetcher: (resolve: (v: T) => void, reject: (e: string) => void) => void): [ResourceAccessor<T>, { refetch: () => void }] {
343
+ const resource = _createResource(fetcher);
344
+
345
+ // Use resourceGet for tracking dependencies, stateValue for actual value
346
+ const accessor = () => stateValue(resourceGet(resource));
347
+ Object.defineProperties(accessor, {
348
+ loading: { get: () => resourceIsPending(resource) },
349
+ error: { get: () => resourceError(resource) },
350
+ state: {
351
+ get: () => {
352
+ if (resourceIsPending(resource)) return "pending";
353
+ if (resourceIsSuccess(resource)) return "ready";
354
+ if (resourceIsFailure(resource)) return "errored";
355
+ return "unresolved";
356
+ },
357
+ },
358
+ latest: { get: () => resourcePeek(resource) },
359
+ });
360
+
361
+ return [accessor, { refetch: () => resourceRefetch(resource) }];
362
+ }
363
+
364
+ /**
365
+ * Creates a deferred resource (SolidJS-style)
366
+ */
367
+ export function createDeferred<T>(): [ResourceAccessor<T>, (value: T) => void, (error: string) => void] {
368
+ const result = _createDeferred();
369
+ const resource = result._0;
370
+ const resolve = result._1;
371
+ const reject = result._2;
372
+
373
+ // Use resourceGet for tracking dependencies, stateValue for actual value
374
+ const accessor = () => stateValue(resourceGet(resource));
375
+ Object.defineProperties(accessor, {
376
+ loading: { get: () => resourceIsPending(resource) },
377
+ error: { get: () => resourceError(resource) },
378
+ });
379
+
380
+ return [accessor, resolve, reject];
381
+ }
382
+
383
+ /**
384
+ * Debounces a signal (returns SolidJS-style signal)
385
+ */
386
+ export function debounced<T>(signal: Signal<T>, delayMs: number): Signal<T> {
387
+ const [getter] = signal;
388
+ const innerSignal = _createSignal(getter());
389
+ const debouncedInner = _debounced(innerSignal, delayMs);
390
+ return [() => _get(debouncedInner), (v) => _set(innerSignal, v)];
391
+ }
392
+
393
+ // ============================================================================
394
+ // SolidJS-compatible Component API
395
+ // ============================================================================
396
+
397
+ /**
398
+ * Resolves child content: if it's a function, calls it with args.
399
+ * If the result is an array, wraps it in a fragment.
400
+ */
401
+ function resolveChild(value: any, ...args: any[]): any {
402
+ if (typeof value === "function") {
403
+ const result = value(...args);
404
+ return Array.isArray(result) ? fragment(result) : result;
405
+ }
406
+ return Array.isArray(value) ? fragment(value) : value;
407
+ }
408
+
409
+ /**
410
+ * JSX-compatible Fragment component.
411
+ * Wraps children in a LunaNode fragment for use in JSX.
412
+ * Also supports direct array call for backwards compatibility: Fragment([...])
413
+ */
414
+ export function Fragment(propsOrChildren: { children?: any } | any[]): any {
415
+ // Support direct array call: Fragment([child1, child2])
416
+ if (Array.isArray(propsOrChildren)) {
417
+ return fragment(propsOrChildren);
418
+ }
419
+ // JSX style: Fragment({ children })
420
+ const { children } = propsOrChildren || {};
421
+ if (!children) return fragment([]);
422
+ if (Array.isArray(children)) {
423
+ return fragment(children);
424
+ }
425
+ return fragment([children]);
426
+ }
427
+
428
+ /**
429
+ * For component for list rendering (SolidJS-style)
430
+ */
431
+ export function For<T>(props: ForProps<T>): any {
432
+ const { each, fallback, children } = props;
433
+
434
+ // If each is not provided or is falsy, show fallback
435
+ if (!each) {
436
+ return fallback ?? null;
437
+ }
438
+
439
+ // each should be a getter function
440
+ const getter = typeof each === "function" ? each : () => each;
441
+
442
+ return forEach(getter, (item, index) => {
443
+ // Wrap index in a getter for SolidJS compatibility
444
+ return children(item, () => index);
445
+ });
446
+ }
447
+
448
+ /**
449
+ * Show component for conditional rendering (SolidJS-style)
450
+ */
451
+ export function Show<T>(props: ShowProps<T>): any {
452
+ const { when, children } = props;
453
+ // TODO: fallback support requires MoonBit-side changes
454
+
455
+ // Convert when to a getter if it's not already
456
+ const condition = typeof when === "function" ? when : () => when;
457
+
458
+ return show(
459
+ () => Boolean(condition()),
460
+ () => resolveChild(children, condition())
461
+ );
462
+ }
463
+
464
+ /**
465
+ * Index component for index-based list rendering (SolidJS-style)
466
+ */
467
+ export function Index<T>(props: IndexProps<T>): any {
468
+ const { each, fallback, children } = props;
469
+
470
+ if (!each) {
471
+ return fallback ?? null;
472
+ }
473
+
474
+ const getter = typeof each === "function" ? each : () => each;
475
+ const items = getter();
476
+
477
+ if (items.length === 0 && fallback) {
478
+ return fallback;
479
+ }
480
+
481
+ // Use index_each from MoonBit if available, otherwise simulate with forEach
482
+ // For now, we'll use forEach with index-based tracking
483
+ return forEach(getter, (_item, index) => {
484
+ // Provide item as a getter for reactivity at that index
485
+ const itemGetter = () => getter()[index];
486
+ return children(itemGetter, index);
487
+ });
488
+ }
489
+
490
+ /**
491
+ * Provider component for Context (SolidJS-style)
492
+ * Children must be a function: {() => <Child />}
493
+ */
494
+ export function Provider<T>(props: ProviderProps<T>): any {
495
+ const { context, value, children } = props;
496
+
497
+ return provide(context, value, children);
498
+ }
499
+
500
+ /**
501
+ * Switch component for conditional rendering with multiple branches (SolidJS-style)
502
+ * Reactively updates when conditions change.
503
+ */
504
+ export function Switch(props: SwitchProps): any {
505
+ const { fallback, children } = props;
506
+
507
+ // children should be Match components, each with { when, children }
508
+ // Since we don't have compile-time JSX, children is an array of Match results
509
+
510
+ // Normalize children to a flat array
511
+ let childArray: any[];
512
+ if (!children) {
513
+ childArray = [];
514
+ } else if (!Array.isArray(children)) {
515
+ childArray = [children];
516
+ } else {
517
+ // Flatten nested arrays (JSX can nest them)
518
+ childArray = children.flat();
519
+ }
520
+
521
+ // Filter to only Match components
522
+ const matches = childArray.filter((child) => child && child.__isMatch);
523
+
524
+ if (matches.length === 0) {
525
+ return fallback ?? null;
526
+ }
527
+
528
+ // Track which Match index is currently active (-1 = none, show fallback)
529
+ const matchIndex = createMemo(() => {
530
+ for (let i = 0; i < matches.length; i++) {
531
+ const match = matches[i];
532
+ if (match.when()) {
533
+ return i;
534
+ }
535
+ }
536
+ return -1;
537
+ });
538
+
539
+ // Create a show for each Match (only the active one will render)
540
+ const nodes: any[] = [];
541
+ for (let i = 0; i < matches.length; i++) {
542
+ const match = matches[i];
543
+ const idx = i; // Capture index for closure
544
+ nodes.push(
545
+ show(
546
+ () => matchIndex() === idx,
547
+ match.children // Match.children is already a resolved function
548
+ )
549
+ );
550
+ }
551
+
552
+ // Add fallback (renders when no match)
553
+ if (fallback) {
554
+ nodes.push(
555
+ show(
556
+ () => matchIndex() === -1,
557
+ () => resolveChild(fallback)
558
+ )
559
+ );
560
+ }
561
+
562
+ return fragment(nodes);
563
+ }
564
+
565
+ /**
566
+ * Match component for use inside Switch (SolidJS-style)
567
+ */
568
+ export function Match<T>(props: MatchProps<T>): { __isMatch: true; when: () => boolean; condition: () => T; children: () => any } {
569
+ const { when, children } = props;
570
+ const condition = typeof when === "function" ? when : () => when;
571
+
572
+ return {
573
+ __isMatch: true,
574
+ when: () => Boolean(condition()),
575
+ condition,
576
+ // Wrap children in a function that resolves with condition value
577
+ children: () => resolveChild(children, condition()),
578
+ };
579
+ }
580
+
581
+ /**
582
+ * Portal component for rendering outside the component tree (SolidJS-style)
583
+ * Children must be a function: {() => <Child />}
584
+ */
585
+ export function Portal(props: PortalProps): any {
586
+ const { mount, useShadow = false, children } = props;
587
+
588
+ // Resolve children (must be a function)
589
+ const resolvedChildren = [children()];
590
+
591
+ // Handle different mount targets
592
+ if (useShadow) {
593
+ if (typeof mount === "string") {
594
+ const target = document.querySelector(mount);
595
+ if (target) {
596
+ return portalToElementWithShadow(target, resolvedChildren);
597
+ }
598
+ } else if (mount) {
599
+ return portalToElementWithShadow(mount, resolvedChildren);
600
+ }
601
+ return portalWithShadow(resolvedChildren);
602
+ }
603
+
604
+ if (typeof mount === "string") {
605
+ return portalToSelector(mount, resolvedChildren);
606
+ }
607
+
608
+ if (mount) {
609
+ // For custom element mount, use selector approach
610
+ return portalToBody(resolvedChildren);
611
+ }
612
+
613
+ return portalToBody(resolvedChildren);
614
+ }
615
+
616
+ // ============================================================================
617
+ // Store API (SolidJS-style)
618
+ // ============================================================================
619
+
620
+ /**
621
+ * Creates a reactive store with nested property tracking (SolidJS-style)
622
+ */
623
+ export function createStore<T extends object>(initialValue: T): [T, SetStoreFunction<T>] {
624
+ // Store signals for each path
625
+ const signals = new Map();
626
+ // Deep clone the initial value to avoid mutation issues
627
+ const store = structuredClone(initialValue);
628
+
629
+ // Get or create a signal for a path
630
+ function getSignal(path) {
631
+ const key = path.join(".");
632
+ if (!signals.has(key)) {
633
+ const value = getValueAtPath(store, path);
634
+ signals.set(key, _createSignal(value));
635
+ }
636
+ return signals.get(key);
637
+ }
638
+
639
+ // Get value at a path in an object
640
+ function getValueAtPath(obj, path) {
641
+ let current = obj;
642
+ for (const key of path) {
643
+ if (current == null) return undefined;
644
+ current = current[key];
645
+ }
646
+ return current;
647
+ }
648
+
649
+ // Set value at a path in an object
650
+ function setValueAtPath(obj, path, value) {
651
+ if (path.length === 0) return;
652
+ let current = obj;
653
+ for (let i = 0; i < path.length - 1; i++) {
654
+ const key = path[i];
655
+ if (current[key] == null) {
656
+ // Preserve array vs object based on next key
657
+ const nextKey = path[i + 1];
658
+ current[key] = typeof nextKey === "number" || /^\d+$/.test(nextKey) ? [] : {};
659
+ }
660
+ current = current[key];
661
+ }
662
+ current[path[path.length - 1]] = value;
663
+ }
664
+
665
+ // Notify all signals that might be affected by a path change
666
+ // Uses batch to ensure effects only run once even if multiple signals are updated
667
+ function notifyPath(path) {
668
+ const pathStr = path.join(".");
669
+
670
+ batchStart();
671
+ try {
672
+ for (const [key, signal] of signals.entries()) {
673
+ // Only notify:
674
+ // 1. The exact path that changed
675
+ // 2. Child paths (paths that start with the changed path)
676
+ // Do NOT notify parent paths - they didn't change (object reference is same)
677
+ if (key === pathStr || key.startsWith(pathStr + ".")) {
678
+ const signalPath = key.split(".");
679
+ const newValue = getValueAtPath(store, signalPath);
680
+ _set(signal, newValue);
681
+ }
682
+ }
683
+ } finally {
684
+ batchEnd();
685
+ }
686
+ }
687
+
688
+ // Create a proxy for reactive access
689
+ function createProxy(target, path = []) {
690
+ if (target === null || typeof target !== "object") {
691
+ return target;
692
+ }
693
+
694
+ return new Proxy(target, {
695
+ get(obj, prop) {
696
+ if (typeof prop === "symbol") {
697
+ return obj[prop];
698
+ }
699
+
700
+ const currentPath = [...path, prop];
701
+ const signal = getSignal(currentPath);
702
+ // Track dependency by reading the signal
703
+ _get(signal);
704
+
705
+ const value = obj[prop];
706
+ if (value !== null && typeof value === "object") {
707
+ return createProxy(value, currentPath);
708
+ }
709
+ return value;
710
+ },
711
+
712
+ set(obj, prop, value) {
713
+ // Direct assignment on proxy - update store and notify
714
+ const currentPath = [...path, prop];
715
+ obj[prop] = value;
716
+ notifyPath(currentPath);
717
+ return true;
718
+ },
719
+ });
720
+ }
721
+
722
+ // setState function supporting path-based updates
723
+ function setState(...args) {
724
+ if (args.length === 0) return;
725
+
726
+ // Collect path segments and final value/updater
727
+ const path = [];
728
+ let i = 0;
729
+
730
+ // Collect string path segments
731
+ while (i < args.length - 1 && typeof args[i] === "string") {
732
+ path.push(args[i]);
733
+ i++;
734
+ }
735
+
736
+ const valueOrUpdater = args[i];
737
+
738
+ // If no path, treat as root update
739
+ if (path.length === 0 && typeof valueOrUpdater === "object" && valueOrUpdater !== null) {
740
+ // Merge at root
741
+ Object.assign(store, valueOrUpdater);
742
+ // Notify all signals
743
+ for (const [key, signal] of signals.entries()) {
744
+ const signalPath = key.split(".");
745
+ const newValue = getValueAtPath(store, signalPath);
746
+ _set(signal, newValue);
747
+ }
748
+ return;
749
+ }
750
+
751
+ // Get current value at path
752
+ const currentValue = getValueAtPath(store, path);
753
+
754
+ // Determine new value
755
+ let newValue;
756
+ if (typeof valueOrUpdater === "function") {
757
+ newValue = valueOrUpdater(currentValue);
758
+ } else if (
759
+ Array.isArray(valueOrUpdater)
760
+ ) {
761
+ // Arrays are replaced, not merged
762
+ newValue = valueOrUpdater;
763
+ } else if (
764
+ typeof valueOrUpdater === "object" &&
765
+ valueOrUpdater !== null &&
766
+ typeof currentValue === "object" &&
767
+ currentValue !== null &&
768
+ !Array.isArray(currentValue)
769
+ ) {
770
+ // Merge objects (but not arrays)
771
+ newValue = { ...currentValue, ...valueOrUpdater };
772
+ } else {
773
+ newValue = valueOrUpdater;
774
+ }
775
+
776
+ // Set value in store
777
+ setValueAtPath(store, path, newValue);
778
+
779
+ // Notify affected signals
780
+ notifyPath(path);
781
+ }
782
+
783
+ const proxy = createProxy(store);
784
+ return [proxy, setState];
785
+ }
786
+
787
+ /**
788
+ * Produce helper for immer-style mutations (SolidJS-style)
789
+ * @template T
790
+ * @param {(draft: T) => void} fn - Mutation function
791
+ * @returns {(state: T) => T} - Function that applies mutations to a copy
792
+ */
793
+ export function produce(fn) {
794
+ return (state) => {
795
+ const draft = structuredClone(state);
796
+ fn(draft);
797
+ return draft;
798
+ };
799
+ }
800
+
801
+ /**
802
+ * Reconcile helper for efficient array/object updates (SolidJS-style)
803
+ * @template T
804
+ * @param {T} value - New value to reconcile
805
+ * @returns {(state: T) => T} - Function that returns the new value
806
+ */
807
+ export function reconcile(value) {
808
+ return () => value;
809
+ }
810
+
811
+ // Re-export unchanged APIs
812
+ export {
813
+ // Batch control
814
+ batchStart,
815
+ batchEnd,
816
+ batch,
817
+ // Cleanup
818
+ onCleanup,
819
+ // Owner/Root
820
+ createRoot,
821
+ getOwner,
822
+ runWithOwner,
823
+ hasOwner,
824
+ onMount,
825
+ // DOM API
826
+ text,
827
+ textDyn,
828
+ render,
829
+ mount,
830
+ show,
831
+ jsx,
832
+ jsxs,
833
+ fragment, // Low-level MoonBit fragment function
834
+ createElement,
835
+ createElementNs,
836
+ svgNs,
837
+ mathmlNs,
838
+ events,
839
+ forEach,
840
+ // Route definitions
841
+ routePage,
842
+ routePageTitled,
843
+ routePageFull,
844
+ createRouter,
845
+ routerNavigate,
846
+ routerReplace,
847
+ routerGetPath,
848
+ routerGetMatch,
849
+ routerGetBase,
850
+ // Context API
851
+ createContext,
852
+ provide,
853
+ useContext,
854
+ // Resource helpers (for direct access)
855
+ resourceGet,
856
+ resourcePeek,
857
+ resourceRefetch,
858
+ resourceIsPending,
859
+ resourceIsSuccess,
860
+ resourceIsFailure,
861
+ resourceValue,
862
+ resourceError,
863
+ stateIsPending,
864
+ stateIsSuccess,
865
+ stateIsFailure,
866
+ stateValue,
867
+ stateError,
868
+ // Portal API (low-level)
869
+ portalToBody,
870
+ portalToSelector,
871
+ portalWithShadow,
872
+ portalToElementWithShadow,
873
+ };
874
+
875
+ // Legacy API exports (for backwards compatibility during migration)
876
+ export {
877
+ _get as get,
878
+ _set as set,
879
+ _update as update,
880
+ _peek as peek,
881
+ _subscribe as subscribe,
882
+ _map as map,
883
+ _combine as combine,
884
+ _effect as effect,
885
+ _renderEffect as renderEffect,
886
+ runUntracked,
887
+ };
888
+
889
+ // Event utilities (tree-shakeable, also available via "@luna_ui/luna/event-utils")
890
+ export * from "./event-utils";