@ship-it-ui/ui 0.0.8 → 0.0.9

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
@@ -138,14 +138,16 @@ function useOutsideClick(ref, handler, enabled = true) {
138
138
  }
139
139
 
140
140
  // src/hooks/useTheme.ts
141
- import { useCallback as useCallback4, useEffect as useEffect4, useState as useState4 } from "react";
141
+ import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
142
142
  function useTheme() {
143
143
  const [theme, setThemeState] = useState4("dark");
144
+ const internalMutation = useRef3(false);
144
145
  const setTheme = useCallback4((next) => {
145
146
  if (typeof document === "undefined") {
146
147
  setThemeState(next);
147
148
  return;
148
149
  }
150
+ internalMutation.current = true;
149
151
  if (next === "light") {
150
152
  document.documentElement.setAttribute("data-theme", "light");
151
153
  } else {
@@ -160,6 +162,10 @@ function useTheme() {
160
162
  const initial = document.documentElement.getAttribute("data-theme");
161
163
  setThemeState(initial === "light" ? "light" : "dark");
162
164
  const observer = new MutationObserver(() => {
165
+ if (internalMutation.current) {
166
+ internalMutation.current = false;
167
+ return;
168
+ }
163
169
  const attr = document.documentElement.getAttribute("data-theme");
164
170
  setThemeState(attr === "light" ? "light" : "dark");
165
171
  });
@@ -544,7 +550,7 @@ import {
544
550
  useCallback as useCallback5,
545
551
  useEffect as useEffect5,
546
552
  useImperativeHandle,
547
- useRef as useRef3,
553
+ useRef as useRef4,
548
554
  useState as useState5
549
555
  } from "react";
550
556
  import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -612,7 +618,7 @@ var InlineEdit = forwardRef7(function InlineEdit2({
612
618
  });
613
619
  const [draft, setDraft] = useState5(value);
614
620
  const [error, setError] = useState5(null);
615
- const inputRef = useRef3(null);
621
+ const inputRef = useRef4(null);
616
622
  useEffect5(() => {
617
623
  if (!editing) {
618
624
  setDraft(value);
@@ -855,7 +861,7 @@ import {
855
861
  useCallback as useCallback6,
856
862
  useEffect as useEffect6,
857
863
  useId as useId3,
858
- useRef as useRef4
864
+ useRef as useRef5
859
865
  } from "react";
860
866
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
861
867
  var wrapperSizes = {
@@ -891,8 +897,8 @@ var NumberInput = forwardRef10(function NumberInput2({
891
897
  });
892
898
  const reactId = useId3();
893
899
  const id = idProp ?? `ni-${reactId}`;
894
- const repeatTimer = useRef4(void 0);
895
- const repeatInterval = useRef4(void 0);
900
+ const repeatTimer = useRef5(void 0);
901
+ const repeatInterval = useRef5(void 0);
896
902
  const clamp = useCallback6((n) => Math.min(max, Math.max(min, n)), [min, max]);
897
903
  const bump = useCallback6(
898
904
  (dir) => {
@@ -1008,13 +1014,13 @@ import {
1008
1014
  forwardRef as forwardRef11,
1009
1015
  useId as useId4,
1010
1016
  useImperativeHandle as useImperativeHandle2,
1011
- useRef as useRef5,
1017
+ useRef as useRef6,
1012
1018
  useState as useState6
1013
1019
  } from "react";
1014
1020
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1015
1021
  var OTP = forwardRef11(function OTP2({ length = 6, onComplete, onChange, defaultValue = "", ariaLabel = "Code", className, disabled }, ref) {
1016
1022
  const baseId = useId4();
1017
- const refs = useRef5([]);
1023
+ const refs = useRef6([]);
1018
1024
  const [values, setValues] = useState6(
1019
1025
  () => Array.from({ length }, (_, i) => defaultValue[i] ?? "")
1020
1026
  );
@@ -1563,6 +1569,53 @@ AccordionContent.displayName = "AccordionContent";
1563
1569
  import * as RadixAvatar from "@radix-ui/react-avatar";
1564
1570
  import { forwardRef as forwardRef20 } from "react";
1565
1571
 
1572
+ // src/utils/color-override.ts
1573
+ var HEX = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
1574
+ var FUNCTIONAL = /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix)\([^()]*(?:\([^()]*\)[^()]*)*\)$/;
1575
+ var KEYWORDS = /* @__PURE__ */ new Set([
1576
+ "transparent",
1577
+ "currentColor",
1578
+ "currentcolor",
1579
+ "inherit",
1580
+ "initial",
1581
+ "unset",
1582
+ "red",
1583
+ "green",
1584
+ "blue",
1585
+ "black",
1586
+ "white",
1587
+ "gray",
1588
+ "grey",
1589
+ "orange",
1590
+ "yellow",
1591
+ "purple",
1592
+ "pink",
1593
+ "brown",
1594
+ "cyan",
1595
+ "magenta"
1596
+ ]);
1597
+ var isValid = (value) => {
1598
+ const v = value.trim();
1599
+ if (!v) return false;
1600
+ if (typeof CSS !== "undefined" && typeof CSS.supports === "function") {
1601
+ return CSS.supports("color", v);
1602
+ }
1603
+ return HEX.test(v) || FUNCTIONAL.test(v) || KEYWORDS.has(v);
1604
+ };
1605
+ var warnIfInvalidColor = (value, component) => {
1606
+ if (isValid(value)) return true;
1607
+ if (process.env.NODE_ENV !== "production") {
1608
+ console.warn(
1609
+ `[${component}] Invalid color value "${value}". Falling back to the default variant. Use a hex, rgb/rgba, hsl, oklch, lab/lch, color(), color-mix(), or a CSS color keyword.`
1610
+ );
1611
+ }
1612
+ return false;
1613
+ };
1614
+ var tintStyle = (color) => ({
1615
+ background: `color-mix(in oklab, ${color}, transparent 85%)`,
1616
+ color
1617
+ });
1618
+
1566
1619
  // src/components/StatusDot/StatusDot.tsx
1567
1620
  import { forwardRef as forwardRef19 } from "react";
1568
1621
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -1590,13 +1643,14 @@ var stateLabel = {
1590
1643
  sync: "Syncing",
1591
1644
  accent: "Active"
1592
1645
  };
1593
- var StatusDot = forwardRef19(function StatusDot2({ state = "ok", label, pulse, size = 8, className, ...props }, ref) {
1646
+ var StatusDot = forwardRef19(function StatusDot2({ state = "ok", color, label, pulse, size = 8, className, ...props }, ref) {
1647
+ const useColor = color && warnIfInvalidColor(color, "StatusDot");
1594
1648
  return /* @__PURE__ */ jsxs16(
1595
1649
  "span",
1596
1650
  {
1597
1651
  ref,
1598
1652
  role: label ? "status" : "img",
1599
- "aria-label": !label ? stateLabel[state] : void 0,
1653
+ "aria-label": !label ? useColor ? "Status" : stateLabel[state] : void 0,
1600
1654
  className: cn("inline-flex items-center gap-[6px]", className),
1601
1655
  ...props,
1602
1656
  children: [
@@ -1605,11 +1659,15 @@ var StatusDot = forwardRef19(function StatusDot2({ state = "ok", label, pulse, s
1605
1659
  {
1606
1660
  className: cn(
1607
1661
  "inline-block rounded-full",
1608
- stateColor[state],
1609
- pulse && "animate-[ship-pulse-ring_1.6s_infinite]",
1610
- stateText[state]
1662
+ !useColor && stateColor[state],
1663
+ !useColor && stateText[state],
1664
+ pulse && "animate-[ship-pulse-ring_1.6s_infinite]"
1611
1665
  ),
1612
- style: { width: size, height: size }
1666
+ style: {
1667
+ width: size,
1668
+ height: size,
1669
+ ...useColor ? { backgroundColor: color, color } : {}
1670
+ }
1613
1671
  }
1614
1672
  ),
1615
1673
  label && /* @__PURE__ */ jsx20("span", { className: "text-text-muted text-[12px]", children: label })
@@ -1644,10 +1702,12 @@ function hashHue(str) {
1644
1702
  for (let i = 0; i < str.length; i++) h = (h * 31 + str.charCodeAt(i)) % 360;
1645
1703
  return h;
1646
1704
  }
1647
- var Avatar = forwardRef20(function Avatar2({ name = "?", src, size = "md", status, initials, className, style, ...props }, ref) {
1705
+ var Avatar = forwardRef20(function Avatar2({ name = "?", src, size = "md", status, initials, color, className, style, ...props }, ref) {
1648
1706
  const dim = sizePx[size];
1649
1707
  const hue = hashHue(name);
1650
1708
  const computedInitials = initials ?? initialsFor(name);
1709
+ const useColor = color && warnIfInvalidColor(color, "Avatar");
1710
+ const fallbackBg = useColor ? color : `oklch(var(--color-avatar-fallback-l) var(--color-avatar-fallback-c) ${hue})`;
1651
1711
  return /* @__PURE__ */ jsxs17(
1652
1712
  "span",
1653
1713
  {
@@ -1661,7 +1721,7 @@ var Avatar = forwardRef20(function Avatar2({ name = "?", src, size = "md", statu
1661
1721
  {
1662
1722
  className: "border-border relative inline-flex h-full w-full shrink-0 overflow-hidden rounded-full border",
1663
1723
  style: {
1664
- background: src ? void 0 : `oklch(var(--color-avatar-fallback-l) var(--color-avatar-fallback-c) ${hue})`
1724
+ background: src ? void 0 : fallbackBg
1665
1725
  },
1666
1726
  children: [
1667
1727
  src && /* @__PURE__ */ jsx21(RadixAvatar.Image, { src, alt: name, className: "h-full w-full object-cover" }),
@@ -1729,6 +1789,16 @@ AvatarGroup.displayName = "AvatarGroup";
1729
1789
  import { cva as cva6 } from "class-variance-authority";
1730
1790
  import { forwardRef as forwardRef22 } from "react";
1731
1791
  import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
1792
+ var badgeStructural = cva6("inline-flex items-center font-sans leading-none whitespace-nowrap", {
1793
+ variants: {
1794
+ size: {
1795
+ sm: "h-[18px] px-[6px] py-[1px] text-[10px] gap-1 rounded-full",
1796
+ md: "h-[22px] px-2 py-[2px] text-[11px] gap-[5px] rounded-full",
1797
+ lg: "h-[26px] px-[10px] py-[3px] text-[12px] gap-[6px] rounded-full"
1798
+ }
1799
+ },
1800
+ defaultVariants: { size: "md" }
1801
+ });
1732
1802
  var badgeStyles = cva6("inline-flex items-center font-sans leading-none whitespace-nowrap", {
1733
1803
  variants: {
1734
1804
  variant: {
@@ -1762,20 +1832,53 @@ var dotColorClass = {
1762
1832
  solid: "bg-bg"
1763
1833
  };
1764
1834
  var dotSize = { sm: "h-[5px] w-[5px]", md: "h-[6px] w-[6px]", lg: "h-[7px] w-[7px]" };
1765
- var Badge = forwardRef22(function Badge2({ variant = "neutral", size = "md", dot, icon, className, children, ...props }, ref) {
1835
+ var Badge = forwardRef22(function Badge2({ variant = "neutral", size = "md", dot, icon, className, children, color, style, ...props }, ref) {
1766
1836
  const sz = size ?? "md";
1767
- const v = variant ?? "neutral";
1768
- return /* @__PURE__ */ jsxs19("span", { ref, className: cn(badgeStyles({ variant, size }), className), ...props, children: [
1769
- dot && /* @__PURE__ */ jsx23(
1837
+ const useColor = color && warnIfInvalidColor(color, "Badge");
1838
+ if (useColor) {
1839
+ return /* @__PURE__ */ jsxs19(
1770
1840
  "span",
1771
1841
  {
1772
- "aria-hidden": true,
1773
- className: cn("inline-block rounded-full", dotSize[sz], dotColorClass[v])
1842
+ ref,
1843
+ className: cn(badgeStructural({ size }), className),
1844
+ style: { ...tintStyle(color), ...style },
1845
+ ...props,
1846
+ children: [
1847
+ dot && /* @__PURE__ */ jsx23(
1848
+ "span",
1849
+ {
1850
+ "aria-hidden": true,
1851
+ className: cn("inline-block rounded-full", dotSize[sz]),
1852
+ style: { background: color }
1853
+ }
1854
+ ),
1855
+ icon && /* @__PURE__ */ jsx23("span", { className: "inline-flex leading-none", children: icon }),
1856
+ children
1857
+ ]
1774
1858
  }
1775
- ),
1776
- icon && /* @__PURE__ */ jsx23("span", { className: "inline-flex leading-none", children: icon }),
1777
- children
1778
- ] });
1859
+ );
1860
+ }
1861
+ const v = variant ?? "neutral";
1862
+ return /* @__PURE__ */ jsxs19(
1863
+ "span",
1864
+ {
1865
+ ref,
1866
+ className: cn(badgeStyles({ variant, size }), className),
1867
+ style,
1868
+ ...props,
1869
+ children: [
1870
+ dot && /* @__PURE__ */ jsx23(
1871
+ "span",
1872
+ {
1873
+ "aria-hidden": true,
1874
+ className: cn("inline-block rounded-full", dotSize[sz], dotColorClass[v])
1875
+ }
1876
+ ),
1877
+ icon && /* @__PURE__ */ jsx23("span", { className: "inline-flex leading-none", children: icon }),
1878
+ children
1879
+ ]
1880
+ }
1881
+ );
1779
1882
  });
1780
1883
  Badge.displayName = "Badge";
1781
1884
 
@@ -1923,18 +2026,23 @@ StatCard.displayName = "StatCard";
1923
2026
  // src/components/Chip/Chip.tsx
1924
2027
  import { forwardRef as forwardRef25 } from "react";
1925
2028
  import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
1926
- var Chip = forwardRef25(function Chip2({ icon, onRemove, density = "comfortable", className, children, ...props }, ref) {
2029
+ var Chip = forwardRef25(function Chip2({ icon, onRemove, density = "comfortable", color, className, children, style, ...props }, ref) {
1927
2030
  const isTouch = density === "touch";
2031
+ const useColor = color && warnIfInvalidColor(color, "Chip");
2032
+ const structural = cn(
2033
+ "inline-flex items-center gap-[6px] font-sans rounded-full border",
2034
+ isTouch ? "text-m-mono h-8 py-[5px] pr-[6px] pl-3" : "h-[26px] py-[4px] pr-1 pl-[10px] text-[12px]"
2035
+ );
2036
+ const defaultPaint = "bg-panel-2 text-text border-border";
1928
2037
  return /* @__PURE__ */ jsxs22(
1929
2038
  "span",
1930
2039
  {
1931
2040
  ref,
1932
- className: cn(
1933
- "inline-flex items-center gap-[6px] font-sans",
1934
- isTouch ? "text-m-mono h-8 py-[5px] pr-[6px] pl-3" : "h-[26px] py-[4px] pr-1 pl-[10px] text-[12px]",
1935
- "bg-panel-2 text-text border-border rounded-full border",
1936
- className
1937
- ),
2041
+ className: cn(structural, !useColor && defaultPaint, className),
2042
+ style: {
2043
+ ...useColor ? { ...tintStyle(color), borderColor: "transparent" } : {},
2044
+ ...style
2045
+ },
1938
2046
  ...props,
1939
2047
  children: [
1940
2048
  icon && /* @__PURE__ */ jsx26("span", { className: cn("text-text-dim inline-flex", isTouch ? "text-[12px]" : "text-[10px]"), children: icon }),
@@ -1985,7 +2093,7 @@ import {
1985
2093
  forwardRef as forwardRef27,
1986
2094
  useEffect as useEffect7,
1987
2095
  useId as useId7,
1988
- useRef as useRef6
2096
+ useRef as useRef7
1989
2097
  } from "react";
1990
2098
  import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
1991
2099
  var sizeMap = {
@@ -2003,8 +2111,10 @@ var Rating = forwardRef27(function Rating2({
2003
2111
  readOnly = false,
2004
2112
  className,
2005
2113
  "aria-label": ariaLabel,
2114
+ color,
2006
2115
  ...props
2007
2116
  }, ref) {
2117
+ const useColor = color && warnIfInvalidColor(color, "Rating");
2008
2118
  const [current, setCurrent] = useControllableState({
2009
2119
  value,
2010
2120
  defaultValue: defaultValue ?? 0,
@@ -2013,8 +2123,8 @@ var Rating = forwardRef27(function Rating2({
2013
2123
  const reactId = useId7();
2014
2124
  const px = sizeMap[size];
2015
2125
  const currentInt = Math.round(current ?? 0);
2016
- const buttonsRef = useRef6([]);
2017
- const shouldFocusRef = useRef6(false);
2126
+ const buttonsRef = useRef7([]);
2127
+ const shouldFocusRef = useRef7(false);
2018
2128
  useEffect7(() => {
2019
2129
  if (!shouldFocusRef.current) return;
2020
2130
  shouldFocusRef.current = false;
@@ -2058,10 +2168,19 @@ var Rating = forwardRef27(function Rating2({
2058
2168
  /* @__PURE__ */ jsx28(
2059
2169
  "div",
2060
2170
  {
2171
+ "data-filled-stars": true,
2061
2172
  className: "pointer-events-none absolute inset-0 inline-flex items-center gap-0.5 overflow-hidden",
2062
- style: { width: `${fillPct}%` },
2173
+ style: { width: `${fillPct}%`, ...useColor ? { color } : {} },
2063
2174
  "aria-hidden": true,
2064
- children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx28(IconGlyph3, { name: "star", size: px, className: "text-rating shrink-0" }, i))
2175
+ children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx28(
2176
+ IconGlyph3,
2177
+ {
2178
+ name: "star",
2179
+ size: px,
2180
+ className: cn("shrink-0", !useColor && "text-rating")
2181
+ },
2182
+ i
2183
+ ))
2065
2184
  }
2066
2185
  )
2067
2186
  ]
@@ -2076,6 +2195,7 @@ var Rating = forwardRef27(function Rating2({
2076
2195
  "aria-label": ariaLabel ?? "Rating",
2077
2196
  tabIndex: -1,
2078
2197
  className: cn("inline-flex items-center gap-0.5", className),
2198
+ style: useColor ? { color } : void 0,
2079
2199
  onKeyDown: handleKey,
2080
2200
  ...props,
2081
2201
  children: Array.from({ length: max }).map((_, i) => {
@@ -2099,8 +2219,8 @@ var Rating = forwardRef27(function Rating2({
2099
2219
  "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-sm",
2100
2220
  "focus-visible:ring-accent-dim outline-none focus-visible:ring-[3px]",
2101
2221
  "transition-colors duration-(--duration-micro)",
2102
- filled ? "text-rating" : "text-rating-dim",
2103
- "hover:text-rating"
2222
+ useColor ? filled ? "" : "opacity-30" : filled ? "text-rating" : "text-rating-dim",
2223
+ !useColor && "hover:text-rating"
2104
2224
  ),
2105
2225
  children: /* @__PURE__ */ jsx28(IconGlyph3, { name: "star", size: px })
2106
2226
  },
@@ -2226,17 +2346,20 @@ SkeletonGroup.displayName = "SkeletonGroup";
2226
2346
  // src/components/Tag/Tag.tsx
2227
2347
  import { forwardRef as forwardRef30 } from "react";
2228
2348
  import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
2229
- var Tag = forwardRef30(function Tag2({ onRemove, icon, size = 22, className, children, ...props }, ref) {
2349
+ var Tag = forwardRef30(function Tag2({ onRemove, icon, size = 22, color, className, children, style, ...props }, ref) {
2350
+ const useColor = color && warnIfInvalidColor(color, "Tag");
2351
+ const structural = "inline-flex items-center gap-[6px] px-2 py-[3px] font-sans text-[11px] rounded-xs border";
2352
+ const defaultPaint = "bg-panel-2 text-text border-border";
2230
2353
  return /* @__PURE__ */ jsxs25(
2231
2354
  "span",
2232
2355
  {
2233
2356
  ref,
2234
- className: cn(
2235
- "inline-flex items-center gap-[6px] px-2 py-[3px] font-sans text-[11px]",
2236
- "bg-panel-2 text-text border-border rounded-xs border",
2237
- className
2238
- ),
2239
- style: { height: size },
2357
+ className: cn(structural, !useColor && defaultPaint, className),
2358
+ style: {
2359
+ height: size,
2360
+ ...useColor ? { ...tintStyle(color), borderColor: "transparent" } : {},
2361
+ ...style
2362
+ },
2240
2363
  ...props,
2241
2364
  children: [
2242
2365
  icon && /* @__PURE__ */ jsx31("span", { className: "text-text-dim inline-flex", children: icon }),
@@ -2365,18 +2488,25 @@ var DialogContent = forwardRef32(function DialogContent2({ className, width = 46
2365
2488
  });
2366
2489
  DialogContent.displayName = "DialogContent";
2367
2490
  function Dialog({ title, description, footer, width, children, ...rootProps }) {
2368
- return /* @__PURE__ */ jsx33(DialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxs27(DialogContent, { width, children: [
2369
- title && /* @__PURE__ */ jsx33(
2370
- RadixDialog.Title,
2371
- {
2372
- className: cn("text-[16px] font-medium", description ? "mb-[6px]" : "mb-4"),
2373
- children: title
2374
- }
2375
- ),
2376
- description && /* @__PURE__ */ jsx33(RadixDialog.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }),
2377
- children,
2378
- footer && /* @__PURE__ */ jsx33("div", { className: "mt-5 flex justify-end gap-2", children: footer })
2379
- ] }) });
2491
+ return /* @__PURE__ */ jsx33(DialogRoot, { ...rootProps, children: /* @__PURE__ */ jsxs27(
2492
+ DialogContent,
2493
+ {
2494
+ width,
2495
+ ...description ? {} : { "aria-describedby": void 0 },
2496
+ children: [
2497
+ title && /* @__PURE__ */ jsx33(
2498
+ RadixDialog.Title,
2499
+ {
2500
+ className: cn("text-[16px] font-medium", description ? "mb-[6px]" : "mb-4"),
2501
+ children: title
2502
+ }
2503
+ ),
2504
+ description && /* @__PURE__ */ jsx33(RadixDialog.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }),
2505
+ children,
2506
+ footer && /* @__PURE__ */ jsx33("div", { className: "mt-5 flex justify-end gap-2", children: footer })
2507
+ ]
2508
+ }
2509
+ ) });
2380
2510
  }
2381
2511
 
2382
2512
  // src/components/Dialog/Drawer.tsx
@@ -2494,7 +2624,13 @@ var AlertDialog = forwardRef35(function AlertDialog2({ title, description, foote
2494
2624
  children: title
2495
2625
  }
2496
2626
  ),
2497
- description && /* @__PURE__ */ jsx36(RadixAlert.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }),
2627
+ description ? /* @__PURE__ */ jsx36(RadixAlert.Description, { className: "text-text-muted mb-[18px] text-[13px] leading-[1.55]", children: description }) : (
2628
+ // Radix AlertDialog requires a description for screen-reader users
2629
+ // and warns in dev mode when one is missing. When the caller opts
2630
+ // out of a visible description, fall back to the title text in a
2631
+ // visually-hidden Description so the a11y contract is still met.
2632
+ /* @__PURE__ */ jsx36(RadixAlert.Description, { className: "sr-only", children: title })
2633
+ ),
2498
2634
  children,
2499
2635
  footer && /* @__PURE__ */ jsx36("div", { className: "mt-5 flex justify-end gap-2", children: footer })
2500
2636
  ]
@@ -2944,7 +3080,7 @@ import {
2944
3080
  forwardRef as forwardRef44,
2945
3081
  useCallback as useCallback9,
2946
3082
  useEffect as useEffect8,
2947
- useRef as useRef7
3083
+ useRef as useRef8
2948
3084
  } from "react";
2949
3085
  import { Fragment, jsx as jsx45, jsxs as jsxs38 } from "react/jsx-runtime";
2950
3086
  var Carousel = forwardRef44(function Carousel2({
@@ -2966,7 +3102,7 @@ var Carousel = forwardRef44(function Carousel2({
2966
3102
  defaultValue: defaultIndex ?? 0,
2967
3103
  onChange: onIndexChange
2968
3104
  });
2969
- const viewportRef = useRef7(null);
3105
+ const viewportRef = useRef8(null);
2970
3106
  const goTo = useCallback9(
2971
3107
  (i) => {
2972
3108
  const clamped = Math.max(0, Math.min(items.length - 1, i));
@@ -3104,7 +3240,7 @@ import {
3104
3240
  useEffect as useEffect9,
3105
3241
  useId as useId8,
3106
3242
  useMemo as useMemo2,
3107
- useRef as useRef8,
3243
+ useRef as useRef9,
3108
3244
  useState as useState9
3109
3245
  } from "react";
3110
3246
  import { jsx as jsx46, jsxs as jsxs39 } from "react/jsx-runtime";
@@ -3163,7 +3299,7 @@ var Combobox = forwardRef45(function Combobox2({
3163
3299
  onChange: onQueryChange
3164
3300
  });
3165
3301
  const [open, setOpen] = useState9(false);
3166
- const wrapperRef = useRef8(null);
3302
+ const wrapperRef = useRef9(null);
3167
3303
  useOutsideClick(wrapperRef, () => setOpen(false));
3168
3304
  const filtered = useMemo2(
3169
3305
  () => query ? normalized.filter((o) => filter(o, query)) : normalized,
@@ -3443,7 +3579,7 @@ function filterCommandItems(query, groups) {
3443
3579
  }
3444
3580
 
3445
3581
  // src/patterns/DataTable/DataTable.tsx
3446
- import { useEffect as useEffect11, useMemo as useMemo4, useRef as useRef9 } from "react";
3582
+ import { useEffect as useEffect11, useMemo as useMemo4, useRef as useRef10 } from "react";
3447
3583
  import { jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
3448
3584
  var alignClass = {
3449
3585
  left: "text-left",
@@ -3500,7 +3636,7 @@ function DataTable(props) {
3500
3636
  const selectedSet = selected ?? EMPTY_SET;
3501
3637
  const allSelected = allIds.length > 0 && allIds.every((id) => selectedSet.has(id));
3502
3638
  const someSelected = !allSelected && allIds.some((id) => selectedSet.has(id));
3503
- const headerCheckRef = useRef9(null);
3639
+ const headerCheckRef = useRef10(null);
3504
3640
  useEffect11(() => {
3505
3641
  if (headerCheckRef.current) headerCheckRef.current.indeterminate = someSelected;
3506
3642
  }, [someSelected]);
@@ -3532,7 +3668,7 @@ function DataTable(props) {
3532
3668
  return next;
3533
3669
  });
3534
3670
  };
3535
- return /* @__PURE__ */ jsxs41("table", { ref, className: cn("w-full border-collapse text-[12px]", className), children: [
3671
+ return /* @__PURE__ */ jsxs41("table", { ref, className: cn("relative w-full border-collapse text-[12px]", className), children: [
3536
3672
  caption && /* @__PURE__ */ jsx48("caption", { className: "sr-only", children: caption }),
3537
3673
  /* @__PURE__ */ jsx48("thead", { className: cn("bg-panel-2", stickyHeader && "z-raised sticky top-0"), children: /* @__PURE__ */ jsxs41("tr", { children: [
3538
3674
  selectable && /* @__PURE__ */ jsx48("th", { scope: "col", className: "border-border w-8 border-b px-3 py-2 text-left", children: /* @__PURE__ */ jsx48(
@@ -3627,7 +3763,7 @@ import {
3627
3763
  forwardRef as forwardRef47,
3628
3764
  useCallback as useCallback10,
3629
3765
  useEffect as useEffect12,
3630
- useRef as useRef10,
3766
+ useRef as useRef11,
3631
3767
  useState as useState10
3632
3768
  } from "react";
3633
3769
  import { jsx as jsx49, jsxs as jsxs42 } from "react/jsx-runtime";
@@ -3721,8 +3857,8 @@ var Calendar = forwardRef47(function Calendar2({
3721
3857
  }, [selectedDate]);
3722
3858
  const focusedInVisibleMonth = focusedDate.getMonth() === month && focusedDate.getFullYear() === year;
3723
3859
  const effectiveFocusDay = focusedInVisibleMonth ? focusedDate.getDate() : clampDay(year, month, focusedDate.getDate());
3724
- const dayRefs = useRef10(/* @__PURE__ */ new Map());
3725
- const shouldFocusRef = useRef10(false);
3860
+ const dayRefs = useRef11(/* @__PURE__ */ new Map());
3861
+ const shouldFocusRef = useRef11(false);
3726
3862
  useEffect12(() => {
3727
3863
  if (!shouldFocusRef.current) return;
3728
3864
  shouldFocusRef.current = false;
@@ -4320,7 +4456,7 @@ var ListingCard = forwardRef51(function ListingCard2({
4320
4456
  ListingCard.displayName = "ListingCard";
4321
4457
 
4322
4458
  // src/patterns/PhoneInput/PhoneInput.tsx
4323
- import { forwardRef as forwardRef52, useEffect as useEffect14, useMemo as useMemo5, useRef as useRef11, useState as useState13 } from "react";
4459
+ import { forwardRef as forwardRef52, useEffect as useEffect14, useMemo as useMemo5, useRef as useRef12, useState as useState13 } from "react";
4324
4460
 
4325
4461
  // src/patterns/PhoneInput/countries.ts
4326
4462
  var phoneCountries = [
@@ -4398,7 +4534,7 @@ var PhoneInput = forwardRef52(function PhoneInput2({
4398
4534
  parsed?.country ?? countries.find((c) => c.code === defaultCountry) ?? countries[0]
4399
4535
  );
4400
4536
  const [national, setNational] = useState13(parsed?.national ?? "");
4401
- const lastEmittedRef = useRef11(committed ?? "");
4537
+ const lastEmittedRef = useRef12(committed ?? "");
4402
4538
  useEffect14(() => {
4403
4539
  const current = committed ?? "";
4404
4540
  if (current === lastEmittedRef.current) return;
@@ -5228,7 +5364,7 @@ import {
5228
5364
  forwardRef as forwardRef65,
5229
5365
  useCallback as useCallback14,
5230
5366
  useEffect as useEffect15,
5231
- useRef as useRef12,
5367
+ useRef as useRef13,
5232
5368
  useState as useState17
5233
5369
  } from "react";
5234
5370
 
@@ -5662,7 +5798,7 @@ function VerticalItem({ item, activeId, onActivate }) {
5662
5798
  const hasChildren = (item.children?.length ?? 0) > 0;
5663
5799
  const treeActive = isActiveTree(item, activeId);
5664
5800
  const [open, setOpen] = useState17(treeActive);
5665
- const prevTreeActive = useRef12(treeActive);
5801
+ const prevTreeActive = useRef13(treeActive);
5666
5802
  useEffect15(() => {
5667
5803
  if (treeActive && !prevTreeActive.current) setOpen(true);
5668
5804
  prevTreeActive.current = treeActive;
@@ -6582,9 +6718,10 @@ import {
6582
6718
  useCallback as useCallback16,
6583
6719
  useEffect as useEffect16,
6584
6720
  useMemo as useMemo7,
6585
- useRef as useRef13,
6721
+ useRef as useRef14,
6586
6722
  useState as useState19
6587
6723
  } from "react";
6724
+ import { flushSync } from "react-dom";
6588
6725
  import { jsx as jsx80, jsxs as jsxs70 } from "react/jsx-runtime";
6589
6726
  var EMPTY_SET2 = /* @__PURE__ */ new Set();
6590
6727
  function flattenVisible(items, expanded, level, parentId, out) {
@@ -6635,7 +6772,7 @@ var Tree = forwardRef78(function Tree2({
6635
6772
  if (value && flatVisible.some((f) => f.id === value)) return value;
6636
6773
  return flatVisible[0]?.id ?? null;
6637
6774
  }, [activeId, flatVisible, value]);
6638
- const listRef = useRef13(null);
6775
+ const listRef = useRef14(null);
6639
6776
  const setRefs = useCallback16(
6640
6777
  (node) => {
6641
6778
  listRef.current = node;
@@ -6652,8 +6789,8 @@ var Tree = forwardRef78(function Tree2({
6652
6789
  }, []);
6653
6790
  const moveActive = useCallback16(
6654
6791
  (id) => {
6655
- setActiveId(id);
6656
- queueMicrotask(() => focusItem(id));
6792
+ flushSync(() => setActiveId(id));
6793
+ focusItem(id);
6657
6794
  },
6658
6795
  [focusItem]
6659
6796
  );
@@ -6924,17 +7061,30 @@ var WizardDialog = forwardRef79(function WizardDialog2({
6924
7061
  goNext();
6925
7062
  }
6926
7063
  };
6927
- return /* @__PURE__ */ jsx81(DialogRoot, { open, defaultOpen, onOpenChange, children: /* @__PURE__ */ jsxs71(DialogContent, { ref, width, children: [
6928
- title && /* @__PURE__ */ jsx81(WizardTitle, { children: title }),
6929
- description && /* @__PURE__ */ jsx81(WizardDescription, { children: description }),
6930
- /* @__PURE__ */ jsx81("div", { className: "mb-5", children: /* @__PURE__ */ jsx81(Stepper, { steps: stepperSteps, current: safeCurrent }) }),
6931
- /* @__PURE__ */ jsx81("div", { className: "mb-5", children: body }),
6932
- /* @__PURE__ */ jsxs71("div", { className: "flex justify-end gap-2", children: [
6933
- cancelLabel && /* @__PURE__ */ jsx81(Button, { type: "button", variant: "ghost", onClick: onCancel, children: cancelLabel }),
6934
- /* @__PURE__ */ jsx81(Button, { type: "button", variant: "secondary", onClick: goBack, disabled: ctx.isFirst, children: backLabel }),
6935
- /* @__PURE__ */ jsx81(Button, { type: "button", variant: "primary", onClick: handlePrimary, disabled: !canAdvance, children: ctx.isLast ? completeLabel : nextLabel })
6936
- ] })
6937
- ] }) });
7064
+ return /* @__PURE__ */ jsx81(DialogRoot, { open, defaultOpen, onOpenChange, children: /* @__PURE__ */ jsxs71(
7065
+ DialogContent,
7066
+ {
7067
+ ref,
7068
+ width,
7069
+ ...description ? {} : { "aria-describedby": void 0 },
7070
+ children: [
7071
+ title ? /* @__PURE__ */ jsx81(WizardTitle, { children: title }) : (
7072
+ // Radix Dialog requires a Title for assistive tech and warns in dev
7073
+ // mode without one. Fall back to a visually-hidden generic title so
7074
+ // the contract is met even when no title prop is supplied.
7075
+ /* @__PURE__ */ jsx81(RadixDialog6.Title, { className: "sr-only", children: "Wizard" })
7076
+ ),
7077
+ description && /* @__PURE__ */ jsx81(WizardDescription, { children: description }),
7078
+ /* @__PURE__ */ jsx81("div", { className: "mb-5", children: /* @__PURE__ */ jsx81(Stepper, { steps: stepperSteps, current: safeCurrent }) }),
7079
+ /* @__PURE__ */ jsx81("div", { className: "mb-5", children: body }),
7080
+ /* @__PURE__ */ jsxs71("div", { className: "flex justify-end gap-2", children: [
7081
+ cancelLabel && /* @__PURE__ */ jsx81(Button, { type: "button", variant: "ghost", onClick: onCancel, children: cancelLabel }),
7082
+ /* @__PURE__ */ jsx81(Button, { type: "button", variant: "secondary", onClick: goBack, disabled: ctx.isFirst, children: backLabel }),
7083
+ /* @__PURE__ */ jsx81(Button, { type: "button", variant: "primary", onClick: handlePrimary, disabled: !canAdvance, children: ctx.isLast ? completeLabel : nextLabel })
7084
+ ] })
7085
+ ]
7086
+ }
7087
+ ) });
6938
7088
  });
6939
7089
  function WizardTitle({ children }) {
6940
7090
  return /* @__PURE__ */ jsx81(RadixDialog6.Title, { className: "mb-2 text-[16px] font-medium", children });