@tinybigui/react 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6555,7 +6555,6 @@ var snackbarBaseVariants = cva(
6555
6555
  "min-w-72",
6556
6556
  "max-w-snackbar-max",
6557
6557
  "w-max",
6558
- "min-h-12",
6559
6558
  // Restore pointer events so hover/focus timer pause works
6560
6559
  "pointer-events-auto",
6561
6560
  // Surface
@@ -6566,25 +6565,27 @@ var snackbarBaseVariants = cva(
6566
6565
  "shadow-elevation-3",
6567
6566
  // Layout
6568
6567
  "flex",
6569
- "items-center",
6570
6568
  "gap-x-1",
6571
- "pl-4 pr-2",
6572
- // Typography
6569
+ "pl-4",
6570
+ // Typography base (inherited by message/supporting-text slots)
6573
6571
  "text-body-medium",
6574
6572
  "text-inverse-on-surface",
6575
- // Transition (properties used by both entry and exit)
6573
+ // Slide + fade transition spring-standard effects tokens (no overshoot).
6574
+ // The translate offset is small (12px), so using the effects token pair for
6575
+ // BOTH opacity AND transform is safe: no visible overshoot at this scale.
6576
6576
  "transition-[opacity,transform]",
6577
6577
  "will-change-[opacity,transform]"
6578
6578
  ],
6579
6579
  {
6580
6580
  variants: {
6581
6581
  /**
6582
- * Whether the Snackbar has supporting text (two-line layout).
6583
- * Adjusts vertical padding to MD3 spec for two-line configuration.
6582
+ * Two-line density mode.
6583
+ * false 48dp, items centered (single-line message)
6584
+ * true — 68dp, items top-aligned (message + supporting text)
6584
6585
  */
6585
6586
  twoLine: {
6586
- true: "py-1",
6587
- false: "py-1"
6587
+ false: ["min-h-12", "items-center", "pr-1"],
6588
+ true: ["min-h-[4.25rem]", "items-start", "pr-1"]
6588
6589
  }
6589
6590
  },
6590
6591
  defaultVariants: {
@@ -6610,53 +6611,211 @@ cva("", {
6610
6611
  var snackbarAnimationVariants = cva("", {
6611
6612
  variants: {
6612
6613
  animationState: {
6613
- entering: ["opacity-0", "scale-75"],
6614
- visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
6615
- exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
6616
- exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
6614
+ entering: [],
6615
+ visible: [],
6616
+ exiting: [],
6617
+ exited: []
6617
6618
  },
6618
6619
  enterDirection: {
6619
- up: ["origin-bottom"],
6620
- down: ["origin-top"]
6620
+ up: [],
6621
+ down: []
6621
6622
  }
6622
6623
  },
6623
- defaultVariants: {
6624
- animationState: "entering",
6625
- enterDirection: "up"
6626
- }
6627
- });
6628
- cva([...snackbarBaseVariants()], {
6629
- variants: {
6630
- animationState: {
6631
- entering: ["opacity-0", "scale-75"],
6632
- visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
6633
- exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
6634
- exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
6624
+ compoundVariants: [
6625
+ // ── entering ──────────────────────────────────────────────────────────────
6626
+ // No transition duration — instant jump to offset state before first paint.
6627
+ {
6628
+ animationState: "entering",
6629
+ enterDirection: "up",
6630
+ className: ["opacity-0", "translate-y-3"]
6635
6631
  },
6636
- enterDirection: {
6637
- up: ["origin-bottom"],
6638
- down: ["origin-top"]
6632
+ {
6633
+ animationState: "entering",
6634
+ enterDirection: "down",
6635
+ className: ["opacity-0", "-translate-y-3"]
6639
6636
  },
6640
- position: {
6641
- "bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
6642
- "bottom-left": ["bottom-4", "left-4"],
6643
- "bottom-right": ["bottom-4", "right-4"],
6644
- "top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
6645
- "top-left": ["top-4", "left-4"],
6646
- "top-right": ["top-4", "right-4"]
6637
+ // ── visible ───────────────────────────────────────────────────────────────
6638
+ // spring-standard default effects = 200ms, no overshoot.
6639
+ {
6640
+ animationState: "visible",
6641
+ enterDirection: "up",
6642
+ className: [
6643
+ "opacity-100",
6644
+ "translate-y-0",
6645
+ "duration-spring-standard-default-effects",
6646
+ "ease-spring-standard-default-effects"
6647
+ ]
6648
+ },
6649
+ {
6650
+ animationState: "visible",
6651
+ enterDirection: "down",
6652
+ className: [
6653
+ "opacity-100",
6654
+ "translate-y-0",
6655
+ "duration-spring-standard-default-effects",
6656
+ "ease-spring-standard-default-effects"
6657
+ ]
6658
+ },
6659
+ // ── exiting ───────────────────────────────────────────────────────────────
6660
+ // spring-standard fast effects = 150ms (quicker exit).
6661
+ {
6662
+ animationState: "exiting",
6663
+ enterDirection: "up",
6664
+ className: [
6665
+ "opacity-0",
6666
+ "translate-y-3",
6667
+ "duration-spring-standard-fast-effects",
6668
+ "ease-spring-standard-fast-effects"
6669
+ ]
6670
+ },
6671
+ {
6672
+ animationState: "exiting",
6673
+ enterDirection: "down",
6674
+ className: [
6675
+ "opacity-0",
6676
+ "-translate-y-3",
6677
+ "duration-spring-standard-fast-effects",
6678
+ "ease-spring-standard-fast-effects"
6679
+ ]
6680
+ },
6681
+ // ── exited ────────────────────────────────────────────────────────────────
6682
+ // Hold final position — element is removed from DOM shortly after.
6683
+ {
6684
+ animationState: "exited",
6685
+ enterDirection: "up",
6686
+ className: ["opacity-0", "translate-y-3"]
6647
6687
  },
6648
- twoLine: {
6649
- true: "py-1",
6650
- false: "py-1"
6688
+ {
6689
+ animationState: "exited",
6690
+ enterDirection: "down",
6691
+ className: ["opacity-0", "-translate-y-3"]
6651
6692
  }
6652
- },
6693
+ ],
6653
6694
  defaultVariants: {
6654
6695
  animationState: "entering",
6655
- enterDirection: "up",
6656
- position: "bottom-center",
6657
- twoLine: false
6696
+ enterDirection: "up"
6658
6697
  }
6659
6698
  });
6699
+ cva(
6700
+ [
6701
+ "min-w-72",
6702
+ "max-w-snackbar-max",
6703
+ "w-max",
6704
+ "pointer-events-auto",
6705
+ "bg-inverse-surface",
6706
+ "rounded-xs",
6707
+ "shadow-elevation-3",
6708
+ "flex",
6709
+ "gap-x-1",
6710
+ "pl-4",
6711
+ "text-body-medium",
6712
+ "text-inverse-on-surface",
6713
+ "transition-[opacity,transform]",
6714
+ "will-change-[opacity,transform]"
6715
+ ],
6716
+ {
6717
+ variants: {
6718
+ twoLine: {
6719
+ false: ["min-h-12", "items-center", "pr-1"],
6720
+ true: ["min-h-[4.25rem]", "items-start", "pr-1"]
6721
+ },
6722
+ animationState: {
6723
+ entering: [],
6724
+ visible: [],
6725
+ exiting: [],
6726
+ exited: []
6727
+ },
6728
+ enterDirection: {
6729
+ up: [],
6730
+ down: []
6731
+ },
6732
+ position: {
6733
+ "bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
6734
+ "bottom-left": ["bottom-4", "left-4"],
6735
+ "bottom-right": ["bottom-4", "right-4"],
6736
+ "top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
6737
+ "top-left": ["top-4", "left-4"],
6738
+ "top-right": ["top-4", "right-4"]
6739
+ }
6740
+ },
6741
+ compoundVariants: [
6742
+ {
6743
+ animationState: "entering",
6744
+ enterDirection: "up",
6745
+ className: ["opacity-0", "translate-y-3"]
6746
+ },
6747
+ {
6748
+ animationState: "entering",
6749
+ enterDirection: "down",
6750
+ className: ["opacity-0", "-translate-y-3"]
6751
+ },
6752
+ {
6753
+ animationState: "visible",
6754
+ enterDirection: "up",
6755
+ className: [
6756
+ "opacity-100",
6757
+ "translate-y-0",
6758
+ "duration-spring-standard-default-effects",
6759
+ "ease-spring-standard-default-effects"
6760
+ ]
6761
+ },
6762
+ {
6763
+ animationState: "visible",
6764
+ enterDirection: "down",
6765
+ className: [
6766
+ "opacity-100",
6767
+ "translate-y-0",
6768
+ "duration-spring-standard-default-effects",
6769
+ "ease-spring-standard-default-effects"
6770
+ ]
6771
+ },
6772
+ {
6773
+ animationState: "exiting",
6774
+ enterDirection: "up",
6775
+ className: [
6776
+ "opacity-0",
6777
+ "translate-y-3",
6778
+ "duration-spring-standard-fast-effects",
6779
+ "ease-spring-standard-fast-effects"
6780
+ ]
6781
+ },
6782
+ {
6783
+ animationState: "exiting",
6784
+ enterDirection: "down",
6785
+ className: [
6786
+ "opacity-0",
6787
+ "-translate-y-3",
6788
+ "duration-spring-standard-fast-effects",
6789
+ "ease-spring-standard-fast-effects"
6790
+ ]
6791
+ },
6792
+ {
6793
+ animationState: "exited",
6794
+ enterDirection: "up",
6795
+ className: ["opacity-0", "translate-y-3"]
6796
+ },
6797
+ {
6798
+ animationState: "exited",
6799
+ enterDirection: "down",
6800
+ className: ["opacity-0", "-translate-y-3"]
6801
+ }
6802
+ ],
6803
+ defaultVariants: {
6804
+ animationState: "entering",
6805
+ enterDirection: "up",
6806
+ position: "bottom-center",
6807
+ twoLine: false
6808
+ }
6809
+ }
6810
+ );
6811
+ var snackbarContentVariants = cva([
6812
+ "flex",
6813
+ "flex-col",
6814
+ "flex-1",
6815
+ "min-w-0",
6816
+ "py-3",
6817
+ "pr-2"
6818
+ ]);
6660
6819
  var snackbarMessageVariants = cva([
6661
6820
  "flex-1",
6662
6821
  "text-body-medium",
@@ -6665,15 +6824,83 @@ var snackbarMessageVariants = cva([
6665
6824
  var snackbarSupportingTextVariants = cva([
6666
6825
  "text-body-medium",
6667
6826
  "text-inverse-on-surface",
6668
- "opacity-80"
6827
+ "mt-1"
6669
6828
  ]);
6670
- var snackbarActionVariants = cva(["shrink-0", "text-inverse-primary"]);
6671
- var snackbarCloseVariants = cva(["shrink-0", "text-inverse-on-surface"]);
6672
- var snackbarContentVariants = cva(["flex", "flex-col", "flex-1", "min-w-0 py-2 pr-2"]);
6673
- cva(["scale-75", "opacity-0"]);
6829
+ cva(["opacity-0"]);
6674
6830
  function getEnterDirection(position) {
6675
6831
  return position.startsWith("top") ? "down" : "up";
6676
6832
  }
6833
+ var snackbarActionVariants = cva([
6834
+ // Layout
6835
+ "relative inline-flex items-center justify-center shrink-0",
6836
+ "h-9 px-3",
6837
+ "rounded-full cursor-pointer select-none",
6838
+ // Typography (MD3 text button: label-large)
6839
+ "text-label-large",
6840
+ "text-inverse-primary",
6841
+ // Effects transition (color)
6842
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6843
+ // Disabled
6844
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
6845
+ "data-[disabled]:text-on-surface/38"
6846
+ ]);
6847
+ var snackbarActionStateLayerVariants = cva([
6848
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
6849
+ "bg-inverse-primary",
6850
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6851
+ // Hover: 8%
6852
+ "group-data-[hovered]/snackbar-action:opacity-8",
6853
+ // Focus: 10%
6854
+ "group-data-[focus-visible]/snackbar-action:opacity-10",
6855
+ // Pressed: 10%, doubled selector wins over hover
6856
+ "group-data-[pressed]/snackbar-action:group-data-[pressed]/snackbar-action:opacity-10",
6857
+ // No state layer when disabled
6858
+ "group-data-[disabled]/snackbar-action:hidden"
6859
+ ]);
6860
+ var snackbarActionFocusRingVariants = cva([
6861
+ "pointer-events-none absolute inset-[-3px] rounded-full",
6862
+ "outline outline-2 outline-offset-0 outline-inverse-primary",
6863
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6864
+ "opacity-0",
6865
+ "group-data-[focus-visible]/snackbar-action:opacity-100"
6866
+ ]);
6867
+ var snackbarCloseVariants = cva([
6868
+ // Layout
6869
+ "relative inline-flex items-center justify-center shrink-0",
6870
+ "size-8",
6871
+ "rounded-full cursor-pointer select-none",
6872
+ // Color
6873
+ "text-inverse-on-surface",
6874
+ // Effects transition (color)
6875
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6876
+ // Disabled
6877
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
6878
+ "data-[disabled]:text-on-surface/38"
6879
+ ]);
6880
+ var snackbarCloseStateLayerVariants = cva([
6881
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
6882
+ "bg-inverse-on-surface",
6883
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6884
+ // Hover: 8%
6885
+ "group-data-[hovered]/snackbar-close:opacity-8",
6886
+ // Focus: 10%
6887
+ "group-data-[focus-visible]/snackbar-close:opacity-10",
6888
+ // Pressed: 10%, doubled selector wins over hover
6889
+ "group-data-[pressed]/snackbar-close:group-data-[pressed]/snackbar-close:opacity-10",
6890
+ // No state layer when disabled
6891
+ "group-data-[disabled]/snackbar-close:hidden"
6892
+ ]);
6893
+ var snackbarCloseFocusRingVariants = cva([
6894
+ "pointer-events-none absolute inset-[-3px] rounded-full",
6895
+ "outline outline-2 outline-offset-0 outline-inverse-on-surface",
6896
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6897
+ "opacity-0",
6898
+ "group-data-[focus-visible]/snackbar-close:opacity-100"
6899
+ ]);
6900
+ var snackbarCloseIconVariants = cva([
6901
+ "relative z-10 inline-flex shrink-0 items-center justify-center",
6902
+ "size-6"
6903
+ ]);
6677
6904
  function CloseIcon() {
6678
6905
  return /* @__PURE__ */ jsx(
6679
6906
  "svg",
@@ -6688,6 +6915,52 @@ function CloseIcon() {
6688
6915
  }
6689
6916
  );
6690
6917
  }
6918
+ function SnackbarActionButton({ label, onAction }) {
6919
+ const ref = useRef(null);
6920
+ const { buttonProps, isPressed } = useButton({ onPress: onAction }, ref);
6921
+ const { isHovered, hoverProps } = useHover({});
6922
+ const { isFocusVisible, focusProps } = useFocusRing();
6923
+ const { onMouseDown, ripples } = useRipple();
6924
+ return /* @__PURE__ */ jsxs(
6925
+ "button",
6926
+ {
6927
+ type: "button",
6928
+ ...mergeProps$1(buttonProps, hoverProps, focusProps, { onMouseDown }),
6929
+ ref,
6930
+ className: cn(snackbarActionVariants(), "group/snackbar-action"),
6931
+ ...getInteractionDataAttributes({ isHovered, isFocusVisible, isPressed }),
6932
+ children: [
6933
+ ripples,
6934
+ /* @__PURE__ */ jsx("span", { className: snackbarActionStateLayerVariants(), "aria-hidden": "true" }),
6935
+ /* @__PURE__ */ jsx("span", { className: snackbarActionFocusRingVariants(), "aria-hidden": "true" }),
6936
+ /* @__PURE__ */ jsx("span", { className: "relative z-10", children: label })
6937
+ ]
6938
+ }
6939
+ );
6940
+ }
6941
+ function SnackbarCloseButton({ onPress }) {
6942
+ const ref = useRef(null);
6943
+ const { buttonProps, isPressed } = useButton({ onPress, "aria-label": "Close" }, ref);
6944
+ const { isHovered, hoverProps } = useHover({});
6945
+ const { isFocusVisible, focusProps } = useFocusRing();
6946
+ const { onMouseDown, ripples } = useRipple();
6947
+ return /* @__PURE__ */ jsxs(
6948
+ "button",
6949
+ {
6950
+ type: "button",
6951
+ ...mergeProps$1(buttonProps, hoverProps, focusProps, { onMouseDown }),
6952
+ ref,
6953
+ className: cn(snackbarCloseVariants(), "group/snackbar-close"),
6954
+ ...getInteractionDataAttributes({ isHovered, isFocusVisible, isPressed }),
6955
+ children: [
6956
+ ripples,
6957
+ /* @__PURE__ */ jsx("span", { className: snackbarCloseStateLayerVariants(), "aria-hidden": "true" }),
6958
+ /* @__PURE__ */ jsx("span", { className: snackbarCloseFocusRingVariants(), "aria-hidden": "true" }),
6959
+ /* @__PURE__ */ jsx("span", { className: snackbarCloseIconVariants(), "aria-hidden": "true", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
6960
+ ]
6961
+ }
6962
+ );
6963
+ }
6691
6964
  var Snackbar = forwardRef(function Snackbar2({
6692
6965
  message,
6693
6966
  supportingText,
@@ -6700,6 +6973,7 @@ var Snackbar = forwardRef(function Snackbar2({
6700
6973
  className
6701
6974
  }, ref) {
6702
6975
  const isTwoLine = Boolean(supportingText);
6976
+ const reducedMotion = useReducedMotion();
6703
6977
  const baseClassName = cn(snackbarBaseVariants({ twoLine: isTwoLine }), className);
6704
6978
  return /* @__PURE__ */ jsx(
6705
6979
  SnackbarHeadless,
@@ -6714,31 +6988,22 @@ var Snackbar = forwardRef(function Snackbar2({
6714
6988
  position,
6715
6989
  ...onClose !== void 0 && { onClose },
6716
6990
  className: baseClassName,
6717
- getAnimationClassName: (state, pos) => snackbarAnimationVariants({ animationState: state, enterDirection: getEnterDirection(pos) }),
6991
+ getAnimationClassName: (state, pos) => {
6992
+ if (reducedMotion) {
6993
+ return state === "visible" ? "opacity-100 duration-spring-standard-default-effects ease-spring-standard-default-effects" : "opacity-0";
6994
+ }
6995
+ return snackbarAnimationVariants({
6996
+ animationState: state,
6997
+ enterDirection: getEnterDirection(pos)
6998
+ });
6999
+ },
6718
7000
  children: ({ onClose: triggerClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [
6719
7001
  /* @__PURE__ */ jsxs("div", { className: snackbarContentVariants(), children: [
6720
7002
  /* @__PURE__ */ jsx("span", { className: snackbarMessageVariants(), children: message }),
6721
7003
  supportingText && /* @__PURE__ */ jsx("span", { className: snackbarSupportingTextVariants(), children: supportingText })
6722
7004
  ] }),
6723
- action && /* @__PURE__ */ jsx("span", { className: snackbarActionVariants(), children: /* @__PURE__ */ jsx(
6724
- Button,
6725
- {
6726
- variant: "text",
6727
- onPress: action.onAction,
6728
- className: "text-inverse-primary hover:text-inverse-primary px-3",
6729
- children: action.label
6730
- }
6731
- ) }),
6732
- showClose && /* @__PURE__ */ jsx("span", { className: snackbarCloseVariants(), children: /* @__PURE__ */ jsx(
6733
- IconButton,
6734
- {
6735
- variant: "standard",
6736
- "aria-label": "Close",
6737
- onPress: triggerClose,
6738
- className: "text-inverse-on-surface hover:text-inverse-on-surface",
6739
- children: /* @__PURE__ */ jsx(CloseIcon, {})
6740
- }
6741
- ) })
7005
+ action && /* @__PURE__ */ jsx(SnackbarActionButton, { label: action.label, onAction: action.onAction }),
7006
+ showClose && /* @__PURE__ */ jsx(SnackbarCloseButton, { onPress: triggerClose })
6742
7007
  ] })
6743
7008
  }
6744
7009
  );
@@ -10409,9 +10674,12 @@ function SliderThumbInternal({
10409
10674
  state,
10410
10675
  trackRef,
10411
10676
  isDisabled,
10677
+ orientation,
10412
10678
  formatValue: formatValue2,
10413
10679
  className,
10414
10680
  "data-direction": dataDirection,
10681
+ renderContent,
10682
+ onDraggingChange,
10415
10683
  ...ariaProps
10416
10684
  }) {
10417
10685
  const inputRef = useRef(null);
@@ -10426,33 +10694,70 @@ function SliderThumbInternal({
10426
10694
  state
10427
10695
  );
10428
10696
  const { isFocusVisible, focusProps } = useFocusRing();
10697
+ const { isHovered, hoverProps } = useHover({ isDisabled });
10698
+ useEffect(() => {
10699
+ onDraggingChange?.(isDragging);
10700
+ }, [isDragging, onDraggingChange]);
10429
10701
  const currentValue = state.getThumbValue(index);
10430
10702
  const ariaValueText = formatValue2 ? formatValue2(currentValue) : void 0;
10431
- return /* @__PURE__ */ jsx(
10703
+ const thumbPercent = state.getThumbPercent(index);
10704
+ const positionStyle = orientation === "horizontal" ? {
10705
+ position: "absolute",
10706
+ left: `${thumbPercent * 100}%`,
10707
+ top: "50%",
10708
+ transform: "translate(-50%, -50%)",
10709
+ zIndex: 10
10710
+ } : {
10711
+ position: "absolute",
10712
+ bottom: `${thumbPercent * 100}%`,
10713
+ left: "50%",
10714
+ transform: "translate(-50%, 50%)",
10715
+ zIndex: 10
10716
+ };
10717
+ const renderState = {
10718
+ index,
10719
+ value: currentValue,
10720
+ isDragging,
10721
+ isFocusVisible,
10722
+ isHovered,
10723
+ isDisabled
10724
+ };
10725
+ return /* @__PURE__ */ jsxs(
10432
10726
  "div",
10433
10727
  {
10434
- ...thumbProps,
10728
+ ...mergeProps$1(thumbProps, hoverProps, { style: positionStyle }),
10729
+ "data-slot": "slider-thumb",
10435
10730
  "data-dragging": isDragging || void 0,
10436
10731
  "data-focused": isFocused || void 0,
10437
- "data-focus-visible": isFocusVisible || void 0,
10438
- "data-disabled": isDisabled || void 0,
10439
10732
  ...dataDirection !== void 0 ? { "data-direction": dataDirection } : {},
10733
+ ...getInteractionDataAttributes({
10734
+ isHovered,
10735
+ isFocusVisible,
10736
+ isPressed: isDragging,
10737
+ isDisabled
10738
+ }),
10440
10739
  className: cn(
10740
+ // Group scope: interaction selectors on children target this element
10741
+ "group/slider-thumb",
10742
+ // Accessibility: remove default outline (custom focus ring via data-[focus-visible])
10441
10743
  "outline-none",
10442
- // Focus ring visible only on keyboard focus — matches project pattern (md3-design.mdc §Accessibility)
10744
+ // Focus ring visible only on keyboard focus — matches project pattern
10443
10745
  "data-[focus-visible]:ring-3",
10444
10746
  "data-[focus-visible]:ring-secondary",
10445
10747
  "data-[focus-visible]:ring-offset-2",
10446
10748
  className
10447
10749
  ),
10448
- children: /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(
10449
- "input",
10450
- {
10451
- ref: inputRef,
10452
- ...mergeProps$1(inputProps, focusProps),
10453
- ...ariaValueText !== void 0 ? { "aria-valuetext": ariaValueText } : {}
10454
- }
10455
- ) })
10750
+ children: [
10751
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(
10752
+ "input",
10753
+ {
10754
+ ref: inputRef,
10755
+ ...mergeProps$1(inputProps, focusProps),
10756
+ ...ariaValueText !== void 0 ? { "aria-valuetext": ariaValueText } : {}
10757
+ }
10758
+ ) }),
10759
+ renderContent?.(renderState)
10760
+ ]
10456
10761
  }
10457
10762
  );
10458
10763
  }
@@ -10475,6 +10780,9 @@ var SliderHeadless = forwardRef(
10475
10780
  className,
10476
10781
  style,
10477
10782
  children,
10783
+ trackClassName,
10784
+ renderThumbContent,
10785
+ onThumbDraggingChange,
10478
10786
  ...ariaProps
10479
10787
  } = props;
10480
10788
  const trackRef = useRef(null);
@@ -10536,7 +10844,18 @@ var SliderHeadless = forwardRef(
10536
10844
  "data-variant": variant,
10537
10845
  ...zeroPercent !== void 0 ? { "data-zero-percent": zeroPercent } : {},
10538
10846
  children: [
10539
- label && /* @__PURE__ */ jsx("label", { ...labelProps, children: label }),
10847
+ label && /* @__PURE__ */ jsx("label", { ...labelProps, className: cn(orientation === "vertical" && "sr-only"), children: label }),
10848
+ /* @__PURE__ */ jsx(
10849
+ "output",
10850
+ {
10851
+ ...outputProps,
10852
+ className: cn(
10853
+ orientation === "horizontal" && "justify-self-end",
10854
+ orientation === "vertical" && "sr-only"
10855
+ ),
10856
+ children: isRange ? formatValue2 ? `${formatValue2(state.getThumbValue(0))} \u2013 ${formatValue2(state.getThumbValue(1))}` : `${state.getThumbValueLabel(0)} \u2013 ${state.getThumbValueLabel(1)}` : formatValue2 ? formatValue2(state.getThumbValue(0)) : state.getThumbValueLabel(0)
10857
+ }
10858
+ ),
10540
10859
  /* @__PURE__ */ jsxs(
10541
10860
  "div",
10542
10861
  {
@@ -10545,6 +10864,10 @@ var SliderHeadless = forwardRef(
10545
10864
  "data-orientation": orientation,
10546
10865
  "data-track": true,
10547
10866
  ...zeroPercent !== void 0 ? { "data-zero-percent": zeroPercent } : {},
10867
+ className: cn(
10868
+ trackClassName ?? "relative w-full",
10869
+ orientation === "vertical" && !trackClassName && "h-full"
10870
+ ),
10548
10871
  children: [
10549
10872
  children,
10550
10873
  /* @__PURE__ */ jsx(
@@ -10554,9 +10877,12 @@ var SliderHeadless = forwardRef(
10554
10877
  state,
10555
10878
  trackRef,
10556
10879
  isDisabled,
10880
+ orientation,
10557
10881
  ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {},
10558
10882
  ...thumb0Label !== void 0 ? { "aria-label": thumb0Label } : {},
10559
- ...direction !== void 0 ? { "data-direction": direction } : {}
10883
+ ...direction !== void 0 ? { "data-direction": direction } : {},
10884
+ ...renderThumbContent !== void 0 ? { renderContent: renderThumbContent } : {},
10885
+ ...onThumbDraggingChange !== void 0 ? { onDraggingChange: (d) => onThumbDraggingChange(0, d) } : {}
10560
10886
  }
10561
10887
  ),
10562
10888
  isRange && /* @__PURE__ */ jsx(
@@ -10566,144 +10892,174 @@ var SliderHeadless = forwardRef(
10566
10892
  state,
10567
10893
  trackRef,
10568
10894
  isDisabled,
10895
+ orientation,
10569
10896
  ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {},
10570
- "aria-label": thumbLabels?.[1] ?? "Maximum"
10897
+ "aria-label": thumbLabels?.[1] ?? "Maximum",
10898
+ ...renderThumbContent !== void 0 ? { renderContent: renderThumbContent } : {},
10899
+ ...onThumbDraggingChange !== void 0 ? { onDraggingChange: (d) => onThumbDraggingChange(1, d) } : {}
10571
10900
  }
10572
10901
  )
10573
10902
  ]
10574
10903
  }
10575
- ),
10576
- /* @__PURE__ */ jsx("output", { ...outputProps, children: isRange ? formatValue2 ? `${formatValue2(state.getThumbValue(0))} \u2013 ${formatValue2(state.getThumbValue(1))}` : `${state.getThumbValueLabel(0)} \u2013 ${state.getThumbValueLabel(1)}` : formatValue2 ? formatValue2(state.getThumbValue(0)) : state.getThumbValueLabel(0) })
10904
+ )
10577
10905
  ]
10578
10906
  }
10579
10907
  );
10580
10908
  }
10581
10909
  );
10582
10910
  SliderHeadless.displayName = "SliderHeadless";
10583
- var sliderContainerVariants = cva(
10584
- [
10585
- "relative",
10586
- "flex",
10587
- "items-center",
10588
- "w-full",
10589
- "touch-none",
10590
- // NOTE: measurement-derived value from MD3 spec; permitted exception — prevents browser scroll on drag
10591
- "select-none"
10592
- ],
10593
- {
10594
- variants: {
10595
- size: {
10596
- // NOTE: measurement-derived values from MD3 spec §4.2; permitted exception
10597
- xsmall: "h-[44px]",
10598
- small: "h-[44px]",
10599
- medium: "h-[52px]",
10600
- large: "h-[68px]",
10601
- xlarge: "h-[108px]"
10602
- },
10603
- orientation: {
10604
- // Horizontal: w-full already in base; flex-row is default flex direction
10605
- horizontal: "",
10606
- // Vertical: transposed — container height fills parent, width = handle height (per size)
10607
- // flex-col stacks label → track → output vertically
10608
- // NOTE: h-full requires a parent with defined height; w-[...] set via compound variants
10609
- vertical: "h-full flex-col"
10610
- },
10611
- disabled: {
10612
- true: "cursor-not-allowed pointer-events-none",
10613
- false: "cursor-pointer"
10614
- }
10615
- },
10616
- compoundVariants: [
10617
- // Vertical: container WIDTH = handle height (MD3 §10.9 — dimensions transposed)
10618
- // Overrides w-full from base via tailwind-merge in cn()
10911
+ var sliderContainerVariants = cva(["group/slider", "relative", "select-none"], {
10912
+ variants: {
10913
+ orientation: {
10914
+ // Grid: 1fr for label, auto for output value; gap-x for label↔output spacing
10915
+ horizontal: "grid grid-cols-[1fr_auto] items-center gap-x-2 w-full",
10916
+ // Flex column: label → track → output stacked; width = handle height (per size)
10917
+ vertical: "flex flex-col items-center h-full"
10918
+ },
10919
+ size: {
10920
+ // Vertical orientation: container width = handle height (dimensions transposed)
10921
+ // Applied only for vertical via compoundVariants below
10619
10922
  // NOTE: measurement-derived values from MD3 spec §4.2; permitted exception
10620
- { orientation: "vertical", size: "xsmall", className: "w-[44px]" },
10621
- { orientation: "vertical", size: "small", className: "w-[44px]" },
10622
- { orientation: "vertical", size: "medium", className: "w-[52px]" },
10623
- { orientation: "vertical", size: "large", className: "w-[68px]" },
10624
- { orientation: "vertical", size: "xlarge", className: "w-[108px]" }
10625
- ],
10626
- defaultVariants: {
10627
- size: "xsmall",
10628
- orientation: "horizontal",
10629
- disabled: false
10923
+ xsmall: "",
10924
+ small: "",
10925
+ medium: "",
10926
+ large: "",
10927
+ xlarge: ""
10630
10928
  }
10929
+ },
10930
+ compoundVariants: [
10931
+ // Vertical: container WIDTH = handle height (MD3 §10.9 — dimensions transposed)
10932
+ // NOTE: measurement-derived values from MD3 spec §4.2; permitted exception
10933
+ { orientation: "vertical", size: "xsmall", class: "w-[44px]" },
10934
+ { orientation: "vertical", size: "small", class: "w-[44px]" },
10935
+ { orientation: "vertical", size: "medium", class: "w-[52px]" },
10936
+ { orientation: "vertical", size: "large", class: "w-[68px]" },
10937
+ { orientation: "vertical", size: "xlarge", class: "w-[108px]" }
10938
+ ],
10939
+ defaultVariants: {
10940
+ orientation: "horizontal",
10941
+ size: "xsmall"
10631
10942
  }
10632
- );
10943
+ });
10944
+ var sliderTrackRegionVariants = cva(["relative", "touch-none"], {
10945
+ variants: {
10946
+ orientation: {
10947
+ horizontal: "col-span-2 w-full",
10948
+ // flex-1 fills the vertical container reliably; h-full collapses when the
10949
+ // container itself is a flex item without an explicit pixel height (CSS spec).
10950
+ // min-h-0 allows the flex child to shrink below its natural size if needed.
10951
+ vertical: "flex-1 min-h-0"
10952
+ },
10953
+ size: {
10954
+ // Horizontal: size controls track region HEIGHT (= handle height)
10955
+ // Vertical: size controls track region WIDTH (= handle height, dimensions transposed)
10956
+ // Applied as compound variants below to avoid cross-orientation conflicts
10957
+ xsmall: "",
10958
+ small: "",
10959
+ medium: "",
10960
+ large: "",
10961
+ xlarge: ""
10962
+ }
10963
+ },
10964
+ compoundVariants: [
10965
+ // Horizontal: height = handle height per MD3 §4.2
10966
+ { orientation: "horizontal", size: "xsmall", class: "h-[44px]" },
10967
+ { orientation: "horizontal", size: "small", class: "h-[44px]" },
10968
+ { orientation: "horizontal", size: "medium", class: "h-[52px]" },
10969
+ { orientation: "horizontal", size: "large", class: "h-[68px]" },
10970
+ { orientation: "horizontal", size: "xlarge", class: "h-[108px]" },
10971
+ // Vertical: width = handle height (transposed per MD3 §10.9)
10972
+ { orientation: "vertical", size: "xsmall", class: "w-[44px]" },
10973
+ { orientation: "vertical", size: "small", class: "w-[44px]" },
10974
+ { orientation: "vertical", size: "medium", class: "w-[52px]" },
10975
+ { orientation: "vertical", size: "large", class: "w-[68px]" },
10976
+ { orientation: "vertical", size: "xlarge", class: "w-[108px]" }
10977
+ ],
10978
+ defaultVariants: {
10979
+ orientation: "horizontal",
10980
+ size: "xsmall"
10981
+ }
10982
+ });
10983
+ var sliderTrackLayoutVariants = cva(["absolute", "inset-0", "pointer-events-none"]);
10633
10984
  var sliderActiveTrackVariants = cva(
10634
- ["bg-primary", "flex-shrink-0", "overflow-hidden", "relative"],
10985
+ [
10986
+ // Color
10987
+ "bg-primary",
10988
+ // Disabled — driven by root group/slider data-disabled attr
10989
+ "group-data-[disabled]/slider:bg-on-surface",
10990
+ "group-data-[disabled]/slider:opacity-38",
10991
+ // Layout — absolute fill within the track region
10992
+ "absolute",
10993
+ "overflow-hidden"
10994
+ ],
10635
10995
  {
10636
10996
  variants: {
10637
10997
  size: {
10638
- // NOTE: measurement-derived values from MD3 spec §4.2, §6 Corner tokens; permitted exception
10639
- // Corner classes are in compound variants to avoid conflicts with vertical orientation corners
10998
+ // Horizontal: left (start) = outer corner, right (near handle) = 2dp inner
10999
+ // NOTE: measurement-derived values from MD3 spec §4.2, §6; permitted exception
10640
11000
  xsmall: "h-[16px] rounded-l-[16px] rounded-r-[2px]",
10641
- // corner.large outer (16dp), 2dp inner
10642
11001
  small: "h-[16px] rounded-l-[16px] rounded-r-[2px]",
10643
11002
  medium: "h-[40px] rounded-l-[12px] rounded-r-[2px]",
10644
- // corner.medium outer (12dp), 2dp inner
10645
11003
  large: "h-[56px] rounded-l-[16px] rounded-r-[2px]",
10646
- // corner.large outer (16dp), 2dp inner
10647
11004
  xlarge: "h-[96px] rounded-l-[28px] rounded-r-[2px]"
10648
- // corner.extra-large outer (28dp), 2dp inner
10649
11005
  },
10650
11006
  orientation: {
10651
- horizontal: "",
10652
- // Vertical: track thickness is now width; flex-basis (inline style) controls height.
10653
- // h-[...] from size variant is overridden by flex-basis in a flex-col container.
10654
- // Individual corner classes (rounded-tl/tr/bl/br) override the horizontal rounded-l/r
10655
- // via tailwind-merge conflict resolution in cn().
10656
- vertical: ""
10657
- },
10658
- disabled: {
10659
- true: "bg-on-surface opacity-38",
10660
- false: ""
11007
+ // Horizontal: center vertically within track region
11008
+ horizontal: "top-1/2 -translate-y-1/2",
11009
+ // Vertical: center horizontally; length controlled by inline top/height styles
11010
+ vertical: "left-1/2 -translate-x-1/2"
10661
11011
  }
10662
11012
  },
10663
11013
  compoundVariants: [
10664
- // Vertical: width = track thickness, corners transposed (bottom = outer, top = inner near handle)
10665
- // Using individual corner utilities so tailwind-merge correctly resolves conflicts with
10666
- // the horizontal rounded-l/rounded-r classes from size variants.
10667
- // NOTE: measurement-derived values from MD3 spec §4.2, §6 Corner tokens; permitted exception
11014
+ // Vertical: width = track thickness; bottom = outer corner, top = 2dp inner (near handle)
11015
+ // NOTE: measurement-derived values from MD3 spec §4.2, §6; permitted exception
10668
11016
  {
10669
11017
  orientation: "vertical",
10670
11018
  size: "xsmall",
10671
- className: "w-[16px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
11019
+ class: "w-[16px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
10672
11020
  },
10673
11021
  {
10674
11022
  orientation: "vertical",
10675
11023
  size: "small",
10676
- className: "w-[16px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
11024
+ class: "w-[16px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
10677
11025
  },
10678
11026
  {
10679
11027
  orientation: "vertical",
10680
11028
  size: "medium",
10681
- className: "w-[40px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[12px] rounded-br-[12px]"
11029
+ class: "w-[40px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[12px] rounded-br-[12px]"
10682
11030
  },
10683
11031
  {
10684
11032
  orientation: "vertical",
10685
11033
  size: "large",
10686
- className: "w-[56px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
11034
+ class: "w-[56px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[16px] rounded-br-[16px]"
10687
11035
  },
10688
11036
  {
10689
11037
  orientation: "vertical",
10690
11038
  size: "xlarge",
10691
- className: "w-[96px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[28px] rounded-br-[28px]"
11039
+ class: "w-[96px] rounded-tl-[2px] rounded-tr-[2px] rounded-bl-[28px] rounded-br-[28px]"
10692
11040
  }
10693
11041
  ],
10694
11042
  defaultVariants: {
10695
11043
  size: "xsmall",
10696
- orientation: "horizontal",
10697
- disabled: false
11044
+ orientation: "horizontal"
10698
11045
  }
10699
11046
  }
10700
11047
  );
10701
11048
  var sliderInactiveTrackVariants = cva(
10702
- ["bg-secondary-container", "flex-1", "overflow-hidden", "relative"],
11049
+ [
11050
+ // Color
11051
+ "bg-secondary-container",
11052
+ // Disabled — driven by root group/slider data-disabled attr
11053
+ "group-data-[disabled]/slider:bg-on-surface/10",
11054
+ // Layout — absolute fill within the track region
11055
+ "absolute",
11056
+ "overflow-hidden"
11057
+ ],
10703
11058
  {
10704
11059
  variants: {
10705
11060
  size: {
10706
- // NOTE: measurement-derived values from MD3 spec §4.2, §6 Corner tokens; permitted exception
11061
+ // Horizontal: left (near handle) = 2dp inner, right (end) = outer corner
11062
+ // NOTE: measurement-derived values from MD3 spec §4.2, §6; permitted exception
10707
11063
  xsmall: "h-[16px] rounded-l-[2px] rounded-r-[16px]",
10708
11064
  small: "h-[16px] rounded-l-[2px] rounded-r-[16px]",
10709
11065
  medium: "h-[40px] rounded-l-[2px] rounded-r-[12px]",
@@ -10711,68 +11067,65 @@ var sliderInactiveTrackVariants = cva(
10711
11067
  xlarge: "h-[96px] rounded-l-[2px] rounded-r-[28px]"
10712
11068
  },
10713
11069
  orientation: {
10714
- horizontal: "",
10715
- // Vertical: track thickness is width; flex-1 controls height growth.
10716
- // Individual corner classes override horizontal rounded-l/r via tailwind-merge.
10717
- vertical: ""
10718
- },
10719
- disabled: {
10720
- true: "bg-on-surface/10",
10721
- // MD3 §8.2: 10% opacity via background alpha
10722
- false: ""
11070
+ // Horizontal: center vertically within track region
11071
+ horizontal: "top-1/2 -translate-y-1/2",
11072
+ // Vertical: center horizontally; length controlled by inline top/height styles
11073
+ vertical: "left-1/2 -translate-x-1/2"
10723
11074
  }
10724
11075
  },
10725
11076
  compoundVariants: [
10726
- // Vertical: width = track thickness, corners transposed (top = outer, bottom = inner near handle)
10727
- // NOTE: measurement-derived values from MD3 spec §4.2, §6 Corner tokens; permitted exception
11077
+ // Vertical: width = track thickness; top = outer corner, bottom = 2dp inner (near handle)
11078
+ // NOTE: measurement-derived values from MD3 spec §4.2, §6; permitted exception
10728
11079
  {
10729
11080
  orientation: "vertical",
10730
11081
  size: "xsmall",
10731
- className: "w-[16px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
11082
+ class: "w-[16px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
10732
11083
  },
10733
11084
  {
10734
11085
  orientation: "vertical",
10735
11086
  size: "small",
10736
- className: "w-[16px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
11087
+ class: "w-[16px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
10737
11088
  },
10738
11089
  {
10739
11090
  orientation: "vertical",
10740
11091
  size: "medium",
10741
- className: "w-[40px] rounded-tl-[12px] rounded-tr-[12px] rounded-bl-[2px] rounded-br-[2px]"
11092
+ class: "w-[40px] rounded-tl-[12px] rounded-tr-[12px] rounded-bl-[2px] rounded-br-[2px]"
10742
11093
  },
10743
11094
  {
10744
11095
  orientation: "vertical",
10745
11096
  size: "large",
10746
- className: "w-[56px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
11097
+ class: "w-[56px] rounded-tl-[16px] rounded-tr-[16px] rounded-bl-[2px] rounded-br-[2px]"
10747
11098
  },
10748
11099
  {
10749
11100
  orientation: "vertical",
10750
11101
  size: "xlarge",
10751
- className: "w-[96px] rounded-tl-[28px] rounded-tr-[28px] rounded-bl-[2px] rounded-br-[2px]"
11102
+ class: "w-[96px] rounded-tl-[28px] rounded-tr-[28px] rounded-bl-[2px] rounded-br-[2px]"
10752
11103
  }
10753
11104
  ],
10754
11105
  defaultVariants: {
10755
11106
  size: "xsmall",
10756
- orientation: "horizontal",
10757
- disabled: false
11107
+ orientation: "horizontal"
10758
11108
  }
10759
11109
  }
10760
11110
  );
10761
11111
  var sliderHandleVariants = cva(
10762
11112
  [
11113
+ // Color
10763
11114
  "bg-primary",
11115
+ // Disabled — driven by thumb group/slider-thumb data-disabled attr
11116
+ "group-data-[disabled]/slider-thumb:bg-on-surface",
11117
+ "group-data-[disabled]/slider-thumb:opacity-38",
11118
+ // Pressed width (MD3: 4dp → 2dp on press, spatial spring)
11119
+ "group-data-[pressed]/slider-thumb:w-[2px]",
11120
+ // Shape
10764
11121
  "rounded-[2px]",
10765
- // NOTE: measurement-derived value from MD3 spec §10.3 (2dp handle border-radius); permitted exception
11122
+ // Layout
10766
11123
  "flex-shrink-0",
10767
- "relative",
10768
- "z-10",
10769
- "outline-none"
10770
- // Motion classes applied conditionally in Slider.tsx via useReducedMotion guard
11124
+ "pointer-events-none"
10771
11125
  ],
10772
11126
  {
10773
11127
  variants: {
10774
11128
  size: {
10775
- // NOTE: measurement-derived values from MD3 spec §4.2, §10.3; permitted exception
10776
11129
  xsmall: "w-[4px] h-[44px]",
10777
11130
  small: "w-[4px] h-[44px]",
10778
11131
  medium: "w-[4px] h-[52px]",
@@ -10781,79 +11134,99 @@ var sliderHandleVariants = cva(
10781
11134
  },
10782
11135
  orientation: {
10783
11136
  horizontal: "",
10784
- // Vertical: dimensions transposed. h-[4px] overrides size-variant h-[...] via tailwind-merge;
10785
- // w-full overrides size-variant w-[4px] via tailwind-merge (both in cn() call at styled layer).
10786
- // NOTE: measurement-derived value from MD3 spec §10.3 (4dp handle width); permitted exception
10787
- vertical: "h-[4px] w-full"
10788
- },
10789
- pressed: {
10790
- true: "w-[2px]",
10791
- // NOTE: measurement-derived value from MD3 spec §10.3 (2dp pressed width); permitted exception
10792
- false: ""
10793
- },
10794
- disabled: {
10795
- true: "bg-on-surface opacity-38",
10796
- false: ""
11137
+ // Vertical: handle is a thin horizontal bar. h-[4px] overrides the base
11138
+ // h-[44px..108px]. Width is explicitly set per size below so the RA thumb
11139
+ // (which is shrink-to-fit) assumes the correct measured width this also
11140
+ // fixes the hit-area (w-full) and state-layer (inset-0) widths.
11141
+ vertical: "h-[4px]"
10797
11142
  }
10798
11143
  },
11144
+ compoundVariants: [
11145
+ // Vertical: override to height-based narrowing on press
11146
+ {
11147
+ orientation: "vertical",
11148
+ class: "group-data-[pressed]/slider-thumb:h-[2px]"
11149
+ },
11150
+ // Vertical per-size widths (transposed handle length = track region width per MD3 §10.9)
11151
+ // NOTE: measurement-derived values from MD3 spec §4.2; permitted exception
11152
+ { orientation: "vertical", size: "xsmall", class: "w-[44px]" },
11153
+ { orientation: "vertical", size: "small", class: "w-[44px]" },
11154
+ { orientation: "vertical", size: "medium", class: "w-[52px]" },
11155
+ { orientation: "vertical", size: "large", class: "w-[68px]" },
11156
+ { orientation: "vertical", size: "xlarge", class: "w-[108px]" }
11157
+ ],
10799
11158
  defaultVariants: {
10800
11159
  size: "xsmall",
10801
- orientation: "horizontal",
10802
- pressed: false,
10803
- disabled: false
10804
- }
10805
- }
10806
- );
10807
- var sliderHandleStateLayerVariants = cva(
10808
- [
10809
- "absolute",
10810
- "inset-0",
10811
- "rounded-[4px]",
10812
- // NOTE: measurement-derived value from MD3 spec §10.3 (4dp state layer border-radius); permitted exception
10813
- "bg-on-primary",
10814
- "pointer-events-none"
10815
- // Motion classes applied conditionally in Slider.tsx via useReducedMotion guard
10816
- ],
10817
- {
10818
- variants: {
10819
- state: {
10820
- enabled: "opacity-0",
10821
- hovered: "opacity-8",
10822
- // MD3 §8.3: 8% hover
10823
- pressed: "opacity-10",
10824
- // MD3 §8.3: 10% pressed
10825
- focused: "opacity-10",
10826
- // MD3 §8.3: 10% focus
10827
- disabled: "opacity-0"
10828
- }
10829
- },
10830
- defaultVariants: {
10831
- state: "enabled"
11160
+ orientation: "horizontal"
10832
11161
  }
10833
11162
  }
10834
11163
  );
10835
- var sliderTrackLayoutVariants = cva(
10836
- [
10837
- "relative",
10838
- "flex",
10839
- "items-center",
10840
- "gap-[6px]"
10841
- // NOTE: measurement-derived value from MD3 spec §2, §6 (thumbTrackGapSize: 6dp); permitted exception
10842
- ],
10843
- {
10844
- variants: {
10845
- orientation: {
10846
- // Horizontal: full width, left-to-right fill
10847
- horizontal: "flex-row w-full",
10848
- // Vertical: full height, bottom-to-top fill (flex-col-reverse places active track at bottom)
10849
- vertical: "flex-col-reverse h-full"
10850
- }
11164
+ var sliderHandleStateLayerVariants = cva([
11165
+ // Color
11166
+ "bg-primary",
11167
+ // Positioning — covers the handle
11168
+ "absolute",
11169
+ "inset-0",
11170
+ "rounded-[2px]",
11171
+ // Interaction: hidden by default
11172
+ "opacity-0",
11173
+ "pointer-events-none",
11174
+ // State opacities — driven by group/slider-thumb data attrs
11175
+ "group-data-[hovered]/slider-thumb:opacity-8",
11176
+ "group-data-[focus-visible]/slider-thumb:opacity-10",
11177
+ "group-data-[pressed]/slider-thumb:opacity-10",
11178
+ // Disabled: hide state layer (no interaction feedback)
11179
+ "group-data-[disabled]/slider-thumb:hidden",
11180
+ // Motion: effects spring (opacity transition only)
11181
+ "transition-opacity",
11182
+ "duration-spring-standard-fast-effects",
11183
+ "ease-spring-standard-fast-effects"
11184
+ ]);
11185
+ var sliderValueIndicatorVariants = cva([
11186
+ // Positioning: float above handle center
11187
+ "absolute",
11188
+ "left-1/2",
11189
+ "-translate-x-1/2",
11190
+ "bottom-[calc(100%+4px)]",
11191
+ // Shape & color
11192
+ "bg-inverse-surface",
11193
+ "rounded-full",
11194
+ "px-[12px]",
11195
+ "py-[6px]",
11196
+ "min-w-[48px]",
11197
+ "text-center",
11198
+ // Hidden by default; revealed when thumb group has data-pressed
11199
+ "opacity-0",
11200
+ "scale-0",
11201
+ "group-data-[pressed]/slider-thumb:opacity-100",
11202
+ "group-data-[pressed]/slider-thumb:scale-100",
11203
+ // Prevent interaction (value display only)
11204
+ "pointer-events-none",
11205
+ // Z-index above track overlays
11206
+ "z-10",
11207
+ // In Tailwind v4, scale-* maps to the CSS `scale` property (not `transform`),
11208
+ // so we must list `scale` here — not `transform` — to animate the reveal.
11209
+ "will-change-[scale,opacity]"
11210
+ ]);
11211
+ var sliderStopDotVariants = cva(["rounded-full", "flex-shrink-0", "pointer-events-none"], {
11212
+ variants: {
11213
+ region: {
11214
+ active: "bg-on-primary",
11215
+ inactive: "bg-on-secondary-container"
10851
11216
  },
10852
- defaultVariants: {
10853
- orientation: "horizontal"
11217
+ size: {
11218
+ xsmall: "w-[4px] h-[4px]",
11219
+ small: "w-[4px] h-[4px]",
11220
+ medium: "w-[6px] h-[6px]",
11221
+ large: "w-[6px] h-[6px]",
11222
+ xlarge: "w-[8px] h-[8px]"
10854
11223
  }
11224
+ },
11225
+ defaultVariants: {
11226
+ region: "inactive",
11227
+ size: "xsmall"
10855
11228
  }
10856
- );
11229
+ });
10857
11230
  var sliderStopsContainerVariants = cva([
10858
11231
  "absolute",
10859
11232
  "inset-0",
@@ -10861,58 +11234,22 @@ var sliderStopsContainerVariants = cva([
10861
11234
  "items-center",
10862
11235
  "justify-between",
10863
11236
  "px-[4px]",
10864
- // NOTE: measurement-derived value from MD3 spec §10.5 (stopPadding: 4dp); permitted exception
10865
11237
  "pointer-events-none",
10866
- "z-0"
11238
+ "z-10"
10867
11239
  ]);
10868
- var sliderStopDotVariants = cva(
10869
- [
10870
- "rounded-full",
10871
- "flex-shrink-0",
10872
- "w-[4px]",
10873
- // NOTE: measurement-derived value from MD3 spec §10.5 (stopIndicatorSize: 4dp); permitted exception
10874
- "h-[4px]"
10875
- ],
10876
- {
10877
- variants: {
10878
- /**
10879
- * Whether this dot is positioned on the active track portion.
10880
- * Determines the dot color per MD3 spec §5.2.
10881
- */
10882
- onActiveTrack: {
10883
- true: "bg-on-primary",
10884
- // Light dots on primary background
10885
- false: "bg-on-secondary-container"
10886
- // Dark dots on secondary-container background
10887
- },
10888
- disabled: {
10889
- true: "opacity-38",
10890
- false: ""
10891
- }
10892
- },
10893
- defaultVariants: {
10894
- onActiveTrack: false,
10895
- disabled: false
10896
- }
10897
- }
10898
- );
10899
11240
  var sliderTrackStopVariants = cva(
10900
11241
  [
10901
11242
  "absolute",
10902
- "top-1/2",
10903
- "-translate-y-1/2",
10904
- "w-[4px]",
10905
- // NOTE: measurement-derived value from MD3 spec §10.6 (trackStopDiameter: 4dp); permitted exception
10906
- "h-[4px]",
10907
11243
  "rounded-full",
10908
11244
  "bg-on-secondary-container",
10909
- "pointer-events-none"
11245
+ "pointer-events-none",
11246
+ "w-[4px]",
11247
+ "h-[4px]"
10910
11248
  ],
10911
11249
  {
10912
11250
  variants: {
10913
11251
  position: {
10914
11252
  start: "left-[4px]",
10915
- // NOTE: measurement-derived (trackStopOffset: 4dp); permitted exception
10916
11253
  end: "right-[4px]"
10917
11254
  }
10918
11255
  },
@@ -10921,64 +11258,23 @@ var sliderTrackStopVariants = cva(
10921
11258
  }
10922
11259
  }
10923
11260
  );
10924
- var sliderValueIndicatorVariants = cva(
10925
- [
10926
- "absolute",
10927
- "left-1/2",
10928
- "-translate-x-1/2",
10929
- "bottom-[calc(100%+4px)]",
10930
- // NOTE: measurement-derived (4dp gap above handle); permitted exception
10931
- "bg-inverse-surface",
10932
- "rounded-full",
10933
- // pill shape (1000dp radius)
10934
- "px-[16px]",
10935
- // NOTE: measurement-derived (valueIndicatorPaddingH: 16dp); permitted exception
10936
- "py-[12px]",
10937
- // NOTE: measurement-derived (valueIndicatorPaddingV: 12dp); permitted exception
10938
- "min-w-[48px]",
10939
- // NOTE: measurement-derived (valueIndicatorWidth: 48dp); permitted exception
10940
- "flex",
10941
- "items-center",
10942
- "justify-center",
10943
- "pointer-events-none",
10944
- "z-20"
10945
- // Motion classes (transition-[transform,opacity] with directional easing) applied
10946
- // conditionally in SliderValueIndicator.tsx via useReducedMotion guard.
10947
- ],
10948
- {
10949
- variants: {
10950
- visible: {
10951
- true: "opacity-100 scale-100",
10952
- false: "opacity-0 scale-0"
10953
- }
10954
- },
10955
- defaultVariants: {
10956
- visible: false
10957
- }
10958
- }
10959
- );
10960
11261
  var sliderValueIndicatorTextVariants = cva([
10961
11262
  "text-inverse-on-surface",
10962
11263
  "text-label-large",
10963
- // MD3 Label Large typescale token
10964
- "whitespace-nowrap",
10965
- "text-center"
11264
+ "select-none",
11265
+ "whitespace-nowrap"
10966
11266
  ]);
10967
11267
  var sliderInsetIconVariants = cva(
10968
11268
  ["absolute", "text-on-primary", "pointer-events-none", "flex", "items-center", "justify-center"],
10969
11269
  {
10970
11270
  variants: {
10971
11271
  size: {
10972
- // NOTE: measurement-derived values from MD3 spec §10.7 (icon sizes); permitted exception
10973
11272
  medium: "w-[24px] h-[24px]",
10974
11273
  large: "w-[24px] h-[24px]",
10975
11274
  xlarge: "w-[32px] h-[32px]"
10976
11275
  },
10977
11276
  orientation: {
10978
- // Horizontal: 8dp from active track left edge, vertically centered
10979
- // NOTE: measurement-derived value from MD3 spec §10.7 (iconOffset: 8dp); permitted exception
10980
11277
  horizontal: "left-[8px] top-1/2 -translate-y-1/2",
10981
- // Vertical: 8dp from active track bottom edge (outer end), horizontally centered
10982
11278
  vertical: "bottom-[8px] left-1/2 -translate-x-1/2"
10983
11279
  }
10984
11280
  },
@@ -11009,7 +11305,7 @@ function SliderStops({
11009
11305
  step,
11010
11306
  values,
11011
11307
  variant,
11012
- isDisabled,
11308
+ size = "xsmall",
11013
11309
  className
11014
11310
  }) {
11015
11311
  const stopCount = Math.floor((maxValue - minValue) / step) + 1;
@@ -11027,7 +11323,10 @@ function SliderStops({
11027
11323
  {
11028
11324
  "data-slot": "stop-dot",
11029
11325
  className: cn(
11030
- sliderStopDotVariants({ onActiveTrack: isOnActive, disabled: isDisabled })
11326
+ sliderStopDotVariants({
11327
+ region: isOnActive ? "active" : "inactive",
11328
+ size
11329
+ })
11031
11330
  )
11032
11331
  },
11033
11332
  i
@@ -11038,27 +11337,19 @@ function SliderStops({
11038
11337
  }
11039
11338
  function SliderValueIndicator({
11040
11339
  value,
11041
- isVisible,
11042
11340
  formatValue: formatValue2,
11043
11341
  className
11044
11342
  }) {
11045
11343
  const displayValue = formatValue2 ? formatValue2(value) : `${Math.round(value)}`;
11046
11344
  const reducedMotion = useReducedMotion();
11047
- const transitionClasses = reducedMotion ? "" : cn(
11048
- "transition-[transform,opacity]",
11049
- isVisible ? "duration-short3 ease-standard-decelerate" : "duration-short2 ease-standard-accelerate"
11050
- );
11345
+ const transitionClasses = reducedMotion ? "" : "transition-[scale,opacity] duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial";
11051
11346
  return /* @__PURE__ */ jsx(
11052
11347
  "div",
11053
11348
  {
11054
11349
  "data-slot": "value-indicator",
11055
- className: cn(
11056
- sliderValueIndicatorVariants({ visible: isVisible }),
11057
- transitionClasses,
11058
- className
11059
- ),
11350
+ className: cn(sliderValueIndicatorVariants(), transitionClasses, className),
11060
11351
  role: "tooltip",
11061
- "aria-hidden": !isVisible,
11352
+ "aria-hidden": "true",
11062
11353
  children: /* @__PURE__ */ jsx("span", { className: sliderValueIndicatorTextVariants(), children: displayValue })
11063
11354
  }
11064
11355
  );
@@ -11071,6 +11362,16 @@ function resolveDefaultValue(variant, minValue) {
11071
11362
  if (variant === "centered") return [0];
11072
11363
  return [minValue];
11073
11364
  }
11365
+ var GAP_PX = 3;
11366
+ function segmentStyle(orientation, opts) {
11367
+ const { start, end, startGap = 0, endGap = 0 } = opts;
11368
+ const startVal = start !== null ? `calc(${start}% + ${startGap}px)` : `${startGap}px`;
11369
+ const endVal = end !== null ? `calc(${100 - end}% + ${endGap}px)` : `${endGap}px`;
11370
+ if (orientation === "horizontal") {
11371
+ return { left: startVal, right: endVal };
11372
+ }
11373
+ return { bottom: startVal, top: endVal };
11374
+ }
11074
11375
  var Slider = forwardRef(
11075
11376
  ({
11076
11377
  size = "xsmall",
@@ -11104,103 +11405,75 @@ var Slider = forwardRef(
11104
11405
  },
11105
11406
  [value, onChange]
11106
11407
  );
11107
- const thumbCount = variant === "range" ? 2 : 1;
11108
- const [thumbStates, setThumbStates] = useState(
11109
- () => Array(thumbCount).fill("enabled")
11110
- );
11111
- const isDragging = thumbStates.some((s) => s === "pressed");
11112
- const trackTransition = reducedMotion || isDragging ? "" : "transition-[flex-basis] duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial";
11113
- const handleMotion = reducedMotion ? "" : "transition-[width] duration-short2 ease-standard";
11114
- const stateLayerMotion = reducedMotion ? "" : "transition-opacity duration-short1 ease-standard";
11408
+ const [anyThumbDragging, setAnyThumbDragging] = useState(false);
11409
+ const handleThumbDraggingChange = useCallback((_index, isDragging) => {
11410
+ setAnyThumbDragging(isDragging);
11411
+ }, []);
11412
+ const springTokens = "duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial";
11413
+ const trackTransition = reducedMotion || anyThumbDragging ? "" : orientation === "vertical" ? `transition-[top,bottom,height] ${springTokens}` : `transition-[left,width,right] ${springTokens}`;
11414
+ const handleMotion = reducedMotion ? "" : "transition-[width] duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial";
11115
11415
  const isRange = variant === "range";
11116
11416
  const isCentered = variant === "centered";
11117
11417
  const showIcon = icon !== void 0 && variant === "standard" && (size === "medium" || size === "large" || size === "xlarge");
11418
+ const renderThumbContent = useCallback(
11419
+ ({ value: thumbValue }) => /* @__PURE__ */ jsxs(Fragment, { children: [
11420
+ /* @__PURE__ */ jsx(
11421
+ "div",
11422
+ {
11423
+ "aria-hidden": "true",
11424
+ className: cn(
11425
+ "absolute",
11426
+ "left-1/2",
11427
+ "top-1/2",
11428
+ "-translate-x-1/2",
11429
+ "-translate-y-1/2",
11430
+ orientation === "vertical" ? "h-[20px] w-full" : "h-full w-[20px]"
11431
+ )
11432
+ }
11433
+ ),
11434
+ /* @__PURE__ */ jsx(
11435
+ "div",
11436
+ {
11437
+ "data-slot": "handle",
11438
+ className: cn(sliderHandleVariants({ size, orientation }), handleMotion)
11439
+ }
11440
+ ),
11441
+ /* @__PURE__ */ jsx("div", { "data-slot": "state-layer", className: cn(sliderHandleStateLayerVariants()) }),
11442
+ showValueIndicator && /* @__PURE__ */ jsx(
11443
+ SliderValueIndicator,
11444
+ {
11445
+ value: thumbValue,
11446
+ ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {}
11447
+ }
11448
+ )
11449
+ ] }),
11450
+ [size, orientation, showValueIndicator, formatValue2, handleMotion]
11451
+ );
11118
11452
  const renderStandardTrack = () => {
11119
11453
  const pct = clampPercent(currentValues[0] ?? minValue, minValue, maxValue);
11120
- const thumb0State = isDisabled ? "disabled" : thumbStates[0] ?? "enabled";
11121
11454
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11122
11455
  /* @__PURE__ */ jsx(
11123
11456
  "div",
11124
11457
  {
11125
11458
  "data-slot": "active-track",
11126
- className: cn(
11127
- sliderActiveTrackVariants({ size, disabled: isDisabled, orientation }),
11128
- trackTransition
11129
- ),
11130
- style: { flexBasis: `${pct}%` },
11459
+ className: cn(sliderActiveTrackVariants({ size, orientation }), trackTransition),
11460
+ style: segmentStyle(orientation, { start: null, end: pct, endGap: GAP_PX }),
11131
11461
  children: showIcon && /* @__PURE__ */ jsx(
11132
11462
  "span",
11133
11463
  {
11134
11464
  "data-slot": "inset-icon",
11135
- className: cn(
11136
- sliderInsetIconVariants({
11137
- size,
11138
- orientation
11139
- })
11140
- ),
11465
+ className: cn(sliderInsetIconVariants({ size, orientation })),
11141
11466
  children: icon
11142
11467
  }
11143
11468
  )
11144
11469
  }
11145
11470
  ),
11146
- /* @__PURE__ */ jsxs(
11147
- "div",
11148
- {
11149
- "data-slot": "handle",
11150
- className: cn(
11151
- sliderHandleVariants({
11152
- size,
11153
- disabled: isDisabled,
11154
- pressed: thumb0State === "pressed",
11155
- orientation
11156
- }),
11157
- handleMotion
11158
- ),
11159
- onPointerEnter: () => {
11160
- if (!isDisabled) setThumbStates(["hovered"]);
11161
- },
11162
- onPointerLeave: () => {
11163
- if (!isDisabled) setThumbStates(["enabled"]);
11164
- },
11165
- onPointerDown: (e) => {
11166
- e.stopPropagation();
11167
- if (!isDisabled) setThumbStates(["pressed"]);
11168
- },
11169
- onPointerUp: (e) => {
11170
- e.stopPropagation();
11171
- if (!isDisabled) setThumbStates(["enabled"]);
11172
- },
11173
- children: [
11174
- /* @__PURE__ */ jsx(
11175
- "div",
11176
- {
11177
- "data-slot": "state-layer",
11178
- className: cn(
11179
- sliderHandleStateLayerVariants({ state: thumb0State }),
11180
- stateLayerMotion
11181
- )
11182
- }
11183
- ),
11184
- showValueIndicator && /* @__PURE__ */ jsx(
11185
- SliderValueIndicator,
11186
- {
11187
- value: currentValues[0] ?? minValue,
11188
- isVisible: thumb0State === "pressed",
11189
- ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {}
11190
- }
11191
- )
11192
- ]
11193
- }
11194
- ),
11195
11471
  /* @__PURE__ */ jsx(
11196
11472
  "div",
11197
11473
  {
11198
11474
  "data-slot": "inactive-track",
11199
- className: cn(
11200
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11201
- trackTransition
11202
- ),
11203
- style: { flexBasis: `${100 - pct}%` },
11475
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11476
+ style: segmentStyle(orientation, { start: pct, startGap: GAP_PX, end: null }),
11204
11477
  children: showStops && /* @__PURE__ */ jsx(
11205
11478
  "span",
11206
11479
  {
@@ -11215,20 +11488,13 @@ var Slider = forwardRef(
11215
11488
  const renderRangeTrack = () => {
11216
11489
  const leftPct = clampPercent(currentValues[0] ?? minValue, minValue, maxValue);
11217
11490
  const rightPct = clampPercent(currentValues[1] ?? maxValue, minValue, maxValue);
11218
- const thumb0State = isDisabled ? "disabled" : thumbStates[0] ?? "enabled";
11219
- const thumb1State = isDisabled ? "disabled" : thumbStates[1] ?? "enabled";
11220
- const setThumb0 = (next) => setThumbStates((s) => [next, s[1] ?? "enabled"]);
11221
- const setThumb1 = (next) => setThumbStates((s) => [s[0] ?? "enabled", next]);
11222
11491
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11223
11492
  /* @__PURE__ */ jsx(
11224
11493
  "div",
11225
11494
  {
11226
11495
  "data-slot": "inactive-track-left",
11227
- className: cn(
11228
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11229
- trackTransition
11230
- ),
11231
- style: { flexBasis: `${leftPct}%` },
11496
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11497
+ style: segmentStyle(orientation, { start: null, end: leftPct, endGap: GAP_PX }),
11232
11498
  children: showStops && /* @__PURE__ */ jsx(
11233
11499
  "span",
11234
11500
  {
@@ -11238,128 +11504,30 @@ var Slider = forwardRef(
11238
11504
  )
11239
11505
  }
11240
11506
  ),
11241
- /* @__PURE__ */ jsxs(
11242
- "div",
11243
- {
11244
- "data-slot": "handle",
11245
- "data-index": "0",
11246
- className: cn(
11247
- sliderHandleVariants({
11248
- size,
11249
- disabled: isDisabled,
11250
- pressed: thumb0State === "pressed",
11251
- orientation
11252
- }),
11253
- handleMotion
11254
- ),
11255
- onPointerEnter: () => {
11256
- if (!isDisabled) setThumb0("hovered");
11257
- },
11258
- onPointerLeave: () => {
11259
- if (!isDisabled) setThumb0("enabled");
11260
- },
11261
- onPointerDown: (e) => {
11262
- e.stopPropagation();
11263
- if (!isDisabled) setThumb0("pressed");
11264
- },
11265
- onPointerUp: (e) => {
11266
- e.stopPropagation();
11267
- if (!isDisabled) setThumb0("enabled");
11268
- },
11269
- children: [
11270
- /* @__PURE__ */ jsx(
11271
- "div",
11272
- {
11273
- "data-slot": "state-layer",
11274
- className: cn(
11275
- sliderHandleStateLayerVariants({ state: thumb0State }),
11276
- stateLayerMotion
11277
- )
11278
- }
11279
- ),
11280
- showValueIndicator && /* @__PURE__ */ jsx(
11281
- SliderValueIndicator,
11282
- {
11283
- value: currentValues[0] ?? minValue,
11284
- isVisible: thumb0State === "pressed",
11285
- ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {}
11286
- }
11287
- )
11288
- ]
11289
- }
11290
- ),
11291
11507
  /* @__PURE__ */ jsx(
11292
11508
  "div",
11293
11509
  {
11294
11510
  "data-slot": "active-track",
11295
11511
  className: cn(
11296
- sliderActiveTrackVariants({ size, disabled: isDisabled, orientation }),
11512
+ sliderActiveTrackVariants({ size, orientation }),
11297
11513
  "rounded-[2px]",
11298
- // Both ends near handles: 2dp (MD3 §10.2)
11514
+ // Both ends near handles: 2dp inner (MD3 §10.2)
11299
11515
  trackTransition
11300
11516
  ),
11301
- style: { flexBasis: `${rightPct - leftPct}%` }
11302
- }
11303
- ),
11304
- /* @__PURE__ */ jsxs(
11305
- "div",
11306
- {
11307
- "data-slot": "handle",
11308
- "data-index": "1",
11309
- className: cn(
11310
- sliderHandleVariants({
11311
- size,
11312
- disabled: isDisabled,
11313
- pressed: thumb1State === "pressed",
11314
- orientation
11315
- }),
11316
- handleMotion
11317
- ),
11318
- onPointerEnter: () => {
11319
- if (!isDisabled) setThumb1("hovered");
11320
- },
11321
- onPointerLeave: () => {
11322
- if (!isDisabled) setThumb1("enabled");
11323
- },
11324
- onPointerDown: (e) => {
11325
- e.stopPropagation();
11326
- if (!isDisabled) setThumb1("pressed");
11327
- },
11328
- onPointerUp: (e) => {
11329
- e.stopPropagation();
11330
- if (!isDisabled) setThumb1("enabled");
11331
- },
11332
- children: [
11333
- /* @__PURE__ */ jsx(
11334
- "div",
11335
- {
11336
- "data-slot": "state-layer",
11337
- className: cn(
11338
- sliderHandleStateLayerVariants({ state: thumb1State }),
11339
- stateLayerMotion
11340
- )
11341
- }
11342
- ),
11343
- showValueIndicator && /* @__PURE__ */ jsx(
11344
- SliderValueIndicator,
11345
- {
11346
- value: currentValues[1] ?? maxValue,
11347
- isVisible: thumb1State === "pressed",
11348
- ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {}
11349
- }
11350
- )
11351
- ]
11517
+ style: segmentStyle(orientation, {
11518
+ start: leftPct,
11519
+ startGap: GAP_PX,
11520
+ end: rightPct,
11521
+ endGap: GAP_PX
11522
+ })
11352
11523
  }
11353
11524
  ),
11354
11525
  /* @__PURE__ */ jsx(
11355
11526
  "div",
11356
11527
  {
11357
11528
  "data-slot": "inactive-track-right",
11358
- className: cn(
11359
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11360
- trackTransition
11361
- ),
11362
- style: { flexBasis: `${100 - rightPct}%` },
11529
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11530
+ style: segmentStyle(orientation, { start: rightPct, startGap: GAP_PX, end: null }),
11363
11531
  children: showStops && /* @__PURE__ */ jsx(
11364
11532
  "span",
11365
11533
  {
@@ -11374,126 +11542,65 @@ var Slider = forwardRef(
11374
11542
  const renderCenteredTrack = () => {
11375
11543
  const thumbPct = clampPercent(currentValues[0] ?? minValue, minValue, maxValue);
11376
11544
  const zeroPct = minValue >= 0 ? 0 : maxValue <= 0 ? 100 : (0 - minValue) / (maxValue - minValue) * 100;
11377
- const thumb0State = isDisabled ? "disabled" : thumbStates[0] ?? "enabled";
11378
- const handleEl = /* @__PURE__ */ jsxs(
11379
- "div",
11380
- {
11381
- "data-slot": "handle",
11382
- className: cn(
11383
- sliderHandleVariants({
11384
- size,
11385
- disabled: isDisabled,
11386
- pressed: thumb0State === "pressed",
11387
- orientation
11388
- }),
11389
- handleMotion
11390
- ),
11391
- onPointerEnter: () => {
11392
- if (!isDisabled) setThumbStates(["hovered"]);
11393
- },
11394
- onPointerLeave: () => {
11395
- if (!isDisabled) setThumbStates(["enabled"]);
11396
- },
11397
- onPointerDown: (e) => {
11398
- e.stopPropagation();
11399
- if (!isDisabled) setThumbStates(["pressed"]);
11400
- },
11401
- onPointerUp: (e) => {
11402
- e.stopPropagation();
11403
- if (!isDisabled) setThumbStates(["enabled"]);
11404
- },
11405
- children: [
11406
- /* @__PURE__ */ jsx(
11407
- "div",
11408
- {
11409
- "data-slot": "state-layer",
11410
- className: cn(sliderHandleStateLayerVariants({ state: thumb0State }), stateLayerMotion)
11411
- }
11412
- ),
11413
- showValueIndicator && /* @__PURE__ */ jsx(
11414
- SliderValueIndicator,
11415
- {
11416
- value: currentValues[0] ?? minValue,
11417
- isVisible: thumb0State === "pressed",
11418
- ...formatValue2 !== void 0 ? { formatValue: formatValue2 } : {}
11419
- }
11420
- )
11421
- ]
11422
- }
11423
- );
11424
11545
  if (thumbPct >= zeroPct) {
11425
- const activePct = thumbPct - zeroPct;
11426
11546
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11427
11547
  /* @__PURE__ */ jsx(
11428
11548
  "div",
11429
11549
  {
11430
11550
  "data-slot": "inactive-track-left",
11431
- className: cn(
11432
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11433
- trackTransition
11434
- ),
11435
- style: { flexBasis: `${zeroPct}%` }
11551
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11552
+ style: segmentStyle(orientation, { start: null, end: zeroPct })
11436
11553
  }
11437
11554
  ),
11438
- handleEl,
11439
11555
  /* @__PURE__ */ jsx(
11440
11556
  "div",
11441
11557
  {
11442
11558
  "data-slot": "active-track",
11443
- className: cn(
11444
- sliderActiveTrackVariants({ size, disabled: isDisabled, orientation }),
11445
- trackTransition
11446
- ),
11447
- style: { flexBasis: `${activePct}%` }
11559
+ className: cn(sliderActiveTrackVariants({ size, orientation }), trackTransition),
11560
+ style: segmentStyle(orientation, {
11561
+ start: zeroPct,
11562
+ end: thumbPct,
11563
+ endGap: GAP_PX
11564
+ })
11448
11565
  }
11449
11566
  ),
11450
11567
  /* @__PURE__ */ jsx(
11451
11568
  "div",
11452
11569
  {
11453
11570
  "data-slot": "inactive-track-right",
11454
- className: cn(
11455
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11456
- trackTransition
11457
- ),
11458
- style: { flexBasis: `${100 - zeroPct - activePct}%` }
11571
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11572
+ style: segmentStyle(orientation, { start: thumbPct, startGap: GAP_PX, end: null })
11459
11573
  }
11460
11574
  )
11461
11575
  ] });
11462
11576
  } else {
11463
- const activePct = zeroPct - thumbPct;
11464
11577
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11465
11578
  /* @__PURE__ */ jsx(
11466
11579
  "div",
11467
11580
  {
11468
11581
  "data-slot": "inactive-track-left",
11469
- className: cn(
11470
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11471
- trackTransition
11472
- ),
11473
- style: { flexBasis: `${thumbPct}%` }
11582
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11583
+ style: segmentStyle(orientation, { start: null, end: thumbPct, endGap: GAP_PX })
11474
11584
  }
11475
11585
  ),
11476
11586
  /* @__PURE__ */ jsx(
11477
11587
  "div",
11478
11588
  {
11479
11589
  "data-slot": "active-track",
11480
- className: cn(
11481
- sliderActiveTrackVariants({ size, disabled: isDisabled, orientation }),
11482
- trackTransition
11483
- ),
11484
- style: { flexBasis: `${activePct}%` }
11590
+ className: cn(sliderActiveTrackVariants({ size, orientation }), trackTransition),
11591
+ style: segmentStyle(orientation, {
11592
+ start: thumbPct,
11593
+ startGap: GAP_PX,
11594
+ end: zeroPct
11595
+ })
11485
11596
  }
11486
11597
  ),
11487
- handleEl,
11488
11598
  /* @__PURE__ */ jsx(
11489
11599
  "div",
11490
11600
  {
11491
11601
  "data-slot": "inactive-track-right",
11492
- className: cn(
11493
- sliderInactiveTrackVariants({ size, disabled: isDisabled, orientation }),
11494
- trackTransition
11495
- ),
11496
- style: { flexBasis: `${100 - zeroPct}%` }
11602
+ className: cn(sliderInactiveTrackVariants({ size, orientation }), trackTransition),
11603
+ style: segmentStyle(orientation, { start: zeroPct, end: null })
11497
11604
  }
11498
11605
  )
11499
11606
  ] });
@@ -11516,11 +11623,11 @@ var Slider = forwardRef(
11516
11623
  ...value !== void 0 ? { value } : {},
11517
11624
  ...defaultValue !== void 0 ? { defaultValue } : {},
11518
11625
  ...onChangeEnd !== void 0 ? { onChangeEnd } : {},
11519
- className: cn(
11520
- sliderContainerVariants({ size, disabled: isDisabled, orientation }),
11521
- className
11522
- ),
11523
- children: /* @__PURE__ */ jsxs("div", { "data-slot": "track-layout", className: cn(sliderTrackLayoutVariants({ orientation })), children: [
11626
+ renderThumbContent,
11627
+ onThumbDraggingChange: handleThumbDraggingChange,
11628
+ className: cn(sliderContainerVariants({ size, orientation }), className),
11629
+ trackClassName: sliderTrackRegionVariants({ size, orientation }),
11630
+ children: /* @__PURE__ */ jsxs("div", { "data-slot": "track-layout", className: cn(sliderTrackLayoutVariants()), children: [
11524
11631
  isRange ? renderRangeTrack() : isCentered ? renderCenteredTrack() : renderStandardTrack(),
11525
11632
  canShowStops && /* @__PURE__ */ jsx(
11526
11633
  SliderStops,
@@ -11530,7 +11637,7 @@ var Slider = forwardRef(
11530
11637
  step,
11531
11638
  values: currentValues,
11532
11639
  variant,
11533
- isDisabled
11640
+ size
11534
11641
  }
11535
11642
  )
11536
11643
  ] })