@aster-ui/prefixed 0.12.87 → 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.
@@ -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
- /** Computed theme colors as hex values */
12
+ /** Toggle between light and dark. Only available with ThemeProvider. */
13
+ toggleTheme: (() => void) | undefined;
14
+ /** Computed theme colors as hex values. Computed asynchronously after theme changes. */
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 computed asynchronously after mount and theme changes,
30
+ * using DOM-based color conversion (no canvas).
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)
@@ -1,6 +1,6 @@
1
- import { useState as i, useEffect as m, useMemo as u } from "react";
2
- import { useHasThemeProvider as d, useThemeContext as l } from "../providers/ThemeProvider.js";
3
- const h = /* @__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,107 +13,106 @@ const h = /* @__PURE__ */ new Set([
13
13
  "coffee",
14
14
  "dim",
15
15
  "sunset"
16
- ]);
17
- function g(r) {
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 = r, t.fillRect(0, 0, 1, 1);
24
- const [n, o, s] = t.getImageData(0, 0, 1, 1).data;
25
- return `#${((1 << 24) + (n << 16) + (o << 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 r = getComputedStyle(document.documentElement), e = (t, n) => {
42
- const o = r.getPropertyValue(t).trim();
43
- return o ? g(o) : n;
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 y() {
59
+ function k() {
59
60
  return typeof window > "u" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
60
61
  }
61
- function b() {
62
+ function C() {
62
63
  return typeof document > "u" ? null : document.documentElement.getAttribute("data-theme");
63
64
  }
64
- function k() {
65
- if (d()) {
66
- const e = l();
67
- return {
68
- theme: e.theme,
69
- resolvedTheme: e.resolvedTheme,
70
- isDark: e.isDark,
71
- setTheme: e.setTheme,
72
- colors: e.colors,
73
- systemTheme: e.systemTheme
74
- };
75
- }
76
- return T();
65
+ function x() {
66
+ return b() ? S() : E();
67
+ }
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]);
77
83
  }
78
- function T() {
79
- const [r, e] = i(() => ({
80
- isDark: !1,
81
- colors: a()
82
- }));
83
- return m(() => {
84
- const t = () => {
85
- const s = b(), f = y();
86
- let c = !1;
87
- s ? c = h.has(s) : c = f === "dark", requestAnimationFrame(() => {
88
- requestAnimationFrame(() => {
89
- e({
90
- isDark: c,
91
- colors: a()
92
- });
93
- });
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());
94
92
  });
95
93
  };
96
- t();
97
- const n = new MutationObserver(t);
98
- n.observe(document.documentElement, {
94
+ r();
95
+ const c = new MutationObserver(r);
96
+ c.observe(document.documentElement, {
99
97
  attributes: !0,
100
98
  attributeFilter: ["data-theme", "class"]
101
99
  });
102
- const o = window.matchMedia("(prefers-color-scheme: dark)");
103
- return o.addEventListener("change", t), () => {
104
- n.disconnect(), o.removeEventListener("change", t);
100
+ const m = window.matchMedia("(prefers-color-scheme: dark)");
101
+ return m.addEventListener("change", r), () => {
102
+ c.disconnect(), m.removeEventListener("change", r);
105
103
  };
106
- }, []), u(() => ({
104
+ }, []), l(() => ({
107
105
  theme: void 0,
108
106
  resolvedTheme: void 0,
109
- isDark: r.isDark,
107
+ isDark: e,
110
108
  setTheme: void 0,
111
- colors: r.colors,
109
+ toggleTheme: void 0,
110
+ colors: s,
112
111
  systemTheme: void 0
113
- }), [r.isDark, r.colors]);
112
+ }), [e, s]);
114
113
  }
115
114
  export {
116
- k as default,
117
- k as useTheme
115
+ x as default,
116
+ x as useTheme
118
117
  };
119
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 /** 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, 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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"}
@@ -33,8 +33,8 @@ export interface ThemeContextValue {
33
33
  isDark: boolean;
34
34
  /** Set the theme */
35
35
  setTheme: (theme: string) => void;
36
- /** Computed theme colors as hex values (for canvas/non-CSS contexts) */
37
- colors: ThemeColors;
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 E } from "react/jsx-runtime";
2
- import { useState as d, useMemo as m, useCallback as k, useEffect as l, createContext as P, useContext as v } from "react";
3
- const A = /* @__PURE__ */ new Set([
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
- ]), h = P(void 0);
17
- function L(t) {
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 H(t) {
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 I(t, e) {
28
+ function b(t, f) {
70
29
  if (!(!t || typeof window > "u"))
71
30
  try {
72
- localStorage.setItem(t, e);
31
+ localStorage.setItem(t, f);
73
32
  } catch {
74
33
  }
75
34
  }
76
- function F({
35
+ function V({
77
36
  children: t,
78
- defaultTheme: e = "system",
79
- storageKey: n = "asterui-theme",
80
- lightTheme: f = "light",
81
- darkTheme: o = "dark",
82
- isDarkTheme: i
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, w] = d(() => H(n) || e), [a, C] = d(M), c = m(() => u === "system" ? a === "dark" ? o : f : u, [u, a, f, o]), g = m(() => i ? i(c) : A.has(c), [c, i]), [y, S] = d(b), p = k((r) => {
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" || (document.documentElement.setAttribute("data-theme", c), requestAnimationFrame(() => {
89
- requestAnimationFrame(() => {
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 r = window.matchMedia("(prefers-color-scheme: dark)"), s = (T) => {
96
- C(T.matches ? "dark" : "light");
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 (!n || typeof window > "u") return;
101
- const r = (s) => {
102
- s.key === n && s.newValue && w(s.newValue);
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", r), () => window.removeEventListener("storage", r);
105
- }, [n]);
106
- const x = m(() => ({
107
- theme: u,
108
- resolvedTheme: c,
109
- isDark: g,
110
- setTheme: p,
111
- colors: y,
112
- systemTheme: a
113
- }), [u, c, g, p, y, a]);
114
- return /* @__PURE__ */ E(h.Provider, { value: x, children: t });
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 R() {
117
- const t = v(h);
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 j() {
123
- return v(h) !== void 0;
80
+ function q() {
81
+ return g(w) !== void 0;
124
82
  }
125
83
  export {
126
- F as ThemeProvider,
127
- j as useHasThemeProvider,
128
- R as useThemeContext
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":";;AAGA,MAAMA,wBAAkB,IAAI;AAAA,EAC1B;AAAA,EAAQ;AAAA,EAAa;AAAA,EAAa;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAC/D;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAAA,EAAO;AACxC,CAAC,GA4CKC,IAAeC,EAA6C,MAAS;AAE3E,SAASC,IAAmC;AAC1C,SAAI,OAAO,SAAW,MAAoB,UACnC,OAAO,WAAW,8BAA8B,EAAE,UAAU,SAAS;AAC9E;AAEA,SAASC,EAAeC,GAAoC;AAC1D,MAAI,CAACA,KAAO,OAAO,SAAW,IAAa,QAAO;AAClD,MAAI;AACF,WAAO,aAAa,QAAQA,CAAG;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAASC,EAAWD,GAAqBE,GAAqB;AAC5D,MAAI,GAACF,KAAO,OAAO,SAAW;AAC9B,QAAI;AACF,mBAAa,QAAQA,GAAKE,CAAK;AAAA,IACjC,QAAQ;AAAA,IAER;AACF;AAEO,SAASC,EAAc;AAAA,EAC5B,UAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,YAAAC,IAAa;AAAA,EACb,YAAAC,IAAa;AAAA,EACb,WAAAC,IAAY;AAAA,EACZ,aAAAC;AACF,GAAuB;AACrB,QAAM,CAACC,GAAaC,CAAc,IAAIC,EAA2Bd,CAAc,GAEzE,CAACI,GAAOW,CAAa,IAAID,EAAiB,MACvCb,EAAeO,CAAU,KAAKD,CACtC,GAEKS,IAAgBC,EAAQ,MACxBb,MAAU,WACLQ,MAAgB,SAASF,IAAYD,IAEvCL,GACN,CAACA,GAAOQ,GAAaH,GAAYC,CAAS,CAAC,GAExCQ,IAASD,EAAQ,MACjBN,IAAoBA,EAAYK,CAAa,IAC1CnB,EAAY,IAAImB,CAAa,GACnC,CAACA,GAAeL,CAAW,CAAC;AAG/B,EAAAQ,EAAU,MAAM;AACd,IAAI,OAAO,WAAa,OACxB,SAAS,gBAAgB,aAAa,cAAcH,CAAa;AAAA,EACnE,GAAG,CAACA,CAAa,CAAC,GAGlBG,EAAU,MAAM;AACd,QAAI,OAAO,SAAW,IAAa;AACnC,UAAMC,IAAK,OAAO,WAAW,8BAA8B,GACrDC,IAAU,CAACC,MAA2BT,EAAeS,EAAE,UAAU,SAAS,OAAO;AACvF,WAAAF,EAAG,iBAAiB,UAAUC,CAAO,GAC9B,MAAMD,EAAG,oBAAoB,UAAUC,CAAO;AAAA,EACvD,GAAG,CAAA,CAAE,GAGLF,EAAU,MAAM;AACd,QAAI,CAACX,KAAc,OAAO,SAAW,IAAa;AAClD,UAAMa,IAAU,CAACC,MAAoB;AACnC,MAAIA,EAAE,QAAQd,KAAcc,EAAE,YAC5BP,EAAcO,EAAE,QAAQ;AAAA,IAE5B;AACA,kBAAO,iBAAiB,WAAWD,CAAO,GACnC,MAAM,OAAO,oBAAoB,WAAWA,CAAO;AAAA,EAC5D,GAAG,CAACb,CAAU,CAAC;AAEf,QAAMe,IAAWC,EAAY,CAACC,MAAc;AAC1C,IAAAV,EAAcU,CAAC,GACftB,EAAWK,GAAYiB,CAAC;AAAA,EAC1B,GAAG,CAACjB,CAAU,CAAC,GAETkB,IAAcF,EAAY,MAAM;AACpC,IAAAT,EAAc,CAACY,MAAY;AACzB,YAAMC,IAAWD,MAAY,WACxBf,MAAgB,SAASF,IAAYD,IACtCkB,GAEEE,KADgBlB,IAAcA,EAAYiB,CAAQ,IAAI/B,EAAY,IAAI+B,CAAQ,KACvDnB,IAAaC;AAC1C,aAAAP,EAAWK,GAAYqB,CAAI,GACpBA;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAACjB,GAAaH,GAAYC,GAAWC,GAAaH,CAAU,CAAC,GAE1DsB,IAAQb,EAA2B,OAAO;AAAA,IAC9C,OAAAb;AAAA,IAAO,eAAAY;AAAA,IAAe,QAAAE;AAAA,IAAQ,UAAAK;AAAA,IAAU,aAAAG;AAAA,IAAa,aAAAd;AAAA,EAAA,IACnD,CAACR,GAAOY,GAAeE,GAAQK,GAAUG,GAAad,CAAW,CAAC;AAEtE,SACE,gBAAAmB,EAACjC,EAAa,UAAb,EAAsB,OAAAgC,GACpB,UAAAxB,EAAA,CACH;AAEJ;AAMO,SAAS0B,IAAqC;AACnD,QAAMC,IAAUC,EAAWpC,CAAY;AACvC,MAAI,CAACmC;AACH,UAAM,IAAI,MAAM,qDAAqD;AAEvE,SAAOA;AACT;AAKO,SAASE,IAA+B;AAC7C,SAAOD,EAAWpC,CAAY,MAAM;AACtC;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aster-ui/prefixed",
3
- "version": "0.12.87",
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": {