@fluixi/core 1.0.0-alpha.53

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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +611 -0
  3. package/dist/cdn/core.global.js +3 -0
  4. package/dist/cli/generate.cjs +1814 -0
  5. package/dist/cli/generate.d.ts +7 -0
  6. package/dist/cli/generate.d.ts.map +1 -0
  7. package/dist/cli/generate.js +2580 -0
  8. package/dist/cli/generate.mjs +1814 -0
  9. package/dist/cli/index.cjs +1814 -0
  10. package/dist/cli/index.d.ts +7 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/cli/index.js +2580 -0
  13. package/dist/cli/index.mjs +1814 -0
  14. package/dist/cli/run.cjs +2 -0
  15. package/dist/cli/run.d.ts +3 -0
  16. package/dist/cli/run.d.ts.map +1 -0
  17. package/dist/cli/run.js +62 -0
  18. package/dist/cli/run.mjs +2 -0
  19. package/dist/fluixi.d.ts +5 -0
  20. package/dist/src/cdn/chunk-PFM5O5UE.mjs +1 -0
  21. package/dist/src/cdn/core.cjs +1 -0
  22. package/dist/src/cdn/core.d.ts +16 -0
  23. package/dist/src/cdn/core.d.ts.map +1 -0
  24. package/dist/src/cdn/core.js +15 -0
  25. package/dist/src/cdn/core.mjs +1 -0
  26. package/dist/src/cdn/router-next-WNWCFVC2.mjs +1 -0
  27. package/dist/src/index.cjs +1 -0
  28. package/dist/src/index.d.ts +7 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/index.js +26 -0
  31. package/dist/src/index.mjs +1 -0
  32. package/dist/src/jsx-dev-runtime.cjs +1 -0
  33. package/dist/src/jsx-dev-runtime.d.ts +2 -0
  34. package/dist/src/jsx-dev-runtime.d.ts.map +1 -0
  35. package/dist/src/jsx-dev-runtime.js +1 -0
  36. package/dist/src/jsx-dev-runtime.mjs +1 -0
  37. package/dist/src/jsx-runtime.cjs +1 -0
  38. package/dist/src/jsx-runtime.d.ts +7 -0
  39. package/dist/src/jsx-runtime.d.ts.map +1 -0
  40. package/dist/src/jsx-runtime.js +17 -0
  41. package/dist/src/jsx-runtime.mjs +1 -0
  42. package/dist/src/lib/client/chunk-D3VTWVNJ.mjs +1 -0
  43. package/dist/src/lib/client/index.cjs +1 -0
  44. package/dist/src/lib/client/index.d.ts +54 -0
  45. package/dist/src/lib/client/index.d.ts.map +1 -0
  46. package/dist/src/lib/client/index.js +142 -0
  47. package/dist/src/lib/client/index.mjs +1 -0
  48. package/dist/src/lib/client/router-next-UYIYMRJL.mjs +1 -0
  49. package/dist/src/lib/context/context.cjs +1 -0
  50. package/dist/src/lib/context/context.d.ts +337 -0
  51. package/dist/src/lib/context/context.d.ts.map +1 -0
  52. package/dist/src/lib/context/context.js +462 -0
  53. package/dist/src/lib/context/context.mjs +1 -0
  54. package/dist/src/lib/context/index.cjs +1 -0
  55. package/dist/src/lib/context/index.d.ts +3 -0
  56. package/dist/src/lib/context/index.d.ts.map +1 -0
  57. package/dist/src/lib/context/index.js +5 -0
  58. package/dist/src/lib/context/index.mjs +1 -0
  59. package/dist/src/lib/control-flow.cjs +1 -0
  60. package/dist/src/lib/control-flow.d.ts +4 -0
  61. package/dist/src/lib/control-flow.d.ts.map +1 -0
  62. package/dist/src/lib/control-flow.js +1 -0
  63. package/dist/src/lib/control-flow.mjs +1 -0
  64. package/dist/src/lib/core.cjs +1 -0
  65. package/dist/src/lib/core.d.ts +90 -0
  66. package/dist/src/lib/core.d.ts.map +1 -0
  67. package/dist/src/lib/core.js +181 -0
  68. package/dist/src/lib/core.mjs +1 -0
  69. package/dist/src/lib/directives/lit.cjs +1 -0
  70. package/dist/src/lib/directives/lit.d.ts +2 -0
  71. package/dist/src/lib/directives/lit.d.ts.map +1 -0
  72. package/dist/src/lib/directives/lit.js +31 -0
  73. package/dist/src/lib/directives/lit.mjs +0 -0
  74. package/dist/src/lib/env/index.cjs +1 -0
  75. package/dist/src/lib/env/index.d.ts +39 -0
  76. package/dist/src/lib/env/index.d.ts.map +1 -0
  77. package/dist/src/lib/env/index.js +50 -0
  78. package/dist/src/lib/env/index.mjs +1 -0
  79. package/dist/src/lib/i18n/index.cjs +1 -0
  80. package/dist/src/lib/i18n/index.d.ts +79 -0
  81. package/dist/src/lib/i18n/index.d.ts.map +1 -0
  82. package/dist/src/lib/i18n/index.js +127 -0
  83. package/dist/src/lib/i18n/index.mjs +1 -0
  84. package/dist/src/lib/index.cjs +1 -0
  85. package/dist/src/lib/index.d.ts +83 -0
  86. package/dist/src/lib/index.d.ts.map +1 -0
  87. package/dist/src/lib/index.js +147 -0
  88. package/dist/src/lib/index.mjs +1 -0
  89. package/dist/src/lib/isomorphic.cjs +1 -0
  90. package/dist/src/lib/isomorphic.d.ts +69 -0
  91. package/dist/src/lib/isomorphic.d.ts.map +1 -0
  92. package/dist/src/lib/isomorphic.js +92 -0
  93. package/dist/src/lib/isomorphic.mjs +1 -0
  94. package/dist/src/lib/jsx-runtime/index.cjs +1 -0
  95. package/dist/src/lib/jsx-runtime/index.d.ts +13 -0
  96. package/dist/src/lib/jsx-runtime/index.d.ts.map +1 -0
  97. package/dist/src/lib/jsx-runtime/index.js +23 -0
  98. package/dist/src/lib/jsx-runtime/index.mjs +1 -0
  99. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -0
  100. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts +2 -0
  101. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts.map +1 -0
  102. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.js +1 -0
  103. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -0
  104. package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +13 -0
  105. package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts +21 -0
  106. package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts.map +1 -0
  107. package/dist/src/lib/plugins/fluixi-routes-plugin.js +102 -0
  108. package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +13 -0
  109. package/dist/src/lib/plugins/index.cjs +13 -0
  110. package/dist/src/lib/plugins/index.d.ts +4 -0
  111. package/dist/src/lib/plugins/index.d.ts.map +1 -0
  112. package/dist/src/lib/plugins/index.js +3 -0
  113. package/dist/src/lib/plugins/index.mjs +13 -0
  114. package/dist/src/lib/plugins/route-codegen.cjs +8 -0
  115. package/dist/src/lib/plugins/route-codegen.d.ts +13 -0
  116. package/dist/src/lib/plugins/route-codegen.d.ts.map +1 -0
  117. package/dist/src/lib/plugins/route-codegen.js +81 -0
  118. package/dist/src/lib/plugins/route-codegen.mjs +8 -0
  119. package/dist/src/lib/plugins/route-scanner.cjs +1 -0
  120. package/dist/src/lib/plugins/route-scanner.d.ts +39 -0
  121. package/dist/src/lib/plugins/route-scanner.d.ts.map +1 -0
  122. package/dist/src/lib/plugins/route-scanner.js +216 -0
  123. package/dist/src/lib/plugins/route-scanner.mjs +1 -0
  124. package/dist/src/lib/plugins/vite.cjs +1 -0
  125. package/dist/src/lib/plugins/vite.d.ts +3 -0
  126. package/dist/src/lib/plugins/vite.d.ts.map +1 -0
  127. package/dist/src/lib/plugins/vite.js +1 -0
  128. package/dist/src/lib/plugins/vite.mjs +1 -0
  129. package/dist/src/lib/render/component.cjs +1 -0
  130. package/dist/src/lib/render/component.d.ts +328 -0
  131. package/dist/src/lib/render/component.d.ts.map +1 -0
  132. package/dist/src/lib/render/component.js +520 -0
  133. package/dist/src/lib/render/component.mjs +1 -0
  134. package/dist/src/lib/render/index.cjs +1 -0
  135. package/dist/src/lib/render/index.d.ts +113 -0
  136. package/dist/src/lib/render/index.d.ts.map +1 -0
  137. package/dist/src/lib/render/index.js +201 -0
  138. package/dist/src/lib/render/index.mjs +1 -0
  139. package/dist/src/lib/render/lazy.cjs +1 -0
  140. package/dist/src/lib/render/lazy.d.ts +28 -0
  141. package/dist/src/lib/render/lazy.d.ts.map +1 -0
  142. package/dist/src/lib/render/lazy.js +62 -0
  143. package/dist/src/lib/render/lazy.mjs +1 -0
  144. package/dist/src/lib/render/suspense.cjs +1 -0
  145. package/dist/src/lib/render/suspense.d.ts +25 -0
  146. package/dist/src/lib/render/suspense.d.ts.map +1 -0
  147. package/dist/src/lib/render/suspense.js +139 -0
  148. package/dist/src/lib/render/suspense.mjs +1 -0
  149. package/dist/src/lib/router-next/data.cjs +1 -0
  150. package/dist/src/lib/router-next/data.d.ts +101 -0
  151. package/dist/src/lib/router-next/data.d.ts.map +1 -0
  152. package/dist/src/lib/router-next/data.js +179 -0
  153. package/dist/src/lib/router-next/data.mjs +1 -0
  154. package/dist/src/lib/router-next/index.cjs +1 -0
  155. package/dist/src/lib/router-next/index.d.ts +156 -0
  156. package/dist/src/lib/router-next/index.d.ts.map +1 -0
  157. package/dist/src/lib/router-next/index.js +464 -0
  158. package/dist/src/lib/router-next/index.mjs +1 -0
  159. package/dist/src/lib/server/hydration.cjs +1 -0
  160. package/dist/src/lib/server/hydration.d.ts +238 -0
  161. package/dist/src/lib/server/hydration.d.ts.map +1 -0
  162. package/dist/src/lib/server/hydration.js +384 -0
  163. package/dist/src/lib/server/hydration.mjs +1 -0
  164. package/dist/src/lib/server/index.cjs +16 -0
  165. package/dist/src/lib/server/index.d.ts +91 -0
  166. package/dist/src/lib/server/index.d.ts.map +1 -0
  167. package/dist/src/lib/server/index.js +141 -0
  168. package/dist/src/lib/server/index.mjs +16 -0
  169. package/dist/src/lib/server/reactive.cjs +1 -0
  170. package/dist/src/lib/server/reactive.d.ts +298 -0
  171. package/dist/src/lib/server/reactive.d.ts.map +1 -0
  172. package/dist/src/lib/server/reactive.js +472 -0
  173. package/dist/src/lib/server/reactive.mjs +1 -0
  174. package/dist/src/lib/theme/index.cjs +1 -0
  175. package/dist/src/lib/theme/index.d.ts +51 -0
  176. package/dist/src/lib/theme/index.d.ts.map +1 -0
  177. package/dist/src/lib/theme/index.js +79 -0
  178. package/dist/src/lib/theme/index.mjs +1 -0
  179. package/dist/src/lib/utils/index.cjs +1 -0
  180. package/dist/src/lib/utils/index.d.ts +379 -0
  181. package/dist/src/lib/utils/index.d.ts.map +1 -0
  182. package/dist/src/lib/utils/index.js +527 -0
  183. package/dist/src/lib/utils/index.mjs +1 -0
  184. package/dist/src/rx.cjs +1 -0
  185. package/dist/src/rx.d.ts +2 -0
  186. package/dist/src/rx.d.ts.map +1 -0
  187. package/dist/src/rx.js +101 -0
  188. package/dist/src/rx.mjs +0 -0
  189. package/dist/src/server.cjs +16 -0
  190. package/dist/src/server.d.ts +64 -0
  191. package/dist/src/server.d.ts.map +1 -0
  192. package/dist/src/server.js +63 -0
  193. package/dist/src/server.mjs +16 -0
  194. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  195. package/package.json +128 -0
  196. package/src/index.ts +31 -0
  197. package/types/fluixi.d.ts +5 -0
  198. package/types/vinxi.d.ts +50 -0
@@ -0,0 +1,520 @@
1
+ /**
2
+ * Component creation for Fluixi. Component-creation logic only — context lives in
3
+ * the reactive system, rendering in render/index.ts, and SSR in server/.
4
+ */
5
+ import { registerCreateComponent, asComponent, } from '@fluixi/dom';
6
+ import { untrack, onCleanup, getOwner, createEffect, createMemo, createSignal, isSignal, batch, runWithOwner, } from '@fluixi/reactive/signal';
7
+ const sharedConfig = {
8
+ context: null,
9
+ owner: null,
10
+ };
11
+ /**
12
+ * Get shared reactive config
13
+ * Used for maintaining reactive context across components
14
+ * @internal
15
+ */
16
+ export function getSharedConfig() {
17
+ return sharedConfig;
18
+ }
19
+ /**
20
+ * Set current owner in shared config
21
+ * @internal
22
+ */
23
+ export function setOwner(owner) {
24
+ sharedConfig.owner = owner;
25
+ sharedConfig.context = owner;
26
+ }
27
+ /**
28
+ * Get current owner from shared config
29
+ * @internal
30
+ */
31
+ export function getContextOwner() {
32
+ return sharedConfig.context || sharedConfig.owner;
33
+ }
34
+ // ============================================================================
35
+ // GLOBAL STATE
36
+ // ============================================================================
37
+ /**
38
+ * Development mode flag
39
+ */
40
+ export const DEV = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development';
41
+ // ============================================================================
42
+ // OWNER-BASED LIFECYCLE COORDINATION
43
+ // ============================================================================
44
+ // Every component has a reactive Owner (from createRoot).
45
+ // onMount and useEffect attach callbacks to the Owner via a Symbol-keyed
46
+ // property. A single queueMicrotask per Owner flushes them in order:
47
+ // 1. All onMount callbacks run first
48
+ // 2. Then all useEffect callbacks are created as reactive effects
49
+ // This works regardless of whether the component goes through $component,
50
+ // the JSX runtime, or is called directly — as long as there's an Owner.
51
+ const _LIFECYCLE = Symbol.for('fluixi-lifecycle');
52
+ /**
53
+ * Get or create a lifecycle bucket on the current Owner.
54
+ * Returns null if there is no reactive Owner.
55
+ */
56
+ function getOwnerLifecycle() {
57
+ const owner = getOwner();
58
+ if (!owner)
59
+ return null;
60
+ if (!owner[_LIFECYCLE]) {
61
+ const lc = { mounts: [], effects: [], scheduled: false };
62
+ owner[_LIFECYCLE] = lc;
63
+ }
64
+ return owner[_LIFECYCLE];
65
+ }
66
+ /**
67
+ * Schedule a microtask to flush the lifecycle for the current Owner.
68
+ * Only schedules once per Owner — subsequent calls are no-ops.
69
+ */
70
+ function scheduleLifecycleFlush(lc) {
71
+ if (lc.scheduled)
72
+ return;
73
+ lc.scheduled = true;
74
+ // Capture the owner now; by microtask time it will have been restored.
75
+ const owner = getOwner();
76
+ queueMicrotask(() => {
77
+ runWithOwner(owner, () => {
78
+ // 1. Run ALL onMount callbacks first
79
+ for (const cb of lc.mounts) {
80
+ try {
81
+ const cleanup = cb();
82
+ if (typeof cleanup === 'function') {
83
+ onCleanup(cleanup);
84
+ }
85
+ }
86
+ catch (e) {
87
+ console.error('Error in onMount callback:', e);
88
+ }
89
+ }
90
+ // 2. THEN create effects for useEffect callbacks
91
+ for (const cb of lc.effects) {
92
+ let cleanup;
93
+ createEffect(() => {
94
+ if (cleanup)
95
+ cleanup();
96
+ cleanup = cb();
97
+ });
98
+ onCleanup(() => {
99
+ if (cleanup)
100
+ cleanup();
101
+ });
102
+ }
103
+ // Clear
104
+ lc.mounts = [];
105
+ lc.effects = [];
106
+ });
107
+ });
108
+ }
109
+ // Give the dom runtime our createComponent. It gets everything else (effects,
110
+ // memos, …) from @fluixi/reactive directly.
111
+ export function ensureIntegration(from) {
112
+ registerCreateComponent(createComponent);
113
+ }
114
+ /**
115
+ * Create and execute a component once. Opens an Owner, runs the component untracked,
116
+ * captures its output, keeps children lazy, propagates context (via sharedConfig), and
117
+ * attaches cleanup. Components execute once and never re-execute.
118
+ *
119
+ * @template P - Props type
120
+ * @param {Component<P>} Comp - Component function
121
+ * @param {P} props - Component props
122
+ * @returns {any} Component output
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const MyComponent = (props: { name: string }) => {
127
+ * return html`<div>Hello ${props.name}</div>`;
128
+ * };
129
+ *
130
+ * const result = createComponent(MyComponent, { name: 'World' });
131
+ * ```
132
+ */
133
+ // export function $component<T, U = any>(value: T, props?: U) {
134
+ // const component = () => (typeof value === 'function' && props) ?(value as any)(props) : value;
135
+ // Object.defineProperty(component, '__fluixi', {
136
+ // enumerable: true,
137
+ // configurable: true,
138
+ // value: true,
139
+ // });
140
+ // // (component as any).$COMPONENT = true;
141
+ // return asComponent(component) as C<T, U>;
142
+ // }
143
+ //
144
+ export function createComponent(Comp, props) {
145
+ return $component(Comp, props);
146
+ // const c = $component(Comp, props)
147
+ // // return c() as any
148
+ // return c as any
149
+ }
150
+ const cached = new WeakMap();
151
+ export function $component(value, props) {
152
+ // if(isComponent(value) || isRoutes(value) || isRouter(value)) {
153
+ // // if(!cached.has(value)){
154
+ // // cached.set(value, ()=>untrack(()=>value(props)))
155
+ // // }else{
156
+ // // console.log('skipp track', value)
157
+ // // }
158
+ // // return cached.get(value)()
159
+ // return untrack(() => value(props))
160
+ // }
161
+ const component = (typeof value === 'function')
162
+ ? untrack(() => value(props))
163
+ : value;
164
+ // Only stamp $name and $COMPONENT on functions/objects — primitives (strings, numbers)
165
+ // cannot have properties added in strict mode and would throw TypeError.
166
+ // Also skip stamping reactive values (signals/memos) with $COMPONENT so the DOM
167
+ // runtime doesn't misidentify them as static component thunks and cache them.
168
+ if (component != null && (typeof component === 'function' || typeof component === 'object') && !isSignal(component)) {
169
+ try {
170
+ component['$name'] = value.name;
171
+ }
172
+ catch { }
173
+ // Always mark with asComponent so isComponent() works reliably in both dev and
174
+ // production browser environments.
175
+ return asComponent(component);
176
+ }
177
+ return component;
178
+ }
179
+ // ============================================================================
180
+ // LIFECYCLE HOOKS
181
+ // ============================================================================
182
+ /**
183
+ * Register a callback to run when component mounts
184
+ *
185
+ * SolidJS-aligned: uses createEffect to schedule the callback.
186
+ * The effect runs once after the reactive graph is established,
187
+ * tied to the current Owner for automatic cleanup.
188
+ *
189
+ * @param {LifecycleCallback} fn - Mount callback
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * const MyComponent = () => {
194
+ * onMount(() => {
195
+ * console.log('Component mounted');
196
+ * return () => console.log('Cleanup');
197
+ * });
198
+ *
199
+ * return html`<div>Content</div>`;
200
+ * };
201
+ * ```
202
+ */
203
+ export function onMount(fn, reactive = true) {
204
+ const lc = getOwnerLifecycle();
205
+ if (lc) {
206
+ if (!reactive) {
207
+ if (!lc.scheduled) {
208
+ fn();
209
+ }
210
+ return;
211
+ }
212
+ // Attach to Owner — will run BEFORE useEffect callbacks in the flush.
213
+ lc.mounts.push(fn);
214
+ scheduleLifecycleFlush(lc);
215
+ }
216
+ else {
217
+ if (!reactive) {
218
+ fn();
219
+ return;
220
+ }
221
+ // No Owner (rare). Fall back to SolidJS pattern.
222
+ createEffect(() => {
223
+ const cleanup = untrack(fn);
224
+ if (typeof cleanup === 'function') {
225
+ onCleanup(cleanup);
226
+ }
227
+ });
228
+ }
229
+ }
230
+ /**
231
+ * Register a callback to run when component unmounts
232
+ *
233
+ * SolidJS-aligned: directly delegates to onCleanup which registers
234
+ * with the current reactive Owner for automatic disposal.
235
+ *
236
+ * @param {() => void} fn - Unmount callback
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const MyComponent = () => {
241
+ * onUnmount(() => {
242
+ * console.log('Component is unmounting');
243
+ * });
244
+ *
245
+ * return html`<div>Content</div>`;
246
+ * };
247
+ * ```
248
+ */
249
+ export function onUnmount(fn) {
250
+ onCleanup(fn);
251
+ }
252
+ /**
253
+ * Register a cleanup function
254
+ *
255
+ * Section 1: Component constructs reactive graph including cleanup
256
+ *
257
+ * @param {() => void} fn - Cleanup function
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * const MyComponent = () => {
262
+ * const timer = setInterval(() => console.log('tick'), 1000);
263
+ *
264
+ * onCleanup(() => clearInterval(timer));
265
+ *
266
+ * return html`<div>Timer running</div>`;
267
+ * };
268
+ * ```
269
+ */
270
+ export { onCleanup };
271
+ // ============================================================================
272
+ // HOOKS
273
+ // ============================================================================
274
+ /**
275
+ * Create a reactive effect
276
+ *
277
+ * Effects run when their dependencies change
278
+ * On server, effects run once
279
+ *
280
+ * @param {(v?: any) => any} fn - Effect function
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const MyComponent = () => {
285
+ * const [count, setCount] = createSignal(0);
286
+ *
287
+ * useEffect(() => {
288
+ * console.log('Count changed:', count());
289
+ * });
290
+ *
291
+ * return html`<button @click=${() => setCount(count() + 1)}>Click</button>`;
292
+ * };
293
+ * ```
294
+ */
295
+ export function useEffect(callback) {
296
+ const lc = getOwnerLifecycle();
297
+ if (lc) {
298
+ // Attach to the Owner — created as an effect after all onMount callbacks.
299
+ lc.effects.push(callback);
300
+ scheduleLifecycleFlush(lc);
301
+ }
302
+ else {
303
+ // No Owner (rare). Create the effect immediately.
304
+ let cleanup;
305
+ createEffect(() => {
306
+ if (cleanup)
307
+ cleanup();
308
+ cleanup = callback();
309
+ });
310
+ onCleanup(() => {
311
+ if (cleanup)
312
+ cleanup();
313
+ });
314
+ }
315
+ }
316
+ /**
317
+ * Create a memoized computed value
318
+ *
319
+ * @template T
320
+ * @param {() => T} fn - Computation function
321
+ * @returns {() => T} Memoized accessor
322
+ *
323
+ * @example
324
+ * ```typescript
325
+ * const MyComponent = () => {
326
+ * const [count, setCount] = createSignal(0);
327
+ * const doubled = useMemo(() => count() * 2);
328
+ *
329
+ * return html`<div>Doubled: ${doubled()}</div>`;
330
+ * };
331
+ * ```
332
+ */
333
+ export function useMemo(fn) {
334
+ // createMemo is natively reactive and disposed automatically
335
+ // when its Owner is cleaned up. No lifecycle stack needed.
336
+ return createMemo(fn);
337
+ }
338
+ /**
339
+ * Create a ref object
340
+ *
341
+ * Refs persist across component re-renders (though components only run once)
342
+ * Useful for storing DOM references and mutable values
343
+ *
344
+ * @template T
345
+ * @param {T} initialValue - Initial value
346
+ * @returns {RefObject<T>} Ref object
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * const MyComponent = () => {
351
+ * const inputRef = useRef<HTMLInputElement>(null);
352
+ *
353
+ * onMount(() => {
354
+ * inputRef.current?.focus();
355
+ * });
356
+ *
357
+ * return html`<input ref=${inputRef} />`;
358
+ * };
359
+ * ```
360
+ */
361
+ export function useRef(initialValue) {
362
+ const ref = { current: initialValue };
363
+ // Register cleanup to clear ref
364
+ onCleanup(() => {
365
+ ref.current = null;
366
+ });
367
+ return ref;
368
+ }
369
+ /**
370
+ * Create a reducer for state management
371
+ *
372
+ * @template S - State type
373
+ * @template A - Action type
374
+ * @param {(state: S, action: A) => S} reducer - Reducer function
375
+ * @param {S} initialState - Initial state
376
+ * @returns {[() => S, (action: A) => void]} State accessor and dispatch function
377
+ *
378
+ * @example
379
+ * ```typescript
380
+ * type Action = { type: 'increment' } | { type: 'decrement' };
381
+ *
382
+ * const MyComponent = () => {
383
+ * const [state, dispatch] = useReducer(
384
+ * (state: number, action: Action) => {
385
+ * switch (action.type) {
386
+ * case 'increment': return state + 1;
387
+ * case 'decrement': return state - 1;
388
+ * }
389
+ * },
390
+ * 0
391
+ * );
392
+ *
393
+ * return html`
394
+ * <button @click=${() => dispatch({ type: 'increment' })}>
395
+ * Count: ${state()}
396
+ * </button>
397
+ * `;
398
+ * };
399
+ * ```
400
+ */
401
+ export function useReducer(reducer, initialState) {
402
+ const [state, setState] = createSignal(initialState);
403
+ const dispatch = (action) => {
404
+ setState(reducer(state(), action));
405
+ };
406
+ return [state, dispatch];
407
+ }
408
+ export function useEventListener(target, event, handler, options) {
409
+ useEffect(() => {
410
+ // Resolve target from ref or direct value
411
+ const element = target && 'current' in target
412
+ ? target.current
413
+ : target;
414
+ if (!element)
415
+ return;
416
+ // Attach event listener
417
+ element.addEventListener(event, handler, options);
418
+ // Return cleanup function
419
+ return () => {
420
+ element.removeEventListener(event, handler, options);
421
+ };
422
+ });
423
+ }
424
+ /**
425
+ * Create a callback function (memoization optimization)
426
+ *
427
+ * In Fluixi, components only run once, so this is mostly for
428
+ * API compatibility and explicit intent
429
+ *
430
+ * @template T
431
+ * @param {T} callback - Callback function
432
+ * @returns {T} Callback function
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * const MyComponent = () => {
437
+ * const handleClick = useCallback(() => {
438
+ * console.log('Clicked');
439
+ * });
440
+ *
441
+ * return html`<button @click=${handleClick}>Click</button>`;
442
+ * };
443
+ * ```
444
+ */
445
+ export function useCallback(callback) {
446
+ // Components execute once, so callback is already stable
447
+ // This is mainly for API compatibility with React-like patterns
448
+ return callback;
449
+ }
450
+ /**
451
+ * Batch update helper
452
+ * Re-exported for convenience
453
+ */
454
+ export { batch };
455
+ /**
456
+ * Create a memo
457
+ * Re-exported for convenience
458
+ */
459
+ export { createMemo };
460
+ /**
461
+ * Create an effect
462
+ * Re-exported for convenience
463
+ */
464
+ export { createEffect };
465
+ /**
466
+ * Get current reactive owner
467
+ * Re-exported for convenience
468
+ */
469
+ export { getOwner };
470
+ /**
471
+ * Run with specific owner
472
+ * Re-exported for convenience
473
+ */
474
+ export { runWithOwner };
475
+ // ============================================================================
476
+ // HELPER FUNCTIONS (INTERNAL)
477
+ // ============================================================================
478
+ /**
479
+ * Helper to check if we're in a component context
480
+ * @internal
481
+ */
482
+ export function hasLifecycleContext() {
483
+ return getOwner() !== null;
484
+ }
485
+ // ============================================================================
486
+ // DEV MODE UTILITIES
487
+ // ============================================================================
488
+ /**
489
+ * Check if in development mode
490
+ *
491
+ * @returns {boolean} True if in development mode
492
+ *
493
+ * @example
494
+ * ```typescript
495
+ * if (isDev()) {
496
+ * console.log('Running in development mode');
497
+ * }
498
+ * ```
499
+ */
500
+ export function isDev() {
501
+ // return false
502
+ return DEV;
503
+ }
504
+ /**
505
+ * Development-only code execution
506
+ *
507
+ * @param {() => void} fn - Function to run in dev mode
508
+ *
509
+ * @example
510
+ * ```typescript
511
+ * devOnly(() => {
512
+ * console.log('This only runs in development');
513
+ * });
514
+ * ```
515
+ */
516
+ export function devOnly(fn) {
517
+ if (DEV) {
518
+ fn();
519
+ }
520
+ }
@@ -0,0 +1 @@
1
+ import{registerCreateComponent as y,asComponent as x}from"@fluixi/dom";import{untrack as a,onCleanup as r,getOwner as f,createEffect as s,createMemo as m,createSignal as C,isSignal as T,batch as R,runWithOwner as E}from"@fluixi/reactive/signal";var c={context:null,owner:null};function W(){return c}function K(e){c.owner=e,c.context=e}function V(){return c.context||c.owner}var p=typeof process<"u"&&!1,u=Symbol.for("fluixi-lifecycle");function l(){let e=f();if(!e)return null;if(!e[u]){let t={mounts:[],effects:[],scheduled:!1};e[u]=t}return e[u]}function d(e){if(e.scheduled)return;e.scheduled=!0;let t=f();queueMicrotask(()=>{E(t,()=>{for(let n of e.mounts)try{let o=n();typeof o=="function"&&r(o)}catch(o){console.error("Error in onMount callback:",o)}for(let n of e.effects){let o;s(()=>{o&&o(),o=n()}),r(()=>{o&&o()})}e.mounts=[],e.effects=[]})})}function F(e){y(O)}function O(e,t){return w(e,t)}function w(e,t){let n=typeof e=="function"?a(()=>e(t)):e;if(n!=null&&(typeof n=="function"||typeof n=="object")&&!T(n)){try{n.$name=e.name}catch{}return x(n)}return n}function I(e,t=!0){let n=l();if(n){if(!t){n.scheduled||e();return}n.mounts.push(e),d(n)}else{if(!t){e();return}s(()=>{let o=a(e);typeof o=="function"&&r(o)})}}function N(e){r(e)}function h(e){let t=l();if(t)t.effects.push(e),d(t);else{let n;s(()=>{n&&n(),n=e()}),r(()=>{n&&n()})}}function $(e){return m(e)}function q(e){let t={current:e};return r(()=>{t.current=null}),t}function P(e,t){let[n,o]=C(t);return[n,v=>{o(e(n(),v))}]}function Y(e,t,n,o){h(()=>{let i=e&&"current"in e?e.current:e;if(i)return i.addEventListener(t,n,o),()=>{i.removeEventListener(t,n,o)}})}function z(e){return e}function B(){return f()!==null}function G(){return p}function H(e){p&&e()}export{w as $component,p as DEV,R as batch,O as createComponent,s as createEffect,m as createMemo,H as devOnly,F as ensureIntegration,V as getContextOwner,f as getOwner,W as getSharedConfig,B as hasLifecycleContext,G as isDev,r as onCleanup,I as onMount,N as onUnmount,E as runWithOwner,K as setOwner,z as useCallback,h as useEffect,Y as useEventListener,$ as useMemo,P as useReducer,q as useRef};
@@ -0,0 +1 @@
1
+ "use strict";var X=Object.create;var b=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var ee=(e,n)=>{for(var t in n)b(e,t,{get:n[t],enumerable:!0})},O=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of G(n))!Z.call(e,s)&&s!==t&&b(e,s,{get:()=>n[s],enumerable:!(o=Y(n,s))||o.enumerable});return e};var ne=(e,n,t)=>(t=e!=null?X(Q(e)):{},O(n||!e||!e.__esModule?b(t,"default",{value:e,enumerable:!0}):t,e)),te=e=>O(b({},"__esModule",{value:!0}),e);var pe={};ee(pe,{$component:()=>L,DEV:()=>x,Suspense:()=>C,SuspenseList:()=>H,batch:()=>r.batch,cleanupDelegation:()=>fe,createComponent:()=>v,createEffect:()=>r.createEffect,createMemo:()=>r.createMemo,devOnly:()=>N,getOwner:()=>r.getOwner,getSharedConfig:()=>k,initDelegation:()=>ue,isDev:()=>U,isJSXElement:()=>V,isLitResult:()=>I,isNode:()=>W,isPromise:()=>E,isRenderable:()=>ae,lazy:()=>K,onCleanup:()=>r.onCleanup,onMount:()=>j,onUnmount:()=>F,portal:()=>ce,render:()=>J,runWithOwner:()=>r.runWithOwner,useCallback:()=>z,useEffect:()=>g,useEventListener:()=>_,useMemo:()=>M,useReducer:()=>$,useRef:()=>D});module.exports=te(pe);var q=require("@fluixi/reactive/signal"),d=require("@fluixi/dom");var h=require("@fluixi/dom"),r=require("@fluixi/reactive/signal"),oe={context:null,owner:null};function k(){return oe}var x=typeof process<"u"&&!1,w=Symbol.for("fluixi-lifecycle");function R(){let e=(0,r.getOwner)();if(!e)return null;if(!e[w]){let n={mounts:[],effects:[],scheduled:!1};e[w]=n}return e[w]}function P(e){if(e.scheduled)return;e.scheduled=!0;let n=(0,r.getOwner)();queueMicrotask(()=>{(0,r.runWithOwner)(n,()=>{for(let t of e.mounts)try{let o=t();typeof o=="function"&&(0,r.onCleanup)(o)}catch(o){console.error("Error in onMount callback:",o)}for(let t of e.effects){let o;(0,r.createEffect)(()=>{o&&o(),o=t()}),(0,r.onCleanup)(()=>{o&&o()})}e.mounts=[],e.effects=[]})})}function A(e){(0,h.registerCreateComponent)(v)}function v(e,n){return L(e,n)}function L(e,n){let t=typeof e=="function"?(0,r.untrack)(()=>e(n)):e;if(t!=null&&(typeof t=="function"||typeof t=="object")&&!(0,r.isSignal)(t)){try{t.$name=e.name}catch{}return(0,h.asComponent)(t)}return t}function j(e,n=!0){let t=R();if(t){if(!n){t.scheduled||e();return}t.mounts.push(e),P(t)}else{if(!n){e();return}(0,r.createEffect)(()=>{let o=(0,r.untrack)(e);typeof o=="function"&&(0,r.onCleanup)(o)})}}function F(e){(0,r.onCleanup)(e)}function g(e){let n=R();if(n)n.effects.push(e),P(n);else{let t;(0,r.createEffect)(()=>{t&&t(),t=e()}),(0,r.onCleanup)(()=>{t&&t()})}}function M(e){return(0,r.createMemo)(e)}function D(e){let n={current:e};return(0,r.onCleanup)(()=>{n.current=null}),n}function $(e,n){let[t,o]=(0,r.createSignal)(n);return[t,p=>{o(e(t(),p))}]}function _(e,n,t,o){g(()=>{let s=e&&"current"in e?e.current:e;if(s)return s.addEventListener(n,t,o),()=>{s.removeEventListener(n,t,o)}})}function z(e){return e}function U(){return x}function N(e){x&&e()}var i=require("@fluixi/reactive/signal"),l=require("@fluixi/dom");function W(e){return typeof window>"u"?!1:typeof Node=="function"&&e instanceof Node?!0:!!(e&&typeof e=="object"&&typeof e.nodeType=="number")}function I(e){return!e||typeof e!="object"?!1:!!(typeof e._$litType$<"u"||typeof e._$litDirective$<"u"||Array.isArray(e.strings)&&Array.isArray(e.values))}function E(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}function V(e){return!!(e&&typeof e=="object"&&"type"in e&&"props"in e)}var B=(0,i.createContext)();function C(e){return(0,l.createComponent)(re,e)}function re(e){let n=(0,i.createSuspenseBoundary)(),t=(0,i.useContext)(B),o=t?t.register(n.inFallback):void 0;function s(a){return a==null||typeof a=="boolean"?null:typeof a=="function"&&(0,l.isComponent)(a)&&!(0,i.isSignal)(a)?a():a}let p=(0,l.runWithoutHydration)(()=>s(e.fallback??null)),u=(0,i.provideSuspense)(n,()=>e.children);(0,i.provideSuspense)(n,()=>{(0,i.createRenderEffect)(()=>{let a=u;if(Array.isArray(a))for(let S of a)typeof S=="function"&&(0,i.isSignal)(S)&&S();else typeof a=="function"&&(0,i.isSignal)(a)&&a()})});let[f,c]=(0,i.createSignal)(void 0),m=E(u);return m&&(n.increment(),u.then(a=>{c(()=>a),n.decrement()},()=>n.decrement())),(0,i.createMemo)(()=>(o?o.showFallback():n.inFallback())?p:m?f():u)}function H(e){return(0,l.createComponent)(ie,e)}function ie(e){let{revealOrder:n="together",tail:t}=e,o=[];function s(){if(n==="together"){let u=o.every(f=>!f.inFallback());o.forEach(f=>{f.setShowContent(u),f.setShowFallback(!u)})}else{let u=n==="backwards"?[...o].reverse():o,f=!1;for(let c of u)f||c.inFallback()?(f=!0,c.setShowContent(!1),c.setShowFallback(t!=="hidden")):(c.setShowContent(!0),c.setShowFallback(!1))}}let p={register:u=>{let[f,c]=(0,i.createSignal)(!0),[m,a]=(0,i.createSignal)(!1);return o.push({inFallback:u,setShowContent:c,setShowFallback:a}),(0,i.createEffect)(()=>{u(),s()}),{showContent:f,showFallback:m}}};return B.Provider({value:p,children:e.children})}(0,l.asSuspense)(C);Object.defineProperty(C,"__suspense",{value:!0,enumerable:!0});var y=require("@fluixi/reactive/signal");function K(e,n){let t,o,s;function p(){return o||(o=e().then(f=>t=f.default)),o}n?.preload&&p();let u=(f=>{if(t){let c=t;return(0,y.untrack)(()=>c(f))}if(!s){let[c]=(0,y.createResource)(()=>p());if(s=c,c.error)throw c.error}return(0,y.createMemo)(()=>{let c=s();return c?(0,y.untrack)(()=>c(f)):void 0},void 0,{name:"lazy"})});return u.preload=()=>p().then(()=>{}),u.$lazy=!0,u.loader=e,u}typeof window<"u"&&import("lit").then(e=>(0,d.registerLitRender)(e.render));var T=typeof window>"u";function J(e,n,t={}){if(A("render"),(0,d.delegateEvents)(["click","input","change","submit"]),T)throw new Error("render() is for client-side only. Use renderToString() on server.");if(!n)throw new Error("Container element is required");let o;return(0,q.createRoot)(s=>{o=s;let p=typeof e=="function"?e():e;n.textContent="",n.setAttribute("fluixi-js","v1"),(0,d.insert)(n,()=>p)}),()=>{o&&(o(),o=void 0)}}function se(e){return e&&typeof e=="object"&&(e._$litType$!==void 0||e._$litDirective$!==void 0)}function ce(e,n,t={}){let o=document.createElement("div");o.setAttribute("data-portal","true"),n.appendChild(o);let s=J(e,o,t);return()=>{s(),n.contains(o)&&n.removeChild(o)}}function ae(e){return!!(e==null||typeof e=="function"||(0,d.isDOMNode)(e)||se(e)||Array.isArray(e)||typeof e=="string"||typeof e=="number"||typeof e=="boolean")}function ue(){T||(0,d.delegateEvents)(["click","input","change","submit"])}function fe(){}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @fileoverview Client-Side Rendering for Fluixi
3
+ * @module @fluixi/core/render
4
+ *
5
+ * Client-side rendering:
6
+ * - Real DOM
7
+ * - Fine-grained mutation
8
+ *
9
+ * Following SolidJS structure: render logic separated from component creation
10
+ */
11
+ /**
12
+ * Render options
13
+ */
14
+ export interface RenderOptions {
15
+ /**
16
+ * Whether to hydrate existing content
17
+ */
18
+ hydrate?: boolean;
19
+ /**
20
+ * Marker for hydration boundaries
21
+ */
22
+ marker?: Node;
23
+ /**
24
+ * Callback when disposed
25
+ */
26
+ onDispose?: () => void;
27
+ }
28
+ /**
29
+ * Render a component into a DOM element
30
+ *
31
+ * Section 7 — CLIENT:
32
+ * - Real DOM (no Virtual DOM)
33
+ * - Fine-grained mutation (no reconciliation)
34
+ *
35
+ * Section 1: Component executes once during render
36
+ * Section 5: Creates reactive owner (root)
37
+ *
38
+ * @param {() => any} code - Component or function to render
39
+ * @param {HTMLElement} container - Target DOM element
40
+ * @param {RenderOptions} options - Render options
41
+ * @returns {() => void} Dispose function
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * import { render } from '@fluixi/core';
46
+ * import { createSignal } from '@fluixi/reactive';
47
+ * import { html } from 'lit';
48
+ *
49
+ * const App = () => {
50
+ * const [count, setCount] = createSignal(0);
51
+ * return html`
52
+ * <button @click=${() => setCount(count() + 1)}>
53
+ * Count: ${count()}
54
+ * </button>
55
+ * `;
56
+ * };
57
+ *
58
+ * const dispose = render(App, document.getElementById('app'));
59
+ * ```
60
+ */
61
+ export declare function render(code: () => any, container: HTMLElement, options?: RenderOptions): () => void;
62
+ /**
63
+ * Render into a different part of the DOM tree
64
+ *
65
+ * @param {() => any} code - Component to render
66
+ * @param {HTMLElement} target - Target element (outside current tree)
67
+ * @param {RenderOptions} options - Render options
68
+ * @returns {() => void} Dispose function
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * import { portal } from '@fluixi/core';
73
+ *
74
+ * const Modal = () => {
75
+ * return portal(
76
+ * () => html`<div class="modal">Content</div>`,
77
+ * document.body
78
+ * );
79
+ * };
80
+ * ```
81
+ */
82
+ export declare function portal(code: () => any, target: HTMLElement, options?: RenderOptions): () => void;
83
+ /**
84
+ * Check if a value can be rendered
85
+ *
86
+ * @param {any} value - Value to check
87
+ * @returns {boolean} True if renderable
88
+ */
89
+ export declare function isRenderable(value: any): boolean;
90
+ /**
91
+ * Initialize event delegation
92
+ * Should be called once when app starts
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * import { initDelegation } from '@fluixi/core';
97
+ *
98
+ * initDelegation();
99
+ * render(App, document.getElementById('app'));
100
+ * ```
101
+ */
102
+ export declare function initDelegation(): void;
103
+ /**
104
+ * Cleanup event delegation
105
+ * Should be called when app unmounts
106
+ */
107
+ export declare function cleanupDelegation(): void;
108
+ export { createComponent, onMount, onUnmount, useEffect, useRef, useReducer, useMemo, useEventListener, useCallback, onCleanup, batch, createMemo, createEffect, getOwner, runWithOwner, isDev, devOnly, DEV, getSharedConfig, $component, } from './component.js';
109
+ export { Suspense, SuspenseList, type SuspenseProps, type SuspenseListProps, isNode, isLitResult, isPromise, isJSXElement, } from './suspense.js';
110
+ export { lazy } from "./lazy.js";
111
+ export type { LazyOptions, LazyComponent } from "./lazy.js";
112
+ export type { Component, ComponentProps, LifecycleCallback, RefObject, } from './component.js';
113
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA0BH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,GAAG,EACf,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,aAAkB,GAC1B,MAAM,IAAI,CA4CZ;AAmBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,GAAG,EACf,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,aAAkB,GAC1B,MAAM,IAAI,CAaZ;AAMD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAchD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAOD,OAAO,EACL,eAAe,EACf,OAAO,EACP,SAAS,EACT,SAAS,EACT,MAAM,EACN,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,KAAK,EACL,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,OAAO,EACP,GAAG,EACH,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,EACR,YAAY,EAEZ,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAEtB,MAAM,EACN,WAAW,EACX,SAAS,EACT,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,YAAY,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,WAAW,CAAA;AAEzD,YAAY,EACV,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,SAAS,GACV,MAAM,gBAAgB,CAAC"}