@tinybigui/react 0.11.1 → 0.11.2

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.d.cts CHANGED
@@ -3085,15 +3085,12 @@ declare const Tabs: React__default.ForwardRefExoticComponent<TabsProps & React__
3085
3085
  * Uses React Aria's useTabList for role="tablist", keyboard navigation,
3086
3086
  * and accessibility attributes.
3087
3087
  *
3088
- * The active indicator slides to the selected tab using CSS transitions
3089
- * with MD3 motion tokens (medium2 duration, emphasized easing).
3088
+ * Active indicator behavior (MD3 spec):
3089
+ * - Primary: indicator width = content (label/icon) width, centered under content.
3090
+ * Measured via the [data-tab-content] child span of the selected tab.
3091
+ * - Secondary: indicator spans the full tab button width.
3090
3092
  *
3091
- * MD3 Specifications:
3092
- * - Container background: bg-surface
3093
- * - Container height: 48dp
3094
- * - Bottom border: 1dp, outline-variant color
3095
- * - Fixed layout: tabs fill width equally
3096
- * - Scrollable layout: overflow-x, no wrapping
3093
+ * Motion: left and width are spatial properties → spring-standard-default-spatial.
3097
3094
  *
3098
3095
  * @example
3099
3096
  * ```tsx
@@ -3111,25 +3108,26 @@ declare const TabList: React__default.ForwardRefExoticComponent<TabListProps & R
3111
3108
  /**
3112
3109
  * Material Design 3 Tab Component (Layer 3: Styled)
3113
3110
  *
3114
- * Renders a single tab item inside a TabList.
3115
- * Supports three content modes: icon-only, label-only, icon + label (stacked).
3111
+ * Architecture: Variants-vs-States
3112
+ * - Design-time variants (primary/secondary, fixed/scrollable) live in CVA.
3113
+ * - All interaction states are expressed as data-* attributes on the root button
3114
+ * via getInteractionDataAttributes, consumed by slots using group-data-[x]/tab.
3115
+ * - Content flags (data-with-icon, data-with-label) describe structure, set explicitly.
3116
3116
  *
3117
- * Features:
3118
- * - Icon-only, label-only, icon + label (stacked) content modes
3119
- * - Ripple effect (Material Design)
3120
- * - MD3 state layers (hover 8%, pressed 12%)
3121
- * - Badge support (numeric, dot, 999+)
3122
- * - Disabled state (opacity-38, not focusable)
3123
- * - ✅ Full keyboard accessibility (via React Aria)
3124
- * - ✅ Primary/secondary variant colors
3117
+ * Slots:
3118
+ * root button — group/tab; typography, label color, disabled, content flags
3119
+ * state layer — absolute inset hover/focus/pressed overlay
3120
+ * content span — data-tab-content; measured by TabList for primary indicator width
3121
+ * icon wrapper — 24dp icon + badge anchor
3122
+ * label span — truncated text label
3125
3123
  *
3126
3124
  * MD3 Specifications:
3127
- * - Minimum height: 48dp
3128
- * - Minimum width: 90dp
3129
- * - Typography: Title Small (14px, weight 500, tracking 0.1px)
3130
- * - Icon: 24x24dp
3131
- * - Active indicator: 3dp primary / 2dp secondary
3132
- * - State layers: 8% hover, 12% pressed/focus
3125
+ * - Minimum height: 48dp (label/icon-only), 64dp (icon+label stacked)
3126
+ * - Typography: Title Small (text-title-small, weight 500, tracking 0.1px)
3127
+ * - Icon: 24×24dp
3128
+ * - Active indicator: 3dp primary / 2dp secondary — both bg-primary
3129
+ * - State layers: hover 8%, focus/pressed 10%
3130
+ * - Disabled: 38% opacity (not focusable)
3133
3131
  *
3134
3132
  * @example
3135
3133
  * ```tsx
package/dist/index.d.ts CHANGED
@@ -3085,15 +3085,12 @@ declare const Tabs: React__default.ForwardRefExoticComponent<TabsProps & React__
3085
3085
  * Uses React Aria's useTabList for role="tablist", keyboard navigation,
3086
3086
  * and accessibility attributes.
3087
3087
  *
3088
- * The active indicator slides to the selected tab using CSS transitions
3089
- * with MD3 motion tokens (medium2 duration, emphasized easing).
3088
+ * Active indicator behavior (MD3 spec):
3089
+ * - Primary: indicator width = content (label/icon) width, centered under content.
3090
+ * Measured via the [data-tab-content] child span of the selected tab.
3091
+ * - Secondary: indicator spans the full tab button width.
3090
3092
  *
3091
- * MD3 Specifications:
3092
- * - Container background: bg-surface
3093
- * - Container height: 48dp
3094
- * - Bottom border: 1dp, outline-variant color
3095
- * - Fixed layout: tabs fill width equally
3096
- * - Scrollable layout: overflow-x, no wrapping
3093
+ * Motion: left and width are spatial properties → spring-standard-default-spatial.
3097
3094
  *
3098
3095
  * @example
3099
3096
  * ```tsx
@@ -3111,25 +3108,26 @@ declare const TabList: React__default.ForwardRefExoticComponent<TabListProps & R
3111
3108
  /**
3112
3109
  * Material Design 3 Tab Component (Layer 3: Styled)
3113
3110
  *
3114
- * Renders a single tab item inside a TabList.
3115
- * Supports three content modes: icon-only, label-only, icon + label (stacked).
3111
+ * Architecture: Variants-vs-States
3112
+ * - Design-time variants (primary/secondary, fixed/scrollable) live in CVA.
3113
+ * - All interaction states are expressed as data-* attributes on the root button
3114
+ * via getInteractionDataAttributes, consumed by slots using group-data-[x]/tab.
3115
+ * - Content flags (data-with-icon, data-with-label) describe structure, set explicitly.
3116
3116
  *
3117
- * Features:
3118
- * - Icon-only, label-only, icon + label (stacked) content modes
3119
- * - Ripple effect (Material Design)
3120
- * - MD3 state layers (hover 8%, pressed 12%)
3121
- * - Badge support (numeric, dot, 999+)
3122
- * - Disabled state (opacity-38, not focusable)
3123
- * - ✅ Full keyboard accessibility (via React Aria)
3124
- * - ✅ Primary/secondary variant colors
3117
+ * Slots:
3118
+ * root button — group/tab; typography, label color, disabled, content flags
3119
+ * state layer — absolute inset hover/focus/pressed overlay
3120
+ * content span — data-tab-content; measured by TabList for primary indicator width
3121
+ * icon wrapper — 24dp icon + badge anchor
3122
+ * label span — truncated text label
3125
3123
  *
3126
3124
  * MD3 Specifications:
3127
- * - Minimum height: 48dp
3128
- * - Minimum width: 90dp
3129
- * - Typography: Title Small (14px, weight 500, tracking 0.1px)
3130
- * - Icon: 24x24dp
3131
- * - Active indicator: 3dp primary / 2dp secondary
3132
- * - State layers: 8% hover, 12% pressed/focus
3125
+ * - Minimum height: 48dp (label/icon-only), 64dp (icon+label stacked)
3126
+ * - Typography: Title Small (text-title-small, weight 500, tracking 0.1px)
3127
+ * - Icon: 24×24dp
3128
+ * - Active indicator: 3dp primary / 2dp secondary — both bg-primary
3129
+ * - State layers: hover 8%, focus/pressed 10%
3130
+ * - Disabled: 38% opacity (not focusable)
3133
3131
  *
3134
3132
  * @example
3135
3133
  * ```tsx
package/dist/index.js CHANGED
@@ -3667,10 +3667,9 @@ var Tabs = forwardRef(
3667
3667
  Tabs.displayName = "Tabs";
3668
3668
  var tabListVariants = cva(
3669
3669
  [
3670
- // Base classes
3671
3670
  "relative flex",
3672
3671
  "bg-surface",
3673
- // Bottom divider line (MD3 spec)
3672
+ // MD3: 1dp bottom divider in outline-variant color
3674
3673
  "border-b border-outline-variant"
3675
3674
  ],
3676
3675
  {
@@ -3687,108 +3686,110 @@ var tabListVariants = cva(
3687
3686
  );
3688
3687
  var tabVariants = cva(
3689
3688
  [
3690
- // Base layout
3689
+ // Layout
3691
3690
  "relative flex flex-col items-center justify-center",
3692
3691
  "min-h-12 px-4",
3693
3692
  "cursor-pointer select-none",
3693
+ // Clip state layer to tab boundary
3694
3694
  "overflow-hidden",
3695
- // Typography: MD3 Title Small
3696
- "text-sm font-medium tracking-[0.1px]",
3697
- // Transition
3698
- "transition-colors duration-200",
3699
- // Focus visible
3695
+ // MD3 Title Small typography
3696
+ "text-title-small font-medium tracking-[0.1px]",
3697
+ // Effects transition for color changes (not spatial)
3698
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
3699
+ // Remove default button focus outline — handled via group-data-[focus-visible]/tab
3700
3700
  "focus-visible:outline-none",
3701
- // State layer via before pseudo-element
3702
- "before:absolute before:inset-0 before:transition-opacity before:duration-200",
3703
- "before:bg-current before:opacity-0",
3704
- "hover:before:opacity-8",
3705
- "active:before:opacity-12",
3706
- "focus-visible:before:opacity-12"
3701
+ // Disabled self-targeting data-[x]: selectors (not group)
3702
+ "data-[disabled]:opacity-38 data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
3703
+ // Icon+label stacked: 64dp height
3704
+ "data-[with-icon]:data-[with-label]:min-h-16"
3707
3705
  ],
3708
3706
  {
3709
3707
  variants: {
3710
3708
  /**
3711
- * Tab variant (Primary or Secondary)
3709
+ * Design-time variant: affects active label/icon color and state-layer color.
3710
+ * primary: active → text-primary
3711
+ * secondary: active → text-on-surface
3712
3712
  */
3713
3713
  variant: {
3714
- primary: "",
3715
- secondary: ""
3716
- },
3717
- /**
3718
- * Selected state
3719
- */
3720
- selected: {
3721
- true: "",
3722
- false: ""
3723
- },
3724
- /**
3725
- * Disabled state
3726
- */
3727
- disabled: {
3728
- true: "opacity-38 cursor-not-allowed pointer-events-none",
3729
- false: ""
3714
+ primary: [
3715
+ // Inactive: on-surface-variant (base)
3716
+ "text-on-surface-variant",
3717
+ // Active: text-primary
3718
+ "group-data-[selected]/tab:text-primary"
3719
+ // Disabled active: on-surface/38 inherits from opacity-38 on root
3720
+ ],
3721
+ secondary: [
3722
+ // Inactive: on-surface-variant (base)
3723
+ "text-on-surface-variant",
3724
+ // Active: on-surface
3725
+ "group-data-[selected]/tab:text-on-surface"
3726
+ ]
3730
3727
  },
3731
3728
  /**
3732
- * Layout determines min-width behavior
3729
+ * Design-time variant: affects flex sizing in the tab row.
3733
3730
  */
3734
3731
  layout: {
3735
3732
  fixed: "flex-1",
3736
3733
  scrollable: "min-w-[90px] shrink-0"
3737
3734
  }
3738
3735
  },
3739
- compoundVariants: [
3740
- // Primary + selected
3741
- {
3742
- variant: "primary",
3743
- selected: true,
3744
- disabled: false,
3745
- className: "text-primary"
3746
- },
3747
- // Primary + unselected
3748
- {
3749
- variant: "primary",
3750
- selected: false,
3751
- disabled: false,
3752
- className: "text-on-surface-variant"
3753
- },
3754
- // Secondary + selected
3755
- {
3756
- variant: "secondary",
3757
- selected: true,
3758
- disabled: false,
3759
- className: "text-on-surface"
3760
- },
3761
- // Secondary + unselected
3762
- {
3763
- variant: "secondary",
3764
- selected: false,
3765
- disabled: false,
3766
- className: "text-on-surface-variant"
3767
- }
3768
- ],
3736
+ // compoundVariants intentionally empty — state combinations are handled
3737
+ // via group-data-[selected]/tab:group-data-[...]/tab: in state slot
3738
+ compoundVariants: [],
3769
3739
  defaultVariants: {
3770
3740
  variant: "primary",
3771
- selected: false,
3772
- disabled: false,
3773
3741
  layout: "fixed"
3774
3742
  }
3775
3743
  }
3776
3744
  );
3745
+ var tabStateLayerVariants = cva(
3746
+ [
3747
+ "absolute inset-0 pointer-events-none opacity-0",
3748
+ // Effects transition for opacity — no spatial overshoot
3749
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
3750
+ // Hover: 8%
3751
+ "group-data-[hovered]/tab:opacity-8",
3752
+ // Focus: 10%
3753
+ "group-data-[focus-visible]/tab:opacity-10",
3754
+ // Pressed: 10%, doubled selector beats hover at equal cascade position
3755
+ "group-data-[pressed]/tab:group-data-[pressed]/tab:opacity-10",
3756
+ // No state layer when disabled
3757
+ "group-data-[disabled]/tab:hidden"
3758
+ ],
3759
+ {
3760
+ variants: {
3761
+ variant: {
3762
+ primary: [
3763
+ // Inactive state-layer color
3764
+ "bg-on-surface",
3765
+ // Active state-layer color (higher cascade position wins over base bg-on-surface)
3766
+ "group-data-[selected]/tab:bg-primary"
3767
+ ],
3768
+ secondary: [
3769
+ // Secondary: always on-surface
3770
+ "bg-on-surface"
3771
+ ]
3772
+ }
3773
+ },
3774
+ defaultVariants: {
3775
+ variant: "primary"
3776
+ }
3777
+ }
3778
+ );
3777
3779
  var tabIndicatorVariants = cva(
3778
3780
  [
3779
- // Base: absolutely positioned at bottom
3780
3781
  "absolute bottom-0 left-0",
3781
3782
  "pointer-events-none",
3782
- // Transition using MD3 motion tokens (medium2 duration, emphasized easing)
3783
+ // Spatial spring indicator position/width are spatial (not effects)
3783
3784
  "transition-[left,width]",
3784
- "duration-medium2",
3785
- "ease-emphasized"
3785
+ "duration-spring-standard-default-spatial",
3786
+ "ease-spring-standard-default-spatial"
3786
3787
  ],
3787
3788
  {
3788
3789
  variants: {
3789
3790
  variant: {
3790
- primary: ["h-[3px]", "bg-primary", "rounded-t-sm"],
3791
- secondary: ["h-[2px]", "bg-on-surface-variant"]
3791
+ primary: ["h-[3px]", "bg-primary", "rounded-tl-sm rounded-tr-sm"],
3792
+ secondary: ["h-[2px]", "bg-primary"]
3792
3793
  }
3793
3794
  },
3794
3795
  defaultVariants: {
@@ -3796,20 +3797,28 @@ var tabIndicatorVariants = cva(
3796
3797
  }
3797
3798
  }
3798
3799
  );
3799
- var tabPanelVariants = cva(
3800
+ var tabIconVariants = cva(
3800
3801
  [
3801
- // Base panel styles
3802
- "outline-none",
3803
- "focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2"
3802
+ "relative inline-flex items-center justify-center",
3803
+ // MD3 tab icon size: 24dp
3804
+ "size-6",
3805
+ // Effects transition for color (inherited from parent, guard here too)
3806
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
3804
3807
  ],
3805
3808
  {
3806
- variants: {},
3807
- defaultVariants: {}
3809
+ variants: {
3810
+ hasLabel: {
3811
+ true: "mb-1",
3812
+ false: ""
3813
+ }
3814
+ },
3815
+ defaultVariants: {
3816
+ hasLabel: false
3817
+ }
3808
3818
  }
3809
3819
  );
3810
3820
  var tabBadgeVariants = cva(
3811
3821
  [
3812
- // Base badge
3813
3822
  "absolute",
3814
3823
  "inline-flex items-center justify-center",
3815
3824
  "bg-error text-on-error",
@@ -3819,7 +3828,7 @@ var tabBadgeVariants = cva(
3819
3828
  {
3820
3829
  variants: {
3821
3830
  type: {
3822
- dot: ["top-1 right-1", "w-1.5 h-1.5", "rounded-full"],
3831
+ dot: ["top-0 right-0", "w-1.5 h-1.5", "rounded-full"],
3823
3832
  count: ["-top-1 -right-1", "min-w-[16px] h-4", "px-1", "rounded-full", "text-[11px]"]
3824
3833
  }
3825
3834
  },
@@ -3828,20 +3837,10 @@ var tabBadgeVariants = cva(
3828
3837
  }
3829
3838
  }
3830
3839
  );
3831
- var tabIconVariants = cva(
3832
- ["relative", "inline-flex items-center justify-center", "w-6 h-6"],
3833
- {
3834
- variants: {
3835
- hasLabel: {
3836
- true: "mb-1",
3837
- false: ""
3838
- }
3839
- },
3840
- defaultVariants: {
3841
- hasLabel: false
3842
- }
3843
- }
3844
- );
3840
+ var tabPanelVariants = cva([
3841
+ "outline-none",
3842
+ "focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2"
3843
+ ]);
3845
3844
  var TabList = forwardRef(
3846
3845
  ({ children, className }, forwardedRef) => {
3847
3846
  const { state } = useHeadlessTabsContext("TabList");
@@ -3920,18 +3919,41 @@ var TabList = forwardRef(
3920
3919
  const selectedTab = container.querySelector('[aria-selected="true"]');
3921
3920
  if (!selectedTab) return;
3922
3921
  const containerRect = container.getBoundingClientRect();
3923
- const tabRect = selectedTab.getBoundingClientRect();
3924
- const newLeft = tabRect.left - containerRect.left + container.scrollLeft;
3925
- const newWidth = tabRect.width;
3926
- setIndicatorStyle((prev) => {
3927
- if (prev.left === newLeft && prev.width === newWidth) return prev;
3928
- return { left: newLeft, width: newWidth };
3929
- });
3922
+ if (variant === "primary") {
3923
+ const contentEl = selectedTab.querySelector("[data-tab-content]");
3924
+ if (!contentEl) return;
3925
+ const contentRect = contentEl.getBoundingClientRect();
3926
+ const newLeft = contentRect.left - containerRect.left + container.scrollLeft;
3927
+ const newWidth = contentRect.width;
3928
+ setIndicatorStyle((prev) => {
3929
+ if (prev.left === newLeft && prev.width === newWidth) return prev;
3930
+ return { left: newLeft, width: newWidth };
3931
+ });
3932
+ } else {
3933
+ const tabRect = selectedTab.getBoundingClientRect();
3934
+ const newLeft = tabRect.left - containerRect.left + container.scrollLeft;
3935
+ const newWidth = tabRect.width;
3936
+ setIndicatorStyle((prev) => {
3937
+ if (prev.left === newLeft && prev.width === newWidth) return prev;
3938
+ return { left: newLeft, width: newWidth };
3939
+ });
3940
+ }
3930
3941
  setIndicatorReady(true);
3931
- }, [ref]);
3942
+ }, [ref, variant]);
3932
3943
  useLayoutEffect(() => {
3933
3944
  updateIndicator();
3934
3945
  }, [state.selectedKey, updateIndicator]);
3946
+ useEffect(() => {
3947
+ const container = ref.current;
3948
+ if (!container || typeof ResizeObserver === "undefined") return;
3949
+ const observer = new ResizeObserver(() => {
3950
+ updateIndicator();
3951
+ });
3952
+ observer.observe(container);
3953
+ return () => {
3954
+ observer.disconnect();
3955
+ };
3956
+ }, [ref, updateIndicator]);
3935
3957
  const mergedTabListProps = { ...tabListProps, onKeyDown: handleKeyDown };
3936
3958
  return /* @__PURE__ */ jsxs("div", { ...mergedTabListProps, ref, className: cn(tabListVariants({ layout }), className), children: [
3937
3959
  children,
@@ -3946,7 +3968,6 @@ var TabList = forwardRef(
3946
3968
  !indicatorReady && "opacity-0"
3947
3969
  ),
3948
3970
  style: {
3949
- // Dynamic left/width values from DOM measurements
3950
3971
  left: `${indicatorStyle.left}px`,
3951
3972
  width: `${indicatorStyle.width}px`
3952
3973
  }
@@ -3974,10 +3995,12 @@ var Tab = forwardRef(
3974
3995
  const {
3975
3996
  tabProps,
3976
3997
  isSelected,
3977
- isDisabled: ariaIsDisabled
3998
+ isDisabled: ariaIsDisabled,
3999
+ isPressed
3978
4000
  } = useTab({ key: id, isDisabled }, state, ref);
3979
4001
  const { isFocusVisible, focusProps } = useFocusRing();
3980
4002
  const finalIsDisabled = isDisabled || ariaIsDisabled;
4003
+ const { isHovered, hoverProps } = useHover({ isDisabled: finalIsDisabled });
3981
4004
  const { onMouseDown: handleRipple, ripples } = useRipple({
3982
4005
  disabled: finalIsDisabled || disableRipple
3983
4006
  });
@@ -3991,7 +4014,7 @@ var Tab = forwardRef(
3991
4014
  state.selectionManager.setFocusedKey(id);
3992
4015
  }
3993
4016
  }, [state.selectionManager, id, finalIsDisabled]);
3994
- const mergedProps = mergeProps(tabProps, focusProps, {
4017
+ const mergedProps = mergeProps(tabProps, focusProps, hoverProps, {
3995
4018
  onMouseDown: disableRipple ? void 0 : handleRipple,
3996
4019
  onClick: handleClick,
3997
4020
  onFocus: handleFocus
@@ -4008,47 +4031,56 @@ var Tab = forwardRef(
4008
4031
  type: "button",
4009
4032
  "data-key": String(id),
4010
4033
  tabIndex: finalIsDisabled ? -1 : isSelected ? 0 : -1,
4011
- className: cn(
4012
- tabVariants({
4013
- variant,
4014
- selected: isSelected,
4015
- disabled: finalIsDisabled,
4016
- layout
4017
- }),
4018
- isFocusVisible && "outline-primary outline-2 outline-offset-2",
4019
- hasLabel && hasIcon && "min-h-16",
4020
- className
4021
- ),
4034
+ className: cn(tabVariants({ variant, layout }), className),
4035
+ ...getInteractionDataAttributes({
4036
+ isHovered,
4037
+ isFocusVisible,
4038
+ isPressed,
4039
+ isSelected,
4040
+ isDisabled: finalIsDisabled
4041
+ }),
4042
+ "data-with-icon": hasIcon ? "" : void 0,
4043
+ "data-with-label": hasLabel ? "" : void 0,
4022
4044
  ...htmlProps,
4023
4045
  children: [
4024
4046
  !disableRipple && ripples,
4025
- hasIcon && /* @__PURE__ */ jsxs("span", { className: cn(tabIconVariants({ hasLabel })), children: [
4026
- icon,
4027
- badgeDisplay && /* @__PURE__ */ jsx(
4028
- "span",
4029
- {
4030
- "data-badge-type": isDotBadge ? "dot" : "count",
4031
- "aria-hidden": "true",
4032
- className: cn(tabBadgeVariants({ type: isDotBadge ? "dot" : "count" })),
4033
- children: !isDotBadge && badgeDisplay
4034
- }
4035
- )
4036
- ] }),
4037
- hasLabel && /* @__PURE__ */ jsxs("span", { className: "relative z-10 truncate", children: [
4038
- label,
4039
- !hasIcon && badgeDisplay && /* @__PURE__ */ jsx(
4040
- "span",
4041
- {
4042
- "data-badge-type": isDotBadge ? "dot" : "count",
4043
- "aria-hidden": "true",
4044
- className: cn(
4045
- "relative ml-1",
4046
- tabBadgeVariants({ type: isDotBadge ? "dot" : "count" })
4047
- ),
4048
- children: !isDotBadge && badgeDisplay
4049
- }
4050
- )
4051
- ] })
4047
+ /* @__PURE__ */ jsx("span", { className: cn(tabStateLayerVariants({ variant })), "aria-hidden": "true" }),
4048
+ /* @__PURE__ */ jsxs(
4049
+ "span",
4050
+ {
4051
+ "data-tab-content": true,
4052
+ className: "relative z-10 inline-flex flex-col items-center justify-center",
4053
+ children: [
4054
+ hasIcon && /* @__PURE__ */ jsxs("span", { className: cn(tabIconVariants({ hasLabel })), children: [
4055
+ icon,
4056
+ badgeDisplay && /* @__PURE__ */ jsx(
4057
+ "span",
4058
+ {
4059
+ "data-badge-type": isDotBadge ? "dot" : "count",
4060
+ "aria-hidden": "true",
4061
+ className: cn(tabBadgeVariants({ type: isDotBadge ? "dot" : "count" })),
4062
+ children: !isDotBadge && badgeDisplay
4063
+ }
4064
+ )
4065
+ ] }),
4066
+ hasLabel && /* @__PURE__ */ jsxs("span", { className: "truncate", children: [
4067
+ label,
4068
+ !hasIcon && badgeDisplay && /* @__PURE__ */ jsx(
4069
+ "span",
4070
+ {
4071
+ "data-badge-type": isDotBadge ? "dot" : "count",
4072
+ "aria-hidden": "true",
4073
+ className: cn(
4074
+ "relative ml-1",
4075
+ tabBadgeVariants({ type: isDotBadge ? "dot" : "count" })
4076
+ ),
4077
+ children: !isDotBadge && badgeDisplay
4078
+ }
4079
+ )
4080
+ ] })
4081
+ ]
4082
+ }
4083
+ )
4052
4084
  ]
4053
4085
  }
4054
4086
  );