@work-rjkashyap/unified-ui 0.1.2 → 0.2.0
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/CHANGELOG.md +93 -0
- package/bin/cli.mjs +721 -0
- package/dist/{chunk-EO4WROWH.mjs → chunk-3OZJ4JLW.mjs} +116 -2
- package/dist/chunk-B3CW2WZS.cjs +20748 -0
- package/dist/chunk-CTWNFFLB.mjs +20438 -0
- package/dist/{chunk-7ITQSRGX.cjs → chunk-FUWXGHWQ.cjs} +0 -1
- package/dist/{chunk-ZPIPKY2J.cjs → chunk-HITTFB2U.cjs} +127 -1
- package/dist/{chunk-F5S6NLOT.mjs → chunk-OHEH57BV.mjs} +0 -1
- package/dist/{chunk-PQR7C4OH.cjs → chunk-TESKVASH.cjs} +332 -99
- package/dist/{chunk-ZDB557B2.mjs → chunk-YFH5JPAA.mjs} +331 -101
- package/dist/components.cjs +780 -126
- package/dist/components.d.cts +5183 -1464
- package/dist/components.d.ts +5183 -1464
- package/dist/components.mjs +3 -1
- package/dist/index.cjs +926 -214
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.mjs +5 -5
- package/dist/motion.cjs +94 -46
- package/dist/motion.d.cts +53 -2
- package/dist/motion.d.ts +53 -2
- package/dist/motion.mjs +1 -1
- package/dist/primitives.cjs +13 -13
- package/dist/primitives.mjs +1 -1
- package/dist/theme.cjs +40 -28
- package/dist/theme.d.cts +100 -62
- package/dist/theme.d.ts +100 -62
- package/dist/theme.mjs +1 -1
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +190 -183
- package/styles.css +636 -473
- package/dist/chunk-4NYLE2LT.cjs +0 -10042
- package/dist/chunk-A4YYJAAJ.mjs +0 -9897
|
@@ -212,96 +212,6 @@ var cssVar = {
|
|
|
212
212
|
/** Returns the raw `var(--<key>)` — same as color() since values are complete oklch */
|
|
213
213
|
colorChannels: (key) => `var(${colorVarNames[key]})`
|
|
214
214
|
};
|
|
215
|
-
var DSThemeContext = react.createContext(null);
|
|
216
|
-
function useDSTheme() {
|
|
217
|
-
const ctx = react.useContext(DSThemeContext);
|
|
218
|
-
if (!ctx) {
|
|
219
|
-
throw new Error(
|
|
220
|
-
"useDSTheme must be used within a <DSThemeProvider>. Wrap your application (or layout) with <DSThemeProvider>."
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
return ctx;
|
|
224
|
-
}
|
|
225
|
-
function getSystemPreference() {
|
|
226
|
-
if (typeof window === "undefined") return "light";
|
|
227
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
228
|
-
}
|
|
229
|
-
function resolveTheme(theme) {
|
|
230
|
-
if (theme === "system") return getSystemPreference();
|
|
231
|
-
return theme;
|
|
232
|
-
}
|
|
233
|
-
var STORAGE_KEY = "ds-theme-preference";
|
|
234
|
-
function getStoredTheme() {
|
|
235
|
-
if (typeof window === "undefined") return "system";
|
|
236
|
-
try {
|
|
237
|
-
const stored = localStorage.getItem(STORAGE_KEY);
|
|
238
|
-
if (stored === "light" || stored === "dark" || stored === "system") {
|
|
239
|
-
return stored;
|
|
240
|
-
}
|
|
241
|
-
} catch {
|
|
242
|
-
}
|
|
243
|
-
return "system";
|
|
244
|
-
}
|
|
245
|
-
function storeTheme(theme) {
|
|
246
|
-
try {
|
|
247
|
-
localStorage.setItem(STORAGE_KEY, theme);
|
|
248
|
-
} catch {
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
function DSThemeProvider({
|
|
252
|
-
children,
|
|
253
|
-
defaultTheme,
|
|
254
|
-
manageHtmlClass = false
|
|
255
|
-
}) {
|
|
256
|
-
const [theme, setThemeState] = react.useState(
|
|
257
|
-
() => defaultTheme ?? getStoredTheme()
|
|
258
|
-
);
|
|
259
|
-
const [systemPreference, setSystemPreference] = react.useState("light");
|
|
260
|
-
react.useEffect(() => {
|
|
261
|
-
setSystemPreference(getSystemPreference());
|
|
262
|
-
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
263
|
-
const handler = (e) => {
|
|
264
|
-
setSystemPreference(e.matches ? "dark" : "light");
|
|
265
|
-
};
|
|
266
|
-
mql.addEventListener("change", handler);
|
|
267
|
-
return () => mql.removeEventListener("change", handler);
|
|
268
|
-
}, []);
|
|
269
|
-
const resolvedTheme = react.useMemo(
|
|
270
|
-
() => theme === "system" ? systemPreference : theme,
|
|
271
|
-
[theme, systemPreference]
|
|
272
|
-
);
|
|
273
|
-
react.useEffect(() => {
|
|
274
|
-
if (!manageHtmlClass) return;
|
|
275
|
-
const root = document.documentElement;
|
|
276
|
-
if (resolvedTheme === "dark") {
|
|
277
|
-
root.classList.add("dark");
|
|
278
|
-
} else {
|
|
279
|
-
root.classList.remove("dark");
|
|
280
|
-
}
|
|
281
|
-
}, [resolvedTheme, manageHtmlClass]);
|
|
282
|
-
const setTheme = react.useCallback((newTheme) => {
|
|
283
|
-
setThemeState(newTheme);
|
|
284
|
-
storeTheme(newTheme);
|
|
285
|
-
}, []);
|
|
286
|
-
const toggleTheme = react.useCallback(() => {
|
|
287
|
-
setThemeState((current) => {
|
|
288
|
-
const resolved = resolveTheme(current);
|
|
289
|
-
const next = resolved === "dark" ? "light" : "dark";
|
|
290
|
-
storeTheme(next);
|
|
291
|
-
return next;
|
|
292
|
-
});
|
|
293
|
-
}, []);
|
|
294
|
-
const value = react.useMemo(
|
|
295
|
-
() => ({
|
|
296
|
-
theme,
|
|
297
|
-
resolvedTheme,
|
|
298
|
-
setTheme,
|
|
299
|
-
toggleTheme
|
|
300
|
-
}),
|
|
301
|
-
[theme, resolvedTheme, setTheme, toggleTheme]
|
|
302
|
-
);
|
|
303
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DSThemeContext.Provider, { value, children });
|
|
304
|
-
}
|
|
305
215
|
|
|
306
216
|
// src/theme/presets.ts
|
|
307
217
|
var STATUS_LIGHT = {
|
|
@@ -841,7 +751,119 @@ var SURFACE_STYLE_PRESETS = [
|
|
|
841
751
|
}
|
|
842
752
|
];
|
|
843
753
|
var DEFAULT_SURFACE_STYLE_KEY = "bordered";
|
|
754
|
+
var STYLE_PRESETS = [
|
|
755
|
+
{
|
|
756
|
+
name: "Vega",
|
|
757
|
+
key: "vega",
|
|
758
|
+
description: "The classic shadcn/ui look. Clean, neutral, and familiar.",
|
|
759
|
+
iconPath: "M3 3h18v18H3V3zm2 2v14h14V5H7z",
|
|
760
|
+
defaults: {
|
|
761
|
+
radius: "0.625",
|
|
762
|
+
font: "outfit",
|
|
763
|
+
shadow: "default",
|
|
764
|
+
surfaceStyle: "bordered"
|
|
765
|
+
},
|
|
766
|
+
vars: {
|
|
767
|
+
spacingUnit: "1",
|
|
768
|
+
paddingCard: "1.5rem",
|
|
769
|
+
paddingButtonX: "1rem",
|
|
770
|
+
paddingButtonY: "0.5rem",
|
|
771
|
+
gapDefault: "0.75rem",
|
|
772
|
+
borderWidth: "1px",
|
|
773
|
+
controlHeight: "2.25rem"
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
name: "Nova",
|
|
778
|
+
key: "nova",
|
|
779
|
+
description: "Reduced padding and margins for compact layouts.",
|
|
780
|
+
iconPath: "M4 4h16v16H4V4zm1.5 1.5v13h13v-13h-13z",
|
|
781
|
+
defaults: {
|
|
782
|
+
radius: "0.5",
|
|
783
|
+
font: "inter",
|
|
784
|
+
shadow: "subtle",
|
|
785
|
+
surfaceStyle: "bordered"
|
|
786
|
+
},
|
|
787
|
+
vars: {
|
|
788
|
+
spacingUnit: "0.875",
|
|
789
|
+
paddingCard: "1rem",
|
|
790
|
+
paddingButtonX: "0.75rem",
|
|
791
|
+
paddingButtonY: "0.375rem",
|
|
792
|
+
gapDefault: "0.5rem",
|
|
793
|
+
borderWidth: "1px",
|
|
794
|
+
controlHeight: "2rem"
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
name: "Maia",
|
|
799
|
+
key: "maia",
|
|
800
|
+
description: "Soft and rounded, with generous spacing.",
|
|
801
|
+
iconPath: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z",
|
|
802
|
+
defaults: {
|
|
803
|
+
radius: "0.75",
|
|
804
|
+
font: "outfit",
|
|
805
|
+
shadow: "default",
|
|
806
|
+
surfaceStyle: "mixed"
|
|
807
|
+
},
|
|
808
|
+
vars: {
|
|
809
|
+
spacingUnit: "1.125",
|
|
810
|
+
paddingCard: "1.75rem",
|
|
811
|
+
paddingButtonX: "1.25rem",
|
|
812
|
+
paddingButtonY: "0.625rem",
|
|
813
|
+
gapDefault: "1rem",
|
|
814
|
+
borderWidth: "1px",
|
|
815
|
+
controlHeight: "2.5rem"
|
|
816
|
+
}
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
name: "Lyra",
|
|
820
|
+
key: "lyra",
|
|
821
|
+
description: "Boxy and sharp. Pairs well with mono fonts.",
|
|
822
|
+
iconPath: "M3 3h18v18H3V3zm1 1v16h16V4H4z",
|
|
823
|
+
defaults: {
|
|
824
|
+
radius: "0",
|
|
825
|
+
font: "system",
|
|
826
|
+
shadow: "none",
|
|
827
|
+
surfaceStyle: "bordered"
|
|
828
|
+
},
|
|
829
|
+
vars: {
|
|
830
|
+
spacingUnit: "1",
|
|
831
|
+
paddingCard: "1.25rem",
|
|
832
|
+
paddingButtonX: "1rem",
|
|
833
|
+
paddingButtonY: "0.5rem",
|
|
834
|
+
gapDefault: "0.75rem",
|
|
835
|
+
borderWidth: "1px",
|
|
836
|
+
controlHeight: "2.25rem"
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
name: "Mira",
|
|
841
|
+
key: "mira",
|
|
842
|
+
description: "Compact. Made for dense interfaces.",
|
|
843
|
+
iconPath: "M5 3h14a2 2 0 012 2v14a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2zm0 2v14h14V5H5zm2 2h10v2H7V7zm0 4h10v2H7v-2zm0 4h7v2H7v-2z",
|
|
844
|
+
defaults: {
|
|
845
|
+
radius: "0.375",
|
|
846
|
+
font: "inter",
|
|
847
|
+
shadow: "none",
|
|
848
|
+
surfaceStyle: "bordered"
|
|
849
|
+
},
|
|
850
|
+
vars: {
|
|
851
|
+
spacingUnit: "0.75",
|
|
852
|
+
paddingCard: "0.75rem",
|
|
853
|
+
paddingButtonX: "0.625rem",
|
|
854
|
+
paddingButtonY: "0.25rem",
|
|
855
|
+
gapDefault: "0.375rem",
|
|
856
|
+
borderWidth: "1px",
|
|
857
|
+
controlHeight: "1.75rem"
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
];
|
|
861
|
+
var DEFAULT_STYLE_KEY = "vega";
|
|
862
|
+
function getStylePreset(key) {
|
|
863
|
+
return STYLE_PRESETS.find((s) => s.key === key) ?? STYLE_PRESETS[0];
|
|
864
|
+
}
|
|
844
865
|
var DEFAULT_THEME_CONFIG = {
|
|
866
|
+
style: DEFAULT_STYLE_KEY,
|
|
845
867
|
colorPreset: "zinc",
|
|
846
868
|
radius: DEFAULT_RADIUS_KEY,
|
|
847
869
|
font: DEFAULT_FONT_KEY,
|
|
@@ -927,7 +949,15 @@ function buildThemeOverrides(config, mode) {
|
|
|
927
949
|
}
|
|
928
950
|
}
|
|
929
951
|
const radiusPreset = getRadiusPreset(config.radius);
|
|
952
|
+
const baseRem = Number.parseFloat(radiusPreset.value);
|
|
953
|
+
const isZero = radiusPreset.key === "0";
|
|
930
954
|
vars["--radius"] = radiusPreset.value;
|
|
955
|
+
vars["--radius-none"] = "0px";
|
|
956
|
+
vars["--radius-sm"] = isZero ? "0px" : `${Math.max(baseRem * 0.4, 0.125)}rem`;
|
|
957
|
+
vars["--radius-md"] = isZero ? "0px" : `${Math.max(baseRem * 0.6, 0.25)}rem`;
|
|
958
|
+
vars["--radius-lg"] = isZero ? "0px" : `${Math.max(baseRem * 0.8, 0.375)}rem`;
|
|
959
|
+
vars["--radius-xl"] = isZero ? "0px" : `${Math.max(baseRem * 1.2, 0.5)}rem`;
|
|
960
|
+
vars["--radius-full"] = "9999px";
|
|
931
961
|
const fontPreset = getFontPreset(config.font);
|
|
932
962
|
vars["--font-sans"] = fontPreset.value;
|
|
933
963
|
const shadowPreset = getShadowPreset(config.shadow);
|
|
@@ -939,6 +969,23 @@ function buildThemeOverrides(config, mode) {
|
|
|
939
969
|
vars["--shadow-lg"] = shadows.lg;
|
|
940
970
|
vars["--shadow-xl"] = shadows.xl;
|
|
941
971
|
vars["--shadow-2xl"] = shadows["2xl"];
|
|
972
|
+
const stylePreset = getStylePreset(config.style);
|
|
973
|
+
const sv = stylePreset.vars;
|
|
974
|
+
vars["--ds-spacing-unit"] = sv.spacingUnit;
|
|
975
|
+
vars["--ds-padding-card"] = sv.paddingCard;
|
|
976
|
+
vars["--ds-padding-button-x"] = sv.paddingButtonX;
|
|
977
|
+
vars["--ds-padding-button-y"] = sv.paddingButtonY;
|
|
978
|
+
vars["--ds-gap-default"] = sv.gapDefault;
|
|
979
|
+
vars["--ds-border-width"] = sv.borderWidth;
|
|
980
|
+
vars["--ds-control-height"] = sv.controlHeight;
|
|
981
|
+
if (config.surfaceStyle === "elevated") {
|
|
982
|
+
vars["--card"] = mode === "dark" ? "oklch(0.205 0 0)" : "oklch(1 0 0)";
|
|
983
|
+
vars["--border"] = mode === "dark" ? "oklch(0.205 0 0 / 0)" : "oklch(0.922 0 0 / 0)";
|
|
984
|
+
vars["--border-muted"] = mode === "dark" ? "oklch(0.205 0 0 / 0)" : "oklch(0.922 0 0 / 0)";
|
|
985
|
+
} else if (config.surfaceStyle === "mixed") {
|
|
986
|
+
vars["--border"] = mode === "dark" ? "oklch(0.4 0 0 / 0.15)" : "oklch(0.8 0 0 / 0.3)";
|
|
987
|
+
vars["--border-muted"] = mode === "dark" ? "oklch(0.4 0 0 / 0.1)" : "oklch(0.85 0 0 / 0.25)";
|
|
988
|
+
}
|
|
942
989
|
return vars;
|
|
943
990
|
}
|
|
944
991
|
function generateThemeCSS(config) {
|
|
@@ -949,6 +996,7 @@ function generateThemeCSS(config) {
|
|
|
949
996
|
"/* ============================================",
|
|
950
997
|
" * Unified UI \u2014 Custom Theme",
|
|
951
998
|
` * Preset: ${getColorPreset(config.colorPreset).name}`,
|
|
999
|
+
` * Style: ${getStylePreset(config.style).name}`,
|
|
952
1000
|
` * Radius: ${getRadiusPreset(config.radius).label}`,
|
|
953
1001
|
` * Font: ${getFontPreset(config.font).name}`,
|
|
954
1002
|
` * Shadows: ${getShadowPreset(config.shadow).name}`,
|
|
@@ -963,7 +1011,7 @@ function generateThemeCSS(config) {
|
|
|
963
1011
|
"}"
|
|
964
1012
|
].join("\n");
|
|
965
1013
|
}
|
|
966
|
-
var
|
|
1014
|
+
var STORAGE_KEY = "ds-theme-customizer";
|
|
967
1015
|
var STYLE_ELEMENT_ID = "ds-theme-customizer";
|
|
968
1016
|
var ThemeCustomizerContext = react.createContext(null);
|
|
969
1017
|
function useThemeCustomizer() {
|
|
@@ -978,10 +1026,11 @@ function useThemeCustomizer() {
|
|
|
978
1026
|
function loadConfig() {
|
|
979
1027
|
if (typeof window === "undefined") return DEFAULT_THEME_CONFIG;
|
|
980
1028
|
try {
|
|
981
|
-
const raw = localStorage.getItem(
|
|
1029
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
982
1030
|
if (!raw) return DEFAULT_THEME_CONFIG;
|
|
983
1031
|
const parsed = JSON.parse(raw);
|
|
984
1032
|
return {
|
|
1033
|
+
style: STYLE_PRESETS.some((s) => s.key === parsed.style) ? parsed.style : DEFAULT_THEME_CONFIG.style,
|
|
985
1034
|
colorPreset: COLOR_PRESET_KEYS.includes(parsed.colorPreset ?? "") ? parsed.colorPreset : DEFAULT_THEME_CONFIG.colorPreset,
|
|
986
1035
|
radius: RADIUS_PRESETS.some((r) => r.key === parsed.radius) ? parsed.radius : DEFAULT_THEME_CONFIG.radius,
|
|
987
1036
|
font: FONT_PRESETS.some((f) => f.key === parsed.font) ? parsed.font : DEFAULT_THEME_CONFIG.font,
|
|
@@ -997,7 +1046,7 @@ function loadConfig() {
|
|
|
997
1046
|
function saveConfig(config) {
|
|
998
1047
|
if (typeof window === "undefined") return;
|
|
999
1048
|
try {
|
|
1000
|
-
localStorage.setItem(
|
|
1049
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
|
|
1001
1050
|
} catch {
|
|
1002
1051
|
}
|
|
1003
1052
|
}
|
|
@@ -1007,7 +1056,9 @@ function getResolvedMode() {
|
|
|
1007
1056
|
}
|
|
1008
1057
|
function injectStyles(config) {
|
|
1009
1058
|
if (typeof document === "undefined") return;
|
|
1010
|
-
let styleEl = document.getElementById(
|
|
1059
|
+
let styleEl = document.getElementById(
|
|
1060
|
+
STYLE_ELEMENT_ID
|
|
1061
|
+
);
|
|
1011
1062
|
if (!styleEl) {
|
|
1012
1063
|
styleEl = document.createElement("style");
|
|
1013
1064
|
styleEl.id = STYLE_ELEMENT_ID;
|
|
@@ -1030,7 +1081,7 @@ function removeStyles() {
|
|
|
1030
1081
|
}
|
|
1031
1082
|
}
|
|
1032
1083
|
function configsEqual(a, b) {
|
|
1033
|
-
return a.colorPreset === b.colorPreset && a.radius === b.radius && a.font === b.font && a.shadow === b.shadow && a.surfaceStyle === b.surfaceStyle;
|
|
1084
|
+
return a.style === b.style && a.colorPreset === b.colorPreset && a.radius === b.radius && a.font === b.font && a.shadow === b.shadow && a.surfaceStyle === b.surfaceStyle;
|
|
1034
1085
|
}
|
|
1035
1086
|
function ThemeCustomizerProvider({
|
|
1036
1087
|
children,
|
|
@@ -1040,7 +1091,7 @@ function ThemeCustomizerProvider({
|
|
|
1040
1091
|
const [config, setConfigState] = react.useState(
|
|
1041
1092
|
() => defaultConfig ?? loadConfig()
|
|
1042
1093
|
);
|
|
1043
|
-
const [
|
|
1094
|
+
const [_resolvedMode, setResolvedMode] = react.useState("light");
|
|
1044
1095
|
const configRef = react.useRef(config);
|
|
1045
1096
|
configRef.current = config;
|
|
1046
1097
|
react.useEffect(() => {
|
|
@@ -1062,7 +1113,7 @@ function ThemeCustomizerProvider({
|
|
|
1062
1113
|
if (applyStyles) {
|
|
1063
1114
|
injectStyles(config);
|
|
1064
1115
|
}
|
|
1065
|
-
}, [config,
|
|
1116
|
+
}, [config, applyStyles]);
|
|
1066
1117
|
react.useEffect(() => {
|
|
1067
1118
|
saveConfig(config);
|
|
1068
1119
|
}, [config]);
|
|
@@ -1075,7 +1126,7 @@ function ThemeCustomizerProvider({
|
|
|
1075
1126
|
}, [applyStyles]);
|
|
1076
1127
|
react.useEffect(() => {
|
|
1077
1128
|
const handleStorage = (e) => {
|
|
1078
|
-
if (e.key ===
|
|
1129
|
+
if (e.key === STORAGE_KEY && e.newValue) {
|
|
1079
1130
|
try {
|
|
1080
1131
|
const parsed = JSON.parse(e.newValue);
|
|
1081
1132
|
setConfigState((prev) => {
|
|
@@ -1092,6 +1143,20 @@ function ThemeCustomizerProvider({
|
|
|
1092
1143
|
const setConfig = react.useCallback((newConfig) => {
|
|
1093
1144
|
setConfigState(newConfig);
|
|
1094
1145
|
}, []);
|
|
1146
|
+
const setStyle = react.useCallback((key) => {
|
|
1147
|
+
const preset = getStylePreset(key);
|
|
1148
|
+
setConfigState((prev) => {
|
|
1149
|
+
if (prev.style === key) return prev;
|
|
1150
|
+
return {
|
|
1151
|
+
...prev,
|
|
1152
|
+
style: key,
|
|
1153
|
+
radius: preset.defaults.radius,
|
|
1154
|
+
font: preset.defaults.font,
|
|
1155
|
+
shadow: preset.defaults.shadow,
|
|
1156
|
+
surfaceStyle: preset.defaults.surfaceStyle
|
|
1157
|
+
};
|
|
1158
|
+
});
|
|
1159
|
+
}, []);
|
|
1095
1160
|
const setColorPreset = react.useCallback((key) => {
|
|
1096
1161
|
setConfigState((prev) => {
|
|
1097
1162
|
if (prev.colorPreset === key) return prev;
|
|
@@ -1133,6 +1198,7 @@ function ThemeCustomizerProvider({
|
|
|
1133
1198
|
() => ({
|
|
1134
1199
|
config,
|
|
1135
1200
|
setConfig,
|
|
1201
|
+
setStyle,
|
|
1136
1202
|
setColorPreset,
|
|
1137
1203
|
setRadius,
|
|
1138
1204
|
setFont,
|
|
@@ -1145,6 +1211,7 @@ function ThemeCustomizerProvider({
|
|
|
1145
1211
|
[
|
|
1146
1212
|
config,
|
|
1147
1213
|
setConfig,
|
|
1214
|
+
setStyle,
|
|
1148
1215
|
setColorPreset,
|
|
1149
1216
|
setRadius,
|
|
1150
1217
|
setFont,
|
|
@@ -1244,7 +1311,7 @@ function RadiusOption({
|
|
|
1244
1311
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1245
1312
|
isActive ? "border-primary bg-muted/60 shadow-sm" : "border-border bg-transparent"
|
|
1246
1313
|
),
|
|
1247
|
-
title: preset.name
|
|
1314
|
+
title: `${preset.name} (${preset.label})`,
|
|
1248
1315
|
children: [
|
|
1249
1316
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1250
1317
|
"span",
|
|
@@ -1334,6 +1401,69 @@ function PillToggle({
|
|
|
1334
1401
|
}
|
|
1335
1402
|
);
|
|
1336
1403
|
}
|
|
1404
|
+
function StyleOption({
|
|
1405
|
+
preset,
|
|
1406
|
+
isActive,
|
|
1407
|
+
onClick
|
|
1408
|
+
}) {
|
|
1409
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1410
|
+
"button",
|
|
1411
|
+
{
|
|
1412
|
+
type: "button",
|
|
1413
|
+
onClick,
|
|
1414
|
+
className: chunk4ON3M3OM_cjs.cn(
|
|
1415
|
+
"flex items-start gap-3 rounded-md border px-3 py-3 text-left transition-all duration-fast ease-standard",
|
|
1416
|
+
"hover:border-border-strong hover:bg-muted/50",
|
|
1417
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1418
|
+
isActive ? "border-primary bg-muted/60 shadow-sm" : "border-border bg-transparent"
|
|
1419
|
+
),
|
|
1420
|
+
title: preset.description,
|
|
1421
|
+
children: [
|
|
1422
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1423
|
+
"svg",
|
|
1424
|
+
{
|
|
1425
|
+
className: chunk4ON3M3OM_cjs.cn(
|
|
1426
|
+
"size-5 shrink-0 mt-0.5",
|
|
1427
|
+
isActive ? "text-primary" : "text-muted-foreground"
|
|
1428
|
+
),
|
|
1429
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1430
|
+
viewBox: "0 0 24 24",
|
|
1431
|
+
fill: "none",
|
|
1432
|
+
stroke: "currentColor",
|
|
1433
|
+
strokeWidth: "1.5",
|
|
1434
|
+
strokeLinecap: "round",
|
|
1435
|
+
strokeLinejoin: "round",
|
|
1436
|
+
"aria-hidden": "true",
|
|
1437
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: preset.iconPath })
|
|
1438
|
+
}
|
|
1439
|
+
),
|
|
1440
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1441
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1442
|
+
"div",
|
|
1443
|
+
{
|
|
1444
|
+
className: chunk4ON3M3OM_cjs.cn(
|
|
1445
|
+
"text-sm font-semibold leading-tight",
|
|
1446
|
+
isActive ? "text-foreground" : "text-foreground"
|
|
1447
|
+
),
|
|
1448
|
+
children: preset.name
|
|
1449
|
+
}
|
|
1450
|
+
),
|
|
1451
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1452
|
+
"div",
|
|
1453
|
+
{
|
|
1454
|
+
className: chunk4ON3M3OM_cjs.cn(
|
|
1455
|
+
"mt-0.5 text-xs leading-snug",
|
|
1456
|
+
isActive ? "text-muted-foreground" : "text-muted-foreground/70"
|
|
1457
|
+
),
|
|
1458
|
+
children: preset.description
|
|
1459
|
+
}
|
|
1460
|
+
)
|
|
1461
|
+
] }),
|
|
1462
|
+
isActive && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "shrink-0 mt-0.5 text-primary" })
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1337
1467
|
function CopyButton({
|
|
1338
1468
|
getText,
|
|
1339
1469
|
className,
|
|
@@ -1399,6 +1529,7 @@ function ThemeCustomizer({
|
|
|
1399
1529
|
}) {
|
|
1400
1530
|
const {
|
|
1401
1531
|
config,
|
|
1532
|
+
setStyle,
|
|
1402
1533
|
setColorPreset,
|
|
1403
1534
|
setRadius,
|
|
1404
1535
|
setFont,
|
|
@@ -1415,6 +1546,15 @@ function ThemeCustomizer({
|
|
|
1415
1546
|
"data-ds": "",
|
|
1416
1547
|
"data-ds-component": "theme-customizer",
|
|
1417
1548
|
children: [
|
|
1549
|
+
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Style", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2", children: STYLE_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1550
|
+
StyleOption,
|
|
1551
|
+
{
|
|
1552
|
+
preset,
|
|
1553
|
+
isActive: config.style === preset.key,
|
|
1554
|
+
onClick: () => setStyle(preset.key)
|
|
1555
|
+
},
|
|
1556
|
+
preset.key
|
|
1557
|
+
)) }) }),
|
|
1418
1558
|
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Color", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: COLOR_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1419
1559
|
ColorSwatch,
|
|
1420
1560
|
{
|
|
@@ -1503,18 +1643,110 @@ function ThemeCustomizer({
|
|
|
1503
1643
|
);
|
|
1504
1644
|
}
|
|
1505
1645
|
ThemeCustomizer.displayName = "ThemeCustomizer";
|
|
1646
|
+
var DSThemeContext = react.createContext(null);
|
|
1647
|
+
function useDSTheme() {
|
|
1648
|
+
const ctx = react.useContext(DSThemeContext);
|
|
1649
|
+
if (!ctx) {
|
|
1650
|
+
throw new Error(
|
|
1651
|
+
"useDSTheme must be used within a <DSThemeProvider>. Wrap your application (or layout) with <DSThemeProvider>."
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
return ctx;
|
|
1655
|
+
}
|
|
1656
|
+
function getSystemPreference() {
|
|
1657
|
+
if (typeof window === "undefined") return "light";
|
|
1658
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
1659
|
+
}
|
|
1660
|
+
function resolveTheme(theme) {
|
|
1661
|
+
if (theme === "system") return getSystemPreference();
|
|
1662
|
+
return theme;
|
|
1663
|
+
}
|
|
1664
|
+
var STORAGE_KEY2 = "ds-theme-preference";
|
|
1665
|
+
function getStoredTheme() {
|
|
1666
|
+
if (typeof window === "undefined") return "system";
|
|
1667
|
+
try {
|
|
1668
|
+
const stored = localStorage.getItem(STORAGE_KEY2);
|
|
1669
|
+
if (stored === "light" || stored === "dark" || stored === "system") {
|
|
1670
|
+
return stored;
|
|
1671
|
+
}
|
|
1672
|
+
} catch {
|
|
1673
|
+
}
|
|
1674
|
+
return "system";
|
|
1675
|
+
}
|
|
1676
|
+
function storeTheme(theme) {
|
|
1677
|
+
try {
|
|
1678
|
+
localStorage.setItem(STORAGE_KEY2, theme);
|
|
1679
|
+
} catch {
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
function DSThemeProvider({
|
|
1683
|
+
children,
|
|
1684
|
+
defaultTheme,
|
|
1685
|
+
manageHtmlClass = false
|
|
1686
|
+
}) {
|
|
1687
|
+
const [theme, setThemeState] = react.useState(
|
|
1688
|
+
() => defaultTheme ?? getStoredTheme()
|
|
1689
|
+
);
|
|
1690
|
+
const [systemPreference, setSystemPreference] = react.useState("light");
|
|
1691
|
+
react.useEffect(() => {
|
|
1692
|
+
setSystemPreference(getSystemPreference());
|
|
1693
|
+
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
1694
|
+
const handler = (e) => {
|
|
1695
|
+
setSystemPreference(e.matches ? "dark" : "light");
|
|
1696
|
+
};
|
|
1697
|
+
mql.addEventListener("change", handler);
|
|
1698
|
+
return () => mql.removeEventListener("change", handler);
|
|
1699
|
+
}, []);
|
|
1700
|
+
const resolvedTheme = react.useMemo(
|
|
1701
|
+
() => theme === "system" ? systemPreference : theme,
|
|
1702
|
+
[theme, systemPreference]
|
|
1703
|
+
);
|
|
1704
|
+
react.useEffect(() => {
|
|
1705
|
+
if (!manageHtmlClass) return;
|
|
1706
|
+
const root = document.documentElement;
|
|
1707
|
+
if (resolvedTheme === "dark") {
|
|
1708
|
+
root.classList.add("dark");
|
|
1709
|
+
} else {
|
|
1710
|
+
root.classList.remove("dark");
|
|
1711
|
+
}
|
|
1712
|
+
}, [resolvedTheme, manageHtmlClass]);
|
|
1713
|
+
const setTheme = react.useCallback((newTheme) => {
|
|
1714
|
+
setThemeState(newTheme);
|
|
1715
|
+
storeTheme(newTheme);
|
|
1716
|
+
}, []);
|
|
1717
|
+
const toggleTheme = react.useCallback(() => {
|
|
1718
|
+
setThemeState((current) => {
|
|
1719
|
+
const resolved = resolveTheme(current);
|
|
1720
|
+
const next = resolved === "dark" ? "light" : "dark";
|
|
1721
|
+
storeTheme(next);
|
|
1722
|
+
return next;
|
|
1723
|
+
});
|
|
1724
|
+
}, []);
|
|
1725
|
+
const value = react.useMemo(
|
|
1726
|
+
() => ({
|
|
1727
|
+
theme,
|
|
1728
|
+
resolvedTheme,
|
|
1729
|
+
setTheme,
|
|
1730
|
+
toggleTheme
|
|
1731
|
+
}),
|
|
1732
|
+
[theme, resolvedTheme, setTheme, toggleTheme]
|
|
1733
|
+
);
|
|
1734
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DSThemeContext.Provider, { value, children });
|
|
1735
|
+
}
|
|
1506
1736
|
|
|
1507
1737
|
exports.COLOR_PRESETS = COLOR_PRESETS;
|
|
1508
1738
|
exports.COLOR_PRESET_KEYS = COLOR_PRESET_KEYS;
|
|
1509
1739
|
exports.DEFAULT_FONT_KEY = DEFAULT_FONT_KEY;
|
|
1510
1740
|
exports.DEFAULT_RADIUS_KEY = DEFAULT_RADIUS_KEY;
|
|
1511
1741
|
exports.DEFAULT_SHADOW_KEY = DEFAULT_SHADOW_KEY;
|
|
1742
|
+
exports.DEFAULT_STYLE_KEY = DEFAULT_STYLE_KEY;
|
|
1512
1743
|
exports.DEFAULT_SURFACE_STYLE_KEY = DEFAULT_SURFACE_STYLE_KEY;
|
|
1513
1744
|
exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
|
|
1514
1745
|
exports.DSThemeProvider = DSThemeProvider;
|
|
1515
1746
|
exports.FONT_PRESETS = FONT_PRESETS;
|
|
1516
1747
|
exports.RADIUS_PRESETS = RADIUS_PRESETS;
|
|
1517
1748
|
exports.SHADOW_PRESETS = SHADOW_PRESETS;
|
|
1749
|
+
exports.STYLE_PRESETS = STYLE_PRESETS;
|
|
1518
1750
|
exports.SURFACE_STYLE_PRESETS = SURFACE_STYLE_PRESETS;
|
|
1519
1751
|
exports.ThemeCustomizer = ThemeCustomizer;
|
|
1520
1752
|
exports.ThemeCustomizerProvider = ThemeCustomizerProvider;
|
|
@@ -1529,5 +1761,6 @@ exports.getColorPreset = getColorPreset;
|
|
|
1529
1761
|
exports.getFontPreset = getFontPreset;
|
|
1530
1762
|
exports.getRadiusPreset = getRadiusPreset;
|
|
1531
1763
|
exports.getShadowPreset = getShadowPreset;
|
|
1764
|
+
exports.getStylePreset = getStylePreset;
|
|
1532
1765
|
exports.useDSTheme = useDSTheme;
|
|
1533
1766
|
exports.useThemeCustomizer = useThemeCustomizer;
|