@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,201 @@
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
+ import { createRoot } from '@fluixi/reactive/signal';
12
+ import { isDOMNode, delegateEvents, registerLitRender, insert, } from '@fluixi/dom';
13
+ import { ensureIntegration, } from './component.js';
14
+ // Register Lit's render function with the DOM runtime so reactive updates can render
15
+ // Lit templates. CLIENT-ONLY and lazily imported: lit extends HTMLElement at module
16
+ // init, so a static import would crash SSR — this keeps lit out of server bundles.
17
+ if (typeof window !== 'undefined') {
18
+ import('lit').then((lit) => registerLitRender(lit.render));
19
+ }
20
+ const isServer = typeof window === 'undefined';
21
+ // ============================================================================
22
+ // SECTION 7 — RENDERING (CLIENT)
23
+ // ============================================================================
24
+ /**
25
+ * Render a component into a DOM element
26
+ *
27
+ * Section 7 — CLIENT:
28
+ * - Real DOM (no Virtual DOM)
29
+ * - Fine-grained mutation (no reconciliation)
30
+ *
31
+ * Section 1: Component executes once during render
32
+ * Section 5: Creates reactive owner (root)
33
+ *
34
+ * @param {() => any} code - Component or function to render
35
+ * @param {HTMLElement} container - Target DOM element
36
+ * @param {RenderOptions} options - Render options
37
+ * @returns {() => void} Dispose function
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { render } from '@fluixi/core';
42
+ * import { createSignal } from '@fluixi/reactive';
43
+ * import { html } from 'lit';
44
+ *
45
+ * const App = () => {
46
+ * const [count, setCount] = createSignal(0);
47
+ * return html`
48
+ * <button @click=${() => setCount(count() + 1)}>
49
+ * Count: ${count()}
50
+ * </button>
51
+ * `;
52
+ * };
53
+ *
54
+ * const dispose = render(App, document.getElementById('app'));
55
+ * ```
56
+ */
57
+ export function render(code, container, options = {}) {
58
+ ensureIntegration('render');
59
+ delegateEvents(['click', 'input', 'change', 'submit']);
60
+ if (isServer) {
61
+ throw new Error('render() is for client-side only. Use renderToString() on server.');
62
+ }
63
+ if (!container) {
64
+ throw new Error('Container element is required');
65
+ }
66
+ let disposer;
67
+ // domRender(code, container)
68
+ createRoot((dispose) => {
69
+ disposer = dispose;
70
+ // Section 1: Execute code function once — Providers run here with Owner = root
71
+ // so "also stamp" in createProvider sets context on root.contexts, making
72
+ // it reachable from every render effect created by insert() below.
73
+ const result = typeof code === 'function' ? code() : code;
74
+ // Section 7: Insert into real DOM using the SAME root as code() so that
75
+ // render effects share the Owner chain with Provider context nodes.
76
+ // Using domRender() would create a second createRoot, severing the chain.
77
+ container.textContent = '';
78
+ container.setAttribute('fluixi-js', 'v1');
79
+ // Wrap the (already-computed) result in a STABLE thunk so insert() creates a
80
+ // top-level render effect. Without this, a static array result — e.g. the
81
+ // imperative backend's `[createMemo(() => createComponent(App)), " "]` — is
82
+ // flattened ONCE with no enclosing effect, so the nested memos are read
83
+ // untracked and reactive boundaries deep in the tree (Suspense fallback ->
84
+ // content, Outlet, Show/For) never update. The thunk returns the same result
85
+ // each run, so code()/Providers are not re-executed (context stays on root).
86
+ insert(container, () => result);
87
+ });
88
+ return () => {
89
+ if (disposer) {
90
+ disposer();
91
+ disposer = undefined;
92
+ }
93
+ };
94
+ }
95
+ /**
96
+ * Type guard for Lit template results
97
+ * @internal
98
+ */
99
+ function isLitTemplateResult(value) {
100
+ return (value &&
101
+ typeof value === 'object' &&
102
+ (value['_$litType$'] !== undefined ||
103
+ value['_$litDirective$'] !== undefined));
104
+ }
105
+ // ============================================================================
106
+ // PORTAL RENDERING
107
+ // ============================================================================
108
+ /**
109
+ * Render into a different part of the DOM tree
110
+ *
111
+ * @param {() => any} code - Component to render
112
+ * @param {HTMLElement} target - Target element (outside current tree)
113
+ * @param {RenderOptions} options - Render options
114
+ * @returns {() => void} Dispose function
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * import { portal } from '@fluixi/core';
119
+ *
120
+ * const Modal = () => {
121
+ * return portal(
122
+ * () => html`<div class="modal">Content</div>`,
123
+ * document.body
124
+ * );
125
+ * };
126
+ * ```
127
+ */
128
+ export function portal(code, target, options = {}) {
129
+ const container = document.createElement('div');
130
+ container.setAttribute('data-portal', 'true');
131
+ target.appendChild(container);
132
+ const dispose = render(code, container, options);
133
+ return () => {
134
+ dispose();
135
+ if (target.contains(container)) {
136
+ target.removeChild(container);
137
+ }
138
+ };
139
+ }
140
+ // ============================================================================
141
+ // UTILITIES
142
+ // ============================================================================
143
+ /**
144
+ * Check if a value can be rendered
145
+ *
146
+ * @param {any} value - Value to check
147
+ * @returns {boolean} True if renderable
148
+ */
149
+ export function isRenderable(value) {
150
+ if (value == null)
151
+ return true;
152
+ if (typeof value === 'function')
153
+ return true;
154
+ if (isDOMNode(value))
155
+ return true;
156
+ if (isLitTemplateResult(value))
157
+ return true;
158
+ if (Array.isArray(value))
159
+ return true;
160
+ if (typeof value === 'string' ||
161
+ typeof value === 'number' ||
162
+ typeof value === 'boolean') {
163
+ return true;
164
+ }
165
+ return false;
166
+ }
167
+ /**
168
+ * Initialize event delegation
169
+ * Should be called once when app starts
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * import { initDelegation } from '@fluixi/core';
174
+ *
175
+ * initDelegation();
176
+ * render(App, document.getElementById('app'));
177
+ * ```
178
+ */
179
+ export function initDelegation() {
180
+ if (isServer)
181
+ return;
182
+ delegateEvents(['click', 'input', 'change', 'submit']);
183
+ }
184
+ /**
185
+ * Cleanup event delegation
186
+ * Should be called when app unmounts
187
+ */
188
+ export function cleanupDelegation() {
189
+ if (isServer)
190
+ return;
191
+ // Clear delegated events manually if needed
192
+ }
193
+ // ============================================================================
194
+ // EXPORTS
195
+ // ============================================================================
196
+ // Re-export component creation
197
+ export { createComponent, onMount, onUnmount, useEffect, useRef, useReducer, useMemo, useEventListener, useCallback, onCleanup, batch, createMemo, createEffect, getOwner, runWithOwner, isDev, devOnly, DEV, getSharedConfig, $component, } from './component.js';
198
+ export { Suspense, SuspenseList,
199
+ // type ShowProps,
200
+ isNode, isLitResult, isPromise, isJSXElement, } from './suspense.js';
201
+ export { lazy } from "./lazy.js";
@@ -0,0 +1 @@
1
+ import{createRoot as be}from"@fluixi/reactive/signal";import{isDOMNode as he,delegateEvents as D,registerLitRender as xe,insert as Ce}from"@fluixi/dom";import{registerCreateComponent as $,asComponent as _}from"@fluixi/dom";import{untrack as w,onCleanup as f,getOwner as m,createEffect as l,createMemo as v,createSignal as z,isSignal as U,batch as N,runWithOwner as L}from"@fluixi/reactive/signal";var W={context:null,owner:null};function I(){return W}var b=typeof process<"u"&&!1,y=Symbol.for("fluixi-lifecycle");function g(){let e=m();if(!e)return null;if(!e[y]){let n={mounts:[],effects:[],scheduled:!1};e[y]=n}return e[y]}function E(e){if(e.scheduled)return;e.scheduled=!0;let n=m();queueMicrotask(()=>{L(n,()=>{for(let o of e.mounts)try{let t=o();typeof t=="function"&&f(t)}catch(t){console.error("Error in onMount callback:",t)}for(let o of e.effects){let t;l(()=>{t&&t(),t=o()}),f(()=>{t&&t()})}e.mounts=[],e.effects=[]})})}function T(e){$(O)}function O(e,n){return k(e,n)}function k(e,n){let o=typeof e=="function"?w(()=>e(n)):e;if(o!=null&&(typeof o=="function"||typeof o=="object")&&!U(o)){try{o.$name=e.name}catch{}return _(o)}return o}function V(e,n=!0){let o=g();if(o){if(!n){o.scheduled||e();return}o.mounts.push(e),E(o)}else{if(!n){e();return}l(()=>{let t=w(e);typeof t=="function"&&f(t)})}}function B(e){f(e)}function R(e){let n=g();if(n)n.effects.push(e),E(n);else{let o;l(()=>{o&&o(),o=e()}),f(()=>{o&&o()})}}function H(e){return v(e)}function K(e){let n={current:e};return f(()=>{n.current=null}),n}function q(e,n){let[o,t]=z(n);return[o,u=>{t(e(o(),u))}]}function J(e,n,o,t){R(()=>{let c=e&&"current"in e?e.current:e;if(c)return c.addEventListener(n,o,t),()=>{c.removeEventListener(n,o,t)}})}function X(e){return e}function Y(){return b}function G(e){b&&e()}import{createSignal as x,createMemo as Q,createEffect as Z,createRenderEffect as ee,isSignal as h,useContext as ne,createContext as te,createSuspenseBoundary as oe,provideSuspense as P}from"@fluixi/reactive/signal";import{asSuspense as re,isComponent as ie,createComponent as A,runWithoutHydration as se}from"@fluixi/dom";function ce(e){return typeof window>"u"?!1:typeof Node=="function"&&e instanceof Node?!0:!!(e&&typeof e=="object"&&typeof e.nodeType=="number")}function ae(e){return!e||typeof e!="object"?!1:!!(typeof e._$litType$<"u"||typeof e._$litDirective$<"u"||Array.isArray(e.strings)&&Array.isArray(e.values))}function j(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}function ue(e){return!!(e&&typeof e=="object"&&"type"in e&&"props"in e)}var F=te();function C(e){return A(fe,e)}function fe(e){let n=oe(),o=ne(F),t=o?o.register(n.inFallback):void 0;function c(i){return i==null||typeof i=="boolean"?null:typeof i=="function"&&ie(i)&&!h(i)?i():i}let u=se(()=>c(e.fallback??null)),s=P(n,()=>e.children);P(n,()=>{ee(()=>{let i=s;if(Array.isArray(i))for(let d of i)typeof d=="function"&&h(d)&&d();else typeof i=="function"&&h(i)&&i()})});let[a,r]=x(void 0),p=j(s);return p&&(n.increment(),s.then(i=>{r(()=>i),n.decrement()},()=>n.decrement())),Q(()=>(t?t.showFallback():n.inFallback())?u:p?a():s)}function pe(e){return A(le,e)}function le(e){let{revealOrder:n="together",tail:o}=e,t=[];function c(){if(n==="together"){let s=t.every(a=>!a.inFallback());t.forEach(a=>{a.setShowContent(s),a.setShowFallback(!s)})}else{let s=n==="backwards"?[...t].reverse():t,a=!1;for(let r of s)a||r.inFallback()?(a=!0,r.setShowContent(!1),r.setShowFallback(o!=="hidden")):(r.setShowContent(!0),r.setShowFallback(!1))}}let u={register:s=>{let[a,r]=x(!0),[p,i]=x(!1);return t.push({inFallback:s,setShowContent:r,setShowFallback:i}),Z(()=>{s(),c()}),{showContent:a,showFallback:p}}};return F.Provider({value:u,children:e.children})}re(C);Object.defineProperty(C,"__suspense",{value:!0,enumerable:!0});import{untrack as M,createMemo as de,createResource as ye}from"@fluixi/reactive/signal";function me(e,n){let o,t,c;function u(){return t||(t=e().then(a=>o=a.default)),t}n?.preload&&u();let s=(a=>{if(o){let r=o;return M(()=>r(a))}if(!c){let[r]=ye(()=>u());if(c=r,r.error)throw r.error}return de(()=>{let r=c();return r?M(()=>r(a)):void 0},void 0,{name:"lazy"})});return s.preload=()=>u().then(()=>{}),s.$lazy=!0,s.loader=e,s}typeof window<"u"&&import("lit").then(e=>xe(e.render));var S=typeof window>"u";function Se(e,n,o={}){if(T("render"),D(["click","input","change","submit"]),S)throw new Error("render() is for client-side only. Use renderToString() on server.");if(!n)throw new Error("Container element is required");let t;return be(c=>{t=c;let u=typeof e=="function"?e():e;n.textContent="",n.setAttribute("fluixi-js","v1"),Ce(n,()=>u)}),()=>{t&&(t(),t=void 0)}}function we(e){return e&&typeof e=="object"&&(e._$litType$!==void 0||e._$litDirective$!==void 0)}function Ve(e,n,o={}){let t=document.createElement("div");t.setAttribute("data-portal","true"),n.appendChild(t);let c=Se(e,t,o);return()=>{c(),n.contains(t)&&n.removeChild(t)}}function Be(e){return!!(e==null||typeof e=="function"||he(e)||we(e)||Array.isArray(e)||typeof e=="string"||typeof e=="number"||typeof e=="boolean")}function He(){S||D(["click","input","change","submit"])}function Ke(){}export{k as $component,b as DEV,C as Suspense,pe as SuspenseList,N as batch,Ke as cleanupDelegation,O as createComponent,l as createEffect,v as createMemo,G as devOnly,m as getOwner,I as getSharedConfig,He as initDelegation,Y as isDev,ue as isJSXElement,ae as isLitResult,ce as isNode,j as isPromise,Be as isRenderable,me as lazy,f as onCleanup,V as onMount,B as onUnmount,Ve as portal,Se as render,L as runWithOwner,X as useCallback,R as useEffect,J as useEventListener,H as useMemo,q as useReducer,K as useRef};
@@ -0,0 +1 @@
1
+ "use strict";var m=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(n,e)=>{for(var r in e)m(n,r,{get:e[r],enumerable:!0})},y=(n,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of f(e))!l.call(n,o)&&o!==r&&m(n,o,{get:()=>e[o],enumerable:!(i=u(e,o))||i.enumerable});return n};var C=n=>y(m({},"__esModule",{value:!0}),n);var z={};c(z,{lazy:()=>P});module.exports=C(z);var a=require("@fluixi/reactive/signal");function P(n,e){let r,i,o;function p(){return i||(i=n().then(s=>r=s.default)),i}e?.preload&&p();let d=(s=>{if(r){let t=r;return(0,a.untrack)(()=>t(s))}if(!o){let[t]=(0,a.createResource)(()=>p());if(o=t,t.error)throw t.error}return(0,a.createMemo)(()=>{let t=o();return t?(0,a.untrack)(()=>t(s)):void 0},void 0,{name:"lazy"})});return d.preload=()=>p().then(()=>{}),d.$lazy=!0,d.loader=n,d}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Lazy-load a component module.
3
+ *
4
+ * SolidJS-aligned pattern:
5
+ * 1. `comp` signal is shared across all instances of this lazy component (module-level).
6
+ * 2. `createResource` at the component level registers the load promise with the
7
+ * nearest Suspense boundary (trackPromise / resource.loading).
8
+ * 3. A pure `createMemo` reads `comp()` — undefined while loading (Suspense shows
9
+ * fallback), the rendered component once loaded.
10
+ * 4. `preload()` is exposed so routes / link hover handlers can start the download
11
+ * before the component is rendered.
12
+ */
13
+ import { Component, ComponentProps } from '@fluixi/dom';
14
+ export type LazyComponent<P = ComponentProps> = () => Promise<{
15
+ default: Component<P>;
16
+ }>;
17
+ export interface LazyOptions {
18
+ /** Show this while the module is loading */
19
+ fallback?: any;
20
+ /** If true, start loading immediately when lazy() is called */
21
+ preload?: boolean;
22
+ }
23
+ export declare function lazy<T extends (...args: any[]) => any>(loader: () => Promise<{
24
+ default: T;
25
+ }>, options?: LazyOptions): T & {
26
+ preload: () => Promise<void>;
27
+ };
28
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../../../src/lib/render/lazy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAUxD,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,cAAc,IAAI,MAAM,OAAO,CAAC;IAC5D,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID,wBAAgB,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACpD,MAAM,EAAE,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC,EACrC,OAAO,CAAC,EAAE,WAAW,GACpB,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAqDtC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Lazy-load a component module.
3
+ *
4
+ * SolidJS-aligned pattern:
5
+ * 1. `comp` signal is shared across all instances of this lazy component (module-level).
6
+ * 2. `createResource` at the component level registers the load promise with the
7
+ * nearest Suspense boundary (trackPromise / resource.loading).
8
+ * 3. A pure `createMemo` reads `comp()` — undefined while loading (Suspense shows
9
+ * fallback), the rendered component once loaded.
10
+ * 4. `preload()` is exposed so routes / link hover handlers can start the download
11
+ * before the component is rendered.
12
+ */
13
+ import { untrack, createMemo, createResource, } from '@fluixi/reactive/signal';
14
+ // ─── Implementation ──────────────────────────────────────────────────────────
15
+ export function lazy(loader, options) {
16
+ // The resolved component, set once the module loads. The whole hydration story turns on
17
+ // this: when it's already set when LazyWrapper renders — because the route was preloaded
18
+ // before hydration (see startClient → preloadRoutes) — we render it SYNCHRONOUSLY on the
19
+ // first pass. No resource, no Suspense fallback, no late re-render. So the lazy file-route
20
+ // adopts the server DOM in place instead of resolving a tick later and building a duplicate
21
+ // next to it. The async path below is only for a cold client navigation.
22
+ let resolved;
23
+ // Single in-flight / completed import. Idempotent: repeat calls reuse the same promise.
24
+ let promise;
25
+ // Suspense-tracked resource, created lazily on the cold (not-preloaded) path only.
26
+ let component;
27
+ function load() {
28
+ if (!promise) {
29
+ promise = loader().then((mod) => (resolved = mod.default));
30
+ }
31
+ return promise;
32
+ }
33
+ if (options?.preload)
34
+ load();
35
+ const LazyWrapper = ((props) => {
36
+ // Fast path: module already loaded (eager preload, or preloaded before hydration).
37
+ // Render straight through — under hydration this consumes the cursor in place.
38
+ if (resolved) {
39
+ const C = resolved;
40
+ return untrack(() => C(props));
41
+ }
42
+ // Cold path: not loaded yet (client-side navigation to a route whose chunk hasn't been
43
+ // fetched). Register the import with the nearest Suspense via createResource so the
44
+ // fallback shows while it downloads, then swap in the component once it resolves.
45
+ if (!component) {
46
+ const [resource] = createResource(() => load());
47
+ component = resource;
48
+ if (resource.error)
49
+ throw resource.error;
50
+ }
51
+ return createMemo(() => {
52
+ const C = component();
53
+ return C ? untrack(() => C(props)) : undefined;
54
+ }, undefined, { name: 'lazy' });
55
+ });
56
+ // Callers (link hover, router prefetch, the hydration preload pass) start the download
57
+ // before the component enters the view: <a onMouseEnter={() => LazyFoo.preload()}>.
58
+ LazyWrapper.preload = () => load().then(() => undefined);
59
+ LazyWrapper.$lazy = true;
60
+ LazyWrapper.loader = loader;
61
+ return LazyWrapper;
62
+ }
@@ -0,0 +1 @@
1
+ import{untrack as s,createMemo as m,createResource as u}from"@fluixi/reactive/signal";function c(d,p){let r,t,a;function i(){return t||(t=d().then(o=>r=o.default)),t}p?.preload&&i();let n=(o=>{if(r){let e=r;return s(()=>e(o))}if(!a){let[e]=u(()=>i());if(a=e,e.error)throw e.error}return m(()=>{let e=a();return e?s(()=>e(o)):void 0},void 0,{name:"lazy"})});return n.preload=()=>i().then(()=>{}),n.$lazy=!0,n.loader=d,n}export{c as lazy};
@@ -0,0 +1 @@
1
+ "use strict";var y=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var a in t)y(e,a,{get:t[a],enumerable:!0})},F=(e,t,a,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of w(t))!k.call(e,c)&&c!==a&&y(e,c,{get:()=>t[c],enumerable:!(r=m(t,c))||r.enumerable});return e};var P=e=>F(y({},"__esModule",{value:!0}),e);var N={};C(N,{$SUSPENSE:()=>g,Suspense:()=>b,SuspenseList:()=>E,isJSXElement:()=>x,isLitResult:()=>L,isNode:()=>A,isPromise:()=>S});module.exports=P(N);var n=require("@fluixi/reactive/signal"),f=require("@fluixi/dom"),g=Symbol.for("suspense");function A(e){return typeof window>"u"?!1:typeof Node=="function"&&e instanceof Node?!0:!!(e&&typeof e=="object"&&typeof e.nodeType=="number")}function L(e){return!e||typeof e!="object"?!1:!!(typeof e._$litType$<"u"||typeof e._$litDirective$<"u"||Array.isArray(e.strings)&&Array.isArray(e.values))}function S(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}function x(e){return!!(e&&typeof e=="object"&&"type"in e&&"props"in e)}var h=(0,n.createContext)();function b(e){return(0,f.createComponent)(R,e)}function R(e){let t=(0,n.createSuspenseBoundary)(),a=(0,n.useContext)(h),r=a?a.register(t.inFallback):void 0;function c(o){return o==null||typeof o=="boolean"?null:typeof o=="function"&&(0,f.isComponent)(o)&&!(0,n.isSignal)(o)?o():o}let p=(0,f.runWithoutHydration)(()=>c(e.fallback??null)),s=(0,n.provideSuspense)(t,()=>e.children);(0,n.provideSuspense)(t,()=>{(0,n.createRenderEffect)(()=>{let o=s;if(Array.isArray(o))for(let d of o)typeof d=="function"&&(0,n.isSignal)(d)&&d();else typeof o=="function"&&(0,n.isSignal)(o)&&o()})});let[i,l]=(0,n.createSignal)(void 0),u=S(s);return u&&(t.increment(),s.then(o=>{l(()=>o),t.decrement()},()=>t.decrement())),(0,n.createMemo)(()=>(r?r.showFallback():t.inFallback())?p:u?i():s)}function E(e){return(0,f.createComponent)(j,e)}function j(e){let{revealOrder:t="together",tail:a}=e,r=[];function c(){if(t==="together"){let s=r.every(i=>!i.inFallback());r.forEach(i=>{i.setShowContent(s),i.setShowFallback(!s)})}else{let s=t==="backwards"?[...r].reverse():r,i=!1;for(let l of s)i||l.inFallback()?(i=!0,l.setShowContent(!1),l.setShowFallback(a!=="hidden")):(l.setShowContent(!0),l.setShowFallback(!1))}}let p={register:s=>{let[i,l]=(0,n.createSignal)(!0),[u,o]=(0,n.createSignal)(!1);return r.push({inFallback:s,setShowContent:l,setShowFallback:o}),(0,n.createEffect)(()=>{s(),c()}),{showContent:i,showFallback:u}}};return h.Provider({value:p,children:e.children})}(0,f.asSuspense)(b);Object.defineProperty(b,"__suspense",{value:!0,enumerable:!0});
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Suspense on the TC39 boundary. A createResource read throws its promise while
3
+ * pending; the effect running it reports that to the nearest boundary (stamped as
4
+ * SuspenseContext on this component's owner), which flips inFallback. The output
5
+ * memo swaps between fallback and children on that signal.
6
+ */
7
+ export interface SuspenseProps {
8
+ fallback?: any;
9
+ children?: any;
10
+ id?: string;
11
+ }
12
+ export interface SuspenseListProps {
13
+ children: any;
14
+ revealOrder?: 'forwards' | 'backwards' | 'together';
15
+ tail?: 'collapsed' | 'hidden';
16
+ }
17
+ export declare const $SUSPENSE: unique symbol;
18
+ declare function isNode(value: any): value is Node;
19
+ declare function isLitResult(value: any): boolean;
20
+ declare function isPromise<T = any>(value: any): value is Promise<T>;
21
+ declare function isJSXElement(value: any): boolean;
22
+ export declare function Suspense(props: SuspenseProps): any;
23
+ export declare function SuspenseList(props: SuspenseListProps): any;
24
+ export { isNode, isLitResult, isPromise, isJSXElement };
25
+ //# sourceMappingURL=suspense.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suspense.d.ts","sourceRoot":"","sources":["../../../../src/lib/render/suspense.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,GAAG,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,CAAC;IACpD,IAAI,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;CAC/B;AAED,eAAO,MAAM,SAAS,eAAyB,CAAC;AAEhD,iBAAS,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,IAAI,CAIzC;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAOxC;AAED,iBAAS,SAAS,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAK3D;AAED,iBAAS,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAEzC;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,GAAG,CAElD;AA6DD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,CAE1D;AAwDD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Suspense on the TC39 boundary. A createResource read throws its promise while
3
+ * pending; the effect running it reports that to the nearest boundary (stamped as
4
+ * SuspenseContext on this component's owner), which flips inFallback. The output
5
+ * memo swaps between fallback and children on that signal.
6
+ */
7
+ import { createSignal, createMemo, createEffect, createRenderEffect, isSignal, useContext, createContext, createSuspenseBoundary, provideSuspense, } from '@fluixi/reactive/signal';
8
+ import { asSuspense, isComponent, createComponent, runWithoutHydration, } from '@fluixi/dom';
9
+ export const $SUSPENSE = Symbol.for('suspense');
10
+ function isNode(value) {
11
+ if (typeof window === 'undefined')
12
+ return false;
13
+ if (typeof Node === 'function' && value instanceof Node)
14
+ return true;
15
+ return !!(value && typeof value === 'object' && typeof value.nodeType === 'number');
16
+ }
17
+ function isLitResult(value) {
18
+ if (!value || typeof value !== 'object')
19
+ return false;
20
+ return !!(typeof value['_$litType$'] !== 'undefined' ||
21
+ typeof value['_$litDirective$'] !== 'undefined' ||
22
+ (Array.isArray(value.strings) && Array.isArray(value.values)));
23
+ }
24
+ function isPromise(value) {
25
+ return !!((value && typeof value === 'object' && typeof value.then === 'function') ||
26
+ value instanceof Promise);
27
+ }
28
+ function isJSXElement(value) {
29
+ return !!(value && typeof value === 'object' && 'type' in value && 'props' in value);
30
+ }
31
+ const SuspenseListContext = createContext();
32
+ export function Suspense(props) {
33
+ return createComponent(SuspenseImpl, props);
34
+ }
35
+ function SuspenseImpl(props) {
36
+ const boundary = createSuspenseBoundary();
37
+ // SuspenseList coordination, if any.
38
+ const listCtx = useContext(SuspenseListContext);
39
+ const listState = listCtx ? listCtx.register(boundary.inFallback) : undefined;
40
+ function instantiateOnce(val) {
41
+ if (val == null || typeof val === 'boolean')
42
+ return null;
43
+ if (typeof val === 'function' && isComponent(val) && !isSignal(val))
44
+ return val();
45
+ return val;
46
+ }
47
+ // Build the fallback off the hydration cursor — it isn't shown when the server
48
+ // already rendered content, so it must not adopt (and duplicate) server nodes.
49
+ const fallback = runWithoutHydration(() => instantiateOnce(props.fallback ?? null));
50
+ // Read the children under the boundary so the memos they create capture its owner;
51
+ // then a suspended resource read inside them throws to THIS boundary, not the parent.
52
+ const children = provideSuspense(boundary, () => props.children);
53
+ // Instantiate the children now, in their own effect under the boundary. A suspended
54
+ // resource read inside them throws here synchronously — a sibling of the output memo
55
+ // below — so the increment reschedules the output cleanly (matching the canary). If we
56
+ // only rendered children through the output's return, the resource read would be nested
57
+ // inside the output's own insert effect, which then never re-runs to show the fallback.
58
+ provideSuspense(boundary, () => {
59
+ createRenderEffect(() => {
60
+ const c = children;
61
+ if (Array.isArray(c)) {
62
+ for (const x of c)
63
+ if (typeof x === 'function' && isSignal(x))
64
+ x();
65
+ }
66
+ else if (typeof c === 'function' && isSignal(c)) {
67
+ c();
68
+ }
69
+ });
70
+ });
71
+ // A raw promise child: track it directly on the boundary.
72
+ const [resolved, setResolved] = createSignal(undefined);
73
+ const childIsPromise = isPromise(children);
74
+ if (childIsPromise) {
75
+ boundary.increment();
76
+ children.then((v) => {
77
+ setResolved(() => v);
78
+ boundary.decrement();
79
+ }, () => boundary.decrement());
80
+ }
81
+ return createMemo(() => {
82
+ const showFallback = listState ? listState.showFallback() : boundary.inFallback();
83
+ if (showFallback)
84
+ return fallback;
85
+ if (childIsPromise)
86
+ return resolved();
87
+ return children;
88
+ });
89
+ }
90
+ export function SuspenseList(props) {
91
+ return createComponent(SuspenseListImpl, props);
92
+ }
93
+ function SuspenseListImpl(props) {
94
+ const { revealOrder = 'together', tail } = props;
95
+ const registrations = [];
96
+ function coordinateReveal() {
97
+ if (revealOrder === 'together') {
98
+ const allResolved = registrations.every((r) => !r.inFallback());
99
+ registrations.forEach((r) => {
100
+ r.setShowContent(allResolved);
101
+ r.setShowFallback(!allResolved);
102
+ });
103
+ }
104
+ else {
105
+ const items = revealOrder === 'backwards' ? [...registrations].reverse() : registrations;
106
+ let blocked = false;
107
+ for (const r of items) {
108
+ if (blocked || r.inFallback()) {
109
+ blocked = true;
110
+ r.setShowContent(false);
111
+ r.setShowFallback(tail !== 'hidden');
112
+ }
113
+ else {
114
+ r.setShowContent(true);
115
+ r.setShowFallback(false);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ const coordinator = {
121
+ register: (inFallback) => {
122
+ const [showContent, setShowContent] = createSignal(true);
123
+ const [showFallback, setShowFallback] = createSignal(false);
124
+ registrations.push({ inFallback, setShowContent, setShowFallback });
125
+ createEffect(() => {
126
+ inFallback();
127
+ coordinateReveal();
128
+ });
129
+ return { showContent, showFallback };
130
+ },
131
+ };
132
+ return SuspenseListContext.Provider({
133
+ value: coordinator,
134
+ children: props.children,
135
+ });
136
+ }
137
+ asSuspense(Suspense);
138
+ Object.defineProperty(Suspense, '__suspense', { value: true, enumerable: true });
139
+ export { isNode, isLitResult, isPromise, isJSXElement };
@@ -0,0 +1 @@
1
+ import{createSignal as d,createMemo as m,createEffect as w,createRenderEffect as k,isSignal as p,useContext as C,createContext as F,createSuspenseBoundary as P,provideSuspense as y}from"@fluixi/reactive/signal";import{asSuspense as g,isComponent as A,createComponent as b,runWithoutHydration as L}from"@fluixi/dom";var $=Symbol.for("suspense");function O(e){return typeof window>"u"?!1:typeof Node=="function"&&e instanceof Node?!0:!!(e&&typeof e=="object"&&typeof e.nodeType=="number")}function T(e){return!e||typeof e!="object"?!1:!!(typeof e._$litType$<"u"||typeof e._$litDirective$<"u"||Array.isArray(e.strings)&&Array.isArray(e.values))}function x(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}function _(e){return!!(e&&typeof e=="object"&&"type"in e&&"props"in e)}var S=F();function h(e){return b(R,e)}function R(e){let s=P(),a=C(S),i=a?a.register(s.inFallback):void 0;function l(n){return n==null||typeof n=="boolean"?null:typeof n=="function"&&A(n)&&!p(n)?n():n}let f=L(()=>l(e.fallback??null)),t=y(s,()=>e.children);y(s,()=>{k(()=>{let n=t;if(Array.isArray(n))for(let u of n)typeof u=="function"&&p(u)&&u();else typeof n=="function"&&p(n)&&n()})});let[o,r]=d(void 0),c=x(t);return c&&(s.increment(),t.then(n=>{r(()=>n),s.decrement()},()=>s.decrement())),m(()=>(i?i.showFallback():s.inFallback())?f:c?o():t)}function B(e){return b(E,e)}function E(e){let{revealOrder:s="together",tail:a}=e,i=[];function l(){if(s==="together"){let t=i.every(o=>!o.inFallback());i.forEach(o=>{o.setShowContent(t),o.setShowFallback(!t)})}else{let t=s==="backwards"?[...i].reverse():i,o=!1;for(let r of t)o||r.inFallback()?(o=!0,r.setShowContent(!1),r.setShowFallback(a!=="hidden")):(r.setShowContent(!0),r.setShowFallback(!1))}}let f={register:t=>{let[o,r]=d(!0),[c,n]=d(!1);return i.push({inFallback:t,setShowContent:r,setShowFallback:n}),w(()=>{t(),l()}),{showContent:o,showFallback:c}}};return S.Provider({value:f,children:e.children})}g(h);Object.defineProperty(h,"__suspense",{value:!0,enumerable:!0});export{$ as $SUSPENSE,h as Suspense,B as SuspenseList,_ as isJSXElement,T as isLitResult,O as isNode,x as isPromise};
@@ -0,0 +1 @@
1
+ "use strict";var x=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var n in t)x(e,n,{get:t[n],enumerable:!0})},k=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of D(t))!L.call(e,o)&&o!==n&&x(e,o,{get:()=>t[o],enumerable:!(r=O(t,o))||r.enumerable});return e};var H=e=>k(x({},"__esModule",{value:!0}),e);var q={};_(q,{RouteDataContext:()=>m,RouteDataProvider:()=>Y,action:()=>R,cache:()=>F,createAsync:()=>K,revalidate:()=>z,useAction:()=>X,useRouteData:()=>B,useSubmission:()=>J});module.exports=H(q);var u=require("@fluixi/reactive/signal");var M=!1,T=new Map;function v(){return M}function h(e,t){T.set(e,t)}function C(e){return T.get(e)}function U(){T.clear()}function j(){if(typeof window>"u")return;let e=document.getElementById("__FLUIXI_HYDRATION__");e&&e.remove();let t=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null),n=[],r;for(;r=t.nextNode();){let o=r,i=o.nodeValue||"";(i.startsWith("#")||i.startsWith("/"))&&n.push(o)}n.forEach(o=>o.remove()),U()}typeof window<"u"&&window.addEventListener("load",()=>{setTimeout(j,100)});function b(){return typeof window>"u"}var S=require("@fluixi/dom"),l=require("@fluixi/reactive/signal"),V=require("@fluixi/reactive/signal");var f=require("@fluixi/dom"),s=require("@fluixi/reactive/signal");function A(e){(0,f.registerCreateComponent)(I)}function I(e,t){return N(e,t)}function N(e,t){let n=typeof e=="function"?(0,s.untrack)(()=>e(t)):e;if(n!=null&&(typeof n=="function"||typeof n=="object")&&!(0,s.isSignal)(n)){try{n.$name=e.name}catch{}return(0,f.asComponent)(n)}return n}A("index");function w(e){let t=(0,l.createContext)(e),n=r=>(r.debug,t.Provider({value:r.value,get children(){return r.children},debug:r.debug}));return typeof Symbol<"u"&&Symbol.for&&(n.$$typeof=Symbol.for("react.provider")),n.$$typeof=Symbol.for("react.provider"),{id:t.id,Provider:(0,S.asProvider)(n),defaultValue:e}}function P(e){let t=(0,l.useContext)(e);return t!==void 0?t:e.defaultValue}var d=new Map,c=new Map;function F(e,t){return async(...n)=>{let r=t+":"+JSON.stringify(n);if(v()||typeof window<"u"){let i=C(r);if(i!==void 0)return i}if(d.has(r))return d.get(r);if(c.has(r))return c.get(r);let o=Promise.resolve(e(...n)).then(i=>(d.set(r,i),c.delete(r),b()&&h(r,i),i),i=>{throw c.delete(r),i});return c.set(r,o),o}}var[Te,W]=(0,u.createSignal)(0),$=new Set;function z(e){let t=typeof e=="string"?n=>n.startsWith(e):e;for(let n of d.keys())t(n)&&(d.delete(n),$.add(n));W(n=>n+1)}function K(e,t){let[n]=(0,u.createResource)(t||(()=>!0),e);return n}var g=new Map;function E(e){return g.has(e)||g.set(e,(0,u.createSignal)(void 0)),g.get(e)}function R(e,t){let n=t||e.name||"action",r=async o=>{let[,i]=E(n),p=()=>i(void 0),y=()=>r(o);i({input:o,pending:!0,clear:p,retry:y});try{let a=await e(o);return i({input:o,result:a,pending:!1,clear:p,retry:y}),a}catch(a){throw i({input:o,error:a,pending:!1,clear:p,retry:y}),a}};return r.url=n,r.with=o=>R((...i)=>e(o,...i),t),r}function J(e){let[t]=E(e.url);return t}function X(e){return e}var m=w(),Y=m.Provider;function B(){let e=P(m);return typeof e=="function"?e:()=>e}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @fileoverview Data fetching and caching primitives for Fluixi Router
3
+ * @module @fluixi/core/router/data
4
+ */
5
+ import { type Accessor, Resource } from '@fluixi/reactive/signal';
6
+ export type CacheFn<T, Args extends any[]> = (...args: Args) => Promise<T> | T | undefined;
7
+ export interface Action<T, Args extends any[]> {
8
+ (...args: Args): Promise<T>;
9
+ url?: string;
10
+ with?: (args: any) => Action<T, Args>;
11
+ }
12
+ export interface Submission<T, Args extends any[]> {
13
+ input: Args;
14
+ result?: T;
15
+ error?: any;
16
+ pending: boolean;
17
+ clear: () => void;
18
+ retry: () => void;
19
+ }
20
+ /**
21
+ * Cache an async function for data fetching
22
+ *
23
+ * Supports:
24
+ * - Deduplication
25
+ * - Hydration (Server -> Client)
26
+ * - Revalidation
27
+ *
28
+ * @param fn Async function to cache
29
+ * @param name Unique name for the cache key
30
+ */
31
+ export declare function cache<T, Args extends any[]>(fn: (...args: Args) => Promise<T> | T, name: string): (...args: Args) => Promise<T>;
32
+ /**
33
+ * Revalidate a cache key. Clears the memory cache and triggers
34
+ * reactive invalidation so resources using createAsync re-fetch.
35
+ *
36
+ * @param key Key prefix string or predicate function to match cache keys
37
+ */
38
+ export declare function revalidate(key: string | ((key: string) => boolean)): void;
39
+ /**
40
+ * Create an async resource from a promise or cache function
41
+ *
42
+ * @param fetcher Function that returns a promise
43
+ * @param source Dependency signal (optional)
44
+ */
45
+ export declare function createAsync<T, S extends any = true>(fetcher: (source: S) => Promise<T> | T, source?: () => S): Resource<S>;
46
+ /**
47
+ * Create a server action
48
+ *
49
+ * @param fn Function to execute (server-side)
50
+ * @param name Action name
51
+ */
52
+ export declare function action<T, Args extends any[]>(fn: (...args: Args) => Promise<T> | T, name?: string): Action<T, Args>;
53
+ /**
54
+ * Hook to track action submission state
55
+ */
56
+ export declare function useSubmission<T, Args extends any[]>(actionFn: Action<T, Args>): Accessor<Submission<T, Args> | undefined>;
57
+ /**
58
+ * Hook to get action executor
59
+ */
60
+ export declare function useAction<T, Args extends any[]>(actionFn: Action<T, Args>): (...args: Args) => Promise<T>;
61
+ export interface RouteDataArgs {
62
+ /**
63
+ * Route params — either a reactive signal accessor (when called from the
64
+ * router's createRoot during layout creation) or a plain snapshot object
65
+ * (legacy / manual usage). Always normalise with:
66
+ * `const getParams = typeof args.params === 'function' ? args.params : () => args.params;`
67
+ */
68
+ params: Record<string, string> | (() => Record<string, string>);
69
+ location: {
70
+ pathname: string;
71
+ search: string;
72
+ } | (() => {
73
+ pathname: string;
74
+ search: string;
75
+ });
76
+ }
77
+ export type RouteLoadFunc = (args: RouteDataArgs, owner?: any, isCancelled?: () => boolean) => any;
78
+ export declare const RouteDataContext: {
79
+ id: symbol;
80
+ Provider: (props: {
81
+ value: any;
82
+ children?: any;
83
+ debug?: boolean;
84
+ }) => any;
85
+ defaultValue: any;
86
+ };
87
+ export declare const RouteDataProvider: (props: {
88
+ value: any;
89
+ children?: any;
90
+ debug?: boolean;
91
+ }) => any;
92
+ /**
93
+ * Access the data returned by the nearest ancestor route's `routeData` export.
94
+ *
95
+ * Returns a stable accessor function. Call it to get the current route data:
96
+ *
97
+ * const data = useRouteData<WorkspaceRouteData>();
98
+ * createEffect(() => console.log(data()?.workspace()));
99
+ */
100
+ export declare function useRouteData<T>(): () => T | undefined;
101
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../../src/lib/router-next/data.ts"],"names":[],"mappings":"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"}