@bug-on/m3-expressive 1.2.2 → 1.2.3

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.
@@ -1631,6 +1631,8 @@ interface NavigationBarItemProps {
1631
1631
  badge?: React$1.ReactNode;
1632
1632
  "aria-label"?: string;
1633
1633
  className?: string;
1634
+ asChild?: boolean;
1635
+ children?: React$1.ReactNode;
1634
1636
  }
1635
1637
  interface NavigationBarProps {
1636
1638
  /** Visual variant of the Navigation Bar */
@@ -1671,6 +1673,8 @@ interface NavigationRailItemProps {
1671
1673
  badge?: React$1.ReactNode;
1672
1674
  "aria-label"?: string;
1673
1675
  className?: string;
1676
+ asChild?: boolean;
1677
+ children?: React$1.ReactNode;
1674
1678
  }
1675
1679
  interface NavigationRailProps {
1676
1680
  variant?: NavigationRailVariant;
@@ -2758,6 +2762,8 @@ type ToolbarIconButtonVariant = "standard" | "tonal" | "filled";
2758
2762
  * - Support for `asChild` slot delegation.
2759
2763
  * - Always `rounded-full` shape (required for floating toolbars per MD3 spec).
2760
2764
  * - Always 48dp height to meet MD3 accessibility touch-target requirements.
2765
+ * - Material Design 3 Expressive spring motion physics (`TOOLBAR_SPRING_TRANSITION`)
2766
+ * synchronized with `ButtonDistribute` for responsive press scale and width expansion.
2761
2767
  *
2762
2768
  * @example
2763
2769
  * ```tsx
@@ -1631,6 +1631,8 @@ interface NavigationBarItemProps {
1631
1631
  badge?: React$1.ReactNode;
1632
1632
  "aria-label"?: string;
1633
1633
  className?: string;
1634
+ asChild?: boolean;
1635
+ children?: React$1.ReactNode;
1634
1636
  }
1635
1637
  interface NavigationBarProps {
1636
1638
  /** Visual variant of the Navigation Bar */
@@ -1671,6 +1673,8 @@ interface NavigationRailItemProps {
1671
1673
  badge?: React$1.ReactNode;
1672
1674
  "aria-label"?: string;
1673
1675
  className?: string;
1676
+ asChild?: boolean;
1677
+ children?: React$1.ReactNode;
1674
1678
  }
1675
1679
  interface NavigationRailProps {
1676
1680
  variant?: NavigationRailVariant;
@@ -2758,6 +2762,8 @@ type ToolbarIconButtonVariant = "standard" | "tonal" | "filled";
2758
2762
  * - Support for `asChild` slot delegation.
2759
2763
  * - Always `rounded-full` shape (required for floating toolbars per MD3 spec).
2760
2764
  * - Always 48dp height to meet MD3 accessibility touch-target requirements.
2765
+ * - Material Design 3 Expressive spring motion physics (`TOOLBAR_SPRING_TRANSITION`)
2766
+ * synchronized with `ButtonDistribute` for responsive press scale and width expansion.
2761
2767
  *
2762
2768
  * @example
2763
2769
  * ```tsx
@@ -2685,8 +2685,11 @@ var NavigationBarItemComponent = React36__namespace.forwardRef(
2685
2685
  disabled = false,
2686
2686
  badge,
2687
2687
  className,
2688
- "aria-label": ariaLabelProp
2688
+ "aria-label": ariaLabelProp,
2689
+ asChild = false,
2690
+ children
2689
2691
  }, ref) => {
2692
+ var _a;
2690
2693
  const {
2691
2694
  variant,
2692
2695
  itemLayout,
@@ -2714,6 +2717,101 @@ var NavigationBarItemComponent = React36__namespace.forwardRef(
2714
2717
  [disabled, selected, onClick]
2715
2718
  );
2716
2719
  const filledIcon = cloneIconWithFill(icon, selected);
2720
+ const itemClassName = cn(
2721
+ "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none h-full items-center justify-center min-w-0",
2722
+ 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",
2723
+ disabled && "pointer-events-none opacity-[0.38]",
2724
+ contextItemClassName,
2725
+ className
2726
+ );
2727
+ if (asChild && children) {
2728
+ const child = React36__namespace.Children.only(children);
2729
+ const innerContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2730
+ /* @__PURE__ */ jsxRuntime.jsxs(
2731
+ "div",
2732
+ {
2733
+ className: cn(
2734
+ "relative flex items-center justify-center flex-col gap-y-1 w-full px-1 py-1.5",
2735
+ 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",
2736
+ isForcedHorizontal && "flex-row gap-y-0 gap-x-1.5 h-10 px-4 py-0 rounded-full w-auto"
2737
+ ),
2738
+ children: [
2739
+ /* @__PURE__ */ jsxRuntime.jsxs(
2740
+ "div",
2741
+ {
2742
+ className: cn(
2743
+ "absolute inset-0 z-0 hidden",
2744
+ isResponsiveHorizontal && "min-[600px]:block",
2745
+ isForcedHorizontal && "block!"
2746
+ ),
2747
+ children: [
2748
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsxRuntime.jsx(ActivePill, {}) }),
2749
+ /* @__PURE__ */ jsxRuntime.jsx(HoverStateLayer, {}),
2750
+ /* @__PURE__ */ jsxRuntime.jsx(RippleLayer, { ripples, onRippleDone: removeRipple })
2751
+ ]
2752
+ }
2753
+ ),
2754
+ /* @__PURE__ */ jsxRuntime.jsxs(
2755
+ "div",
2756
+ {
2757
+ className: cn(
2758
+ "relative flex items-center justify-center shrink-0 z-10",
2759
+ "h-8 w-16 mx-auto rounded-full",
2760
+ isResponsiveHorizontal && "min-[600px]:size-6 min-[600px]:w-auto min-[600px]:h-auto",
2761
+ isForcedHorizontal && "size-6 w-auto h-auto"
2762
+ ),
2763
+ children: [
2764
+ /* @__PURE__ */ jsxRuntime.jsxs(
2765
+ "div",
2766
+ {
2767
+ className: cn(
2768
+ "absolute inset-0 z-0",
2769
+ isResponsiveHorizontal && "min-[600px]:hidden",
2770
+ isForcedHorizontal && "hidden"
2771
+ ),
2772
+ children: [
2773
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsxRuntime.jsx(ActivePill, {}) }),
2774
+ /* @__PURE__ */ jsxRuntime.jsx(HoverStateLayer, {}),
2775
+ /* @__PURE__ */ jsxRuntime.jsx(RippleLayer, { ripples, onRippleDone: removeRipple })
2776
+ ]
2777
+ }
2778
+ ),
2779
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10 flex size-6 items-center justify-center text-current", children: /* @__PURE__ */ jsxRuntime.jsx(IconContainer, { selected, badge, children: filledIcon }) })
2780
+ ]
2781
+ }
2782
+ ),
2783
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsxRuntime.jsx(
2784
+ "span",
2785
+ {
2786
+ className: cn(
2787
+ "z-10 transition-all duration-200 truncate px-1",
2788
+ selected ? "text-m3-on-surface" : "text-m3-on-surface-variant",
2789
+ "font-medium text-[12px] leading-4 tracking-[0.5px]"
2790
+ ),
2791
+ children: (_a = child.props.children) != null ? _a : label
2792
+ },
2793
+ "nav-label"
2794
+ ) })
2795
+ ]
2796
+ }
2797
+ ),
2798
+ /* @__PURE__ */ jsxRuntime.jsx(TouchTarget, {})
2799
+ ] });
2800
+ return /* @__PURE__ */ jsxRuntime.jsx(
2801
+ reactSlot.Slot,
2802
+ {
2803
+ ref,
2804
+ role: "menuitem",
2805
+ "aria-current": selected ? "page" : void 0,
2806
+ "aria-disabled": disabled ? true : void 0,
2807
+ "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
2808
+ onClick: handleClick,
2809
+ onPointerDown,
2810
+ className: itemClassName,
2811
+ children: React36__namespace.cloneElement(child, { children: innerContent })
2812
+ }
2813
+ );
2814
+ }
2717
2815
  return /* @__PURE__ */ jsxRuntime.jsxs(
2718
2816
  react.m.button,
2719
2817
  {
@@ -2725,13 +2823,7 @@ var NavigationBarItemComponent = React36__namespace.forwardRef(
2725
2823
  "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
2726
2824
  onClick: handleClick,
2727
2825
  onPointerDown,
2728
- className: cn(
2729
- "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none h-full items-center justify-center min-w-0",
2730
- 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",
2731
- disabled && "pointer-events-none opacity-[0.38]",
2732
- contextItemClassName,
2733
- className
2734
- ),
2826
+ className: itemClassName,
2735
2827
  children: [
2736
2828
  /* @__PURE__ */ jsxRuntime.jsxs(
2737
2829
  "div",
@@ -3036,8 +3128,11 @@ var NavigationRailItemComponent = React36__namespace.forwardRef(
3036
3128
  disabled = false,
3037
3129
  badge,
3038
3130
  className,
3039
- "aria-label": ariaLabelProp
3131
+ "aria-label": ariaLabelProp,
3132
+ asChild = false,
3133
+ children
3040
3134
  }, ref) => {
3135
+ var _a;
3041
3136
  const { variant, labelVisibility } = React36__namespace.useContext(
3042
3137
  NavigationRailContext
3043
3138
  );
@@ -3061,6 +3156,96 @@ var NavigationRailItemComponent = React36__namespace.forwardRef(
3061
3156
  );
3062
3157
  const filledIcon = cloneIconWithFill2(icon, selected);
3063
3158
  const labelInitial = isModal ? false : { opacity: 0, x: isExpanded ? -12 : 0, y: isExpanded ? 0 : -8 };
3159
+ const itemClassName = cn(
3160
+ "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none",
3161
+ "focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2 rounded-full",
3162
+ disabled && "pointer-events-none opacity-[0.38]",
3163
+ isExpanded ? "w-full flex-row items-center px-3 h-14" : "w-full flex-col justify-center h-14",
3164
+ className
3165
+ );
3166
+ if (asChild && children) {
3167
+ const child = React36__namespace.Children.only(children);
3168
+ const innerContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3169
+ /* @__PURE__ */ jsxRuntime.jsxs(
3170
+ react.m.div,
3171
+ {
3172
+ layout: enableLayout,
3173
+ className: cn(
3174
+ "relative flex z-10",
3175
+ 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"
3176
+ ),
3177
+ children: [
3178
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsxRuntime.jsx(
3179
+ ActivePill2,
3180
+ {
3181
+ layoutId: activePillId,
3182
+ disableInitial: isModal
3183
+ }
3184
+ ) }),
3185
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(HoverStateLayer2, {}),
3186
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(RippleLayer2, { ripples, onRippleDone: removeRipple }),
3187
+ /* @__PURE__ */ jsxRuntime.jsxs(
3188
+ react.m.div,
3189
+ {
3190
+ layout: enableLayout,
3191
+ className: cn(
3192
+ "relative flex items-center justify-center shrink-0 z-10",
3193
+ isExpanded ? "size-6" : "h-8 w-14 mx-auto"
3194
+ ),
3195
+ style: { borderRadius: 9999 },
3196
+ children: [
3197
+ !isExpanded && /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { initial: false, children: selected && /* @__PURE__ */ jsxRuntime.jsx(ActivePill2, { layoutId: activePillId }) }),
3198
+ !isExpanded && /* @__PURE__ */ jsxRuntime.jsx(HoverStateLayer2, {}),
3199
+ !isExpanded && /* @__PURE__ */ jsxRuntime.jsx(RippleLayer2, { ripples, onRippleDone: removeRipple }),
3200
+ /* @__PURE__ */ jsxRuntime.jsx(
3201
+ react.m.div,
3202
+ {
3203
+ layout: enableLayout ? "position" : false,
3204
+ className: "relative z-10 flex size-6 items-center justify-center text-current",
3205
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconContainer2, { selected, badge, children: filledIcon })
3206
+ }
3207
+ )
3208
+ ]
3209
+ }
3210
+ ),
3211
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "popLayout", children: showLabel && (label || child.props.children) && /* @__PURE__ */ jsxRuntime.jsx(
3212
+ react.m.span,
3213
+ {
3214
+ layout: enableLayout ? "position" : false,
3215
+ initial: labelInitial,
3216
+ animate: { opacity: 1, x: 0, y: 0 },
3217
+ exit: { opacity: 0, transition: { duration: 0.1 } },
3218
+ transition: SPRING_TRANSITION,
3219
+ className: cn(
3220
+ "z-10 transition-colors duration-200 whitespace-nowrap",
3221
+ selected ? "text-m3-on-surface" : "text-m3-on-surface-variant",
3222
+ isExpanded ? "text-sm font-medium tracking-wide text-left" : "text-xs font-medium tracking-wide"
3223
+ ),
3224
+ children: (_a = child.props.children) != null ? _a : label
3225
+ },
3226
+ "rail-label"
3227
+ ) })
3228
+ ]
3229
+ }
3230
+ ),
3231
+ /* @__PURE__ */ jsxRuntime.jsx(TouchTarget, {})
3232
+ ] });
3233
+ return /* @__PURE__ */ jsxRuntime.jsx(react.LazyMotion, { features: react.domMax, strict: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3234
+ reactSlot.Slot,
3235
+ {
3236
+ ref,
3237
+ role: "menuitem",
3238
+ "aria-current": selected ? "page" : void 0,
3239
+ "aria-disabled": disabled ? true : void 0,
3240
+ "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
3241
+ onClick: handleClick,
3242
+ onPointerDown,
3243
+ className: itemClassName,
3244
+ tabIndex: -1,
3245
+ children: React36__namespace.cloneElement(child, { children: innerContent })
3246
+ }
3247
+ ) });
3248
+ }
3064
3249
  return /* @__PURE__ */ jsxRuntime.jsx(react.LazyMotion, { features: react.domMax, strict: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
3065
3250
  react.m.button,
3066
3251
  {
@@ -3073,13 +3258,7 @@ var NavigationRailItemComponent = React36__namespace.forwardRef(
3073
3258
  "aria-label": ariaLabelProp || (typeof label === "string" ? label : void 0),
3074
3259
  onClick: handleClick,
3075
3260
  onPointerDown,
3076
- className: cn(
3077
- "group relative flex cursor-pointer transition-colors duration-200 outline-none select-none",
3078
- "focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2 rounded-full",
3079
- disabled && "pointer-events-none opacity-[0.38]",
3080
- isExpanded ? "w-full flex-row items-center px-3 h-14" : "w-full flex-col justify-center h-14",
3081
- className
3082
- ),
3261
+ className: itemClassName,
3083
3262
  tabIndex: -1,
3084
3263
  children: [
3085
3264
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6217,6 +6396,12 @@ var BottomDockedToolbar = React36__namespace.forwardRef(
6217
6396
  BottomDockedToolbar.displayName = "BottomDockedToolbar";
6218
6397
 
6219
6398
  // src/ui/toolbar/toolbar-tokens.ts
6399
+ var TOOLBAR_SPRING_TRANSITION = {
6400
+ type: "spring",
6401
+ stiffness: 300,
6402
+ damping: 30,
6403
+ mass: 0.8
6404
+ };
6220
6405
  var FloatingToolbarTokens = {
6221
6406
  ContainerBetweenSpace: 4,
6222
6407
  ContainerHeight: 64};
@@ -6648,13 +6833,17 @@ var ToolbarIconButton = React36__namespace.forwardRef(
6648
6833
  toolbarSize = "default",
6649
6834
  selected,
6650
6835
  asChild,
6651
- className
6836
+ className,
6837
+ transition,
6838
+ whileTap
6652
6839
  } = _b, props = __objRest(_b, [
6653
6840
  "emphasis",
6654
6841
  "toolbarSize",
6655
6842
  "selected",
6656
6843
  "asChild",
6657
- "className"
6844
+ "className",
6845
+ "transition",
6846
+ "whileTap"
6658
6847
  ]);
6659
6848
  const context = useToolbarContext();
6660
6849
  const widthClass = TOOLBAR_ICON_BUTTON_WIDTH[toolbarSize];
@@ -6665,16 +6854,20 @@ var ToolbarIconButton = React36__namespace.forwardRef(
6665
6854
  } : {
6666
6855
  variant: "default"
6667
6856
  };
6857
+ const motionProps = asChild ? __spreadValues(__spreadValues({}, transition !== void 0 && { transition }), whileTap !== void 0 && { whileTap }) : {
6858
+ transition: transition != null ? transition : TOOLBAR_SPRING_TRANSITION,
6859
+ whileTap: whileTap != null ? whileTap : { scale: 0.95 }
6860
+ };
6668
6861
  return /* @__PURE__ */ jsxRuntime.jsx(
6669
6862
  IconButton,
6670
- __spreadValues(__spreadProps(__spreadValues({
6863
+ __spreadValues(__spreadProps(__spreadValues(__spreadValues({
6671
6864
  ref,
6672
6865
  asChild,
6673
6866
  colorStyle,
6674
6867
  size: "md",
6675
6868
  shape: "round",
6676
6869
  iconSize: ToolbarIconButtonTokens.IconSize
6677
- }, iconButtonProps), {
6870
+ }, motionProps), iconButtonProps), {
6678
6871
  className: cn(
6679
6872
  "h-[48px]",
6680
6873
  widthClass,
@@ -6850,8 +7043,8 @@ var ToolbarToggleButton = React36__namespace.forwardRef(
6850
7043
  [pressScale, pressBounceOffset]
6851
7044
  );
6852
7045
  const transitionConfig = React36__namespace.useMemo(
6853
- () => ({
6854
- scale: FAST_SPATIAL_SPRING,
7046
+ () => __spreadProps(__spreadValues({}, TOOLBAR_SPRING_TRANSITION), {
7047
+ scale: TOOLBAR_SPRING_TRANSITION,
6855
7048
  x: {
6856
7049
  duration: 0.35,
6857
7050
  ease: "easeInOut"