@aster-ui/prefixed 0.12.88 → 0.12.89

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.
@@ -11,7 +11,7 @@ export interface UseThemeReturn {
11
11
  setTheme: ((theme: string) => void) | undefined;
12
12
  /** Toggle between light and dark. Only available with ThemeProvider. */
13
13
  toggleTheme: (() => void) | undefined;
14
- /** Computed theme colors as hex values. Lazy only computed when accessed. */
14
+ /** Computed theme colors as hex values. Computed asynchronously after theme changes. */
15
15
  colors: ThemeColors;
16
16
  /** The system preference. Only available with ThemeProvider. */
17
17
  systemTheme: 'light' | 'dark' | undefined;
@@ -26,8 +26,8 @@ export interface UseThemeReturn {
26
26
  * to isDark and colors based on the current data-theme attribute and
27
27
  * system preference.
28
28
  *
29
- * Colors are lazy — only computed (via canvas) when you access them.
30
- * Components that only need isDark/setTheme pay no cost for color computation.
29
+ * Colors are computed asynchronously after mount and theme changes,
30
+ * using DOM-based color conversion (no canvas).
31
31
  *
32
32
  * @example
33
33
  * // With ThemeProvider (full control)
@@ -1,6 +1,6 @@
1
- import { useMemo as i, useState as d, useEffect as l } from "react";
2
- import { useHasThemeProvider as h, useThemeContext as y } from "../providers/ThemeProvider.js";
3
- const g = /* @__PURE__ */ new Set([
1
+ import { useState as u, useRef as g, useEffect as f, useMemo as l } from "react";
2
+ import { useHasThemeProvider as b, useThemeContext as T } from "../providers/ThemeProvider.js";
3
+ const p = /* @__PURE__ */ new Set([
4
4
  "dark",
5
5
  "synthwave",
6
6
  "halloween",
@@ -13,120 +13,106 @@ const g = /* @__PURE__ */ new Set([
13
13
  "coffee",
14
14
  "dim",
15
15
  "sunset"
16
- ]);
17
- function b(o) {
18
- if (typeof document > "u") return "#000000";
19
- const e = document.createElement("canvas");
20
- e.width = e.height = 1;
21
- const t = e.getContext("2d");
22
- if (!t) return "#000000";
23
- t.fillStyle = o, t.fillRect(0, 0, 1, 1);
24
- const [r, n, s] = t.getImageData(0, 0, 1, 1).data;
25
- return `#${((1 << 24) + (r << 16) + (n << 8) + s).toString(16).slice(1)}`;
16
+ ]), a = {
17
+ background: "#ffffff",
18
+ foreground: "#000000",
19
+ primary: "#6366f1",
20
+ primaryContent: "#ffffff",
21
+ secondary: "#f000b8",
22
+ accent: "#37cdbe",
23
+ info: "#3abff8",
24
+ success: "#36d399",
25
+ warning: "#fbbd23",
26
+ error: "#f87272"
27
+ };
28
+ let o = null;
29
+ function v() {
30
+ return o || (o = document.createElement("span"), o.style.position = "absolute", o.style.visibility = "hidden", o.style.pointerEvents = "none", o.style.width = "0", o.style.height = "0", o.style.overflow = "hidden", document.body.appendChild(o)), o;
26
31
  }
27
- function a() {
28
- if (typeof document > "u")
29
- return {
30
- background: "#ffffff",
31
- foreground: "#000000",
32
- primary: "#6366f1",
33
- primaryContent: "#ffffff",
34
- secondary: "#f000b8",
35
- accent: "#37cdbe",
36
- info: "#3abff8",
37
- success: "#36d399",
38
- warning: "#fbbd23",
39
- error: "#f87272"
40
- };
41
- const o = getComputedStyle(document.documentElement), e = (t, r) => {
42
- const n = o.getPropertyValue(t).trim();
43
- return n ? b(n) : r;
32
+ function w(e) {
33
+ const t = v();
34
+ t.style.color = e;
35
+ const n = getComputedStyle(t).color.match(/\d+/g);
36
+ if (!n) return "#000000";
37
+ const [r, c, m] = n.map(Number);
38
+ return `#${((1 << 24) + (r << 16) + (c << 8) + m).toString(16).slice(1)}`;
39
+ }
40
+ function h() {
41
+ if (typeof document > "u") return a;
42
+ const e = getComputedStyle(document.documentElement), t = (s, n) => {
43
+ const r = e.getPropertyValue(s).trim();
44
+ return r ? w(r) : n;
44
45
  };
45
46
  return {
46
- background: e("--color-base-100", "#ffffff"),
47
- foreground: e("--color-base-content", "#000000"),
48
- primary: e("--color-primary", "#6366f1"),
49
- primaryContent: e("--color-primary-content", "#ffffff"),
50
- secondary: e("--color-secondary", "#f000b8"),
51
- accent: e("--color-accent", "#37cdbe"),
52
- info: e("--color-info", "#3abff8"),
53
- success: e("--color-success", "#36d399"),
54
- warning: e("--color-warning", "#fbbd23"),
55
- error: e("--color-error", "#f87272")
47
+ background: t("--color-base-100", "#ffffff"),
48
+ foreground: t("--color-base-content", "#000000"),
49
+ primary: t("--color-primary", "#6366f1"),
50
+ primaryContent: t("--color-primary-content", "#ffffff"),
51
+ secondary: t("--color-secondary", "#f000b8"),
52
+ accent: t("--color-accent", "#37cdbe"),
53
+ info: t("--color-info", "#3abff8"),
54
+ success: t("--color-success", "#36d399"),
55
+ warning: t("--color-warning", "#fbbd23"),
56
+ error: t("--color-error", "#f87272")
56
57
  };
57
58
  }
58
- function T() {
59
+ function k() {
59
60
  return typeof window > "u" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
60
61
  }
61
- function f() {
62
+ function C() {
62
63
  return typeof document > "u" ? null : document.documentElement.getAttribute("data-theme");
63
64
  }
64
- function u(o) {
65
- let e = null;
66
- return new Proxy({}, {
67
- get(t, r) {
68
- return e || (e = a()), e[r];
69
- },
70
- ownKeys() {
71
- return e || (e = a()), Object.keys(e);
72
- },
73
- getOwnPropertyDescriptor(t, r) {
74
- if (e || (e = a()), r in e)
75
- return { configurable: !0, enumerable: !0, value: e[r] };
76
- }
77
- });
65
+ function x() {
66
+ return b() ? S() : E();
78
67
  }
79
- function k() {
80
- if (h()) {
81
- const e = y(), t = i(() => u(e.resolvedTheme), [e.resolvedTheme]);
82
- return {
83
- theme: e.theme,
84
- resolvedTheme: e.resolvedTheme,
85
- isDark: e.isDark,
86
- setTheme: e.setTheme,
87
- toggleTheme: e.toggleTheme,
88
- colors: t,
89
- systemTheme: e.systemTheme
90
- };
91
- }
92
- return v();
68
+ function S() {
69
+ const e = T(), [t, s] = u(a), n = g(!1);
70
+ return f(() => {
71
+ requestAnimationFrame(() => {
72
+ s(h());
73
+ }), n.current = !0;
74
+ }, [e.resolvedTheme]), l(() => ({
75
+ theme: e.theme,
76
+ resolvedTheme: e.resolvedTheme,
77
+ isDark: e.isDark,
78
+ setTheme: e.setTheme,
79
+ toggleTheme: e.toggleTheme,
80
+ colors: t,
81
+ systemTheme: e.systemTheme
82
+ }), [e.theme, e.resolvedTheme, e.isDark, e.setTheme, e.toggleTheme, t, e.systemTheme]);
93
83
  }
94
- function v() {
95
- const [o, e] = d(() => ({
96
- isDark: !1,
97
- themeKey: f()
98
- }));
99
- return l(() => {
100
- const t = () => {
101
- const s = f(), m = T();
102
- let c = !1;
103
- s ? c = g.has(s) : c = m === "dark", e({ isDark: c, themeKey: s });
84
+ function E() {
85
+ const [e, t] = u(!1), [s, n] = u(a);
86
+ return f(() => {
87
+ const r = () => {
88
+ const d = C(), y = k();
89
+ let i = !1;
90
+ d ? i = p.has(d) : i = y === "dark", t(i), requestAnimationFrame(() => {
91
+ n(h());
92
+ });
104
93
  };
105
- t();
106
- const r = new MutationObserver(t);
107
- r.observe(document.documentElement, {
94
+ r();
95
+ const c = new MutationObserver(r);
96
+ c.observe(document.documentElement, {
108
97
  attributes: !0,
109
98
  attributeFilter: ["data-theme", "class"]
110
99
  });
111
- const n = window.matchMedia("(prefers-color-scheme: dark)");
112
- return n.addEventListener("change", t), () => {
113
- r.disconnect(), n.removeEventListener("change", t);
114
- };
115
- }, []), i(() => {
116
- const t = u(o.themeKey);
117
- return {
118
- theme: void 0,
119
- resolvedTheme: void 0,
120
- isDark: o.isDark,
121
- setTheme: void 0,
122
- toggleTheme: void 0,
123
- colors: t,
124
- systemTheme: void 0
100
+ const m = window.matchMedia("(prefers-color-scheme: dark)");
101
+ return m.addEventListener("change", r), () => {
102
+ c.disconnect(), m.removeEventListener("change", r);
125
103
  };
126
- }, [o.isDark, o.themeKey]);
104
+ }, []), l(() => ({
105
+ theme: void 0,
106
+ resolvedTheme: void 0,
107
+ isDark: e,
108
+ setTheme: void 0,
109
+ toggleTheme: void 0,
110
+ colors: s,
111
+ systemTheme: void 0
112
+ }), [e, s]);
127
113
  }
128
114
  export {
129
- k as default,
130
- k as useTheme
115
+ x as default,
116
+ x as useTheme
131
117
  };
132
118
  //# sourceMappingURL=useTheme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useTheme.js","sources":["../../src/hooks/useTheme.ts"],"sourcesContent":["import { useEffect, useState, useMemo } from 'react'\nimport { useHasThemeProvider, useThemeContext, type ThemeColors } from '../providers/ThemeProvider'\n\nexport type { ThemeColors }\n\n// Common dark themes in DaisyUI\nconst DARK_THEMES = new Set([\n 'dark', 'synthwave', 'halloween', 'forest', 'black', 'luxury', 'dracula',\n 'business', 'night', 'coffee', 'dim', 'sunset'\n])\n\nexport interface UseThemeReturn {\n /** The theme setting (what user selected). Only available with ThemeProvider. */\n theme: string | undefined\n /** The actual applied theme. Only available with ThemeProvider. */\n resolvedTheme: string | undefined\n /** Whether dark mode is active */\n isDark: boolean\n /** Set the theme. Only available with ThemeProvider. */\n setTheme: ((theme: string) => void) | undefined\n /** Toggle between light and dark. Only available with ThemeProvider. */\n toggleTheme: (() => void) | undefined\n /** Computed theme colors as hex values. Lazy — only computed when accessed. */\n colors: ThemeColors\n /** The system preference. Only available with ThemeProvider. */\n systemTheme: 'light' | 'dark' | undefined\n}\n\n// Convert any CSS color to hex via canvas\nfunction colorToHex(color: string): string {\n if (typeof document === 'undefined') return '#000000'\n const canvas = document.createElement('canvas')\n canvas.width = canvas.height = 1\n const ctx = canvas.getContext('2d')\n if (!ctx) return '#000000'\n ctx.fillStyle = color\n ctx.fillRect(0, 0, 1, 1)\n const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`\n}\n\nfunction getThemeColors(): ThemeColors {\n if (typeof document === 'undefined') {\n return {\n background: '#ffffff',\n foreground: '#000000',\n primary: '#6366f1',\n primaryContent: '#ffffff',\n secondary: '#f000b8',\n accent: '#37cdbe',\n info: '#3abff8',\n success: '#36d399',\n warning: '#fbbd23',\n error: '#f87272',\n }\n }\n\n const style = getComputedStyle(document.documentElement)\n const getColor = (varName: string, fallback: string): string => {\n const value = style.getPropertyValue(varName).trim()\n return value ? colorToHex(value) : fallback\n }\n\n return {\n background: getColor('--color-base-100', '#ffffff'),\n foreground: getColor('--color-base-content', '#000000'),\n primary: getColor('--color-primary', '#6366f1'),\n primaryContent: getColor('--color-primary-content', '#ffffff'),\n secondary: getColor('--color-secondary', '#f000b8'),\n accent: getColor('--color-accent', '#37cdbe'),\n info: getColor('--color-info', '#3abff8'),\n success: getColor('--color-success', '#36d399'),\n warning: getColor('--color-warning', '#fbbd23'),\n error: getColor('--color-error', '#f87272'),\n }\n}\n\nfunction getSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nfunction getCurrentTheme(): string | null {\n if (typeof document === 'undefined') return null\n return document.documentElement.getAttribute('data-theme')\n}\n\n/**\n * Create a lazy colors object that only computes hex values when accessed.\n * Returns a new object each time so referential identity tracks the dep key.\n */\nfunction createLazyColors(depKey: unknown): ThemeColors {\n let cached: ThemeColors | null = null\n // depKey is used only to invalidate the closure identity\n void depKey\n return new Proxy({} as ThemeColors, {\n get(_target, prop: string) {\n if (!cached) cached = getThemeColors()\n return cached[prop as keyof ThemeColors]\n },\n ownKeys() {\n if (!cached) cached = getThemeColors()\n return Object.keys(cached)\n },\n getOwnPropertyDescriptor(_target, prop) {\n if (!cached) cached = getThemeColors()\n if (prop in cached) {\n return { configurable: true, enumerable: true, value: cached[prop as keyof ThemeColors] }\n }\n },\n })\n}\n\n/**\n * Hook to detect current theme and get computed colors.\n *\n * When used within a ThemeProvider, returns full theme control including\n * setTheme, theme selection, and resolved theme.\n *\n * When used standalone (without ThemeProvider), provides read-only access\n * to isDark and colors based on the current data-theme attribute and\n * system preference.\n *\n * Colors are lazy — only computed (via canvas) when you access them.\n * Components that only need isDark/setTheme pay no cost for color computation.\n *\n * @example\n * // With ThemeProvider (full control)\n * const { theme, setTheme, resolvedTheme, isDark, colors } = useTheme()\n * setTheme('dark')\n *\n * @example\n * // Without ThemeProvider (read-only)\n * const { isDark, colors } = useTheme()\n * // colors.primary, colors.foreground, etc.\n */\nexport function useTheme(): UseThemeReturn {\n const hasProvider = useHasThemeProvider()\n\n if (hasProvider) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const context = useThemeContext()\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const lazyColors = useMemo(() => createLazyColors(context.resolvedTheme), [context.resolvedTheme])\n return {\n theme: context.theme,\n resolvedTheme: context.resolvedTheme,\n isDark: context.isDark,\n setTheme: context.setTheme,\n toggleTheme: context.toggleTheme,\n colors: lazyColors,\n systemTheme: context.systemTheme,\n }\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useThemeStandalone()\n}\n\n/**\n * Standalone theme detection (no ThemeProvider)\n */\nfunction useThemeStandalone(): UseThemeReturn {\n const [state, setState] = useState<{ isDark: boolean; themeKey: string | null }>(() => ({\n isDark: false,\n themeKey: getCurrentTheme(),\n }))\n\n useEffect(() => {\n const updateTheme = () => {\n const currentTheme = getCurrentTheme()\n const systemTheme = getSystemTheme()\n\n let isDark = false\n if (currentTheme) {\n isDark = DARK_THEMES.has(currentTheme)\n } else {\n isDark = systemTheme === 'dark'\n }\n\n setState({ isDark, themeKey: currentTheme })\n }\n\n updateTheme()\n\n const observer = new MutationObserver(updateTheme)\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme', 'class']\n })\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n mediaQuery.addEventListener('change', updateTheme)\n\n return () => {\n observer.disconnect()\n mediaQuery.removeEventListener('change', updateTheme)\n }\n }, [])\n\n return useMemo(() => {\n const lazyColors = createLazyColors(state.themeKey)\n return {\n theme: undefined,\n resolvedTheme: undefined,\n isDark: state.isDark,\n setTheme: undefined,\n toggleTheme: undefined,\n colors: lazyColors,\n systemTheme: undefined,\n }\n }, [state.isDark, state.themeKey])\n}\n\nexport default useTheme\n"],"names":["DARK_THEMES","colorToHex","color","canvas","ctx","g","b","getThemeColors","style","getColor","varName","fallback","value","getSystemTheme","getCurrentTheme","createLazyColors","depKey","cached","_target","prop","useTheme","useHasThemeProvider","context","useThemeContext","lazyColors","useMemo","useThemeStandalone","state","setState","useState","useEffect","updateTheme","currentTheme","systemTheme","isDark","observer","mediaQuery"],"mappings":"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"}
1
+ {"version":3,"file":"useTheme.js","sources":["../../src/hooks/useTheme.ts"],"sourcesContent":["import { useEffect, useState, useMemo, useRef } from 'react'\nimport { useHasThemeProvider, useThemeContext, type ThemeColors } from '../providers/ThemeProvider'\n\nexport type { ThemeColors }\n\n// Common dark themes in DaisyUI\nconst DARK_THEMES = new Set([\n 'dark', 'synthwave', 'halloween', 'forest', 'black', 'luxury', 'dracula',\n 'business', 'night', 'coffee', 'dim', 'sunset'\n])\n\nexport interface UseThemeReturn {\n /** The theme setting (what user selected). Only available with ThemeProvider. */\n theme: string | undefined\n /** The actual applied theme. Only available with ThemeProvider. */\n resolvedTheme: string | undefined\n /** Whether dark mode is active */\n isDark: boolean\n /** Set the theme. Only available with ThemeProvider. */\n setTheme: ((theme: string) => void) | undefined\n /** Toggle between light and dark. Only available with ThemeProvider. */\n toggleTheme: (() => void) | undefined\n /** Computed theme colors as hex values. Computed asynchronously after theme changes. */\n colors: ThemeColors\n /** The system preference. Only available with ThemeProvider. */\n systemTheme: 'light' | 'dark' | undefined\n}\n\nconst SSR_COLORS: ThemeColors = {\n background: '#ffffff',\n foreground: '#000000',\n primary: '#6366f1',\n primaryContent: '#ffffff',\n secondary: '#f000b8',\n accent: '#37cdbe',\n info: '#3abff8',\n success: '#36d399',\n warning: '#fbbd23',\n error: '#f87272',\n}\n\n// Persistent hidden element for DOM-based color conversion\nlet colorProbe: HTMLSpanElement | null = null\n\nfunction getColorProbe(): HTMLSpanElement {\n if (!colorProbe) {\n colorProbe = document.createElement('span')\n colorProbe.style.position = 'absolute'\n colorProbe.style.visibility = 'hidden'\n colorProbe.style.pointerEvents = 'none'\n colorProbe.style.width = '0'\n colorProbe.style.height = '0'\n colorProbe.style.overflow = 'hidden'\n document.body.appendChild(colorProbe)\n }\n return colorProbe\n}\n\n/** Convert any CSS color (including oklch) to hex via getComputedStyle */\nfunction colorToHex(color: string): string {\n const probe = getColorProbe()\n probe.style.color = color\n const computed = getComputedStyle(probe).color\n // getComputedStyle returns rgb(r, g, b) or rgba(r, g, b, a)\n const match = computed.match(/\\d+/g)\n if (!match) return '#000000'\n const [r, g, b] = match.map(Number)\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`\n}\n\nfunction computeThemeColors(): ThemeColors {\n if (typeof document === 'undefined') return SSR_COLORS\n\n const style = getComputedStyle(document.documentElement)\n const getColor = (varName: string, fallback: string): string => {\n const value = style.getPropertyValue(varName).trim()\n return value ? colorToHex(value) : fallback\n }\n\n return {\n background: getColor('--color-base-100', '#ffffff'),\n foreground: getColor('--color-base-content', '#000000'),\n primary: getColor('--color-primary', '#6366f1'),\n primaryContent: getColor('--color-primary-content', '#ffffff'),\n secondary: getColor('--color-secondary', '#f000b8'),\n accent: getColor('--color-accent', '#37cdbe'),\n info: getColor('--color-info', '#3abff8'),\n success: getColor('--color-success', '#36d399'),\n warning: getColor('--color-warning', '#fbbd23'),\n error: getColor('--color-error', '#f87272'),\n }\n}\n\nfunction getSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nfunction getCurrentTheme(): string | null {\n if (typeof document === 'undefined') return null\n return document.documentElement.getAttribute('data-theme')\n}\n\n/**\n * Hook to detect current theme and get computed colors.\n *\n * When used within a ThemeProvider, returns full theme control including\n * setTheme, theme selection, and resolved theme.\n *\n * When used standalone (without ThemeProvider), provides read-only access\n * to isDark and colors based on the current data-theme attribute and\n * system preference.\n *\n * Colors are computed asynchronously after mount and theme changes,\n * using DOM-based color conversion (no canvas).\n *\n * @example\n * // With ThemeProvider (full control)\n * const { theme, setTheme, resolvedTheme, isDark, colors } = useTheme()\n * setTheme('dark')\n *\n * @example\n * // Without ThemeProvider (read-only)\n * const { isDark, colors } = useTheme()\n * // colors.primary, colors.foreground, etc.\n */\nexport function useTheme(): UseThemeReturn {\n const hasProvider = useHasThemeProvider()\n\n if (hasProvider) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useThemeWithProvider()\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useThemeStandalone()\n}\n\n/**\n * Theme hook when ThemeProvider is present.\n */\nfunction useThemeWithProvider(): UseThemeReturn {\n const context = useThemeContext()\n const [colors, setColors] = useState<ThemeColors>(SSR_COLORS)\n const mountedRef = useRef(false)\n\n useEffect(() => {\n // On mount and when theme changes, compute colors after CSS has applied\n requestAnimationFrame(() => {\n setColors(computeThemeColors())\n })\n mountedRef.current = true\n }, [context.resolvedTheme])\n\n return useMemo(() => ({\n theme: context.theme,\n resolvedTheme: context.resolvedTheme,\n isDark: context.isDark,\n setTheme: context.setTheme,\n toggleTheme: context.toggleTheme,\n colors,\n systemTheme: context.systemTheme,\n }), [context.theme, context.resolvedTheme, context.isDark, context.setTheme, context.toggleTheme, colors, context.systemTheme])\n}\n\n/**\n * Standalone theme detection (no ThemeProvider)\n */\nfunction useThemeStandalone(): UseThemeReturn {\n const [isDark, setIsDark] = useState(false)\n const [colors, setColors] = useState<ThemeColors>(SSR_COLORS)\n\n useEffect(() => {\n const updateTheme = () => {\n const currentTheme = getCurrentTheme()\n const systemTheme = getSystemTheme()\n\n let dark = false\n if (currentTheme) {\n dark = DARK_THEMES.has(currentTheme)\n } else {\n dark = systemTheme === 'dark'\n }\n\n setIsDark(dark)\n\n // Compute colors after CSS has applied\n requestAnimationFrame(() => {\n setColors(computeThemeColors())\n })\n }\n\n updateTheme()\n\n const observer = new MutationObserver(updateTheme)\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme', 'class']\n })\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n mediaQuery.addEventListener('change', updateTheme)\n\n return () => {\n observer.disconnect()\n mediaQuery.removeEventListener('change', updateTheme)\n }\n }, [])\n\n return useMemo(() => ({\n theme: undefined,\n resolvedTheme: undefined,\n isDark,\n setTheme: undefined,\n toggleTheme: undefined,\n colors,\n systemTheme: undefined,\n }), [isDark, colors])\n}\n\nexport default useTheme\n"],"names":["DARK_THEMES","SSR_COLORS","colorProbe","getColorProbe","colorToHex","color","probe","match","g","b","computeThemeColors","style","getColor","varName","fallback","value","getSystemTheme","getCurrentTheme","useTheme","useHasThemeProvider","useThemeWithProvider","useThemeStandalone","context","useThemeContext","colors","setColors","useState","mountedRef","useRef","useEffect","useMemo","isDark","setIsDark","updateTheme","currentTheme","systemTheme","dark","observer","mediaQuery"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aster-ui/prefixed",
3
- "version": "0.12.88",
3
+ "version": "0.12.89",
4
4
  "description": "React UI component library with DaisyUI (prefixed classes)",
5
5
  "homepage": "https://asterui.com",
6
6
  "repository": {