@bug-on/m3-expressive 1.2.2 → 1.2.4

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.mjs CHANGED
@@ -6724,6 +6724,7 @@ var ButtonComponent = React61.forwardRef(
6724
6724
  loading = false,
6725
6725
  loadingVariant = "loading-indicator",
6726
6726
  asChild = false,
6727
+ fullWidth = false,
6727
6728
  outlineWidth,
6728
6729
  children,
6729
6730
  onClick,
@@ -6746,6 +6747,7 @@ var ButtonComponent = React61.forwardRef(
6746
6747
  "loading",
6747
6748
  "loadingVariant",
6748
6749
  "asChild",
6750
+ "fullWidth",
6749
6751
  "outlineWidth",
6750
6752
  "children",
6751
6753
  "onClick",
@@ -6825,7 +6827,8 @@ var ButtonComponent = React61.forwardRef(
6825
6827
  [loading, onClick, onKeyDown]
6826
6828
  );
6827
6829
  const buttonClassName = cn(
6828
- "relative w-fit shrink-0 inline-flex flex-row items-center justify-center",
6830
+ "relative inline-flex flex-row items-center justify-center",
6831
+ fullWidth ? "w-full" : "w-fit shrink-0",
6829
6832
  "whitespace-nowrap select-none cursor-pointer",
6830
6833
  "transition-[background-color,color,border-color,box-shadow,opacity,filter] duration-200",
6831
6834
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2",
@@ -8011,7 +8014,9 @@ var FABComponent = React61.forwardRef(
8011
8014
  asChild = false,
8012
8015
  onClick,
8013
8016
  onKeyDown,
8014
- "aria-label": ariaLabel
8017
+ "aria-label": ariaLabel,
8018
+ layout,
8019
+ layoutId
8015
8020
  } = _b, restProps = __objRest(_b, [
8016
8021
  "className",
8017
8022
  "style",
@@ -8027,7 +8032,9 @@ var FABComponent = React61.forwardRef(
8027
8032
  "asChild",
8028
8033
  "onClick",
8029
8034
  "onKeyDown",
8030
- "aria-label"
8035
+ "aria-label",
8036
+ "layout",
8037
+ "layoutId"
8031
8038
  ]);
8032
8039
  var _a2, _b2, _c, _d;
8033
8040
  const colors = (_a2 = COLOR_CLASSES2[colorStyle]) != null ? _a2 : COLOR_CLASSES2.primary;
@@ -8068,7 +8075,9 @@ var FABComponent = React61.forwardRef(
8068
8075
  /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone: removeRipple }),
8069
8076
  /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: loading ? /* @__PURE__ */ jsx(
8070
8077
  m.span,
8071
- __spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
8078
+ __spreadProps(__spreadValues({
8079
+ layout: "position"
8080
+ }, ICON_SPAN_VARIANTS), {
8072
8081
  transition: SPRING_TRANSITION,
8073
8082
  className: cn(
8074
8083
  "flex items-center justify-center shrink-0",
@@ -8095,7 +8104,9 @@ var FABComponent = React61.forwardRef(
8095
8104
  "loading"
8096
8105
  ) : /* @__PURE__ */ jsx(
8097
8106
  m.span,
8098
- __spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
8107
+ __spreadProps(__spreadValues({
8108
+ layout: "position"
8109
+ }, ICON_SPAN_VARIANTS), {
8099
8110
  transition: SPRING_TRANSITION,
8100
8111
  "aria-hidden": "true",
8101
8112
  className: cn(
@@ -8109,10 +8120,15 @@ var FABComponent = React61.forwardRef(
8109
8120
  /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: extended && labelContent && /* @__PURE__ */ jsx(
8110
8121
  m.span,
8111
8122
  {
8123
+ layout: "position",
8112
8124
  initial: { width: 0, opacity: 0 },
8113
8125
  animate: { width: "auto", opacity: 1 },
8114
8126
  exit: { width: 0, opacity: 0 },
8115
- transition: SPRING_TRANSITION,
8127
+ transition: {
8128
+ opacity: { duration: 0.15, ease: "linear" },
8129
+ width: SPRING_TRANSITION,
8130
+ layout: SPRING_TRANSITION
8131
+ },
8116
8132
  className: "overflow-hidden whitespace-nowrap ml-3",
8117
8133
  children: labelContent
8118
8134
  },
@@ -8129,7 +8145,7 @@ var FABComponent = React61.forwardRef(
8129
8145
  colors.text,
8130
8146
  lowered ? "shadow-sm" : colors.shadow,
8131
8147
  (_d = SIZE_STYLES[size]) != null ? _d : "h-14 w-14",
8132
- extended && "w-auto px-6",
8148
+ extended && "w-auto pl-4 pr-6",
8133
8149
  SIZE_TEXT_CLASS[size],
8134
8150
  loading && "pointer-events-none opacity-75 cursor-not-allowed",
8135
8151
  className
@@ -8160,6 +8176,8 @@ var FABComponent = React61.forwardRef(
8160
8176
  __spreadProps(__spreadValues({
8161
8177
  ref,
8162
8178
  type: "button",
8179
+ layout: layout !== void 0 ? layout : true,
8180
+ layoutId,
8163
8181
  "aria-label": computedAriaLabel,
8164
8182
  "aria-busy": loading || void 0,
8165
8183
  "aria-disabled": loading || restProps.disabled,
@@ -8178,7 +8196,8 @@ var FABComponent = React61.forwardRef(
8178
8196
  transition: {
8179
8197
  borderRadius: SPRING_TRANSITION_FAST,
8180
8198
  scale: SPRING_TRANSITION,
8181
- opacity: { duration: 0.25, ease: "easeOut" }
8199
+ opacity: { duration: 0.25, ease: "easeOut" },
8200
+ layout: SPRING_TRANSITION
8182
8201
  },
8183
8202
  className: containerClassName
8184
8203
  }, restProps), {
@@ -15757,6 +15776,23 @@ var ListItemImpl = React61.forwardRef(
15757
15776
  );
15758
15777
  ListItemImpl.displayName = "ListItem";
15759
15778
  var ListItem = React61.memo(ListItemImpl);
15779
+
15780
+ // src/ui/navigation/navigation-shape-utils.ts
15781
+ function getNavigationShapeStyle(shape, width = 56, height = 56) {
15782
+ if (!shape || shape === "pill" || shape === "circle") {
15783
+ return void 0;
15784
+ }
15785
+ const polygon = MD3Shapes[shape];
15786
+ if (!polygon) {
15787
+ return void 0;
15788
+ }
15789
+ return {
15790
+ clipPath: toClipPath(polygon, width, height)
15791
+ };
15792
+ }
15793
+ function isSquareShape(shape) {
15794
+ return Boolean(shape && shape !== "pill");
15795
+ }
15760
15796
  var NavigationBarContext = React61.createContext({ variant: "flexible" });
15761
15797
  function cloneIconWithFill(icon, selected) {
15762
15798
  if (!React61.isValidElement(icon)) return icon;
@@ -15768,16 +15804,23 @@ function cloneIconWithFill(icon, selected) {
15768
15804
  }
15769
15805
  return icon;
15770
15806
  }
15771
- function ActivePill() {
15807
+ function ActivePill({
15808
+ shape = "pill",
15809
+ width = 56,
15810
+ height = 32
15811
+ }) {
15772
15812
  const { activeIndicatorTransition } = React61.useContext(NavigationBarContext);
15813
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
15773
15814
  return /* @__PURE__ */ jsx(
15774
15815
  m.div,
15775
15816
  {
15776
- className: "absolute inset-0 bg-m3-secondary-container pointer-events-none",
15777
- style: {
15778
- borderRadius: 9999,
15817
+ className: cn(
15818
+ "bg-m3-secondary-container pointer-events-none",
15819
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : shape === "circle" ? "absolute inset-0 rounded-full" : "absolute inset-0 rounded-full"
15820
+ ),
15821
+ style: __spreadValues(__spreadValues({
15779
15822
  zIndex: 0
15780
- },
15823
+ }, shapeStyle ? { width, height } : {}), shapeStyle),
15781
15824
  initial: { opacity: 0, scale: 0.5 },
15782
15825
  animate: { opacity: 1, scale: 1 },
15783
15826
  exit: { opacity: 0, scale: 0.5 },
@@ -15785,11 +15828,42 @@ function ActivePill() {
15785
15828
  }
15786
15829
  );
15787
15830
  }
15788
- function HoverStateLayer() {
15789
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-m3-on-surface opacity-0 group-hover:opacity-[0.08] group-focus-visible:opacity-[0.10] active:opacity-[0.10] transition-opacity duration-200 pointer-events-none z-0" });
15831
+ function HoverStateLayer({
15832
+ shape = "pill",
15833
+ width = 56,
15834
+ height = 32
15835
+ }) {
15836
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
15837
+ return /* @__PURE__ */ jsx(
15838
+ "div",
15839
+ {
15840
+ className: cn(
15841
+ "bg-m3-on-surface opacity-0 group-hover:opacity-[0.08] group-focus-visible:opacity-[0.10] active:opacity-[0.10] transition-opacity duration-200 pointer-events-none z-0",
15842
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : shape === "circle" ? "absolute inset-0 rounded-full" : "absolute inset-0 rounded-[16px]"
15843
+ ),
15844
+ style: __spreadValues(__spreadValues({}, shapeStyle ? { width, height } : {}), shapeStyle)
15845
+ }
15846
+ );
15790
15847
  }
15791
- function RippleLayer({ ripples, onRippleDone }) {
15792
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full overflow-hidden pointer-events-none z-0", children: /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone }) });
15848
+ function RippleLayer({
15849
+ ripples,
15850
+ onRippleDone,
15851
+ shape = "pill",
15852
+ width = 56,
15853
+ height = 32
15854
+ }) {
15855
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
15856
+ return /* @__PURE__ */ jsx(
15857
+ "div",
15858
+ {
15859
+ className: cn(
15860
+ "overflow-hidden pointer-events-none z-0",
15861
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : shape === "circle" ? "absolute inset-0 rounded-full" : "absolute inset-0 rounded-[16px]"
15862
+ ),
15863
+ style: __spreadValues(__spreadValues({}, shapeStyle ? { width, height } : {}), shapeStyle),
15864
+ children: /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone })
15865
+ }
15866
+ );
15793
15867
  }
15794
15868
  function IconContainer({ selected, badge, children }) {
15795
15869
  return /* @__PURE__ */ jsxs(
@@ -15815,16 +15889,33 @@ var NavigationBarItemComponent = React61.forwardRef(
15815
15889
  onClick,
15816
15890
  disabled = false,
15817
15891
  badge,
15892
+ shape: shapeProp,
15893
+ shapeSize: shapeSizeProp,
15894
+ hideLabel = false,
15818
15895
  className,
15819
- "aria-label": ariaLabelProp
15896
+ "aria-label": ariaLabelProp,
15897
+ asChild = false,
15898
+ children
15820
15899
  }, ref) => {
15900
+ var _a, _b, _c;
15821
15901
  const {
15822
15902
  variant,
15823
15903
  itemLayout,
15904
+ shape: contextShape,
15905
+ labelVisibility: contextLabelVisibility,
15906
+ shapeSize: contextShapeSize,
15824
15907
  itemClassName: contextItemClassName
15825
15908
  } = React61.useContext(NavigationBarContext);
15909
+ const activeShape = (_a = shapeProp != null ? shapeProp : contextShape) != null ? _a : "pill";
15910
+ const isSquare = isSquareShape(activeShape);
15911
+ const resolvedShapeSize = (_b = shapeSizeProp != null ? shapeSizeProp : contextShapeSize) != null ? _b : 56;
15826
15912
  const isForcedHorizontal = itemLayout === "horizontal";
15827
15913
  const isResponsiveHorizontal = (variant === "flexible" || variant === "xr") && itemLayout === void 0;
15914
+ const shouldShowLabel = !hideLabel && (() => {
15915
+ if (contextLabelVisibility === "unlabeled") return false;
15916
+ if (contextLabelVisibility === "auto") return selected;
15917
+ return true;
15918
+ })();
15828
15919
  const { ripples, onPointerDown, removeRipple } = useRippleState({
15829
15920
  disabled
15830
15921
  });
@@ -15845,6 +15936,145 @@ var NavigationBarItemComponent = React61.forwardRef(
15845
15936
  [disabled, selected, onClick]
15846
15937
  );
15847
15938
  const filledIcon = cloneIconWithFill(icon, selected);
15939
+ const itemClassName = cn(
15940
+ "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none h-full items-center justify-center min-w-0",
15941
+ variant === "xr" ? isResponsiveHorizontal ? "flex-1 min-[600px]:flex-initial min-[600px]:w-auto" : isForcedHorizontal ? "flex-initial w-auto" : "flex-1" : isForcedHorizontal ? "flex-initial w-auto" : "flex-1",
15942
+ disabled && "pointer-events-none opacity-[0.38]",
15943
+ contextItemClassName,
15944
+ className
15945
+ );
15946
+ const iconPillWidth = isSquare ? resolvedShapeSize : 56;
15947
+ const iconPillHeight = isSquare ? resolvedShapeSize : 32;
15948
+ if (asChild && children) {
15949
+ const child = React61.Children.only(children);
15950
+ const innerContent = /* @__PURE__ */ jsxs(Fragment, { children: [
15951
+ /* @__PURE__ */ jsxs(
15952
+ "div",
15953
+ {
15954
+ className: cn(
15955
+ "relative flex items-center justify-center flex-col gap-y-1 w-full px-1 py-1.5",
15956
+ isResponsiveHorizontal && "min-[600px]:flex-row min-[600px]:gap-y-0 min-[600px]:gap-x-1.5 min-[600px]:h-10 min-[600px]:px-4 min-[600px]:py-0 min-[600px]:rounded-full min-[600px]:w-auto",
15957
+ isForcedHorizontal && "flex-row gap-y-0 gap-x-1.5 h-10 px-4 py-0 rounded-full w-auto",
15958
+ // When label is hidden and not horizontal, remove bottom gap
15959
+ !shouldShowLabel && !isForcedHorizontal && "gap-y-0"
15960
+ ),
15961
+ children: [
15962
+ !isSquare && /* @__PURE__ */ jsxs(
15963
+ "div",
15964
+ {
15965
+ className: cn(
15966
+ "absolute inset-0 z-0 hidden",
15967
+ isResponsiveHorizontal && "min-[600px]:block",
15968
+ isForcedHorizontal && "block!"
15969
+ ),
15970
+ children: [
15971
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(ActivePill, { shape: activeShape, width: 56, height: 40 }) }),
15972
+ /* @__PURE__ */ jsx(HoverStateLayer, { shape: activeShape, width: 56, height: 40 }),
15973
+ /* @__PURE__ */ jsx(
15974
+ RippleLayer,
15975
+ {
15976
+ ripples,
15977
+ onRippleDone: removeRipple,
15978
+ shape: activeShape,
15979
+ width: 56,
15980
+ height: 40
15981
+ }
15982
+ )
15983
+ ]
15984
+ }
15985
+ ),
15986
+ /* @__PURE__ */ jsxs(
15987
+ "div",
15988
+ {
15989
+ className: cn(
15990
+ "relative flex items-center justify-center shrink-0 z-10",
15991
+ isSquare ? "mx-auto" : "h-8 w-14 mx-auto rounded-[16px]",
15992
+ !isSquare && isResponsiveHorizontal && "min-[600px]:size-6 min-[600px]:w-auto min-[600px]:h-auto",
15993
+ !isSquare && isForcedHorizontal && "size-6 w-auto h-auto"
15994
+ ),
15995
+ style: isSquare ? { width: resolvedShapeSize, height: resolvedShapeSize } : void 0,
15996
+ children: [
15997
+ /* @__PURE__ */ jsxs(
15998
+ "div",
15999
+ {
16000
+ className: cn(
16001
+ "absolute inset-0 z-0",
16002
+ !isSquare && isResponsiveHorizontal && "min-[600px]:hidden",
16003
+ !isSquare && isForcedHorizontal && "hidden"
16004
+ ),
16005
+ children: [
16006
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16007
+ ActivePill,
16008
+ {
16009
+ shape: activeShape,
16010
+ width: iconPillWidth,
16011
+ height: iconPillHeight
16012
+ }
16013
+ ) }),
16014
+ /* @__PURE__ */ jsx(
16015
+ HoverStateLayer,
16016
+ {
16017
+ shape: activeShape,
16018
+ width: iconPillWidth,
16019
+ height: iconPillHeight
16020
+ }
16021
+ ),
16022
+ /* @__PURE__ */ jsx(
16023
+ RippleLayer,
16024
+ {
16025
+ ripples,
16026
+ onRippleDone: removeRipple,
16027
+ shape: activeShape,
16028
+ width: iconPillWidth,
16029
+ height: iconPillHeight
16030
+ }
16031
+ )
16032
+ ]
16033
+ }
16034
+ ),
16035
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 flex size-6 items-center justify-center text-current", children: /* @__PURE__ */ jsx(IconContainer, { selected, badge, children: filledIcon }) })
16036
+ ]
16037
+ }
16038
+ ),
16039
+ label && /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", initial: false, children: shouldShowLabel && /* @__PURE__ */ jsx(
16040
+ m.span,
16041
+ {
16042
+ initial: { opacity: 0, height: 0, scale: 0.85, y: -2 },
16043
+ animate: { opacity: 1, height: "auto", scale: 1, y: 0 },
16044
+ exit: { opacity: 0, height: 0, scale: 0.85, y: -2 },
16045
+ transition: SPRING_TRANSITION_EXPRESSIVE,
16046
+ className: cn(
16047
+ "z-10 transition-colors duration-200 truncate px-1 inline-block overflow-hidden",
16048
+ selected ? "text-m3-on-surface font-medium" : "text-m3-on-surface-variant font-medium",
16049
+ "text-[12px] leading-4 tracking-[0.5px]"
16050
+ ),
16051
+ children: (_c = child.props.children) != null ? _c : label
16052
+ },
16053
+ "nav-label"
16054
+ ) })
16055
+ ]
16056
+ }
16057
+ ),
16058
+ /* @__PURE__ */ jsx(TouchTarget, {})
16059
+ ] });
16060
+ return /* @__PURE__ */ jsx(
16061
+ Slot,
16062
+ {
16063
+ ref,
16064
+ role: "menuitem",
16065
+ "aria-current": selected ? "page" : void 0,
16066
+ "aria-disabled": disabled ? true : void 0,
16067
+ "aria-label": (
16068
+ // Always provide aria-label even when label is visually hidden
16069
+ ariaLabelProp || (typeof label === "string" ? label : void 0)
16070
+ ),
16071
+ onClick: handleClick,
16072
+ onPointerDown,
16073
+ className: itemClassName,
16074
+ children: React61.cloneElement(child, { children: innerContent })
16075
+ }
16076
+ );
16077
+ }
15848
16078
  return /* @__PURE__ */ jsxs(
15849
16079
  m.button,
15850
16080
  {
@@ -15853,16 +16083,13 @@ var NavigationBarItemComponent = React61.forwardRef(
15853
16083
  role: "menuitem",
15854
16084
  "aria-current": selected ? "page" : void 0,
15855
16085
  "aria-disabled": disabled ? true : void 0,
15856
- "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
16086
+ "aria-label": (
16087
+ // Always provide aria-label even when label is visually hidden
16088
+ ariaLabelProp || (typeof label === "string" ? label : void 0)
16089
+ ),
15857
16090
  onClick: handleClick,
15858
16091
  onPointerDown,
15859
- className: cn(
15860
- "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none h-full items-center justify-center min-w-0",
15861
- variant === "xr" ? isResponsiveHorizontal ? "flex-1 min-[600px]:flex-initial min-[600px]:w-auto" : isForcedHorizontal ? "flex-initial w-auto" : "flex-1" : isForcedHorizontal ? "flex-initial w-auto" : "flex-1",
15862
- disabled && "pointer-events-none opacity-[0.38]",
15863
- contextItemClassName,
15864
- className
15865
- ),
16092
+ className: itemClassName,
15866
16093
  children: [
15867
16094
  /* @__PURE__ */ jsxs(
15868
16095
  "div",
@@ -15870,10 +16097,12 @@ var NavigationBarItemComponent = React61.forwardRef(
15870
16097
  className: cn(
15871
16098
  "relative flex items-center justify-center flex-col gap-y-1 w-full px-1 py-1.5",
15872
16099
  isResponsiveHorizontal && "min-[600px]:flex-row min-[600px]:gap-y-0 min-[600px]:gap-x-1.5 min-[600px]:h-10 min-[600px]:px-4 min-[600px]:py-0 min-[600px]:rounded-full min-[600px]:w-auto",
15873
- isForcedHorizontal && "flex-row gap-y-0 gap-x-1.5 h-10 px-4 py-0 rounded-full w-auto"
16100
+ isForcedHorizontal && "flex-row gap-y-0 gap-x-1.5 h-10 px-4 py-0 rounded-full w-auto",
16101
+ // When label is hidden and not horizontal, remove bottom gap
16102
+ !shouldShowLabel && !isForcedHorizontal && "gap-y-0"
15874
16103
  ),
15875
16104
  children: [
15876
- /* @__PURE__ */ jsxs(
16105
+ !isSquare && /* @__PURE__ */ jsxs(
15877
16106
  "div",
15878
16107
  {
15879
16108
  className: cn(
@@ -15882,9 +16111,18 @@ var NavigationBarItemComponent = React61.forwardRef(
15882
16111
  isForcedHorizontal && "block!"
15883
16112
  ),
15884
16113
  children: [
15885
- /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(ActivePill, {}) }),
15886
- /* @__PURE__ */ jsx(HoverStateLayer, {}),
15887
- /* @__PURE__ */ jsx(RippleLayer, { ripples, onRippleDone: removeRipple })
16114
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(ActivePill, { shape: activeShape, width: 56, height: 40 }) }),
16115
+ /* @__PURE__ */ jsx(HoverStateLayer, { shape: activeShape, width: 56, height: 40 }),
16116
+ /* @__PURE__ */ jsx(
16117
+ RippleLayer,
16118
+ {
16119
+ ripples,
16120
+ onRippleDone: removeRipple,
16121
+ shape: activeShape,
16122
+ width: 56,
16123
+ height: 40
16124
+ }
16125
+ )
15888
16126
  ]
15889
16127
  }
15890
16128
  ),
@@ -15893,23 +16131,47 @@ var NavigationBarItemComponent = React61.forwardRef(
15893
16131
  {
15894
16132
  className: cn(
15895
16133
  "relative flex items-center justify-center shrink-0 z-10",
15896
- "h-8 w-16 mx-auto rounded-full",
15897
- isResponsiveHorizontal && "min-[600px]:size-6 min-[600px]:w-auto min-[600px]:h-auto",
15898
- isForcedHorizontal && "size-6 w-auto h-auto"
16134
+ isSquare ? "mx-auto" : "h-8 w-14 mx-auto rounded-[16px]",
16135
+ !isSquare && isResponsiveHorizontal && "min-[600px]:size-6 min-[600px]:w-auto min-[600px]:h-auto",
16136
+ !isSquare && isForcedHorizontal && "size-6 w-auto h-auto"
15899
16137
  ),
16138
+ style: isSquare ? { width: resolvedShapeSize, height: resolvedShapeSize } : void 0,
15900
16139
  children: [
15901
16140
  /* @__PURE__ */ jsxs(
15902
16141
  "div",
15903
16142
  {
15904
16143
  className: cn(
15905
16144
  "absolute inset-0 z-0",
15906
- isResponsiveHorizontal && "min-[600px]:hidden",
15907
- isForcedHorizontal && "hidden"
16145
+ !isSquare && isResponsiveHorizontal && "min-[600px]:hidden",
16146
+ !isSquare && isForcedHorizontal && "hidden"
15908
16147
  ),
15909
16148
  children: [
15910
- /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(ActivePill, {}) }),
15911
- /* @__PURE__ */ jsx(HoverStateLayer, {}),
15912
- /* @__PURE__ */ jsx(RippleLayer, { ripples, onRippleDone: removeRipple })
16149
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16150
+ ActivePill,
16151
+ {
16152
+ shape: activeShape,
16153
+ width: iconPillWidth,
16154
+ height: iconPillHeight
16155
+ }
16156
+ ) }),
16157
+ /* @__PURE__ */ jsx(
16158
+ HoverStateLayer,
16159
+ {
16160
+ shape: activeShape,
16161
+ width: iconPillWidth,
16162
+ height: iconPillHeight
16163
+ }
16164
+ ),
16165
+ /* @__PURE__ */ jsx(
16166
+ RippleLayer,
16167
+ {
16168
+ ripples,
16169
+ onRippleDone: removeRipple,
16170
+ shape: activeShape,
16171
+ width: iconPillWidth,
16172
+ height: iconPillHeight
16173
+ }
16174
+ )
15913
16175
  ]
15914
16176
  }
15915
16177
  ),
@@ -15917,13 +16179,17 @@ var NavigationBarItemComponent = React61.forwardRef(
15917
16179
  ]
15918
16180
  }
15919
16181
  ),
15920
- /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsx(
15921
- "span",
16182
+ label && /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", initial: false, children: shouldShowLabel && /* @__PURE__ */ jsx(
16183
+ m.span,
15922
16184
  {
16185
+ initial: { opacity: 0, height: 0, scale: 0.85, y: -2 },
16186
+ animate: { opacity: 1, height: "auto", scale: 1, y: 0 },
16187
+ exit: { opacity: 0, height: 0, scale: 0.85, y: -2 },
16188
+ transition: SPRING_TRANSITION_EXPRESSIVE,
15923
16189
  className: cn(
15924
- "z-10 transition-all duration-200 truncate px-1",
15925
- selected ? "text-m3-on-surface" : "text-m3-on-surface-variant",
15926
- "font-medium text-[12px] leading-4 tracking-[0.5px]"
16190
+ "z-10 transition-colors duration-200 truncate px-1 inline-block overflow-hidden",
16191
+ selected ? "text-m3-on-surface font-medium" : "text-m3-on-surface-variant font-medium",
16192
+ "text-[12px] leading-4 tracking-[0.5px]"
15927
16193
  ),
15928
16194
  children: label
15929
16195
  },
@@ -15945,9 +16211,9 @@ var navContainerVariants = cva(
15945
16211
  {
15946
16212
  variants: {
15947
16213
  variant: {
15948
- flexible: "bottom-0 left-0 right-0 w-full h-16 pb-safe",
15949
- baseline: "bottom-0 left-0 right-0 w-full h-20 pb-safe",
15950
- xr: "bottom-6 left-1/2 -translate-x-1/2 w-auto max-w-[calc(100%-2rem)] min-[600px]:max-w-fit h-20 min-[600px]:h-16 rounded-[48px] px-2"
16214
+ flexible: "bottom-0 left-0 right-0 w-full min-h-16 py-1 pb-safe",
16215
+ baseline: "bottom-0 left-0 right-0 w-full min-h-20 py-1 pb-safe",
16216
+ xr: "bottom-6 left-1/2 -translate-x-1/2 w-auto max-w-[calc(100%-2rem)] min-[600px]:max-w-fit min-h-20 min-[600px]:min-h-16 rounded-[48px] px-2 py-1"
15951
16217
  },
15952
16218
  position: {
15953
16219
  fixed: "fixed",
@@ -15969,6 +16235,9 @@ var NavigationBarComponent = React61.forwardRef(
15969
16235
  ({
15970
16236
  variant = "flexible",
15971
16237
  itemLayout,
16238
+ shape,
16239
+ labelVisibility,
16240
+ shapeSize,
15972
16241
  hideOnScroll = false,
15973
16242
  elevated = false,
15974
16243
  fixed = true,
@@ -15983,6 +16252,13 @@ var NavigationBarComponent = React61.forwardRef(
15983
16252
  const lastScrollY = React61.useRef(
15984
16253
  typeof window !== "undefined" ? window.scrollY : 0
15985
16254
  );
16255
+ const isSquare = isSquareShape(shape);
16256
+ const effectiveShapeSize = shapeSize != null ? shapeSize : isSquare ? 56 : 32;
16257
+ const computedMinHeight = React61.useMemo(() => {
16258
+ const baseHeight = variant === "baseline" ? 80 : 64;
16259
+ const requiredHeight = itemLayout === "horizontal" || labelVisibility === "unlabeled" ? effectiveShapeSize + 16 : effectiveShapeSize + 32;
16260
+ return Math.max(baseHeight, requiredHeight);
16261
+ }, [variant, itemLayout, labelVisibility, effectiveShapeSize]);
15986
16262
  React61.useEffect(() => {
15987
16263
  if (typeof window === "undefined" || !hideOnScroll) {
15988
16264
  setIsVisible(true);
@@ -16029,6 +16305,9 @@ var NavigationBarComponent = React61.forwardRef(
16029
16305
  value: {
16030
16306
  variant,
16031
16307
  itemLayout,
16308
+ shape,
16309
+ labelVisibility,
16310
+ shapeSize,
16032
16311
  activeIndicatorTransition,
16033
16312
  itemClassName
16034
16313
  },
@@ -16039,7 +16318,7 @@ var NavigationBarComponent = React61.forwardRef(
16039
16318
  role: "navigation",
16040
16319
  "aria-label": "Main navigation",
16041
16320
  className: navBaseClasses,
16042
- style,
16321
+ style: __spreadValues({ minHeight: computedMinHeight }, style),
16043
16322
  initial: false,
16044
16323
  animate: {
16045
16324
  y: isVisible ? "0%" : variant === "xr" ? "calc(100% + 40px)" : "100%"
@@ -16051,8 +16330,8 @@ var NavigationBarComponent = React61.forwardRef(
16051
16330
  role: "menubar",
16052
16331
  "aria-orientation": "horizontal",
16053
16332
  className: cn(
16054
- "flex w-full h-full mx-auto",
16055
- variant === "xr" ? "gap-0 min-[600px]:gap-1.5 items-center justify-center px-1" : "max-w-7xl gap-1.5"
16333
+ "flex w-full h-full mx-auto items-center justify-center",
16334
+ variant === "xr" ? "gap-0 min-[600px]:gap-1.5 px-1" : "max-w-7xl gap-1.5"
16056
16335
  ),
16057
16336
  children
16058
16337
  }
@@ -16065,7 +16344,11 @@ var NavigationBarComponent = React61.forwardRef(
16065
16344
  );
16066
16345
  NavigationBarComponent.displayName = "NavigationBar";
16067
16346
  var NavigationBar = React61.memo(NavigationBarComponent);
16068
- var NavigationRailContext = React61.createContext({ variant: "collapsed", labelVisibility: "labeled" });
16347
+ var NavigationRailContext = React61.createContext({
16348
+ variant: "collapsed",
16349
+ labelVisibility: "labeled",
16350
+ activeIndicatorWidth: "hug"
16351
+ });
16069
16352
  var MD3_MODAL_TRANSITION = {
16070
16353
  type: "tween",
16071
16354
  ease: [0.05, 0.7, 0.1, 1],
@@ -16076,9 +16359,9 @@ var railContainerVariants = cva(
16076
16359
  {
16077
16360
  variants: {
16078
16361
  variant: {
16079
- collapsed: "items-center h-full pt-11 pb-4 shadow-none bg-m3-surface rounded-none",
16080
- expanded: "items-start h-full pt-11 pb-4 shadow-none bg-m3-surface rounded-none",
16081
- modal: "bg-m3-surface shadow-lg rounded-r-[var(--m3-shape-corner-large)] h-full pt-11 pb-4",
16362
+ collapsed: "items-center h-full pt-11 pb-14 shadow-none bg-m3-surface rounded-none",
16363
+ expanded: "items-start h-full pt-11 pb-14 shadow-none bg-m3-surface rounded-none",
16364
+ modal: "bg-m3-surface shadow-lg rounded-r-[var(--m3-shape-corner-large)] h-full pt-11 pb-14",
16082
16365
  xr: "h-fit py-5 rounded-[48px] shadow-xl bg-m3-surface border border-white/5"
16083
16366
  },
16084
16367
  narrow: {
@@ -16121,14 +16404,28 @@ function setFocusedItem(items, index) {
16121
16404
  target.focus();
16122
16405
  }
16123
16406
  }
16124
- function ActivePill2({ layoutId, disableInitial = false }) {
16407
+ function ActivePill2({
16408
+ layoutId,
16409
+ disableInitial = false,
16410
+ shape = "pill",
16411
+ width = 56,
16412
+ height = 32
16413
+ }) {
16125
16414
  const { activeIndicatorTransition } = React61.useContext(NavigationRailContext);
16415
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
16126
16416
  return /* @__PURE__ */ jsx(
16127
16417
  m.div,
16128
16418
  {
16129
16419
  layoutId,
16130
- className: "absolute inset-0 bg-m3-secondary-container pointer-events-none",
16131
- style: { borderRadius: 9999, zIndex: 0, originX: 0.5, originY: 0.5 },
16420
+ className: cn(
16421
+ "bg-m3-secondary-container pointer-events-none",
16422
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : "absolute inset-0 rounded-full"
16423
+ ),
16424
+ style: __spreadValues(__spreadValues({
16425
+ zIndex: 0,
16426
+ originX: 0.5,
16427
+ originY: 0.5
16428
+ }, shapeStyle ? { width, height } : {}), shapeStyle),
16132
16429
  initial: disableInitial ? false : { opacity: 0, scale: 0.5 },
16133
16430
  animate: { opacity: 1, scale: 1 },
16134
16431
  exit: { opacity: 0, scale: 0.5, transition: { duration: 0.15 } },
@@ -16136,11 +16433,42 @@ function ActivePill2({ layoutId, disableInitial = false }) {
16136
16433
  }
16137
16434
  );
16138
16435
  }
16139
- function HoverStateLayer2() {
16140
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-m3-on-surface opacity-0 group-hover:opacity-[0.08] transition-opacity duration-200 pointer-events-none z-0" });
16436
+ function HoverStateLayer2({
16437
+ shape = "pill",
16438
+ width = 56,
16439
+ height = 32
16440
+ }) {
16441
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
16442
+ return /* @__PURE__ */ jsx(
16443
+ "div",
16444
+ {
16445
+ className: cn(
16446
+ "bg-m3-on-surface opacity-0 group-hover:opacity-[0.08] transition-opacity duration-200 pointer-events-none z-0",
16447
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : "absolute inset-0 rounded-full"
16448
+ ),
16449
+ style: __spreadValues(__spreadValues({}, shapeStyle ? { width, height } : {}), shapeStyle)
16450
+ }
16451
+ );
16141
16452
  }
16142
- function RippleLayer2({ ripples, onRippleDone }) {
16143
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full overflow-hidden pointer-events-none z-0", children: /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone }) });
16453
+ function RippleLayer2({
16454
+ ripples,
16455
+ onRippleDone,
16456
+ shape = "pill",
16457
+ width = 56,
16458
+ height = 32
16459
+ }) {
16460
+ const shapeStyle = getNavigationShapeStyle(shape, width, height);
16461
+ return /* @__PURE__ */ jsx(
16462
+ "div",
16463
+ {
16464
+ className: cn(
16465
+ "overflow-hidden pointer-events-none z-0",
16466
+ shapeStyle ? "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-none" : "absolute inset-0 rounded-full"
16467
+ ),
16468
+ style: __spreadValues(__spreadValues({}, shapeStyle ? { width, height } : {}), shapeStyle),
16469
+ children: /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone })
16470
+ }
16471
+ );
16144
16472
  }
16145
16473
  function IconContainer2({ selected, badge, children }) {
16146
16474
  return /* @__PURE__ */ jsxs(
@@ -16166,15 +16494,31 @@ var NavigationRailItemComponent = React61.forwardRef(
16166
16494
  onClick,
16167
16495
  disabled = false,
16168
16496
  badge,
16497
+ shape: shapeProp,
16498
+ shapeSize: shapeSizeProp,
16499
+ activeIndicatorWidth: activeIndicatorWidthProp,
16169
16500
  className,
16170
- "aria-label": ariaLabelProp
16501
+ "aria-label": ariaLabelProp,
16502
+ asChild = false,
16503
+ children
16171
16504
  }, ref) => {
16172
- const { variant, labelVisibility } = React61.useContext(
16173
- NavigationRailContext
16174
- );
16505
+ var _a, _b, _c, _d;
16506
+ const {
16507
+ variant,
16508
+ labelVisibility,
16509
+ shape: contextShape,
16510
+ shapeSize: contextShapeSize,
16511
+ activeIndicatorWidth: contextActiveIndicatorWidth
16512
+ } = React61.useContext(NavigationRailContext);
16513
+ const activeShape = (_a = shapeProp != null ? shapeProp : contextShape) != null ? _a : "pill";
16514
+ const isSquare = isSquareShape(activeShape);
16515
+ const resolvedShapeSize = (_b = shapeSizeProp != null ? shapeSizeProp : contextShapeSize) != null ? _b : 56;
16516
+ const activeIndicatorWidth = (_c = activeIndicatorWidthProp != null ? activeIndicatorWidthProp : contextActiveIndicatorWidth) != null ? _c : "hug";
16175
16517
  const isExpanded = variant === "expanded" || variant === "modal";
16176
16518
  const isModal = variant === "modal";
16177
16519
  const enableLayout = !isModal;
16520
+ const isExpandedPill = isExpanded && !isSquare;
16521
+ const expandedPillWidthClass = activeIndicatorWidth === "fill" ? "w-full" : "w-fit";
16178
16522
  const activePillId = `rail-pill-${React61.useId()}`;
16179
16523
  const { ripples, onPointerDown, removeRipple } = useRippleState({
16180
16524
  disabled
@@ -16192,6 +16536,138 @@ var NavigationRailItemComponent = React61.forwardRef(
16192
16536
  );
16193
16537
  const filledIcon = cloneIconWithFill2(icon, selected);
16194
16538
  const labelInitial = isModal ? false : { opacity: 0, x: isExpanded ? -12 : 0, y: isExpanded ? 0 : -8 };
16539
+ const itemClassName = cn(
16540
+ "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none",
16541
+ "focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2 rounded-full",
16542
+ disabled && "pointer-events-none opacity-[0.38]",
16543
+ isExpanded ? "w-full flex-row items-center px-3 h-14" : "w-full flex-col justify-center h-14",
16544
+ className
16545
+ );
16546
+ const iconPillWidth = isSquare ? resolvedShapeSize : 56;
16547
+ const iconPillHeight = isSquare ? resolvedShapeSize : 32;
16548
+ if (asChild && children) {
16549
+ const child = React61.Children.only(children);
16550
+ const innerContent = /* @__PURE__ */ jsxs(Fragment, { children: [
16551
+ /* @__PURE__ */ jsxs(
16552
+ m.div,
16553
+ {
16554
+ layout: enableLayout,
16555
+ className: cn(
16556
+ "relative flex z-10",
16557
+ isExpanded ? cn(
16558
+ "flex-row items-center h-14 px-4 gap-x-3 rounded-full",
16559
+ expandedPillWidthClass
16560
+ ) : "flex-col items-center justify-center w-full gap-y-1 rounded-full"
16561
+ ),
16562
+ children: [
16563
+ isExpandedPill && /* @__PURE__ */ jsxs(Fragment, { children: [
16564
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16565
+ ActivePill2,
16566
+ {
16567
+ layoutId: activePillId,
16568
+ disableInitial: isModal,
16569
+ shape: activeShape
16570
+ }
16571
+ ) }),
16572
+ /* @__PURE__ */ jsx(HoverStateLayer2, { shape: activeShape }),
16573
+ /* @__PURE__ */ jsx(
16574
+ RippleLayer2,
16575
+ {
16576
+ ripples,
16577
+ onRippleDone: removeRipple,
16578
+ shape: activeShape
16579
+ }
16580
+ )
16581
+ ] }),
16582
+ /* @__PURE__ */ jsxs(
16583
+ m.div,
16584
+ {
16585
+ layout: enableLayout,
16586
+ className: cn(
16587
+ "relative flex items-center justify-center shrink-0 z-10",
16588
+ isSquare ? "mx-auto" : isExpandedPill ? "size-6" : "h-8 w-14 mx-auto rounded-full"
16589
+ ),
16590
+ style: isSquare ? { width: resolvedShapeSize, height: resolvedShapeSize } : void 0,
16591
+ children: [
16592
+ !isExpandedPill && /* @__PURE__ */ jsxs(Fragment, { children: [
16593
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16594
+ ActivePill2,
16595
+ {
16596
+ layoutId: activePillId,
16597
+ disableInitial: isModal,
16598
+ shape: activeShape,
16599
+ width: iconPillWidth,
16600
+ height: iconPillHeight
16601
+ }
16602
+ ) }),
16603
+ /* @__PURE__ */ jsx(
16604
+ HoverStateLayer2,
16605
+ {
16606
+ shape: activeShape,
16607
+ width: iconPillWidth,
16608
+ height: iconPillHeight
16609
+ }
16610
+ ),
16611
+ /* @__PURE__ */ jsx(
16612
+ RippleLayer2,
16613
+ {
16614
+ ripples,
16615
+ onRippleDone: removeRipple,
16616
+ shape: activeShape,
16617
+ width: iconPillWidth,
16618
+ height: iconPillHeight
16619
+ }
16620
+ )
16621
+ ] }),
16622
+ /* @__PURE__ */ jsx(
16623
+ m.div,
16624
+ {
16625
+ layout: enableLayout ? "position" : false,
16626
+ className: "relative z-10 flex size-6 items-center justify-center text-current",
16627
+ children: /* @__PURE__ */ jsx(IconContainer2, { selected, badge, children: filledIcon })
16628
+ }
16629
+ )
16630
+ ]
16631
+ }
16632
+ ),
16633
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: showLabel && (label || child.props.children) && /* @__PURE__ */ jsx(
16634
+ m.span,
16635
+ {
16636
+ layout: enableLayout ? "position" : false,
16637
+ initial: labelInitial,
16638
+ animate: { opacity: 1, x: 0, y: 0 },
16639
+ exit: { opacity: 0, transition: { duration: 0.1 } },
16640
+ transition: SPRING_TRANSITION,
16641
+ className: cn(
16642
+ "z-10 transition-colors duration-200 whitespace-nowrap",
16643
+ selected ? isExpandedPill ? "text-m3-on-secondary-container font-medium" : "text-m3-on-surface font-medium" : "text-m3-on-surface-variant font-medium",
16644
+ isExpanded ? "text-sm tracking-wide text-left" : "text-xs tracking-wide"
16645
+ ),
16646
+ children: (_d = child.props.children) != null ? _d : label
16647
+ },
16648
+ "rail-label"
16649
+ ) })
16650
+ ]
16651
+ }
16652
+ ),
16653
+ /* @__PURE__ */ jsx(TouchTarget, {})
16654
+ ] });
16655
+ return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsx(
16656
+ Slot,
16657
+ {
16658
+ ref,
16659
+ role: "menuitem",
16660
+ "aria-current": selected ? "page" : void 0,
16661
+ "aria-disabled": disabled ? true : void 0,
16662
+ "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
16663
+ onClick: handleClick,
16664
+ onPointerDown,
16665
+ className: itemClassName,
16666
+ tabIndex: -1,
16667
+ children: React61.cloneElement(child, { children: innerContent })
16668
+ }
16669
+ ) });
16670
+ }
16195
16671
  return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
16196
16672
  m.button,
16197
16673
  {
@@ -16204,13 +16680,7 @@ var NavigationRailItemComponent = React61.forwardRef(
16204
16680
  "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
16205
16681
  onClick: handleClick,
16206
16682
  onPointerDown,
16207
- className: cn(
16208
- "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none",
16209
- "focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2 rounded-full",
16210
- disabled && "pointer-events-none opacity-[0.38]",
16211
- isExpanded ? "w-full flex-row items-center px-3 h-14" : "w-full flex-col justify-center h-14",
16212
- className
16213
- ),
16683
+ className: itemClassName,
16214
16684
  tabIndex: -1,
16215
16685
  children: [
16216
16686
  /* @__PURE__ */ jsxs(
@@ -16219,31 +16689,71 @@ var NavigationRailItemComponent = React61.forwardRef(
16219
16689
  layout: enableLayout,
16220
16690
  className: cn(
16221
16691
  "relative flex z-10",
16222
- isExpanded ? "flex-row items-center w-fit h-14 px-4 gap-x-3 rounded-full" : "flex-col items-center justify-center w-full gap-y-1 rounded-full"
16692
+ isExpanded ? cn(
16693
+ "flex-row items-center h-14 px-4 gap-x-3 rounded-full",
16694
+ expandedPillWidthClass
16695
+ ) : "flex-col items-center justify-center w-full gap-y-1 rounded-full"
16223
16696
  ),
16224
16697
  children: [
16225
- isExpanded && /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16226
- ActivePill2,
16227
- {
16228
- layoutId: activePillId,
16229
- disableInitial: isModal
16230
- }
16231
- ) }),
16232
- isExpanded && /* @__PURE__ */ jsx(HoverStateLayer2, {}),
16233
- isExpanded && /* @__PURE__ */ jsx(RippleLayer2, { ripples, onRippleDone: removeRipple }),
16698
+ isExpandedPill && /* @__PURE__ */ jsxs(Fragment, { children: [
16699
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16700
+ ActivePill2,
16701
+ {
16702
+ layoutId: activePillId,
16703
+ disableInitial: isModal,
16704
+ shape: activeShape
16705
+ }
16706
+ ) }),
16707
+ /* @__PURE__ */ jsx(HoverStateLayer2, { shape: activeShape }),
16708
+ /* @__PURE__ */ jsx(
16709
+ RippleLayer2,
16710
+ {
16711
+ ripples,
16712
+ onRippleDone: removeRipple,
16713
+ shape: activeShape
16714
+ }
16715
+ )
16716
+ ] }),
16234
16717
  /* @__PURE__ */ jsxs(
16235
16718
  m.div,
16236
16719
  {
16237
16720
  layout: enableLayout,
16238
16721
  className: cn(
16239
16722
  "relative flex items-center justify-center shrink-0 z-10",
16240
- isExpanded ? "size-6" : "h-8 w-14 mx-auto"
16723
+ isSquare ? "mx-auto" : isExpandedPill ? "size-6" : "h-8 w-14 mx-auto rounded-full"
16241
16724
  ),
16242
- style: { borderRadius: 9999 },
16725
+ style: isSquare ? { width: resolvedShapeSize, height: resolvedShapeSize } : void 0,
16243
16726
  children: [
16244
- !isExpanded && /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(ActivePill2, { layoutId: activePillId }) }),
16245
- !isExpanded && /* @__PURE__ */ jsx(HoverStateLayer2, {}),
16246
- !isExpanded && /* @__PURE__ */ jsx(RippleLayer2, { ripples, onRippleDone: removeRipple }),
16727
+ !isExpandedPill && /* @__PURE__ */ jsxs(Fragment, { children: [
16728
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsx(
16729
+ ActivePill2,
16730
+ {
16731
+ layoutId: activePillId,
16732
+ disableInitial: isModal,
16733
+ shape: activeShape,
16734
+ width: iconPillWidth,
16735
+ height: iconPillHeight
16736
+ }
16737
+ ) }),
16738
+ /* @__PURE__ */ jsx(
16739
+ HoverStateLayer2,
16740
+ {
16741
+ shape: activeShape,
16742
+ width: iconPillWidth,
16743
+ height: iconPillHeight
16744
+ }
16745
+ ),
16746
+ /* @__PURE__ */ jsx(
16747
+ RippleLayer2,
16748
+ {
16749
+ ripples,
16750
+ onRippleDone: removeRipple,
16751
+ shape: activeShape,
16752
+ width: iconPillWidth,
16753
+ height: iconPillHeight
16754
+ }
16755
+ )
16756
+ ] }),
16247
16757
  /* @__PURE__ */ jsx(
16248
16758
  m.div,
16249
16759
  {
@@ -16265,8 +16775,8 @@ var NavigationRailItemComponent = React61.forwardRef(
16265
16775
  transition: SPRING_TRANSITION,
16266
16776
  className: cn(
16267
16777
  "z-10 transition-colors duration-200 whitespace-nowrap",
16268
- selected ? "text-m3-on-surface" : "text-m3-on-surface-variant",
16269
- isExpanded ? "text-sm font-medium tracking-wide text-left" : "text-xs font-medium tracking-wide"
16778
+ selected ? isExpandedPill ? "text-m3-on-secondary-container font-medium" : "text-m3-on-surface font-medium" : "text-m3-on-surface-variant font-medium",
16779
+ isExpanded ? "text-sm tracking-wide text-left" : "text-xs tracking-wide"
16270
16780
  ),
16271
16781
  children: label
16272
16782
  },
@@ -16326,6 +16836,9 @@ var NavigationRailComponent = React61.forwardRef(
16326
16836
  ({
16327
16837
  variant = "collapsed",
16328
16838
  labelVisibility = "labeled",
16839
+ shape,
16840
+ shapeSize,
16841
+ activeIndicatorWidth = "hug",
16329
16842
  header,
16330
16843
  fab,
16331
16844
  fabPlacement = "contained",
@@ -16339,6 +16852,7 @@ var NavigationRailComponent = React61.forwardRef(
16339
16852
  style
16340
16853
  }, ref) => {
16341
16854
  const isModal = variant === "modal";
16855
+ const isExpanded = variant === "expanded" || variant === "modal";
16342
16856
  const isXr = variant === "xr";
16343
16857
  const isSpatial = isXr && fabPlacement === "spatialized";
16344
16858
  const applyAnimation = !isXr || !isSpatial;
@@ -16380,10 +16894,12 @@ var NavigationRailComponent = React61.forwardRef(
16380
16894
  transition: isModal ? MD3_MODAL_TRANSITION : SPRING_TRANSITION,
16381
16895
  children: [
16382
16896
  (header || fab && !isSpatial) && /* @__PURE__ */ jsxs(
16383
- "div",
16897
+ m.div,
16384
16898
  {
16899
+ layout: true,
16385
16900
  className: cn(
16386
- "flex w-full flex-col items-center justify-start shrink-0 empty:hidden",
16901
+ "flex w-full flex-col justify-start shrink-0 empty:hidden",
16902
+ isExpanded ? "items-start px-3" : "items-center",
16387
16903
  navHeaderSpacing
16388
16904
  ),
16389
16905
  children: [
@@ -16449,6 +16965,9 @@ var NavigationRailComponent = React61.forwardRef(
16449
16965
  const contextValue = {
16450
16966
  variant,
16451
16967
  labelVisibility,
16968
+ shape,
16969
+ shapeSize,
16970
+ activeIndicatorWidth,
16452
16971
  activeIndicatorTransition
16453
16972
  };
16454
16973
  if (isModal) {
@@ -23186,6 +23705,12 @@ var BottomDockedToolbar = React61.forwardRef(
23186
23705
  BottomDockedToolbar.displayName = "BottomDockedToolbar";
23187
23706
 
23188
23707
  // src/ui/toolbar/toolbar-tokens.ts
23708
+ var TOOLBAR_SPRING_TRANSITION = {
23709
+ type: "spring",
23710
+ stiffness: 300,
23711
+ damping: 30,
23712
+ mass: 0.8
23713
+ };
23189
23714
  var FloatingToolbarTokens = {
23190
23715
  ContainerBetweenSpace: 4,
23191
23716
  ContainerHeight: 64};
@@ -23215,6 +23740,10 @@ var ToolbarToggleButtonTokens = {
23215
23740
  PaddingX: 16,
23216
23741
  Gap: 8
23217
23742
  };
23743
+ var ToolbarToggleButtonRadiusTokens = {
23744
+ pillRadius: 24,
23745
+ pressedRadius: 12
23746
+ };
23218
23747
  var ALIGNMENT_CLASS = {
23219
23748
  start: "justify-start",
23220
23749
  center: "justify-center",
@@ -23617,13 +24146,17 @@ var ToolbarIconButton = React61.forwardRef(
23617
24146
  toolbarSize = "default",
23618
24147
  selected,
23619
24148
  asChild,
23620
- className
24149
+ className,
24150
+ transition,
24151
+ whileTap
23621
24152
  } = _b, props = __objRest(_b, [
23622
24153
  "emphasis",
23623
24154
  "toolbarSize",
23624
24155
  "selected",
23625
24156
  "asChild",
23626
- "className"
24157
+ "className",
24158
+ "transition",
24159
+ "whileTap"
23627
24160
  ]);
23628
24161
  const context = useToolbarContext();
23629
24162
  const widthClass = TOOLBAR_ICON_BUTTON_WIDTH[toolbarSize];
@@ -23634,16 +24167,20 @@ var ToolbarIconButton = React61.forwardRef(
23634
24167
  } : {
23635
24168
  variant: "default"
23636
24169
  };
24170
+ const motionProps = asChild ? __spreadValues(__spreadValues({}, transition !== void 0 && { transition }), whileTap !== void 0 && { whileTap }) : {
24171
+ transition: transition != null ? transition : TOOLBAR_SPRING_TRANSITION,
24172
+ whileTap: whileTap != null ? whileTap : { scale: 0.95 }
24173
+ };
23637
24174
  return /* @__PURE__ */ jsx(
23638
24175
  IconButton,
23639
- __spreadValues(__spreadProps(__spreadValues({
24176
+ __spreadValues(__spreadProps(__spreadValues(__spreadValues({
23640
24177
  ref,
23641
24178
  asChild,
23642
24179
  colorStyle,
23643
24180
  size: "md",
23644
24181
  shape: "round",
23645
24182
  iconSize: ToolbarIconButtonTokens.IconSize
23646
- }, iconButtonProps), {
24183
+ }, motionProps), iconButtonProps), {
23647
24184
  className: cn(
23648
24185
  "h-[48px]",
23649
24186
  widthClass,
@@ -23753,29 +24290,34 @@ var ToolbarToggleButton = React61.forwardRef(
23753
24290
  selected = false,
23754
24291
  icon,
23755
24292
  children,
23756
- pressScale = 0.95,
23757
- pressBounceOffset = 6,
24293
+ pressExpand = true,
24294
+ pressExpandRatio = 0.06,
23758
24295
  ripple = true,
23759
24296
  asChild = false,
23760
24297
  className,
23761
24298
  type = "button",
23762
24299
  disabled,
23763
- onPointerDown: onPointerDownProp
24300
+ onPointerDown: onPointerDownProp,
24301
+ onPointerUp: onPointerUpProp,
24302
+ onPointerLeave: onPointerLeaveProp
23764
24303
  } = _b, props = __objRest(_b, [
23765
24304
  "emphasis",
23766
24305
  "selected",
23767
24306
  "icon",
23768
24307
  "children",
23769
- "pressScale",
23770
- "pressBounceOffset",
24308
+ "pressExpand",
24309
+ "pressExpandRatio",
23771
24310
  "ripple",
23772
24311
  "asChild",
23773
24312
  "className",
23774
24313
  "type",
23775
24314
  "disabled",
23776
- "onPointerDown"
24315
+ "onPointerDown",
24316
+ "onPointerUp",
24317
+ "onPointerLeave"
23777
24318
  ]);
23778
24319
  const context = useToolbarContext();
24320
+ const [isPressed, setIsPressed] = React61.useState(false);
23779
24321
  const {
23780
24322
  ripples,
23781
24323
  onPointerDown: handleRipplePointerDown,
@@ -23785,6 +24327,7 @@ var ToolbarToggleButton = React61.forwardRef(
23785
24327
  });
23786
24328
  const handlePointerDown = React61.useCallback(
23787
24329
  (e) => {
24330
+ setIsPressed(true);
23788
24331
  if (!disabled && ripple) {
23789
24332
  handleRipplePointerDown(e);
23790
24333
  }
@@ -23792,7 +24335,21 @@ var ToolbarToggleButton = React61.forwardRef(
23792
24335
  },
23793
24336
  [disabled, ripple, handleRipplePointerDown, onPointerDownProp]
23794
24337
  );
23795
- const baseClasses = "relative overflow-hidden inline-flex items-center justify-center min-w-[95px] h-[48px] px-4 rounded-full text-sm font-medium transition-colors select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/40 disabled:pointer-events-none disabled:opacity-38";
24338
+ const handlePointerUp = React61.useCallback(
24339
+ (e) => {
24340
+ setIsPressed(false);
24341
+ onPointerUpProp == null ? void 0 : onPointerUpProp(e);
24342
+ },
24343
+ [onPointerUpProp]
24344
+ );
24345
+ const handlePointerLeave = React61.useCallback(
24346
+ (e) => {
24347
+ setIsPressed(false);
24348
+ onPointerLeaveProp == null ? void 0 : onPointerLeaveProp(e);
24349
+ },
24350
+ [onPointerLeaveProp]
24351
+ );
24352
+ const baseClasses = "relative overflow-hidden inline-flex items-center justify-center min-w-[95px] h-[48px] px-4 text-sm font-medium select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/40 disabled:pointer-events-none disabled:opacity-38";
23796
24353
  const variantClasses = {
23797
24354
  standard: selected ? "bg-current/16 text-current hover:bg-current/20 active:bg-current/24" : "bg-transparent text-current hover:bg-current/8 active:bg-current/12",
23798
24355
  tonal: selected ? "bg-m3-secondary-container text-m3-on-secondary-container hover:shadow-sm" : "bg-m3-surface-container-high text-m3-on-surface hover:bg-m3-surface-container-highest",
@@ -23804,27 +24361,17 @@ var ToolbarToggleButton = React61.forwardRef(
23804
24361
  context == null ? void 0 : context.itemClassName,
23805
24362
  className
23806
24363
  );
23807
- const whileTapConfig = React61.useMemo(
24364
+ const animateConfig = React61.useMemo(
23808
24365
  () => ({
23809
- scale: pressScale,
23810
- x: pressBounceOffset ? [
23811
- 0,
23812
- -pressBounceOffset,
23813
- pressBounceOffset,
23814
- -pressBounceOffset / 2,
23815
- pressBounceOffset / 2,
23816
- 0
23817
- ] : 0
24366
+ scaleX: pressExpand && isPressed ? 1 + pressExpandRatio : 1,
24367
+ borderRadius: isPressed ? ToolbarToggleButtonRadiusTokens.pressedRadius : ToolbarToggleButtonRadiusTokens.pillRadius
23818
24368
  }),
23819
- [pressScale, pressBounceOffset]
24369
+ [pressExpand, pressExpandRatio, isPressed]
23820
24370
  );
23821
24371
  const transitionConfig = React61.useMemo(
23822
24372
  () => ({
23823
- scale: FAST_SPATIAL_SPRING,
23824
- x: {
23825
- duration: 0.35,
23826
- ease: "easeInOut"
23827
- }
24373
+ scaleX: FAST_SPATIAL_SPRING,
24374
+ borderRadius: BUTTON_RADIUS_SPRING
23828
24375
  }),
23829
24376
  []
23830
24377
  );
@@ -23878,7 +24425,9 @@ var ToolbarToggleButton = React61.forwardRef(
23878
24425
  ref,
23879
24426
  "aria-pressed": selected,
23880
24427
  className: combinedClassName,
23881
- onPointerDown: handlePointerDown
24428
+ onPointerDown: handlePointerDown,
24429
+ onPointerUp: handlePointerUp,
24430
+ onPointerLeave: handlePointerLeave
23882
24431
  }, strippedProps), {
23883
24432
  children: React61.cloneElement(child, { children: innerChildContent })
23884
24433
  })
@@ -23891,9 +24440,13 @@ var ToolbarToggleButton = React61.forwardRef(
23891
24440
  type,
23892
24441
  "aria-pressed": selected,
23893
24442
  disabled,
23894
- whileTap: whileTapConfig,
24443
+ animate: animateConfig,
23895
24444
  transition: transitionConfig,
24445
+ initial: false,
24446
+ style: { transformOrigin: "center" },
23896
24447
  onPointerDown: handlePointerDown,
24448
+ onPointerUp: handlePointerUp,
24449
+ onPointerLeave: handlePointerLeave,
23897
24450
  className: combinedClassName
23898
24451
  }, props), {
23899
24452
  children: [