@fluixi/core 1.0.0-alpha.100

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 (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +334 -0
  3. package/dist/cdn/core.global.js +2 -0
  4. package/dist/cli/generate.cjs +5639 -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 +5644 -0
  9. package/dist/cli/index.cjs +5639 -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 +5644 -0
  14. package/dist/cli/run.cjs +64 -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 +40 -0
  19. package/dist/fluixi.d.ts +5 -0
  20. package/dist/src/cdn/chunk-RKBFEFZP.mjs +987 -0
  21. package/dist/src/cdn/core.cjs +1592 -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 +714 -0
  26. package/dist/src/cdn/router-V2THK27H.mjs +74 -0
  27. package/dist/src/index.cjs +1711 -0
  28. package/dist/src/index.d.ts +4 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/index.js +11 -0
  31. package/dist/src/index.mjs +1833 -0
  32. package/dist/src/jsx-dev-runtime.cjs +26 -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 +24 -0
  37. package/dist/src/jsx-runtime.cjs +26 -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 +8 -0
  41. package/dist/src/jsx-runtime.mjs +24 -0
  42. package/dist/src/lib/client/chunk-FDOPDB6Z.mjs +53 -0
  43. package/dist/src/lib/client/index.cjs +1210 -0
  44. package/dist/src/lib/client/index.d.ts +51 -0
  45. package/dist/src/lib/client/index.d.ts.map +1 -0
  46. package/dist/src/lib/client/index.js +174 -0
  47. package/dist/src/lib/client/index.mjs +293 -0
  48. package/dist/src/lib/client/router-4PTBPZLQ.mjs +891 -0
  49. package/dist/src/lib/context/context.cjs +81 -0
  50. package/dist/src/lib/context/context.d.ts +73 -0
  51. package/dist/src/lib/context/context.d.ts.map +1 -0
  52. package/dist/src/lib/context/context.js +93 -0
  53. package/dist/src/lib/context/context.mjs +64 -0
  54. package/dist/src/lib/context/index.cjs +83 -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 +1 -0
  58. package/dist/src/lib/context/index.mjs +64 -0
  59. package/dist/src/lib/control-flow.cjs +35 -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 +25 -0
  64. package/dist/src/lib/core.cjs +1710 -0
  65. package/dist/src/lib/core.d.ts +91 -0
  66. package/dist/src/lib/core.d.ts.map +1 -0
  67. package/dist/src/lib/core.js +158 -0
  68. package/dist/src/lib/core.mjs +1833 -0
  69. package/dist/src/lib/env/index.cjs +44 -0
  70. package/dist/src/lib/env/index.d.ts +26 -0
  71. package/dist/src/lib/env/index.d.ts.map +1 -0
  72. package/dist/src/lib/env/index.js +31 -0
  73. package/dist/src/lib/env/index.mjs +23 -0
  74. package/dist/src/lib/i18n/index.cjs +123 -0
  75. package/dist/src/lib/i18n/index.d.ts +110 -0
  76. package/dist/src/lib/i18n/index.d.ts.map +1 -0
  77. package/dist/src/lib/i18n/index.js +164 -0
  78. package/dist/src/lib/i18n/index.mjs +103 -0
  79. package/dist/src/lib/index.cjs +598 -0
  80. package/dist/src/lib/index.d.ts +81 -0
  81. package/dist/src/lib/index.d.ts.map +1 -0
  82. package/dist/src/lib/index.js +130 -0
  83. package/dist/src/lib/index.mjs +688 -0
  84. package/dist/src/lib/isomorphic.cjs +90 -0
  85. package/dist/src/lib/isomorphic.d.ts +114 -0
  86. package/dist/src/lib/isomorphic.d.ts.map +1 -0
  87. package/dist/src/lib/isomorphic.js +132 -0
  88. package/dist/src/lib/isomorphic.mjs +69 -0
  89. package/dist/src/lib/jsx-runtime/index.cjs +21 -0
  90. package/dist/src/lib/jsx-runtime/index.d.ts +13 -0
  91. package/dist/src/lib/jsx-runtime/index.d.ts.map +1 -0
  92. package/dist/src/lib/jsx-runtime/index.js +13 -0
  93. package/dist/src/lib/jsx-runtime/index.mjs +4 -0
  94. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +21 -0
  95. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts +2 -0
  96. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts.map +1 -0
  97. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.js +1 -0
  98. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +4 -0
  99. package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +302 -0
  100. package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts +35 -0
  101. package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts.map +1 -0
  102. package/dist/src/lib/plugins/fluixi-routes-plugin.js +118 -0
  103. package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +271 -0
  104. package/dist/src/lib/plugins/index.cjs +311 -0
  105. package/dist/src/lib/plugins/index.d.ts +6 -0
  106. package/dist/src/lib/plugins/index.d.ts.map +1 -0
  107. package/dist/src/lib/plugins/index.js +7 -0
  108. package/dist/src/lib/plugins/index.mjs +279 -0
  109. package/dist/src/lib/plugins/route-codegen.cjs +73 -0
  110. package/dist/src/lib/plugins/route-codegen.d.ts +12 -0
  111. package/dist/src/lib/plugins/route-codegen.d.ts.map +1 -0
  112. package/dist/src/lib/plugins/route-codegen.js +80 -0
  113. package/dist/src/lib/plugins/route-codegen.mjs +52 -0
  114. package/dist/src/lib/plugins/route-scanner.cjs +189 -0
  115. package/dist/src/lib/plugins/route-scanner.d.ts +38 -0
  116. package/dist/src/lib/plugins/route-scanner.d.ts.map +1 -0
  117. package/dist/src/lib/plugins/route-scanner.js +215 -0
  118. package/dist/src/lib/plugins/route-scanner.mjs +158 -0
  119. package/dist/src/lib/plugins/vite.cjs +27 -0
  120. package/dist/src/lib/plugins/vite.d.ts +3 -0
  121. package/dist/src/lib/plugins/vite.d.ts.map +1 -0
  122. package/dist/src/lib/plugins/vite.js +1 -0
  123. package/dist/src/lib/plugins/vite.mjs +6 -0
  124. package/dist/src/lib/render/await.cjs +38 -0
  125. package/dist/src/lib/render/await.d.ts +26 -0
  126. package/dist/src/lib/render/await.d.ts.map +1 -0
  127. package/dist/src/lib/render/await.js +45 -0
  128. package/dist/src/lib/render/await.mjs +17 -0
  129. package/dist/src/lib/render/component.cjs +221 -0
  130. package/dist/src/lib/render/component.d.ts +296 -0
  131. package/dist/src/lib/render/component.d.ts.map +1 -0
  132. package/dist/src/lib/render/component.js +514 -0
  133. package/dist/src/lib/render/component.mjs +214 -0
  134. package/dist/src/lib/render/deferred.cjs +175 -0
  135. package/dist/src/lib/render/deferred.d.ts +36 -0
  136. package/dist/src/lib/render/deferred.d.ts.map +1 -0
  137. package/dist/src/lib/render/deferred.js +141 -0
  138. package/dist/src/lib/render/deferred.mjs +158 -0
  139. package/dist/src/lib/render/index.cjs +573 -0
  140. package/dist/src/lib/render/index.d.ts +98 -0
  141. package/dist/src/lib/render/index.d.ts.map +1 -0
  142. package/dist/src/lib/render/index.js +180 -0
  143. package/dist/src/lib/render/index.mjs +590 -0
  144. package/dist/src/lib/render/lazy.cjs +67 -0
  145. package/dist/src/lib/render/lazy.d.ts +49 -0
  146. package/dist/src/lib/render/lazy.d.ts.map +1 -0
  147. package/dist/src/lib/render/lazy.js +105 -0
  148. package/dist/src/lib/render/lazy.mjs +50 -0
  149. package/dist/src/lib/render/suspense.cjs +141 -0
  150. package/dist/src/lib/render/suspense.d.ts +65 -0
  151. package/dist/src/lib/render/suspense.d.ts.map +1 -0
  152. package/dist/src/lib/render/suspense.js +196 -0
  153. package/dist/src/lib/render/suspense.mjs +136 -0
  154. package/dist/src/lib/render/versions.cjs +35 -0
  155. package/dist/src/lib/render/versions.d.ts +2 -0
  156. package/dist/src/lib/render/versions.d.ts.map +1 -0
  157. package/dist/src/lib/render/versions.js +21 -0
  158. package/dist/src/lib/render/versions.mjs +14 -0
  159. package/dist/src/lib/router/data.cjs +228 -0
  160. package/dist/src/lib/router/data.d.ts +142 -0
  161. package/dist/src/lib/router/data.d.ts.map +1 -0
  162. package/dist/src/lib/router/data.js +258 -0
  163. package/dist/src/lib/router/data.mjs +214 -0
  164. package/dist/src/lib/router/index.cjs +921 -0
  165. package/dist/src/lib/router/index.d.ts +274 -0
  166. package/dist/src/lib/router/index.d.ts.map +1 -0
  167. package/dist/src/lib/router/index.js +904 -0
  168. package/dist/src/lib/router/index.mjs +938 -0
  169. package/dist/src/lib/router/scroll.cjs +79 -0
  170. package/dist/src/lib/router/scroll.d.ts +19 -0
  171. package/dist/src/lib/router/scroll.d.ts.map +1 -0
  172. package/dist/src/lib/router/scroll.js +68 -0
  173. package/dist/src/lib/router/scroll.mjs +58 -0
  174. package/dist/src/lib/router/transition.cjs +75 -0
  175. package/dist/src/lib/router/transition.d.ts +81 -0
  176. package/dist/src/lib/router/transition.d.ts.map +1 -0
  177. package/dist/src/lib/router/transition.js +136 -0
  178. package/dist/src/lib/router/transition.mjs +54 -0
  179. package/dist/src/lib/server/hydration.cjs +169 -0
  180. package/dist/src/lib/server/hydration.d.ts +198 -0
  181. package/dist/src/lib/server/hydration.d.ts.map +1 -0
  182. package/dist/src/lib/server/hydration.js +345 -0
  183. package/dist/src/lib/server/hydration.mjs +148 -0
  184. package/dist/src/lib/server/index.cjs +406 -0
  185. package/dist/src/lib/server/index.d.ts +115 -0
  186. package/dist/src/lib/server/index.d.ts.map +1 -0
  187. package/dist/src/lib/server/index.js +164 -0
  188. package/dist/src/lib/server/index.mjs +384 -0
  189. package/dist/src/lib/server/reactive.cjs +197 -0
  190. package/dist/src/lib/server/reactive.d.ts +239 -0
  191. package/dist/src/lib/server/reactive.d.ts.map +1 -0
  192. package/dist/src/lib/server/reactive.js +413 -0
  193. package/dist/src/lib/server/reactive.mjs +176 -0
  194. package/dist/src/lib/storage/cache.cjs +51 -0
  195. package/dist/src/lib/storage/cache.d.ts +18 -0
  196. package/dist/src/lib/storage/cache.d.ts.map +1 -0
  197. package/dist/src/lib/storage/cache.js +42 -0
  198. package/dist/src/lib/storage/cache.mjs +30 -0
  199. package/dist/src/lib/storage/index.cjs +246 -0
  200. package/dist/src/lib/storage/index.d.ts +83 -0
  201. package/dist/src/lib/storage/index.d.ts.map +1 -0
  202. package/dist/src/lib/storage/index.js +179 -0
  203. package/dist/src/lib/storage/index.mjs +231 -0
  204. package/dist/src/lib/storage/persisted.cjs +91 -0
  205. package/dist/src/lib/storage/persisted.d.ts +53 -0
  206. package/dist/src/lib/storage/persisted.d.ts.map +1 -0
  207. package/dist/src/lib/storage/persisted.js +75 -0
  208. package/dist/src/lib/storage/persisted.mjs +70 -0
  209. package/dist/src/lib/theme/color-scheme.cjs +281 -0
  210. package/dist/src/lib/theme/color-scheme.d.ts +61 -0
  211. package/dist/src/lib/theme/color-scheme.d.ts.map +1 -0
  212. package/dist/src/lib/theme/color-scheme.js +120 -0
  213. package/dist/src/lib/theme/color-scheme.mjs +265 -0
  214. package/dist/src/lib/theme/index.cjs +267 -0
  215. package/dist/src/lib/theme/index.d.ts +78 -0
  216. package/dist/src/lib/theme/index.d.ts.map +1 -0
  217. package/dist/src/lib/theme/index.js +135 -0
  218. package/dist/src/lib/theme/index.mjs +251 -0
  219. package/dist/src/lib/theme/provider.cjs +346 -0
  220. package/dist/src/lib/theme/provider.d.ts +34 -0
  221. package/dist/src/lib/theme/provider.d.ts.map +1 -0
  222. package/dist/src/lib/theme/provider.js +60 -0
  223. package/dist/src/lib/theme/provider.mjs +332 -0
  224. package/dist/src/lib/utils/index.cjs +209 -0
  225. package/dist/src/lib/utils/index.d.ts +286 -0
  226. package/dist/src/lib/utils/index.d.ts.map +1 -0
  227. package/dist/src/lib/utils/index.js +434 -0
  228. package/dist/src/lib/utils/index.mjs +188 -0
  229. package/dist/src/routes.cjs +37 -0
  230. package/dist/src/routes.d.ts +22 -0
  231. package/dist/src/routes.d.ts.map +1 -0
  232. package/dist/src/routes.js +20 -0
  233. package/dist/src/routes.mjs +17 -0
  234. package/dist/src/server.cjs +405 -0
  235. package/dist/src/server.d.ts +63 -0
  236. package/dist/src/server.d.ts.map +1 -0
  237. package/dist/src/server.js +62 -0
  238. package/dist/src/server.mjs +382 -0
  239. package/dist/src/utils.cjs +21 -0
  240. package/dist/src/utils.d.ts +10 -0
  241. package/dist/src/utils.d.ts.map +1 -0
  242. package/dist/src/utils.js +9 -0
  243. package/dist/src/utils.mjs +4 -0
  244. package/dist/src/version.generated.cjs +26 -0
  245. package/dist/src/version.generated.d.ts +3 -0
  246. package/dist/src/version.generated.d.ts.map +1 -0
  247. package/dist/src/version.generated.js +3 -0
  248. package/dist/src/version.generated.mjs +5 -0
  249. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  250. package/package.json +164 -0
  251. package/src/index.ts +19 -0
  252. package/types/fluixi.d.ts +5 -0
  253. package/types/vinxi.d.ts +50 -0
@@ -0,0 +1,135 @@
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
+ * The choice lives in a cookie by default, so the server render reads it and sends
8
+ * `<html data-theme>` already set: no flash and no mismatch for a returning visitor.
9
+ */
10
+ import { getActiveHead, useHead } from '@fluixi/head';
11
+ import { createSignal } from '@fluixi/reactive/signal';
12
+ import { StorageUnavailableError } from '@fluixi/storage';
13
+ import { env } from '../env/index.js';
14
+ import { persisted } from '../storage/persisted.js';
15
+ import { useStorage } from '../storage/index.js';
16
+ function systemMap(system) {
17
+ if (!system)
18
+ return null;
19
+ if (system === true)
20
+ return { dark: 'dark', light: 'light' };
21
+ return system;
22
+ }
23
+ const YEAR = 60 * 60 * 24 * 365;
24
+ /** @internal: a cookie for a year, or memory outside a request on the server. */
25
+ export function defaultStorage() {
26
+ try {
27
+ return useStorage({ scope: 'cookie', cookie: { maxAge: YEAR, sameSite: 'lax' } });
28
+ }
29
+ catch (error) {
30
+ if (error instanceof StorageUnavailableError)
31
+ return null;
32
+ throw error;
33
+ }
34
+ }
35
+ /** How the head script finds the stored choice before any module has loaded. */
36
+ /** @internal */
37
+ export function storedLookup(storage, key) {
38
+ if (!storage)
39
+ return null;
40
+ const full = storage.keyPrefix + key;
41
+ if (storage.scope === 'cookie') {
42
+ return { from: 'cookie', name: encodeURIComponent(full).replace(/[()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`) };
43
+ }
44
+ if (storage.scope === 'local')
45
+ return { from: 'local', name: full };
46
+ return null;
47
+ }
48
+ /**
49
+ * A theme controller: a reactive current theme, written to an attribute on the document.
50
+ *
51
+ * The initial value is taken from storage, then from the system preference, then from
52
+ * `options.default`, so a returning visitor keeps their choice and a new one gets what
53
+ * their OS asked for. The attribute defaults to `data-theme`, which is what a CSS
54
+ * `[data-theme="dark"]` block selects on.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const theme = createTheme({ themes: ['light', 'dark'], system: { dark: 'dark' } });
59
+ * theme.set('dark');
60
+ * theme.value(); // 'dark', and the document now carries data-theme="dark"
61
+ * ```
62
+ */
63
+ export function createTheme(options) {
64
+ const storageKey = options.storageKey ?? 'theme';
65
+ const attribute = options.attribute ?? 'data-theme';
66
+ const sys = systemMap(options.system);
67
+ const storage = options.storage === undefined ? defaultStorage() : options.storage;
68
+ const valid = (t) => typeof t === 'string' && options.themes.includes(t);
69
+ // Without a stored choice: the system preference where there is one to ask, else the default.
70
+ const fallback = sys && env.window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches ? sys.dark : sys ? sys.light : options.default;
71
+ const stored = storage ? persisted(storage, storageKey) : null;
72
+ // Holds a choice the storage refused (a cookie after the response went out), so the page still switches.
73
+ const [unsaved, setUnsaved] = createSignal(null);
74
+ const value = () => {
75
+ const local = unsaved();
76
+ if (local !== null)
77
+ return local;
78
+ const saved = stored?.();
79
+ return valid(saved) ? saved : fallback;
80
+ };
81
+ const [isLoading, setLoading] = createSignal(false);
82
+ const apply = (t) => {
83
+ env.document?.documentElement.setAttribute(attribute, t);
84
+ };
85
+ const set = (t) => {
86
+ if (!options.themes.includes(t))
87
+ return;
88
+ const prev = value();
89
+ try {
90
+ stored?.set(t);
91
+ setUnsaved(stored ? null : t);
92
+ }
93
+ catch {
94
+ setUnsaved(() => t);
95
+ }
96
+ apply(t);
97
+ options.onChange?.(t, prev);
98
+ if (options.load) {
99
+ setLoading(true);
100
+ options.onLoading?.(t);
101
+ Promise.resolve(options.load(t)).finally(() => {
102
+ setLoading(false);
103
+ options.onLoaded?.(t);
104
+ });
105
+ }
106
+ };
107
+ const toggle = () => {
108
+ const i = options.themes.indexOf(value());
109
+ set(options.themes[(i + 1) % options.themes.length]);
110
+ };
111
+ const init = () => apply(value());
112
+ const scriptBody = () => {
113
+ const cfg = JSON.stringify({ s: storedLookup(storage, storageKey), a: attribute, d: options.default, sys, ts: options.themes }).replace(/</g, '\\u003c');
114
+ // Runs before paint: read the stored choice (or the system preference) and set the
115
+ // attribute, for pages the server did not render with it. Stored values are envelopes.
116
+ return (`(function(){try{var c=${cfg},t=null,s=c.s,r=null;` +
117
+ `if(s&&s.from==='local')r=localStorage.getItem(s.name);` +
118
+ `if(s&&s.from==='cookie')document.cookie.split('; ').forEach(function(p){var i=p.indexOf('=');if(p.slice(0,i)===s.name)r=decodeURIComponent(p.slice(i+1));});` +
119
+ `if(r){var e=JSON.parse(r);t=e&&e.v===1?e.value:e;}` +
120
+ `if(c.ts.indexOf(t)<0)t=null;` +
121
+ `if(!t&&c.sys)t=matchMedia('(prefers-color-scheme: dark)').matches?c.sys.dark:c.sys.light;` +
122
+ `if(!t)t=c.d;document.documentElement.setAttribute(c.a,t);}catch(e){}})();`);
123
+ };
124
+ const headScript = () => `<script>${scriptBody()}</script>`;
125
+ // During a render the attribute goes out with the page; on the client the head keeps it current.
126
+ // A prerendered page, or a first visit before any choice, has nothing the server could know;
127
+ // the script settles it before paint, from the same configuration.
128
+ if (getActiveHead()) {
129
+ useHead({
130
+ htmlAttrs: { [attribute]: () => value() },
131
+ ...(options.script === false ? {} : { script: [{ children: scriptBody() }] }),
132
+ });
133
+ }
134
+ return { value, isLoading, set, toggle, init, headScript };
135
+ }
@@ -0,0 +1,251 @@
1
+ // src/lib/theme/index.ts
2
+ import { getActiveHead, useHead } from "@fluixi/head";
3
+ import { createSignal } from "@fluixi/reactive/signal";
4
+ import { StorageUnavailableError as StorageUnavailableError2 } from "@fluixi/storage";
5
+
6
+ // src/lib/env/index.ts
7
+ import { isServer } from "@fluixi/dom";
8
+ import { isServer as onServer } from "@fluixi/dom";
9
+ var env = {
10
+ get window() {
11
+ return typeof window !== "undefined" ? window : void 0;
12
+ },
13
+ get document() {
14
+ return typeof document !== "undefined" ? document : void 0;
15
+ }
16
+ };
17
+
18
+ // src/lib/storage/persisted.ts
19
+ import { getOwner, onCleanup, signal, untrack } from "@fluixi/reactive/signal";
20
+ var isAsync = (storage) => "encryption" in storage;
21
+ function persisted(storage, key, options = {}) {
22
+ const fallback = options.fallback ?? null;
23
+ const name = options.name ?? `storage:${storage.keyPrefix}${key}`;
24
+ const state = signal(isAsync(storage) ? fallback : storage.get(key) ?? fallback, { name });
25
+ const put = (value) => state.set(() => value);
26
+ const resolve = (next) => typeof next === "function" ? next(untrack(state)) : next;
27
+ const writeOptions = (extra) => ({
28
+ ...options.ttl !== void 0 ? { ttl: options.ttl } : {},
29
+ ...options.encrypt ? { encrypt: true } : {},
30
+ ...extra
31
+ });
32
+ if (!isAsync(storage)) {
33
+ const off2 = storage.subscribe(key, (event) => {
34
+ if (event.type !== "set") return put(fallback);
35
+ if (event.value !== void 0) put(event.value);
36
+ });
37
+ if (getOwner()) onCleanup(off2);
38
+ return Object.assign(() => state(), {
39
+ set(next, extra) {
40
+ const value = resolve(next);
41
+ storage.set(key, value, writeOptions(extra));
42
+ put(value);
43
+ },
44
+ remove() {
45
+ storage.remove(key);
46
+ put(fallback);
47
+ }
48
+ });
49
+ }
50
+ let written = false;
51
+ const reread = () => storage.get(key).then(
52
+ (value) => put(value ?? fallback),
53
+ () => void 0
54
+ );
55
+ const off = storage.subscribe(key, (event) => {
56
+ if (event.type !== "set") return put(fallback);
57
+ if (event.value !== void 0) put(event.value);
58
+ else void reread();
59
+ });
60
+ if (getOwner()) onCleanup(off);
61
+ const ready = storage.get(key).then((value) => {
62
+ if (!written) put(value ?? fallback);
63
+ });
64
+ return Object.assign(() => state(), {
65
+ ready,
66
+ async set(next, extra) {
67
+ const previous = untrack(state);
68
+ const value = resolve(next);
69
+ written = true;
70
+ put(value);
71
+ try {
72
+ await storage.set(key, value, writeOptions(extra));
73
+ } catch (error) {
74
+ put(previous);
75
+ throw error;
76
+ }
77
+ },
78
+ async remove() {
79
+ written = true;
80
+ await storage.remove(key);
81
+ put(fallback);
82
+ }
83
+ });
84
+ }
85
+
86
+ // src/lib/storage/index.ts
87
+ import { appendResponseHeader, getRequestContext, getServerData } from "@fluixi/dom";
88
+ import { createContext, useContext } from "@fluixi/reactive/signal";
89
+ import {
90
+ createAsyncStorage,
91
+ createSyncStorage,
92
+ memoryStorage,
93
+ StorageUnavailableError
94
+ } from "@fluixi/storage";
95
+ import { documentCookieAdapter, localStorageAdapter, sessionStorageAdapter } from "@fluixi/storage/browser";
96
+ import { cookieStorage, requestStorage, toStorageRequest } from "@fluixi/storage/server";
97
+ var StorageContext = createContext(void 0, "storage");
98
+ var AsyncStorageContext = createContext(void 0, "asyncStorage");
99
+ var isBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
100
+ var perRequest = /* @__PURE__ */ new WeakMap();
101
+ var perPage = /* @__PURE__ */ new Map();
102
+ function cached(scope, id, make) {
103
+ let adapter = scope.get(id);
104
+ if (!adapter) scope.set(id, adapter = make());
105
+ return adapter;
106
+ }
107
+ function requestRequired(scope) {
108
+ throw new StorageUnavailableError(
109
+ `useStorage({ scope: '${scope}' }) on the server needs a request: call it during a render, a loader or a server function, or provide a storage with <StorageProvider>.`
110
+ );
111
+ }
112
+ function adapterFor(scope, cookie = {}) {
113
+ const ctx = getRequestContext();
114
+ const options = { httpOnly: false, ...cookie };
115
+ switch (scope) {
116
+ case "local":
117
+ return localStorageAdapter();
118
+ case "session":
119
+ return sessionStorageAdapter();
120
+ case "request":
121
+ if (isBrowser()) return cached(perPage, "request", memoryStorage);
122
+ if (!ctx) requestRequired(scope);
123
+ return cached(perRequest.get(ctx) ?? perRequest.set(ctx, /* @__PURE__ */ new Map()).get(ctx), "request", requestStorage);
124
+ case "cookie": {
125
+ const id = `cookie:${JSON.stringify(options)}`;
126
+ if (isBrowser()) {
127
+ const { httpOnly: _ignored, ...browser } = options;
128
+ return cached(perPage, id, () => documentCookieAdapter(browser));
129
+ }
130
+ if (!ctx) requestRequired(scope);
131
+ const raw = ctx.event.request;
132
+ const target = raw && typeof raw === "object" ? raw : void 0;
133
+ return cached(
134
+ perRequest.get(ctx) ?? perRequest.set(ctx, /* @__PURE__ */ new Map()).get(ctx),
135
+ id,
136
+ () => cookieStorage({
137
+ ...options,
138
+ request: raw && typeof raw === "object" && ("headers" in raw || "getHeader" in raw) ? toStorageRequest(raw) : void 0,
139
+ response: {
140
+ appendHeader(name, value) {
141
+ if (!appendResponseHeader(name, value, target)) {
142
+ throw new StorageUnavailableError("The response headers were already sent, so this cookie cannot reach the browser. Write it before the page head goes out: in middleware, a loader, a server function or the render before its first chunk.");
143
+ }
144
+ }
145
+ }
146
+ })
147
+ );
148
+ }
149
+ }
150
+ }
151
+ function useStorage(options = {}) {
152
+ const { scope = "auto", cookie, ...storageOptions } = options;
153
+ if (scope === "auto") {
154
+ const provided = useContext(StorageContext);
155
+ if (provided) return options.namespace ? provided.namespace(options.namespace) : provided;
156
+ }
157
+ return createSyncStorage({ ...storageOptions, adapter: resolveAdapter(scope, cookie) });
158
+ }
159
+ function resolveAdapter(scope, cookie) {
160
+ if (scope !== "auto") return adapterFor(scope, cookie);
161
+ if (isBrowser()) return adapterFor("local");
162
+ if (!getRequestContext()) requestRequired(scope);
163
+ return adapterFor("request");
164
+ }
165
+
166
+ // src/lib/theme/index.ts
167
+ function systemMap(system) {
168
+ if (!system) return null;
169
+ if (system === true) return { dark: "dark", light: "light" };
170
+ return system;
171
+ }
172
+ var YEAR = 60 * 60 * 24 * 365;
173
+ function defaultStorage() {
174
+ try {
175
+ return useStorage({ scope: "cookie", cookie: { maxAge: YEAR, sameSite: "lax" } });
176
+ } catch (error) {
177
+ if (error instanceof StorageUnavailableError2) return null;
178
+ throw error;
179
+ }
180
+ }
181
+ function storedLookup(storage, key) {
182
+ if (!storage) return null;
183
+ const full = storage.keyPrefix + key;
184
+ if (storage.scope === "cookie") {
185
+ return { from: "cookie", name: encodeURIComponent(full).replace(/[()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`) };
186
+ }
187
+ if (storage.scope === "local") return { from: "local", name: full };
188
+ return null;
189
+ }
190
+ function createTheme(options) {
191
+ const storageKey = options.storageKey ?? "theme";
192
+ const attribute = options.attribute ?? "data-theme";
193
+ const sys = systemMap(options.system);
194
+ const storage = options.storage === void 0 ? defaultStorage() : options.storage;
195
+ const valid = (t) => typeof t === "string" && options.themes.includes(t);
196
+ const fallback = sys && env.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches ? sys.dark : sys ? sys.light : options.default;
197
+ const stored = storage ? persisted(storage, storageKey) : null;
198
+ const [unsaved, setUnsaved] = createSignal(null);
199
+ const value = () => {
200
+ const local = unsaved();
201
+ if (local !== null) return local;
202
+ const saved = stored?.();
203
+ return valid(saved) ? saved : fallback;
204
+ };
205
+ const [isLoading, setLoading] = createSignal(false);
206
+ const apply = (t) => {
207
+ env.document?.documentElement.setAttribute(attribute, t);
208
+ };
209
+ const set = (t) => {
210
+ if (!options.themes.includes(t)) return;
211
+ const prev = value();
212
+ try {
213
+ stored?.set(t);
214
+ setUnsaved(stored ? null : t);
215
+ } catch {
216
+ setUnsaved(() => t);
217
+ }
218
+ apply(t);
219
+ options.onChange?.(t, prev);
220
+ if (options.load) {
221
+ setLoading(true);
222
+ options.onLoading?.(t);
223
+ Promise.resolve(options.load(t)).finally(() => {
224
+ setLoading(false);
225
+ options.onLoaded?.(t);
226
+ });
227
+ }
228
+ };
229
+ const toggle = () => {
230
+ const i = options.themes.indexOf(value());
231
+ set(options.themes[(i + 1) % options.themes.length]);
232
+ };
233
+ const init = () => apply(value());
234
+ const scriptBody = () => {
235
+ const cfg = JSON.stringify({ s: storedLookup(storage, storageKey), a: attribute, d: options.default, sys, ts: options.themes }).replace(/</g, "\\u003c");
236
+ return `(function(){try{var c=${cfg},t=null,s=c.s,r=null;if(s&&s.from==='local')r=localStorage.getItem(s.name);if(s&&s.from==='cookie')document.cookie.split('; ').forEach(function(p){var i=p.indexOf('=');if(p.slice(0,i)===s.name)r=decodeURIComponent(p.slice(i+1));});if(r){var e=JSON.parse(r);t=e&&e.v===1?e.value:e;}if(c.ts.indexOf(t)<0)t=null;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){}})();`;
237
+ };
238
+ const headScript = () => `<script>${scriptBody()}<\/script>`;
239
+ if (getActiveHead()) {
240
+ useHead({
241
+ htmlAttrs: { [attribute]: () => value() },
242
+ ...options.script === false ? {} : { script: [{ children: scriptBody() }] }
243
+ });
244
+ }
245
+ return { value, isLoading, set, toggle, init, headScript };
246
+ }
247
+ export {
248
+ createTheme,
249
+ defaultStorage,
250
+ storedLookup
251
+ };