@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,472 @@
1
+ /**
2
+ * @fileoverview Server Reactive Primitives for Fluixi
3
+ * @module @fluixi/core/server/reactive
4
+ *
5
+ * Maps reactive primitives for server-side execution
6
+ * Following SolidJS pattern of server-specific reactive behavior
7
+ *
8
+ * Server mode:
9
+ * - Signals read-only snapshot
10
+ * - Effects run once
11
+ * - No scheduling
12
+ * - No subscriptions
13
+ */
14
+ // ============================================================================
15
+ // SERVER SIGNAL
16
+ // ============================================================================
17
+ /**
18
+ * Server createSignal - Returns snapshot value
19
+ *
20
+ * Section 4: Signals read-only snapshot on server
21
+ * No reactivity, no tracking, just initial value
22
+ *
23
+ * @template T
24
+ * @param {T} value - Initial value
25
+ * @param {SignalOptions<T>} options - SignalTuple options (ignored on server)
26
+ * @returns {SignalTuple<T>} Tuple of [getter, setter]
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * // On server, this returns a static snapshot
31
+ * const [count, setCount] = createSignal(0);
32
+ * console.log(count()); // 0
33
+ * setCount(1); // Updates value but triggers no effects
34
+ * console.log(count()); // 1
35
+ * ```
36
+ */
37
+ export function createSignal(value, options) {
38
+ // Server: Simple read/write, no reactivity
39
+ let current = value;
40
+ const read = (() => current);
41
+ const write = (newValue) => {
42
+ if (typeof newValue === 'function') {
43
+ current = newValue(current);
44
+ }
45
+ else {
46
+ current = newValue;
47
+ }
48
+ return current;
49
+ };
50
+ return [read, write];
51
+ }
52
+ // ============================================================================
53
+ // SERVER EFFECT
54
+ // ============================================================================
55
+ /**
56
+ * Server createEffect - Runs once, no tracking
57
+ *
58
+ * Section 4: Effects run once on server, no scheduling
59
+ * Execute immediately and return no-op disposer
60
+ *
61
+ * @param {(v?: any) => any} fn - Effect function
62
+ * @param {any} value - Initial value (optional)
63
+ * @param {any} options - Effect options (ignored on server)
64
+ * @returns {{ dispose: () => void }} Disposer object
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // On server, runs once immediately
69
+ * createEffect(() => {
70
+ * console.log('This runs once');
71
+ * });
72
+ * ```
73
+ */
74
+ export function createEffect(fn, value, options) {
75
+ // Server: Run once, no tracking, no scheduling
76
+ try {
77
+ fn(value);
78
+ }
79
+ catch (error) {
80
+ console.error('[Fluixi Server] Effect error:', error);
81
+ }
82
+ // Return no-op disposer
83
+ return { dispose: () => { } };
84
+ }
85
+ // ============================================================================
86
+ // SERVER MEMO
87
+ // ============================================================================
88
+ /**
89
+ * Server createMemo - Compute once, return static accessor
90
+ *
91
+ * Section 4: No tracking on server, single evaluation
92
+ * Memoizes value at creation time
93
+ *
94
+ * @template T
95
+ * @param {(v?: T) => T} fn - Computation function
96
+ * @param {T} value - Initial value (optional)
97
+ * @param {any} options - Memo options (ignored on server)
98
+ * @returns {Accessor<T>} Static accessor
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const [count] = createSignal(5);
103
+ * const doubled = createMemo(() => count() * 2);
104
+ * console.log(doubled()); // 10 (computed once)
105
+ * ```
106
+ */
107
+ export function createMemo(fn, value, options) {
108
+ // Server: Compute once, no reactivity
109
+ const computed = fn(value);
110
+ return (() => computed);
111
+ }
112
+ // ============================================================================
113
+ // SERVER ROOT
114
+ // ============================================================================
115
+ /**
116
+ * Server createRoot - Creates owner but no reactive tracking
117
+ *
118
+ * Section 5: Owners exist on server for tree structure
119
+ * Needed for context and cleanup, but no reactive tracking
120
+ *
121
+ * @template T
122
+ * @param {(dispose: () => void) => T} fn - Root function
123
+ * @returns {T} Function result
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const result = createRoot((dispose) => {
128
+ * // Server: Executes once, maintains owner tree
129
+ * return <App />;
130
+ * });
131
+ * ```
132
+ */
133
+ export function createRoot(fn) {
134
+ // Server: Execute function with no-op disposer
135
+ // Owner tree maintained for context/cleanup
136
+ const cleanups = [];
137
+ const dispose = () => {
138
+ cleanups.forEach((cleanup) => {
139
+ try {
140
+ cleanup();
141
+ }
142
+ catch (error) {
143
+ console.error('[Fluixi Server] Cleanup error:', error);
144
+ }
145
+ });
146
+ cleanups.length = 0;
147
+ };
148
+ try {
149
+ return fn(dispose);
150
+ }
151
+ catch (error) {
152
+ dispose();
153
+ throw error;
154
+ }
155
+ }
156
+ // ============================================================================
157
+ // SERVER BATCH
158
+ // ============================================================================
159
+ /**
160
+ * Server batch - Execute immediately, no batching
161
+ *
162
+ * Section 4: No scheduling on server
163
+ * Just runs the function synchronously
164
+ *
165
+ * @template T
166
+ * @param {() => T} fn - Function to batch
167
+ * @returns {T} Function result
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * batch(() => {
172
+ * setCount(1);
173
+ * setName('Alice');
174
+ * }); // Executes immediately
175
+ * ```
176
+ */
177
+ export function batch(fn) {
178
+ // Server: No batching needed, just run
179
+ return fn();
180
+ }
181
+ // ============================================================================
182
+ // SERVER UNTRACK
183
+ // ============================================================================
184
+ /**
185
+ * Server untrack - Execute function (already untracked)
186
+ *
187
+ * Section 4: No tracking on server anyway
188
+ * This is a no-op but exists for API compatibility
189
+ *
190
+ * @template T
191
+ * @param {() => T} fn - Function to run untracked
192
+ * @returns {T} Function result
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * untrack(() => {
197
+ * return signal(); // Not tracked (but nothing is on server)
198
+ * });
199
+ * ```
200
+ */
201
+ export function untrack(fn) {
202
+ // Server: Already untracked, just run
203
+ return fn();
204
+ }
205
+ // ============================================================================
206
+ // SERVER CLEANUP
207
+ // ============================================================================
208
+ let currentCleanups = null;
209
+ /**
210
+ * Server onCleanup - Register cleanup function
211
+ *
212
+ * Section 5: Cleanup still needed for SSR resource management
213
+ * Stores cleanup for execution when root disposes
214
+ *
215
+ * @param {() => void} fn - Cleanup function
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * createRoot((dispose) => {
220
+ * onCleanup(() => {
221
+ * console.log('Cleanup on dispose');
222
+ * });
223
+ * return result;
224
+ * });
225
+ * ```
226
+ */
227
+ export function onCleanup(fn) {
228
+ if (currentCleanups) {
229
+ currentCleanups.push(fn);
230
+ }
231
+ }
232
+ // ============================================================================
233
+ // SERVER OWNER
234
+ // ============================================================================
235
+ let currentOwner = null;
236
+ /**
237
+ * Server getOwner - Get current reactive owner
238
+ *
239
+ * Section 5: Owner tree maintained on server for context
240
+ *
241
+ * @returns {RootOwner | null} Current owner or null
242
+ */
243
+ export function getOwner() {
244
+ return currentOwner;
245
+ }
246
+ /**
247
+ * Server runWithOwner - Run function with specific owner
248
+ *
249
+ * Section 5: Owner switching for proper context nesting
250
+ *
251
+ * @template T
252
+ * @param {RootOwner | null} owner - Owner to run with
253
+ * @param {() => T} fn - Function to run
254
+ * @returns {T} Function result
255
+ */
256
+ export function runWithOwner(owner, fn) {
257
+ const prev = currentOwner;
258
+ currentOwner = owner;
259
+ try {
260
+ return fn();
261
+ }
262
+ finally {
263
+ currentOwner = prev;
264
+ }
265
+ }
266
+ // ============================================================================
267
+ // SERVER CONTEXT
268
+ // ============================================================================
269
+ const contextMap = new Map();
270
+ /**
271
+ * Server createContext - Create context with default value
272
+ *
273
+ * Section 9: Context lookup-based, no subscriptions on server
274
+ *
275
+ * @template T
276
+ * @param {T} defaultValue - Default context value
277
+ * @returns {Context<T>} Context object
278
+ *
279
+ * @example
280
+ * ```typescript
281
+ * const ThemeContext = createContext('light');
282
+ * ```
283
+ */
284
+ export function createContext(defaultValue) {
285
+ const id = Symbol('context');
286
+ const Provider = (props) => {
287
+ // Server: Store value in context map
288
+ const prevValue = contextMap.get(id);
289
+ contextMap.set(id, props.value);
290
+ try {
291
+ return props.children;
292
+ }
293
+ finally {
294
+ // Restore previous value
295
+ if (prevValue !== undefined) {
296
+ contextMap.set(id, prevValue);
297
+ }
298
+ else {
299
+ contextMap.delete(id);
300
+ }
301
+ }
302
+ };
303
+ return {
304
+ id,
305
+ Provider,
306
+ defaultValue: defaultValue,
307
+ };
308
+ }
309
+ /**
310
+ * Server useContext - Retrieve context value
311
+ *
312
+ * Section 9: No subscriptions on server, just lookup
313
+ *
314
+ * @template T
315
+ * @param {Context<T>} context - Context to use
316
+ * @returns {T} Context value
317
+ *
318
+ * @example
319
+ * ```typescript
320
+ * const theme = useContext(ThemeContext);
321
+ * ```
322
+ */
323
+ export function useContext(context) {
324
+ // Server: Simple lookup, no subscription
325
+ const value = contextMap.get(context.id);
326
+ return value !== undefined ? value : context.defaultValue;
327
+ }
328
+ // ============================================================================
329
+ // SERVER COMPUTED
330
+ // ============================================================================
331
+ /**
332
+ * Server createComputed - Alias for createEffect
333
+ *
334
+ * On server, computed values run once like effects
335
+ *
336
+ * @param {() => any} fn - Computation function
337
+ * @returns {{ dispose: () => void }} Disposer
338
+ */
339
+ export function createComputed(fn) {
340
+ return createEffect(fn);
341
+ }
342
+ // ============================================================================
343
+ // SERVER RENDER EFFECT
344
+ // ============================================================================
345
+ /**
346
+ * Server createRenderEffect - Runs once for SSR rendering
347
+ *
348
+ * @param {() => any} fn - Render effect function
349
+ * @returns {{ dispose: () => void }} Disposer
350
+ */
351
+ export function createRenderEffect(fn) {
352
+ return createEffect(fn);
353
+ }
354
+ // ============================================================================
355
+ // SERVER DEFERRED
356
+ // ============================================================================
357
+ /**
358
+ * Server createDeferred - No deferring on server
359
+ *
360
+ * @template T
361
+ * @param {() => T} fn - Deferred computation
362
+ * @returns {Accessor<T>} Accessor
363
+ */
364
+ export function createDeferred(fn) {
365
+ return createMemo(fn);
366
+ }
367
+ // ============================================================================
368
+ // SERVER SELECTOR
369
+ // ============================================================================
370
+ /**
371
+ * Server createSelector - Returns static equality check
372
+ *
373
+ * @template T
374
+ * @param {() => T} source - Source value
375
+ * @returns {(key: T) => boolean} Selector function
376
+ */
377
+ // ENVIRONMENT
378
+ export function createSelector(source) {
379
+ const value = source();
380
+ return (key) => key === value;
381
+ }
382
+ // ============================================================================
383
+ // SERVER RESOURCE
384
+ // ============================================================================
385
+ /**
386
+ * Server createResource - Stub for resource creation
387
+ *
388
+ * @param source Source signal or value
389
+ * @param fetcher Fetcher function
390
+ * @param options Resource options
391
+ */
392
+ export function createResource(source, fetcher, options) {
393
+ return [
394
+ () => undefined,
395
+ {
396
+ mutate: (v) => v,
397
+ refetch: () => { },
398
+ },
399
+ ];
400
+ }
401
+ /**
402
+ * Server createStore — plain object wrapper, no reactivity.
403
+ * Mirrors the client API so shared code compiles on both sides.
404
+ */
405
+ export function createStore(init) {
406
+ const state = { ...init };
407
+ function setStore(keyOrPatch, value) {
408
+ if (typeof keyOrPatch === 'object' &&
409
+ keyOrPatch !== null &&
410
+ !Array.isArray(keyOrPatch)) {
411
+ for (const k of Object.keys(keyOrPatch)) {
412
+ const v = keyOrPatch[k];
413
+ state[k] = typeof v === 'function' ? v(state[k]) : v;
414
+ }
415
+ }
416
+ else {
417
+ state[keyOrPatch] =
418
+ typeof value === 'function' ? value(state[keyOrPatch]) : value;
419
+ }
420
+ }
421
+ return [state, setStore];
422
+ }
423
+ // ============================================================================
424
+ // SERVER TRANSITION
425
+ // ============================================================================
426
+ /**
427
+ * Server startTransition - Execute immediately
428
+ *
429
+ * @param fn Transition function
430
+ */
431
+ export function startTransition(fn) {
432
+ fn();
433
+ }
434
+ // ============================================================================
435
+ // ENVIRONMENT
436
+ // ============================================================================
437
+ // ENVIRONMENT
438
+ // ============================================================================
439
+ /**
440
+ * Check if running on server
441
+ */
442
+ export const isServer = true;
443
+ /**
444
+ * Check if running on client
445
+ */
446
+ export const isClient = false;
447
+ // ============================================================================
448
+ // COMPATIBILITY
449
+ // ============================================================================
450
+ /**
451
+ * Server sharedConfig - Empty config object for compatibility
452
+ */
453
+ export const sharedConfig = {
454
+ context: null,
455
+ owner: null,
456
+ };
457
+ /**
458
+ * Set current reactive owner (for internal use)
459
+ * @internal
460
+ */
461
+ export function setOwner(owner) {
462
+ currentOwner = owner;
463
+ sharedConfig.owner = owner;
464
+ sharedConfig.context = owner;
465
+ }
466
+ /**
467
+ * Get shared config (for compatibility)
468
+ * @internal
469
+ */
470
+ export function getSharedConfig() {
471
+ return sharedConfig;
472
+ }
@@ -0,0 +1 @@
1
+ function f(e,t){let o=e;return[(()=>o),c=>(typeof c=="function"?o=c(o):o=c,o)]}function T(e,t,o){try{e(t)}catch(n){console.error("[Fluixi Server] Effect error:",n)}return{dispose:()=>{}}}function p(e,t,o){let n=e(t);return(()=>n)}function d(e){let t=[],o=()=>{t.forEach(n=>{try{n()}catch(r){console.error("[Fluixi Server] Cleanup error:",r)}}),t.length=0};try{return e(o)}catch(n){throw o(),n}}function x(e){return e()}function y(e){return e()}var l=null;function v(e){l&&l.push(e)}var s=null;function S(){return s}function g(e,t){let o=s;s=e;try{return t()}finally{s=o}}var i=new Map;function w(e){let t=Symbol("context");return{id:t,Provider:n=>{let r=i.get(t);i.set(t,n.value);try{return n.children}finally{r!==void 0?i.set(t,r):i.delete(t)}},defaultValue:e}}function C(e){let t=i.get(e.id);return t!==void 0?t:e.defaultValue}function h(e){return T(e)}function A(e){return T(e)}function K(e){return p(e)}function R(e){let t=e();return o=>o===t}function O(e,t,o){return[()=>{},{mutate:n=>n,refetch:()=>{}}]}function b(e){let t={...e};function o(n,r){if(typeof n=="object"&&n!==null&&!Array.isArray(n))for(let c of Object.keys(n)){let u=n[c];t[c]=typeof u=="function"?u(t[c]):u}else t[n]=typeof r=="function"?r(t[n]):r}return[t,o]}function m(e){e()}var j=!0,F=!1,a={context:null,owner:null};function E(e){s=e,a.owner=e,a.context=e}function k(){return a}export{x as batch,h as createComputed,w as createContext,K as createDeferred,T as createEffect,p as createMemo,A as createRenderEffect,O as createResource,d as createRoot,R as createSelector,f as createSignal,b as createStore,S as getOwner,k as getSharedConfig,F as isClient,j as isServer,v as onCleanup,g as runWithOwner,E as setOwner,a as sharedConfig,m as startTransition,y as untrack,C as useContext};
@@ -0,0 +1 @@
1
+ "use strict";var s=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var x=(e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})},S=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of v(t))!p.call(e,i)&&i!==r&&s(e,i,{get:()=>t[i],enumerable:!(o=y(t,i))||o.enumerable});return e};var k=e=>S(s({},"__esModule",{value:!0}),e);var I={};x(I,{createTheme:()=>O});module.exports=k(I);var l=require("@fluixi/reactive/signal");function b(){let e=new Map;return{getItem:t=>e.has(t)?e.get(t):null,setItem:(t,r)=>{e.set(t,String(r))},removeItem:t=>{e.delete(t)},clear:()=>e.clear(),key:t=>Array.from(e.keys())[t]??null,get length(){return e.size}}}var a=typeof localStorage<"u"?localStorage:b(),c={get window(){return typeof window<"u"?window:void 0},get document(){return typeof document<"u"?document:void 0}};function w(e){return e?e===!0?{dark:"dark",light:"light"}:e:null}function O(e){let t=e.storageKey??"theme",r=e.attribute??"data-theme",o=w(e.system),i=()=>{let n=a.getItem(t);return n&&e.themes.includes(n)?n:o&&c.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches?o.dark:o?o.light:e.default},[d,f]=(0,l.createSignal)(i()),[T,u]=(0,l.createSignal)(!1),g=n=>{c.document?.documentElement.setAttribute(r,n);try{a.setItem(t,n)}catch{}},m=n=>{if(!e.themes.includes(n))return;let h=d();f(()=>n),g(n),e.onChange?.(n,h),e.load&&(u(!0),e.onLoading?.(n),Promise.resolve(e.load(n)).finally(()=>{u(!1),e.onLoaded?.(n)}))};return{value:d,isLoading:T,set:m,toggle:()=>{let n=e.themes.indexOf(d());m(e.themes[(n+1)%e.themes.length])},init:()=>g(d()),headScript:()=>`<script>(function(){try{var c=${JSON.stringify({k:t,a:r,d:e.default,sys:o})},t=localStorage.getItem(c.k);if(!t&&c.sys)t=matchMedia('(prefers-color-scheme: dark)').matches?c.sys.dark:c.sys.light;if(!t)t=c.d;document.documentElement.setAttribute(c.a,t);}catch(e){}})();<\/script>`}}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * createTheme — a reusable, SSR-safe theme store so every Fluixi app gets the whole
3
+ * theme workflow (detect → persist → apply → toggle, + the no-flash head script)
4
+ * without rewriting it. Generic over an arbitrary theme list (not just light/dark),
5
+ * with optional async theme loading and lifecycle hooks.
6
+ *
7
+ * Built on the universal `storage` + `env` utilities, so reading the stored theme at
8
+ * module-eval and touching `document`/`matchMedia` are safe on the server.
9
+ */
10
+ import { type Accessor } from '@fluixi/reactive/signal';
11
+ export interface ThemeOptions<T extends string> {
12
+ /** The full set of themes. `toggle()` cycles through them in order. */
13
+ themes: readonly T[];
14
+ /** Theme used when nothing is stored and system preference doesn't apply. */
15
+ default: T;
16
+ /** localStorage key the choice is persisted under (default `"theme"`). */
17
+ storageKey?: string;
18
+ /** Attribute set on `<html>` to drive CSS (default `"data-theme"`). */
19
+ attribute?: string;
20
+ /**
21
+ * Follow `prefers-color-scheme` when there is no stored choice. `true` assumes the
22
+ * themes literally include `"dark"`/`"light"`; pass `{ dark, light }` to map explicitly.
23
+ */
24
+ system?: boolean | {
25
+ dark: T;
26
+ light: T;
27
+ };
28
+ /** Optional async work per theme (e.g. lazy-import a CSS bundle). Drives `isLoading()`. */
29
+ load?: (theme: T) => void | Promise<void>;
30
+ /** Fired after a theme is applied. */
31
+ onChange?: (next: T, prev: T | undefined) => void;
32
+ /** Fired when an async `load` starts / finishes. */
33
+ onLoading?: (theme: T) => void;
34
+ onLoaded?: (theme: T) => void;
35
+ }
36
+ export interface Theme<T extends string> {
37
+ /** Reactive current theme. */
38
+ value: Accessor<T>;
39
+ /** Reactive — true while an async `load` is running. */
40
+ isLoading: Accessor<boolean>;
41
+ /** Set a specific theme (persists, applies, runs `load`/hooks). */
42
+ set: (theme: T) => void;
43
+ /** Cycle to the next theme in `themes`. */
44
+ toggle: () => void;
45
+ /** Apply the current theme to the DOM (call once on client mount). */
46
+ init: () => void;
47
+ /** Inline `<script>` for `<head>` that sets the attribute BEFORE first paint (no flash). */
48
+ headScript: () => string;
49
+ }
50
+ export declare function createTheme<T extends string>(options: ThemeOptions<T>): Theme<T>;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/theme/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGtE,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C,uEAAuE;IACvE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;IACrB,6EAA6E;IAC7E,OAAO,EAAE,CAAC,CAAC;IACX,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC;IACzC,2FAA2F;IAC3F,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,sCAAsC;IACtC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,oDAAoD;IACpD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM;IACrC,8BAA8B;IAC9B,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB,wDAAwD;IACxD,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7B,mEAAmE;IACnE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACxB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,sEAAsE;IACtE,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B;AAUD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAiEhF"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * createTheme — a reusable, SSR-safe theme store so every Fluixi app gets the whole
3
+ * theme workflow (detect → persist → apply → toggle, + the no-flash head script)
4
+ * without rewriting it. Generic over an arbitrary theme list (not just light/dark),
5
+ * with optional async theme loading and lifecycle hooks.
6
+ *
7
+ * Built on the universal `storage` + `env` utilities, so reading the stored theme at
8
+ * module-eval and touching `document`/`matchMedia` are safe on the server.
9
+ */
10
+ import { createSignal } from '@fluixi/reactive/signal';
11
+ import { storage, env } from '../env/index.js';
12
+ function systemMap(system) {
13
+ if (!system)
14
+ return null;
15
+ if (system === true)
16
+ return { dark: 'dark', light: 'light' };
17
+ return system;
18
+ }
19
+ export function createTheme(options) {
20
+ const storageKey = options.storageKey ?? 'theme';
21
+ const attribute = options.attribute ?? 'data-theme';
22
+ const sys = systemMap(options.system);
23
+ const detectInitial = () => {
24
+ const stored = storage.getItem(storageKey);
25
+ if (stored && options.themes.includes(stored))
26
+ return stored;
27
+ if (sys && env.window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches)
28
+ return sys.dark;
29
+ if (sys)
30
+ return sys.light;
31
+ return options.default;
32
+ };
33
+ const [value, setValue] = createSignal(detectInitial());
34
+ const [isLoading, setLoading] = createSignal(false);
35
+ const apply = (t) => {
36
+ env.document?.documentElement.setAttribute(attribute, t);
37
+ try {
38
+ storage.setItem(storageKey, t);
39
+ }
40
+ catch {
41
+ /* best-effort persistence */
42
+ }
43
+ };
44
+ const set = (t) => {
45
+ if (!options.themes.includes(t))
46
+ return;
47
+ const prev = value();
48
+ setValue(() => t);
49
+ apply(t);
50
+ options.onChange?.(t, prev);
51
+ if (options.load) {
52
+ setLoading(true);
53
+ options.onLoading?.(t);
54
+ Promise.resolve(options.load(t)).finally(() => {
55
+ setLoading(false);
56
+ options.onLoaded?.(t);
57
+ });
58
+ }
59
+ };
60
+ const toggle = () => {
61
+ const i = options.themes.indexOf(value());
62
+ set(options.themes[(i + 1) % options.themes.length]);
63
+ };
64
+ const init = () => apply(value());
65
+ const headScript = () => {
66
+ const cfg = JSON.stringify({
67
+ k: storageKey,
68
+ a: attribute,
69
+ d: options.default,
70
+ sys,
71
+ });
72
+ // Runs before paint: read stored choice (or system pref), set the attribute, so the
73
+ // server-rendered HTML never flashes the default theme before hydration.
74
+ return (`<script>(function(){try{var c=${cfg},t=localStorage.getItem(c.k);` +
75
+ `if(!t&&c.sys)t=matchMedia('(prefers-color-scheme: dark)').matches?c.sys.dark:c.sys.light;` +
76
+ `if(!t)t=c.d;document.documentElement.setAttribute(c.a,t);}catch(e){}})();</script>`);
77
+ };
78
+ return { value, isLoading, set, toggle, init, headScript };
79
+ }
@@ -0,0 +1 @@
1
+ import{createSignal as u}from"@fluixi/reactive/signal";function h(){let e=new Map;return{getItem:n=>e.has(n)?e.get(n):null,setItem:(n,o)=>{e.set(n,String(o))},removeItem:n=>{e.delete(n)},clear:()=>e.clear(),key:n=>Array.from(e.keys())[n]??null,get length(){return e.size}}}var d=typeof localStorage<"u"?localStorage:h(),s={get window(){return typeof window<"u"?window:void 0},get document(){return typeof document<"u"?document:void 0}};function y(e){return e?e===!0?{dark:"dark",light:"light"}:e:null}function w(e){let n=e.storageKey??"theme",o=e.attribute??"data-theme",r=y(e.system),g=()=>{let t=d.getItem(n);return t&&e.themes.includes(t)?t:r&&s.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches?r.dark:r?r.light:e.default},[i,m]=u(g()),[f,a]=u(!1),c=t=>{s.document?.documentElement.setAttribute(o,t);try{d.setItem(n,t)}catch{}},l=t=>{if(!e.themes.includes(t))return;let T=i();m(()=>t),c(t),e.onChange?.(t,T),e.load&&(a(!0),e.onLoading?.(t),Promise.resolve(e.load(t)).finally(()=>{a(!1),e.onLoaded?.(t)}))};return{value:i,isLoading:f,set:l,toggle:()=>{let t=e.themes.indexOf(i());l(e.themes[(t+1)%e.themes.length])},init:()=>c(i()),headScript:()=>`<script>(function(){try{var c=${JSON.stringify({k:n,a:o,d:e.default,sys:r})},t=localStorage.getItem(c.k);if(!t&&c.sys)t=matchMedia('(prefers-color-scheme: dark)').matches?c.sys.dark:c.sys.light;if(!t)t=c.d;document.documentElement.setAttribute(c.a,t);}catch(e){}})();<\/script>`}}export{w as createTheme};
@@ -0,0 +1 @@
1
+ "use strict";var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var m=(e,t)=>{for(var r in t)i(e,r,{get:t[r],enumerable:!0})},y=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of T(t))!p.call(e,o)&&o!==r&&i(e,o,{get:()=>t[o],enumerable:!(n=f(t,o))||n.enumerable});return e};var g=e=>y(i({},"__esModule",{value:!0}),e);var _={};m(_,{camelCase:()=>K,capitalize:()=>P,clamp:()=>k,debounce:()=>l,deepClone:()=>s,deepMerge:()=>u,formatBytes:()=>M,formatNumber:()=>b,groupBy:()=>E,isDefined:()=>D,isEmpty:()=>B,kebabCase:()=>w,memoize:()=>d,omit:()=>C,pick:()=>O,pipe:()=>R,random:()=>A,range:()=>S,retry:()=>c,sleep:()=>z,throttle:()=>x,uniqueId:()=>h});module.exports=g(_);function l(e,t){let r;return(...n)=>{clearTimeout(r),r=setTimeout(()=>e(...n),t)}}function x(e,t){let r;return(...n)=>{r||(e(...n),r=!0,setTimeout(()=>r=!1,t))}}function d(e){let t=new Map;return((...r)=>{let n=JSON.stringify(r);if(t.has(n))return t.get(n);let o=e(...r);return t.set(n,o),o})}function s(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(e instanceof Array)return Array.from(e).map(r=>s(r));if(e instanceof Set)return new Set(Array.from(e).map(r=>s(r)));if(e instanceof Map)return new Map(Array.from(e.entries()).map(([r,n])=>[s(r),s(n)]));let t={};for(let r in e)e.hasOwnProperty(r)&&(t[r]=s(e[r]));return t}function u(...e){let t={};for(let r of e)for(let n in r)if(r.hasOwnProperty(n)){let o=r[n];o!==null&&typeof o=="object"&&!Array.isArray(o)?t[n]=u(t[n]||{},o):t[n]=o}return t}function h(e=""){return e+Math.random().toString(36).substr(2,9)}function b(e){return e.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function M(e,t=2){if(e===0)return"0 Bytes";let r=1024,n=t<0?0:t,o=["Bytes","KB","MB","GB","TB","PB"],a=Math.floor(Math.log(e)/Math.log(r));return parseFloat((e/Math.pow(r,a)).toFixed(n))+" "+o[a]}function P(e){return e.charAt(0).toUpperCase()+e.slice(1)}function w(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function K(e){return e.replace(/[-_\s](.)/g,(t,r)=>r.toUpperCase())}function k(e,t,r){return Math.min(Math.max(e,t),r)}function A(e,t){return Math.floor(Math.random()*(t-e+1))+e}function B(e){return e==null?!0:typeof e=="string"?e.trim().length===0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.keys(e).length===0:!1}function O(e,...t){let r={};return t.forEach(n=>{n in e&&(r[n]=e[n])}),r}function C(e,...t){let r={...e};return t.forEach(n=>{delete r[n]}),r}function E(e,t){return e.reduce((r,n)=>{let o=t(n),a=r.get(o)||[];return a.push(n),r.set(o,a),r},new Map)}function S(e,t,r=1){let n=[];for(let o=e;o<=t;o+=r)n.push(o);return n}async function c(e,t=3,r=1e3){try{return await e()}catch(n){if(t<=0)throw n;return await new Promise(o=>setTimeout(o,r)),c(e,t-1,r)}}function z(e){return new Promise(t=>setTimeout(t,e))}function D(e){return e!=null}function R(...e){return t=>e.reduce((r,n)=>n(r),t)}