@sckyzo/cosmos-react 0.0.2 → 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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
3
3
  import { forwardRef, createContext, Children, Fragment, cloneElement, isValidElement, useState, useRef, useCallback, useEffect, useId, useContext, useMemo } from 'react';
4
- import { ChevronRight, Check, Copy, BellOff, Bell, CheckCircle2, Info, AlertTriangle, XCircle, ChevronDown, Sun, Moon, MoonStar, ExternalLink, Search, EyeOff, Eye, Minus, Paperclip, Clock, X, ChevronLeft, Dot as Dot$1, ArrowRight, HelpCircle, Home, Inbox, AlertCircle, CheckCircle, RefreshCw, Loader2, Save, Megaphone, Cookie, ArrowUp, ChevronUp, Plus, Maximize2, RotateCcw, Camera, Trash2, Upload, File, ChevronsUpDown, Filter, Quote, Calendar as Calendar$1 } from 'lucide-react';
4
+ import { ChevronRight, Check, Copy, BellOff, Bell, CheckCircle2, Info, AlertTriangle, XCircle, ChevronDown, Sun, Moon, MoonStar, ExternalLink, Search, EyeOff, Eye, Minus, Paperclip, Clock, X, ChevronLeft, Dot as Dot$1, ArrowRight, HelpCircle, Home, Inbox, AlertCircle, CheckCircle, RefreshCw, Loader2, Save, Megaphone, Cookie, ArrowUp, ChevronUp, Plus, Maximize2, RotateCcw, Camera, Trash2, Upload, File, ChevronsUpDown, Filter, MailCheck, ArrowLeft, Mail, User, ShieldCheck, Palette, Quote, Calendar as Calendar$1 } from 'lucide-react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import Autoplay from 'embla-carousel-autoplay';
7
7
  import useEmblaCarousel from 'embla-carousel-react';
@@ -12,93 +12,6 @@ import { Command } from 'cmdk';
12
12
  import { getDefaultClassNames, DayPicker } from 'react-day-picker';
13
13
  import 'react-day-picker/style.css';
14
14
 
15
- // src/storybook-avatars.ts
16
- var PALETTE = [
17
- ["#6366f1", "#ffffff"],
18
- // indigo
19
- ["#8b5cf6", "#ffffff"],
20
- // violet
21
- ["#0ea5e9", "#ffffff"],
22
- // sky
23
- ["#10b981", "#ffffff"],
24
- // emerald
25
- ["#f59e0b", "#1f2937"],
26
- // amber (dark text on warm bg)
27
- ["#f43f5e", "#ffffff"],
28
- // rose
29
- ["#14b8a6", "#ffffff"],
30
- // teal
31
- ["#ec4899", "#ffffff"],
32
- // pink
33
- ["#64748b", "#ffffff"],
34
- // slate
35
- ["#a855f7", "#ffffff"]
36
- // purple
37
- ];
38
- var hashSeed = (seed) => {
39
- let h = 5381;
40
- for (let i = 0; i < seed.length; i += 1) {
41
- h = (h << 5) + h + seed.charCodeAt(i) | 0;
42
- }
43
- return Math.abs(h);
44
- };
45
- var extractInitials = (seed) => {
46
- const cleaned = seed.replace(/[^\p{L}\p{N}\s'.-]/gu, " ").trim();
47
- if (!cleaned) return "?";
48
- const parts = cleaned.split(/[\s.'-]+/).filter(Boolean);
49
- if (parts.length >= 2) {
50
- return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
51
- }
52
- return cleaned.slice(0, 2).toUpperCase();
53
- };
54
- var buildSvg = (initials, bg, fg, size) => {
55
- const fontSize = initials.length === 1 ? 56 : 42;
56
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${bg}"/><text x="50" y="50" font-family="ui-sans-serif,system-ui,sans-serif" font-size="${fontSize}" font-weight="600" fill="${fg}" text-anchor="middle" dominant-baseline="central">${initials}</text></svg>`;
57
- };
58
- var placeholderAvatar = (seed, size = 64, opts = {}) => {
59
- const initials = extractInitials(seed);
60
- const [defaultBg, defaultFg] = PALETTE[hashSeed(seed) % PALETTE.length];
61
- const bg = opts.bg ?? defaultBg;
62
- const fg = opts.fg ?? defaultFg;
63
- const svg = buildSvg(initials, bg, fg, size);
64
- return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
65
- };
66
- var buildCoverSvg = (seed, from, to, width, height) => {
67
- const h = hashSeed(seed);
68
- const angle = h % 180;
69
- const cx1 = h % 60 + 20;
70
- const cy1 = (h >> 3) % 60 + 20;
71
- const r1 = (h >> 5) % 35 + 25;
72
- const cx2 = (h >> 7) % 60 + 20;
73
- const cy2 = (h >> 9) % 60 + 20;
74
- const r2 = (h >> 11) % 25 + 15;
75
- const gradientId = `g-${(h % 1e5).toString(36)}`;
76
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 100 100" preserveAspectRatio="none"><defs><linearGradient id="${gradientId}" gradientTransform="rotate(${angle})"><stop offset="0" stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="100" height="100" fill="url(#${gradientId})"/><circle cx="${cx1}" cy="${cy1}" r="${r1}" fill="rgba(255,255,255,0.08)"/><circle cx="${cx2}" cy="${cy2}" r="${r2}" fill="rgba(0,0,0,0.10)"/></svg>`;
77
- };
78
- var placeholderCover = (seed, width = 1600, height = 700, opts = {}) => {
79
- const h = hashSeed(seed);
80
- const [from] = PALETTE[h % PALETTE.length];
81
- const [to] = PALETTE[(h + 3) % PALETTE.length];
82
- const svg = buildCoverSvg(seed, opts.from ?? from, opts.to ?? to, width, height);
83
- return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
84
- };
85
-
86
- // src/storybook-helpers.ts
87
- var buildParams = (height) => ({
88
- layout: "fullscreen",
89
- docs: {
90
- story: {
91
- inline: false,
92
- iframeHeight: `${height}px`
93
- }
94
- }
95
- });
96
- var fn = ((height = 480) => buildParams(height));
97
- fn.sm = () => buildParams(320);
98
- fn.md = () => buildParams(480);
99
- fn.lg = () => buildParams(640);
100
- fn.full = () => buildParams(800);
101
- var portalDocsParams = fn;
102
15
  var Root = ({
103
16
  inset,
104
17
  align = "center",
@@ -407,11 +320,11 @@ var SidebarItem = ({
407
320
  const baseClass = clsx(
408
321
  "group mx-2 flex items-center gap-3 rounded-lg py-2 text-sm font-medium transition-colors",
409
322
  collapsed ? "justify-center px-2" : "px-3",
410
- 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"
323
+ 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"
411
324
  );
412
325
  const style = !collapsed && depth > 0 ? { paddingLeft: 12 + depth * 20 } : void 0;
413
326
  const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
414
- /* @__PURE__ */ jsx(Icon2, { className: clsx("h-5 w-5 shrink-0", active && "text-brand-500") }),
327
+ /* @__PURE__ */ jsx(Icon2, { className: "h-5 w-5 shrink-0" }),
415
328
  !collapsed && /* @__PURE__ */ jsxs(Fragment$1, { children: [
416
329
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label }),
417
330
  badge && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: badge })
@@ -462,9 +375,9 @@ var SidebarSubMenu = ({
462
375
  title: label,
463
376
  className: clsx(
464
377
  "group mx-2 flex w-[calc(100%-1rem)] items-center justify-center rounded-lg px-2 py-2 text-sm font-medium transition-colors",
465
- 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"
378
+ 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"
466
379
  ),
467
- children: /* @__PURE__ */ jsx(Icon2, { className: clsx("h-5 w-5 shrink-0", active && "text-brand-500") })
380
+ children: /* @__PURE__ */ jsx(Icon2, { className: "h-5 w-5 shrink-0" })
468
381
  }
469
382
  );
470
383
  }
@@ -477,10 +390,10 @@ var SidebarSubMenu = ({
477
390
  "aria-expanded": open,
478
391
  className: clsx(
479
392
  "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",
480
- 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"
393
+ 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"
481
394
  ),
482
395
  children: [
483
- /* @__PURE__ */ jsx(Icon2, { className: clsx("h-5 w-5 shrink-0", active && "text-brand-500") }),
396
+ /* @__PURE__ */ jsx(Icon2, { className: "h-5 w-5 shrink-0" }),
484
397
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label }),
485
398
  badge && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: badge }),
486
399
  /* @__PURE__ */ jsx(
@@ -541,7 +454,7 @@ Sidebar.SubMenu = SidebarSubMenu;
541
454
  var PageBreadcrumb = ({ items, className }) => /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-1 text-sm", children: items.map((item, i) => {
542
455
  const isFirst = i === 0;
543
456
  const isLast = i === items.length - 1;
544
- const linkClass = "hover:text-brand-500 dark:hover:text-brand-400 flex items-center gap-1 text-[var(--color-text-secondary)] transition-colors";
457
+ const linkClass = "hover:text-brand-600 dark:hover:text-brand-400 flex items-center gap-1 text-[var(--color-text-secondary)] transition-colors";
545
458
  const renderInner = /* @__PURE__ */ jsxs(Fragment$1, { children: [
546
459
  isFirst && /* @__PURE__ */ jsx(Home, { className: "h-4 w-4" }),
547
460
  item.label
@@ -685,7 +598,7 @@ var ErrorState = ({
685
598
  {
686
599
  type: "button",
687
600
  onClick: onRetry,
688
- className: "text-brand-500 hover:text-brand-600 text-xs font-medium hover:underline",
601
+ className: "text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 text-xs font-medium hover:underline",
689
602
  children: "Try again"
690
603
  }
691
604
  )
@@ -2068,6 +1981,8 @@ var Dropdown = ({
2068
1981
  }) => {
2069
1982
  const [open, setOpen] = useState(false);
2070
1983
  const ref = useRef(null);
1984
+ const triggerRef = useRef(null);
1985
+ const menuRef = useRef(null);
2071
1986
  useEffect(() => {
2072
1987
  if (!open) return;
2073
1988
  const handler = (e) => {
@@ -2076,15 +1991,47 @@ var Dropdown = ({
2076
1991
  document.addEventListener("mousedown", handler);
2077
1992
  return () => document.removeEventListener("mousedown", handler);
2078
1993
  }, [open]);
1994
+ useEffect(() => {
1995
+ if (!open) return;
1996
+ const first = menuRef.current?.querySelector('[role="menuitem"]:not(:disabled)');
1997
+ first?.focus();
1998
+ }, [open]);
1999
+ const closeAndRefocus = () => {
2000
+ setOpen(false);
2001
+ triggerRef.current?.focus();
2002
+ };
2003
+ const onMenuKeyDown = (e) => {
2004
+ if (e.key === "Escape") {
2005
+ e.preventDefault();
2006
+ closeAndRefocus();
2007
+ return;
2008
+ }
2009
+ const items = Array.from(
2010
+ menuRef.current?.querySelectorAll('[role="menuitem"]:not(:disabled)') ?? []
2011
+ );
2012
+ if (items.length === 0) return;
2013
+ const currentIndex = items.indexOf(document.activeElement);
2014
+ const focusAt = (i) => {
2015
+ e.preventDefault();
2016
+ items[(i + items.length) % items.length]?.focus();
2017
+ };
2018
+ if (e.key === "ArrowDown") focusAt(currentIndex + 1);
2019
+ else if (e.key === "ArrowUp") focusAt(currentIndex - 1);
2020
+ else if (e.key === "Home") focusAt(0);
2021
+ else if (e.key === "End") focusAt(items.length - 1);
2022
+ };
2079
2023
  const selected = options.find((o) => !isDivider(o) && o.value === value);
2080
2024
  const displayLabel = selected?.label ?? placeholder ?? label ?? "Select\u2026";
2081
2025
  return /* @__PURE__ */ jsxs("div", { ref, className: clsx("relative inline-block", className), children: [
2082
2026
  /* @__PURE__ */ jsxs(
2083
2027
  "button",
2084
2028
  {
2029
+ ref: triggerRef,
2085
2030
  type: "button",
2086
2031
  onClick: () => !disabled && setOpen((v) => !v),
2087
2032
  disabled,
2033
+ "aria-haspopup": "menu",
2034
+ "aria-expanded": open,
2088
2035
  className: clsx(
2089
2036
  "flex h-9 items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700",
2090
2037
  open && "ring-brand-500/30 ring-2"
@@ -2109,6 +2056,10 @@ var Dropdown = ({
2109
2056
  /* @__PURE__ */ jsx(
2110
2057
  "div",
2111
2058
  {
2059
+ ref: menuRef,
2060
+ role: "menu",
2061
+ "aria-label": label,
2062
+ onKeyDown: onMenuKeyDown,
2112
2063
  className: clsx(
2113
2064
  "absolute top-full z-50 mt-1 min-w-[180px] overflow-hidden rounded-xl border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800",
2114
2065
  align === "right" ? "right-0" : "left-0"
@@ -2130,10 +2081,11 @@ var Dropdown = ({
2130
2081
  "button",
2131
2082
  {
2132
2083
  type: "button",
2084
+ role: "menuitem",
2133
2085
  disabled: opt.disabled,
2134
2086
  onClick: () => {
2135
2087
  onChange?.(opt.value);
2136
- setOpen(false);
2088
+ closeAndRefocus();
2137
2089
  },
2138
2090
  className: clsx(
2139
2091
  "flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50",
@@ -2153,6 +2105,51 @@ var Dropdown = ({
2153
2105
  ] })
2154
2106
  ] });
2155
2107
  };
2108
+ var FOCUSABLE_SELECTOR = [
2109
+ "a[href]",
2110
+ "button:not([disabled])",
2111
+ "textarea:not([disabled])",
2112
+ "input:not([disabled])",
2113
+ "select:not([disabled])",
2114
+ '[tabindex]:not([tabindex="-1"])'
2115
+ ].join(",");
2116
+ function useFocusTrap(active) {
2117
+ const ref = useRef(null);
2118
+ useEffect(() => {
2119
+ if (!active) return;
2120
+ const node = ref.current;
2121
+ if (!node) return;
2122
+ const previouslyFocused = document.activeElement;
2123
+ const focusables = () => Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR));
2124
+ (focusables()[0] ?? node).focus();
2125
+ const onKeyDown = (e) => {
2126
+ if (e.key !== "Tab") return;
2127
+ const items = focusables();
2128
+ if (items.length === 0) {
2129
+ e.preventDefault();
2130
+ return;
2131
+ }
2132
+ const first = items[0];
2133
+ const last = items[items.length - 1];
2134
+ if (e.shiftKey && document.activeElement === first) {
2135
+ e.preventDefault();
2136
+ last.focus();
2137
+ } else if (!e.shiftKey && document.activeElement === last) {
2138
+ e.preventDefault();
2139
+ first.focus();
2140
+ }
2141
+ };
2142
+ node.addEventListener("keydown", onKeyDown);
2143
+ return () => {
2144
+ node.removeEventListener("keydown", onKeyDown);
2145
+ previouslyFocused?.focus?.();
2146
+ };
2147
+ }, [active]);
2148
+ return ref;
2149
+ }
2150
+ var DialogTitleContext = createContext(void 0);
2151
+ var DialogTitleProvider = DialogTitleContext.Provider;
2152
+ var useDialogTitleId = () => useContext(DialogTitleContext);
2156
2153
  var SIZE_CLASS5 = {
2157
2154
  sm: "max-w-sm",
2158
2155
  md: "max-w-md",
@@ -2160,7 +2157,9 @@ var SIZE_CLASS5 = {
2160
2157
  xl: "max-w-2xl",
2161
2158
  full: "h-full w-full max-w-none rounded-none"
2162
2159
  };
2163
- var Root8 = ({ open, onClose, size = "md", className, children }) => {
2160
+ var Root8 = ({ open, onClose, size = "md", className, ariaLabel, children }) => {
2161
+ const titleId = useId();
2162
+ const trapRef = useFocusTrap(open);
2164
2163
  useEffect(() => {
2165
2164
  if (!open) return;
2166
2165
  const handler = (e) => {
@@ -2175,12 +2174,16 @@ var Root8 = ({ open, onClose, size = "md", className, children }) => {
2175
2174
  /* @__PURE__ */ jsxs(
2176
2175
  "div",
2177
2176
  {
2177
+ ref: trapRef,
2178
+ tabIndex: -1,
2178
2179
  className: clsx(
2179
2180
  "fixed inset-0 z-50 flex",
2180
2181
  isFull ? "items-stretch justify-stretch" : "items-center justify-center p-4"
2181
2182
  ),
2182
2183
  role: "dialog",
2183
2184
  "aria-modal": "true",
2185
+ "aria-label": ariaLabel,
2186
+ "aria-labelledby": ariaLabel ? void 0 : titleId,
2184
2187
  children: [
2185
2188
  /* @__PURE__ */ jsx(
2186
2189
  "div",
@@ -2199,7 +2202,7 @@ var Root8 = ({ open, onClose, size = "md", className, children }) => {
2199
2202
  SIZE_CLASS5[size],
2200
2203
  className
2201
2204
  ),
2202
- children
2205
+ children: /* @__PURE__ */ jsx(DialogTitleProvider, { value: titleId, children })
2203
2206
  }
2204
2207
  )
2205
2208
  ]
@@ -2208,32 +2211,35 @@ var Root8 = ({ open, onClose, size = "md", className, children }) => {
2208
2211
  document.body
2209
2212
  );
2210
2213
  };
2211
- var Header2 = ({ title, description, onClose, className, children }) => /* @__PURE__ */ jsxs(
2212
- "div",
2213
- {
2214
- className: clsx(
2215
- "flex items-start justify-between gap-4 border-b border-gray-200 px-5 py-4 dark:border-gray-800",
2216
- className
2217
- ),
2218
- children: [
2219
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2220
- title && /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: title }),
2221
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description }),
2222
- children
2223
- ] }),
2224
- onClose && /* @__PURE__ */ jsx(
2225
- "button",
2226
- {
2227
- type: "button",
2228
- onClick: onClose,
2229
- "aria-label": "Close modal",
2230
- className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-white/5 dark:hover:text-gray-300",
2231
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
2232
- }
2233
- )
2234
- ]
2235
- }
2236
- );
2214
+ var Header2 = ({ title, description, onClose, className, children }) => {
2215
+ const titleId = useDialogTitleId();
2216
+ return /* @__PURE__ */ jsxs(
2217
+ "div",
2218
+ {
2219
+ className: clsx(
2220
+ "flex items-start justify-between gap-4 border-b border-gray-200 px-5 py-4 dark:border-gray-800",
2221
+ className
2222
+ ),
2223
+ children: [
2224
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2225
+ title && /* @__PURE__ */ jsx("h2", { id: titleId, className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: title }),
2226
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description }),
2227
+ children
2228
+ ] }),
2229
+ onClose && /* @__PURE__ */ jsx(
2230
+ "button",
2231
+ {
2232
+ type: "button",
2233
+ onClick: onClose,
2234
+ "aria-label": "Close modal",
2235
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-white/5 dark:hover:text-gray-300",
2236
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
2237
+ }
2238
+ )
2239
+ ]
2240
+ }
2241
+ );
2242
+ };
2237
2243
  var Body3 = ({ children, className }) => /* @__PURE__ */ jsx("div", { className: clsx("px-5 py-4", className), children });
2238
2244
  var Footer3 = ({ children, className }) => /* @__PURE__ */ jsx(
2239
2245
  "div",
@@ -2282,7 +2288,7 @@ var Alert = ({
2282
2288
  const handleConfirm = () => onConfirm ? onConfirm() : onClose();
2283
2289
  const handleCancel = () => onCancel ? onCancel() : onClose();
2284
2290
  if (layout === "horizontal") {
2285
- return /* @__PURE__ */ jsxs(Root8, { open, onClose, size: "lg", children: [
2291
+ return /* @__PURE__ */ jsxs(Root8, { open, onClose, size: "lg", ariaLabel: title, children: [
2286
2292
  /* @__PURE__ */ jsxs("div", { className: "bg-white sm:flex sm:items-start sm:p-6 dark:bg-gray-900", children: [
2287
2293
  /* @__PURE__ */ jsx(
2288
2294
  "div",
@@ -2314,7 +2320,7 @@ var Alert = ({
2314
2320
  ] })
2315
2321
  ] });
2316
2322
  }
2317
- return /* @__PURE__ */ jsx(Root8, { open, onClose, size: "sm", children: /* @__PURE__ */ jsxs("div", { className: "p-6 text-center", children: [
2323
+ return /* @__PURE__ */ jsx(Root8, { open, onClose, size: "sm", ariaLabel: title, children: /* @__PURE__ */ jsxs("div", { className: "p-6 text-center", children: [
2318
2324
  /* @__PURE__ */ jsx(
2319
2325
  "div",
2320
2326
  {
@@ -2392,9 +2398,12 @@ var Root9 = ({
2392
2398
  size = "md",
2393
2399
  withBackdrop = true,
2394
2400
  closeOutside = false,
2401
+ ariaLabel,
2395
2402
  className,
2396
2403
  children
2397
2404
  }) => {
2405
+ const titleId = useId();
2406
+ const trapRef = useFocusTrap(open);
2398
2407
  useEffect(() => {
2399
2408
  if (!open) return;
2400
2409
  const handler = (e) => {
@@ -2434,6 +2443,8 @@ var Root9 = ({
2434
2443
  /* @__PURE__ */ jsx(
2435
2444
  "aside",
2436
2445
  {
2446
+ ref: trapRef,
2447
+ tabIndex: -1,
2437
2448
  className: clsx(
2438
2449
  "fixed top-0 bottom-0 z-50 flex flex-col border-gray-200 bg-white shadow-2xl transition-transform duration-300 ease-in-out dark:border-gray-800 dark:bg-gray-900",
2439
2450
  SIDE_CLASS[side],
@@ -2443,7 +2454,9 @@ var Root9 = ({
2443
2454
  ),
2444
2455
  role: "dialog",
2445
2456
  "aria-modal": "true",
2446
- children
2457
+ "aria-label": ariaLabel,
2458
+ "aria-labelledby": ariaLabel ? void 0 : titleId,
2459
+ children: /* @__PURE__ */ jsx(DialogTitleProvider, { value: titleId, children })
2447
2460
  }
2448
2461
  )
2449
2462
  ] }),
@@ -2457,37 +2470,47 @@ var Header3 = ({
2457
2470
  onClose,
2458
2471
  className,
2459
2472
  children
2460
- }) => /* @__PURE__ */ jsxs(
2461
- "div",
2462
- {
2463
- className: clsx(
2464
- "flex shrink-0 items-center justify-between border-b border-gray-200 p-5 dark:border-gray-800",
2465
- className
2466
- ),
2467
- children: [
2468
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
2469
- Icon2 && /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsx(Icon2, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" }) }),
2470
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2471
- /* @__PURE__ */ jsx("h3", { className: "truncate text-base font-semibold text-gray-900 dark:text-white", children: title }),
2472
- description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 truncate text-sm text-gray-500 dark:text-gray-400", children: description })
2473
+ }) => {
2474
+ const titleId = useDialogTitleId();
2475
+ return /* @__PURE__ */ jsxs(
2476
+ "div",
2477
+ {
2478
+ className: clsx(
2479
+ "flex shrink-0 items-center justify-between border-b border-gray-200 p-5 dark:border-gray-800",
2480
+ className
2481
+ ),
2482
+ children: [
2483
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
2484
+ Icon2 && /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsx(Icon2, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" }) }),
2485
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2486
+ /* @__PURE__ */ jsx(
2487
+ "h3",
2488
+ {
2489
+ id: titleId,
2490
+ className: "truncate text-base font-semibold text-gray-900 dark:text-white",
2491
+ children: title
2492
+ }
2493
+ ),
2494
+ description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 truncate text-sm text-gray-500 dark:text-gray-400", children: description })
2495
+ ] })
2496
+ ] }),
2497
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2498
+ children,
2499
+ onClose && /* @__PURE__ */ jsx(
2500
+ "button",
2501
+ {
2502
+ type: "button",
2503
+ onClick: onClose,
2504
+ "aria-label": "Close drawer",
2505
+ className: "text-gray-400 transition-colors hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300",
2506
+ children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
2507
+ }
2508
+ )
2473
2509
  ] })
2474
- ] }),
2475
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2476
- children,
2477
- onClose && /* @__PURE__ */ jsx(
2478
- "button",
2479
- {
2480
- type: "button",
2481
- onClick: onClose,
2482
- "aria-label": "Close drawer",
2483
- className: "text-gray-400 transition-colors hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300",
2484
- children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
2485
- }
2486
- )
2487
- ] })
2488
- ]
2489
- }
2490
- );
2510
+ ]
2511
+ }
2512
+ );
2513
+ };
2491
2514
  var Body4 = ({ children, className }) => /* @__PURE__ */ jsx("div", { className: clsx("flex-1 overflow-y-auto p-5", className), children });
2492
2515
  var Footer4 = ({ children, className }) => /* @__PURE__ */ jsx(
2493
2516
  "div",
@@ -3072,6 +3095,8 @@ var ConfirmationModal = ({
3072
3095
  saveLabel = "Save & go",
3073
3096
  hideSave = false
3074
3097
  }) => {
3098
+ const titleId = useId();
3099
+ const trapRef = useFocusTrap(open);
3075
3100
  useEffect(() => {
3076
3101
  if (!open) return;
3077
3102
  const handler = (e) => {
@@ -3085,24 +3110,19 @@ var ConfirmationModal = ({
3085
3110
  /* @__PURE__ */ jsxs(
3086
3111
  "div",
3087
3112
  {
3113
+ ref: trapRef,
3114
+ tabIndex: -1,
3088
3115
  className: "fixed inset-0 z-50 flex items-center justify-center p-4",
3089
3116
  role: "dialog",
3090
3117
  "aria-modal": "true",
3091
- "aria-labelledby": "cosmos-confirmation-title",
3118
+ "aria-labelledby": titleId,
3092
3119
  children: [
3093
3120
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm", onClick: onStay, "aria-hidden": true }),
3094
3121
  /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-md overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-2xl dark:border-gray-700 dark:bg-gray-900", children: [
3095
3122
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4 p-6", children: [
3096
3123
  /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-amber-50 dark:bg-amber-500/10", children: /* @__PURE__ */ jsx(AlertTriangle, { className: "h-5 w-5 text-amber-500" }) }),
3097
3124
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3098
- /* @__PURE__ */ jsx(
3099
- "h3",
3100
- {
3101
- id: "cosmos-confirmation-title",
3102
- className: "font-semibold text-gray-900 dark:text-white",
3103
- children: title
3104
- }
3105
- ),
3125
+ /* @__PURE__ */ jsx("h3", { id: titleId, className: "font-semibold text-gray-900 dark:text-white", children: title }),
3106
3126
  /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: message })
3107
3127
  ] }),
3108
3128
  /* @__PURE__ */ jsx(
@@ -3459,7 +3479,7 @@ var NotificationsPanelFooter = ({
3459
3479
  if (closeOnClick && !e.defaultPrevented) setOpen(false);
3460
3480
  },
3461
3481
  className: clsx(
3462
- "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",
3482
+ "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",
3463
3483
  className
3464
3484
  ),
3465
3485
  ...rest,
@@ -3792,7 +3812,7 @@ var SIZE_CLASS9 = {
3792
3812
  sm: { box: "h-8 w-8", icon: "h-4 w-4" },
3793
3813
  md: { box: "h-10 w-10", icon: "h-5 w-5" }
3794
3814
  };
3795
- var TRI_ORDER = ["light", "dark", "oled"];
3815
+ var TRI_ORDER = ["light", "dark", "deep-blue"];
3796
3816
  var nextInCycle = (current) => {
3797
3817
  const idx = TRI_ORDER.indexOf(current);
3798
3818
  return TRI_ORDER[(idx + 1) % TRI_ORDER.length];
@@ -3800,7 +3820,7 @@ var nextInCycle = (current) => {
3800
3820
  var ICON_FOR = {
3801
3821
  light: Sun,
3802
3822
  dark: Moon,
3803
- oled: MoonStar
3823
+ "deep-blue": MoonStar
3804
3824
  };
3805
3825
  var ThemeToggleTri = forwardRef(
3806
3826
  function ThemeToggleTri2({
@@ -3809,12 +3829,12 @@ var ThemeToggleTri = forwardRef(
3809
3829
  size = "md",
3810
3830
  lightLabel = "Switch to light mode",
3811
3831
  darkLabel = "Switch to dark mode",
3812
- oledLabel = "Switch to OLED mode",
3832
+ deepBlueLabel = "Switch to deep blue mode",
3813
3833
  className,
3814
3834
  ...rest
3815
3835
  }, ref) {
3816
3836
  const next = nextInCycle(theme);
3817
- const label = next === "light" ? lightLabel : next === "dark" ? darkLabel : oledLabel;
3837
+ const label = next === "light" ? lightLabel : next === "dark" ? darkLabel : deepBlueLabel;
3818
3838
  const Icon2 = ICON_FOR[theme];
3819
3839
  const { box, icon } = SIZE_CLASS9[size];
3820
3840
  return /* @__PURE__ */ jsx(
@@ -4066,9 +4086,12 @@ var PopoverRoot = ({
4066
4086
  const handler = () => refreshRect();
4067
4087
  window.addEventListener("resize", handler);
4068
4088
  window.addEventListener("scroll", handler, true);
4089
+ const observer = new ResizeObserver(handler);
4090
+ if (triggerRef.current) observer.observe(triggerRef.current, { box: "border-box" });
4069
4091
  return () => {
4070
4092
  window.removeEventListener("resize", handler);
4071
4093
  window.removeEventListener("scroll", handler, true);
4094
+ observer.disconnect();
4072
4095
  };
4073
4096
  }, [open, refreshRect]);
4074
4097
  useEffect(() => {
@@ -4107,13 +4130,18 @@ var PopoverTrigger = forwardRef(function PopoverTrigger2({ onClick, children, ..
4107
4130
  }
4108
4131
  );
4109
4132
  });
4110
- var positionStyle = (position, rect, offset) => {
4133
+ var VIEWPORT_MARGIN = 16;
4134
+ var positionStyle = (position, align, rect, offset) => {
4135
+ const left = align === "end" ? rect.right : rect.left + rect.width / 2;
4136
+ const shiftX = align === "end" ? "-100%" : "-50%";
4137
+ const maxWidth = align === "end" ? rect.right - VIEWPORT_MARGIN : void 0;
4111
4138
  switch (position) {
4112
4139
  case "top":
4113
4140
  return {
4114
4141
  top: rect.top - offset,
4115
- left: rect.left + rect.width / 2,
4116
- transform: "translate(-50%, -100%)"
4142
+ left,
4143
+ maxWidth,
4144
+ transform: `translate(${shiftX}, -100%)`
4117
4145
  };
4118
4146
  case "right":
4119
4147
  return {
@@ -4131,32 +4159,36 @@ var positionStyle = (position, rect, offset) => {
4131
4159
  default:
4132
4160
  return {
4133
4161
  top: rect.bottom + offset,
4134
- left: rect.left + rect.width / 2,
4135
- transform: "translateX(-50%)"
4162
+ left,
4163
+ maxWidth,
4164
+ transform: `translateX(${shiftX})`
4136
4165
  };
4137
4166
  }
4138
4167
  };
4139
- var arrowStyle = (position) => {
4168
+ var arrowStyle = (position, align, rect) => {
4140
4169
  const base = {
4141
4170
  position: "absolute",
4142
4171
  width: 8,
4143
4172
  height: 8,
4144
4173
  transform: "rotate(45deg)"
4145
4174
  };
4175
+ const x = align === "end" ? { right: rect.width / 2 - 1, marginRight: -4 } : { left: "50%", marginLeft: -4 };
4146
4176
  switch (position) {
4147
4177
  case "top":
4148
- return { ...base, bottom: -4, left: "50%", marginLeft: -4 };
4178
+ return { ...base, bottom: -4, ...x };
4149
4179
  case "right":
4150
4180
  return { ...base, left: -4, top: "50%", marginTop: -4 };
4151
4181
  case "left":
4152
4182
  return { ...base, right: -4, top: "50%", marginTop: -4 };
4153
4183
  case "bottom":
4154
4184
  default:
4155
- return { ...base, top: -4, left: "50%", marginLeft: -4 };
4185
+ return { ...base, top: -4, ...x };
4156
4186
  }
4157
4187
  };
4158
4188
  var PopoverContent = ({
4159
4189
  position = "bottom",
4190
+ align = "center",
4191
+ "aria-label": ariaLabel,
4160
4192
  offset = 8,
4161
4193
  arrow = false,
4162
4194
  width = "w-64",
@@ -4172,7 +4204,8 @@ var PopoverContent = ({
4172
4204
  "div",
4173
4205
  {
4174
4206
  role: "dialog",
4175
- style: positionStyle(position, triggerRect, offset),
4207
+ "aria-label": ariaLabel,
4208
+ style: positionStyle(position, align, triggerRect, offset),
4176
4209
  className: clsx(
4177
4210
  "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",
4178
4211
  width,
@@ -4183,7 +4216,7 @@ var PopoverContent = ({
4183
4216
  "span",
4184
4217
  {
4185
4218
  "aria-hidden": true,
4186
- style: arrowStyle(position),
4219
+ style: arrowStyle(position, align, triggerRect),
4187
4220
  className: "border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900"
4188
4221
  }
4189
4222
  ),
@@ -7604,7 +7637,7 @@ var ColumnHeader = ({
7604
7637
  "aria-label": "Filter column",
7605
7638
  className: clsx(
7606
7639
  "flex items-center gap-1 rounded p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-white/10",
7607
- filterCount > 0 && "text-brand-500"
7640
+ filterCount > 0 && "text-brand-600 dark:text-brand-400"
7608
7641
  ),
7609
7642
  children: [
7610
7643
  /* @__PURE__ */ jsx(Filter, { className: "h-3 w-3" }),
@@ -8111,6 +8144,34 @@ var DataTable = ({
8111
8144
  }
8112
8145
  );
8113
8146
  };
8147
+ var AuthLayout = ({
8148
+ logo: Logo,
8149
+ title,
8150
+ subtitle,
8151
+ brand,
8152
+ children,
8153
+ className
8154
+ }) => {
8155
+ const showBuiltInBrand = brand === void 0 && (Logo || title || subtitle);
8156
+ const renderBrand = brand !== void 0 ? brand : showBuiltInBrand ? /* @__PURE__ */ jsxs("div", { className: "mb-8 flex flex-col items-center gap-2 text-center", children: [
8157
+ Logo && /* @__PURE__ */ jsx("div", { className: "bg-brand-500 flex h-12 w-12 items-center justify-center rounded-xl text-white", children: /* @__PURE__ */ jsx(Logo, { className: "h-6 w-6" }) }),
8158
+ title && /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-gray-900 dark:text-white", children: title }),
8159
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: subtitle })
8160
+ ] }) : null;
8161
+ return /* @__PURE__ */ jsx(
8162
+ "div",
8163
+ {
8164
+ className: clsx(
8165
+ "flex min-h-screen items-center justify-center bg-gray-50 p-4 dark:bg-gray-950",
8166
+ className
8167
+ ),
8168
+ children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-8 shadow-sm dark:border-gray-800 dark:bg-gray-900", children: [
8169
+ renderBrand,
8170
+ children
8171
+ ] }) })
8172
+ }
8173
+ );
8174
+ };
8114
8175
  var ErrorPage = ({
8115
8176
  code,
8116
8177
  title,
@@ -8134,6 +8195,462 @@ var ErrorPage = ({
8134
8195
  ]
8135
8196
  }
8136
8197
  );
8198
+ var STATUS_LABEL2 = {
8199
+ connected: "Connected",
8200
+ available: "Available",
8201
+ error: "Error",
8202
+ pending: "Pending"
8203
+ };
8204
+ var STATUS_VARIANT = {
8205
+ connected: "success",
8206
+ available: "neutral",
8207
+ error: "danger",
8208
+ pending: "warning"
8209
+ };
8210
+ var IntegrationCard = ({
8211
+ logo,
8212
+ name,
8213
+ description,
8214
+ status,
8215
+ category,
8216
+ actionLabel,
8217
+ actionVariant = "primary",
8218
+ onAction,
8219
+ secondaryLabel,
8220
+ onSecondary,
8221
+ loading = false,
8222
+ className
8223
+ }) => /* @__PURE__ */ jsxs(
8224
+ "div",
8225
+ {
8226
+ className: clsx(
8227
+ "flex h-full flex-col rounded-2xl border border-gray-200 bg-white p-5 transition-shadow hover:shadow-md dark:border-gray-700 dark:bg-gray-800",
8228
+ className
8229
+ ),
8230
+ children: [
8231
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
8232
+ /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-gray-100 bg-white dark:border-gray-700 dark:bg-gray-900 [&_img]:h-full [&_img]:w-full [&_img]:object-contain [&_svg]:h-7 [&_svg]:w-7", children: logo }),
8233
+ status && /* @__PURE__ */ jsx(Badge, { variant: STATUS_VARIANT[status], appearance: "light", children: STATUS_LABEL2[status] })
8234
+ ] }),
8235
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 min-w-0 flex-1", children: [
8236
+ category && /* @__PURE__ */ jsx("p", { className: "font-mono text-[10px] tracking-wide text-gray-400 uppercase dark:text-gray-500", children: category }),
8237
+ /* @__PURE__ */ jsx("h3", { className: "mt-0.5 truncate text-sm font-semibold text-gray-900 dark:text-white", children: name }),
8238
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 text-xs text-gray-600 dark:text-gray-400", children: description })
8239
+ ] }),
8240
+ (actionLabel || secondaryLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2", children: [
8241
+ secondaryLabel && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onSecondary, disabled: loading, children: secondaryLabel }),
8242
+ actionLabel && /* @__PURE__ */ jsx(
8243
+ Button,
8244
+ {
8245
+ variant: actionVariant,
8246
+ size: "sm",
8247
+ onClick: onAction,
8248
+ loading,
8249
+ disabled: loading,
8250
+ children: actionLabel
8251
+ }
8252
+ )
8253
+ ] })
8254
+ ]
8255
+ }
8256
+ );
8257
+ var ResetPasswordForm = ({
8258
+ onSubmit,
8259
+ signInHref,
8260
+ signInLabel = "Back to sign in",
8261
+ sent = false,
8262
+ sentEmail,
8263
+ loading = false,
8264
+ error,
8265
+ title = "Reset your password",
8266
+ description = "Enter your email and we\u2019ll send you a link to reset your password.",
8267
+ submitLabel = "Send reset link",
8268
+ onResend,
8269
+ resendLabel = "Resend",
8270
+ className
8271
+ }) => {
8272
+ const [email, setEmail] = useState("");
8273
+ const handleSubmit = (e) => {
8274
+ e.preventDefault();
8275
+ if (loading || email.length === 0) return;
8276
+ void onSubmit(email);
8277
+ };
8278
+ if (sent) {
8279
+ return /* @__PURE__ */ jsxs("div", { className, children: [
8280
+ /* @__PURE__ */ jsx("div", { className: "bg-brand-500/10 text-brand-600 dark:text-brand-400 mx-auto flex h-12 w-12 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(MailCheck, { className: "h-6 w-6", "aria-hidden": true }) }),
8281
+ /* @__PURE__ */ jsx("h1", { className: "mt-4 text-center text-xl font-semibold text-gray-900 dark:text-white", children: "Check your inbox" }),
8282
+ /* @__PURE__ */ jsxs("p", { className: "mt-2 text-center text-sm text-gray-500 dark:text-gray-400", children: [
8283
+ "We've sent a reset link to",
8284
+ " ",
8285
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700 dark:text-gray-200", children: sentEmail ?? email }),
8286
+ ". The link expires in 1 hour."
8287
+ ] }),
8288
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-col items-stretch gap-2", children: [
8289
+ onResend && /* @__PURE__ */ jsx(Button, { variant: "secondary", loading, disabled: loading, onClick: onResend, children: resendLabel }),
8290
+ signInHref && /* @__PURE__ */ jsxs(Link, { href: signInHref, variant: "subtle", className: "justify-center", children: [
8291
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5", "aria-hidden": true }),
8292
+ signInLabel
8293
+ ] })
8294
+ ] })
8295
+ ] });
8296
+ }
8297
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, children: [
8298
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
8299
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: title }),
8300
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description })
8301
+ ] }),
8302
+ error && /* @__PURE__ */ jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsx(AlertBanner, { variant: "error", children: error }) }),
8303
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8304
+ /* @__PURE__ */ jsx(
8305
+ Input,
8306
+ {
8307
+ label: "Email",
8308
+ type: "email",
8309
+ icon: Mail,
8310
+ autoComplete: "email",
8311
+ required: true,
8312
+ placeholder: "john@example.com",
8313
+ value: email,
8314
+ onChange: (e) => setEmail(e.target.value),
8315
+ disabled: loading
8316
+ }
8317
+ ),
8318
+ /* @__PURE__ */ jsx(
8319
+ Button,
8320
+ {
8321
+ type: "submit",
8322
+ loading,
8323
+ disabled: loading || email.length === 0,
8324
+ className: "w-full",
8325
+ children: submitLabel
8326
+ }
8327
+ )
8328
+ ] }),
8329
+ signInHref && /* @__PURE__ */ jsx("p", { className: "mt-5 text-center text-xs text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsxs(Link, { href: signInHref, variant: "colored", children: [
8330
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5", "aria-hidden": true }),
8331
+ signInLabel
8332
+ ] }) })
8333
+ ] });
8334
+ };
8335
+ var SignInForm = ({
8336
+ onSubmit,
8337
+ onForgotPassword,
8338
+ signUpHref,
8339
+ signUpLabel = "Create one",
8340
+ title = "Sign in",
8341
+ description = "Welcome back \u2014 enter your credentials below.",
8342
+ emailLabel = "Email",
8343
+ passwordLabel = "Password",
8344
+ rememberLabel = "Keep me signed in",
8345
+ submitLabel = "Sign in",
8346
+ forgotLabel = "Forgot password?",
8347
+ loading = false,
8348
+ error,
8349
+ extraTop,
8350
+ className
8351
+ }) => {
8352
+ const [email, setEmail] = useState("");
8353
+ const [password, setPassword] = useState("");
8354
+ const [remember, setRemember] = useState(false);
8355
+ const handleSubmit = (e) => {
8356
+ e.preventDefault();
8357
+ if (loading) return;
8358
+ void onSubmit({ email, password, remember });
8359
+ };
8360
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, children: [
8361
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
8362
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: title }),
8363
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description })
8364
+ ] }),
8365
+ extraTop && /* @__PURE__ */ jsx("div", { className: "mb-5", children: extraTop }),
8366
+ error && /* @__PURE__ */ jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsx(AlertBanner, { variant: "error", children: error }) }),
8367
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8368
+ /* @__PURE__ */ jsx(
8369
+ Input,
8370
+ {
8371
+ label: emailLabel,
8372
+ type: "email",
8373
+ icon: Mail,
8374
+ autoComplete: "email",
8375
+ required: true,
8376
+ placeholder: "john@example.com",
8377
+ value: email,
8378
+ onChange: (e) => setEmail(e.target.value),
8379
+ disabled: loading
8380
+ }
8381
+ ),
8382
+ /* @__PURE__ */ jsx(
8383
+ PasswordInput,
8384
+ {
8385
+ label: passwordLabel,
8386
+ autoComplete: "current-password",
8387
+ required: true,
8388
+ value: password,
8389
+ onChange: (e) => setPassword(e.target.value),
8390
+ disabled: loading
8391
+ }
8392
+ ),
8393
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8394
+ /* @__PURE__ */ jsx(
8395
+ Checkbox,
8396
+ {
8397
+ label: rememberLabel,
8398
+ checked: remember,
8399
+ onChange: (c) => setRemember(c),
8400
+ disabled: loading
8401
+ }
8402
+ ),
8403
+ onForgotPassword && /* @__PURE__ */ jsx(
8404
+ "button",
8405
+ {
8406
+ type: "button",
8407
+ onClick: onForgotPassword,
8408
+ className: "text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 text-xs font-medium transition-colors",
8409
+ children: forgotLabel
8410
+ }
8411
+ )
8412
+ ] }),
8413
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading, disabled: loading, className: "w-full", children: submitLabel })
8414
+ ] }),
8415
+ signUpHref && /* @__PURE__ */ jsxs("p", { className: "mt-5 text-center text-xs text-[var(--color-text-muted)]", children: [
8416
+ "No account?",
8417
+ " ",
8418
+ /* @__PURE__ */ jsx(Link, { href: signUpHref, variant: "colored", children: signUpLabel })
8419
+ ] })
8420
+ ] });
8421
+ };
8422
+ var SignUpForm = ({
8423
+ onSubmit,
8424
+ signInHref,
8425
+ signInLabel = "Sign in",
8426
+ termsHref = "#",
8427
+ privacyHref = "#",
8428
+ showPolicy = true,
8429
+ loading = false,
8430
+ error,
8431
+ title = "Create your account",
8432
+ description = "A few details to get you started.",
8433
+ submitLabel = "Create account",
8434
+ extraTop,
8435
+ className
8436
+ }) => {
8437
+ const [firstName, setFirstName] = useState("");
8438
+ const [lastName, setLastName] = useState("");
8439
+ const [email, setEmail] = useState("");
8440
+ const [password, setPassword] = useState("");
8441
+ const [agreedToTerms, setAgreedToTerms] = useState(false);
8442
+ const rules = useMemo(() => defaultPasswordRules(password), [password]);
8443
+ const allRulesPass = rules.every((r) => r.ok);
8444
+ const canSubmit = firstName.length > 0 && lastName.length > 0 && email.length > 0 && (showPolicy ? allRulesPass : password.length > 0) && agreedToTerms && !loading;
8445
+ const handleSubmit = (e) => {
8446
+ e.preventDefault();
8447
+ if (!canSubmit) return;
8448
+ void onSubmit({ firstName, lastName, email, password, agreedToTerms });
8449
+ };
8450
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, children: [
8451
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
8452
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: title }),
8453
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description })
8454
+ ] }),
8455
+ extraTop && /* @__PURE__ */ jsx("div", { className: "mb-5", children: extraTop }),
8456
+ error && /* @__PURE__ */ jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsx(AlertBanner, { variant: "error", children: error }) }),
8457
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8458
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
8459
+ /* @__PURE__ */ jsx(
8460
+ Input,
8461
+ {
8462
+ label: "First name",
8463
+ icon: User,
8464
+ autoComplete: "given-name",
8465
+ required: true,
8466
+ placeholder: "John",
8467
+ value: firstName,
8468
+ onChange: (e) => setFirstName(e.target.value),
8469
+ disabled: loading
8470
+ }
8471
+ ),
8472
+ /* @__PURE__ */ jsx(
8473
+ Input,
8474
+ {
8475
+ label: "Last name",
8476
+ autoComplete: "family-name",
8477
+ required: true,
8478
+ placeholder: "Doe",
8479
+ value: lastName,
8480
+ onChange: (e) => setLastName(e.target.value),
8481
+ disabled: loading
8482
+ }
8483
+ )
8484
+ ] }),
8485
+ /* @__PURE__ */ jsx(
8486
+ Input,
8487
+ {
8488
+ label: "Email",
8489
+ type: "email",
8490
+ icon: Mail,
8491
+ autoComplete: "email",
8492
+ required: true,
8493
+ placeholder: "john@example.com",
8494
+ value: email,
8495
+ onChange: (e) => setEmail(e.target.value),
8496
+ disabled: loading
8497
+ }
8498
+ ),
8499
+ /* @__PURE__ */ jsx(
8500
+ PasswordInput,
8501
+ {
8502
+ label: "Password",
8503
+ autoComplete: "new-password",
8504
+ required: true,
8505
+ value: password,
8506
+ onChange: (e) => setPassword(e.target.value),
8507
+ disabled: loading
8508
+ }
8509
+ ),
8510
+ showPolicy && password.length > 0 && /* @__PURE__ */ jsx(PasswordPolicyChecker, { rules }),
8511
+ /* @__PURE__ */ jsx(
8512
+ Checkbox,
8513
+ {
8514
+ label: /* @__PURE__ */ jsxs("span", { children: [
8515
+ "I agree to the",
8516
+ " ",
8517
+ /* @__PURE__ */ jsx(Link, { href: termsHref, variant: "underline", className: "text-current", children: "terms" }),
8518
+ " ",
8519
+ "and",
8520
+ " ",
8521
+ /* @__PURE__ */ jsx(Link, { href: privacyHref, variant: "underline", className: "text-current", children: "privacy policy" }),
8522
+ "."
8523
+ ] }),
8524
+ checked: agreedToTerms,
8525
+ onChange: (c) => setAgreedToTerms(c),
8526
+ disabled: loading
8527
+ }
8528
+ ),
8529
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading, disabled: !canSubmit, className: "w-full", children: submitLabel })
8530
+ ] }),
8531
+ signInHref && /* @__PURE__ */ jsxs("p", { className: "mt-5 text-center text-xs text-[var(--color-text-muted)]", children: [
8532
+ "Already have an account?",
8533
+ " ",
8534
+ /* @__PURE__ */ jsx(Link, { href: signInHref, variant: "colored", children: signInLabel })
8535
+ ] })
8536
+ ] });
8537
+ };
8538
+ var PROVIDER_NAME = {
8539
+ google: "Google",
8540
+ github: "GitHub",
8541
+ x: "X",
8542
+ facebook: "Facebook",
8543
+ apple: "Apple",
8544
+ microsoft: "Microsoft"
8545
+ };
8546
+ var GoogleIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": true, children: [
8547
+ /* @__PURE__ */ jsx(
8548
+ "path",
8549
+ {
8550
+ fill: "#4285F4",
8551
+ d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
8552
+ }
8553
+ ),
8554
+ /* @__PURE__ */ jsx(
8555
+ "path",
8556
+ {
8557
+ fill: "#34A853",
8558
+ d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84A10.99 10.99 0 0 0 12 23z"
8559
+ }
8560
+ ),
8561
+ /* @__PURE__ */ jsx(
8562
+ "path",
8563
+ {
8564
+ fill: "#FBBC05",
8565
+ d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18a10.99 10.99 0 0 0 0 9.86l3.66-2.84z"
8566
+ }
8567
+ ),
8568
+ /* @__PURE__ */ jsx(
8569
+ "path",
8570
+ {
8571
+ fill: "#EA4335",
8572
+ d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1a10.99 10.99 0 0 0-9.82 6.07l3.66 2.84C6.71 7.31 9.14 5.38 12 5.38z"
8573
+ }
8574
+ )
8575
+ ] });
8576
+ var GithubIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": true, children: /* @__PURE__ */ jsx(
8577
+ "path",
8578
+ {
8579
+ fillRule: "evenodd",
8580
+ clipRule: "evenodd",
8581
+ d: "M12 2C6.48 2 2 6.58 2 12.26c0 4.49 2.87 8.3 6.84 9.65.5.09.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.36-3.37-1.36-.46-1.18-1.11-1.5-1.11-1.5-.91-.63.07-.62.07-.62 1 .07 1.53 1.05 1.53 1.05.89 1.56 2.34 1.11 2.91.85.09-.66.35-1.11.63-1.36-2.22-.26-4.55-1.13-4.55-5.04 0-1.11.39-2.02 1.03-2.74-.1-.26-.45-1.3.1-2.71 0 0 .84-.27 2.75 1.05A9.4 9.4 0 0 1 12 6.99c.85 0 1.71.12 2.51.34 1.91-1.32 2.75-1.05 2.75-1.05.55 1.41.2 2.45.1 2.71.64.72 1.03 1.63 1.03 2.74 0 3.92-2.34 4.78-4.57 5.03.36.32.68.94.68 1.9 0 1.37-.01 2.48-.01 2.81 0 .27.18.59.69.49A10.04 10.04 0 0 0 22 12.26C22 6.58 17.52 2 12 2z"
8582
+ }
8583
+ ) });
8584
+ var XIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231 5.45-6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117l11.966 15.644Z" }) });
8585
+ var FacebookIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": true, children: /* @__PURE__ */ jsx(
8586
+ "path",
8587
+ {
8588
+ fill: "#1877F2",
8589
+ d: "M24 12.07C24 5.41 18.63 0 12 0S0 5.41 0 12.07c0 6.02 4.39 11.01 10.13 11.93v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.69.23 2.69.23v2.97h-1.51c-1.49 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.61 23.08 24 18.09 24 12.07Z"
8590
+ }
8591
+ ) });
8592
+ var AppleIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M17.05 12.04c-.03-2.97 2.43-4.4 2.54-4.47-1.39-2.03-3.55-2.31-4.32-2.34-1.83-.19-3.59 1.08-4.52 1.08-.95 0-2.38-1.06-3.92-1.03-2.01.03-3.88 1.18-4.92 2.97-2.1 3.65-.54 9.05 1.51 12.01 1 1.45 2.18 3.07 3.74 3.01 1.51-.06 2.07-.97 3.89-.97 1.81 0 2.32.97 3.92.94 1.62-.03 2.65-1.46 3.62-2.92 1.15-1.67 1.62-3.32 1.65-3.4-.04-.01-3.16-1.21-3.19-4.81zM14.06 3.74c.81-1 1.36-2.39 1.21-3.78-1.17.05-2.6.79-3.44 1.78-.74.87-1.4 2.28-1.23 3.64 1.31.1 2.65-.66 3.46-1.65z" }) });
8593
+ var MicrosoftIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": true, children: [
8594
+ /* @__PURE__ */ jsx("path", { fill: "#F25022", d: "M11.4 11.4H1V1h10.4v10.4Z" }),
8595
+ /* @__PURE__ */ jsx("path", { fill: "#7FBA00", d: "M23 11.4H12.6V1H23v10.4Z" }),
8596
+ /* @__PURE__ */ jsx("path", { fill: "#00A4EF", d: "M11.4 23H1V12.6h10.4V23Z" }),
8597
+ /* @__PURE__ */ jsx("path", { fill: "#FFB900", d: "M23 23H12.6V12.6H23V23Z" })
8598
+ ] });
8599
+ var PROVIDER_ICON = {
8600
+ google: GoogleIcon,
8601
+ github: GithubIcon,
8602
+ x: XIcon,
8603
+ facebook: FacebookIcon,
8604
+ apple: AppleIcon,
8605
+ microsoft: MicrosoftIcon
8606
+ };
8607
+ var SocialAuthButtons = ({
8608
+ providers,
8609
+ onProviderClick,
8610
+ loading,
8611
+ divider = true,
8612
+ dividerLabel = "OR continue with",
8613
+ layout = "stacked",
8614
+ labelFor,
8615
+ position = "above",
8616
+ className
8617
+ }) => {
8618
+ if (providers.length === 0) return null;
8619
+ const buttonsList = /* @__PURE__ */ jsx("div", { className: clsx(layout === "grid" ? "grid grid-cols-2 gap-2" : "flex flex-col gap-2"), children: providers.map((provider) => {
8620
+ const Icon2 = PROVIDER_ICON[provider];
8621
+ const isLoading = loading === provider;
8622
+ const isDisabled = loading !== void 0 && loading !== null;
8623
+ const label = labelFor ? labelFor(provider) : `Continue with ${PROVIDER_NAME[provider]}`;
8624
+ return /* @__PURE__ */ jsxs(
8625
+ "button",
8626
+ {
8627
+ type: "button",
8628
+ onClick: () => onProviderClick(provider),
8629
+ disabled: isDisabled,
8630
+ "aria-label": label,
8631
+ className: "flex h-10 items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700",
8632
+ children: [
8633
+ isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Icon2, {}),
8634
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
8635
+ ]
8636
+ },
8637
+ provider
8638
+ );
8639
+ }) });
8640
+ if (!divider) return /* @__PURE__ */ jsx("div", { className, children: buttonsList });
8641
+ const dividerNode = /* @__PURE__ */ jsxs("div", { className: "my-4 flex items-center gap-3", children: [
8642
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" }),
8643
+ /* @__PURE__ */ jsx("span", { className: "text-xs tracking-wide text-gray-400 uppercase dark:text-gray-500", children: dividerLabel }),
8644
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" })
8645
+ ] });
8646
+ return /* @__PURE__ */ jsx("div", { className, children: position === "above" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
8647
+ buttonsList,
8648
+ dividerNode
8649
+ ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
8650
+ dividerNode,
8651
+ buttonsList
8652
+ ] }) });
8653
+ };
8137
8654
  var StickyScrollNav = ({
8138
8655
  sections,
8139
8656
  onNavigate,
@@ -8169,6 +8686,80 @@ var StickyScrollNav = ({
8169
8686
  }
8170
8687
  );
8171
8688
  };
8689
+ var TwoStepVerificationForm = ({
8690
+ onSubmit,
8691
+ onResend,
8692
+ sentTo,
8693
+ length = 6,
8694
+ loading = false,
8695
+ error,
8696
+ autoSubmit = true,
8697
+ cancelHref,
8698
+ cancelLabel = "Back to sign in",
8699
+ title = "Two-step verification",
8700
+ submitLabel = "Verify my account",
8701
+ resendLabel = "Resend code",
8702
+ className
8703
+ }) => {
8704
+ const [code, setCode] = useState("");
8705
+ const description = sentTo ? `Enter the ${length}-digit code we sent to ${sentTo}.` : `Enter the ${length}-digit verification code from your authenticator app.`;
8706
+ const handleSubmit = (e) => {
8707
+ e.preventDefault();
8708
+ if (loading || code.length !== length) return;
8709
+ void onSubmit(code);
8710
+ };
8711
+ const handleComplete = (value) => {
8712
+ if (autoSubmit && !loading) void onSubmit(value);
8713
+ };
8714
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, children: [
8715
+ /* @__PURE__ */ jsx("div", { className: "bg-brand-500/10 text-brand-600 dark:text-brand-400 mx-auto flex h-12 w-12 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(ShieldCheck, { className: "h-6 w-6", "aria-hidden": true }) }),
8716
+ /* @__PURE__ */ jsx("h1", { className: "mt-4 text-center text-xl font-semibold text-gray-900 dark:text-white", children: title }),
8717
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-center text-sm text-gray-500 dark:text-gray-400", children: description }),
8718
+ error && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(AlertBanner, { variant: "error", children: error }) }),
8719
+ /* @__PURE__ */ jsx("div", { className: "mt-6 flex justify-center", children: /* @__PURE__ */ jsx(
8720
+ OtpInput,
8721
+ {
8722
+ length,
8723
+ value: code,
8724
+ onChange: setCode,
8725
+ onComplete: handleComplete,
8726
+ disabled: loading,
8727
+ error: !!error,
8728
+ autoFocus: true
8729
+ }
8730
+ ) }),
8731
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
8732
+ /* @__PURE__ */ jsx(
8733
+ Button,
8734
+ {
8735
+ type: "submit",
8736
+ loading,
8737
+ disabled: loading || code.length !== length,
8738
+ className: "w-full",
8739
+ children: submitLabel
8740
+ }
8741
+ ),
8742
+ onResend && /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-[var(--color-text-muted)]", children: [
8743
+ "Didn't get a code?",
8744
+ " ",
8745
+ /* @__PURE__ */ jsx(
8746
+ "button",
8747
+ {
8748
+ type: "button",
8749
+ onClick: onResend,
8750
+ disabled: loading,
8751
+ 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",
8752
+ children: resendLabel
8753
+ }
8754
+ )
8755
+ ] }),
8756
+ cancelHref && /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxs(Link, { href: cancelHref, variant: "subtle", children: [
8757
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5", "aria-hidden": true }),
8758
+ cancelLabel
8759
+ ] }) })
8760
+ ] })
8761
+ ] });
8762
+ };
8172
8763
  var ColorSwatch = ({
8173
8764
  hex,
8174
8765
  label,
@@ -8273,7 +8864,7 @@ var PaletteCard = ({ meta, active = false, onClick, className }) => /* @__PURE__
8273
8864
  /* @__PURE__ */ jsxs(
8274
8865
  "div",
8275
8866
  {
8276
- className: "flex items-center justify-between px-2.5 py-1.5",
8867
+ className: "flex flex-1 items-center justify-between px-2.5 py-1.5",
8277
8868
  style: {
8278
8869
  backgroundColor: meta.preview.surface,
8279
8870
  borderTop: `1px solid ${meta.preview.border}`
@@ -8284,11 +8875,11 @@ var PaletteCard = ({ meta, active = false, onClick, className }) => /* @__PURE__
8284
8875
  "span",
8285
8876
  {
8286
8877
  className: "block text-xs font-semibold",
8287
- style: { color: active ? void 0 : "#6b7280" },
8878
+ style: { color: meta.preview.text ?? (active ? void 0 : "#6b7280") },
8288
8879
  children: meta.label
8289
8880
  }
8290
8881
  ),
8291
- meta.desc && /* @__PURE__ */ jsx("span", { className: "block text-[10px]", style: { color: "#9ca3af" }, children: meta.desc })
8882
+ meta.desc && /* @__PURE__ */ jsx("span", { className: "block text-[10px]", style: { color: meta.preview.text ?? "#9ca3af" }, children: meta.desc })
8292
8883
  ] }),
8293
8884
  active && /* @__PURE__ */ jsx("span", { className: "bg-brand-500 flex h-4 w-4 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(Check, { className: "h-2.5 w-2.5 text-white", "aria-hidden": true }) })
8294
8885
  ]
@@ -8338,7 +8929,7 @@ var OptionCard = ({
8338
8929
  {
8339
8930
  className: clsx(
8340
8931
  "text-xs font-semibold",
8341
- active ? "text-brand-500" : "text-gray-700 dark:text-gray-300"
8932
+ active ? "text-brand-600 dark:text-brand-400" : "text-gray-700 dark:text-gray-300"
8342
8933
  ),
8343
8934
  children: label
8344
8935
  }
@@ -8374,6 +8965,129 @@ var OptionPicker = ({
8374
8965
  ))
8375
8966
  }
8376
8967
  );
8968
+
8969
+ // src/settings/appearance.ts
8970
+ var COSMOS_THEMES = [
8971
+ {
8972
+ id: "light",
8973
+ label: "Light",
8974
+ dark: false,
8975
+ preview: { bg: "#f9fafb", surface: "#ffffff", border: "#e5e7eb", text: "#667085" }
8976
+ },
8977
+ {
8978
+ id: "sand",
8979
+ label: "Sand",
8980
+ dark: false,
8981
+ preview: { bg: "#f9f5eb", surface: "#fffcf7", border: "#e7dfd0", text: "#746656" }
8982
+ },
8983
+ {
8984
+ id: "dark",
8985
+ label: "Dark",
8986
+ dark: true,
8987
+ preview: { bg: "#0a0a0a", surface: "#141414", border: "#3d3d3d", text: "#a3a3a3" }
8988
+ },
8989
+ {
8990
+ id: "deep-blue",
8991
+ label: "Deep Blue",
8992
+ dark: true,
8993
+ preview: { bg: "#0c111d", surface: "#101828", border: "#344054", text: "#98a2b3" }
8994
+ }
8995
+ ];
8996
+ var COSMOS_ACCENTS = [
8997
+ { id: "blue", label: "Blue", hex: "#465fff" },
8998
+ { id: "indigo", label: "Indigo", hex: "#5963e9" },
8999
+ { id: "violet", label: "Violet", hex: "#8745f1" },
9000
+ { id: "purple", label: "Purple", hex: "#ad2ecf" },
9001
+ { id: "rose", label: "Rose", hex: "#d4166d" },
9002
+ { id: "teal", label: "Teal", hex: "#038378" },
9003
+ { id: "cyan", label: "Cyan", hex: "#017f9d" },
9004
+ { id: "graphite", label: "Graphite", hex: "#707580" },
9005
+ { id: "red", label: "Red", hex: "#db192a" },
9006
+ { id: "orange", label: "Orange", hex: "#c04f01" },
9007
+ { id: "amber", label: "Amber", hex: "#a46800" },
9008
+ { id: "green", label: "Green", hex: "#02863c" }
9009
+ ];
9010
+ var THEME_CLASSES = COSMOS_THEMES.map((t) => t.id).filter((id) => id !== "light");
9011
+ var isDarkTheme = (theme) => COSMOS_THEMES.some((t) => t.id === theme && t.dark);
9012
+ var applyAppearance = ({ theme, accent }, root) => {
9013
+ const el = root ?? (typeof document === "undefined" ? void 0 : document.documentElement);
9014
+ if (!el) return;
9015
+ el.classList.remove(...THEME_CLASSES);
9016
+ if (theme !== "light") el.classList.add(theme);
9017
+ if (accent === "blue") delete el.dataset.accent;
9018
+ else el.dataset.accent = accent;
9019
+ };
9020
+ var AppearanceSettings = ({
9021
+ theme,
9022
+ accent,
9023
+ onThemeChange,
9024
+ onAccentChange,
9025
+ themeLabel = "Theme",
9026
+ accentLabel = "Accent color",
9027
+ themes = COSMOS_THEMES,
9028
+ accents = COSMOS_ACCENTS,
9029
+ themeColumns = 4,
9030
+ className
9031
+ }) => {
9032
+ const themeHeadingId = useId();
9033
+ const accentHeadingId = useId();
9034
+ return /* @__PURE__ */ jsxs("div", { className: clsx("space-y-6", className), children: [
9035
+ /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": themeHeadingId, children: [
9036
+ /* @__PURE__ */ jsx("p", { id: themeHeadingId, className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: themeLabel }),
9037
+ /* @__PURE__ */ jsx(
9038
+ PalettePicker,
9039
+ {
9040
+ className: "mt-3",
9041
+ palettes: themes,
9042
+ value: theme,
9043
+ cols: themeColumns,
9044
+ onChange: (id) => onThemeChange(id)
9045
+ }
9046
+ )
9047
+ ] }),
9048
+ /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": accentHeadingId, children: [
9049
+ /* @__PURE__ */ jsx("p", { id: accentHeadingId, className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: accentLabel }),
9050
+ /* @__PURE__ */ jsx(
9051
+ AccentPicker,
9052
+ {
9053
+ className: "mt-3",
9054
+ colors: accents,
9055
+ value: accent,
9056
+ onChange: (id) => onAccentChange(id),
9057
+ cols: 6
9058
+ }
9059
+ )
9060
+ ] })
9061
+ ] });
9062
+ };
9063
+ var SIZE_CLASS12 = {
9064
+ sm: { box: "h-8 w-8", icon: "h-4 w-4" },
9065
+ md: { box: "h-10 w-10", icon: "h-5 w-5" }
9066
+ };
9067
+ var AppearanceMenu = ({
9068
+ label = "Appearance",
9069
+ size = "md",
9070
+ className,
9071
+ ...settings
9072
+ }) => {
9073
+ const { box, icon } = SIZE_CLASS12[size];
9074
+ return /* @__PURE__ */ jsxs(Popover, { children: [
9075
+ /* @__PURE__ */ jsx(
9076
+ Popover.Trigger,
9077
+ {
9078
+ title: label,
9079
+ "aria-label": label,
9080
+ className: clsx(
9081
+ "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",
9082
+ box,
9083
+ className
9084
+ ),
9085
+ children: /* @__PURE__ */ jsx(Palette, { className: icon, "aria-hidden": true })
9086
+ }
9087
+ ),
9088
+ /* @__PURE__ */ jsx(Popover.Content, { align: "end", width: "w-96", "aria-label": label, children: /* @__PURE__ */ jsx(AppearanceSettings, { themeColumns: 2, ...settings }) })
9089
+ ] });
9090
+ };
8377
9091
  var SIZE = {
8378
9092
  sm: "text-base leading-relaxed",
8379
9093
  md: "text-lg leading-relaxed",
@@ -8541,6 +9255,6 @@ var Figure = ({
8541
9255
  caption && /* @__PURE__ */ jsx("figcaption", { className: "mt-2 text-center text-xs text-gray-500 italic dark:text-gray-400", children: caption })
8542
9256
  ] });
8543
9257
 
8544
- export { AccentPicker, Accordion2 as Accordion, ActionPanel, ActiveFiltersBar, ActivityFeed, AlertBanner, AnnouncementBar, Avatar, AvatarUploader, BackToTopFab, Backdrop, Badge, Blockquote, Breadcrumb, Button, ButtonGroup, Calendar, Card2 as Card, Carousel, CarouselRoot, Checkbox, CheckboxGroup, ClickableRow, Clipboard, CodeBlock, ColBox, ColorSwatch, ColumnFilterDropdown, ColumnHeader, Combobox, CommandPalette, ConfirmationModal, ContentNarrow, ContentStackedList, CookieBanner, DataTable, DatePicker, DescriptionList, Divider, Drawer, Dropdown, Dropzone, EmptyState, ErrorPage, ErrorState, Figure, FileInput, FilterPills, FormFooter, FormRow, GridList, HealthBadge, HealthDot, HelpOverlay, IconBox, ImageGrid, Input, Kbd2 as Kbd, KpiCard, Link, List2 as List, LoadingState, MediaObject, MiniCalendar, Modal, NarrowStackedList, Navbar, NotificationCard, NotificationsPanel, NumberInput, OptionCard, OptionPicker, OtpInput, PageActionButton, PageActionIconButton, PageBreadcrumb, PageCard, PageHeader, Pagination, PaletteCard, PalettePicker, PasswordInput, PasswordPolicyChecker, Popover, ProgressBar, REFRESH_OPTIONS, Radio, RadioGroup, RefreshButton, Ribbon, RowActionButton, STATUS_COLOR, STATUS_PILL, SearchInput, SectionCard, SectionLabel, SegmentedControl, Select, SelectInput, Shell, Sidebar, SimpleRow, Sk, SkeletonList, SkeletonTable, SkeletonText, Spinner, StackedList, StackedListInCard, StatefulSaveButton, StatusBadge, StatusRow, Stepper, StepperInput, StepperRoot, StickyScrollNav, Tabs, Textarea, ThemeToggle, ThemeToggleTri, TimePicker, Timeline, Toaster, Toggle, Tooltip, TooltipHelp, Topbar, UnsavedIndicator, UserMenu, VerticalNavigation, VideoEmbed, ZoomBar, defaultPasswordRules, placeholderAvatar, placeholderCover, portalDocsParams, useAutoRefresh };
9258
+ export { AccentPicker, Accordion2 as Accordion, ActionPanel, ActiveFiltersBar, ActivityFeed, AlertBanner, AnnouncementBar, AppearanceMenu, AppearanceSettings, AuthLayout, Avatar, AvatarUploader, BackToTopFab, Backdrop, Badge, Blockquote, Breadcrumb, Button, ButtonGroup, COSMOS_ACCENTS, COSMOS_THEMES, Calendar, Card2 as Card, Carousel, CarouselRoot, Checkbox, CheckboxGroup, ClickableRow, Clipboard, CodeBlock, ColBox, ColorSwatch, ColumnFilterDropdown, ColumnHeader, Combobox, CommandPalette, ConfirmationModal, ContentNarrow, ContentStackedList, CookieBanner, DataTable, DatePicker, DescriptionList, Divider, Drawer, Dropdown, Dropzone, EmptyState, ErrorPage, ErrorState, Figure, FileInput, FilterPills, FormFooter, FormRow, GridList, HealthBadge, HealthDot, HelpOverlay, IconBox, ImageGrid, Input, IntegrationCard, Kbd2 as Kbd, KpiCard, Link, List2 as List, LoadingState, MediaObject, MiniCalendar, Modal, NarrowStackedList, Navbar, NotificationCard, NotificationsPanel, NumberInput, OptionCard, OptionPicker, OtpInput, PageActionButton, PageActionIconButton, PageBreadcrumb, PageCard, PageHeader, Pagination, PaletteCard, PalettePicker, PasswordInput, PasswordPolicyChecker, Popover, ProgressBar, REFRESH_OPTIONS, Radio, RadioGroup, RefreshButton, ResetPasswordForm, Ribbon, RowActionButton, STATUS_COLOR, STATUS_PILL, SearchInput, SectionCard, SectionLabel, SegmentedControl, Select, SelectInput, Shell, Sidebar, SignInForm, SignUpForm, SimpleRow, Sk, SkeletonList, SkeletonTable, SkeletonText, SocialAuthButtons, Spinner, StackedList, StackedListInCard, StatefulSaveButton, StatusBadge, StatusRow, Stepper, StepperInput, StepperRoot, StickyScrollNav, Tabs, Textarea, ThemeToggle, ThemeToggleTri, TimePicker, Timeline, Toaster, Toggle, Tooltip, TooltipHelp, Topbar, TwoStepVerificationForm, UnsavedIndicator, UserMenu, VerticalNavigation, VideoEmbed, ZoomBar, applyAppearance, defaultPasswordRules, isDarkTheme, useAutoRefresh };
8545
9259
  //# sourceMappingURL=index.js.map
8546
9260
  //# sourceMappingURL=index.js.map