@fluixi/core 1.0.0-alpha.92 → 1.0.0-alpha.93

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 (113) hide show
  1. package/dist/cdn/core.global.js +2 -2
  2. package/dist/src/cdn/{chunk-MDJLC3PE.mjs → chunk-7XM7Q5VR.mjs} +271 -229
  3. package/dist/src/cdn/core.cjs +360 -253
  4. package/dist/src/cdn/core.mjs +92 -20
  5. package/dist/src/cdn/{router-JYFZP3EZ.mjs → router-VOY43YNM.mjs} +7 -3
  6. package/dist/src/index.cjs +547 -232
  7. package/dist/src/index.mjs +547 -223
  8. package/dist/src/lib/client/chunk-QT3RFKH6.mjs +53 -0
  9. package/dist/src/lib/client/index.cjs +310 -176
  10. package/dist/src/lib/client/index.d.ts.map +1 -1
  11. package/dist/src/lib/client/index.js +33 -18
  12. package/dist/src/lib/client/index.mjs +86 -15
  13. package/dist/src/lib/client/{router-PHLUYVQU.mjs → router-ADTS55OP.mjs} +244 -99
  14. package/dist/src/lib/context/context.cjs +35 -72
  15. package/dist/src/lib/context/context.d.ts +45 -291
  16. package/dist/src/lib/context/context.d.ts.map +1 -1
  17. package/dist/src/lib/context/context.js +65 -397
  18. package/dist/src/lib/context/context.mjs +38 -73
  19. package/dist/src/lib/context/index.cjs +35 -72
  20. package/dist/src/lib/context/index.d.ts +2 -2
  21. package/dist/src/lib/context/index.d.ts.map +1 -1
  22. package/dist/src/lib/context/index.js +1 -5
  23. package/dist/src/lib/context/index.mjs +38 -73
  24. package/dist/src/lib/core.cjs +546 -231
  25. package/dist/src/lib/core.d.ts +3 -1
  26. package/dist/src/lib/core.d.ts.map +1 -1
  27. package/dist/src/lib/core.js +5 -3
  28. package/dist/src/lib/core.mjs +546 -222
  29. package/dist/src/lib/env/index.cjs +1 -17
  30. package/dist/src/lib/env/index.d.ts +2 -14
  31. package/dist/src/lib/env/index.d.ts.map +1 -1
  32. package/dist/src/lib/env/index.js +2 -26
  33. package/dist/src/lib/env/index.mjs +1 -17
  34. package/dist/src/lib/i18n/index.cjs +17 -2
  35. package/dist/src/lib/i18n/index.d.ts +10 -0
  36. package/dist/src/lib/i18n/index.d.ts.map +1 -1
  37. package/dist/src/lib/i18n/index.js +17 -1
  38. package/dist/src/lib/i18n/index.mjs +17 -2
  39. package/dist/src/lib/index.cjs +64 -99
  40. package/dist/src/lib/index.mjs +43 -76
  41. package/dist/src/lib/isomorphic.cjs +9 -4
  42. package/dist/src/lib/isomorphic.d.ts +9 -2
  43. package/dist/src/lib/isomorphic.d.ts.map +1 -1
  44. package/dist/src/lib/isomorphic.js +11 -4
  45. package/dist/src/lib/isomorphic.mjs +9 -4
  46. package/dist/src/lib/jsx-runtime/index.cjs +1 -1
  47. package/dist/src/lib/jsx-runtime/index.mjs +1 -1
  48. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -1
  49. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -1
  50. package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +2 -2
  51. package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +2 -2
  52. package/dist/src/lib/plugins/index.cjs +3 -3
  53. package/dist/src/lib/plugins/index.mjs +3 -3
  54. package/dist/src/lib/plugins/route-codegen.cjs +2 -2
  55. package/dist/src/lib/plugins/route-codegen.js +1 -1
  56. package/dist/src/lib/plugins/route-codegen.mjs +2 -2
  57. package/dist/src/lib/render/index.cjs +1 -1
  58. package/dist/src/lib/render/index.mjs +1 -1
  59. package/dist/src/lib/render/versions.cjs +1 -1
  60. package/dist/src/lib/render/versions.mjs +1 -1
  61. package/dist/src/lib/router/data.cjs +113 -115
  62. package/dist/src/lib/router/data.d.ts +63 -10
  63. package/dist/src/lib/router/data.d.ts.map +1 -1
  64. package/dist/src/lib/router/data.js +158 -68
  65. package/dist/src/lib/router/data.mjs +112 -112
  66. package/dist/src/lib/router/index.cjs +260 -163
  67. package/dist/src/lib/router/index.d.ts +22 -2
  68. package/dist/src/lib/router/index.d.ts.map +1 -1
  69. package/dist/src/lib/router/index.js +165 -22
  70. package/dist/src/lib/router/index.mjs +244 -143
  71. package/dist/src/lib/server/index.cjs +1 -1
  72. package/dist/src/lib/server/index.mjs +1 -1
  73. package/dist/src/lib/storage/cache.cjs +51 -0
  74. package/dist/src/lib/storage/cache.d.ts +18 -0
  75. package/dist/src/lib/storage/cache.d.ts.map +1 -0
  76. package/dist/src/lib/storage/cache.js +42 -0
  77. package/dist/src/lib/storage/cache.mjs +30 -0
  78. package/dist/src/lib/storage/index.cjs +246 -0
  79. package/dist/src/lib/storage/index.d.ts +83 -0
  80. package/dist/src/lib/storage/index.d.ts.map +1 -0
  81. package/dist/src/lib/storage/index.js +179 -0
  82. package/dist/src/lib/storage/index.mjs +231 -0
  83. package/dist/src/lib/storage/persisted.cjs +91 -0
  84. package/dist/src/lib/storage/persisted.d.ts +53 -0
  85. package/dist/src/lib/storage/persisted.d.ts.map +1 -0
  86. package/dist/src/lib/storage/persisted.js +75 -0
  87. package/dist/src/lib/storage/persisted.mjs +70 -0
  88. package/dist/src/lib/theme/color-scheme.cjs +281 -0
  89. package/dist/src/lib/theme/color-scheme.d.ts +61 -0
  90. package/dist/src/lib/theme/color-scheme.d.ts.map +1 -0
  91. package/dist/src/lib/theme/color-scheme.js +120 -0
  92. package/dist/src/lib/theme/color-scheme.mjs +265 -0
  93. package/dist/src/lib/theme/index.cjs +194 -37
  94. package/dist/src/lib/theme/index.d.ts +23 -11
  95. package/dist/src/lib/theme/index.d.ts.map +1 -1
  96. package/dist/src/lib/theme/index.js +73 -32
  97. package/dist/src/lib/theme/index.mjs +197 -35
  98. package/dist/src/lib/theme/provider.cjs +346 -0
  99. package/dist/src/lib/theme/provider.d.ts +34 -0
  100. package/dist/src/lib/theme/provider.d.ts.map +1 -0
  101. package/dist/src/lib/theme/provider.js +60 -0
  102. package/dist/src/lib/theme/provider.mjs +332 -0
  103. package/dist/src/routes.cjs +1 -1
  104. package/dist/src/routes.mjs +1 -1
  105. package/dist/src/utils.cjs +1 -1
  106. package/dist/src/utils.mjs +1 -1
  107. package/dist/src/version.generated.cjs +1 -1
  108. package/dist/src/version.generated.d.ts +1 -1
  109. package/dist/src/version.generated.js +1 -1
  110. package/dist/src/version.generated.mjs +1 -1
  111. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  112. package/package.json +18 -11
  113. package/dist/src/lib/client/chunk-VB567ABU.mjs +0 -133
@@ -1,26 +1,26 @@
1
- /*! @fluixi/core v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.93 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/version.generated.ts
4
- var VERSION = "1.0.0-alpha.92";
4
+ var VERSION = "1.0.0-alpha.93";
5
5
 
6
6
  // src/lib/core.ts
7
7
  import {
8
- signal,
8
+ signal as signal2,
9
9
  memo,
10
10
  effect,
11
11
  resource,
12
- createEffect as createEffect4,
12
+ createEffect as createEffect5,
13
13
  createMemo as createMemo7,
14
- createSignal as createSignal8,
14
+ createSignal as createSignal9,
15
15
  createResource as createResource6,
16
- createRoot as createRoot3,
16
+ createRoot as createRoot4,
17
17
  createComputed as createComputed2,
18
18
  createRenderEffect as createRenderEffect3,
19
- onCleanup as onCleanup3,
20
- getOwner as getOwner3,
21
- runWithOwner as runWithOwner3,
19
+ onCleanup as onCleanup5,
20
+ getOwner as getOwner6,
21
+ runWithOwner as runWithOwner4,
22
22
  batch as batch2,
23
- untrack as untrack4,
23
+ untrack as untrack5,
24
24
  createDeferred as createDeferred2,
25
25
  setOwner
26
26
  } from "@fluixi/reactive/signal";
@@ -571,84 +571,25 @@ function cleanupDelegation() {
571
571
 
572
572
  // src/lib/context/context.ts
573
573
  import { asProvider } from "@fluixi/dom";
574
- import { createContext as createReactiveContext, useContext as useReactiveContext } from "@fluixi/reactive/signal";
575
574
  import {
576
- readChildren as readChildren2
575
+ createContext as createReactiveContext,
576
+ getOwner as getOwner2,
577
+ useContext as useReactiveContext
577
578
  } from "@fluixi/reactive/signal";
578
- var _warnedEagerProvider = false;
579
- function warnEagerProvider() {
580
- if (_warnedEagerProvider) return;
581
- _warnedEagerProvider = true;
582
- if (typeof process !== "undefined" && true) return;
583
- console.warn(
584
- "[fluixi] createProvider({ context, value, children }) reads `children` eagerly: the object literal materialises `children` BEFORE the context is stamped, so a routed <Outlet/> that has siblings inside the provider renders detached and its descendants see no context under SSR. Use the lazy form instead:\n createProvider(Context, value, props) // children stays a getter\n // or JSX: <Context.Provider value={...}>{props.children}</Context.Provider>"
585
- );
586
- }
587
- function createProvider(a, value, childProps) {
588
- const isLazyForm = !!a?.Provider;
589
- const context = isLazyForm ? a : a.context;
590
- const rawValue = isLazyForm ? value : a.value;
591
- const debug = isLazyForm ? false : a.debug ?? false;
592
- if (!isLazyForm) warnEagerProvider();
593
- const resolvedValue = typeof rawValue === "function" ? rawValue() : rawValue;
594
- const sourceProps = isLazyForm ? childProps : a;
595
- return context.Provider({
596
- value: resolvedValue,
597
- get children() {
598
- return sourceProps?.children;
599
- },
600
- debug
601
- });
602
- }
603
- function createContextWithProvider(defaultValue) {
604
- const context = createContext3(defaultValue);
605
- const provider = (props) => {
606
- return createProvider(context, props.value, props);
607
- };
608
- return [context, provider];
609
- }
610
- function composeProviders(contexts, children) {
611
- if (contexts.length === 0) {
612
- return readChildren2(() => children);
613
- }
614
- const [context, value] = contexts[0];
615
- const remaining = contexts.slice(1);
616
- return createProvider(context, value, {
617
- get children() {
618
- return composeProviders(remaining, children);
619
- }
620
- });
621
- }
622
- function createConsumer(context) {
623
- return (props) => {
624
- const value = useContext3(context);
625
- return props.children(value);
626
- };
627
- }
628
- function useProvide(context, factory) {
629
- const existing = useContext3(context);
630
- if (existing === context.defaultValue) {
631
- return factory();
632
- }
633
- return existing;
634
- }
635
579
  function createContext3(defaultValue, name) {
636
580
  const context = createReactiveContext(defaultValue, name);
637
- const Provider = (props) => {
638
- if (props.debug === true) {
639
- }
640
- return context.Provider({
581
+ const Provider = (props) => (
582
+ // Children stay a getter: the reactive Provider reads them after stamping the value on
583
+ // its owner. Reading `props.children` here would render them, and any <Outlet/> in them,
584
+ // before the context exists.
585
+ context.Provider({
641
586
  value: props.value,
642
587
  get children() {
643
588
  return props.children;
644
589
  },
645
590
  debug: props.debug
646
- });
647
- };
648
- if (typeof Symbol !== "undefined" && Symbol.for) {
649
- Provider.$$typeof = /* @__PURE__ */ Symbol.for("react.provider");
650
- }
651
- Provider.$$typeof = /* @__PURE__ */ Symbol.for("react.provider");
591
+ })
592
+ );
652
593
  return {
653
594
  id: context.id,
654
595
  Provider: asProvider(Provider),
@@ -659,10 +600,38 @@ function useContext3(context) {
659
600
  const value = useReactiveContext(context);
660
601
  return value !== void 0 ? value : context.defaultValue;
661
602
  }
603
+ function createProvider(context, value, props) {
604
+ const resolved = typeof value === "function" ? value() : value;
605
+ return context.Provider({
606
+ value: resolved,
607
+ get children() {
608
+ return props.children;
609
+ }
610
+ });
611
+ }
612
+ function composeProviders(providers, props) {
613
+ const outermost = providers.reduceRight(
614
+ (inner, [context, value]) => ({
615
+ get children() {
616
+ return createProvider(context, value, inner);
617
+ }
618
+ }),
619
+ props
620
+ );
621
+ return outermost.children;
622
+ }
623
+ function requireContext(context, message) {
624
+ for (let owner = getOwner2(); owner; owner = owner.parent) {
625
+ if (owner.contexts?.has(context.id)) return useContext3(context);
626
+ }
627
+ throw new Error(message ?? `[fluixi] No Provider for ${context.id.description ?? "this context"} above this component.`);
628
+ }
662
629
 
663
630
  // src/lib/isomorphic.ts
664
631
  import { createSignal as createSignal4, createMemo as createMemo5 } from "@fluixi/reactive/signal";
665
632
  import { getServerData } from "@fluixi/dom";
633
+ import { createSyncStorage } from "@fluixi/storage";
634
+ import { localStorageAdapter } from "@fluixi/storage/browser";
666
635
  var REGISTRY_KEY = "__fluixi_iso_states__";
667
636
  var SEED_PREFIX = "__iso:";
668
637
  function registry() {
@@ -676,7 +645,7 @@ function readSeed(key) {
676
645
  function createIsomorphicState(key, options) {
677
646
  const seed = readSeed(key);
678
647
  const initial = seed !== void 0 ? seed : typeof window !== "undefined" && options.client ? options.client() : options.fallback;
679
- const [value, set] = createSignal4(initial);
648
+ const [value, set] = createSignal4(initial, { name: key });
680
649
  registry().set(key, { server: options.server, set });
681
650
  return { value, set, key };
682
651
  }
@@ -688,9 +657,12 @@ function createIsomorphicStore(key, options) {
688
657
  });
689
658
  const value = () => base.value() ?? options.fallback;
690
659
  const persistWrite = (v) => {
691
- if (!options.persist || typeof localStorage === "undefined") return;
660
+ const target = options.persist;
661
+ if (!target) return;
662
+ if (typeof target === "string" && typeof window === "undefined") return;
692
663
  try {
693
- localStorage.setItem(options.persist, JSON.stringify(v));
664
+ const { storage, key: key2 } = typeof target === "string" ? { storage: createSyncStorage({ adapter: localStorageAdapter() }), key: target } : target;
665
+ storage.set(key2, v);
694
666
  } catch {
695
667
  }
696
668
  };
@@ -703,7 +675,7 @@ function createIsomorphicStore(key, options) {
703
675
  };
704
676
  const fields = {};
705
677
  for (const k of Object.keys(options.fallback)) {
706
- fields[k] = createMemo5(() => value()[k]);
678
+ fields[k] = createMemo5(() => value()[k], void 0, { name: `${key}.${String(k)}` });
707
679
  }
708
680
  let initPromise = null;
709
681
  const ensureInit = () => {
@@ -727,20 +699,6 @@ import { isServer as onServer } from "@fluixi/dom";
727
699
  function isClient() {
728
700
  return !onServer();
729
701
  }
730
- function createMemoryStorage() {
731
- const mem = /* @__PURE__ */ new Map();
732
- return {
733
- getItem: (k) => mem.has(k) ? mem.get(k) : null,
734
- setItem: (k, v) => void mem.set(k, String(v)),
735
- removeItem: (k) => void mem.delete(k),
736
- clear: () => mem.clear(),
737
- key: (i) => Array.from(mem.keys())[i] ?? null,
738
- get length() {
739
- return mem.size;
740
- }
741
- };
742
- }
743
- var storage = typeof localStorage !== "undefined" ? localStorage : createMemoryStorage();
744
702
  var env = {
745
703
  get window() {
746
704
  return typeof window !== "undefined" ? window : void 0;
@@ -754,36 +712,210 @@ function clientOnly(fn, fallback) {
754
712
  }
755
713
 
756
714
  // src/lib/theme/index.ts
715
+ import { getActiveHead, useHead } from "@fluixi/head";
757
716
  import { createSignal as createSignal5 } from "@fluixi/reactive/signal";
717
+ import { StorageUnavailableError as StorageUnavailableError2 } from "@fluixi/storage";
718
+
719
+ // src/lib/storage/persisted.ts
720
+ import { getOwner as getOwner3, onCleanup as onCleanup2, signal, untrack as untrack3 } from "@fluixi/reactive/signal";
721
+ var isAsync = (storage) => "encryption" in storage;
722
+ function persisted(storage, key, options = {}) {
723
+ const fallback = options.fallback ?? null;
724
+ const name = options.name ?? `storage:${storage.keyPrefix}${key}`;
725
+ const state = signal(isAsync(storage) ? fallback : storage.get(key) ?? fallback, { name });
726
+ const put = (value) => state.set(() => value);
727
+ const resolve = (next) => typeof next === "function" ? next(untrack3(state)) : next;
728
+ const writeOptions = (extra) => ({
729
+ ...options.ttl !== void 0 ? { ttl: options.ttl } : {},
730
+ ...options.encrypt ? { encrypt: true } : {},
731
+ ...extra
732
+ });
733
+ if (!isAsync(storage)) {
734
+ const off2 = storage.subscribe(key, (event) => {
735
+ if (event.type !== "set") return put(fallback);
736
+ if (event.value !== void 0) put(event.value);
737
+ });
738
+ if (getOwner3()) onCleanup2(off2);
739
+ return Object.assign(() => state(), {
740
+ set(next, extra) {
741
+ const value = resolve(next);
742
+ storage.set(key, value, writeOptions(extra));
743
+ put(value);
744
+ },
745
+ remove() {
746
+ storage.remove(key);
747
+ put(fallback);
748
+ }
749
+ });
750
+ }
751
+ let written = false;
752
+ const reread = () => storage.get(key).then(
753
+ (value) => put(value ?? fallback),
754
+ () => void 0
755
+ );
756
+ const off = storage.subscribe(key, (event) => {
757
+ if (event.type !== "set") return put(fallback);
758
+ if (event.value !== void 0) put(event.value);
759
+ else void reread();
760
+ });
761
+ if (getOwner3()) onCleanup2(off);
762
+ const ready = storage.get(key).then((value) => {
763
+ if (!written) put(value ?? fallback);
764
+ });
765
+ return Object.assign(() => state(), {
766
+ ready,
767
+ async set(next, extra) {
768
+ const previous = untrack3(state);
769
+ const value = resolve(next);
770
+ written = true;
771
+ put(value);
772
+ try {
773
+ await storage.set(key, value, writeOptions(extra));
774
+ } catch (error) {
775
+ put(previous);
776
+ throw error;
777
+ }
778
+ },
779
+ async remove() {
780
+ written = true;
781
+ await storage.remove(key);
782
+ put(fallback);
783
+ }
784
+ });
785
+ }
786
+
787
+ // src/lib/storage/index.ts
788
+ import { appendResponseHeader, getRequestContext, getServerData as getServerData2 } from "@fluixi/dom";
789
+ import { createContext as createContext4, useContext as useContext4 } from "@fluixi/reactive/signal";
790
+ import {
791
+ createAsyncStorage,
792
+ createSyncStorage as createSyncStorage2,
793
+ memoryStorage,
794
+ StorageUnavailableError
795
+ } from "@fluixi/storage";
796
+ import { documentCookieAdapter, localStorageAdapter as localStorageAdapter2, sessionStorageAdapter } from "@fluixi/storage/browser";
797
+ import { cookieStorage, requestStorage, toStorageRequest } from "@fluixi/storage/server";
798
+ var StorageContext = createContext4(void 0, "storage");
799
+ var AsyncStorageContext = createContext4(void 0, "asyncStorage");
800
+ var isBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
801
+ var perRequest = /* @__PURE__ */ new WeakMap();
802
+ var perPage = /* @__PURE__ */ new Map();
803
+ function cached(scope, id, make) {
804
+ let adapter = scope.get(id);
805
+ if (!adapter) scope.set(id, adapter = make());
806
+ return adapter;
807
+ }
808
+ function requestRequired(scope) {
809
+ throw new StorageUnavailableError(
810
+ `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>.`
811
+ );
812
+ }
813
+ function adapterFor(scope, cookie = {}) {
814
+ const ctx = getRequestContext();
815
+ const options = { httpOnly: false, ...cookie };
816
+ switch (scope) {
817
+ case "local":
818
+ return localStorageAdapter2();
819
+ case "session":
820
+ return sessionStorageAdapter();
821
+ case "request":
822
+ if (isBrowser()) return cached(perPage, "request", memoryStorage);
823
+ if (!ctx) requestRequired(scope);
824
+ return cached(perRequest.get(ctx) ?? perRequest.set(ctx, /* @__PURE__ */ new Map()).get(ctx), "request", requestStorage);
825
+ case "cookie": {
826
+ const id = `cookie:${JSON.stringify(options)}`;
827
+ if (isBrowser()) {
828
+ const { httpOnly: _ignored, ...browser } = options;
829
+ return cached(perPage, id, () => documentCookieAdapter(browser));
830
+ }
831
+ if (!ctx) requestRequired(scope);
832
+ const raw = ctx.event.request;
833
+ const target = raw && typeof raw === "object" ? raw : void 0;
834
+ return cached(
835
+ perRequest.get(ctx) ?? perRequest.set(ctx, /* @__PURE__ */ new Map()).get(ctx),
836
+ id,
837
+ () => cookieStorage({
838
+ ...options,
839
+ request: raw && typeof raw === "object" && ("headers" in raw || "getHeader" in raw) ? toStorageRequest(raw) : void 0,
840
+ response: {
841
+ appendHeader(name, value) {
842
+ if (!appendResponseHeader(name, value, target)) {
843
+ 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.");
844
+ }
845
+ }
846
+ }
847
+ })
848
+ );
849
+ }
850
+ }
851
+ }
852
+ function useStorage(options = {}) {
853
+ const { scope = "auto", cookie, ...storageOptions } = options;
854
+ if (scope === "auto") {
855
+ const provided = useContext4(StorageContext);
856
+ if (provided) return options.namespace ? provided.namespace(options.namespace) : provided;
857
+ }
858
+ return createSyncStorage2({ ...storageOptions, adapter: resolveAdapter(scope, cookie) });
859
+ }
860
+ function resolveAdapter(scope, cookie) {
861
+ if (scope !== "auto") return adapterFor(scope, cookie);
862
+ if (isBrowser()) return adapterFor("local");
863
+ if (!getRequestContext()) requestRequired(scope);
864
+ return adapterFor("request");
865
+ }
866
+
867
+ // src/lib/theme/index.ts
758
868
  function systemMap(system) {
759
869
  if (!system) return null;
760
870
  if (system === true) return { dark: "dark", light: "light" };
761
871
  return system;
762
872
  }
873
+ var YEAR = 60 * 60 * 24 * 365;
874
+ function defaultStorage() {
875
+ try {
876
+ return useStorage({ scope: "cookie", cookie: { maxAge: YEAR, sameSite: "lax" } });
877
+ } catch (error) {
878
+ if (error instanceof StorageUnavailableError2) return null;
879
+ throw error;
880
+ }
881
+ }
882
+ function storedLookup(storage, key) {
883
+ if (!storage) return null;
884
+ const full = storage.keyPrefix + key;
885
+ if (storage.scope === "cookie") {
886
+ return { from: "cookie", name: encodeURIComponent(full).replace(/[()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`) };
887
+ }
888
+ if (storage.scope === "local") return { from: "local", name: full };
889
+ return null;
890
+ }
763
891
  function createTheme(options) {
764
892
  const storageKey = options.storageKey ?? "theme";
765
893
  const attribute = options.attribute ?? "data-theme";
766
894
  const sys = systemMap(options.system);
767
- const detectInitial = () => {
768
- const stored = storage.getItem(storageKey);
769
- if (stored && options.themes.includes(stored)) return stored;
770
- if (sys && env.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches) return sys.dark;
771
- if (sys) return sys.light;
772
- return options.default;
895
+ const storage = options.storage === void 0 ? defaultStorage() : options.storage;
896
+ const valid = (t) => typeof t === "string" && options.themes.includes(t);
897
+ const fallback = sys && env.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches ? sys.dark : sys ? sys.light : options.default;
898
+ const stored = storage ? persisted(storage, storageKey) : null;
899
+ const [unsaved, setUnsaved] = createSignal5(null);
900
+ const value = () => {
901
+ const local = unsaved();
902
+ if (local !== null) return local;
903
+ const saved = stored?.();
904
+ return valid(saved) ? saved : fallback;
773
905
  };
774
- const [value, setValue] = createSignal5(detectInitial());
775
906
  const [isLoading, setLoading] = createSignal5(false);
776
907
  const apply = (t) => {
777
908
  env.document?.documentElement.setAttribute(attribute, t);
778
- try {
779
- storage.setItem(storageKey, t);
780
- } catch {
781
- }
782
909
  };
783
910
  const set = (t) => {
784
911
  if (!options.themes.includes(t)) return;
785
912
  const prev = value();
786
- setValue(() => t);
913
+ try {
914
+ stored?.set(t);
915
+ setUnsaved(stored ? null : t);
916
+ } catch {
917
+ setUnsaved(() => t);
918
+ }
787
919
  apply(t);
788
920
  options.onChange?.(t, prev);
789
921
  if (options.load) {
@@ -800,27 +932,139 @@ function createTheme(options) {
800
932
  set(options.themes[(i + 1) % options.themes.length]);
801
933
  };
802
934
  const init = () => apply(value());
803
- const headScript = () => {
804
- const cfg = JSON.stringify({
805
- k: storageKey,
806
- a: attribute,
807
- d: options.default,
808
- sys
809
- });
810
- return `<script>(function(){try{var c=${cfg},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>`;
935
+ const scriptBody = () => {
936
+ const cfg = JSON.stringify({ s: storedLookup(storage, storageKey), a: attribute, d: options.default, sys, ts: options.themes }).replace(/</g, "\\u003c");
937
+ 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){}})();`;
811
938
  };
939
+ const headScript = () => `<script>${scriptBody()}<\/script>`;
940
+ if (getActiveHead()) {
941
+ useHead({
942
+ htmlAttrs: { [attribute]: () => value() },
943
+ ...options.script === false ? {} : { script: [{ children: scriptBody() }] }
944
+ });
945
+ }
812
946
  return { value, isLoading, set, toggle, init, headScript };
813
947
  }
814
948
 
949
+ // src/lib/theme/color-scheme.ts
950
+ import { getActiveHead as getActiveHead2, useHead as useHead2 } from "@fluixi/head";
951
+ import { createEffect as createEffect3, createSignal as createSignal6, getOwner as getOwner4, onCleanup as onCleanup3 } from "@fluixi/reactive/signal";
952
+ var CHOICES = ["system", "light", "dark"];
953
+ var DARK = "(prefers-color-scheme: dark)";
954
+ function createColorScheme(options = {}) {
955
+ const storageKey = options.storageKey ?? "color-scheme";
956
+ const attribute = options.attribute ?? "data-theme";
957
+ const systemAs = options.systemAs ?? "resolved";
958
+ const storage = options.storage === void 0 ? defaultStorage() : options.storage;
959
+ const saved = storage ? persisted(storage, storageKey) : null;
960
+ const [unsaved, setUnsaved] = createSignal6(null);
961
+ const value = () => {
962
+ const local = unsaved();
963
+ if (local) return local;
964
+ const stored = saved?.();
965
+ return CHOICES.includes(stored) ? stored : "system";
966
+ };
967
+ const media = env.window?.matchMedia?.(DARK);
968
+ const [osDark, setOsDark] = createSignal6(media?.matches ?? false);
969
+ if (media) {
970
+ const onChange = () => setOsDark(media.matches);
971
+ media.addEventListener?.("change", onChange);
972
+ if (getOwner4()) onCleanup3(() => media.removeEventListener?.("change", onChange));
973
+ }
974
+ const resolved = () => {
975
+ const choice = value();
976
+ return choice === "system" ? osDark() ? "dark" : "light" : choice;
977
+ };
978
+ const shown = () => systemAs === "system" && value() === "system" ? "system" : resolved();
979
+ const apply = () => {
980
+ env.document?.documentElement.setAttribute(attribute, shown());
981
+ };
982
+ const set = (choice) => {
983
+ if (!CHOICES.includes(choice)) return;
984
+ if (!saved) setUnsaved(choice);
985
+ else {
986
+ try {
987
+ saved.set(choice);
988
+ setUnsaved(null);
989
+ } catch {
990
+ setUnsaved(choice);
991
+ }
992
+ }
993
+ apply();
994
+ options.onChange?.(choice);
995
+ };
996
+ const scriptBody = () => {
997
+ const cfg = JSON.stringify({ s: storedLookup(storage, storageKey), a: attribute, sys: systemAs === "system", tc: options.themeColor ?? null, cs: options.colorSchemeMeta !== false }).replace(/</g, "\\u003c");
998
+ 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;}var chosen=t==='light'||t==='dark'?t:null;if(!chosen)t=c.sys?'system':(matchMedia('${DARK}').matches?'dark':'light');document.documentElement.setAttribute(c.a,t);if(chosen&&c.tc)document.querySelectorAll('meta[name="theme-color"]').forEach(function(m){m.setAttribute('content',c.tc[chosen]);m.removeAttribute('media');});if(chosen&&c.cs){var m=document.querySelector('meta[name="color-scheme"]');if(m)m.setAttribute('content',chosen);}}catch(e){}})();`;
999
+ };
1000
+ if (getActiveHead2()) {
1001
+ const colors = options.themeColor;
1002
+ useHead2({
1003
+ htmlAttrs: { [attribute]: shown },
1004
+ ...colors ? {
1005
+ themeColor: () => value() === "system" ? [
1006
+ { color: colors.light, media: "(prefers-color-scheme: light)" },
1007
+ { color: colors.dark, media: DARK }
1008
+ ] : colors[resolved()]
1009
+ } : {},
1010
+ ...options.colorSchemeMeta === false ? {} : { colorScheme: () => value() === "system" ? "light dark" : resolved() },
1011
+ ...options.script === false ? {} : { script: [{ children: scriptBody() }] }
1012
+ });
1013
+ }
1014
+ if (env.document && getOwner4()) createEffect3(apply);
1015
+ return {
1016
+ value,
1017
+ resolved,
1018
+ set,
1019
+ toggle: () => set(resolved() === "dark" ? "light" : "dark"),
1020
+ init: apply,
1021
+ headScript: () => `<script>${scriptBody()}<\/script>`
1022
+ };
1023
+ }
1024
+
1025
+ // src/lib/theme/provider.ts
1026
+ var ThemesContext = createContext3(void 0, "themes");
1027
+ function ThemeProvider(props) {
1028
+ const outer = useContext3(ThemesContext);
1029
+ return ThemesContext.Provider({
1030
+ // A nested provider adds to the axes above it rather than hiding them.
1031
+ value: outer ? { ...outer, ...props.themes } : props.themes,
1032
+ get children() {
1033
+ return props.children;
1034
+ }
1035
+ });
1036
+ }
1037
+ function useTheme(name) {
1038
+ const themes = useContext3(ThemesContext);
1039
+ if (!themes || !(name in themes)) {
1040
+ throw new Error(`[fluixi] No theme named "${name}" above this component: provide it with <ThemeProvider> or <ColorSchemeProvider>.`);
1041
+ }
1042
+ return themes[name];
1043
+ }
1044
+ function ColorSchemeProvider(props) {
1045
+ const scheme = createColorScheme(props);
1046
+ return ThemeProvider({
1047
+ themes: { scheme },
1048
+ get children() {
1049
+ return props.children;
1050
+ }
1051
+ });
1052
+ }
1053
+ function useColorScheme() {
1054
+ return useTheme("scheme");
1055
+ }
1056
+
815
1057
  // src/lib/router/index.ts
816
1058
  import {
817
- createSignal as createSignal7,
1059
+ createSignal as createSignal8,
818
1060
  createMemo as createMemo6,
819
1061
  createResource as createResource5,
820
- createEffect as createEffect3,
821
- getOwner as getOwner2,
822
- onCleanup as onCleanup2,
823
- untrack as untrack3,
1062
+ createEffect as createEffect4,
1063
+ createRoot as createRoot3,
1064
+ getOwner as getOwner5,
1065
+ onCleanup as onCleanup4,
1066
+ runWithOwner as runWithOwner2,
1067
+ untrack as untrack4,
824
1068
  flush
825
1069
  } from "@fluixi/reactive/signal";
826
1070
 
@@ -879,7 +1123,7 @@ import {
879
1123
  createNativeElement,
880
1124
  setAttribute
881
1125
  } from "@fluixi/dom";
882
- import { createContext as createContext4, useContext as useContext4 } from "@fluixi/reactive/signal";
1126
+ import { createContext as createContext5, useContext as useContext5 } from "@fluixi/reactive/signal";
883
1127
  import { get } from "@fluixi/utils/object";
884
1128
  import { deepEqual } from "@fluixi/utils/compare";
885
1129
  import {
@@ -888,80 +1132,99 @@ import {
888
1132
  matchRoutes,
889
1133
  matchPath
890
1134
  } from "@fluixi/router";
891
- import {
892
- createMemoryHistory,
893
- createBrowserHistory as createBrowserHistory2,
894
- matchRoutes as matchRoutes2,
895
- matchPath as matchPath2
896
- } from "@fluixi/router";
897
1135
 
898
1136
  // src/lib/router/data.ts
899
1137
  import {
900
1138
  createResource as createResource4,
901
- createSignal as createSignal6
1139
+ createSignal as createSignal7
902
1140
  } from "@fluixi/reactive/signal";
903
-
904
- // src/lib/server/hydration.ts
905
- import { isServer as domIsServer } from "@fluixi/dom";
906
- var hydrationDataMap = /* @__PURE__ */ new Map();
907
- function clearHydrationData() {
908
- hydrationDataMap.clear();
909
- }
910
- function cleanupHydration() {
911
- if (typeof window === "undefined") {
912
- return;
913
- }
914
- const script = document.getElementById("__FLUIXI_HYDRATION__");
915
- if (script) {
916
- script.remove();
917
- }
918
- const walker = document.createTreeWalker(
919
- document.body,
920
- NodeFilter.SHOW_COMMENT,
921
- null
922
- );
923
- const comments = [];
924
- let node;
925
- while (node = walker.nextNode()) {
926
- const comment = node;
927
- const text = comment.nodeValue || "";
928
- if (text.startsWith("#") || text.startsWith("/")) {
929
- comments.push(comment);
930
- }
1141
+ import { currentResourceCache } from "@fluixi/reactive/signal";
1142
+ var revalidationListeners = /* @__PURE__ */ new Set();
1143
+ function onRevalidate(listener) {
1144
+ revalidationListeners.add(listener);
1145
+ return () => void revalidationListeners.delete(listener);
1146
+ }
1147
+ var reloadMounted = () => {
1148
+ for (const listener of [...revalidationListeners]) listener();
1149
+ };
1150
+ function revalidate(key, store) {
1151
+ const names = typeof key === "string" ? [key] : Array.isArray(key) ? key : null;
1152
+ drop(names ?? key, store ?? currentResourceCache());
1153
+ if (names && !store) tellOtherTabs(names);
1154
+ }
1155
+ function drop(what, store) {
1156
+ const matches = Array.isArray(what) ? (k) => what.some((n) => k === n || k.startsWith(n + ":")) : what;
1157
+ for (const k of [...store.keys()]) if (matches(k)) store.delete(k);
1158
+ reloadMounted();
1159
+ }
1160
+ var TABS_KEY = "fluixi:revalidate";
1161
+ function tellOtherTabs(names) {
1162
+ try {
1163
+ localStorage.setItem(TABS_KEY, JSON.stringify({ names, at: Date.now() + Math.random() }));
1164
+ } catch {
931
1165
  }
932
- comments.forEach((comment) => comment.remove());
933
- clearHydrationData();
934
1166
  }
935
1167
  if (typeof window !== "undefined") {
936
- window.addEventListener("load", () => {
937
- setTimeout(cleanupHydration, 100);
1168
+ window.addEventListener("storage", (event) => {
1169
+ if (event.key !== TABS_KEY || !event.newValue) return;
1170
+ try {
1171
+ const names = JSON.parse(event.newValue).names;
1172
+ if (Array.isArray(names) && names.every((n) => typeof n === "string")) drop(names, currentResourceCache());
1173
+ } catch {
1174
+ }
938
1175
  });
939
1176
  }
940
-
941
- // src/lib/router/data.ts
942
- var [revalidationVersion, setRevalidationVersion] = createSignal6(0);
1177
+ globalThis[/* @__PURE__ */ Symbol.for("fluixi.revalidate")] = (names) => revalidate(names);
943
1178
  var RouteDataContext = createContext3(void 0, "route-data");
944
1179
  var RouteDataProvider = RouteDataContext.Provider;
945
1180
 
946
1181
  // src/lib/router/index.ts
947
- import { runWithOwner as runWithOwner2 } from "@fluixi/reactive/signal";
948
- var RouterContext = createContext4(void 0, "router");
949
- var OutletContext = createContext4(void 0, "outlet");
950
- var LevelParamsContext = createContext4(void 0, "route-params");
951
- var RouteDataContext2 = createContext4(void 0, "route-data");
1182
+ import {
1183
+ createMemoryHistory,
1184
+ createBrowserHistory as createBrowserHistory2,
1185
+ matchRoutes as matchRoutes2,
1186
+ matchPath as matchPath2
1187
+ } from "@fluixi/router";
1188
+ import { runWithOwner as runWithOwner3 } from "@fluixi/reactive/signal";
1189
+ var RouterContext = createContext5(void 0, "router");
1190
+ var OutletContext = createContext5(void 0, "outlet");
1191
+ var LevelParamsContext = createContext5(void 0, "route-params");
1192
+ var RouteDataContext2 = createContext5(void 0, "route-data");
952
1193
  function renderLayer(m, depth, base) {
953
1194
  let data;
954
1195
  const loader = m.route.data;
955
1196
  if (typeof loader === "function") {
956
1197
  let cancelled = false;
957
- onCleanup2(() => {
1198
+ onCleanup4(() => {
958
1199
  cancelled = true;
959
1200
  });
960
- const owner = getOwner2();
961
- const [resource2] = createResource5(
962
- () => loader({ params: base.params, location: base.location }, owner, () => cancelled)
963
- );
964
- data = resource2;
1201
+ const owner = getOwner5();
1202
+ const router = useContext5(RouterContext);
1203
+ let watching = false;
1204
+ const trackDeps = (deps) => {
1205
+ if (watching || cancelled) return;
1206
+ watching = true;
1207
+ runWithOwner2(owner, () => {
1208
+ let first = true;
1209
+ createEffect4(() => {
1210
+ deps();
1211
+ if (first) first = false;
1212
+ else untrack4(() => void refetch());
1213
+ });
1214
+ });
1215
+ };
1216
+ const [resource2, { refetch }] = createResource5(() => {
1217
+ const result = loader({ params: base.params, location: base.location }, owner, () => cancelled, trackDeps);
1218
+ return router ? router.trackLoad(result) : result;
1219
+ });
1220
+ onCleanup4(onRevalidate(() => void refetch()));
1221
+ data = () => {
1222
+ const error = resource2.error;
1223
+ if (error !== void 0 && error !== null) throw error;
1224
+ return resource2();
1225
+ };
1226
+ Object.defineProperty(data, "loading", { get: () => resource2.loading });
1227
+ Object.defineProperty(data, "state", { get: () => resource2.state });
965
1228
  }
966
1229
  const buildPage = () => RouteDataContext2.Provider({
967
1230
  value: data,
@@ -979,33 +1242,62 @@ function renderLayer(m, depth, base) {
979
1242
  });
980
1243
  }
981
1244
  });
982
- if (!data) return buildPage();
1245
+ if (!data) return { view: buildPage(), ready: () => true };
983
1246
  const res = data;
984
- const isLoading = () => res.loading;
985
- const [ready, setReady] = createSignal7(untrack3(() => !isLoading()));
986
- createEffect3(() => setReady(!isLoading()));
987
- return createMemo6(() => ready() ? buildPage() : null);
1247
+ const isLoading = () => {
1248
+ const state = res.state;
1249
+ return state === void 0 ? res.loading : state === "pending" || state === "unresolved";
1250
+ };
1251
+ const [ready, setReady] = createSignal8(untrack4(() => !isLoading()));
1252
+ createEffect4(() => setReady(!isLoading()));
1253
+ return { view: createMemo6(() => ready() ? buildPage() : null), ready };
988
1254
  }
989
1255
  function renderChild(ctx) {
990
1256
  const childIdx = ctx.depth + 1;
991
- const [childComp, setChildComp] = createSignal7(
992
- untrack3(() => ctx.matched()[childIdx]?.component)
1257
+ const [childComp, setChildComp] = createSignal8(
1258
+ untrack4(() => ctx.matched()[childIdx]?.component)
993
1259
  );
994
- createEffect3(() => {
1260
+ createEffect4(() => {
995
1261
  const c = ctx.matched()[childIdx]?.component;
996
- if (untrack3(childComp) !== c) setChildComp(() => c);
1262
+ if (untrack4(childComp) !== c) setChildComp(() => c);
997
1263
  });
998
- return createMemo6(() => {
1264
+ const owner = getOwner5();
1265
+ let shown = null;
1266
+ let pending = null;
1267
+ const drop2 = (layer) => layer?.dispose();
1268
+ onCleanup4(() => {
1269
+ drop2(shown);
1270
+ drop2(pending);
1271
+ shown = pending = null;
1272
+ });
1273
+ const incoming = createMemo6(() => {
999
1274
  const component = childComp();
1000
- if (!component) {
1275
+ if (!component) return null;
1276
+ const m = untrack4(() => ctx.matched())[childIdx];
1277
+ return runWithOwner2(
1278
+ owner,
1279
+ () => createRoot3((dispose) => ({
1280
+ ...renderLayer(m, childIdx, { matched: ctx.matched, params: ctx.params, location: ctx.location }),
1281
+ dispose
1282
+ }))
1283
+ );
1284
+ });
1285
+ return createMemo6(() => {
1286
+ const next = incoming();
1287
+ if (!next) {
1288
+ drop2(shown);
1289
+ drop2(pending);
1290
+ shown = pending = null;
1001
1291
  return ctx.notFound ? ctx.notFound() : null;
1002
1292
  }
1003
- const m = untrack3(() => ctx.matched())[childIdx];
1004
- return renderLayer(m, childIdx, {
1005
- matched: ctx.matched,
1006
- params: ctx.params,
1007
- location: ctx.location
1008
- });
1293
+ if (next === shown) return shown.view;
1294
+ if (pending && pending !== next) drop2(pending);
1295
+ pending = next;
1296
+ if (shown && !next.ready()) return shown.view;
1297
+ drop2(shown);
1298
+ shown = next;
1299
+ pending = null;
1300
+ return shown.view;
1009
1301
  });
1010
1302
  }
1011
1303
  function renderNotFound(notFound) {
@@ -1039,7 +1331,9 @@ function Router(props) {
1039
1331
  base: props.base,
1040
1332
  history
1041
1333
  });
1042
- const [state, setState] = createSignal7(router.state());
1334
+ const [state, setState] = createSignal8(router.state());
1335
+ const [navigating, setNavigating] = createSignal8(false);
1336
+ const [loads, setLoads] = createSignal8(0);
1043
1337
  let navigationId = 0;
1044
1338
  const takeMode = () => {
1045
1339
  const mode = pendingTransitionMode ?? (props.transition ?? "auto");
@@ -1049,12 +1343,15 @@ function Router(props) {
1049
1343
  const unsub = router.subscribe((next) => {
1050
1344
  const id = ++navigationId;
1051
1345
  const mode = takeMode();
1346
+ setNavigating(true);
1052
1347
  const prepared = prepareComponents(
1053
1348
  (next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
1054
1349
  );
1055
1350
  const commit = () => {
1056
1351
  setState(next);
1057
- return flush();
1352
+ const flushed = flush();
1353
+ if (id === navigationId) setNavigating(false);
1354
+ return flushed;
1058
1355
  };
1059
1356
  if (!prepared) {
1060
1357
  void runTransition(mode, commit);
@@ -1065,7 +1362,7 @@ function Router(props) {
1065
1362
  return runTransition(mode, commit);
1066
1363
  });
1067
1364
  });
1068
- onCleanup2(() => {
1365
+ onCleanup4(() => {
1069
1366
  unsub();
1070
1367
  router.destroy();
1071
1368
  navigationId++;
@@ -1076,7 +1373,18 @@ function Router(props) {
1076
1373
  const ctx = {
1077
1374
  router,
1078
1375
  location: createMemo6(() => state().location),
1079
- params: createMemo6(() => state().match?.params ?? {})
1376
+ params: createMemo6(() => state().match?.params ?? {}),
1377
+ isRouting: () => navigating() || loads() > 0,
1378
+ // Counted by the promise, not by an owner: a load a newer navigation superseded still
1379
+ // settles and uncounts itself, and a resource seeded from the server never calls it.
1380
+ trackLoad(result) {
1381
+ if (result && typeof result.finally === "function") {
1382
+ setLoads((n) => n + 1);
1383
+ void result.finally(() => setLoads((n) => n - 1)).catch(() => {
1384
+ });
1385
+ }
1386
+ return result;
1387
+ }
1080
1388
  };
1081
1389
  const root = {
1082
1390
  depth: -1,
@@ -1098,10 +1406,12 @@ var _ssrRouterStub = {
1098
1406
  router: { navigate: () => {
1099
1407
  } },
1100
1408
  location: () => ({ pathname: "", search: "", hash: "", query: {} }),
1101
- params: () => ({})
1409
+ params: () => ({}),
1410
+ isRouting: () => false,
1411
+ trackLoad: (result) => result
1102
1412
  };
1103
1413
  function useRouter() {
1104
- const ctx = useContext4(RouterContext);
1414
+ const ctx = useContext5(RouterContext);
1105
1415
  if (ctx) return ctx;
1106
1416
  if (typeof window === "undefined") return _ssrRouterStub;
1107
1417
  throw new Error("[router] useRouter must be used within <Router>");
@@ -1140,19 +1450,32 @@ var LINK_OWN_PROPS = /* @__PURE__ */ new Set([
1140
1450
  "children"
1141
1451
  ]);
1142
1452
  function Link(props) {
1143
- const ctx = useContext4(RouterContext);
1144
- const navigate = () => ctx?.router.navigate(read(props.href) ?? "", { replace: read(props.replace) });
1453
+ const ctx = useContext5(RouterContext);
1454
+ const navigate = () => ctx.router.navigate(read(props.href) ?? "", { replace: read(props.replace) });
1145
1455
  const a = createNativeElement("a");
1146
1456
  setAttribute(a, "href", read(props.href) ?? "");
1147
1457
  if (props.slot) setAttribute(a, "slot", read(props.slot));
1148
1458
  for (const k of Object.keys(props)) {
1149
1459
  if (LINK_OWN_PROPS.has(k)) continue;
1150
1460
  const v = props[k];
1151
- if (v != null && typeof v !== "function") setAttribute(a, k, String(v));
1461
+ if (typeof v === "function") {
1462
+ if (/^on[A-Z]/.test(k)) continue;
1463
+ const read3 = v;
1464
+ const apply = () => {
1465
+ const value = read3();
1466
+ if (value == null || value === false) a.removeAttribute?.(k);
1467
+ else setAttribute(a, k, String(value));
1468
+ };
1469
+ if (typeof a.addEventListener === "function") createEffect4(apply);
1470
+ else apply();
1471
+ continue;
1472
+ }
1473
+ if (v != null) setAttribute(a, k, String(v));
1152
1474
  }
1153
1475
  if (typeof a.addEventListener === "function") {
1154
1476
  a.addEventListener("click", (e) => {
1155
1477
  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
1478
+ if (!ctx) return;
1156
1479
  e.preventDefault();
1157
1480
  navigate();
1158
1481
  });
@@ -1161,7 +1484,7 @@ function Link(props) {
1161
1484
  if (base) setAttribute(a, "class", base);
1162
1485
  }
1163
1486
  if (typeof a.addEventListener === "function") {
1164
- createEffect3(() => {
1487
+ createEffect4(() => {
1165
1488
  const href = read(props.href) ?? "";
1166
1489
  a.setAttribute("href", href);
1167
1490
  const base = read(props.className ?? props.class) ?? "";
@@ -1234,20 +1557,20 @@ var core_default = {
1234
1557
  // render,
1235
1558
  onMount,
1236
1559
  onUnmount,
1237
- createEffect: createEffect4,
1560
+ createEffect: createEffect5,
1238
1561
  createMemo: createMemo7,
1239
- createSignal: createSignal8,
1562
+ createSignal: createSignal9,
1240
1563
  createContext: createContext3,
1241
- createRoot: createRoot3,
1564
+ createRoot: createRoot4,
1242
1565
  createDeferred: createDeferred2,
1243
1566
  createComputed: createComputed2,
1244
1567
  createRenderEffect: createRenderEffect3,
1245
1568
  createSelector,
1246
- onCleanup: onCleanup3,
1247
- getOwner: getOwner3,
1248
- runWithOwner: runWithOwner3,
1569
+ onCleanup: onCleanup5,
1570
+ getOwner: getOwner6,
1571
+ runWithOwner: runWithOwner4,
1249
1572
  batch: batch2,
1250
- untrack: untrack4,
1573
+ untrack: untrack5,
1251
1574
  useContext: useContext3,
1252
1575
  setOwner,
1253
1576
  // Control Flow
@@ -1277,6 +1600,7 @@ export {
1277
1600
  $component,
1278
1601
  Await,
1279
1602
  ClientOnly,
1603
+ ColorSchemeProvider,
1280
1604
  Dynamic,
1281
1605
  ErrorBoundary,
1282
1606
  FRAMEWORK_NAME,
@@ -1293,6 +1617,7 @@ export {
1293
1617
  Suspense,
1294
1618
  SuspenseList,
1295
1619
  Switch,
1620
+ ThemeProvider,
1296
1621
  VERSION,
1297
1622
  addClass,
1298
1623
  appendChildren,
@@ -1302,26 +1627,24 @@ export {
1302
1627
  clientOnly,
1303
1628
  closest,
1304
1629
  composeProviders,
1630
+ createColorScheme,
1305
1631
  createComponent,
1306
1632
  createComputed2 as createComputed,
1307
- createConsumer,
1308
1633
  createContext3 as createContext,
1309
- createContextWithProvider,
1310
1634
  createDebounce,
1311
1635
  createDebouncedResource,
1312
1636
  createDebouncedSignal,
1313
1637
  createDeferred2 as createDeferred,
1314
- createEffect4 as createEffect,
1638
+ createEffect5 as createEffect,
1315
1639
  createIsomorphicState,
1316
1640
  createIsomorphicStore,
1317
1641
  createMemo7 as createMemo,
1318
- createMemoryStorage,
1319
1642
  createProvider,
1320
1643
  createRenderEffect3 as createRenderEffect,
1321
1644
  createResource6 as createResource,
1322
- createRoot3 as createRoot,
1645
+ createRoot4 as createRoot,
1323
1646
  createSelector,
1324
- createSignal8 as createSignal,
1647
+ createSignal9 as createSignal,
1325
1648
  createStore,
1326
1649
  createTheme,
1327
1650
  core_default as default,
@@ -1332,7 +1655,7 @@ export {
1332
1655
  env,
1333
1656
  getAttribute,
1334
1657
  getOffset,
1335
- getOwner3 as getOwner,
1658
+ getOwner6 as getOwner,
1336
1659
  getStyle,
1337
1660
  hasClass,
1338
1661
  html,
@@ -1350,7 +1673,7 @@ export {
1350
1673
  mergeProps,
1351
1674
  observeIntersection2 as observeIntersection,
1352
1675
  observeResize,
1353
- onCleanup3 as onCleanup,
1676
+ onCleanup5 as onCleanup,
1354
1677
  onMount,
1355
1678
  onUnmount,
1356
1679
  portal,
@@ -1362,22 +1685,23 @@ export {
1362
1685
  removeChildren,
1363
1686
  removeClass,
1364
1687
  render,
1688
+ requireContext,
1365
1689
  resource,
1366
- runWithOwner3 as runWithOwner,
1690
+ runWithOwner4 as runWithOwner,
1367
1691
  scrollIntoView,
1368
1692
  setAttribute2 as setAttribute,
1369
1693
  setOwner,
1370
1694
  setStyles,
1371
- signal,
1695
+ signal2 as signal,
1372
1696
  splitProps,
1373
- storage,
1374
1697
  styleMap,
1375
1698
  svg,
1376
1699
  toggleClass,
1377
- untrack4 as untrack,
1700
+ untrack5 as untrack,
1378
1701
  untrackStore,
1379
1702
  unwrap,
1380
1703
  useCallback,
1704
+ useColorScheme,
1381
1705
  useContext3 as useContext,
1382
1706
  useEffect,
1383
1707
  useEventListener,
@@ -1385,9 +1709,9 @@ export {
1385
1709
  useMemo,
1386
1710
  useNavigate,
1387
1711
  useParams,
1388
- useProvide,
1389
1712
  useReducer,
1390
1713
  useRef,
1391
1714
  useRouter,
1715
+ useTheme,
1392
1716
  waitForElement
1393
1717
  };