@takeoff-ui/react-spar 0.2.0 → 0.3.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.cjs CHANGED
@@ -6,8 +6,10 @@ var spar = require('@turkish-technology/spar');
6
6
  var clsx = require('clsx');
7
7
  var chevronBottom = require('@takeoff-icons/react/chevron-bottom');
8
8
  var chevronTop = require('@takeoff-icons/react/chevron-top');
9
- var reactTable = require('@tanstack/react-table');
10
9
  var chevronRight = require('@takeoff-icons/react/chevron-right');
10
+ var check = require('@takeoff-icons/react/check');
11
+ var close = require('@takeoff-icons/react/close');
12
+ var reactTable = require('@tanstack/react-table');
11
13
  var swap = require('@takeoff-icons/react/swap');
12
14
  var search = require('@takeoff-icons/react/search');
13
15
  var arrowLeft = require('@takeoff-icons/react/arrow-left');
@@ -146,6 +148,10 @@ var resolveDisclosureIndicator = (children, isOpen) => {
146
148
  if (typeof children === "function") return children({ isOpen });
147
149
  return children ?? (isOpen ? DEFAULT_DISCLOSURE_COLLAPSE_ICON : DEFAULT_DISCLOSURE_EXPAND_ICON);
148
150
  };
151
+ var renderPointerArrow = () => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
152
+ /* @__PURE__ */ jsxRuntime.jsx("polygon", { className: "tk-arrow-border", points: "0,0 5,5 10,0" }),
153
+ /* @__PURE__ */ jsxRuntime.jsx("polygon", { className: "tk-arrow-fill", points: "-0.086,-1.5 5,3.586 10.086,-1.5" })
154
+ ] });
149
155
 
150
156
  // src/components/accordion/base.ts
151
157
  var AccordionBase = createComponentBase({
@@ -196,6 +202,37 @@ function createSafeContext(displayName) {
196
202
  };
197
203
  return [Provider, useSafeContext];
198
204
  }
205
+ var resolveStaticWidth = (mode) => {
206
+ if (mode === "trigger" || mode === "content") return void 0;
207
+ return typeof mode === "number" ? `${mode}px` : mode;
208
+ };
209
+ var useContentWidthStyle = (mode, triggerRef) => {
210
+ const [triggerWidth, setTriggerWidth] = react.useState(null);
211
+ react.useEffect(() => {
212
+ if (mode !== "trigger") return;
213
+ const node = triggerRef.current;
214
+ if (!node) return;
215
+ const measure = () => setTriggerWidth(Math.round(node.getBoundingClientRect().width));
216
+ measure();
217
+ let frame = 0;
218
+ const observer = new ResizeObserver(() => {
219
+ cancelAnimationFrame(frame);
220
+ frame = requestAnimationFrame(measure);
221
+ });
222
+ observer.observe(node);
223
+ return () => {
224
+ cancelAnimationFrame(frame);
225
+ observer.disconnect();
226
+ };
227
+ }, [mode, triggerRef]);
228
+ return react.useMemo(() => {
229
+ if (mode === "trigger") {
230
+ return triggerWidth != null ? { width: triggerWidth } : void 0;
231
+ }
232
+ const staticWidth = resolveStaticWidth(mode);
233
+ return staticWidth != null ? { width: staticWidth } : void 0;
234
+ }, [mode, triggerWidth]);
235
+ };
199
236
  function useControllableState(controlledValue, defaultValue, onChange) {
200
237
  const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
201
238
  const { current: isControlled } = react.useRef(controlledValue !== void 0);
@@ -569,7 +606,6 @@ var [BreadcrumbProvider] = createSafeContext("BreadcrumbProvider");
569
606
  // src/components/breadcrumb/defaults.ts
570
607
  var DEFAULT_SIZE3 = "base";
571
608
  var DEFAULT_TYPE2 = "basic";
572
- var DEFAULT_SEPARATOR_VARIANT = "chevron";
573
609
  var Breadcrumb = (props) => {
574
610
  const theme = useComponentTheme("Breadcrumb");
575
611
  const { rootAttrs, rest } = composeRootAttrs(BreadcrumbBase, props, theme, {
@@ -611,17 +647,11 @@ var BreadcrumbPage = (props) => {
611
647
  return /* @__PURE__ */ jsxRuntime.jsx(spar.BreadcrumbPage, { ...spar$1, ref, ...rootAttrs, children });
612
648
  };
613
649
  BreadcrumbPage.displayName = "Breadcrumb.Page";
614
- var DEFAULT_SEPARATOR_ICON = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4L10 8L6 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
615
650
  var BreadcrumbSeparator = (props) => {
616
651
  const theme = useComponentTheme("BreadcrumbSeparator");
617
- const { rootAttrs, rest } = composeRootAttrs(BreadcrumbSeparatorBase, props, theme, {
618
- stateAttrs: ({ variant: variant2 = DEFAULT_SEPARATOR_VARIANT }) => ({
619
- "data-variant": variant2
620
- })
621
- });
622
- const { variant = DEFAULT_SEPARATOR_VARIANT, children, ref, ...spar$1 } = rest;
623
- const fallback = variant === "chevron" ? DEFAULT_SEPARATOR_ICON : null;
624
- return /* @__PURE__ */ jsxRuntime.jsx(spar.BreadcrumbSeparator, { ...spar$1, ref, ...rootAttrs, children: children ?? fallback });
652
+ const { rootAttrs, rest } = composeRootAttrs(BreadcrumbSeparatorBase, props, theme);
653
+ const { children, ref, ...spar$1 } = rest;
654
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.BreadcrumbSeparator, { ...spar$1, ref, ...rootAttrs, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(chevronRight.ChevronRightIconOutlinedRounded, { "aria-hidden": "true", focusable: "false" }) });
625
655
  };
626
656
  BreadcrumbSeparator.displayName = "Breadcrumb.Separator";
627
657
 
@@ -850,56 +880,47 @@ var Checkbox = (props) => {
850
880
  // Visual props are consumed via `stateAttrs`; destructured to keep them
851
881
  // off the rendered DOM where they would leak as raw HTML attributes.
852
882
  size: _size,
853
- // `invalid` is forwarded to Spar as `invalid` (same name).
854
- invalid = false,
855
883
  // takeoff-spar tri-state vocabulary; mapped to Spar's `CheckedState` below.
856
884
  checked,
857
885
  defaultChecked,
858
886
  indeterminate = false,
859
887
  onChange,
860
- // Behavior props owned by Spar — defaults are restated here so they also
861
- // flow into the context for compound sub-components (asterisk on Label).
862
- disabled = false,
863
- readOnly = false,
864
- required = false,
865
888
  children,
866
889
  ref,
890
+ // `invalid`, `disabled`, `readOnly` and `required` are intentionally NOT
891
+ // destructured (so no eager `= false` default is applied) — they flow to
892
+ // Spar via `...sparProps` untouched. Defaulting them here would turn an
893
+ // omitted prop into an explicit `false`, defeating Spar's
894
+ // `prop ?? fieldCtx?.x` inheritance and silently overriding a wrapping
895
+ // `<Field disabled>`. Their resolved values are read back off Spar's
896
+ // render-prop `state` below for the compound context. See Radio/Input/
897
+ // Select wrappers for the same pass-through pattern.
867
898
  ...sparProps
868
899
  } = rest;
869
900
  const sparChecked = indeterminate ? "indeterminate" : checked;
870
901
  const sparDefaultChecked = indeterminate ? "indeterminate" : defaultChecked;
871
902
  const handleSparChange = onChange ? (next) => onChange(next === true) : void 0;
872
- return /* @__PURE__ */ jsxRuntime.jsx(
873
- spar.Checkbox,
903
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.Checkbox, { ...sparProps, checked: sparChecked, defaultChecked: sparDefaultChecked, onChange: handleSparChange, ref, ...rootAttrs, children: (state) => /* @__PURE__ */ jsxRuntime.jsx(
904
+ CheckboxProvider,
874
905
  {
875
- ...sparProps,
876
- checked: sparChecked,
877
- defaultChecked: sparDefaultChecked,
878
- onChange: handleSparChange,
879
- disabled,
880
- readOnly,
881
- required,
882
- invalid,
883
- ref,
884
- ...rootAttrs,
885
- children: (state) => /* @__PURE__ */ jsxRuntime.jsx(
886
- CheckboxProvider,
887
- {
888
- value: {
889
- classNames,
890
- slotProps,
891
- required,
892
- invalid,
893
- disabled: state.disabled,
894
- readOnly: state.readOnly,
895
- checked: state.checked === true,
896
- indeterminate: state.checked === "indeterminate"
897
- },
898
- children: typeof children === "function" ? children(state) : children
899
- }
900
- )
906
+ value: {
907
+ classNames,
908
+ slotProps,
909
+ // Read the *resolved* behavior state off Spar's render-prop so the
910
+ // compound context reflects Field-inherited values, not the raw
911
+ // props. `state.required` / `state.invalid` already fold in
912
+ // `fieldCtx`, so `<Field disabled>` / `<Field invalid>` reach the
913
+ // Label asterisk and slotted styling correctly.
914
+ required: state.required,
915
+ invalid: state.invalid,
916
+ disabled: state.disabled,
917
+ readOnly: state.readOnly,
918
+ checked: state.checked === true,
919
+ indeterminate: state.checked === "indeterminate"
920
+ },
921
+ children: typeof children === "function" ? children(state) : children
901
922
  }
902
- );
923
+ ) });
903
924
  };
904
925
  Checkbox.displayName = "Checkbox";
905
926
  var CheckboxIndicator = (props) => {
@@ -1400,6 +1421,182 @@ var Dialog2 = Object.assign(Dialog, {
1400
1421
  Close: DialogClose
1401
1422
  });
1402
1423
 
1424
+ // src/components/divider/base.ts
1425
+ var DividerBase = createComponentBase({
1426
+ name: "Divider",
1427
+ slots: ["root", "label"],
1428
+ classes: {
1429
+ root: "tk-divider",
1430
+ label: "tk-divider-label"
1431
+ }
1432
+ });
1433
+
1434
+ // src/components/divider/defaults.ts
1435
+ var DEFAULT_ORIENTATION = "horizontal";
1436
+ var DEFAULT_APPEARANCE5 = "solid";
1437
+ var DEFAULT_ALIGN = "center";
1438
+ var hasRenderableDividerLabel = (node) => Array.isArray(node) ? node.some(hasRenderableDividerLabel) : isRenderableNode(node);
1439
+ var Divider = (props) => {
1440
+ const theme = useComponentTheme("Divider");
1441
+ const { rootAttrs, rest } = composeRootAttrs(DividerBase, props, theme, {
1442
+ // role/aria-orientation live here alongside the data-* hooks so consumer
1443
+ // slotProps cannot silently strip the separator semantics.
1444
+ stateAttrs: ({ orientation: orientation2 = DEFAULT_ORIENTATION, appearance = DEFAULT_APPEARANCE5, align = DEFAULT_ALIGN, decorative: decorative2 = false }) => ({
1445
+ "role": decorative2 ? "none" : "separator",
1446
+ "data-orientation": orientation2,
1447
+ "data-type": appearance,
1448
+ "data-align": align
1449
+ })
1450
+ });
1451
+ const { orientation = DEFAULT_ORIENTATION, appearance: _appearance, align: _align, decorative = false, children, ref, ...nativeProps } = rest;
1452
+ const labelSlotAttrs = buildSlotAttrs(DividerBase.getSlotProps("label"), "label", {
1453
+ themeSlotProps: theme?.slotProps,
1454
+ themeClassNames: theme?.classNames,
1455
+ instanceSlotProps: props.slotProps,
1456
+ instanceClassNames: props.classNames
1457
+ });
1458
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...nativeProps, ...rootAttrs, "aria-orientation": decorative ? void 0 : orientation, ref, children: hasRenderableDividerLabel(children) && /* @__PURE__ */ jsxRuntime.jsx("span", { ...labelSlotAttrs, children }) });
1459
+ };
1460
+ Divider.displayName = "Divider";
1461
+
1462
+ // src/components/dropdown/context.ts
1463
+ var [DropdownProvider, useDropdownOwnContext] = createSafeContext("DropdownProvider");
1464
+
1465
+ // src/components/dropdown/defaults.ts
1466
+ var DEFAULT_SIZE7 = "base";
1467
+ var DEFAULT_CONTENT_WIDTH = "content";
1468
+ var Dropdown = (props) => {
1469
+ const theme = useComponentTheme("Dropdown");
1470
+ const merged = { ...theme?.defaultProps, ...props };
1471
+ const { size = DEFAULT_SIZE7, contentWidth = DEFAULT_CONTENT_WIDTH, children, ...sparProps } = merged;
1472
+ return /* @__PURE__ */ jsxRuntime.jsx(DropdownProvider, { value: { size, contentWidth }, children: /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenu, { ...sparProps, children }) });
1473
+ };
1474
+ Dropdown.displayName = "Dropdown";
1475
+
1476
+ // src/components/dropdown/base.ts
1477
+ var DropdownTriggerBase = createComponentBase({
1478
+ name: "DropdownTrigger",
1479
+ slots: ["root"],
1480
+ classes: { root: "tk-dropdown-trigger" }
1481
+ });
1482
+ var DropdownContentBase = createComponentBase({
1483
+ name: "DropdownContent",
1484
+ slots: ["root"],
1485
+ classes: { root: "tk-dropdown-content" }
1486
+ });
1487
+ var DropdownViewportBase = createComponentBase({
1488
+ name: "DropdownViewport",
1489
+ slots: ["root"],
1490
+ classes: { root: "tk-dropdown-viewport" }
1491
+ });
1492
+ var DropdownItemBase = createComponentBase({
1493
+ name: "DropdownItem",
1494
+ slots: ["root"],
1495
+ classes: { root: "tk-dropdown-item" }
1496
+ });
1497
+ var DropdownGroupBase = createComponentBase({
1498
+ name: "DropdownGroup",
1499
+ slots: ["root"],
1500
+ classes: { root: "tk-dropdown-group" }
1501
+ });
1502
+ var DropdownLabelBase = createComponentBase({
1503
+ name: "DropdownLabel",
1504
+ slots: ["root"],
1505
+ classes: { root: "tk-dropdown-label" }
1506
+ });
1507
+ var DropdownSeparatorBase = createComponentBase({
1508
+ name: "DropdownSeparator",
1509
+ slots: ["root"],
1510
+ classes: { root: "tk-dropdown-separator" }
1511
+ });
1512
+ var DropdownArrowBase = createComponentBase({
1513
+ name: "DropdownArrow",
1514
+ slots: ["root"],
1515
+ classes: { root: "tk-dropdown-arrow" }
1516
+ });
1517
+ var DropdownArrow = (props) => {
1518
+ const theme = useComponentTheme("DropdownArrow");
1519
+ const { rootAttrs, rest } = composeRootAttrs(DropdownArrowBase, props, theme);
1520
+ const { children, ref, ...sparProps } = rest;
1521
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuArrow, { ...sparProps, ...rootAttrs, ref, children: children ?? renderPointerArrow() });
1522
+ };
1523
+ DropdownArrow.displayName = "Dropdown.Arrow";
1524
+ var DropdownContent = (props) => {
1525
+ const theme = useComponentTheme("DropdownContent");
1526
+ const { size, contentWidth } = useDropdownOwnContext("Dropdown.Content");
1527
+ const { triggerRef } = spar.useDropdownMenuContext();
1528
+ const widthStyle = useContentWidthStyle(contentWidth, triggerRef);
1529
+ const { rootAttrs, rest } = composeRootAttrs(DropdownContentBase, props, theme, {
1530
+ stateAttrs: () => ({
1531
+ "data-size": size
1532
+ })
1533
+ });
1534
+ const { children, ref, style: userStyle, ...sparProps } = rest;
1535
+ const { style: rootStyle, ...rootRest } = rootAttrs;
1536
+ const mergedStyle = widthStyle || rootStyle || userStyle ? { ...widthStyle, ...rootStyle, ...userStyle } : void 0;
1537
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuContent, { ...sparProps, ...rootRest, ref, style: mergedStyle, children });
1538
+ };
1539
+ DropdownContent.displayName = "Dropdown.Content";
1540
+ var DropdownGroup = (props) => {
1541
+ const theme = useComponentTheme("DropdownGroup");
1542
+ const { rootAttrs, rest } = composeRootAttrs(DropdownGroupBase, props, theme);
1543
+ const { children, ref, ...sparProps } = rest;
1544
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuGroup, { ...sparProps, ...rootAttrs, ref, children });
1545
+ };
1546
+ DropdownGroup.displayName = "Dropdown.Group";
1547
+ var DropdownItem = (props) => {
1548
+ const theme = useComponentTheme("DropdownItem");
1549
+ const { rootAttrs, rest } = composeRootAttrs(DropdownItemBase, props, theme);
1550
+ const { children, ref, ...sparProps } = rest;
1551
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuItem, { ...sparProps, ...rootAttrs, ref, children });
1552
+ };
1553
+ DropdownItem.displayName = "Dropdown.Item";
1554
+ var DropdownLabel = (props) => {
1555
+ const theme = useComponentTheme("DropdownLabel");
1556
+ const { rootAttrs, rest } = composeRootAttrs(DropdownLabelBase, props, theme);
1557
+ const { children, ref, ...sparProps } = rest;
1558
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuLabel, { ...sparProps, ...rootAttrs, ref, children });
1559
+ };
1560
+ DropdownLabel.displayName = "Dropdown.Label";
1561
+ var DropdownSeparator = (props) => {
1562
+ const theme = useComponentTheme("DropdownSeparator");
1563
+ const { rootAttrs, rest } = composeRootAttrs(DropdownSeparatorBase, props, theme);
1564
+ const { children, ref, ...sparProps } = rest;
1565
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuSeparator, { ...sparProps, ...rootAttrs, ref, children });
1566
+ };
1567
+ DropdownSeparator.displayName = "Dropdown.Separator";
1568
+ var DropdownTrigger = (props) => {
1569
+ const theme = useComponentTheme("DropdownTrigger");
1570
+ const { size } = useDropdownOwnContext("Dropdown.Trigger");
1571
+ const { rootAttrs, rest } = composeRootAttrs(DropdownTriggerBase, props, theme, {
1572
+ stateAttrs: () => ({
1573
+ "data-size": size
1574
+ })
1575
+ });
1576
+ const { children, ref, ...sparProps } = rest;
1577
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuTrigger, { ...sparProps, ...rootAttrs, ref, children });
1578
+ };
1579
+ DropdownTrigger.displayName = "Dropdown.Trigger";
1580
+ var DropdownViewport = (props) => {
1581
+ const theme = useComponentTheme("DropdownViewport");
1582
+ const { rootAttrs, rest } = composeRootAttrs(DropdownViewportBase, props, theme);
1583
+ const { children, ref, ...sparProps } = rest;
1584
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.DropdownMenuViewport, { ...sparProps, ...rootAttrs, ref, children });
1585
+ };
1586
+ DropdownViewport.displayName = "Dropdown.Viewport";
1587
+
1588
+ // src/components/dropdown/index.ts
1589
+ var Dropdown2 = Object.assign(Dropdown, {
1590
+ Trigger: DropdownTrigger,
1591
+ Content: DropdownContent,
1592
+ Viewport: DropdownViewport,
1593
+ Item: DropdownItem,
1594
+ Group: DropdownGroup,
1595
+ Label: DropdownLabel,
1596
+ Separator: DropdownSeparator,
1597
+ Arrow: DropdownArrow
1598
+ });
1599
+
1403
1600
  // src/components/field/base.ts
1404
1601
  var FieldBase = createComponentBase({
1405
1602
  name: "Field",
@@ -1563,7 +1760,7 @@ var InputChipsBase = createComponentBase({
1563
1760
  var [InputProvider, useInputOwnContext] = createSafeContext("InputProvider");
1564
1761
 
1565
1762
  // src/components/input/defaults.ts
1566
- var DEFAULT_SIZE7 = "base";
1763
+ var DEFAULT_SIZE8 = "base";
1567
1764
  var SEGMENT_COUNT = 4;
1568
1765
  var computeStrength = (value) => {
1569
1766
  let strength = 0;
@@ -1615,11 +1812,11 @@ var Input = (props) => {
1615
1812
  for (const value of clearablesRef.current.values()) value.clear();
1616
1813
  }, []);
1617
1814
  const { rootAttrs, rest } = composeRootAttrs(InputBase, props, theme, {
1618
- stateAttrs: ({ size: size2 = DEFAULT_SIZE7 }) => ({
1815
+ stateAttrs: ({ size: size2 = DEFAULT_SIZE8 }) => ({
1619
1816
  "data-size": size2
1620
1817
  })
1621
1818
  });
1622
- const { size = DEFAULT_SIZE7, children, ref, ...sparProps } = rest;
1819
+ const { size = DEFAULT_SIZE8, children, ref, ...sparProps } = rest;
1623
1820
  const contextValue = react.useMemo(
1624
1821
  () => ({
1625
1822
  size,
@@ -2075,19 +2272,19 @@ var RADIO_ITEM_CONTEXT_VALUE = { inside: true };
2075
2272
  var [RadioItemProvider, useRadioItemOwnContext] = createSafeContext("RadioItemProvider");
2076
2273
 
2077
2274
  // src/components/radio/defaults.ts
2078
- var DEFAULT_SIZE8 = "base";
2275
+ var DEFAULT_SIZE9 = "base";
2079
2276
  var DEFAULT_POSITION = "left";
2080
2277
  var Radio = (props) => {
2081
2278
  const theme = useComponentTheme("Radio");
2082
2279
  const { rootAttrs, rest } = composeRootAttrs(RadioBase, props, theme, {
2083
- stateAttrs: ({ size: size2 = DEFAULT_SIZE8, position: position2 = DEFAULT_POSITION, spread }) => ({
2280
+ stateAttrs: ({ size: size2 = DEFAULT_SIZE9, position: position2 = DEFAULT_POSITION, spread }) => ({
2084
2281
  "data-size": size2,
2085
2282
  "data-position": position2,
2086
2283
  "data-spread": spread ? "" : void 0
2087
2284
  })
2088
2285
  });
2089
2286
  const {
2090
- size = DEFAULT_SIZE8,
2287
+ size = DEFAULT_SIZE9,
2091
2288
  position = DEFAULT_POSITION,
2092
2289
  invalid,
2093
2290
  // `spread` is consumed only as a data-attr above; destructure to keep it
@@ -2234,8 +2431,8 @@ PopoverDescription.displayName = "Popover.Description";
2234
2431
  var PopoverArrow = (props) => {
2235
2432
  const theme = useComponentTheme("PopoverArrow");
2236
2433
  const { rootAttrs, rest } = composeRootAttrs(PopoverArrowBase, props, theme);
2237
- const { ref, ...sparProps } = rest;
2238
- return /* @__PURE__ */ jsxRuntime.jsx(spar.PopoverArrow, { ...sparProps, ...rootAttrs, ref });
2434
+ const { ref, children, ...sparProps } = rest;
2435
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.PopoverArrow, { ...sparProps, ...rootAttrs, ref, children: children ?? renderPointerArrow() });
2239
2436
  };
2240
2437
  PopoverArrow.displayName = "Popover.Arrow";
2241
2438
  var PopoverClose = (props) => {
@@ -2256,6 +2453,193 @@ var Popover2 = Object.assign(Popover, {
2256
2453
  Close: PopoverClose
2257
2454
  });
2258
2455
 
2456
+ // src/components/progress/base.ts
2457
+ var ProgressBase = createComponentBase({
2458
+ name: "Progress",
2459
+ slots: ["root"],
2460
+ classes: { root: "tk-progress" }
2461
+ });
2462
+ var ProgressTrackBase = createComponentBase({
2463
+ name: "ProgressTrack",
2464
+ slots: ["root", "rail"],
2465
+ classes: { root: "tk-progress-track", rail: "tk-progress-rail" }
2466
+ });
2467
+ var ProgressIndicatorBase = createComponentBase({
2468
+ name: "ProgressIndicator",
2469
+ slots: ["root"],
2470
+ classes: { root: "tk-progress-indicator" }
2471
+ });
2472
+ var ProgressValueBase = createComponentBase({
2473
+ name: "ProgressValue",
2474
+ slots: ["root"],
2475
+ classes: { root: "tk-progress-value" }
2476
+ });
2477
+
2478
+ // src/components/progress/context.ts
2479
+ var [ProgressProvider, useProgressContext] = createSafeContext("ProgressProvider");
2480
+
2481
+ // src/components/progress/defaults.ts
2482
+ var DEFAULT_APPEARANCE6 = "linear";
2483
+ var DEFAULT_SIZE10 = "base";
2484
+ var DEFAULT_VARIANT6 = "primary";
2485
+ var DEFAULT_MIN = 0;
2486
+ var DEFAULT_MAX = 100;
2487
+ var DEFAULT_RANGE = 100;
2488
+ var DEFAULT_ARIA_LABEL = "Progress";
2489
+ var RING_VIEWBOX = "0 0 40 40";
2490
+ var RING_CENTER = 20;
2491
+ var RING_RADIUS = 18;
2492
+ var ProgressIndicator = (props) => {
2493
+ const theme = useComponentTheme("ProgressIndicator");
2494
+ const { value, min, max, appearance, indeterminate } = useProgressContext("Progress.Indicator");
2495
+ const percent = Math.min(100, Math.max(0, (value - min) * 100 / (max - min)));
2496
+ const { rootAttrs, rest } = composeRootAttrs(ProgressIndicatorBase, props, theme, {
2497
+ stateAttrs: () => ({
2498
+ "data-type": appearance,
2499
+ "data-indeterminate": indeterminate ? "" : void 0
2500
+ })
2501
+ });
2502
+ const { ref, style, ...nativeProps } = rest;
2503
+ const { style: slotStyle, ...slotAttrs } = rootAttrs;
2504
+ if (appearance === "circular") {
2505
+ return /* @__PURE__ */ jsxRuntime.jsx(
2506
+ "circle",
2507
+ {
2508
+ cx: RING_CENTER,
2509
+ cy: RING_CENTER,
2510
+ r: RING_RADIUS,
2511
+ ...nativeProps,
2512
+ ...slotAttrs,
2513
+ pathLength: "100",
2514
+ style: { ...style, ...slotStyle, strokeDasharray: 100, strokeDashoffset: indeterminate ? void 0 : 100 - percent },
2515
+ ref
2516
+ }
2517
+ );
2518
+ }
2519
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...nativeProps, ...slotAttrs, "aria-hidden": "true", style: { ...style, ...slotStyle, width: indeterminate ? void 0 : `${percent}%` }, ref });
2520
+ };
2521
+ ProgressIndicator.displayName = "Progress.Indicator";
2522
+ var ProgressTrack = (props) => {
2523
+ const theme = useComponentTheme("ProgressTrack");
2524
+ const { appearance } = useProgressContext("Progress.Track");
2525
+ const { rootAttrs, rest } = composeRootAttrs(ProgressTrackBase, props, theme, {
2526
+ stateAttrs: () => ({ "data-type": appearance })
2527
+ });
2528
+ const { children, ref, ...nativeProps } = rest;
2529
+ const content = children ?? /* @__PURE__ */ jsxRuntime.jsx(ProgressIndicator, {});
2530
+ if (appearance === "circular") {
2531
+ const railAttrs = buildSlotAttrs(ProgressTrackBase.getSlotProps("rail"), "rail", {
2532
+ themeSlotProps: theme?.slotProps,
2533
+ themeClassNames: theme?.classNames,
2534
+ instanceSlotProps: props.slotProps,
2535
+ instanceClassNames: props.classNames
2536
+ });
2537
+ return (
2538
+ // The decorative role and the ring geometry are design-system
2539
+ // invariants (the value is announced by the root; the viewBox must
2540
+ // agree with the rail/arc circles) — layered after the spreads so
2541
+ // neither instance nor slot props can override them.
2542
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...nativeProps, ...rootAttrs, "aria-hidden": "true", focusable: "false", viewBox: RING_VIEWBOX, ref, children: [
2543
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { ...railAttrs, cx: RING_CENTER, cy: RING_CENTER, r: RING_RADIUS }),
2544
+ content
2545
+ ] })
2546
+ );
2547
+ }
2548
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...nativeProps, ...rootAttrs, ref, children: content });
2549
+ };
2550
+ ProgressTrack.displayName = "Progress.Track";
2551
+ var resolveRange = ({ value: rawValue, min: rawMin = DEFAULT_MIN, max: rawMax = DEFAULT_MAX }) => {
2552
+ const min = Number.isFinite(rawMin) ? rawMin : DEFAULT_MIN;
2553
+ const max = Number.isFinite(rawMax) && rawMax > min ? rawMax : min + DEFAULT_RANGE;
2554
+ const value = typeof rawValue === "number" && Number.isFinite(rawValue) ? Math.min(Math.max(rawValue, min), max) : min;
2555
+ return { min, max, value };
2556
+ };
2557
+ var warnedRanges = /* @__PURE__ */ new Set();
2558
+ var Progress = (props) => {
2559
+ const theme = useComponentTheme("Progress");
2560
+ const field = spar.useOptionalFieldContext();
2561
+ const resolveState = ({
2562
+ indeterminate: indeterminate2 = false,
2563
+ appearance: appearance2 = DEFAULT_APPEARANCE6,
2564
+ size: size2 = DEFAULT_SIZE10,
2565
+ variant: variant2 = DEFAULT_VARIANT6,
2566
+ disabled: disabled2 = field?.disabled ?? false
2567
+ }) => ({ indeterminate: indeterminate2, appearance: appearance2, size: size2, variant: variant2, disabled: disabled2 });
2568
+ const { rootAttrs, rest } = composeRootAttrs(ProgressBase, props, theme);
2569
+ const {
2570
+ // Consumed through resolveState/resolveRange (and as the root data-* hooks
2571
+ // below); destructured so the <div> doesn't receive unknown DOM
2572
+ // attributes.
2573
+ value: _value,
2574
+ min: _min,
2575
+ max: rawMax,
2576
+ indeterminate: _indeterminate,
2577
+ appearance: _appearance,
2578
+ disabled: _disabled,
2579
+ size: _size,
2580
+ variant: _variant,
2581
+ as,
2582
+ children,
2583
+ ref,
2584
+ ...nativeProps
2585
+ } = rest;
2586
+ const { indeterminate, appearance, size, variant, disabled } = resolveState(rest);
2587
+ const { min, max, value } = resolveRange(rest);
2588
+ const dataAttrs = {
2589
+ "data-type": appearance,
2590
+ "data-size": size,
2591
+ "data-variant": variant,
2592
+ "data-disabled": disabled ? "" : void 0,
2593
+ "data-indeterminate": indeterminate ? "" : void 0,
2594
+ // Styling hook for the finished state (e.g. a success fill at 100%);
2595
+ // meaningless while indeterminate, so dropped alongside the value.
2596
+ "data-complete": !indeterminate && value === max ? "" : void 0
2597
+ };
2598
+ if (isDevelopment() && typeof rawMax === "number" && Number.isFinite(rawMax) && rawMax <= min) {
2599
+ const message = `[Progress] \`max\` (${rawMax}) must be greater than \`min\` (${min}); falling back to ${max}.`;
2600
+ if (!warnedRanges.has(message)) {
2601
+ warnedRanges.add(message);
2602
+ console.warn(message);
2603
+ }
2604
+ }
2605
+ const consumerLabelledBy = nativeProps["aria-labelledby"];
2606
+ const accessibilityAttrs = {
2607
+ "role": nativeProps.role ?? "progressbar",
2608
+ "aria-valuemin": min,
2609
+ "aria-valuemax": max,
2610
+ // Per the progressbar pattern, an indeterminate bar exposes no
2611
+ // aria-valuenow — assistive tech then announces it as busy rather than
2612
+ // stuck at a bogus percentage.
2613
+ "aria-valuenow": indeterminate ? void 0 : value,
2614
+ // aria-valuetext accompanies aria-valuenow; drop it while indeterminate so
2615
+ // a consumer-formatted value can't linger next to a busy bar.
2616
+ "aria-valuetext": indeterminate ? void 0 : nativeProps["aria-valuetext"],
2617
+ "aria-labelledby": consumerLabelledBy ?? field?.labelId,
2618
+ "aria-label": nativeProps["aria-label"] ?? (consumerLabelledBy ? void 0 : DEFAULT_ARIA_LABEL),
2619
+ "aria-disabled": disabled || void 0
2620
+ };
2621
+ const Component = as ?? "div";
2622
+ return /* @__PURE__ */ jsxRuntime.jsx(ProgressProvider, { value: { value, min, max, appearance, indeterminate }, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { ...nativeProps, ...accessibilityAttrs, ...rootAttrs, ...dataAttrs, ref, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(ProgressTrack, {}) }) });
2623
+ };
2624
+ Progress.displayName = "Progress";
2625
+ var ProgressValue = (props) => {
2626
+ const theme = useComponentTheme("ProgressValue");
2627
+ const { appearance } = useProgressContext("Progress.Value");
2628
+ const { rootAttrs, rest } = composeRootAttrs(ProgressValueBase, props, theme, {
2629
+ stateAttrs: () => ({ "data-type": appearance })
2630
+ });
2631
+ const { children, ref, ...nativeProps } = rest;
2632
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...nativeProps, ...rootAttrs, "aria-hidden": "true", ref, children });
2633
+ };
2634
+ ProgressValue.displayName = "Progress.Value";
2635
+
2636
+ // src/components/progress/index.ts
2637
+ var Progress2 = Object.assign(Progress, {
2638
+ Track: ProgressTrack,
2639
+ Indicator: ProgressIndicator,
2640
+ Value: ProgressValue
2641
+ });
2642
+
2259
2643
  // src/components/select/base.ts
2260
2644
  var SelectBase = createComponentBase({
2261
2645
  name: "Select",
@@ -2286,6 +2670,11 @@ var SelectContentBase = createComponentBase({
2286
2670
  slots: ["root"],
2287
2671
  classes: { root: "tk-select-content" }
2288
2672
  });
2673
+ var SelectViewportBase = createComponentBase({
2674
+ name: "SelectViewport",
2675
+ slots: ["root"],
2676
+ classes: { root: "tk-select-viewport" }
2677
+ });
2289
2678
  var SelectItemBase = createComponentBase({
2290
2679
  name: "SelectItem",
2291
2680
  slots: ["root"],
@@ -2306,22 +2695,27 @@ var SelectSeparatorBase = createComponentBase({
2306
2695
  slots: ["root"],
2307
2696
  classes: { root: "tk-select-separator" }
2308
2697
  });
2698
+ var SelectArrowBase = createComponentBase({
2699
+ name: "SelectArrow",
2700
+ slots: ["root"],
2701
+ classes: { root: "tk-select-arrow" }
2702
+ });
2309
2703
 
2310
2704
  // src/components/select/context.ts
2311
2705
  var [SelectProvider, useSelectOwnContext] = createSafeContext("SelectProvider");
2312
2706
 
2313
2707
  // src/components/select/defaults.ts
2314
- var DEFAULT_SIZE9 = "base";
2315
- var DEFAULT_CONTENT_WIDTH = "trigger";
2708
+ var DEFAULT_SIZE11 = "base";
2709
+ var DEFAULT_CONTENT_WIDTH2 = "trigger";
2316
2710
  var Select = (props) => {
2317
2711
  const theme = useComponentTheme("Select");
2318
2712
  const { rootAttrs, rest } = composeRootAttrs(SelectBase, props, theme, {
2319
- stateAttrs: ({ size: size2 = DEFAULT_SIZE9, invalid: invalid2 }) => ({
2713
+ stateAttrs: ({ size: size2 = DEFAULT_SIZE11, invalid: invalid2 }) => ({
2320
2714
  "data-size": size2,
2321
2715
  "data-invalid": invalid2 ? "" : void 0
2322
2716
  })
2323
2717
  });
2324
- const { size = DEFAULT_SIZE9, invalid = false, contentWidth = DEFAULT_CONTENT_WIDTH, children, ref, ...sparProps } = rest;
2718
+ const { size = DEFAULT_SIZE11, invalid = false, contentWidth = DEFAULT_CONTENT_WIDTH2, children, ref, ...sparProps } = rest;
2325
2719
  return /* @__PURE__ */ jsxRuntime.jsx(SelectProvider, { value: { size, invalid, contentWidth }, children: /* @__PURE__ */ jsxRuntime.jsx(spar.Select, { ...sparProps, ref, ...rootAttrs, children }) });
2326
2720
  };
2327
2721
  Select.displayName = "Select";
@@ -2372,44 +2766,29 @@ var SelectIndicator = (props) => {
2372
2766
  return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...rendered, ref, "aria-hidden": "true", ...rootAttrs, children: resolved });
2373
2767
  };
2374
2768
  SelectIndicator.displayName = "Select.Indicator";
2375
- var resolveStaticWidth = (mode) => {
2376
- if (mode === "trigger" || mode === "content") return void 0;
2377
- return typeof mode === "number" ? `${mode}px` : mode;
2378
- };
2379
2769
  var SelectContent = (props) => {
2380
2770
  const theme = useComponentTheme("SelectContent");
2381
2771
  const { size, contentWidth } = useSelectOwnContext("Select.Content");
2382
2772
  const { triggerRef } = spar.useSelectContext();
2383
- const [triggerWidth, setTriggerWidth] = react.useState(null);
2384
- react.useEffect(() => {
2385
- if (contentWidth !== "trigger") return;
2386
- const node = triggerRef.current;
2387
- if (!node) return;
2388
- setTriggerWidth(node.offsetWidth);
2389
- const observer = new ResizeObserver((entries) => {
2390
- const entry = entries[0];
2391
- if (entry) setTriggerWidth(Math.round(entry.contentRect.width + 2));
2392
- });
2393
- observer.observe(node);
2394
- return () => observer.disconnect();
2395
- }, [contentWidth, triggerRef]);
2773
+ const widthStyle = useContentWidthStyle(contentWidth, triggerRef);
2396
2774
  const { rootAttrs, rest } = composeRootAttrs(SelectContentBase, props, theme, {
2397
2775
  stateAttrs: () => ({
2398
2776
  "data-size": size
2399
2777
  })
2400
2778
  });
2401
2779
  const { children, ref, style: userStyle, ...spar$1 } = rest;
2402
- const widthStyle = react.useMemo(() => {
2403
- if (contentWidth === "trigger") {
2404
- return triggerWidth != null ? { width: triggerWidth } : void 0;
2405
- }
2406
- const staticWidth = resolveStaticWidth(contentWidth);
2407
- return staticWidth != null ? { width: staticWidth } : void 0;
2408
- }, [contentWidth, triggerWidth]);
2409
- const mergedStyle = widthStyle || userStyle ? { ...widthStyle, ...userStyle } : void 0;
2410
- return /* @__PURE__ */ jsxRuntime.jsx(spar.SelectContent, { ...spar$1, ref, style: mergedStyle, ...rootAttrs, children });
2780
+ const { style: rootStyle, ...rootRest } = rootAttrs;
2781
+ const mergedStyle = widthStyle || rootStyle || userStyle ? { ...widthStyle, ...rootStyle, ...userStyle } : void 0;
2782
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.SelectContent, { ...spar$1, ...rootRest, ref, style: mergedStyle, children });
2411
2783
  };
2412
2784
  SelectContent.displayName = "Select.Content";
2785
+ var SelectViewport = (props) => {
2786
+ const theme = useComponentTheme("SelectViewport");
2787
+ const { rootAttrs, rest } = composeRootAttrs(SelectViewportBase, props, theme);
2788
+ const { children, ref, ...spar$1 } = rest;
2789
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.SelectViewport, { ...spar$1, ref, ...rootAttrs, children });
2790
+ };
2791
+ SelectViewport.displayName = "Select.Viewport";
2413
2792
  var SelectItem = (props) => {
2414
2793
  const theme = useComponentTheme("SelectItem");
2415
2794
  const { rootAttrs, rest } = composeRootAttrs(SelectItemBase, props, theme);
@@ -2438,16 +2817,638 @@ var SelectSeparator = (props) => {
2438
2817
  return /* @__PURE__ */ jsxRuntime.jsx(spar.SelectSeparator, { ...spar$1, ref, ...rootAttrs, children });
2439
2818
  };
2440
2819
  SelectSeparator.displayName = "Select.Separator";
2820
+ var SelectArrow = (props) => {
2821
+ const theme = useComponentTheme("SelectArrow");
2822
+ const { rootAttrs, rest } = composeRootAttrs(SelectArrowBase, props, theme);
2823
+ const { children, ref, ...sparProps } = rest;
2824
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.SelectArrow, { ...sparProps, ...rootAttrs, ref, children: children ?? renderPointerArrow() });
2825
+ };
2826
+ SelectArrow.displayName = "Select.Arrow";
2441
2827
 
2442
2828
  // src/components/select/index.ts
2443
2829
  var Select2 = Object.assign(Select, {
2444
2830
  Trigger: SelectTrigger,
2445
2831
  Indicator: SelectIndicator,
2446
2832
  Content: SelectContent,
2833
+ Viewport: SelectViewport,
2447
2834
  Item: SelectItem,
2448
2835
  Group: SelectGroup,
2449
2836
  Label: SelectLabel,
2450
- Separator: SelectSeparator
2837
+ Separator: SelectSeparator,
2838
+ Arrow: SelectArrow
2839
+ });
2840
+
2841
+ // src/components/slider/base.ts
2842
+ var SliderBase = createComponentBase({
2843
+ name: "Slider",
2844
+ slots: ["root"],
2845
+ classes: { root: "tk-slider" }
2846
+ });
2847
+ var SliderTrackBase = createComponentBase({
2848
+ name: "SliderTrack",
2849
+ slots: ["root"],
2850
+ classes: { root: "tk-slider-track" }
2851
+ });
2852
+ var SliderRangeBase = createComponentBase({
2853
+ name: "SliderRange",
2854
+ slots: ["root"],
2855
+ classes: { root: "tk-slider-range" }
2856
+ });
2857
+ var SliderThumbBase = createComponentBase({
2858
+ name: "SliderThumb",
2859
+ slots: ["root", "tooltip", "arrow"],
2860
+ classes: { root: "tk-slider-thumb", tooltip: "tk-slider-tooltip", arrow: "tk-slider-arrow" }
2861
+ });
2862
+ var SliderTicksBase = createComponentBase({
2863
+ name: "SliderTicks",
2864
+ slots: ["root", "tick"],
2865
+ classes: { root: "tk-slider-ticks", tick: "tk-slider-tick" }
2866
+ });
2867
+ var SliderValueBase = createComponentBase({
2868
+ name: "SliderValue",
2869
+ slots: ["root"],
2870
+ classes: { root: "tk-slider-value" }
2871
+ });
2872
+
2873
+ // src/components/slider/context.ts
2874
+ var [SliderProvider, useSliderContext] = createSafeContext("SliderProvider");
2875
+
2876
+ // src/components/slider/defaults.ts
2877
+ var DEFAULT_ORIENTATION2 = "horizontal";
2878
+ var DEFAULT_SIZE12 = "base";
2879
+ var DEFAULT_VARIANT7 = "primary";
2880
+ var DEFAULT_TOOLTIP = "auto";
2881
+ var DEFAULT_TRACK = "normal";
2882
+ var DEFAULT_MIN_DISTANCE = 0;
2883
+ var DEFAULT_MIN2 = 0;
2884
+ var DEFAULT_MAX2 = 100;
2885
+ var DEFAULT_STEP = 1;
2886
+ var DEFAULT_SPAN = 100;
2887
+ var PAGE_STEP_MULTIPLIER = 10;
2888
+ var MAX_TICKS = 100;
2889
+ var RANGE_VALUE_SEPARATOR = " \u2013 ";
2890
+ var RANGE_THUMB_LABELS = ["Minimum", "Maximum"];
2891
+
2892
+ // src/components/slider/helpers.ts
2893
+ var clamp = (value, min, max) => Math.min(Math.max(value, min), max);
2894
+ var decimalsOf = (value) => {
2895
+ if (!Number.isFinite(value)) return 0;
2896
+ const text = String(value);
2897
+ const exponent = text.indexOf("e-");
2898
+ if (exponent !== -1) {
2899
+ const fraction = text.slice(0, exponent).split(".")[1]?.length ?? 0;
2900
+ return fraction + Number(text.slice(exponent + 2));
2901
+ }
2902
+ const dot = text.indexOf(".");
2903
+ return dot === -1 ? 0 : text.length - dot - 1;
2904
+ };
2905
+ var roundTo = (value, decimals) => decimals > 0 ? Number(value.toFixed(Math.min(decimals, 15))) : Math.round(value);
2906
+ var resolveBounds = (rawMin = DEFAULT_MIN2, rawMax = DEFAULT_MAX2, rawStep = DEFAULT_STEP) => {
2907
+ const min = Number.isFinite(rawMin) ? rawMin : DEFAULT_MIN2;
2908
+ const max = Number.isFinite(rawMax) && rawMax > min ? rawMax : min + DEFAULT_SPAN;
2909
+ const step = Number.isFinite(rawStep) && rawStep > 0 ? rawStep : DEFAULT_STEP;
2910
+ return { min, max, step };
2911
+ };
2912
+ var snap = (value, { min, max, step }) => {
2913
+ if (!Number.isFinite(value)) return min;
2914
+ const steps = Math.round((value - min) / step);
2915
+ const snapped = min + steps * step;
2916
+ return clamp(roundTo(snapped, Math.max(decimalsOf(step), decimalsOf(min))), min, max);
2917
+ };
2918
+ var toPercent = (value, { min, max }) => clamp((value - min) * 100 / (max - min), 0, 100);
2919
+ var fromRatio = (ratio, { min, max }) => min + ratio * (max - min);
2920
+ var pointerCoord = (event, orientation) => orientation === "vertical" ? event.clientY : event.clientX;
2921
+ var valueFromPointer = (rect, point, bounds, orientation) => {
2922
+ const ratio = orientation === "vertical" ? rect.height === 0 ? 0 : (rect.bottom - point) / rect.height : rect.width === 0 ? 0 : (point - rect.left) / rect.width;
2923
+ return snap(fromRatio(clamp(ratio, 0, 1), bounds), bounds);
2924
+ };
2925
+ var offsetStyle = (percent, orientation) => orientation === "vertical" ? { insetBlockEnd: `${percent}%` } : { insetInlineStart: `${percent}%` };
2926
+ var bandStyle = (start, end, orientation) => orientation === "vertical" ? { insetBlockEnd: `${start}%`, height: `${end - start}%` } : { insetInlineStart: `${start}%`, width: `${end - start}%` };
2927
+ var normalizeValues = (value, range, bounds) => {
2928
+ if (range) {
2929
+ const seeded = Array.isArray(value) && value.length >= 2 ? value : [bounds.min, bounds.max];
2930
+ return seeded.map((entry) => snap(entry, bounds)).sort((a, b) => a - b);
2931
+ }
2932
+ return [snap(Array.isArray(value) ? value[0] : value ?? bounds.min, bounds)];
2933
+ };
2934
+ var toCommittedValue = (values, range) => range ? [...values] : values[0];
2935
+ var rangeInputName = (name, index, count) => count === 2 ? index === 0 ? `${name}-min` : `${name}-max` : `${name}-${index + 1}`;
2936
+ var valuesEqual = (a, b) => a.length === b.length && a.every((entry, index) => entry === b[index]);
2937
+ var thumbLabel = (index, count) => {
2938
+ if (count < 2) return void 0;
2939
+ if (count === 2) return RANGE_THUMB_LABELS[index];
2940
+ return `Value ${index + 1}`;
2941
+ };
2942
+ var closestThumbIndex = (values, target, disabled = []) => {
2943
+ let index = 0;
2944
+ let best = Infinity;
2945
+ let found = false;
2946
+ values.forEach((entry, current) => {
2947
+ if (disabled[current]) return;
2948
+ const distance = Math.abs(entry - target);
2949
+ if (distance <= best) {
2950
+ best = distance;
2951
+ index = current;
2952
+ found = true;
2953
+ }
2954
+ });
2955
+ if (found) return index;
2956
+ values.forEach((entry, current) => {
2957
+ const distance = Math.abs(entry - target);
2958
+ if (distance <= best) {
2959
+ best = distance;
2960
+ index = current;
2961
+ }
2962
+ });
2963
+ return index;
2964
+ };
2965
+ var thumbBounds = (values, index, bounds, minDistance = 0) => {
2966
+ const hardLower = index > 0 ? values[index - 1] : bounds.min;
2967
+ const hardUpper = index < values.length - 1 ? values[index + 1] : bounds.max;
2968
+ const lower = index > 0 ? hardLower + minDistance : bounds.min;
2969
+ const upper = index < values.length - 1 ? hardUpper - minDistance : bounds.max;
2970
+ return lower <= upper ? { min: lower, max: upper } : { min: hardLower, max: hardUpper };
2971
+ };
2972
+ var withThumbClamped = (values, index, next, bounds, minDistance = 0) => {
2973
+ const { min: lower, max: upper } = thumbBounds(values, index, bounds, minDistance);
2974
+ const updated = [...values];
2975
+ updated[index] = clamp(snap(next, bounds), lower, upper);
2976
+ return updated;
2977
+ };
2978
+ var withThumbSwapped = (values, index, next, bounds, minDistance = 0, disabled = []) => {
2979
+ const lowerBlocked = index > 0 && disabled[index - 1];
2980
+ const upperBlocked = index < values.length - 1 && disabled[index + 1];
2981
+ if (minDistance > 0 || lowerBlocked || upperBlocked) {
2982
+ const { min: lower, max: upper } = thumbBounds(values, index, bounds, minDistance);
2983
+ const updated2 = [...values];
2984
+ updated2[index] = clamp(snap(next, bounds), lower, upper);
2985
+ return { values: updated2, index };
2986
+ }
2987
+ const updated = [...values];
2988
+ updated[index] = snap(next, bounds);
2989
+ let active = index;
2990
+ while (active > 0 && updated[active] < updated[active - 1]) {
2991
+ [updated[active], updated[active - 1]] = [updated[active - 1], updated[active]];
2992
+ active -= 1;
2993
+ }
2994
+ while (active < updated.length - 1 && updated[active] > updated[active + 1]) {
2995
+ [updated[active], updated[active + 1]] = [updated[active + 1], updated[active]];
2996
+ active += 1;
2997
+ }
2998
+ return { values: updated, index: active };
2999
+ };
3000
+ var formatValueText = (value, formatValue) => formatValue?.(value) ?? String(value);
3001
+ var tickPercents = ({ min, max, step }, limit) => {
3002
+ const raw = (max - min) / step;
3003
+ const steps = Math.abs(raw - Math.round(raw)) < 1e-9 ? Math.round(raw) : Math.floor(raw);
3004
+ const count = steps + 1;
3005
+ if (count > limit) return null;
3006
+ return Array.from({ length: count }, (_, index) => toPercent(min + index * step, { min, max}));
3007
+ };
3008
+ var SliderRange = (props) => {
3009
+ const theme = useComponentTheme("SliderRange");
3010
+ const { values, bounds, range, orientation } = useSliderContext("Slider.Range");
3011
+ const start = range ? toPercent(values[0], bounds) : 0;
3012
+ const end = toPercent(range ? values[values.length - 1] : values[0], bounds);
3013
+ const { rootAttrs, rest } = composeRootAttrs(SliderRangeBase, props, theme);
3014
+ const { ref, style, ...nativeProps } = rest;
3015
+ const { style: slotStyle, ...slotAttrs } = rootAttrs;
3016
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...nativeProps, ...slotAttrs, "aria-hidden": "true", style: { ...style, ...slotStyle, ...bandStyle(start, end, orientation) }, ref });
3017
+ };
3018
+ SliderRange.displayName = "Slider.Range";
3019
+ var SliderThumb = (props) => {
3020
+ const theme = useComponentTheme("SliderThumb");
3021
+ const {
3022
+ values,
3023
+ bounds,
3024
+ range,
3025
+ minDistance,
3026
+ orientation,
3027
+ disabled,
3028
+ readOnly,
3029
+ invalid,
3030
+ required,
3031
+ draggingIndex,
3032
+ formatValue,
3033
+ setThumbValue,
3034
+ startDrag,
3035
+ thumbRefs,
3036
+ thumbDisabledRef,
3037
+ fieldId,
3038
+ labelId,
3039
+ describedBy,
3040
+ rootAriaLabel,
3041
+ rootAriaLabelledby
3042
+ } = useSliderContext("Slider.Thumb");
3043
+ const [isFocused, setIsFocused] = react.useState(false);
3044
+ const { rootAttrs, rest } = composeRootAttrs(SliderThumbBase, props, theme);
3045
+ const { index = 0, disabled: ownDisabled, children, ref, style, onKeyDown, onPointerDown, onFocus, onBlur, ...nativeProps } = rest;
3046
+ const value = values[index] ?? bounds.min;
3047
+ const isDragging = draggingIndex === index;
3048
+ const isDisabled = disabled || Boolean(ownDisabled);
3049
+ thumbDisabledRef.current[index] = isDisabled;
3050
+ const { min: lowerBound, max: upperBound } = thumbBounds(values, index, bounds, minDistance);
3051
+ const handleKeyDown = (event) => {
3052
+ onKeyDown?.(event);
3053
+ if (isDisabled || readOnly || event.defaultPrevented) return;
3054
+ const page = bounds.step * PAGE_STEP_MULTIPLIER;
3055
+ const next = {
3056
+ ArrowRight: value + bounds.step,
3057
+ ArrowUp: value + bounds.step,
3058
+ ArrowLeft: value - bounds.step,
3059
+ ArrowDown: value - bounds.step,
3060
+ PageUp: value + page,
3061
+ PageDown: value - page,
3062
+ Home: bounds.min,
3063
+ End: bounds.max
3064
+ }[event.key];
3065
+ if (next === void 0) return;
3066
+ event.preventDefault();
3067
+ setThumbValue(index, next);
3068
+ };
3069
+ const handlePointerDown = (event) => {
3070
+ onPointerDown?.(event);
3071
+ if (isDisabled || readOnly || event.defaultPrevented || event.button !== 0) return;
3072
+ event.preventDefault();
3073
+ event.stopPropagation();
3074
+ startDrag(index, pointerCoord(event, orientation), false, event.pointerId);
3075
+ };
3076
+ const tooltipAttrs = buildSlotAttrs(SliderThumbBase.getSlotProps("tooltip"), "tooltip", {
3077
+ themeSlotProps: theme?.slotProps,
3078
+ themeClassNames: theme?.classNames,
3079
+ instanceSlotProps: props.slotProps,
3080
+ instanceClassNames: props.classNames
3081
+ });
3082
+ const arrowAttrs = buildSlotAttrs(SliderThumbBase.getSlotProps("arrow"), "arrow", {
3083
+ themeSlotProps: theme?.slotProps,
3084
+ themeClassNames: theme?.classNames,
3085
+ instanceSlotProps: props.slotProps,
3086
+ instanceClassNames: props.classNames
3087
+ });
3088
+ const formattedText = formatValueText(value, formatValue);
3089
+ const formatted = formatValue ? formattedText : void 0;
3090
+ const { style: slotStyle, ...slotAttrs } = rootAttrs;
3091
+ const bubbleContent = children === void 0 ? formattedText : typeof children === "function" ? children({ value, formatted: formattedText, index, isDragging, isFocused }) : children;
3092
+ return /* @__PURE__ */ jsxRuntime.jsx(
3093
+ "span",
3094
+ {
3095
+ ...nativeProps,
3096
+ ...slotAttrs,
3097
+ role: "slider",
3098
+ tabIndex: isDisabled ? -1 : 0,
3099
+ "aria-valuemin": lowerBound,
3100
+ "aria-valuemax": upperBound,
3101
+ "aria-valuenow": value,
3102
+ "aria-valuetext": formatted,
3103
+ "aria-orientation": orientation,
3104
+ "aria-disabled": isDisabled || void 0,
3105
+ "aria-readonly": readOnly || void 0,
3106
+ "aria-invalid": invalid || void 0,
3107
+ "aria-required": required || void 0,
3108
+ "aria-label": nativeProps["aria-label"] ?? thumbLabel(index, values.length) ?? rootAriaLabel,
3109
+ "aria-labelledby": nativeProps["aria-labelledby"] ?? (range ? void 0 : rootAriaLabelledby ?? labelId),
3110
+ "aria-describedby": nativeProps["aria-describedby"] ?? describedBy,
3111
+ id: nativeProps.id ?? (index === 0 ? fieldId : void 0),
3112
+ "data-thumb": range ? index === 0 ? "min" : index === values.length - 1 ? "max" : void 0 : void 0,
3113
+ "data-dragging": isDragging ? "" : void 0,
3114
+ "data-focus": isFocused ? "" : void 0,
3115
+ "data-disabled": isDisabled ? "" : void 0,
3116
+ onKeyDown: handleKeyDown,
3117
+ onPointerDown: handlePointerDown,
3118
+ onFocus: (event) => {
3119
+ onFocus?.(event);
3120
+ setIsFocused(true);
3121
+ },
3122
+ onBlur: (event) => {
3123
+ onBlur?.(event);
3124
+ setIsFocused(false);
3125
+ },
3126
+ style: { ...style, ...slotStyle, ...offsetStyle(toPercent(value, bounds), orientation) },
3127
+ ref: (node) => {
3128
+ thumbRefs.current[index] = node;
3129
+ if (typeof ref === "function") ref(node);
3130
+ else if (ref) ref.current = node;
3131
+ },
3132
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { ...tooltipAttrs, "aria-hidden": "true", children: [
3133
+ bubbleContent,
3134
+ /* @__PURE__ */ jsxRuntime.jsx("span", { ...arrowAttrs, "aria-hidden": "true" })
3135
+ ] })
3136
+ }
3137
+ );
3138
+ };
3139
+ SliderThumb.displayName = "Slider.Thumb";
3140
+ var SliderTrack = (props) => {
3141
+ const theme = useComponentTheme("SliderTrack");
3142
+ const { values, disabled, readOnly, orientation, valueFromPoint, startDrag, trackRef, thumbDisabledRef } = useSliderContext("Slider.Track");
3143
+ const { rootAttrs, rest } = composeRootAttrs(SliderTrackBase, props, theme);
3144
+ const { children, ref, onPointerDown, ...nativeProps } = rest;
3145
+ const handlePointerDown = (event) => {
3146
+ onPointerDown?.(event);
3147
+ if (disabled || readOnly || event.defaultPrevented || event.button !== 0) return;
3148
+ event.preventDefault();
3149
+ const point = pointerCoord(event, orientation);
3150
+ startDrag(closestThumbIndex(values, valueFromPoint(point), thumbDisabledRef.current), point, true, event.pointerId);
3151
+ };
3152
+ return /* @__PURE__ */ jsxRuntime.jsx(
3153
+ "div",
3154
+ {
3155
+ ...nativeProps,
3156
+ ...rootAttrs,
3157
+ onPointerDown: handlePointerDown,
3158
+ ref: (node) => {
3159
+ trackRef.current = node;
3160
+ if (typeof ref === "function") ref(node);
3161
+ else if (ref) ref.current = node;
3162
+ },
3163
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3164
+ /* @__PURE__ */ jsxRuntime.jsx(SliderRange, {}),
3165
+ values.map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(SliderThumb, { index }, index))
3166
+ ] })
3167
+ }
3168
+ );
3169
+ };
3170
+ SliderTrack.displayName = "Slider.Track";
3171
+ var warnedRanges2 = /* @__PURE__ */ new Set();
3172
+ var Slider = (props) => {
3173
+ const theme = useComponentTheme("Slider");
3174
+ const field = spar.useOptionalFieldContext();
3175
+ const { rootAttrs, rest } = composeRootAttrs(SliderBase, props, theme, {
3176
+ stateAttrs: (merged) => {
3177
+ const {
3178
+ size = DEFAULT_SIZE12,
3179
+ variant = DEFAULT_VARIANT7,
3180
+ orientation: orientation2 = DEFAULT_ORIENTATION2,
3181
+ tooltip = DEFAULT_TOOLTIP,
3182
+ track = DEFAULT_TRACK,
3183
+ range: range2,
3184
+ disabled: disabled2,
3185
+ readOnly: readOnly2,
3186
+ invalid: invalid2,
3187
+ required: required2
3188
+ } = merged;
3189
+ return {
3190
+ "data-size": size,
3191
+ "data-variant": variant,
3192
+ "data-orientation": orientation2,
3193
+ "data-tooltip": tooltip,
3194
+ "data-track": track,
3195
+ "data-range": range2 ? "" : void 0,
3196
+ "data-disabled": disabled2 ?? field?.disabled ? "" : void 0,
3197
+ "data-readonly": readOnly2 ?? field?.readOnly ? "" : void 0,
3198
+ "data-invalid": invalid2 ?? field?.invalid ? "" : void 0,
3199
+ "data-required": required2 ?? field?.required ? "" : void 0
3200
+ };
3201
+ }
3202
+ });
3203
+ const {
3204
+ // Consumed through the resolved state below (and as the root data-* hooks);
3205
+ // destructured so the <div> doesn't receive unknown DOM attributes.
3206
+ min: rawMin,
3207
+ max: rawMax,
3208
+ step: rawStep,
3209
+ range = false,
3210
+ value,
3211
+ defaultValue,
3212
+ onValueChange,
3213
+ onValueChangeEnd,
3214
+ disabled: ownDisabled,
3215
+ readOnly: ownReadOnly,
3216
+ invalid: ownInvalid,
3217
+ required: ownRequired,
3218
+ minDistance = DEFAULT_MIN_DISTANCE,
3219
+ orientation = DEFAULT_ORIENTATION2,
3220
+ size: _size,
3221
+ variant: _variant,
3222
+ // Consumed as the `data-tooltip` / `data-track` root hooks above (the recipe
3223
+ // drives the value bubble and the inverted/none fill off them); pulled out
3224
+ // so they never land on the <div> as unknown attributes.
3225
+ tooltip: _tooltip,
3226
+ track: _track,
3227
+ formatValue,
3228
+ name,
3229
+ form,
3230
+ as,
3231
+ children,
3232
+ ref,
3233
+ ...nativeProps
3234
+ } = rest;
3235
+ const disabled = ownDisabled ?? field?.disabled ?? false;
3236
+ const readOnly = ownReadOnly ?? field?.readOnly ?? false;
3237
+ const invalid = ownInvalid ?? field?.invalid ?? false;
3238
+ const required = ownRequired ?? field?.required ?? false;
3239
+ const bounds = resolveBounds(rawMin, rawMax, rawStep);
3240
+ if (isDevelopment() && typeof rawMax === "number" && Number.isFinite(rawMax) && rawMax <= bounds.min) {
3241
+ const message = `[Slider] \`max\` (${rawMax}) must be greater than \`min\` (${bounds.min}); falling back to ${bounds.max}.`;
3242
+ if (!warnedRanges2.has("inverted-range")) {
3243
+ warnedRanges2.add("inverted-range");
3244
+ console.warn(message);
3245
+ }
3246
+ }
3247
+ const controlledValues = value === void 0 ? void 0 : normalizeValues(value, range, bounds);
3248
+ const initialValues = normalizeValues(defaultValue, range, bounds);
3249
+ const onValueChangeRef = react.useRef(onValueChange);
3250
+ onValueChangeRef.current = onValueChange;
3251
+ const handleCommit = react.useCallback((next) => onValueChangeRef.current?.(toCommittedValue(next, range)), [range]);
3252
+ const [rawValues = initialValues, setValues] = useControllableState(controlledValues, initialValues, handleCommit);
3253
+ const values = react.useMemo(() => normalizeValues(toCommittedValue(rawValues, range), range, bounds), [rawValues, range, bounds.min, bounds.max, bounds.step]);
3254
+ const onValueChangeEndRef = react.useRef(onValueChangeEnd);
3255
+ onValueChangeEndRef.current = onValueChangeEnd;
3256
+ const emitChangeEnd = react.useCallback((vals) => onValueChangeEndRef.current?.(toCommittedValue(vals, range)), [range]);
3257
+ const emitChangeEndRef = react.useRef(emitChangeEnd);
3258
+ emitChangeEndRef.current = emitChangeEnd;
3259
+ const [draggingIndex, setDraggingIndex] = react.useState(null);
3260
+ const trackRef = react.useRef(null);
3261
+ const thumbRefs = react.useRef([]);
3262
+ const thumbDisabledRef = react.useRef([]);
3263
+ const gestureStartRef = react.useRef(null);
3264
+ const dragPointerRef = react.useRef(null);
3265
+ const valuesRef = react.useRef(values);
3266
+ valuesRef.current = values;
3267
+ thumbDisabledRef.current.length = values.length;
3268
+ const valueFromPoint = react.useCallback(
3269
+ (point) => {
3270
+ const track = trackRef.current;
3271
+ if (!track) return bounds.min;
3272
+ return valueFromPointer(track.getBoundingClientRect(), point, bounds, orientation);
3273
+ },
3274
+ [bounds.min, bounds.max, bounds.step, orientation]
3275
+ );
3276
+ const commit = react.useCallback(
3277
+ (next) => {
3278
+ if (!valuesEqual(next, valuesRef.current)) setValues(next);
3279
+ },
3280
+ [setValues]
3281
+ );
3282
+ const setThumbValue = react.useCallback(
3283
+ (index, next) => {
3284
+ if (disabled || readOnly || thumbDisabledRef.current[index]) return;
3285
+ const before = valuesRef.current;
3286
+ const updated = withThumbClamped(before, index, next, bounds, minDistance);
3287
+ commit(updated);
3288
+ if (!valuesEqual(updated, before)) emitChangeEnd(updated);
3289
+ },
3290
+ [disabled, readOnly, commit, emitChangeEnd, minDistance, bounds.min, bounds.max, bounds.step]
3291
+ );
3292
+ const startDrag = react.useCallback(
3293
+ (index, point, seek, pointerId) => {
3294
+ if (disabled || readOnly || thumbDisabledRef.current[index]) return;
3295
+ gestureStartRef.current = valuesRef.current;
3296
+ dragPointerRef.current = pointerId;
3297
+ if (!seek) {
3298
+ setDraggingIndex(index);
3299
+ thumbRefs.current[index]?.focus();
3300
+ return;
3301
+ }
3302
+ const { values: next, index: active } = withThumbSwapped(valuesRef.current, index, valueFromPoint(point), bounds, minDistance, thumbDisabledRef.current);
3303
+ setDraggingIndex(active);
3304
+ thumbRefs.current[active]?.focus();
3305
+ commit(next);
3306
+ },
3307
+ [disabled, readOnly, commit, valueFromPoint, minDistance, bounds.min, bounds.max, bounds.step]
3308
+ );
3309
+ react.useEffect(() => {
3310
+ if (draggingIndex === null) return;
3311
+ const ownerId = dragPointerRef.current;
3312
+ const isOwner = (event) => ownerId === null || event.pointerId === ownerId;
3313
+ const settle = () => {
3314
+ setDraggingIndex(null);
3315
+ if (gestureStartRef.current && !valuesEqual(valuesRef.current, gestureStartRef.current)) emitChangeEnd(valuesRef.current);
3316
+ gestureStartRef.current = null;
3317
+ dragPointerRef.current = null;
3318
+ };
3319
+ const handleMove = (event) => {
3320
+ if (!isOwner(event)) return;
3321
+ if (event.buttons === 0) {
3322
+ settle();
3323
+ return;
3324
+ }
3325
+ const { values: next, index: active } = withThumbSwapped(
3326
+ valuesRef.current,
3327
+ draggingIndex,
3328
+ valueFromPoint(pointerCoord(event, orientation)),
3329
+ bounds,
3330
+ minDistance,
3331
+ thumbDisabledRef.current
3332
+ );
3333
+ if (active !== draggingIndex) {
3334
+ setDraggingIndex(active);
3335
+ thumbRefs.current[active]?.focus();
3336
+ }
3337
+ commit(next);
3338
+ };
3339
+ const handleEnd = (event) => {
3340
+ if (!isOwner(event)) return;
3341
+ settle();
3342
+ };
3343
+ document.addEventListener("pointermove", handleMove);
3344
+ document.addEventListener("pointerup", handleEnd);
3345
+ document.addEventListener("pointercancel", handleEnd);
3346
+ return () => {
3347
+ document.removeEventListener("pointermove", handleMove);
3348
+ document.removeEventListener("pointerup", handleEnd);
3349
+ document.removeEventListener("pointercancel", handleEnd);
3350
+ };
3351
+ }, [draggingIndex, valueFromPoint, commit, emitChangeEnd, minDistance, orientation, bounds.min, bounds.max, bounds.step]);
3352
+ react.useEffect(
3353
+ () => () => {
3354
+ if (gestureStartRef.current && !valuesEqual(valuesRef.current, gestureStartRef.current)) emitChangeEndRef.current(valuesRef.current);
3355
+ gestureStartRef.current = null;
3356
+ },
3357
+ []
3358
+ );
3359
+ const Component = as ?? "div";
3360
+ const htmlProps = nativeProps;
3361
+ const groupAttrs = range ? {
3362
+ "role": htmlProps.role ?? "group",
3363
+ "aria-labelledby": htmlProps["aria-labelledby"] ?? field?.labelId
3364
+ } : {};
3365
+ const { "aria-label": rootAriaLabel, "aria-labelledby": rootAriaLabelledby, ...singleWrapperProps } = htmlProps;
3366
+ const wrapperProps = range ? nativeProps : singleWrapperProps;
3367
+ return /* @__PURE__ */ jsxRuntime.jsx(
3368
+ SliderProvider,
3369
+ {
3370
+ value: {
3371
+ values,
3372
+ bounds,
3373
+ range,
3374
+ minDistance,
3375
+ orientation,
3376
+ disabled,
3377
+ readOnly,
3378
+ invalid,
3379
+ required,
3380
+ draggingIndex,
3381
+ trackRef,
3382
+ thumbRefs,
3383
+ thumbDisabledRef,
3384
+ formatValue,
3385
+ setThumbValue,
3386
+ startDrag,
3387
+ valueFromPoint,
3388
+ fieldId: field?.fieldId,
3389
+ labelId: field?.labelId,
3390
+ describedBy: invalid ? field?.errorId : field?.descriptionId,
3391
+ // Only a single slider forwards the root name to its thumb; a range
3392
+ // carries it on the group wrapper above.
3393
+ rootAriaLabel: range ? void 0 : rootAriaLabel,
3394
+ rootAriaLabelledby: range ? void 0 : rootAriaLabelledby
3395
+ },
3396
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Component, { ...wrapperProps, ...groupAttrs, ...rootAttrs, ref, children: [
3397
+ children ?? /* @__PURE__ */ jsxRuntime.jsx(SliderTrack, {}),
3398
+ name && !disabled && (range ? (
3399
+ // One input per handle so a 3+ thumb range submits every value; a
3400
+ // two-handle range keeps the conventional `-min` / `-max` pair.
3401
+ values.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: rangeInputName(name, index, values.length), value: entry, form }, index))
3402
+ ) : /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: values[0], form }))
3403
+ ] })
3404
+ }
3405
+ );
3406
+ };
3407
+ Slider.displayName = "Slider";
3408
+ var warnedGrids = /* @__PURE__ */ new Set();
3409
+ var SliderTicks = (props) => {
3410
+ const theme = useComponentTheme("SliderTicks");
3411
+ const { bounds, orientation } = useSliderContext("Slider.Ticks");
3412
+ const { rootAttrs, rest } = composeRootAttrs(SliderTicksBase, props, theme);
3413
+ const { ref, ...nativeProps } = rest;
3414
+ const percents = tickPercents(bounds, MAX_TICKS);
3415
+ if (percents === null) {
3416
+ if (isDevelopment()) {
3417
+ const message = `[Slider.Ticks] needs at most ${MAX_TICKS} marks, but min ${bounds.min} / max ${bounds.max} / step ${bounds.step} produces more; the ticks are not rendered.`;
3418
+ if (!warnedGrids.has("ticks-too-dense")) {
3419
+ warnedGrids.add("ticks-too-dense");
3420
+ console.warn(message);
3421
+ }
3422
+ }
3423
+ return null;
3424
+ }
3425
+ const tickAttrs = buildSlotAttrs(SliderTicksBase.getSlotProps("tick"), "tick", {
3426
+ themeSlotProps: theme?.slotProps,
3427
+ themeClassNames: theme?.classNames,
3428
+ instanceSlotProps: props.slotProps,
3429
+ instanceClassNames: props.classNames
3430
+ });
3431
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...nativeProps, ...rootAttrs, "aria-hidden": "true", ref, children: percents.map((percent, index) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...tickAttrs, style: offsetStyle(percent, orientation) }, index)) });
3432
+ };
3433
+ SliderTicks.displayName = "Slider.Ticks";
3434
+ var SliderValue = (props) => {
3435
+ const theme = useComponentTheme("SliderValue");
3436
+ const { values, range, formatValue } = useSliderContext("Slider.Value");
3437
+ const { rootAttrs, rest } = composeRootAttrs(SliderValueBase, props, theme);
3438
+ const { children, ref, ...nativeProps } = rest;
3439
+ const formatted = values.map((value) => formatValueText(value, formatValue));
3440
+ const state = { values, formatted, range };
3441
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...nativeProps, ...rootAttrs, "aria-hidden": "true", ref, children: typeof children === "function" ? children(state) : children ?? formatted.join(RANGE_VALUE_SEPARATOR) });
3442
+ };
3443
+ SliderValue.displayName = "Slider.Value";
3444
+
3445
+ // src/components/slider/index.ts
3446
+ var Slider2 = Object.assign(Slider, {
3447
+ Track: SliderTrack,
3448
+ Range: SliderRange,
3449
+ Thumb: SliderThumb,
3450
+ Ticks: SliderTicks,
3451
+ Value: SliderValue
2451
3452
  });
2452
3453
 
2453
3454
  // src/components/spinner/base.ts
@@ -2461,10 +3462,10 @@ var SpinnerBase = createComponentBase({
2461
3462
  });
2462
3463
 
2463
3464
  // src/components/spinner/defaults.ts
2464
- var DEFAULT_APPEARANCE5 = "rounded";
2465
- var DEFAULT_SIZE10 = "base";
2466
- var DEFAULT_VARIANT6 = "neutral";
2467
- var DEFAULT_ARIA_LABEL = "Loading";
3465
+ var DEFAULT_APPEARANCE7 = "rounded";
3466
+ var DEFAULT_SIZE13 = "base";
3467
+ var DEFAULT_VARIANT8 = "neutral";
3468
+ var DEFAULT_ARIA_LABEL2 = "Loading";
2468
3469
  var SPINNER_RADIAL_PARTS = 8;
2469
3470
  var SPINNER_THREE_DOT_PARTS = 3;
2470
3471
  var renderIndicatorContent = (appearance) => {
@@ -2501,13 +3502,13 @@ var renderIndicatorContent = (appearance) => {
2501
3502
  var Spinner = (props) => {
2502
3503
  const theme = useComponentTheme("Spinner");
2503
3504
  const { rootAttrs, rest } = composeRootAttrs(SpinnerBase, props, theme, {
2504
- stateAttrs: ({ variant = DEFAULT_VARIANT6, size = DEFAULT_SIZE10, appearance: appearance2 = DEFAULT_APPEARANCE5 }) => ({
3505
+ stateAttrs: ({ variant = DEFAULT_VARIANT8, size = DEFAULT_SIZE13, appearance: appearance2 = DEFAULT_APPEARANCE7 }) => ({
2505
3506
  "data-variant": variant,
2506
3507
  "data-size": size,
2507
3508
  "data-type": appearance2
2508
3509
  })
2509
3510
  });
2510
- const { variant: _variant, size: _size, appearance = DEFAULT_APPEARANCE5, ref, ...nativeProps } = rest;
3511
+ const { variant: _variant, size: _size, appearance = DEFAULT_APPEARANCE7, ref, ...nativeProps } = rest;
2511
3512
  const indicatorSlotAttrs = buildSlotAttrs(SpinnerBase.getSlotProps("indicator"), "indicator", {
2512
3513
  themeSlotProps: theme?.slotProps,
2513
3514
  themeClassNames: theme?.classNames,
@@ -2517,12 +3518,307 @@ var Spinner = (props) => {
2517
3518
  const isDecorative = nativeProps["aria-hidden"] === true || nativeProps["aria-hidden"] === "true";
2518
3519
  const accessibilityAttrs = isDecorative ? {} : {
2519
3520
  "role": nativeProps.role ?? "status",
2520
- "aria-label": nativeProps["aria-label"] ?? (nativeProps["aria-labelledby"] ? void 0 : DEFAULT_ARIA_LABEL)
3521
+ "aria-label": nativeProps["aria-label"] ?? (nativeProps["aria-labelledby"] ? void 0 : DEFAULT_ARIA_LABEL2)
2521
3522
  };
2522
3523
  return /* @__PURE__ */ jsxRuntime.jsx("span", { ...accessibilityAttrs, ...nativeProps, ...rootAttrs, ref, children: /* @__PURE__ */ jsxRuntime.jsx("span", { ...indicatorSlotAttrs, "aria-hidden": "true", children: renderIndicatorContent(appearance) }) });
2523
3524
  };
2524
3525
  Spinner.displayName = "Spinner";
2525
3526
 
3527
+ // src/components/stepper/base.ts
3528
+ var StepperBase = createComponentBase({
3529
+ name: "Stepper",
3530
+ slots: ["root"],
3531
+ classes: { root: "tk-stepper" }
3532
+ });
3533
+ var StepperItemBase = createComponentBase({
3534
+ name: "StepperItem",
3535
+ slots: ["root", "trigger", "rail", "indicator", "content"],
3536
+ classes: {
3537
+ root: "tk-stepper-item",
3538
+ trigger: "tk-stepper-trigger",
3539
+ rail: "tk-stepper-rail",
3540
+ indicator: "tk-stepper-indicator",
3541
+ content: "tk-stepper-content"
3542
+ }
3543
+ });
3544
+ var StepperTitleBase = createComponentBase({
3545
+ name: "StepperTitle",
3546
+ slots: ["root"],
3547
+ classes: { root: "tk-stepper-title" }
3548
+ });
3549
+ var StepperDescriptionBase = createComponentBase({
3550
+ name: "StepperDescription",
3551
+ slots: ["root"],
3552
+ classes: { root: "tk-stepper-description" }
3553
+ });
3554
+
3555
+ // src/components/stepper/context.ts
3556
+ var [StepperProvider, useStepperContext] = createSafeContext("StepperProvider");
3557
+ var [StepperItemIndexProvider, useStepperItemIndex] = createSafeContext("StepperItemIndexProvider");
3558
+ var [StepperItemProvider, useStepperItem] = createSafeContext("Stepper.Item");
3559
+
3560
+ // src/components/stepper/defaults.ts
3561
+ var DEFAULT_ORIENTATION3 = "horizontal";
3562
+ var DEFAULT_MODE2 = "default";
3563
+ var DEFAULT_SIZE14 = "base";
3564
+ var DEFAULT_ACTIVE = 0;
3565
+ var DEFAULT_COMPLETED_LABEL = "completed";
3566
+ var DEFAULT_ERROR_LABEL = "error";
3567
+ var FOCUSABLE_TRIGGER_SELECTOR = '.tk-stepper-trigger:not(:disabled):not([tabindex="-1"])';
3568
+ var Stepper = (props) => {
3569
+ const theme = useComponentTheme("Stepper");
3570
+ const { rootAttrs, rest } = composeRootAttrs(StepperBase, props, theme, {
3571
+ stateAttrs: ({ orientation: orientation2 = DEFAULT_ORIENTATION3, mode: mode2 = DEFAULT_MODE2, size = DEFAULT_SIZE14, linear: linear2 = false, reverse = false }) => ({
3572
+ "data-orientation": orientation2,
3573
+ "data-mode": mode2,
3574
+ "data-size": size,
3575
+ "data-linear": linear2 ? "" : void 0,
3576
+ "data-reverse": reverse ? "" : void 0
3577
+ })
3578
+ });
3579
+ const {
3580
+ active: controlledActive,
3581
+ defaultActive = DEFAULT_ACTIVE,
3582
+ onActiveChange,
3583
+ onStepClick,
3584
+ orientation = DEFAULT_ORIENTATION3,
3585
+ mode = DEFAULT_MODE2,
3586
+ // Consumed only as root data-* hooks above; destructured so the <ol>
3587
+ // doesn't receive unknown DOM attributes.
3588
+ size: _size,
3589
+ linear = false,
3590
+ reverse: _reverse,
3591
+ completedLabel = DEFAULT_COMPLETED_LABEL,
3592
+ errorLabel = DEFAULT_ERROR_LABEL,
3593
+ onKeyDown: nativeOnKeyDown,
3594
+ as,
3595
+ children,
3596
+ ref,
3597
+ ...nativeProps
3598
+ } = rest;
3599
+ const onActiveChangeRef = react.useRef(onActiveChange);
3600
+ onActiveChangeRef.current = onActiveChange;
3601
+ const stableOnActiveChange = react.useCallback((index) => {
3602
+ onActiveChangeRef.current?.(index);
3603
+ }, []);
3604
+ const onStepClickRef = react.useRef(onStepClick);
3605
+ onStepClickRef.current = onStepClick;
3606
+ const stableOnStepClick = react.useCallback((detail) => {
3607
+ onStepClickRef.current?.(detail);
3608
+ }, []);
3609
+ const [activeValue, setActive] = useControllableState(controlledActive, defaultActive, stableOnActiveChange);
3610
+ const active = activeValue ?? DEFAULT_ACTIVE;
3611
+ const [stepsMeta, setStepsMeta] = react.useState(/* @__PURE__ */ new Map());
3612
+ const { items, renderStepsMeta } = react.useMemo(() => {
3613
+ const meta = /* @__PURE__ */ new Map();
3614
+ let stepIndex = 0;
3615
+ const items2 = react.Children.toArray(children).map((child) => {
3616
+ if (!react.isValidElement(child)) return child;
3617
+ const index = stepIndex++;
3618
+ const { error = false, disabled = false, isClickable = true } = child.props;
3619
+ meta.set(index, { error, disabled, isClickable });
3620
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperItemIndexProvider, { value: { index }, children: child }, child.key ?? index);
3621
+ });
3622
+ return { items: items2, renderStepsMeta: meta };
3623
+ }, [children]);
3624
+ const registerStep = react.useCallback((index, meta) => {
3625
+ setStepsMeta((previous) => new Map(previous).set(index, meta));
3626
+ return () => {
3627
+ setStepsMeta((previous) => {
3628
+ const next = new Map(previous);
3629
+ next.delete(index);
3630
+ return next;
3631
+ });
3632
+ };
3633
+ }, []);
3634
+ const contextValue = react.useMemo(() => {
3635
+ const canSelectStep = (index, selfMeta) => {
3636
+ const target = stepsMeta.get(index) ?? selfMeta ?? renderStepsMeta.get(index);
3637
+ if (!target || target.disabled || !target.isClickable) return false;
3638
+ if (!linear) return true;
3639
+ if (index < active) return true;
3640
+ if (index === active + 1) {
3641
+ const current = stepsMeta.get(active) ?? renderStepsMeta.get(active);
3642
+ return !current?.error && !current?.disabled;
3643
+ }
3644
+ return false;
3645
+ };
3646
+ const getStepStatus = (options) => {
3647
+ const { index } = options;
3648
+ if (index < active) return "completed";
3649
+ if (index === active) return "active";
3650
+ return "inactive";
3651
+ };
3652
+ return {
3653
+ active,
3654
+ mode,
3655
+ completedLabel,
3656
+ errorLabel,
3657
+ getStepStatus,
3658
+ registerStep,
3659
+ canSelectStep,
3660
+ selectStep: (index) => {
3661
+ if (index !== active && canSelectStep(index)) {
3662
+ setActive(index);
3663
+ }
3664
+ },
3665
+ emitStepClick: (detail) => {
3666
+ stableOnStepClick(detail);
3667
+ }
3668
+ };
3669
+ }, [active, mode, completedLabel, errorLabel, linear, stepsMeta, renderStepsMeta, registerStep, setActive, stableOnStepClick]);
3670
+ const { onKeyDown: slotOnKeyDown, ...restRootAttrs } = rootAttrs;
3671
+ const userOnKeyDown = slotOnKeyDown ?? nativeOnKeyDown;
3672
+ const handleKeyDown = (event) => {
3673
+ userOnKeyDown?.(event);
3674
+ if (event.defaultPrevented) return;
3675
+ const forwardKey = orientation === "horizontal" ? "ArrowRight" : "ArrowDown";
3676
+ const backwardKey = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
3677
+ if (event.key !== forwardKey && event.key !== backwardKey && event.key !== "Home" && event.key !== "End") return;
3678
+ const pressedTrigger = event.target instanceof HTMLElement ? event.target.closest(".tk-stepper-trigger") : null;
3679
+ if (!pressedTrigger || pressedTrigger.closest(".tk-stepper") !== event.currentTarget) return;
3680
+ event.preventDefault();
3681
+ const triggers = Array.from(event.currentTarget.querySelectorAll(FOCUSABLE_TRIGGER_SELECTOR)).filter(
3682
+ (trigger) => trigger.closest(".tk-stepper") === event.currentTarget
3683
+ );
3684
+ const currentIndex = triggers.indexOf(pressedTrigger);
3685
+ if (triggers.length === 0 || currentIndex === -1 && event.key !== "Home" && event.key !== "End") return;
3686
+ const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? triggers.length - 1 : event.key === forwardKey ? currentIndex + 1 : currentIndex - 1;
3687
+ triggers[nextIndex]?.focus();
3688
+ };
3689
+ const Component = as ?? "ol";
3690
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperProvider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { ...nativeProps, ...restRootAttrs, ref, onKeyDown: handleKeyDown, children: items }) });
3691
+ };
3692
+ Stepper.displayName = "Stepper";
3693
+ var StepperTitle = (props) => {
3694
+ const theme = useComponentTheme("StepperTitle");
3695
+ useStepperContext("Stepper.Title");
3696
+ const { rootAttrs, rest } = composeRootAttrs(StepperTitleBase, props, theme);
3697
+ const { as, children, ref, ...nativeProps } = rest;
3698
+ const Component = as ?? "span";
3699
+ return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...nativeProps, ...rootAttrs, ref, children });
3700
+ };
3701
+ StepperTitle.displayName = "Stepper.Title";
3702
+ var visuallyHidden = {
3703
+ position: "absolute",
3704
+ width: 1,
3705
+ height: 1,
3706
+ margin: -1,
3707
+ padding: 0,
3708
+ overflow: "hidden",
3709
+ clip: "rect(0 0 0 0)",
3710
+ whiteSpace: "nowrap",
3711
+ border: 0
3712
+ };
3713
+ var StepperItem = (props) => {
3714
+ const theme = useComponentTheme("StepperItem");
3715
+ const { active, mode, completedLabel, errorLabel, getStepStatus, registerStep, canSelectStep, selectStep, emitStepClick } = useStepperContext("Stepper.Item");
3716
+ const { index } = useStepperItemIndex("Stepper.Item");
3717
+ const { rootAttrs, rest } = composeRootAttrs(StepperItemBase, props, theme, {
3718
+ stateAttrs: ({ error: error2 = false, disabled: disabled2 = false, isClickable: isClickable2 = true }) => ({
3719
+ "data-state": getStepStatus({ index }),
3720
+ "data-error": error2 ? "" : void 0,
3721
+ "data-disabled": disabled2 ? "" : void 0,
3722
+ // The active step is excluded: pressing it re-emits `onStepClick` but
3723
+ // can never change the selection, which is what this hook advertises.
3724
+ "data-clickable": index !== active && canSelectStep(index, { error: error2, disabled: disabled2, isClickable: isClickable2 }) ? "" : void 0
3725
+ })
3726
+ });
3727
+ const { error = false, disabled = false, isClickable = true, indicator, as, children, ref, ...nativeProps } = rest;
3728
+ react.useEffect(() => registerStep(index, { error, disabled, isClickable }), [registerStep, index, error, disabled, isClickable]);
3729
+ const status = getStepStatus({ index });
3730
+ const selectable = canSelectStep(index, { error, disabled, isClickable });
3731
+ const isActive = index === active;
3732
+ const ariaDisabled = selectable || isActive ? void 0 : true;
3733
+ const statusLabel = error ? errorLabel : status === "completed" ? completedLabel : void 0;
3734
+ const [descriptionId, setDescriptionId] = react.useState();
3735
+ const registerDescription = react.useCallback((id) => {
3736
+ setDescriptionId(id);
3737
+ return () => {
3738
+ setDescriptionId((current) => current === id ? void 0 : current);
3739
+ };
3740
+ }, []);
3741
+ const itemContextValue = react.useMemo(() => ({ registerDescription }), [registerDescription]);
3742
+ const slotLayering = {
3743
+ themeSlotProps: theme?.slotProps,
3744
+ themeClassNames: theme?.classNames,
3745
+ instanceSlotProps: props.slotProps,
3746
+ instanceClassNames: props.classNames
3747
+ };
3748
+ const triggerSlotAttrs = buildSlotAttrs(StepperItemBase.getSlotProps("trigger"), "trigger", slotLayering);
3749
+ const { onClick: triggerSlotOnClick, ...triggerAttrs } = triggerSlotAttrs;
3750
+ const railAttrs = buildSlotAttrs(StepperItemBase.getSlotProps("rail"), "rail", slotLayering);
3751
+ const indicatorAttrs = buildSlotAttrs(StepperItemBase.getSlotProps("indicator"), "indicator", slotLayering);
3752
+ const contentAttrs = buildSlotAttrs(StepperItemBase.getSlotProps("content"), "content", slotLayering);
3753
+ const resolvedIndicator = typeof indicator === "function" ? indicator({ status, index }) : indicator;
3754
+ let indicatorContent = null;
3755
+ if (!disabled) {
3756
+ if (resolvedIndicator != null) {
3757
+ indicatorContent = resolvedIndicator;
3758
+ } else if (error) {
3759
+ indicatorContent = /* @__PURE__ */ jsxRuntime.jsx(close.CloseIconOutlinedRounded, {});
3760
+ } else if (status === "completed") {
3761
+ indicatorContent = /* @__PURE__ */ jsxRuntime.jsx(check.CheckIconOutlinedRounded, {});
3762
+ }
3763
+ }
3764
+ const handleTriggerClick = (event) => {
3765
+ triggerSlotOnClick?.(event);
3766
+ if (event.defaultPrevented) return;
3767
+ if (!selectable && !(isActive && isClickable)) return;
3768
+ emitStepClick({ index, status });
3769
+ selectStep(index);
3770
+ };
3771
+ const Component = as ?? "li";
3772
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperItemProvider, { value: itemContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(Component, { ...nativeProps, ...rootAttrs, ref, children: [
3773
+ mode !== "compact" && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", ...railAttrs }),
3774
+ /* @__PURE__ */ jsxRuntime.jsxs(
3775
+ "button",
3776
+ {
3777
+ ...triggerAttrs,
3778
+ type: "button",
3779
+ disabled,
3780
+ onClick: handleTriggerClick,
3781
+ "aria-current": isActive ? "step" : void 0,
3782
+ "aria-disabled": ariaDisabled,
3783
+ "aria-describedby": descriptionId,
3784
+ tabIndex: isClickable ? void 0 : -1,
3785
+ children: [
3786
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", ...indicatorAttrs, children: indicatorContent }),
3787
+ /* @__PURE__ */ jsxRuntime.jsx("span", { ...contentAttrs, children }),
3788
+ statusLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: visuallyHidden, children: `, ${statusLabel}` }) : null
3789
+ ]
3790
+ }
3791
+ )
3792
+ ] }) });
3793
+ };
3794
+ StepperItem.displayName = "Stepper.Item";
3795
+ var StepperDescription = (props) => {
3796
+ const theme = useComponentTheme("StepperDescription");
3797
+ const { registerDescription } = useStepperItem("Stepper.Description");
3798
+ const { rootAttrs, rest } = composeRootAttrs(StepperDescriptionBase, props, theme);
3799
+ const { as, children, ref, id: idProp, ...nativeProps } = rest;
3800
+ const autoId = react.useId();
3801
+ const id = idProp ?? autoId;
3802
+ react.useEffect(() => registerDescription(id), [registerDescription, id]);
3803
+ const Component = as ?? "span";
3804
+ return (
3805
+ // Locked after the spread: the id must match the trigger's
3806
+ // `aria-describedby` registration, and `aria-hidden` keeps the description
3807
+ // out of the trigger's accessible NAME — it still reaches assistive
3808
+ // technology as the trigger's description, since `aria-describedby` may
3809
+ // reference hidden elements.
3810
+ /* @__PURE__ */ jsxRuntime.jsx(Component, { ...nativeProps, ...rootAttrs, ref, id, "aria-hidden": "true", children })
3811
+ );
3812
+ };
3813
+ StepperDescription.displayName = "Stepper.Description";
3814
+
3815
+ // src/components/stepper/index.ts
3816
+ var Stepper2 = Object.assign(Stepper, {
3817
+ Item: StepperItem,
3818
+ Title: StepperTitle,
3819
+ Description: StepperDescription
3820
+ });
3821
+
2526
3822
  // src/components/switch/base.ts
2527
3823
  var SwitchBase = createComponentBase({
2528
3824
  name: "Switch",
@@ -2540,12 +3836,12 @@ var SwitchBase = createComponentBase({
2540
3836
  var [SwitchProvider, useSwitchOwnContext] = createSafeContext("SwitchProvider");
2541
3837
 
2542
3838
  // src/components/switch/defaults.ts
2543
- var DEFAULT_SIZE11 = "base";
2544
- var DEFAULT_VARIANT7 = "info";
3839
+ var DEFAULT_SIZE15 = "base";
3840
+ var DEFAULT_VARIANT9 = "info";
2545
3841
  var Switch = (props) => {
2546
3842
  const theme = useComponentTheme("Switch");
2547
3843
  const { rootAttrs, rest } = composeRootAttrs(SwitchBase, props, theme, {
2548
- stateAttrs: ({ size = DEFAULT_SIZE11, variant = DEFAULT_VARIANT7 }) => ({
3844
+ stateAttrs: ({ size = DEFAULT_SIZE15, variant = DEFAULT_VARIANT9 }) => ({
2549
3845
  "data-size": size,
2550
3846
  "data-variant": variant
2551
3847
  })
@@ -2556,13 +3852,17 @@ var Switch = (props) => {
2556
3852
  // off the rendered DOM where they would leak as raw HTML attributes.
2557
3853
  size: _size,
2558
3854
  variant: _variant,
2559
- // `invalid` is forwarded to Spar as `invalid` (same name).
2560
- invalid = false,
2561
3855
  children,
2562
3856
  ref,
3857
+ // `invalid`, `disabled`, `readOnly` and `required` are intentionally NOT
3858
+ // destructured (so no eager `= false` default is applied) — they flow to
3859
+ // Spar via `...sparProps` untouched. Defaulting `invalid` here would turn
3860
+ // an omitted prop into an explicit `false`, defeating Spar's
3861
+ // `invalid ?? fieldCtx?.invalid` inheritance and silently overriding a
3862
+ // wrapping `<Field invalid>`. Mirrors the Radio/Input/Select pass-through.
2563
3863
  ...sparProps
2564
3864
  } = rest;
2565
- return /* @__PURE__ */ jsxRuntime.jsx(spar.Switch, { ...sparProps, invalid, ref, ...rootAttrs, children: (state) => /* @__PURE__ */ jsxRuntime.jsx(
3865
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.Switch, { ...sparProps, ref, ...rootAttrs, children: (state) => /* @__PURE__ */ jsxRuntime.jsx(
2566
3866
  SwitchProvider,
2567
3867
  {
2568
3868
  value: {
@@ -2668,7 +3968,7 @@ var TableBase = createComponentBase({
2668
3968
  var [TableProvider, useTableContext] = createSafeContext("Table");
2669
3969
 
2670
3970
  // src/components/table/defaults.ts
2671
- var DEFAULT_SIZE12 = "base";
3971
+ var DEFAULT_SIZE16 = "base";
2672
3972
  var DEFAULT_PAGE_SIZE = 10;
2673
3973
  var DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
2674
3974
  var DEFAULT_COLUMN_WIDTH = 150;
@@ -3194,7 +4494,7 @@ var Table = (props) => {
3194
4494
  // Visual vocabulary lives on the root so recipes cascade
3195
4495
  // to the portal-free table descendants. `data-loading` mirrors the
3196
4496
  // boolean-presence convention (rule 5).
3197
- stateAttrs: ({ size: size2 = DEFAULT_SIZE12, striped: striped2, bordered: bordered2, stickyHeader: stickyHeader2, loading: loading2 }) => ({
4497
+ stateAttrs: ({ size: size2 = DEFAULT_SIZE16, striped: striped2, bordered: bordered2, stickyHeader: stickyHeader2, loading: loading2 }) => ({
3198
4498
  "data-size": size2,
3199
4499
  "data-striped": striped2 ? "" : void 0,
3200
4500
  "data-bordered": bordered2 ? "" : void 0,
@@ -3208,7 +4508,7 @@ var Table = (props) => {
3208
4508
  getRowId,
3209
4509
  manual = false,
3210
4510
  loading = false,
3211
- size = DEFAULT_SIZE12,
4511
+ size = DEFAULT_SIZE16,
3212
4512
  striped = false,
3213
4513
  bordered = false,
3214
4514
  stickyHeader = false,
@@ -3408,19 +4708,19 @@ var TabsContentBase = createComponentBase({
3408
4708
  var [TabsOwnProvider, useTabsOwnContext] = createSafeContext("Tabs");
3409
4709
 
3410
4710
  // src/components/tabs/defaults.ts
3411
- var DEFAULT_SIZE13 = "base";
3412
- var DEFAULT_VARIANT8 = "primary";
3413
- var DEFAULT_APPEARANCE6 = "basic";
4711
+ var DEFAULT_SIZE17 = "base";
4712
+ var DEFAULT_VARIANT10 = "primary";
4713
+ var DEFAULT_APPEARANCE8 = "basic";
3414
4714
  var Tabs = (props) => {
3415
4715
  const theme = useComponentTheme("Tabs");
3416
4716
  const { rootAttrs, rest } = composeRootAttrs(TabsBase, props, theme, {
3417
- stateAttrs: ({ size: size2 = DEFAULT_SIZE13, variant: variant2 = DEFAULT_VARIANT8, appearance: appearance2 = DEFAULT_APPEARANCE6 }) => ({
4717
+ stateAttrs: ({ size: size2 = DEFAULT_SIZE17, variant: variant2 = DEFAULT_VARIANT10, appearance: appearance2 = DEFAULT_APPEARANCE8 }) => ({
3418
4718
  "data-size": size2,
3419
4719
  "data-variant": variant2,
3420
4720
  "data-type": appearance2
3421
4721
  })
3422
4722
  });
3423
- const { size = DEFAULT_SIZE13, variant = DEFAULT_VARIANT8, appearance = DEFAULT_APPEARANCE6, children, ref, ...sparProps } = rest;
4723
+ const { size = DEFAULT_SIZE17, variant = DEFAULT_VARIANT10, appearance = DEFAULT_APPEARANCE8, children, ref, ...sparProps } = rest;
3424
4724
  return /* @__PURE__ */ jsxRuntime.jsx(TabsOwnProvider, { value: { size, variant, appearance }, children: /* @__PURE__ */ jsxRuntime.jsx(spar.Tabs, { ...sparProps, ...rootAttrs, ref, children }) });
3425
4725
  };
3426
4726
  Tabs.displayName = "Tabs";
@@ -3520,11 +4820,11 @@ var TooltipTrigger = (props) => {
3520
4820
  TooltipTrigger.displayName = "Tooltip.Trigger";
3521
4821
 
3522
4822
  // src/components/tooltip/defaults.ts
3523
- var DEFAULT_VARIANT9 = "white";
4823
+ var DEFAULT_VARIANT11 = "white";
3524
4824
  var TooltipContent = (props) => {
3525
4825
  const theme = useComponentTheme("TooltipContent");
3526
4826
  const { rootAttrs, rest } = composeRootAttrs(TooltipContentBase, props, theme, {
3527
- stateAttrs: ({ variant = DEFAULT_VARIANT9 }) => ({
4827
+ stateAttrs: ({ variant = DEFAULT_VARIANT11 }) => ({
3528
4828
  "data-variant": variant
3529
4829
  })
3530
4830
  });
@@ -3549,8 +4849,8 @@ TooltipDescription.displayName = "Tooltip.Description";
3549
4849
  var TooltipArrow = (props) => {
3550
4850
  const theme = useComponentTheme("TooltipArrow");
3551
4851
  const { rootAttrs, rest } = composeRootAttrs(TooltipArrowBase, props, theme);
3552
- const { ref, ...sparProps } = rest;
3553
- return /* @__PURE__ */ jsxRuntime.jsx(spar.TooltipArrow, { ...sparProps, ...rootAttrs, ref });
4852
+ const { ref, children, ...sparProps } = rest;
4853
+ return /* @__PURE__ */ jsxRuntime.jsx(spar.TooltipArrow, { ...sparProps, ...rootAttrs, ref, children: children ?? renderPointerArrow() });
3554
4854
  };
3555
4855
  TooltipArrow.displayName = "Tooltip.Arrow";
3556
4856
 
@@ -3634,6 +4934,44 @@ var Toaster = (props) => {
3634
4934
  };
3635
4935
  Toaster.displayName = "Toaster";
3636
4936
 
4937
+ // src/components/skeleton/base.ts
4938
+ var SkeletonBase = createComponentBase({
4939
+ name: "Skeleton",
4940
+ slots: ["root", "shimmer"],
4941
+ classes: {
4942
+ root: "tk-skeleton",
4943
+ shimmer: "tk-skeleton-shimmer"
4944
+ }
4945
+ });
4946
+
4947
+ // src/components/skeleton/defaults.ts
4948
+ var DEFAULT_SHAPE = "rectangle";
4949
+ var DEFAULT_ANIMATION = "shimmer";
4950
+ var toCssSize = (value) => typeof value === "number" ? `${value}px` : value;
4951
+ var Skeleton = (props) => {
4952
+ const theme = useComponentTheme("Skeleton");
4953
+ const { rootAttrs, rest } = composeRootAttrs(SkeletonBase, props, theme, {
4954
+ stateAttrs: ({ shape = DEFAULT_SHAPE, animation = DEFAULT_ANIMATION }) => ({
4955
+ "data-type": shape,
4956
+ "data-animation": animation
4957
+ })
4958
+ });
4959
+ const { shape: _shape, animation: _animation, width, height, ref, style, ...nativeProps } = rest;
4960
+ const { style: slotStyle, ...slotAttrs } = rootAttrs;
4961
+ const shimmerSlotAttrs = buildSlotAttrs(SkeletonBase.getSlotProps("shimmer"), "shimmer", {
4962
+ themeSlotProps: theme?.slotProps,
4963
+ themeClassNames: theme?.classNames,
4964
+ instanceSlotProps: props.slotProps,
4965
+ instanceClassNames: props.classNames
4966
+ });
4967
+ const sizeVars = {
4968
+ ...width !== void 0 && { "--tk-skeleton-width": toCssSize(width) },
4969
+ ...height !== void 0 && { "--tk-skeleton-height": toCssSize(height) }
4970
+ };
4971
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", ...nativeProps, ...slotAttrs, style: { ...style, ...slotStyle, ...sizeVars }, ref, children: /* @__PURE__ */ jsxRuntime.jsx("span", { ...shimmerSlotAttrs, "aria-hidden": "true" }) });
4972
+ };
4973
+ Skeleton.displayName = "Skeleton";
4974
+
3637
4975
  Object.defineProperty(exports, "createToaster", {
3638
4976
  enumerable: true,
3639
4977
  get: function () { return spar.createToaster; }
@@ -3647,14 +4985,20 @@ exports.Card = Card2;
3647
4985
  exports.Checkbox = Checkbox2;
3648
4986
  exports.Chip = Chip;
3649
4987
  exports.Dialog = Dialog2;
4988
+ exports.Divider = Divider;
3650
4989
  exports.Drawer = Drawer2;
4990
+ exports.Dropdown = Dropdown2;
3651
4991
  exports.Field = Field2;
3652
4992
  exports.Input = Input2;
3653
4993
  exports.Label = Label;
3654
4994
  exports.Popover = Popover2;
4995
+ exports.Progress = Progress2;
3655
4996
  exports.Radio = Radio2;
3656
4997
  exports.Select = Select2;
4998
+ exports.Skeleton = Skeleton;
4999
+ exports.Slider = Slider2;
3657
5000
  exports.Spinner = Spinner;
5001
+ exports.Stepper = Stepper2;
3658
5002
  exports.Switch = Switch2;
3659
5003
  exports.Table = Table;
3660
5004
  exports.Tabs = Tabs2;