@sckyzo/cosmos-react 0.0.3 → 0.1.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 CHANGED
@@ -5,6 +5,24 @@ All notable changes to `@sckyzo/cosmos-react` are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.0](https://github.com/SckyzO/cosmos/compare/@sckyzo/cosmos-react@0.0.3...@sckyzo/cosmos-react@0.1.0) (2026-10-20)
9
+
10
+
11
+ ### ⚠ BREAKING CHANGES
12
+
13
+ * **react:** ThemeToggleTri's 'oled' mode is now 'deep-blue' and the oledLabel prop is replaced by deepBlueLabel.
14
+
15
+ ### Features
16
+
17
+ * **react:** add align and aria-label to Popover.Content ([d4c39bd](https://github.com/SckyzO/cosmos/commit/d4c39bd28e9b0e27fadd08f932aa6debbecaff01))
18
+ * **react:** add AppearanceMenu for picking theme and accent in a top bar ([5181ad7](https://github.com/SckyzO/cosmos/commit/5181ad7eb3d06c693fbc602500901536383978a6))
19
+ * **react:** add AppearanceSettings and deep-blue ThemeToggleTri mode ([597f714](https://github.com/SckyzO/cosmos/commit/597f714ba4a22076dd9d11ffeffca222b34d0df6))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * **react:** stretch PaletteCard label rows to the card's height ([de3aba7](https://github.com/SckyzO/cosmos/commit/de3aba7397b0ceb8bb8540e47997fe8ec9168b7f))
25
+
8
26
  ## [0.0.3](https://github.com/SckyzO/cosmos/compare/@sckyzo/cosmos-react@0.0.2...@sckyzo/cosmos-react@0.0.3) (2026-07-17)
9
27
 
10
28
 
package/README.md CHANGED
@@ -14,7 +14,7 @@ pnpm add @sckyzo/cosmos-react @sckyzo/cosmos-theme
14
14
  pnpm add react react-dom # peers, react 19+
15
15
  ```
16
16
 
17
- `@sckyzo/cosmos-theme` carries the CSS (tokens, fonts, light/dark vars). The
17
+ `@sckyzo/cosmos-theme` carries the CSS (tokens, fonts, theme and accent vars). The
18
18
  components render unstyled without it.
19
19
 
20
20
  ## Set up the styles
@@ -33,7 +33,7 @@ In your main CSS file:
33
33
  The path is relative to this CSS file; adjust the depth to your layout. */
34
34
  @source '../node_modules/@sckyzo/cosmos-react/dist/**/*.{js,cjs}';
35
35
 
36
- /* Cosmos tokens (the @theme block) then the light/dark CSS vars. */
36
+ /* Cosmos tokens (the @theme block) then the theme and accent CSS vars. */
37
37
  @import '@sckyzo/cosmos-theme/tailwind';
38
38
  @import '@sckyzo/cosmos-theme/vars';
39
39
 
@@ -64,6 +64,38 @@ function Example() {
64
64
  }
65
65
  ```
66
66
 
67
+ ## Themes and accents
68
+
69
+ The theme is a class on `<html>` and the accent a `data-accent` attribute, see
70
+ the [theme README](../theme#themes--accents). `AppearanceSettings` renders a
71
+ picker for each, and `applyAppearance` sets them on the document:
72
+
73
+ ```tsx
74
+ import { useEffect, useState } from 'react';
75
+ import { AppearanceSettings, applyAppearance, type CosmosAppearance } from '@sckyzo/cosmos-react';
76
+
77
+ function Appearance() {
78
+ const [appearance, setAppearance] = useState<CosmosAppearance>({
79
+ theme: 'light',
80
+ accent: 'blue',
81
+ });
82
+ useEffect(() => applyAppearance(appearance), [appearance]);
83
+ return (
84
+ <AppearanceSettings
85
+ theme={appearance.theme}
86
+ accent={appearance.accent}
87
+ onThemeChange={(theme) => setAppearance((a) => ({ ...a, theme }))}
88
+ onAccentChange={(accent) => setAppearance((a) => ({ ...a, accent }))}
89
+ />
90
+ );
91
+ }
92
+ ```
93
+
94
+ For a top bar, `AppearanceMenu` takes the same props and puts the two pickers
95
+ in a panel behind an icon button, for example in `Topbar`'s `rightActions`.
96
+
97
+ Saving the choice (local storage, user profile) is left to the app.
98
+
67
99
  Charts live in a separate package, [`@sckyzo/cosmos-charts`](../charts), so apps
68
100
  that don't render charts don't ship the ApexCharts bundle.
69
101
 
package/dist/index.cjs CHANGED
@@ -345,11 +345,11 @@ var SidebarItem = ({
345
345
  const baseClass = clsx.clsx(
346
346
  "group mx-2 flex items-center gap-3 rounded-lg py-2 text-sm font-medium transition-colors",
347
347
  collapsed ? "justify-center px-2" : "px-3",
348
- active ? "bg-brand-500/10 text-brand-500" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
348
+ active ? "bg-brand-500/10 text-brand-600 dark:text-brand-400" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
349
349
  );
350
350
  const style = !collapsed && depth > 0 ? { paddingLeft: 12 + depth * 20 } : void 0;
351
351
  const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
352
- /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: clsx.clsx("h-5 w-5 shrink-0", active && "text-brand-500") }),
352
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-5 w-5 shrink-0" }),
353
353
  !collapsed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
354
354
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label }),
355
355
  badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: badge })
@@ -400,9 +400,9 @@ var SidebarSubMenu = ({
400
400
  title: label,
401
401
  className: clsx.clsx(
402
402
  "group mx-2 flex w-[calc(100%-1rem)] items-center justify-center rounded-lg px-2 py-2 text-sm font-medium transition-colors",
403
- active ? "bg-brand-500/10 text-brand-500" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
403
+ active ? "bg-brand-500/10 text-brand-600 dark:text-brand-400" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
404
404
  ),
405
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: clsx.clsx("h-5 w-5 shrink-0", active && "text-brand-500") })
405
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-5 w-5 shrink-0" })
406
406
  }
407
407
  );
408
408
  }
@@ -415,10 +415,10 @@ var SidebarSubMenu = ({
415
415
  "aria-expanded": open,
416
416
  className: clsx.clsx(
417
417
  "group mx-2 flex w-[calc(100%-1rem)] items-center gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition-colors",
418
- active ? "bg-brand-500/10 text-brand-500" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
418
+ active ? "bg-brand-500/10 text-brand-600 dark:text-brand-400" : "text-[var(--color-text-secondary)] hover:bg-black/5 hover:text-[var(--color-text-primary)] dark:hover:bg-white/5"
419
419
  ),
420
420
  children: [
421
- /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: clsx.clsx("h-5 w-5 shrink-0", active && "text-brand-500") }),
421
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-5 w-5 shrink-0" }),
422
422
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label }),
423
423
  badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: badge }),
424
424
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -479,7 +479,7 @@ Sidebar.SubMenu = SidebarSubMenu;
479
479
  var PageBreadcrumb = ({ items, className }) => /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex flex-wrap items-center gap-1 text-sm", children: items.map((item, i) => {
480
480
  const isFirst = i === 0;
481
481
  const isLast = i === items.length - 1;
482
- const linkClass = "hover:text-brand-500 dark:hover:text-brand-400 flex items-center gap-1 text-[var(--color-text-secondary)] transition-colors";
482
+ const linkClass = "hover:text-brand-600 dark:hover:text-brand-400 flex items-center gap-1 text-[var(--color-text-secondary)] transition-colors";
483
483
  const renderInner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
484
484
  isFirst && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Home, { className: "h-4 w-4" }),
485
485
  item.label
@@ -623,7 +623,7 @@ var ErrorState = ({
623
623
  {
624
624
  type: "button",
625
625
  onClick: onRetry,
626
- className: "text-brand-500 hover:text-brand-600 text-xs font-medium hover:underline",
626
+ className: "text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 text-xs font-medium hover:underline",
627
627
  children: "Try again"
628
628
  }
629
629
  )
@@ -3504,7 +3504,7 @@ var NotificationsPanelFooter = ({
3504
3504
  if (closeOnClick && !e.defaultPrevented) setOpen(false);
3505
3505
  },
3506
3506
  className: clsx.clsx(
3507
- "text-brand-500 w-full rounded-lg py-2 text-center text-sm font-medium transition-colors hover:bg-gray-50 dark:hover:bg-white/5",
3507
+ "text-brand-600 dark:text-brand-400 w-full rounded-lg py-2 text-center text-sm font-medium transition-colors hover:bg-gray-50 dark:hover:bg-white/5",
3508
3508
  className
3509
3509
  ),
3510
3510
  ...rest,
@@ -3837,7 +3837,7 @@ var SIZE_CLASS9 = {
3837
3837
  sm: { box: "h-8 w-8", icon: "h-4 w-4" },
3838
3838
  md: { box: "h-10 w-10", icon: "h-5 w-5" }
3839
3839
  };
3840
- var TRI_ORDER = ["light", "dark", "oled"];
3840
+ var TRI_ORDER = ["light", "dark", "deep-blue"];
3841
3841
  var nextInCycle = (current) => {
3842
3842
  const idx = TRI_ORDER.indexOf(current);
3843
3843
  return TRI_ORDER[(idx + 1) % TRI_ORDER.length];
@@ -3845,7 +3845,7 @@ var nextInCycle = (current) => {
3845
3845
  var ICON_FOR = {
3846
3846
  light: lucideReact.Sun,
3847
3847
  dark: lucideReact.Moon,
3848
- oled: lucideReact.MoonStar
3848
+ "deep-blue": lucideReact.MoonStar
3849
3849
  };
3850
3850
  var ThemeToggleTri = react.forwardRef(
3851
3851
  function ThemeToggleTri2({
@@ -3854,12 +3854,12 @@ var ThemeToggleTri = react.forwardRef(
3854
3854
  size = "md",
3855
3855
  lightLabel = "Switch to light mode",
3856
3856
  darkLabel = "Switch to dark mode",
3857
- oledLabel = "Switch to OLED mode",
3857
+ deepBlueLabel = "Switch to deep blue mode",
3858
3858
  className,
3859
3859
  ...rest
3860
3860
  }, ref) {
3861
3861
  const next = nextInCycle(theme);
3862
- const label = next === "light" ? lightLabel : next === "dark" ? darkLabel : oledLabel;
3862
+ const label = next === "light" ? lightLabel : next === "dark" ? darkLabel : deepBlueLabel;
3863
3863
  const Icon2 = ICON_FOR[theme];
3864
3864
  const { box, icon } = SIZE_CLASS9[size];
3865
3865
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4111,9 +4111,12 @@ var PopoverRoot = ({
4111
4111
  const handler = () => refreshRect();
4112
4112
  window.addEventListener("resize", handler);
4113
4113
  window.addEventListener("scroll", handler, true);
4114
+ const observer = new ResizeObserver(handler);
4115
+ if (triggerRef.current) observer.observe(triggerRef.current, { box: "border-box" });
4114
4116
  return () => {
4115
4117
  window.removeEventListener("resize", handler);
4116
4118
  window.removeEventListener("scroll", handler, true);
4119
+ observer.disconnect();
4117
4120
  };
4118
4121
  }, [open, refreshRect]);
4119
4122
  react.useEffect(() => {
@@ -4152,13 +4155,18 @@ var PopoverTrigger = react.forwardRef(function PopoverTrigger2({ onClick, childr
4152
4155
  }
4153
4156
  );
4154
4157
  });
4155
- var positionStyle = (position, rect, offset) => {
4158
+ var VIEWPORT_MARGIN = 16;
4159
+ var positionStyle = (position, align, rect, offset) => {
4160
+ const left = align === "end" ? rect.right : rect.left + rect.width / 2;
4161
+ const shiftX = align === "end" ? "-100%" : "-50%";
4162
+ const maxWidth = align === "end" ? rect.right - VIEWPORT_MARGIN : void 0;
4156
4163
  switch (position) {
4157
4164
  case "top":
4158
4165
  return {
4159
4166
  top: rect.top - offset,
4160
- left: rect.left + rect.width / 2,
4161
- transform: "translate(-50%, -100%)"
4167
+ left,
4168
+ maxWidth,
4169
+ transform: `translate(${shiftX}, -100%)`
4162
4170
  };
4163
4171
  case "right":
4164
4172
  return {
@@ -4176,32 +4184,36 @@ var positionStyle = (position, rect, offset) => {
4176
4184
  default:
4177
4185
  return {
4178
4186
  top: rect.bottom + offset,
4179
- left: rect.left + rect.width / 2,
4180
- transform: "translateX(-50%)"
4187
+ left,
4188
+ maxWidth,
4189
+ transform: `translateX(${shiftX})`
4181
4190
  };
4182
4191
  }
4183
4192
  };
4184
- var arrowStyle = (position) => {
4193
+ var arrowStyle = (position, align, rect) => {
4185
4194
  const base = {
4186
4195
  position: "absolute",
4187
4196
  width: 8,
4188
4197
  height: 8,
4189
4198
  transform: "rotate(45deg)"
4190
4199
  };
4200
+ const x = align === "end" ? { right: rect.width / 2 - 1, marginRight: -4 } : { left: "50%", marginLeft: -4 };
4191
4201
  switch (position) {
4192
4202
  case "top":
4193
- return { ...base, bottom: -4, left: "50%", marginLeft: -4 };
4203
+ return { ...base, bottom: -4, ...x };
4194
4204
  case "right":
4195
4205
  return { ...base, left: -4, top: "50%", marginTop: -4 };
4196
4206
  case "left":
4197
4207
  return { ...base, right: -4, top: "50%", marginTop: -4 };
4198
4208
  case "bottom":
4199
4209
  default:
4200
- return { ...base, top: -4, left: "50%", marginLeft: -4 };
4210
+ return { ...base, top: -4, ...x };
4201
4211
  }
4202
4212
  };
4203
4213
  var PopoverContent = ({
4204
4214
  position = "bottom",
4215
+ align = "center",
4216
+ "aria-label": ariaLabel,
4205
4217
  offset = 8,
4206
4218
  arrow = false,
4207
4219
  width = "w-64",
@@ -4217,7 +4229,8 @@ var PopoverContent = ({
4217
4229
  "div",
4218
4230
  {
4219
4231
  role: "dialog",
4220
- style: positionStyle(position, triggerRect, offset),
4232
+ "aria-label": ariaLabel,
4233
+ style: positionStyle(position, align, triggerRect, offset),
4221
4234
  className: clsx.clsx(
4222
4235
  "fixed z-[9999] rounded-xl border border-gray-200 bg-white p-4 text-sm shadow-xl dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100",
4223
4236
  width,
@@ -4228,7 +4241,7 @@ var PopoverContent = ({
4228
4241
  "span",
4229
4242
  {
4230
4243
  "aria-hidden": true,
4231
- style: arrowStyle(position),
4244
+ style: arrowStyle(position, align, triggerRect),
4232
4245
  className: "border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900"
4233
4246
  }
4234
4247
  ),
@@ -7649,7 +7662,7 @@ var ColumnHeader = ({
7649
7662
  "aria-label": "Filter column",
7650
7663
  className: clsx.clsx(
7651
7664
  "flex items-center gap-1 rounded p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-white/10",
7652
- filterCount > 0 && "text-brand-500"
7665
+ filterCount > 0 && "text-brand-600 dark:text-brand-400"
7653
7666
  ),
7654
7667
  children: [
7655
7668
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "h-3 w-3" }),
@@ -8417,7 +8430,7 @@ var SignInForm = ({
8417
8430
  {
8418
8431
  type: "button",
8419
8432
  onClick: onForgotPassword,
8420
- className: "text-brand-500 hover:text-brand-600 text-xs font-medium transition-colors",
8433
+ className: "text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 text-xs font-medium transition-colors",
8421
8434
  children: forgotLabel
8422
8435
  }
8423
8436
  )
@@ -8760,7 +8773,7 @@ var TwoStepVerificationForm = ({
8760
8773
  type: "button",
8761
8774
  onClick: onResend,
8762
8775
  disabled: loading,
8763
- className: "text-brand-500 hover:text-brand-600 font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
8776
+ className: "text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
8764
8777
  children: resendLabel
8765
8778
  }
8766
8779
  )
@@ -8876,7 +8889,7 @@ var PaletteCard = ({ meta, active = false, onClick, className }) => /* @__PURE__
8876
8889
  /* @__PURE__ */ jsxRuntime.jsxs(
8877
8890
  "div",
8878
8891
  {
8879
- className: "flex items-center justify-between px-2.5 py-1.5",
8892
+ className: "flex flex-1 items-center justify-between px-2.5 py-1.5",
8880
8893
  style: {
8881
8894
  backgroundColor: meta.preview.surface,
8882
8895
  borderTop: `1px solid ${meta.preview.border}`
@@ -8887,11 +8900,11 @@ var PaletteCard = ({ meta, active = false, onClick, className }) => /* @__PURE__
8887
8900
  "span",
8888
8901
  {
8889
8902
  className: "block text-xs font-semibold",
8890
- style: { color: active ? void 0 : "#6b7280" },
8903
+ style: { color: meta.preview.text ?? (active ? void 0 : "#6b7280") },
8891
8904
  children: meta.label
8892
8905
  }
8893
8906
  ),
8894
- meta.desc && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-[10px]", style: { color: "#9ca3af" }, children: meta.desc })
8907
+ meta.desc && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-[10px]", style: { color: meta.preview.text ?? "#9ca3af" }, children: meta.desc })
8895
8908
  ] }),
8896
8909
  active && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-brand-500 flex h-4 w-4 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-2.5 w-2.5 text-white", "aria-hidden": true }) })
8897
8910
  ]
@@ -8941,7 +8954,7 @@ var OptionCard = ({
8941
8954
  {
8942
8955
  className: clsx.clsx(
8943
8956
  "text-xs font-semibold",
8944
- active ? "text-brand-500" : "text-gray-700 dark:text-gray-300"
8957
+ active ? "text-brand-600 dark:text-brand-400" : "text-gray-700 dark:text-gray-300"
8945
8958
  ),
8946
8959
  children: label
8947
8960
  }
@@ -8977,6 +8990,129 @@ var OptionPicker = ({
8977
8990
  ))
8978
8991
  }
8979
8992
  );
8993
+
8994
+ // src/settings/appearance.ts
8995
+ var COSMOS_THEMES = [
8996
+ {
8997
+ id: "light",
8998
+ label: "Light",
8999
+ dark: false,
9000
+ preview: { bg: "#f9fafb", surface: "#ffffff", border: "#e5e7eb", text: "#667085" }
9001
+ },
9002
+ {
9003
+ id: "sand",
9004
+ label: "Sand",
9005
+ dark: false,
9006
+ preview: { bg: "#f9f5eb", surface: "#fffcf7", border: "#e7dfd0", text: "#746656" }
9007
+ },
9008
+ {
9009
+ id: "dark",
9010
+ label: "Dark",
9011
+ dark: true,
9012
+ preview: { bg: "#0a0a0a", surface: "#141414", border: "#3d3d3d", text: "#a3a3a3" }
9013
+ },
9014
+ {
9015
+ id: "deep-blue",
9016
+ label: "Deep Blue",
9017
+ dark: true,
9018
+ preview: { bg: "#0c111d", surface: "#101828", border: "#344054", text: "#98a2b3" }
9019
+ }
9020
+ ];
9021
+ var COSMOS_ACCENTS = [
9022
+ { id: "blue", label: "Blue", hex: "#465fff" },
9023
+ { id: "indigo", label: "Indigo", hex: "#5963e9" },
9024
+ { id: "violet", label: "Violet", hex: "#8745f1" },
9025
+ { id: "purple", label: "Purple", hex: "#ad2ecf" },
9026
+ { id: "rose", label: "Rose", hex: "#d4166d" },
9027
+ { id: "teal", label: "Teal", hex: "#038378" },
9028
+ { id: "cyan", label: "Cyan", hex: "#017f9d" },
9029
+ { id: "graphite", label: "Graphite", hex: "#707580" },
9030
+ { id: "red", label: "Red", hex: "#db192a" },
9031
+ { id: "orange", label: "Orange", hex: "#c04f01" },
9032
+ { id: "amber", label: "Amber", hex: "#a46800" },
9033
+ { id: "green", label: "Green", hex: "#02863c" }
9034
+ ];
9035
+ var THEME_CLASSES = COSMOS_THEMES.map((t) => t.id).filter((id) => id !== "light");
9036
+ var isDarkTheme = (theme) => COSMOS_THEMES.some((t) => t.id === theme && t.dark);
9037
+ var applyAppearance = ({ theme, accent }, root) => {
9038
+ const el = root ?? (typeof document === "undefined" ? void 0 : document.documentElement);
9039
+ if (!el) return;
9040
+ el.classList.remove(...THEME_CLASSES);
9041
+ if (theme !== "light") el.classList.add(theme);
9042
+ if (accent === "blue") delete el.dataset.accent;
9043
+ else el.dataset.accent = accent;
9044
+ };
9045
+ var AppearanceSettings = ({
9046
+ theme,
9047
+ accent,
9048
+ onThemeChange,
9049
+ onAccentChange,
9050
+ themeLabel = "Theme",
9051
+ accentLabel = "Accent color",
9052
+ themes = COSMOS_THEMES,
9053
+ accents = COSMOS_ACCENTS,
9054
+ themeColumns = 4,
9055
+ className
9056
+ }) => {
9057
+ const themeHeadingId = react.useId();
9058
+ const accentHeadingId = react.useId();
9059
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx.clsx("space-y-6", className), children: [
9060
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-labelledby": themeHeadingId, children: [
9061
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: themeHeadingId, className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: themeLabel }),
9062
+ /* @__PURE__ */ jsxRuntime.jsx(
9063
+ PalettePicker,
9064
+ {
9065
+ className: "mt-3",
9066
+ palettes: themes,
9067
+ value: theme,
9068
+ cols: themeColumns,
9069
+ onChange: (id) => onThemeChange(id)
9070
+ }
9071
+ )
9072
+ ] }),
9073
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-labelledby": accentHeadingId, children: [
9074
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: accentHeadingId, className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: accentLabel }),
9075
+ /* @__PURE__ */ jsxRuntime.jsx(
9076
+ AccentPicker,
9077
+ {
9078
+ className: "mt-3",
9079
+ colors: accents,
9080
+ value: accent,
9081
+ onChange: (id) => onAccentChange(id),
9082
+ cols: 6
9083
+ }
9084
+ )
9085
+ ] })
9086
+ ] });
9087
+ };
9088
+ var SIZE_CLASS12 = {
9089
+ sm: { box: "h-8 w-8", icon: "h-4 w-4" },
9090
+ md: { box: "h-10 w-10", icon: "h-5 w-5" }
9091
+ };
9092
+ var AppearanceMenu = ({
9093
+ label = "Appearance",
9094
+ size = "md",
9095
+ className,
9096
+ ...settings
9097
+ }) => {
9098
+ const { box, icon } = SIZE_CLASS12[size];
9099
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
9100
+ /* @__PURE__ */ jsxRuntime.jsx(
9101
+ Popover.Trigger,
9102
+ {
9103
+ title: label,
9104
+ "aria-label": label,
9105
+ className: clsx.clsx(
9106
+ "flex items-center justify-center rounded-lg border border-gray-200 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-white",
9107
+ box,
9108
+ className
9109
+ ),
9110
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: icon, "aria-hidden": true })
9111
+ }
9112
+ ),
9113
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { align: "end", width: "w-96", "aria-label": label, children: /* @__PURE__ */ jsxRuntime.jsx(AppearanceSettings, { themeColumns: 2, ...settings }) })
9114
+ ] });
9115
+ };
8980
9116
  var SIZE = {
8981
9117
  sm: "text-base leading-relaxed",
8982
9118
  md: "text-lg leading-relaxed",
@@ -9155,6 +9291,8 @@ exports.ActiveFiltersBar = ActiveFiltersBar;
9155
9291
  exports.ActivityFeed = ActivityFeed;
9156
9292
  exports.AlertBanner = AlertBanner;
9157
9293
  exports.AnnouncementBar = AnnouncementBar;
9294
+ exports.AppearanceMenu = AppearanceMenu;
9295
+ exports.AppearanceSettings = AppearanceSettings;
9158
9296
  exports.AuthLayout = AuthLayout;
9159
9297
  exports.Avatar = Avatar;
9160
9298
  exports.AvatarUploader = AvatarUploader;
@@ -9165,6 +9303,8 @@ exports.Blockquote = Blockquote;
9165
9303
  exports.Breadcrumb = Breadcrumb;
9166
9304
  exports.Button = Button;
9167
9305
  exports.ButtonGroup = ButtonGroup;
9306
+ exports.COSMOS_ACCENTS = COSMOS_ACCENTS;
9307
+ exports.COSMOS_THEMES = COSMOS_THEMES;
9168
9308
  exports.Calendar = Calendar;
9169
9309
  exports.Card = Card2;
9170
9310
  exports.Carousel = Carousel;
@@ -9287,7 +9427,9 @@ exports.UserMenu = UserMenu;
9287
9427
  exports.VerticalNavigation = VerticalNavigation;
9288
9428
  exports.VideoEmbed = VideoEmbed;
9289
9429
  exports.ZoomBar = ZoomBar;
9430
+ exports.applyAppearance = applyAppearance;
9290
9431
  exports.defaultPasswordRules = defaultPasswordRules;
9432
+ exports.isDarkTheme = isDarkTheme;
9291
9433
  exports.useAutoRefresh = useAutoRefresh;
9292
9434
  //# sourceMappingURL=index.cjs.map
9293
9435
  //# sourceMappingURL=index.cjs.map