@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.
@@ -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 STORAGE_KEY2 = "ds-theme-customizer";
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(STORAGE_KEY2);
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(STORAGE_KEY2, JSON.stringify(config));
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(STYLE_ELEMENT_ID);
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 [resolvedMode, setResolvedMode] = react.useState("light");
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, resolvedMode, applyStyles]);
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 === STORAGE_KEY2 && e.newValue) {
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 + " (" + preset.label + ")",
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;