@tinybigui/react 0.19.0 → 0.21.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
@@ -6560,7 +6560,6 @@ var snackbarBaseVariants = classVarianceAuthority.cva(
6560
6560
  "min-w-72",
6561
6561
  "max-w-snackbar-max",
6562
6562
  "w-max",
6563
- "min-h-12",
6564
6563
  // Restore pointer events so hover/focus timer pause works
6565
6564
  "pointer-events-auto",
6566
6565
  // Surface
@@ -6571,25 +6570,27 @@ var snackbarBaseVariants = classVarianceAuthority.cva(
6571
6570
  "shadow-elevation-3",
6572
6571
  // Layout
6573
6572
  "flex",
6574
- "items-center",
6575
6573
  "gap-x-1",
6576
- "pl-4 pr-2",
6577
- // Typography
6574
+ "pl-4",
6575
+ // Typography base (inherited by message/supporting-text slots)
6578
6576
  "text-body-medium",
6579
6577
  "text-inverse-on-surface",
6580
- // Transition (properties used by both entry and exit)
6578
+ // Slide + fade transition spring-standard effects tokens (no overshoot).
6579
+ // The translate offset is small (12px), so using the effects token pair for
6580
+ // BOTH opacity AND transform is safe: no visible overshoot at this scale.
6581
6581
  "transition-[opacity,transform]",
6582
6582
  "will-change-[opacity,transform]"
6583
6583
  ],
6584
6584
  {
6585
6585
  variants: {
6586
6586
  /**
6587
- * Whether the Snackbar has supporting text (two-line layout).
6588
- * Adjusts vertical padding to MD3 spec for two-line configuration.
6587
+ * Two-line density mode.
6588
+ * false 48dp, items centered (single-line message)
6589
+ * true — 68dp, items top-aligned (message + supporting text)
6589
6590
  */
6590
6591
  twoLine: {
6591
- true: "py-1",
6592
- false: "py-1"
6592
+ false: ["min-h-12", "items-center", "pr-1"],
6593
+ true: ["min-h-[4.25rem]", "items-start", "pr-1"]
6593
6594
  }
6594
6595
  },
6595
6596
  defaultVariants: {
@@ -6615,53 +6616,211 @@ classVarianceAuthority.cva("", {
6615
6616
  var snackbarAnimationVariants = classVarianceAuthority.cva("", {
6616
6617
  variants: {
6617
6618
  animationState: {
6618
- entering: ["opacity-0", "scale-75"],
6619
- visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
6620
- exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
6621
- exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
6619
+ entering: [],
6620
+ visible: [],
6621
+ exiting: [],
6622
+ exited: []
6622
6623
  },
6623
6624
  enterDirection: {
6624
- up: ["origin-bottom"],
6625
- down: ["origin-top"]
6625
+ up: [],
6626
+ down: []
6626
6627
  }
6627
6628
  },
6628
- defaultVariants: {
6629
- animationState: "entering",
6630
- enterDirection: "up"
6631
- }
6632
- });
6633
- classVarianceAuthority.cva([...snackbarBaseVariants()], {
6634
- variants: {
6635
- animationState: {
6636
- entering: ["opacity-0", "scale-75"],
6637
- visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
6638
- exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
6639
- exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
6629
+ compoundVariants: [
6630
+ // ── entering ──────────────────────────────────────────────────────────────
6631
+ // No transition duration — instant jump to offset state before first paint.
6632
+ {
6633
+ animationState: "entering",
6634
+ enterDirection: "up",
6635
+ className: ["opacity-0", "translate-y-3"]
6640
6636
  },
6641
- enterDirection: {
6642
- up: ["origin-bottom"],
6643
- down: ["origin-top"]
6637
+ {
6638
+ animationState: "entering",
6639
+ enterDirection: "down",
6640
+ className: ["opacity-0", "-translate-y-3"]
6644
6641
  },
6645
- position: {
6646
- "bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
6647
- "bottom-left": ["bottom-4", "left-4"],
6648
- "bottom-right": ["bottom-4", "right-4"],
6649
- "top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
6650
- "top-left": ["top-4", "left-4"],
6651
- "top-right": ["top-4", "right-4"]
6642
+ // ── visible ───────────────────────────────────────────────────────────────
6643
+ // spring-standard default effects = 200ms, no overshoot.
6644
+ {
6645
+ animationState: "visible",
6646
+ enterDirection: "up",
6647
+ className: [
6648
+ "opacity-100",
6649
+ "translate-y-0",
6650
+ "duration-spring-standard-default-effects",
6651
+ "ease-spring-standard-default-effects"
6652
+ ]
6653
+ },
6654
+ {
6655
+ animationState: "visible",
6656
+ enterDirection: "down",
6657
+ className: [
6658
+ "opacity-100",
6659
+ "translate-y-0",
6660
+ "duration-spring-standard-default-effects",
6661
+ "ease-spring-standard-default-effects"
6662
+ ]
6663
+ },
6664
+ // ── exiting ───────────────────────────────────────────────────────────────
6665
+ // spring-standard fast effects = 150ms (quicker exit).
6666
+ {
6667
+ animationState: "exiting",
6668
+ enterDirection: "up",
6669
+ className: [
6670
+ "opacity-0",
6671
+ "translate-y-3",
6672
+ "duration-spring-standard-fast-effects",
6673
+ "ease-spring-standard-fast-effects"
6674
+ ]
6675
+ },
6676
+ {
6677
+ animationState: "exiting",
6678
+ enterDirection: "down",
6679
+ className: [
6680
+ "opacity-0",
6681
+ "-translate-y-3",
6682
+ "duration-spring-standard-fast-effects",
6683
+ "ease-spring-standard-fast-effects"
6684
+ ]
6685
+ },
6686
+ // ── exited ────────────────────────────────────────────────────────────────
6687
+ // Hold final position — element is removed from DOM shortly after.
6688
+ {
6689
+ animationState: "exited",
6690
+ enterDirection: "up",
6691
+ className: ["opacity-0", "translate-y-3"]
6652
6692
  },
6653
- twoLine: {
6654
- true: "py-1",
6655
- false: "py-1"
6693
+ {
6694
+ animationState: "exited",
6695
+ enterDirection: "down",
6696
+ className: ["opacity-0", "-translate-y-3"]
6656
6697
  }
6657
- },
6698
+ ],
6658
6699
  defaultVariants: {
6659
6700
  animationState: "entering",
6660
- enterDirection: "up",
6661
- position: "bottom-center",
6662
- twoLine: false
6701
+ enterDirection: "up"
6663
6702
  }
6664
6703
  });
6704
+ classVarianceAuthority.cva(
6705
+ [
6706
+ "min-w-72",
6707
+ "max-w-snackbar-max",
6708
+ "w-max",
6709
+ "pointer-events-auto",
6710
+ "bg-inverse-surface",
6711
+ "rounded-xs",
6712
+ "shadow-elevation-3",
6713
+ "flex",
6714
+ "gap-x-1",
6715
+ "pl-4",
6716
+ "text-body-medium",
6717
+ "text-inverse-on-surface",
6718
+ "transition-[opacity,transform]",
6719
+ "will-change-[opacity,transform]"
6720
+ ],
6721
+ {
6722
+ variants: {
6723
+ twoLine: {
6724
+ false: ["min-h-12", "items-center", "pr-1"],
6725
+ true: ["min-h-[4.25rem]", "items-start", "pr-1"]
6726
+ },
6727
+ animationState: {
6728
+ entering: [],
6729
+ visible: [],
6730
+ exiting: [],
6731
+ exited: []
6732
+ },
6733
+ enterDirection: {
6734
+ up: [],
6735
+ down: []
6736
+ },
6737
+ position: {
6738
+ "bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
6739
+ "bottom-left": ["bottom-4", "left-4"],
6740
+ "bottom-right": ["bottom-4", "right-4"],
6741
+ "top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
6742
+ "top-left": ["top-4", "left-4"],
6743
+ "top-right": ["top-4", "right-4"]
6744
+ }
6745
+ },
6746
+ compoundVariants: [
6747
+ {
6748
+ animationState: "entering",
6749
+ enterDirection: "up",
6750
+ className: ["opacity-0", "translate-y-3"]
6751
+ },
6752
+ {
6753
+ animationState: "entering",
6754
+ enterDirection: "down",
6755
+ className: ["opacity-0", "-translate-y-3"]
6756
+ },
6757
+ {
6758
+ animationState: "visible",
6759
+ enterDirection: "up",
6760
+ className: [
6761
+ "opacity-100",
6762
+ "translate-y-0",
6763
+ "duration-spring-standard-default-effects",
6764
+ "ease-spring-standard-default-effects"
6765
+ ]
6766
+ },
6767
+ {
6768
+ animationState: "visible",
6769
+ enterDirection: "down",
6770
+ className: [
6771
+ "opacity-100",
6772
+ "translate-y-0",
6773
+ "duration-spring-standard-default-effects",
6774
+ "ease-spring-standard-default-effects"
6775
+ ]
6776
+ },
6777
+ {
6778
+ animationState: "exiting",
6779
+ enterDirection: "up",
6780
+ className: [
6781
+ "opacity-0",
6782
+ "translate-y-3",
6783
+ "duration-spring-standard-fast-effects",
6784
+ "ease-spring-standard-fast-effects"
6785
+ ]
6786
+ },
6787
+ {
6788
+ animationState: "exiting",
6789
+ enterDirection: "down",
6790
+ className: [
6791
+ "opacity-0",
6792
+ "-translate-y-3",
6793
+ "duration-spring-standard-fast-effects",
6794
+ "ease-spring-standard-fast-effects"
6795
+ ]
6796
+ },
6797
+ {
6798
+ animationState: "exited",
6799
+ enterDirection: "up",
6800
+ className: ["opacity-0", "translate-y-3"]
6801
+ },
6802
+ {
6803
+ animationState: "exited",
6804
+ enterDirection: "down",
6805
+ className: ["opacity-0", "-translate-y-3"]
6806
+ }
6807
+ ],
6808
+ defaultVariants: {
6809
+ animationState: "entering",
6810
+ enterDirection: "up",
6811
+ position: "bottom-center",
6812
+ twoLine: false
6813
+ }
6814
+ }
6815
+ );
6816
+ var snackbarContentVariants = classVarianceAuthority.cva([
6817
+ "flex",
6818
+ "flex-col",
6819
+ "flex-1",
6820
+ "min-w-0",
6821
+ "py-3",
6822
+ "pr-2"
6823
+ ]);
6665
6824
  var snackbarMessageVariants = classVarianceAuthority.cva([
6666
6825
  "flex-1",
6667
6826
  "text-body-medium",
@@ -6670,15 +6829,83 @@ var snackbarMessageVariants = classVarianceAuthority.cva([
6670
6829
  var snackbarSupportingTextVariants = classVarianceAuthority.cva([
6671
6830
  "text-body-medium",
6672
6831
  "text-inverse-on-surface",
6673
- "opacity-80"
6832
+ "mt-1"
6674
6833
  ]);
6675
- var snackbarActionVariants = classVarianceAuthority.cva(["shrink-0", "text-inverse-primary"]);
6676
- var snackbarCloseVariants = classVarianceAuthority.cva(["shrink-0", "text-inverse-on-surface"]);
6677
- var snackbarContentVariants = classVarianceAuthority.cva(["flex", "flex-col", "flex-1", "min-w-0 py-2 pr-2"]);
6678
- classVarianceAuthority.cva(["scale-75", "opacity-0"]);
6834
+ classVarianceAuthority.cva(["opacity-0"]);
6679
6835
  function getEnterDirection(position) {
6680
6836
  return position.startsWith("top") ? "down" : "up";
6681
6837
  }
6838
+ var snackbarActionVariants = classVarianceAuthority.cva([
6839
+ // Layout
6840
+ "relative inline-flex items-center justify-center shrink-0",
6841
+ "h-9 px-3",
6842
+ "rounded-full cursor-pointer select-none",
6843
+ // Typography (MD3 text button: label-large)
6844
+ "text-label-large",
6845
+ "text-inverse-primary",
6846
+ // Effects transition (color)
6847
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6848
+ // Disabled
6849
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
6850
+ "data-[disabled]:text-on-surface/38"
6851
+ ]);
6852
+ var snackbarActionStateLayerVariants = classVarianceAuthority.cva([
6853
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
6854
+ "bg-inverse-primary",
6855
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6856
+ // Hover: 8%
6857
+ "group-data-[hovered]/snackbar-action:opacity-8",
6858
+ // Focus: 10%
6859
+ "group-data-[focus-visible]/snackbar-action:opacity-10",
6860
+ // Pressed: 10%, doubled selector wins over hover
6861
+ "group-data-[pressed]/snackbar-action:group-data-[pressed]/snackbar-action:opacity-10",
6862
+ // No state layer when disabled
6863
+ "group-data-[disabled]/snackbar-action:hidden"
6864
+ ]);
6865
+ var snackbarActionFocusRingVariants = classVarianceAuthority.cva([
6866
+ "pointer-events-none absolute inset-[-3px] rounded-full",
6867
+ "outline outline-2 outline-offset-0 outline-inverse-primary",
6868
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6869
+ "opacity-0",
6870
+ "group-data-[focus-visible]/snackbar-action:opacity-100"
6871
+ ]);
6872
+ var snackbarCloseVariants = classVarianceAuthority.cva([
6873
+ // Layout
6874
+ "relative inline-flex items-center justify-center shrink-0",
6875
+ "size-8",
6876
+ "rounded-full cursor-pointer select-none",
6877
+ // Color
6878
+ "text-inverse-on-surface",
6879
+ // Effects transition (color)
6880
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6881
+ // Disabled
6882
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
6883
+ "data-[disabled]:text-on-surface/38"
6884
+ ]);
6885
+ var snackbarCloseStateLayerVariants = classVarianceAuthority.cva([
6886
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
6887
+ "bg-inverse-on-surface",
6888
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6889
+ // Hover: 8%
6890
+ "group-data-[hovered]/snackbar-close:opacity-8",
6891
+ // Focus: 10%
6892
+ "group-data-[focus-visible]/snackbar-close:opacity-10",
6893
+ // Pressed: 10%, doubled selector wins over hover
6894
+ "group-data-[pressed]/snackbar-close:group-data-[pressed]/snackbar-close:opacity-10",
6895
+ // No state layer when disabled
6896
+ "group-data-[disabled]/snackbar-close:hidden"
6897
+ ]);
6898
+ var snackbarCloseFocusRingVariants = classVarianceAuthority.cva([
6899
+ "pointer-events-none absolute inset-[-3px] rounded-full",
6900
+ "outline outline-2 outline-offset-0 outline-inverse-on-surface",
6901
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
6902
+ "opacity-0",
6903
+ "group-data-[focus-visible]/snackbar-close:opacity-100"
6904
+ ]);
6905
+ var snackbarCloseIconVariants = classVarianceAuthority.cva([
6906
+ "relative z-10 inline-flex shrink-0 items-center justify-center",
6907
+ "size-6"
6908
+ ]);
6682
6909
  function CloseIcon() {
6683
6910
  return /* @__PURE__ */ jsxRuntime.jsx(
6684
6911
  "svg",
@@ -6693,6 +6920,52 @@ function CloseIcon() {
6693
6920
  }
6694
6921
  );
6695
6922
  }
6923
+ function SnackbarActionButton({ label, onAction }) {
6924
+ const ref = React.useRef(null);
6925
+ const { buttonProps, isPressed } = reactAria.useButton({ onPress: onAction }, ref);
6926
+ const { isHovered, hoverProps } = reactAria.useHover({});
6927
+ const { isFocusVisible, focusProps } = reactAria.useFocusRing();
6928
+ const { onMouseDown, ripples } = useRipple();
6929
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6930
+ "button",
6931
+ {
6932
+ type: "button",
6933
+ ...reactAria.mergeProps(buttonProps, hoverProps, focusProps, { onMouseDown }),
6934
+ ref,
6935
+ className: cn(snackbarActionVariants(), "group/snackbar-action"),
6936
+ ...getInteractionDataAttributes({ isHovered, isFocusVisible, isPressed }),
6937
+ children: [
6938
+ ripples,
6939
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarActionStateLayerVariants(), "aria-hidden": "true" }),
6940
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarActionFocusRingVariants(), "aria-hidden": "true" }),
6941
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: label })
6942
+ ]
6943
+ }
6944
+ );
6945
+ }
6946
+ function SnackbarCloseButton({ onPress }) {
6947
+ const ref = React.useRef(null);
6948
+ const { buttonProps, isPressed } = reactAria.useButton({ onPress, "aria-label": "Close" }, ref);
6949
+ const { isHovered, hoverProps } = reactAria.useHover({});
6950
+ const { isFocusVisible, focusProps } = reactAria.useFocusRing();
6951
+ const { onMouseDown, ripples } = useRipple();
6952
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6953
+ "button",
6954
+ {
6955
+ type: "button",
6956
+ ...reactAria.mergeProps(buttonProps, hoverProps, focusProps, { onMouseDown }),
6957
+ ref,
6958
+ className: cn(snackbarCloseVariants(), "group/snackbar-close"),
6959
+ ...getInteractionDataAttributes({ isHovered, isFocusVisible, isPressed }),
6960
+ children: [
6961
+ ripples,
6962
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarCloseStateLayerVariants(), "aria-hidden": "true" }),
6963
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarCloseFocusRingVariants(), "aria-hidden": "true" }),
6964
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarCloseIconVariants(), "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) })
6965
+ ]
6966
+ }
6967
+ );
6968
+ }
6696
6969
  var Snackbar = React.forwardRef(function Snackbar2({
6697
6970
  message,
6698
6971
  supportingText,
@@ -6705,6 +6978,7 @@ var Snackbar = React.forwardRef(function Snackbar2({
6705
6978
  className
6706
6979
  }, ref) {
6707
6980
  const isTwoLine = Boolean(supportingText);
6981
+ const reducedMotion = useReducedMotion();
6708
6982
  const baseClassName = cn(snackbarBaseVariants({ twoLine: isTwoLine }), className);
6709
6983
  return /* @__PURE__ */ jsxRuntime.jsx(
6710
6984
  SnackbarHeadless,
@@ -6719,31 +6993,22 @@ var Snackbar = React.forwardRef(function Snackbar2({
6719
6993
  position,
6720
6994
  ...onClose !== void 0 && { onClose },
6721
6995
  className: baseClassName,
6722
- getAnimationClassName: (state, pos) => snackbarAnimationVariants({ animationState: state, enterDirection: getEnterDirection(pos) }),
6996
+ getAnimationClassName: (state, pos) => {
6997
+ if (reducedMotion) {
6998
+ return state === "visible" ? "opacity-100 duration-spring-standard-default-effects ease-spring-standard-default-effects" : "opacity-0";
6999
+ }
7000
+ return snackbarAnimationVariants({
7001
+ animationState: state,
7002
+ enterDirection: getEnterDirection(pos)
7003
+ });
7004
+ },
6723
7005
  children: ({ onClose: triggerClose }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6724
7006
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: snackbarContentVariants(), children: [
6725
7007
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarMessageVariants(), children: message }),
6726
7008
  supportingText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarSupportingTextVariants(), children: supportingText })
6727
7009
  ] }),
6728
- action && /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarActionVariants(), children: /* @__PURE__ */ jsxRuntime.jsx(
6729
- Button,
6730
- {
6731
- variant: "text",
6732
- onPress: action.onAction,
6733
- className: "text-inverse-primary hover:text-inverse-primary px-3",
6734
- children: action.label
6735
- }
6736
- ) }),
6737
- showClose && /* @__PURE__ */ jsxRuntime.jsx("span", { className: snackbarCloseVariants(), children: /* @__PURE__ */ jsxRuntime.jsx(
6738
- IconButton,
6739
- {
6740
- variant: "standard",
6741
- "aria-label": "Close",
6742
- onPress: triggerClose,
6743
- className: "text-inverse-on-surface hover:text-inverse-on-surface",
6744
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
6745
- }
6746
- ) })
7010
+ action && /* @__PURE__ */ jsxRuntime.jsx(SnackbarActionButton, { label: action.label, onAction: action.onAction }),
7011
+ showClose && /* @__PURE__ */ jsxRuntime.jsx(SnackbarCloseButton, { onPress: triggerClose })
6747
7012
  ] })
6748
7013
  }
6749
7014
  );
@@ -9367,105 +9632,354 @@ var Badge = React.forwardRef(
9367
9632
  }
9368
9633
  );
9369
9634
  Badge.displayName = "Badge";
9370
- var splitButtonContainerVariants = classVarianceAuthority.cva(
9371
- ["inline-flex items-center rounded-full overflow-hidden"],
9635
+ var splitButtonContainerVariants = classVarianceAuthority.cva([
9636
+ "relative inline-flex items-stretch",
9637
+ "gap-0.5"
9638
+ // MD3 2dp gap between segments
9639
+ ]);
9640
+ var splitButtonLeadingVariants = classVarianceAuthority.cva(
9641
+ [
9642
+ // Layout
9643
+ "group/sb-leading relative inline-flex items-center justify-center",
9644
+ "cursor-pointer select-none",
9645
+ // Shape — asymmetric corners via CSS variable
9646
+ "rounded-tl-full rounded-bl-full",
9647
+ "rounded-tr-[var(--sb-inner-radius,var(--radius-xs))]",
9648
+ "rounded-br-[var(--sb-inner-radius,var(--radius-xs))]",
9649
+ // Inner-corner morph — xs/sm/md defaults; lg/xl override in size variants below.
9650
+ // Specificity ladder: rest (0,0,0) < hover (0,1,0) < focus (0,2,0) < pressed (0,3,0)
9651
+ "[--sb-inner-radius:var(--radius-xs)]",
9652
+ "data-[hovered]:[--sb-inner-radius:var(--radius-sm)]",
9653
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-sm)]",
9654
+ // Pressed morphs stronger than hover/focus — tripled selector → (0,3,0)
9655
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-lg)]",
9656
+ // Spatial transition for border-radius morphing
9657
+ "transition-[border-radius]",
9658
+ "duration-expressive-fast-spatial ease-expressive-fast-spatial",
9659
+ // Disabled — self-targeting
9660
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none"
9661
+ ],
9372
9662
  {
9373
9663
  variants: {
9664
+ /**
9665
+ * Visual variant — controls container color, text color, and elevation.
9666
+ * State layer color is handled in splitButtonStateLayerVariants.
9667
+ */
9374
9668
  variant: {
9375
- filled: "bg-primary shadow-elevation-0 hover:shadow-elevation-1",
9376
- tonal: "bg-secondary-container",
9377
- outlined: "border border-outline bg-transparent"
9669
+ /**
9670
+ * Filled — highest emphasis.
9671
+ * container=primary, label=on-primary
9672
+ * Elevation: 0 base → 1 hover → 0 focus/pressed
9673
+ */
9674
+ filled: [
9675
+ "bg-primary text-on-primary shadow-none",
9676
+ "group-data-[hovered]/sb-leading:shadow-elevation-1",
9677
+ "group-data-[focus-visible]/sb-leading:shadow-none",
9678
+ "group-data-[pressed]/sb-leading:group-data-[pressed]/sb-leading:shadow-none",
9679
+ // Disabled
9680
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9681
+ ],
9682
+ /**
9683
+ * Tonal — secondary emphasis.
9684
+ * container=secondary-container, label=on-secondary-container
9685
+ * Elevation: 0 base → 1 hover → 0 focus/pressed
9686
+ */
9687
+ tonal: [
9688
+ "bg-secondary-container text-on-secondary-container shadow-none",
9689
+ "group-data-[hovered]/sb-leading:shadow-elevation-1",
9690
+ "group-data-[focus-visible]/sb-leading:shadow-none",
9691
+ "group-data-[pressed]/sb-leading:group-data-[pressed]/sb-leading:shadow-none",
9692
+ // Disabled
9693
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9694
+ ],
9695
+ /**
9696
+ * Outlined — medium emphasis. Transparent with border.
9697
+ * container=transparent, border=outline, label=primary
9698
+ * Elevation: always 0
9699
+ */
9700
+ outlined: [
9701
+ "bg-transparent border border-outline text-primary",
9702
+ // Disabled
9703
+ "data-[disabled]:border-on-surface/12 data-[disabled]:text-on-surface/38"
9704
+ ],
9705
+ /**
9706
+ * Elevated — uses surface-container-low with a level-1 shadow base.
9707
+ * container=surface-container-low, label=primary
9708
+ * Elevation: 1 base → 2 hover → 1 focus/pressed
9709
+ */
9710
+ elevated: [
9711
+ "bg-surface-container-low text-primary shadow-elevation-1",
9712
+ "group-data-[hovered]/sb-leading:shadow-elevation-2",
9713
+ "group-data-[focus-visible]/sb-leading:shadow-elevation-1",
9714
+ "group-data-[pressed]/sb-leading:group-data-[pressed]/sb-leading:shadow-elevation-1",
9715
+ // Disabled
9716
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9717
+ ]
9378
9718
  },
9719
+ /**
9720
+ * Size — governs height, horizontal padding, typography, and inner-corner rest/morph values.
9721
+ * lg/xl need larger rest radii so their morph steps differ from xs/sm/md.
9722
+ */
9379
9723
  size: {
9380
- small: "h-8",
9381
- medium: "h-10",
9382
- large: "h-12"
9383
- },
9384
- isDisabled: {
9385
- true: "opacity-38 pointer-events-none",
9386
- false: ""
9724
+ xs: "h-8 pl-4 pr-3 text-label-large",
9725
+ sm: "h-10 pl-6 pr-4 text-label-large",
9726
+ md: "h-14 pl-8 pr-6 text-title-medium",
9727
+ lg: [
9728
+ "h-24 pl-10 pr-8 text-headline-small",
9729
+ // lg rest=sm, hover/focus→lg, pressed→xl
9730
+ "[--sb-inner-radius:var(--radius-sm)]",
9731
+ "data-[hovered]:[--sb-inner-radius:var(--radius-lg)]",
9732
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-lg)]",
9733
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-xl)]"
9734
+ ],
9735
+ xl: [
9736
+ "h-[8.5rem] pl-12 pr-10 text-headline-large",
9737
+ // xl rest=md, hover/focus→lg, pressed→xl
9738
+ "[--sb-inner-radius:var(--radius-md)]",
9739
+ "data-[hovered]:[--sb-inner-radius:var(--radius-lg)]",
9740
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-lg)]",
9741
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-xl)]"
9742
+ ]
9387
9743
  }
9388
9744
  },
9389
9745
  defaultVariants: {
9390
9746
  variant: "filled",
9391
- size: "medium",
9392
- isDisabled: false
9747
+ size: "sm"
9393
9748
  }
9394
9749
  }
9395
9750
  );
9396
- var splitButtonPrimaryVariants = classVarianceAuthority.cva(
9751
+ var splitButtonTrailingVariants = classVarianceAuthority.cva(
9397
9752
  [
9398
- "group/primary relative inline-flex items-center justify-center cursor-pointer",
9399
- "h-full font-medium tracking-[0.1px]",
9400
- "focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2"
9753
+ // Layout square so that selected (rounded-full on all corners) = perfect circle
9754
+ "group/sb-trailing relative inline-flex items-center justify-center shrink-0",
9755
+ "cursor-pointer select-none",
9756
+ // Shape — asymmetric corners, inner on the left side
9757
+ "rounded-tr-full rounded-br-full",
9758
+ "rounded-tl-[var(--sb-inner-radius,var(--radius-xs))]",
9759
+ "rounded-bl-[var(--sb-inner-radius,var(--radius-xs))]",
9760
+ // Inner-corner morph — xs/sm/md defaults; lg/xl override in size variants below.
9761
+ // Specificity ladder: rest (0,0,0) < hover (0,1,0) < focus (0,2,0) < pressed (0,3,0) < selected (0,4,0)
9762
+ "[--sb-inner-radius:var(--radius-xs)]",
9763
+ "data-[hovered]:[--sb-inner-radius:var(--radius-sm)]",
9764
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-sm)]",
9765
+ // Pressed morphs stronger than hover/focus — tripled → (0,3,0)
9766
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-lg)]",
9767
+ // Selected (menu open) → full circle; quadrupled → (0,4,0) always wins
9768
+ "data-[selected]:data-[selected]:data-[selected]:data-[selected]:[--sb-inner-radius:var(--radius-full)]",
9769
+ // Spatial transition for border-radius morphing
9770
+ "transition-[border-radius]",
9771
+ "duration-expressive-fast-spatial ease-expressive-fast-spatial",
9772
+ // Disabled — self-targeting
9773
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none"
9401
9774
  ],
9402
9775
  {
9403
9776
  variants: {
9404
9777
  variant: {
9405
- filled: "text-on-primary",
9406
- tonal: "text-on-secondary-container",
9407
- outlined: "text-primary"
9778
+ filled: [
9779
+ "bg-primary text-on-primary shadow-none",
9780
+ "group-data-[hovered]/sb-trailing:shadow-elevation-1",
9781
+ "group-data-[focus-visible]/sb-trailing:shadow-none",
9782
+ "group-data-[pressed]/sb-trailing:group-data-[pressed]/sb-trailing:shadow-none",
9783
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9784
+ ],
9785
+ tonal: [
9786
+ "bg-secondary-container text-on-secondary-container shadow-none",
9787
+ "group-data-[hovered]/sb-trailing:shadow-elevation-1",
9788
+ "group-data-[focus-visible]/sb-trailing:shadow-none",
9789
+ "group-data-[pressed]/sb-trailing:group-data-[pressed]/sb-trailing:shadow-none",
9790
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9791
+ ],
9792
+ outlined: [
9793
+ "bg-transparent border border-outline text-primary",
9794
+ "data-[disabled]:border-on-surface/12 data-[disabled]:text-on-surface/38"
9795
+ ],
9796
+ elevated: [
9797
+ "bg-surface-container-low text-primary shadow-elevation-1",
9798
+ "group-data-[hovered]/sb-trailing:shadow-elevation-2",
9799
+ "group-data-[focus-visible]/sb-trailing:shadow-elevation-1",
9800
+ "group-data-[pressed]/sb-trailing:group-data-[pressed]/sb-trailing:shadow-elevation-1",
9801
+ "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38 data-[disabled]:shadow-none"
9802
+ ]
9408
9803
  },
9409
9804
  size: {
9410
- small: "pl-4 pr-3 text-xs",
9411
- medium: "pl-6 pr-4 text-sm",
9412
- large: "pl-8 pr-5 text-base"
9805
+ // Square dimensions (width = height) so selected state = perfect circle.
9806
+ // Per-size inner-radius rest/morph values mirror the leading segment.
9807
+ xs: "h-8 w-8",
9808
+ sm: "h-10 w-10",
9809
+ md: "h-14 w-14",
9810
+ lg: [
9811
+ "h-24 w-24",
9812
+ // lg rest=sm, hover/focus→lg, pressed→xl; selected→full handled in base classes
9813
+ "[--sb-inner-radius:var(--radius-sm)]",
9814
+ "data-[hovered]:[--sb-inner-radius:var(--radius-lg)]",
9815
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-lg)]",
9816
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-xl)]"
9817
+ ],
9818
+ xl: [
9819
+ "h-[8.5rem] w-[8.5rem]",
9820
+ // xl rest=md, hover/focus→lg, pressed→xl; selected→full handled in base classes
9821
+ "[--sb-inner-radius:var(--radius-md)]",
9822
+ "data-[hovered]:[--sb-inner-radius:var(--radius-lg)]",
9823
+ "data-[focus-visible]:data-[focus-visible]:[--sb-inner-radius:var(--radius-lg)]",
9824
+ "data-[pressed]:data-[pressed]:data-[pressed]:[--sb-inner-radius:var(--radius-xl)]"
9825
+ ]
9413
9826
  }
9414
9827
  },
9415
9828
  defaultVariants: {
9416
9829
  variant: "filled",
9417
- size: "medium"
9830
+ size: "sm"
9418
9831
  }
9419
9832
  }
9420
9833
  );
9421
- var splitButtonDropdownVariants = classVarianceAuthority.cva(
9834
+ var splitButtonStateLayerVariants = classVarianceAuthority.cva(
9422
9835
  [
9423
- "group/dropdown relative inline-flex items-center justify-center cursor-pointer",
9424
- "h-full",
9425
- "focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2"
9836
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
9837
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
9426
9838
  ],
9427
9839
  {
9428
9840
  variants: {
9429
9841
  variant: {
9430
- filled: "text-on-primary border-l border-on-primary/38",
9431
- tonal: "text-on-secondary-container border-l border-on-secondary-container/38",
9432
- outlined: "text-primary border-l border-outline"
9842
+ filled: "bg-on-primary",
9843
+ tonal: "bg-on-secondary-container",
9844
+ outlined: "bg-primary",
9845
+ elevated: "bg-primary"
9433
9846
  },
9434
- size: {
9435
- small: "px-1.5",
9436
- medium: "px-2",
9437
- large: "px-3"
9847
+ /**
9848
+ * groupScope identifies which segment this state layer belongs to so it
9849
+ * reads from the correct group-data-[x]/<scope> selectors.
9850
+ */
9851
+ groupScope: {
9852
+ leading: [
9853
+ "group-data-[hovered]/sb-leading:opacity-8",
9854
+ "group-data-[focus-visible]/sb-leading:opacity-10",
9855
+ "group-data-[pressed]/sb-leading:group-data-[pressed]/sb-leading:opacity-10",
9856
+ "group-data-[disabled]/sb-leading:hidden"
9857
+ ],
9858
+ trailing: [
9859
+ "group-data-[hovered]/sb-trailing:opacity-8",
9860
+ "group-data-[focus-visible]/sb-trailing:opacity-10",
9861
+ "group-data-[pressed]/sb-trailing:group-data-[pressed]/sb-trailing:opacity-10",
9862
+ "group-data-[disabled]/sb-trailing:hidden"
9863
+ ]
9438
9864
  }
9439
9865
  },
9440
9866
  defaultVariants: {
9441
9867
  variant: "filled",
9442
- size: "medium"
9868
+ groupScope: "leading"
9443
9869
  }
9444
9870
  }
9445
9871
  );
9872
+ var splitButtonFocusRingVariants = classVarianceAuthority.cva(
9873
+ [
9874
+ "pointer-events-none absolute inset-[-3px]",
9875
+ "outline outline-2 outline-offset-0 outline-secondary",
9876
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
9877
+ "opacity-0"
9878
+ ],
9879
+ {
9880
+ variants: {
9881
+ /**
9882
+ * Corner shape must match the segment it wraps.
9883
+ * Leading: full-left, inner-right follows --sb-inner-radius.
9884
+ * Trailing: full-right, inner-left follows --sb-inner-radius.
9885
+ */
9886
+ groupScope: {
9887
+ leading: [
9888
+ "rounded-tl-full rounded-bl-full",
9889
+ "rounded-tr-[calc(var(--sb-inner-radius,var(--radius-xs))+3px)]",
9890
+ "rounded-br-[calc(var(--sb-inner-radius,var(--radius-xs))+3px)]",
9891
+ "group-data-[focus-visible]/sb-leading:opacity-100"
9892
+ ],
9893
+ trailing: [
9894
+ "rounded-tr-full rounded-br-full",
9895
+ "rounded-tl-[calc(var(--sb-inner-radius,var(--radius-xs))+3px)]",
9896
+ "rounded-bl-[calc(var(--sb-inner-radius,var(--radius-xs))+3px)]",
9897
+ "group-data-[focus-visible]/sb-trailing:opacity-100"
9898
+ ]
9899
+ }
9900
+ },
9901
+ defaultVariants: { groupScope: "leading" }
9902
+ }
9903
+ );
9904
+ var splitButtonLabelVariants = classVarianceAuthority.cva(["relative z-10 inline-flex items-center"]);
9905
+ var splitButtonIconVariants = classVarianceAuthority.cva(
9906
+ [
9907
+ "relative z-10 inline-flex shrink-0 items-center justify-center",
9908
+ // Spatial spring motion for the optical-offset translate
9909
+ "transition-transform duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial",
9910
+ // Reset offset when the trailing segment is in selected state (menu open)
9911
+ "group-data-[selected]/sb-trailing:translate-x-0"
9912
+ ],
9913
+ {
9914
+ variants: {
9915
+ size: {
9916
+ // Include per-size icon dimension + unselected optical offset
9917
+ xs: ["size-5", "-translate-x-px"],
9918
+ sm: ["size-5", "-translate-x-px"],
9919
+ md: ["size-6", "-translate-x-0.5"],
9920
+ lg: ["size-8", "-translate-x-[3px]"],
9921
+ xl: ["size-10", "-translate-x-[6px]"]
9922
+ }
9923
+ },
9924
+ defaultVariants: { size: "sm" }
9925
+ }
9926
+ );
9927
+ var splitButtonMenuVariants = classVarianceAuthority.cva([
9928
+ "absolute top-full right-0 z-50 mt-1 min-w-40",
9929
+ "bg-surface-container rounded-md py-2",
9930
+ "shadow-elevation-2",
9931
+ "animate-md-scale-in"
9932
+ ]);
9933
+ var splitButtonMenuItemVariants = classVarianceAuthority.cva(
9934
+ [
9935
+ "text-body-large text-on-surface cursor-pointer px-4 py-2",
9936
+ "hover:bg-on-surface/8",
9937
+ "focus:bg-on-surface/10 focus:outline-none"
9938
+ ],
9939
+ {
9940
+ variants: {
9941
+ isDisabled: {
9942
+ true: "text-on-surface/38 pointer-events-none cursor-not-allowed",
9943
+ false: ""
9944
+ }
9945
+ },
9946
+ defaultVariants: { isDisabled: false }
9947
+ }
9948
+ );
9446
9949
  var splitButtonVariants = {
9447
9950
  container: splitButtonContainerVariants,
9448
- primary: splitButtonPrimaryVariants,
9449
- dropdown: splitButtonDropdownVariants
9951
+ leading: splitButtonLeadingVariants,
9952
+ trailing: splitButtonTrailingVariants,
9953
+ stateLayer: splitButtonStateLayerVariants,
9954
+ focusRing: splitButtonFocusRingVariants,
9955
+ label: splitButtonLabelVariants,
9956
+ icon: splitButtonIconVariants,
9957
+ menu: splitButtonMenuVariants,
9958
+ menuItem: splitButtonMenuItemVariants
9450
9959
  };
9451
- var ChevronIcon = ({ isOpen }) => /* @__PURE__ */ jsxRuntime.jsx(
9960
+ var ChevronIcon = ({
9961
+ isOpen,
9962
+ reducedMotion
9963
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
9452
9964
  "svg",
9453
9965
  {
9454
9966
  "aria-hidden": "true",
9455
9967
  "data-testid": "split-button-chevron",
9456
- width: "18",
9457
- height: "18",
9458
9968
  viewBox: "0 0 24 24",
9459
9969
  fill: "none",
9460
9970
  xmlns: "http://www.w3.org/2000/svg",
9461
- className: cn("duration-short4 ease-standard transition-transform", isOpen && "rotate-180"),
9971
+ className: cn(
9972
+ "size-full",
9973
+ !reducedMotion && "duration-expressive-fast-spatial ease-expressive-fast-spatial transition-transform",
9974
+ isOpen && "rotate-180"
9975
+ ),
9462
9976
  children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 10l5 5 5-5H7z", fill: "currentColor" })
9463
9977
  }
9464
9978
  );
9465
9979
  var SplitButton = React.forwardRef(
9466
9980
  ({
9467
9981
  variant = "filled",
9468
- size = "medium",
9982
+ size = "sm",
9469
9983
  primaryLabel,
9470
9984
  onPrimaryAction,
9471
9985
  items,
@@ -9473,32 +9987,73 @@ var SplitButton = React.forwardRef(
9473
9987
  "aria-label": ariaLabel,
9474
9988
  className
9475
9989
  }, forwardedRef) => {
9476
- const primaryRef = React.useRef(null);
9477
- const dropdownRef = React.useRef(null);
9990
+ const leadingRef = React.useRef(null);
9991
+ const trailingRef = React.useRef(null);
9478
9992
  const menuRef = React.useRef(null);
9993
+ const reducedMotion = useReducedMotion();
9479
9994
  const menuState = reactStately.useMenuTriggerState({});
9480
- const { buttonProps: primaryButtonProps } = reactAria.useButton(
9995
+ const [isLeadingPressed, setIsLeadingPressed] = React.useState(false);
9996
+ const handleLeadingPressStart = React.useCallback(() => setIsLeadingPressed(true), []);
9997
+ const handleLeadingPressEnd = React.useCallback(() => setIsLeadingPressed(false), []);
9998
+ const { isHovered: isLeadingHovered, hoverProps: leadingHoverProps } = reactAria.useHover({
9999
+ isDisabled
10000
+ });
10001
+ const { isFocusVisible: isLeadingFocusVisible, focusProps: leadingFocusProps } = reactAria.useFocusRing();
10002
+ const { buttonProps: leadingButtonProps } = reactAria.useButton(
9481
10003
  {
9482
10004
  isDisabled,
9483
10005
  onPress: onPrimaryAction,
10006
+ onPressStart: handleLeadingPressStart,
10007
+ onPressEnd: handleLeadingPressEnd,
9484
10008
  elementType: "button"
9485
10009
  },
9486
- primaryRef
10010
+ leadingRef
9487
10011
  );
9488
- const handleDropdownPress = React.useCallback(() => {
10012
+ const [isTrailingPressed, setIsTrailingPressed] = React.useState(false);
10013
+ const handleTrailingPressStart = React.useCallback(() => setIsTrailingPressed(true), []);
10014
+ const handleTrailingPressEnd = React.useCallback(() => setIsTrailingPressed(false), []);
10015
+ const { isHovered: isTrailingHovered, hoverProps: trailingHoverProps } = reactAria.useHover({
10016
+ isDisabled
10017
+ });
10018
+ const { isFocusVisible: isTrailingFocusVisible, focusProps: trailingFocusProps } = reactAria.useFocusRing();
10019
+ const handleTrailingPress = React.useCallback(() => {
9489
10020
  if (menuState.isOpen) {
9490
10021
  menuState.close();
9491
10022
  } else {
9492
10023
  menuState.open();
9493
10024
  }
9494
10025
  }, [menuState]);
9495
- const { buttonProps: dropdownButtonProps } = reactAria.useButton(
10026
+ const { buttonProps: trailingButtonProps } = reactAria.useButton(
9496
10027
  {
9497
10028
  isDisabled,
9498
- onPress: handleDropdownPress,
10029
+ onPress: handleTrailingPress,
10030
+ onPressStart: handleTrailingPressStart,
10031
+ onPressEnd: handleTrailingPressEnd,
9499
10032
  elementType: "button"
9500
10033
  },
9501
- dropdownRef
10034
+ trailingRef
10035
+ );
10036
+ const { onMouseDown: handleLeadingRipple, ripples: leadingRipples } = useRipple({
10037
+ disabled: isDisabled
10038
+ });
10039
+ const { onMouseDown: handleTrailingRipple, ripples: trailingRipples } = useRipple({
10040
+ disabled: isDisabled
10041
+ });
10042
+ const onLeadingMouseDown = React.useCallback(
10043
+ (e) => {
10044
+ const ariaHandler = leadingButtonProps.onMouseDown;
10045
+ ariaHandler?.(e);
10046
+ handleLeadingRipple(e);
10047
+ },
10048
+ [leadingButtonProps, handleLeadingRipple]
10049
+ );
10050
+ const onTrailingMouseDown = React.useCallback(
10051
+ (e) => {
10052
+ const ariaHandler = trailingButtonProps.onMouseDown;
10053
+ ariaHandler?.(e);
10054
+ handleTrailingRipple(e);
10055
+ },
10056
+ [trailingButtonProps, handleTrailingRipple]
9502
10057
  );
9503
10058
  const handleMenuItemSelect = React.useCallback(
9504
10059
  (item) => {
@@ -9514,13 +10069,11 @@ var SplitButton = React.forwardRef(
9514
10069
  const handleGlobalKeyDown = (e) => {
9515
10070
  if (e.key === "Escape") {
9516
10071
  menuState.close();
9517
- dropdownRef.current?.focus();
10072
+ trailingRef.current?.focus();
9518
10073
  }
9519
10074
  };
9520
10075
  document.addEventListener("keydown", handleGlobalKeyDown);
9521
- return () => {
9522
- document.removeEventListener("keydown", handleGlobalKeyDown);
9523
- };
10076
+ return () => document.removeEventListener("keydown", handleGlobalKeyDown);
9524
10077
  }, [menuState, menuState.isOpen]);
9525
10078
  const handleMenuKeyDown = React.useCallback(
9526
10079
  (e) => {
@@ -9553,7 +10106,7 @@ var SplitButton = React.forwardRef(
9553
10106
  }
9554
10107
  case "Escape": {
9555
10108
  menuState.close();
9556
- dropdownRef.current?.focus();
10109
+ trailingRef.current?.focus();
9557
10110
  break;
9558
10111
  }
9559
10112
  }
@@ -9578,28 +10131,6 @@ var SplitButton = React.forwardRef(
9578
10131
  },
9579
10132
  [menuState]
9580
10133
  );
9581
- const { onMouseDown: handlePrimaryRipple, ripples: primaryRipples } = useRipple({
9582
- disabled: isDisabled
9583
- });
9584
- const { onMouseDown: handleDropdownRipple, ripples: dropdownRipples } = useRipple({
9585
- disabled: isDisabled
9586
- });
9587
- const onPrimaryMouseDown = React.useCallback(
9588
- (e) => {
9589
- const ariaHandler = primaryButtonProps.onMouseDown;
9590
- ariaHandler?.(e);
9591
- handlePrimaryRipple(e);
9592
- },
9593
- [primaryButtonProps, handlePrimaryRipple]
9594
- );
9595
- const onDropdownMouseDown = React.useCallback(
9596
- (e) => {
9597
- const ariaHandler = dropdownButtonProps.onMouseDown;
9598
- ariaHandler?.(e);
9599
- handleDropdownRipple(e);
9600
- },
9601
- [dropdownButtonProps, handleDropdownRipple]
9602
- );
9603
10134
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative inline-flex", children: [
9604
10135
  /* @__PURE__ */ jsxRuntime.jsxs(
9605
10136
  "div",
@@ -9607,63 +10138,81 @@ var SplitButton = React.forwardRef(
9607
10138
  ref: forwardedRef,
9608
10139
  role: "group",
9609
10140
  "aria-label": ariaLabel ?? `${primaryLabel} split button`,
9610
- className: cn(splitButtonContainerVariants({ variant, size, isDisabled }), className),
10141
+ className: cn(splitButtonContainerVariants(), className),
9611
10142
  children: [
9612
10143
  /* @__PURE__ */ jsxRuntime.jsxs(
9613
10144
  "button",
9614
10145
  {
9615
- ...primaryButtonProps,
9616
- ref: primaryRef,
10146
+ ...reactAria.mergeProps(leadingButtonProps, leadingHoverProps, leadingFocusProps),
10147
+ ref: leadingRef,
9617
10148
  type: "button",
9618
10149
  tabIndex: isDisabled ? -1 : 0,
9619
- onMouseDown: onPrimaryMouseDown,
9620
- className: splitButtonPrimaryVariants({ variant, size }),
10150
+ onMouseDown: onLeadingMouseDown,
10151
+ ...getInteractionDataAttributes({
10152
+ isHovered: isLeadingHovered,
10153
+ isFocusVisible: isLeadingFocusVisible,
10154
+ isPressed: isLeadingPressed,
10155
+ isDisabled
10156
+ }),
10157
+ className: splitButtonLeadingVariants({ variant, size }),
9621
10158
  children: [
9622
10159
  /* @__PURE__ */ jsxRuntime.jsx(
9623
10160
  "span",
9624
10161
  {
9625
10162
  "data-testid": "primary-state-layer",
9626
10163
  "aria-hidden": "true",
9627
- className: cn(
9628
- "pointer-events-none absolute inset-0 bg-current opacity-0",
9629
- "duration-spring-standard-fast-effects ease-spring-standard-fast-effects transition-opacity",
9630
- "group-hover/primary:opacity-8"
9631
- )
10164
+ className: splitButtonStateLayerVariants({ variant, groupScope: "leading" })
9632
10165
  }
9633
10166
  ),
9634
- primaryRipples,
9635
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: primaryLabel })
10167
+ leadingRipples,
10168
+ /* @__PURE__ */ jsxRuntime.jsx(
10169
+ "span",
10170
+ {
10171
+ "aria-hidden": "true",
10172
+ className: splitButtonFocusRingVariants({ groupScope: "leading" })
10173
+ }
10174
+ ),
10175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: splitButtonLabelVariants(), children: primaryLabel })
9636
10176
  ]
9637
10177
  }
9638
10178
  ),
9639
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "split-button-divider", "aria-hidden": "true" }),
9640
10179
  /* @__PURE__ */ jsxRuntime.jsxs(
9641
10180
  "button",
9642
10181
  {
9643
- ...dropdownButtonProps,
9644
- ref: dropdownRef,
10182
+ ...reactAria.mergeProps(trailingButtonProps, trailingHoverProps, trailingFocusProps),
10183
+ ref: trailingRef,
9645
10184
  type: "button",
9646
10185
  tabIndex: isDisabled ? -1 : 0,
9647
10186
  "aria-haspopup": "menu",
9648
10187
  "aria-expanded": menuState.isOpen,
9649
10188
  "aria-label": `${primaryLabel} options, expand`,
9650
- onMouseDown: onDropdownMouseDown,
9651
- className: splitButtonDropdownVariants({ variant, size }),
10189
+ onMouseDown: onTrailingMouseDown,
10190
+ ...getInteractionDataAttributes({
10191
+ isHovered: isTrailingHovered,
10192
+ isFocusVisible: isTrailingFocusVisible,
10193
+ isPressed: isTrailingPressed,
10194
+ isSelected: menuState.isOpen,
10195
+ isDisabled
10196
+ }),
10197
+ className: splitButtonTrailingVariants({ variant, size }),
9652
10198
  children: [
9653
10199
  /* @__PURE__ */ jsxRuntime.jsx(
9654
10200
  "span",
9655
10201
  {
9656
10202
  "data-testid": "dropdown-state-layer",
9657
10203
  "aria-hidden": "true",
9658
- className: cn(
9659
- "pointer-events-none absolute inset-0 bg-current opacity-0",
9660
- "duration-spring-standard-fast-effects ease-spring-standard-fast-effects transition-opacity",
9661
- "group-hover/dropdown:opacity-8"
9662
- )
10204
+ className: splitButtonStateLayerVariants({ variant, groupScope: "trailing" })
9663
10205
  }
9664
10206
  ),
9665
- dropdownRipples,
9666
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { isOpen: menuState.isOpen }) })
10207
+ trailingRipples,
10208
+ /* @__PURE__ */ jsxRuntime.jsx(
10209
+ "span",
10210
+ {
10211
+ "aria-hidden": "true",
10212
+ className: splitButtonFocusRingVariants({ groupScope: "trailing" })
10213
+ }
10214
+ ),
10215
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: splitButtonIconVariants({ size }), children: /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { isOpen: menuState.isOpen, reducedMotion }) })
9667
10216
  ]
9668
10217
  }
9669
10218
  )
@@ -9677,10 +10226,7 @@ var SplitButton = React.forwardRef(
9677
10226
  role: "menu",
9678
10227
  "aria-label": `${primaryLabel} options`,
9679
10228
  onKeyDown: handleMenuKeyDown,
9680
- className: cn(
9681
- "bg-surface-container absolute top-full right-0 z-50 mt-1 min-w-40 rounded-md py-2",
9682
- "shadow-elevation-2"
9683
- ),
10229
+ className: splitButtonMenuVariants(),
9684
10230
  children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
9685
10231
  "li",
9686
10232
  {
@@ -9689,11 +10235,7 @@ var SplitButton = React.forwardRef(
9689
10235
  "aria-disabled": item.isDisabled ?? void 0,
9690
10236
  onClick: () => handleMenuItemSelect(item),
9691
10237
  onKeyDown: (e) => handleMenuItemKeyDown(e, item),
9692
- className: cn(
9693
- "text-body-large text-on-surface cursor-pointer px-4 py-2",
9694
- "hover:bg-on-surface/8",
9695
- item.isDisabled && "text-on-surface/38 pointer-events-none"
9696
- ),
10238
+ className: splitButtonMenuItemVariants({ isDisabled: item.isDisabled ?? false }),
9697
10239
  children: item.label
9698
10240
  },
9699
10241
  item.label
@@ -9713,32 +10255,32 @@ var SplitButtonHeadless = React.forwardRef(
9713
10255
  "aria-label": ariaLabel,
9714
10256
  className
9715
10257
  }, forwardedRef) => {
9716
- const primaryRef = React.useRef(null);
9717
- const dropdownRef = React.useRef(null);
10258
+ const leadingRef = React.useRef(null);
10259
+ const trailingRef = React.useRef(null);
9718
10260
  const menuRef = React.useRef(null);
9719
10261
  const menuState = reactStately.useMenuTriggerState({});
9720
- const { buttonProps: primaryButtonProps } = reactAria.useButton(
10262
+ const { buttonProps: leadingButtonProps } = reactAria.useButton(
9721
10263
  {
9722
10264
  isDisabled,
9723
10265
  onPress: onPrimaryAction,
9724
10266
  elementType: "button"
9725
10267
  },
9726
- primaryRef
10268
+ leadingRef
9727
10269
  );
9728
- const handleDropdownPress = React.useCallback(() => {
10270
+ const handleTrailingPress = React.useCallback(() => {
9729
10271
  if (menuState.isOpen) {
9730
10272
  menuState.close();
9731
10273
  } else {
9732
10274
  menuState.open();
9733
10275
  }
9734
10276
  }, [menuState]);
9735
- const { buttonProps: dropdownButtonProps } = reactAria.useButton(
10277
+ const { buttonProps: trailingButtonProps } = reactAria.useButton(
9736
10278
  {
9737
10279
  isDisabled,
9738
- onPress: handleDropdownPress,
10280
+ onPress: handleTrailingPress,
9739
10281
  elementType: "button"
9740
10282
  },
9741
- dropdownRef
10283
+ trailingRef
9742
10284
  );
9743
10285
  const handleMenuItemSelect = React.useCallback(
9744
10286
  (item) => {
@@ -9754,13 +10296,11 @@ var SplitButtonHeadless = React.forwardRef(
9754
10296
  const handleGlobalKeyDown = (e) => {
9755
10297
  if (e.key === "Escape") {
9756
10298
  menuState.close();
9757
- dropdownRef.current?.focus();
10299
+ trailingRef.current?.focus();
9758
10300
  }
9759
10301
  };
9760
10302
  document.addEventListener("keydown", handleGlobalKeyDown);
9761
- return () => {
9762
- document.removeEventListener("keydown", handleGlobalKeyDown);
9763
- };
10303
+ return () => document.removeEventListener("keydown", handleGlobalKeyDown);
9764
10304
  }, [menuState, menuState.isOpen]);
9765
10305
  const handleMenuKeyDown = React.useCallback(
9766
10306
  (e) => {
@@ -9793,7 +10333,7 @@ var SplitButtonHeadless = React.forwardRef(
9793
10333
  }
9794
10334
  case "Escape": {
9795
10335
  menuState.close();
9796
- dropdownRef.current?.focus();
10336
+ trailingRef.current?.focus();
9797
10337
  break;
9798
10338
  }
9799
10339
  }
@@ -9829,19 +10369,18 @@ var SplitButtonHeadless = React.forwardRef(
9829
10369
  /* @__PURE__ */ jsxRuntime.jsx(
9830
10370
  "button",
9831
10371
  {
9832
- ...primaryButtonProps,
9833
- ref: primaryRef,
10372
+ ...leadingButtonProps,
10373
+ ref: leadingRef,
9834
10374
  type: "button",
9835
10375
  tabIndex: isDisabled ? -1 : 0,
9836
10376
  children: primaryLabel
9837
10377
  }
9838
10378
  ),
9839
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true" }),
9840
10379
  /* @__PURE__ */ jsxRuntime.jsx(
9841
10380
  "button",
9842
10381
  {
9843
- ...dropdownButtonProps,
9844
- ref: dropdownRef,
10382
+ ...trailingButtonProps,
10383
+ ref: trailingRef,
9845
10384
  type: "button",
9846
10385
  tabIndex: isDisabled ? -1 : 0,
9847
10386
  "aria-haspopup": "menu",
@@ -16111,8 +16650,14 @@ exports.sliderHandleVariants = sliderHandleVariants;
16111
16650
  exports.sliderInactiveTrackVariants = sliderInactiveTrackVariants;
16112
16651
  exports.sliderTrackLayoutVariants = sliderTrackLayoutVariants;
16113
16652
  exports.splitButtonContainerVariants = splitButtonContainerVariants;
16114
- exports.splitButtonDropdownVariants = splitButtonDropdownVariants;
16115
- exports.splitButtonPrimaryVariants = splitButtonPrimaryVariants;
16653
+ exports.splitButtonFocusRingVariants = splitButtonFocusRingVariants;
16654
+ exports.splitButtonIconVariants = splitButtonIconVariants;
16655
+ exports.splitButtonLabelVariants = splitButtonLabelVariants;
16656
+ exports.splitButtonLeadingVariants = splitButtonLeadingVariants;
16657
+ exports.splitButtonMenuItemVariants = splitButtonMenuItemVariants;
16658
+ exports.splitButtonMenuVariants = splitButtonMenuVariants;
16659
+ exports.splitButtonStateLayerVariants = splitButtonStateLayerVariants;
16660
+ exports.splitButtonTrailingVariants = splitButtonTrailingVariants;
16116
16661
  exports.splitButtonVariants = splitButtonVariants;
16117
16662
  exports.supportingTextVariants = supportingTextVariants;
16118
16663
  exports.timeInputFieldVariants = timeInputFieldVariants;