@geomak/ui 5.5.0 → 5.5.2

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.cjs CHANGED
@@ -10,12 +10,12 @@ var framerMotion = require('framer-motion');
10
10
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
11
11
  var TabsPrimitive = require('@radix-ui/react-tabs');
12
12
  var Accordion = require('@radix-ui/react-accordion');
13
- var ToggleGroup = require('@radix-ui/react-toggle-group');
14
13
  var ContextMenuPrimitive = require('@radix-ui/react-context-menu');
15
14
  var Popover = require('@radix-ui/react-popover');
16
15
  var SwitchPrimitive = require('@radix-ui/react-switch');
17
16
  var CheckboxPrimitive = require('@radix-ui/react-checkbox');
18
17
  var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
18
+ var ToggleGroup = require('@radix-ui/react-toggle-group');
19
19
  var SliderPrimitive = require('@radix-ui/react-slider');
20
20
 
21
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -44,12 +44,12 @@ var Dialog__namespace = /*#__PURE__*/_interopNamespace(Dialog);
44
44
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
45
45
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
46
46
  var Accordion__namespace = /*#__PURE__*/_interopNamespace(Accordion);
47
- var ToggleGroup__namespace = /*#__PURE__*/_interopNamespace(ToggleGroup);
48
47
  var ContextMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(ContextMenuPrimitive);
49
48
  var Popover__namespace = /*#__PURE__*/_interopNamespace(Popover);
50
49
  var SwitchPrimitive__namespace = /*#__PURE__*/_interopNamespace(SwitchPrimitive);
51
50
  var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
52
51
  var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
52
+ var ToggleGroup__namespace = /*#__PURE__*/_interopNamespace(ToggleGroup);
53
53
  var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
54
54
 
55
55
  var Moon = ({ color = "gray" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: color, viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: color, className: "w-8 h-8", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" }) });
@@ -1178,38 +1178,6 @@ function Tree({
1178
1178
  item.key
1179
1179
  )) });
1180
1180
  }
1181
- function ToggleButton({ items, onChange, activeKey }) {
1182
- return /* @__PURE__ */ jsxRuntime.jsx(
1183
- ToggleGroup__namespace.Root,
1184
- {
1185
- type: "single",
1186
- value: activeKey,
1187
- onValueChange: (val) => {
1188
- if (val) onChange(val);
1189
- },
1190
- className: "flex items-center",
1191
- children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1192
- ToggleGroup__namespace.Item,
1193
- {
1194
- value: item.key,
1195
- "aria-label": typeof item.label === "string" ? item.label : item.key,
1196
- className: [
1197
- // Semantic tokens handle both light and dark modes via
1198
- // CSS vars — no `dark:` variants needed.
1199
- index === 0 && "rounded-l-lg border-r border-border",
1200
- index === items.length - 1 && "rounded-r-lg border-l border-border",
1201
- "p-2 cursor-pointer transition-colors duration-150 text-foreground-secondary",
1202
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
1203
- "bg-surface hover:bg-surface-raised",
1204
- "data-[state=on]:bg-accent data-[state=on]:text-accent-fg"
1205
- ].filter(Boolean).join(" "),
1206
- children: item.icon ?? item.label
1207
- },
1208
- item.key
1209
- ))
1210
- }
1211
- );
1212
- }
1213
1181
  var NotificationContext = React8.createContext({
1214
1182
  open: () => void 0,
1215
1183
  close: () => void 0
@@ -1611,6 +1579,10 @@ var TOGGLE_POSITION_CLASS = {
1611
1579
  function ScalableContainer({
1612
1580
  width = "100%",
1613
1581
  height = "auto",
1582
+ expandedWidth = "100%",
1583
+ expandedHeight = "100%",
1584
+ expanded,
1585
+ onExpandedChange,
1614
1586
  children,
1615
1587
  assignClassOnClick,
1616
1588
  expandIcon,
@@ -1618,27 +1590,32 @@ function ScalableContainer({
1618
1590
  togglePosition = "top-right"
1619
1591
  }) {
1620
1592
  const containerRef = React8.useRef(null);
1621
- const [isScaled, setScaled] = React8.useState(false);
1593
+ const [internalScaled, setInternalScaled] = React8.useState(false);
1594
+ const isScaled = expanded ?? internalScaled;
1622
1595
  const reduced = framerMotion.useReducedMotion();
1623
1596
  const onToggle = () => {
1624
1597
  const next = !isScaled;
1625
- setScaled(next);
1626
- requestAnimationFrame(() => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }));
1598
+ if (expanded === void 0) setInternalScaled(next);
1599
+ onExpandedChange?.(next);
1600
+ if (next) {
1601
+ window.setTimeout(
1602
+ () => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }),
1603
+ reduced ? 0 : 340
1604
+ );
1605
+ }
1627
1606
  };
1628
1607
  const wrapperClass = isScaled ? assignClassOnClick : void 0;
1629
1608
  return /* @__PURE__ */ jsxRuntime.jsxs(
1630
1609
  framerMotion.motion.div,
1631
1610
  {
1632
1611
  ref: containerRef,
1633
- layout: true,
1634
1612
  animate: {
1635
- width: isScaled ? "100%" : width,
1636
- height: isScaled ? "100%" : height
1613
+ width: isScaled ? expandedWidth : width,
1614
+ height: isScaled ? expandedHeight : height
1637
1615
  },
1638
1616
  transition: reduced ? { duration: 0 } : {
1639
1617
  width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1640
- height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
1641
- layout: { duration: 0.32, ease: [0.16, 1, 0.3, 1] }
1618
+ height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] }
1642
1619
  },
1643
1620
  className: [
1644
1621
  "relative rounded-lg overflow-hidden",
@@ -2174,10 +2151,10 @@ var FIELD_SIZE = {
2174
2151
  md: { control: "h-control-md", text: "text-sm", padX: "px-3", gap: "gap-2" },
2175
2152
  lg: { control: "h-control-lg", text: "text-sm", padX: "px-3.5", gap: "gap-2.5" }
2176
2153
  };
2177
- var FOCUS_WITHIN = "focus-within:outline-none focus-within:border-accent focus-within:ring-[3px] focus-within:ring-focus-ring";
2178
- var FOCUS_VISIBLE = "focus-visible:outline-none focus-visible:border-accent focus-visible:ring-[3px] focus-visible:ring-focus-ring";
2179
- var FOCUS_WITHIN_ERROR = "focus-within:border-status-error focus-within:ring-focus-ring-error";
2180
- var FOCUS_VISIBLE_ERROR = "focus-visible:border-status-error focus-visible:ring-focus-ring-error";
2154
+ var FOCUS_WITHIN = "focus-within:outline-none focus-within:border-accent";
2155
+ var FOCUS_ELEMENT = "focus:outline-none focus:border-accent data-[state=open]:border-accent";
2156
+ var FOCUS_WITHIN_ERROR = "focus-within:border-status-error";
2157
+ var FOCUS_ELEMENT_ERROR = "focus:border-status-error data-[state=open]:border-status-error";
2181
2158
  function fieldShell({
2182
2159
  size = "md",
2183
2160
  hasError = false,
@@ -2196,8 +2173,8 @@ function fieldShell({
2196
2173
  // hover (only when interactive + no error)
2197
2174
  disabled ? "bg-surface-raised text-foreground-muted cursor-not-allowed" : hasError ? "" : "hover:border-border-strong",
2198
2175
  // focus
2199
- focusWithin ? FOCUS_WITHIN : FOCUS_VISIBLE,
2200
- hasError ? focusWithin ? FOCUS_WITHIN_ERROR : FOCUS_VISIBLE_ERROR : "",
2176
+ focusWithin ? FOCUS_WITHIN : FOCUS_ELEMENT,
2177
+ hasError ? focusWithin ? FOCUS_WITHIN_ERROR : FOCUS_ELEMENT_ERROR : "",
2201
2178
  // placeholder colour for native inputs
2202
2179
  "placeholder:text-foreground-muted"
2203
2180
  ].filter(Boolean).join(" ");
@@ -2232,7 +2209,9 @@ function Field({
2232
2209
  style: { width: horizontal ? labelWidth : void 0, ...labelStyle },
2233
2210
  className: [
2234
2211
  "text-sm font-medium text-foreground select-none",
2235
- horizontal ? "mt-2 flex-shrink-0" : ""
2212
+ // In horizontal layout the label must not wrap onto
2213
+ // multiple lines (e.g. "Report date", "Select option").
2214
+ horizontal ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""
2236
2215
  ].filter(Boolean).join(" "),
2237
2216
  children: [
2238
2217
  label,
@@ -2278,14 +2257,24 @@ var SearchInput = React8__default.default.forwardRef(function SearchInput2({ val
2278
2257
  ) });
2279
2258
  });
2280
2259
  var SearchInput_default = SearchInput;
2281
- function DropdownPill({ value, hasSiblings = false }) {
2282
- return /* @__PURE__ */ jsxRuntime.jsx(
2283
- "div",
2284
- {
2285
- className: `bg-accent text-accent-fg text-sm text-ellipsis ${hasSiblings ? "w-24" : "w-max"} p-1 px-2 rounded-lg whitespace-nowrap overflow-hidden`,
2286
- children: value
2287
- }
2288
- );
2260
+ function Tag({ children, onRemove, removeLabel, disabled }) {
2261
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-border bg-surface-raised text-foreground text-xs pl-2 pr-1 py-0.5 max-w-full", children: [
2262
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
2263
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
2264
+ "button",
2265
+ {
2266
+ type: "button",
2267
+ disabled,
2268
+ onClick: (e) => {
2269
+ e.stopPropagation();
2270
+ onRemove();
2271
+ },
2272
+ "aria-label": removeLabel ?? "Remove",
2273
+ className: "inline-flex items-center justify-center w-4 h-4 flex-shrink-0 rounded text-foreground-muted hover:text-status-error hover:bg-surface transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:cursor-not-allowed",
2274
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
2275
+ }
2276
+ )
2277
+ ] });
2289
2278
  }
2290
2279
  function Dropdown({
2291
2280
  isMultiselect = false,
@@ -2302,7 +2291,6 @@ function Dropdown({
2302
2291
  items = [],
2303
2292
  labelStyle = {},
2304
2293
  placeholder,
2305
- showSelectedCount = false,
2306
2294
  size = "md"
2307
2295
  }) {
2308
2296
  const [open, setOpen] = React8.useState(false);
@@ -2330,6 +2318,17 @@ function Dropdown({
2330
2318
  setOpen(false);
2331
2319
  }
2332
2320
  };
2321
+ const removeSelected = (key) => {
2322
+ if (isMultiselect) {
2323
+ const next = selectedItems.filter((it) => it !== key);
2324
+ setSelectedItems(next);
2325
+ onChange?.({ target: { value: next, id: htmlFor, name } });
2326
+ } else {
2327
+ setSelectedItems([]);
2328
+ onChange?.({ target: { value: "", id: htmlFor, name } });
2329
+ }
2330
+ };
2331
+ const labelFor = (key) => innerItems.find((it) => it.key === key)?.label ?? String(key);
2333
2332
  const onSearchChange = (e) => {
2334
2333
  const term = e.target.value;
2335
2334
  setSearchTerm(term);
@@ -2340,16 +2339,16 @@ function Dropdown({
2340
2339
  );
2341
2340
  };
2342
2341
  const isSelected = (key) => Array.isArray(value) ? value.includes(key) : value === key;
2343
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2", children: [
2342
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2344
2343
  /* @__PURE__ */ jsxRuntime.jsxs(
2345
2344
  "div",
2346
2345
  {
2347
- className: `flex ${layout === "vertical" ? "flex-col" : "flex-row items-center gap-2"}`,
2346
+ className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
2348
2347
  children: [
2349
2348
  label && /* @__PURE__ */ jsxRuntime.jsx(
2350
2349
  "label",
2351
2350
  {
2352
- className: "text-sm font-medium ml-1 max-content select-none text-foreground",
2351
+ className: `text-sm font-medium select-none text-foreground ${layout === "horizontal" ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""}`,
2353
2352
  htmlFor,
2354
2353
  style: labelStyle,
2355
2354
  children: label
@@ -2366,7 +2365,7 @@ function Dropdown({
2366
2365
  "aria-invalid": hasError || void 0,
2367
2366
  "aria-describedby": hasError ? errorId : void 0,
2368
2367
  style,
2369
- className: `flex items-center justify-between cursor-pointer select-none ${fieldShell({ size, hasError, disabled })}`,
2368
+ className: `flex items-center justify-between gap-1 cursor-pointer select-none min-h-[36px] px-3 py-1.5 ${fieldShell({ size, hasError, disabled, sized: false })}`,
2370
2369
  tabIndex: disabled ? -1 : 0,
2371
2370
  onKeyDown: (e) => {
2372
2371
  if (disabled) return;
@@ -2379,18 +2378,25 @@ function Dropdown({
2379
2378
  /* @__PURE__ */ jsxRuntime.jsx(
2380
2379
  "div",
2381
2380
  {
2382
- className: `${!style?.width ? "min-w-[200px]" : ""} flex items-center gap-1 overflow-hidden`,
2383
- children: !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2384
- value.slice(0, 1).map((val) => /* @__PURE__ */ jsxRuntime.jsx(
2385
- DropdownPill,
2386
- {
2387
- hasSiblings: value.length > 1,
2388
- value: innerItems.find((it) => it.key === val)?.label
2389
- },
2390
- String(val)
2391
- )),
2392
- showSelectedCount && value.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(DropdownPill, { value: `+${value.length - 1} more` })
2393
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(DropdownPill, { value: innerItems.find((it) => it.key === value)?.label })
2381
+ className: `${!style?.width ? "min-w-[200px]" : ""} flex flex-wrap items-center gap-1.5`,
2382
+ children: !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? value.map((val) => /* @__PURE__ */ jsxRuntime.jsx(
2383
+ Tag,
2384
+ {
2385
+ disabled,
2386
+ removeLabel: `Remove ${labelFor(val)}`,
2387
+ onRemove: () => removeSelected(val),
2388
+ children: labelFor(val)
2389
+ },
2390
+ String(val)
2391
+ )) : /* @__PURE__ */ jsxRuntime.jsx(
2392
+ Tag,
2393
+ {
2394
+ disabled,
2395
+ removeLabel: `Remove ${labelFor(value)}`,
2396
+ onRemove: () => removeSelected(value),
2397
+ children: labelFor(value)
2398
+ }
2399
+ )
2394
2400
  }
2395
2401
  ),
2396
2402
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 ml-2 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
@@ -3584,74 +3590,54 @@ function Checkbox({
3584
3590
  name,
3585
3591
  htmlFor,
3586
3592
  errorMessage,
3587
- disabled = false
3593
+ disabled = false,
3594
+ layout = "horizontal",
3595
+ labelPosition = "right"
3588
3596
  }) {
3589
3597
  const isChecked = checked ?? value ?? false;
3598
+ const labelFirst = labelPosition === "left";
3599
+ const box = /* @__PURE__ */ jsxRuntime.jsx(
3600
+ CheckboxPrimitive__namespace.Root,
3601
+ {
3602
+ id: htmlFor,
3603
+ name,
3604
+ checked: isChecked,
3605
+ disabled,
3606
+ onCheckedChange: (c) => onChange?.({ target: { checked: !!c, id: htmlFor, name } }),
3607
+ className: [
3608
+ "relative flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center",
3609
+ "rounded-sm border transition-colors duration-150",
3610
+ "border-border-strong bg-surface",
3611
+ "data-[state=checked]:bg-accent data-[state=checked]:border-accent",
3612
+ // Focus halo matches the field tokens for a consistent look.
3613
+ "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
3614
+ "disabled:cursor-not-allowed"
3615
+ ].join(" "),
3616
+ "aria-label": typeof label === "string" ? label : void 0,
3617
+ children: /* @__PURE__ */ jsxRuntime.jsx(CheckboxPrimitive__namespace.Indicator, { className: "flex items-center justify-center data-[state=checked]:animate-check-pop", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "11", height: "9", viewBox: "0 0 11 9", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 4.5L4 7.5L10 1", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
3618
+ }
3619
+ );
3620
+ const labelEl = label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: label });
3590
3621
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
3591
- /* @__PURE__ */ jsxRuntime.jsxs(
3622
+ /* @__PURE__ */ jsxRuntime.jsx(
3592
3623
  "label",
3593
3624
  {
3594
3625
  htmlFor,
3595
3626
  className: [
3596
- "inline-flex items-center gap-2.5",
3627
+ "inline-flex",
3628
+ layout === "vertical" ? "flex-col items-start gap-1.5" : "flex-row items-center gap-2.5",
3597
3629
  disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3598
3630
  ].join(" "),
3599
- children: [
3600
- /* @__PURE__ */ jsxRuntime.jsx(
3601
- CheckboxPrimitive__namespace.Root,
3602
- {
3603
- id: htmlFor,
3604
- name,
3605
- checked: isChecked,
3606
- disabled,
3607
- onCheckedChange: (c) => onChange?.({ target: { checked: !!c, id: htmlFor, name } }),
3608
- className: [
3609
- // Box
3610
- "relative flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center",
3611
- "rounded-sm border transition-colors duration-150",
3612
- // Unchecked
3613
- "border-border-strong bg-surface",
3614
- // Checked
3615
- "data-[state=checked]:bg-accent data-[state=checked]:border-accent",
3616
- // Focus
3617
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1",
3618
- // Disabled
3619
- "disabled:cursor-not-allowed"
3620
- ].join(" "),
3621
- "aria-label": typeof label === "string" ? label : void 0,
3622
- children: /* @__PURE__ */ jsxRuntime.jsx(
3623
- CheckboxPrimitive__namespace.Indicator,
3624
- {
3625
- className: "flex items-center justify-center data-[state=checked]:animate-check-pop",
3626
- children: /* @__PURE__ */ jsxRuntime.jsx(
3627
- "svg",
3628
- {
3629
- width: "11",
3630
- height: "9",
3631
- viewBox: "0 0 11 9",
3632
- fill: "none",
3633
- "aria-hidden": "true",
3634
- children: /* @__PURE__ */ jsxRuntime.jsx(
3635
- "path",
3636
- {
3637
- d: "M1 4.5L4 7.5L10 1",
3638
- stroke: "white",
3639
- strokeWidth: "1.8",
3640
- strokeLinecap: "round",
3641
- strokeLinejoin: "round"
3642
- }
3643
- )
3644
- }
3645
- )
3646
- }
3647
- )
3648
- }
3649
- ),
3650
- label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: label })
3651
- ]
3631
+ children: labelFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3632
+ labelEl,
3633
+ box
3634
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3635
+ box,
3636
+ labelEl
3637
+ ] })
3652
3638
  }
3653
3639
  ),
3654
- errorMessage && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-status-error pl-[26px]", children: errorMessage })
3640
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-status-error mt-0.5", children: errorMessage })
3655
3641
  ] });
3656
3642
  }
3657
3643
  var DOT_SIZE = {
@@ -3757,12 +3743,12 @@ function Switch({
3757
3743
  id,
3758
3744
  checked,
3759
3745
  onCheckedChange: (c) => onChange?.({ target: { checked: c } }),
3760
- className: "relative inline-flex h-6 w-14 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2",
3746
+ className: "relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
3761
3747
  children: /* @__PURE__ */ jsxRuntime.jsx(
3762
3748
  SwitchPrimitive__namespace.Thumb,
3763
3749
  {
3764
- className: "pointer-events-none inline-flex h-8 w-8 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[-4px]",
3765
- children: checkedIcon && uncheckedIcon ? checked ? checkedIcon : uncheckedIcon : null
3750
+ className: "pointer-events-none flex h-5 w-5 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[2px]",
3751
+ children: checkedIcon && uncheckedIcon ? checked ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: checkedIcon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: uncheckedIcon }) : null
3766
3752
  }
3767
3753
  )
3768
3754
  }
@@ -3783,8 +3769,13 @@ function AutoComplete({
3783
3769
  emptyText = "No results found",
3784
3770
  loadingText = "Searching\u2026",
3785
3771
  size = "md",
3786
- icon
3772
+ icon,
3773
+ errorMessage,
3774
+ required,
3775
+ htmlFor
3787
3776
  }) {
3777
+ const errorId = React8.useId();
3778
+ const hasError = errorMessage != null;
3788
3779
  const [term, setTerm] = React8.useState("");
3789
3780
  const [open, setOpen] = React8.useState(false);
3790
3781
  const [asyncItems, setAsyncItems] = React8.useState([]);
@@ -3831,78 +3822,82 @@ function AutoComplete({
3831
3822
  onItemClick?.(item.value);
3832
3823
  setOpen(false);
3833
3824
  };
3834
- return /* @__PURE__ */ jsxRuntime.jsxs(
3835
- "div",
3825
+ return /* @__PURE__ */ jsxRuntime.jsx(
3826
+ Field,
3836
3827
  {
3837
- className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
3838
- style,
3839
- children: [
3840
- label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: `text-sm font-medium text-foreground select-none ${layout === "horizontal" ? "mt-2 flex-shrink-0" : ""}`, children: label }),
3841
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
3842
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center ${fieldShell({ size, disabled, focusWithin: true })}`, children: [
3843
- /* @__PURE__ */ jsxRuntime.jsx(
3844
- "input",
3845
- {
3846
- disabled,
3847
- value: term,
3848
- onChange: (e) => {
3849
- setTerm(e.target.value);
3850
- setOpen(true);
3851
- },
3852
- onFocus: () => setOpen(true),
3853
- type: "text",
3854
- name,
3855
- className: "min-w-0 flex-1 bg-transparent outline-none disabled:cursor-not-allowed placeholder:text-foreground-muted",
3856
- style: inputStyle,
3857
- placeholder: placeholder ?? "",
3858
- autoComplete: "off",
3859
- "aria-haspopup": "listbox",
3860
- "aria-expanded": open,
3861
- "aria-autocomplete": "list",
3862
- "aria-busy": loading || void 0
3863
- }
3864
- ),
3865
- loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 w-4 h-4 flex-shrink-0 flex items-center justify-center text-accent", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { inline: true, size: "xs", spinnerColor: "currentColor" }) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 flex-shrink-0 text-foreground-muted", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10.5 3.75a6.75 6.75 0 100 13.5 6.75 6.75 0 000-13.5zM2.25 10.5a8.25 8.25 0 1114.59 5.28l4.69 4.69a.75.75 0 11-1.06 1.06l-4.69-4.69A8.25 8.25 0 012.25 10.5z", clipRule: "evenodd" }) }) })
3866
- ] }) }),
3867
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
3868
- Popover__namespace.Content,
3828
+ label,
3829
+ htmlFor,
3830
+ errorId,
3831
+ errorMessage,
3832
+ layout,
3833
+ required,
3834
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
3835
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center ${fieldShell({ size, hasError, disabled, focusWithin: true })}`, style, children: [
3836
+ /* @__PURE__ */ jsxRuntime.jsx(
3837
+ "input",
3869
3838
  {
3870
- align: "start",
3871
- sideOffset: 4,
3872
- onOpenAutoFocus: (e) => e.preventDefault(),
3873
- className: "w-64 bg-surface border border-border rounded-lg mt-1 shadow-md z-50 overflow-y-auto max-h-36 animate-in fade-in-0 zoom-in-95",
3874
- children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full w-full flex items-center justify-center gap-2 py-4 text-sm text-foreground-secondary", children: [
3875
- /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { inline: true, size: "xs" }),
3876
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: loadingText })
3877
- ] }) : foundItems.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full flex flex-col items-center justify-center py-4 text-sm text-foreground-secondary", children: emptyText }) : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", children: foundItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
3878
- "div",
3879
- {
3880
- role: "option",
3881
- tabIndex: 0,
3882
- className: "text-sm flex items-center gap-2 p-2 transition-colors duration-150 hover:bg-surface-raised cursor-pointer text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3883
- onClick: () => handleSelect(item),
3884
- onKeyDown: (e) => {
3885
- if (e.key === "Enter" || e.key === " ") {
3886
- e.preventDefault();
3887
- handleSelect(item);
3888
- }
3889
- },
3890
- children: [
3891
- item.icon,
3892
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3893
- item.label,
3894
- " (",
3895
- item.value,
3896
- ")"
3897
- ] })
3898
- ]
3899
- },
3900
- item.key
3901
- )) })
3839
+ id: htmlFor,
3840
+ disabled,
3841
+ value: term,
3842
+ onChange: (e) => {
3843
+ setTerm(e.target.value);
3844
+ setOpen(true);
3845
+ },
3846
+ onFocus: () => setOpen(true),
3847
+ type: "text",
3848
+ name,
3849
+ className: "min-w-0 flex-1 bg-transparent outline-none disabled:cursor-not-allowed placeholder:text-foreground-muted",
3850
+ style: inputStyle,
3851
+ placeholder: placeholder ?? "",
3852
+ autoComplete: "off",
3853
+ "aria-haspopup": "listbox",
3854
+ "aria-expanded": open,
3855
+ "aria-autocomplete": "list",
3856
+ "aria-busy": loading || void 0,
3857
+ "aria-invalid": hasError || void 0,
3858
+ "aria-describedby": hasError ? errorId : void 0
3902
3859
  }
3903
- ) })
3904
- ] }) })
3905
- ]
3860
+ ),
3861
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 w-4 h-4 flex-shrink-0 flex items-center justify-center text-accent", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { inline: true, size: "xs", spinnerColor: "currentColor" }) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 flex-shrink-0 text-foreground-muted", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10.5 3.75a6.75 6.75 0 100 13.5 6.75 6.75 0 000-13.5zM2.25 10.5a8.25 8.25 0 1114.59 5.28l4.69 4.69a.75.75 0 11-1.06 1.06l-4.69-4.69A8.25 8.25 0 012.25 10.5z", clipRule: "evenodd" }) }) })
3862
+ ] }) }),
3863
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
3864
+ Popover__namespace.Content,
3865
+ {
3866
+ align: "start",
3867
+ sideOffset: 4,
3868
+ onOpenAutoFocus: (e) => e.preventDefault(),
3869
+ className: "w-64 bg-surface border border-border rounded-lg mt-1 shadow-md z-50 overflow-y-auto max-h-36 animate-in fade-in-0 zoom-in-95",
3870
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full w-full flex items-center justify-center gap-2 py-4 text-sm text-foreground-secondary", children: [
3871
+ /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { inline: true, size: "xs" }),
3872
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: loadingText })
3873
+ ] }) : foundItems.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full flex flex-col items-center justify-center py-4 text-sm text-foreground-secondary", children: emptyText }) : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", children: foundItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
3874
+ "div",
3875
+ {
3876
+ role: "option",
3877
+ tabIndex: 0,
3878
+ className: "text-sm flex items-center gap-2 p-2 transition-colors duration-150 hover:bg-surface-raised cursor-pointer text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
3879
+ onClick: () => handleSelect(item),
3880
+ onKeyDown: (e) => {
3881
+ if (e.key === "Enter" || e.key === " ") {
3882
+ e.preventDefault();
3883
+ handleSelect(item);
3884
+ }
3885
+ },
3886
+ children: [
3887
+ item.icon,
3888
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3889
+ item.label,
3890
+ " (",
3891
+ item.value,
3892
+ ")"
3893
+ ] })
3894
+ ]
3895
+ },
3896
+ item.key
3897
+ )) })
3898
+ }
3899
+ ) })
3900
+ ] })
3906
3901
  }
3907
3902
  );
3908
3903
  }
@@ -4982,27 +4977,13 @@ function TagsInput({
4982
4977
  className: `flex flex-wrap items-center gap-1.5 min-h-[36px] ${fieldShell({ size, hasError, disabled, focusWithin: true, sized: false })} px-2 py-1.5`,
4983
4978
  onClick: () => inputRef.current?.focus(),
4984
4979
  children: [
4985
- tags.map((tag, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
4986
- "span",
4980
+ tags.map((tag, idx) => /* @__PURE__ */ jsxRuntime.jsx(
4981
+ Tag,
4987
4982
  {
4988
- className: "inline-flex items-center gap-1 rounded-md bg-surface-raised text-foreground text-xs pl-2 pr-1 py-0.5 border border-border",
4989
- children: [
4990
- tag,
4991
- /* @__PURE__ */ jsxRuntime.jsx(
4992
- "button",
4993
- {
4994
- type: "button",
4995
- disabled,
4996
- onClick: (e) => {
4997
- e.stopPropagation();
4998
- removeTag(idx);
4999
- },
5000
- "aria-label": `Remove ${tag}`,
5001
- className: "inline-flex items-center justify-center w-4 h-4 rounded text-foreground-muted hover:text-status-error hover:bg-surface transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent",
5002
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
5003
- }
5004
- )
5005
- ]
4983
+ disabled,
4984
+ removeLabel: `Remove ${tag}`,
4985
+ onRemove: () => removeTag(idx),
4986
+ children: tag
5006
4987
  },
5007
4988
  `${tag}-${idx}`
5008
4989
  )),
@@ -5236,9 +5217,9 @@ function Rating({
5236
5217
  /* @__PURE__ */ jsxRuntime.jsx(
5237
5218
  "span",
5238
5219
  {
5239
- className: "absolute inset-0 overflow-hidden",
5220
+ className: "absolute inset-y-0 left-0 overflow-hidden",
5240
5221
  style: { width: `${fillFraction * 100}%` },
5241
- children: icon(true)
5222
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `block absolute inset-y-0 left-0 ${ICON_SIZE[size]} max-w-none`, children: icon(true) })
5242
5223
  }
5243
5224
  )
5244
5225
  ]
@@ -5745,7 +5726,6 @@ exports.TextInput = TextInput;
5745
5726
  exports.ThemeProvider = ThemeProvider;
5746
5727
  exports.ThemeSwitch = ThemeSwitch;
5747
5728
  exports.TimePicker = TimePicker;
5748
- exports.ToggleButton = ToggleButton;
5749
5729
  exports.Tooltip = Tooltip;
5750
5730
  exports.TooltipProvider = TooltipProvider;
5751
5731
  exports.TopBar = TopBar;