@aster-ui/prefixed 0.12.87 → 0.12.88
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.
package/dist/hooks/useTheme.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export interface UseThemeReturn {
|
|
|
9
9
|
isDark: boolean;
|
|
10
10
|
/** Set the theme. Only available with ThemeProvider. */
|
|
11
11
|
setTheme: ((theme: string) => void) | undefined;
|
|
12
|
-
/**
|
|
12
|
+
/** Toggle between light and dark. Only available with ThemeProvider. */
|
|
13
|
+
toggleTheme: (() => void) | undefined;
|
|
14
|
+
/** Computed theme colors as hex values. Lazy — only computed when accessed. */
|
|
13
15
|
colors: ThemeColors;
|
|
14
16
|
/** The system preference. Only available with ThemeProvider. */
|
|
15
17
|
systemTheme: 'light' | 'dark' | undefined;
|
|
@@ -24,11 +26,13 @@ export interface UseThemeReturn {
|
|
|
24
26
|
* to isDark and colors based on the current data-theme attribute and
|
|
25
27
|
* system preference.
|
|
26
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.
|
|
31
|
+
*
|
|
27
32
|
* @example
|
|
28
33
|
* // With ThemeProvider (full control)
|
|
29
34
|
* const { theme, setTheme, resolvedTheme, isDark, colors } = useTheme()
|
|
30
35
|
* setTheme('dark')
|
|
31
|
-
* setTheme('system')
|
|
32
36
|
*
|
|
33
37
|
* @example
|
|
34
38
|
* // Without ThemeProvider (read-only)
|
package/dist/hooks/useTheme.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useHasThemeProvider as
|
|
3
|
-
const
|
|
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([
|
|
4
4
|
"dark",
|
|
5
5
|
"synthwave",
|
|
6
6
|
"halloween",
|
|
@@ -14,15 +14,15 @@ const h = /* @__PURE__ */ new Set([
|
|
|
14
14
|
"dim",
|
|
15
15
|
"sunset"
|
|
16
16
|
]);
|
|
17
|
-
function
|
|
17
|
+
function b(o) {
|
|
18
18
|
if (typeof document > "u") return "#000000";
|
|
19
19
|
const e = document.createElement("canvas");
|
|
20
20
|
e.width = e.height = 1;
|
|
21
21
|
const t = e.getContext("2d");
|
|
22
22
|
if (!t) return "#000000";
|
|
23
|
-
t.fillStyle =
|
|
24
|
-
const [
|
|
25
|
-
return `#${((1 << 24) + (
|
|
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)}`;
|
|
26
26
|
}
|
|
27
27
|
function a() {
|
|
28
28
|
if (typeof document > "u")
|
|
@@ -38,9 +38,9 @@ function a() {
|
|
|
38
38
|
warning: "#fbbd23",
|
|
39
39
|
error: "#f87272"
|
|
40
40
|
};
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
return
|
|
41
|
+
const o = getComputedStyle(document.documentElement), e = (t, r) => {
|
|
42
|
+
const n = o.getPropertyValue(t).trim();
|
|
43
|
+
return n ? b(n) : r;
|
|
44
44
|
};
|
|
45
45
|
return {
|
|
46
46
|
background: e("--color-base-100", "#ffffff"),
|
|
@@ -55,62 +55,75 @@ function a() {
|
|
|
55
55
|
error: e("--color-error", "#f87272")
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
-
function
|
|
58
|
+
function T() {
|
|
59
59
|
return typeof window > "u" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function f() {
|
|
62
62
|
return typeof document > "u" ? null : document.documentElement.getAttribute("data-theme");
|
|
63
63
|
}
|
|
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
|
+
});
|
|
78
|
+
}
|
|
64
79
|
function k() {
|
|
65
|
-
if (
|
|
66
|
-
const e =
|
|
80
|
+
if (h()) {
|
|
81
|
+
const e = y(), t = i(() => u(e.resolvedTheme), [e.resolvedTheme]);
|
|
67
82
|
return {
|
|
68
83
|
theme: e.theme,
|
|
69
84
|
resolvedTheme: e.resolvedTheme,
|
|
70
85
|
isDark: e.isDark,
|
|
71
86
|
setTheme: e.setTheme,
|
|
72
|
-
|
|
87
|
+
toggleTheme: e.toggleTheme,
|
|
88
|
+
colors: t,
|
|
73
89
|
systemTheme: e.systemTheme
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
|
-
return
|
|
92
|
+
return v();
|
|
77
93
|
}
|
|
78
|
-
function
|
|
79
|
-
const [
|
|
94
|
+
function v() {
|
|
95
|
+
const [o, e] = d(() => ({
|
|
80
96
|
isDark: !1,
|
|
81
|
-
|
|
97
|
+
themeKey: f()
|
|
82
98
|
}));
|
|
83
|
-
return
|
|
99
|
+
return l(() => {
|
|
84
100
|
const t = () => {
|
|
85
|
-
const s =
|
|
101
|
+
const s = f(), m = T();
|
|
86
102
|
let c = !1;
|
|
87
|
-
s ? c =
|
|
88
|
-
requestAnimationFrame(() => {
|
|
89
|
-
e({
|
|
90
|
-
isDark: c,
|
|
91
|
-
colors: a()
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
});
|
|
103
|
+
s ? c = g.has(s) : c = m === "dark", e({ isDark: c, themeKey: s });
|
|
95
104
|
};
|
|
96
105
|
t();
|
|
97
|
-
const
|
|
98
|
-
|
|
106
|
+
const r = new MutationObserver(t);
|
|
107
|
+
r.observe(document.documentElement, {
|
|
99
108
|
attributes: !0,
|
|
100
109
|
attributeFilter: ["data-theme", "class"]
|
|
101
110
|
});
|
|
102
|
-
const
|
|
103
|
-
return
|
|
104
|
-
|
|
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
|
|
105
125
|
};
|
|
106
|
-
}, [
|
|
107
|
-
theme: void 0,
|
|
108
|
-
resolvedTheme: void 0,
|
|
109
|
-
isDark: r.isDark,
|
|
110
|
-
setTheme: void 0,
|
|
111
|
-
colors: r.colors,
|
|
112
|
-
systemTheme: void 0
|
|
113
|
-
}), [r.isDark, r.colors]);
|
|
126
|
+
}, [o.isDark, o.themeKey]);
|
|
114
127
|
}
|
|
115
128
|
export {
|
|
116
129
|
k as default,
|
|
@@ -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 /** Computed theme colors as hex values */\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\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 * 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 * @example\n * // With ThemeProvider (full control)\n * const { theme, setTheme, resolvedTheme, isDark, colors } = useTheme()\n * setTheme('dark')\n * setTheme('system')\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 we have a provider, use its context\n if (hasProvider) {\n // This is safe because hasProvider is stable after initial render\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const context = useThemeContext()\n return {\n theme: context.theme,\n resolvedTheme: context.resolvedTheme,\n isDark: context.isDark,\n setTheme: context.setTheme,\n colors: context.colors,\n systemTheme: context.systemTheme,\n }\n }\n\n // Standalone mode - no provider\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; colors: ThemeColors }>(() => ({\n isDark: false,\n colors: getThemeColors(),\n }))\n\n useEffect(() => {\n const updateTheme = () => {\n const currentTheme = getCurrentTheme()\n const systemTheme = getSystemTheme()\n\n // Determine if dark based on data-theme or system preference\n let isDark = false\n if (currentTheme) {\n isDark = DARK_THEMES.has(currentTheme)\n } else {\n isDark = systemTheme === 'dark'\n }\n\n // Double RAF ensures CSS has fully recalculated\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setState({\n isDark,\n colors: getThemeColors(),\n })\n })\n })\n }\n\n updateTheme()\n\n // Watch for theme changes via attribute mutation\n const observer = new MutationObserver(updateTheme)\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme', 'class']\n })\n\n // Watch for system preference changes\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: state.isDark,\n setTheme: undefined,\n colors: state.colors,\n systemTheme: undefined,\n }), [state.isDark, state.colors])\n}\n\nexport default useTheme\n"],"names":["DARK_THEMES","colorToHex","color","canvas","ctx","r","g","b","getThemeColors","style","getColor","varName","fallback","value","getSystemTheme","getCurrentTheme","useTheme","useHasThemeProvider","context","useThemeContext","useThemeStandalone","state","setState","useState","useEffect","updateTheme","currentTheme","systemTheme","isDark","observer","mediaQuery","useMemo"],"mappings":"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"}
|
|
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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"}
|
|
@@ -33,8 +33,8 @@ export interface ThemeContextValue {
|
|
|
33
33
|
isDark: boolean;
|
|
34
34
|
/** Set the theme */
|
|
35
35
|
setTheme: (theme: string) => void;
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
/** Toggle between light and dark */
|
|
37
|
+
toggleTheme: () => void;
|
|
38
38
|
/** The system preference ("light" or "dark") */
|
|
39
39
|
systemTheme: 'light' | 'dark';
|
|
40
40
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useState as
|
|
3
|
-
const
|
|
1
|
+
import { jsx as M } from "react/jsx-runtime";
|
|
2
|
+
import { useState as S, useMemo as m, useEffect as l, useCallback as y, createContext as P, useContext as g } from "react";
|
|
3
|
+
const C = /* @__PURE__ */ new Set([
|
|
4
4
|
"dark",
|
|
5
5
|
"synthwave",
|
|
6
6
|
"halloween",
|
|
@@ -13,52 +13,11 @@ const A = /* @__PURE__ */ new Set([
|
|
|
13
13
|
"coffee",
|
|
14
14
|
"dim",
|
|
15
15
|
"sunset"
|
|
16
|
-
]),
|
|
17
|
-
function
|
|
18
|
-
if (typeof document > "u") return "#000000";
|
|
19
|
-
const e = document.createElement("canvas");
|
|
20
|
-
e.width = e.height = 1;
|
|
21
|
-
const n = e.getContext("2d");
|
|
22
|
-
if (!n) return "#000000";
|
|
23
|
-
n.fillStyle = t, n.fillRect(0, 0, 1, 1);
|
|
24
|
-
const [f, o, i] = n.getImageData(0, 0, 1, 1).data;
|
|
25
|
-
return `#${((1 << 24) + (f << 16) + (o << 8) + i).toString(16).slice(1)}`;
|
|
26
|
-
}
|
|
27
|
-
function b() {
|
|
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 t = getComputedStyle(document.documentElement), e = (n, f) => {
|
|
42
|
-
const o = t.getPropertyValue(n).trim();
|
|
43
|
-
return o ? L(o) : f;
|
|
44
|
-
};
|
|
45
|
-
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")
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function M() {
|
|
16
|
+
]), w = P(void 0);
|
|
17
|
+
function k() {
|
|
59
18
|
return typeof window > "u" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
60
19
|
}
|
|
61
|
-
function
|
|
20
|
+
function T(t) {
|
|
62
21
|
if (!t || typeof window > "u") return null;
|
|
63
22
|
try {
|
|
64
23
|
return localStorage.getItem(t);
|
|
@@ -66,65 +25,64 @@ function H(t) {
|
|
|
66
25
|
return null;
|
|
67
26
|
}
|
|
68
27
|
}
|
|
69
|
-
function
|
|
28
|
+
function b(t, f) {
|
|
70
29
|
if (!(!t || typeof window > "u"))
|
|
71
30
|
try {
|
|
72
|
-
localStorage.setItem(t,
|
|
31
|
+
localStorage.setItem(t, f);
|
|
73
32
|
} catch {
|
|
74
33
|
}
|
|
75
34
|
}
|
|
76
|
-
function
|
|
35
|
+
function V({
|
|
77
36
|
children: t,
|
|
78
|
-
defaultTheme:
|
|
79
|
-
storageKey:
|
|
80
|
-
lightTheme:
|
|
81
|
-
darkTheme:
|
|
82
|
-
isDarkTheme:
|
|
37
|
+
defaultTheme: f = "system",
|
|
38
|
+
storageKey: r = "asterui-theme",
|
|
39
|
+
lightTheme: c = "light",
|
|
40
|
+
darkTheme: d = "dark",
|
|
41
|
+
isDarkTheme: s
|
|
83
42
|
}) {
|
|
84
|
-
const [u,
|
|
85
|
-
w(r), I(n, r);
|
|
86
|
-
}, [n]);
|
|
43
|
+
const [u, I] = S(k), [i, a] = S(() => T(r) || f), o = m(() => i === "system" ? u === "dark" ? d : c : i, [i, u, c, d]), h = m(() => s ? s(o) : C.has(o), [o, s]);
|
|
87
44
|
l(() => {
|
|
88
|
-
typeof document > "u" ||
|
|
89
|
-
|
|
90
|
-
S(b());
|
|
91
|
-
});
|
|
92
|
-
}));
|
|
93
|
-
}, [c]), l(() => {
|
|
45
|
+
typeof document > "u" || document.documentElement.setAttribute("data-theme", o);
|
|
46
|
+
}, [o]), l(() => {
|
|
94
47
|
if (typeof window > "u") return;
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
};
|
|
98
|
-
return r.addEventListener("change", s), () => r.removeEventListener("change", s);
|
|
48
|
+
const e = window.matchMedia("(prefers-color-scheme: dark)"), n = (x) => I(x.matches ? "dark" : "light");
|
|
49
|
+
return e.addEventListener("change", n), () => e.removeEventListener("change", n);
|
|
99
50
|
}, []), l(() => {
|
|
100
|
-
if (!
|
|
101
|
-
const
|
|
102
|
-
|
|
51
|
+
if (!r || typeof window > "u") return;
|
|
52
|
+
const e = (n) => {
|
|
53
|
+
n.key === r && n.newValue && a(n.newValue);
|
|
103
54
|
};
|
|
104
|
-
return window.addEventListener("storage",
|
|
105
|
-
}, [
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
55
|
+
return window.addEventListener("storage", e), () => window.removeEventListener("storage", e);
|
|
56
|
+
}, [r]);
|
|
57
|
+
const v = y((e) => {
|
|
58
|
+
a(e), b(r, e);
|
|
59
|
+
}, [r]), p = y(() => {
|
|
60
|
+
a((e) => {
|
|
61
|
+
const n = e === "system" ? u === "dark" ? d : c : e, E = (s ? s(n) : C.has(n)) ? c : d;
|
|
62
|
+
return b(r, E), E;
|
|
63
|
+
});
|
|
64
|
+
}, [u, c, d, s, r]), L = m(() => ({
|
|
65
|
+
theme: i,
|
|
66
|
+
resolvedTheme: o,
|
|
67
|
+
isDark: h,
|
|
68
|
+
setTheme: v,
|
|
69
|
+
toggleTheme: p,
|
|
70
|
+
systemTheme: u
|
|
71
|
+
}), [i, o, h, v, p, u]);
|
|
72
|
+
return /* @__PURE__ */ M(w.Provider, { value: L, children: t });
|
|
115
73
|
}
|
|
116
|
-
function
|
|
117
|
-
const t =
|
|
74
|
+
function j() {
|
|
75
|
+
const t = g(w);
|
|
118
76
|
if (!t)
|
|
119
77
|
throw new Error("useThemeContext must be used within a ThemeProvider");
|
|
120
78
|
return t;
|
|
121
79
|
}
|
|
122
|
-
function
|
|
123
|
-
return
|
|
80
|
+
function q() {
|
|
81
|
+
return g(w) !== void 0;
|
|
124
82
|
}
|
|
125
83
|
export {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
84
|
+
V as ThemeProvider,
|
|
85
|
+
q as useHasThemeProvider,
|
|
86
|
+
j as useThemeContext
|
|
129
87
|
};
|
|
130
88
|
//# sourceMappingURL=ThemeProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.js","sources":["../../src/providers/ThemeProvider.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react'\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 ThemeProviderProps {\n children: React.ReactNode\n /** Default theme. Use \"system\" to follow browser preference. */\n defaultTheme?: string\n /** localStorage key for persisting theme. Set to false to disable persistence. */\n storageKey?: string | false\n /** Light theme to use when system preference is light */\n lightTheme?: string\n /** Dark theme to use when system preference is dark */\n darkTheme?: string\n /** Custom function to determine if a theme is dark */\n isDarkTheme?: (theme: string) => boolean\n}\n\nexport interface ThemeColors {\n background: string\n foreground: string\n primary: string\n primaryContent: string\n secondary: string\n accent: string\n info: string\n success: string\n warning: string\n error: string\n}\n\nexport interface ThemeContextValue {\n /** The theme setting (what user selected: \"system\", \"light\", \"dark\", etc.) */\n theme: string\n /** The actual applied theme after resolving \"system\" */\n resolvedTheme: string\n /** Whether the resolved theme is dark */\n isDark: boolean\n /** Set the theme */\n setTheme: (theme: string) => void\n /** Computed theme colors as hex values (for canvas/non-CSS contexts) */\n colors: ThemeColors\n /** The system preference (\"light\" or \"dark\") */\n systemTheme: 'light' | 'dark'\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined)\n\n// Convert any CSS color to hex\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 getStoredTheme(key: string | false): string | null {\n if (!key || typeof window === 'undefined') return null\n try {\n return localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nfunction storeTheme(key: string | false, theme: string): void {\n if (!key || typeof window === 'undefined') return\n try {\n localStorage.setItem(key, theme)\n } catch {\n // Ignore storage errors\n }\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'system',\n storageKey = 'asterui-theme',\n lightTheme = 'light',\n darkTheme = 'dark',\n isDarkTheme,\n}: ThemeProviderProps) {\n // Initialize theme from storage or default\n const [theme, setThemeState] = useState<string>(() => {\n const stored = getStoredTheme(storageKey)\n return stored || defaultTheme\n })\n\n // Track system preference\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>(getSystemTheme)\n\n // Resolve the actual theme\n const resolvedTheme = useMemo(() => {\n if (theme === 'system') {\n return systemTheme === 'dark' ? darkTheme : lightTheme\n }\n return theme\n }, [theme, systemTheme, lightTheme, darkTheme])\n\n // Determine if dark\n const isDark = useMemo(() => {\n if (isDarkTheme) return isDarkTheme(resolvedTheme)\n return DARK_THEMES.has(resolvedTheme)\n }, [resolvedTheme, isDarkTheme])\n\n // Track colors (updated after theme applies)\n const [colors, setColors] = useState<ThemeColors>(getThemeColors)\n\n // Set theme function\n const setTheme = useCallback((newTheme: string) => {\n setThemeState(newTheme)\n storeTheme(storageKey, newTheme)\n }, [storageKey])\n\n // Apply theme to document\n useEffect(() => {\n if (typeof document === 'undefined') return\n document.documentElement.setAttribute('data-theme', resolvedTheme)\n\n // Double RAF ensures CSS has fully recalculated after attribute change\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setColors(getThemeColors())\n })\n })\n }, [resolvedTheme])\n\n // Listen for system preference changes\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n const handleChange = (e: MediaQueryListEvent) => {\n setSystemTheme(e.matches ? 'dark' : 'light')\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [])\n\n // Listen for storage changes (cross-tab sync)\n useEffect(() => {\n if (!storageKey || typeof window === 'undefined') return\n\n const handleStorage = (e: StorageEvent) => {\n if (e.key === storageKey && e.newValue) {\n setThemeState(e.newValue)\n }\n }\n\n window.addEventListener('storage', handleStorage)\n return () => window.removeEventListener('storage', handleStorage)\n }, [storageKey])\n\n const value = useMemo<ThemeContextValue>(() => ({\n theme,\n resolvedTheme,\n isDark,\n setTheme,\n colors,\n systemTheme,\n }), [theme, resolvedTheme, isDark, setTheme, colors, systemTheme])\n\n return (\n <ThemeContext.Provider value={value}>\n {children}\n </ThemeContext.Provider>\n )\n}\n\n/**\n * Hook to access theme context.\n * Must be used within a ThemeProvider.\n */\nexport function useThemeContext(): ThemeContextValue {\n const context = useContext(ThemeContext)\n if (!context) {\n throw new Error('useThemeContext must be used within a ThemeProvider')\n }\n return context\n}\n\n/**\n * Check if ThemeProvider is present in the tree.\n */\nexport function useHasThemeProvider(): boolean {\n return useContext(ThemeContext) !== undefined\n}\n"],"names":["DARK_THEMES","ThemeContext","createContext","colorToHex","color","canvas","ctx","r","g","b","getThemeColors","style","getColor","varName","fallback","value","getSystemTheme","getStoredTheme","key","storeTheme","theme","ThemeProvider","children","defaultTheme","storageKey","lightTheme","darkTheme","isDarkTheme","setThemeState","useState","systemTheme","setSystemTheme","resolvedTheme","useMemo","isDark","colors","setColors","setTheme","useCallback","newTheme","useEffect","mediaQuery","handleChange","e","handleStorage","jsx","useThemeContext","context","useContext","useHasThemeProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ThemeProvider.js","sources":["../../src/providers/ThemeProvider.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react'\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 ThemeProviderProps {\n children: React.ReactNode\n /** Default theme. Use \"system\" to follow browser preference. */\n defaultTheme?: string\n /** localStorage key for persisting theme. Set to false to disable persistence. */\n storageKey?: string | false\n /** Light theme to use when system preference is light */\n lightTheme?: string\n /** Dark theme to use when system preference is dark */\n darkTheme?: string\n /** Custom function to determine if a theme is dark */\n isDarkTheme?: (theme: string) => boolean\n}\n\nexport interface ThemeColors {\n background: string\n foreground: string\n primary: string\n primaryContent: string\n secondary: string\n accent: string\n info: string\n success: string\n warning: string\n error: string\n}\n\nexport interface ThemeContextValue {\n /** The theme setting (what user selected: \"system\", \"light\", \"dark\", etc.) */\n theme: string\n /** The actual applied theme after resolving \"system\" */\n resolvedTheme: string\n /** Whether the resolved theme is dark */\n isDark: boolean\n /** Set the theme */\n setTheme: (theme: string) => void\n /** Toggle between light and dark */\n toggleTheme: () => void\n /** The system preference (\"light\" or \"dark\") */\n systemTheme: 'light' | 'dark'\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined)\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 getStoredTheme(key: string | false): string | null {\n if (!key || typeof window === 'undefined') return null\n try {\n return localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nfunction storeTheme(key: string | false, theme: string): void {\n if (!key || typeof window === 'undefined') return\n try {\n localStorage.setItem(key, theme)\n } catch {\n // Ignore storage errors\n }\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'system',\n storageKey = 'asterui-theme',\n lightTheme = 'light',\n darkTheme = 'dark',\n isDarkTheme,\n}: ThemeProviderProps) {\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>(getSystemTheme)\n\n const [theme, setThemeState] = useState<string>(() => {\n return getStoredTheme(storageKey) || defaultTheme\n })\n\n const resolvedTheme = useMemo(() => {\n if (theme === 'system') {\n return systemTheme === 'dark' ? darkTheme : lightTheme\n }\n return theme\n }, [theme, systemTheme, lightTheme, darkTheme])\n\n const isDark = useMemo(() => {\n if (isDarkTheme) return isDarkTheme(resolvedTheme)\n return DARK_THEMES.has(resolvedTheme)\n }, [resolvedTheme, isDarkTheme])\n\n // Set data-theme on <html>\n useEffect(() => {\n if (typeof document === 'undefined') return\n document.documentElement.setAttribute('data-theme', resolvedTheme)\n }, [resolvedTheme])\n\n // Listen for system preference changes\n useEffect(() => {\n if (typeof window === 'undefined') return\n const mq = window.matchMedia('(prefers-color-scheme: dark)')\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light')\n mq.addEventListener('change', handler)\n return () => mq.removeEventListener('change', handler)\n }, [])\n\n // Listen for storage changes (cross-tab sync)\n useEffect(() => {\n if (!storageKey || typeof window === 'undefined') return\n const handler = (e: StorageEvent) => {\n if (e.key === storageKey && e.newValue) {\n setThemeState(e.newValue)\n }\n }\n window.addEventListener('storage', handler)\n return () => window.removeEventListener('storage', handler)\n }, [storageKey])\n\n const setTheme = useCallback((t: string) => {\n setThemeState(t)\n storeTheme(storageKey, t)\n }, [storageKey])\n\n const toggleTheme = useCallback(() => {\n setThemeState((current) => {\n const resolved = current === 'system'\n ? (systemTheme === 'dark' ? darkTheme : lightTheme)\n : current\n const currentIsDark = isDarkTheme ? isDarkTheme(resolved) : DARK_THEMES.has(resolved)\n const next = currentIsDark ? lightTheme : darkTheme\n storeTheme(storageKey, next)\n return next\n })\n }, [systemTheme, lightTheme, darkTheme, isDarkTheme, storageKey])\n\n const value = useMemo<ThemeContextValue>(() => ({\n theme, resolvedTheme, isDark, setTheme, toggleTheme, systemTheme,\n }), [theme, resolvedTheme, isDark, setTheme, toggleTheme, systemTheme])\n\n return (\n <ThemeContext.Provider value={value}>\n {children}\n </ThemeContext.Provider>\n )\n}\n\n/**\n * Hook to access theme context.\n * Must be used within a ThemeProvider.\n */\nexport function useThemeContext(): ThemeContextValue {\n const context = useContext(ThemeContext)\n if (!context) {\n throw new Error('useThemeContext must be used within a ThemeProvider')\n }\n return context\n}\n\n/**\n * Check if ThemeProvider is present in the tree.\n */\nexport function useHasThemeProvider(): boolean {\n return useContext(ThemeContext) !== undefined\n}\n"],"names":["DARK_THEMES","ThemeContext","createContext","getSystemTheme","getStoredTheme","key","storeTheme","theme","ThemeProvider","children","defaultTheme","storageKey","lightTheme","darkTheme","isDarkTheme","systemTheme","setSystemTheme","useState","setThemeState","resolvedTheme","useMemo","isDark","useEffect","mq","handler","e","setTheme","useCallback","t","toggleTheme","current","resolved","next","value","jsx","useThemeContext","context","useContext","useHasThemeProvider"],"mappings":"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"}
|