@flikk/ui 1.0.0-beta.25 → 1.0.0-beta.26

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.
Files changed (122) hide show
  1. package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
  2. package/dist/components/ai/PromptInput/PromptInput.js +1 -0
  3. package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -0
  4. package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +1 -1
  5. package/dist/components/ai/TokenCounter/TokenCounter.theme.js +1 -1
  6. package/dist/components/charts/BarChart/BarChart.js +2 -2
  7. package/dist/components/charts/StackedBarChart/StackedBarChart.js +1 -1
  8. package/dist/components/charts/shared/BarRenderer/BarRenderer.js +2 -2
  9. package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +1 -1
  10. package/dist/components/core/Button/Button.js +1 -1
  11. package/dist/components/core/Button/Button.theme.js +4 -4
  12. package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +1 -1
  13. package/dist/components/core/ContextMenu/ContextMenu.theme.js +1 -1
  14. package/dist/components/core/Drawer/Drawer.theme.js +2 -2
  15. package/dist/components/core/Dropdown/Dropdown.theme.js +2 -2
  16. package/dist/components/core/Empty/Empty.js +1 -1
  17. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
  18. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
  19. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
  20. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
  21. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
  22. package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
  23. package/dist/components/core/Message/Message.theme.js +1 -1
  24. package/dist/components/core/Modal/Modal.theme.js +1 -1
  25. package/dist/components/core/NavItem/NavItem.d.ts +1 -1
  26. package/dist/components/core/NavItem/NavItem.js +171 -68
  27. package/dist/components/core/NavItem/NavItem.theme.js +20 -12
  28. package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
  29. package/dist/components/core/Pagination/Pagination.theme.js +3 -3
  30. package/dist/components/core/Popover/Popover.theme.js +1 -1
  31. package/dist/components/core/Progress/Progress.theme.js +1 -1
  32. package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
  33. package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
  34. package/dist/components/core/Segmented/Segmented.js +8 -6
  35. package/dist/components/core/Segmented/Segmented.theme.js +3 -3
  36. package/dist/components/core/Sidebar/Sidebar.d.ts +1 -1
  37. package/dist/components/core/Sidebar/Sidebar.js +42 -13
  38. package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
  39. package/dist/components/core/Sidebar/Sidebar.types.d.ts +33 -4
  40. package/dist/components/core/Sidebar/SidebarContent.js +6 -6
  41. package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
  42. package/dist/components/core/Sidebar/SidebarContext.js +42 -19
  43. package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
  44. package/dist/components/core/Sidebar/SidebarHeader.js +4 -9
  45. package/dist/components/core/Sidebar/SidebarLogo.js +3 -7
  46. package/dist/components/core/Sidebar/SidebarNav.js +4 -3
  47. package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
  48. package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
  49. package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
  50. package/dist/components/core/Sidebar/index.d.ts +2 -3
  51. package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
  52. package/dist/components/core/Spinner/Spinner.theme.js +1 -1
  53. package/dist/components/core/Tabs/Tabs.js +6 -1
  54. package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
  55. package/dist/components/core/Tabs/TabsBody.js +5 -3
  56. package/dist/components/core/Tag/Tag.theme.js +1 -1
  57. package/dist/components/core/index.d.ts +1 -0
  58. package/dist/components/core/index.js +2 -2
  59. package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
  60. package/dist/components/data-display/KPI/KPI.js +13 -3
  61. package/dist/components/data-display/KPI/KPI.theme.js +3 -3
  62. package/dist/components/data-display/Metric/Metric.theme.js +3 -3
  63. package/dist/components/data-display/Table/Table.js +4 -3
  64. package/dist/components/data-display/Table/Table.theme.js +11 -1
  65. package/dist/components/data-display/Table/Table.types.d.ts +15 -0
  66. package/dist/components/data-display/Table/TableColumnManager.js +1 -1
  67. package/dist/components/data-display/Table/index.d.ts +2 -2
  68. package/dist/components/effects/Aurora/Aurora.js +79 -40
  69. package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
  70. package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
  71. package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
  72. package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
  73. package/dist/components/effects/MorphingText/MorphingText.js +40 -7
  74. package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
  75. package/dist/components/effects/StripePattern/StripePattern.js +54 -0
  76. package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
  77. package/dist/components/effects/StripePattern/index.d.ts +2 -0
  78. package/dist/components/effects/index.d.ts +2 -0
  79. package/dist/components/effects/index.js +1 -0
  80. package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
  81. package/dist/components/forms/CronInput/CronInput.theme.js +16 -16
  82. package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
  83. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +1 -1
  84. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
  85. package/dist/components/forms/FileUpload/FileUpload.js +1 -1
  86. package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
  87. package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
  88. package/dist/components/forms/Input/Input.theme.js +9 -11
  89. package/dist/components/forms/Mention/Mention.theme.js +3 -3
  90. package/dist/components/forms/Radio/Radio.theme.js +1 -1
  91. package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
  92. package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
  93. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
  94. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
  95. package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
  96. package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
  97. package/dist/components/forms/Select/Select.js +1 -1
  98. package/dist/components/forms/Slider/Slider.theme.js +1 -1
  99. package/dist/components/forms/Switch/Switch.theme.js +1 -1
  100. package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
  101. package/dist/components/forms/TimePicker/TimePickerContent.js +1 -0
  102. package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
  103. package/dist/components/forms/forms.theme.js +12 -12
  104. package/dist/components/forms/index.js +1 -0
  105. package/dist/components/layout/FormLayout/FormLayout.js +6 -4
  106. package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
  107. package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
  108. package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
  109. package/dist/components/layout/PageLayout/PageLayout.js +23 -5
  110. package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
  111. package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
  112. package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
  113. package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
  114. package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
  115. package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
  116. package/dist/components/layout/PageLayout/index.d.ts +1 -1
  117. package/dist/index.js +2 -2
  118. package/dist/styles.css +1 -1
  119. package/package.json +1 -1
  120. package/src/styles/theme.css +127 -92
  121. package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
  122. package/dist/components/core/Sidebar/SidebarSubmenu.js +0 -12
@@ -1,17 +1,22 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import React__default, { useId, useState, useCallback, useMemo } from 'react';
2
+ import React__default, { useId, useRef, useState, useCallback, useEffect, useMemo } from 'react';
3
3
  import { cn } from '../../../utils/cn.js';
4
+ import { Dropdown } from '../Dropdown/Dropdown.js';
5
+ import '../Dropdown/DropdownTrigger.js';
6
+ import '../Dropdown/DropdownMenu.js';
7
+ import '../Dropdown/DropdownItem.js';
8
+ import '../Dropdown/DropdownSection.js';
9
+ import '../Dropdown/DropdownSeparator.js';
10
+ import '../Dropdown/Dropdown.theme.js';
4
11
  import { navItemTheme } from './NavItem.theme.js';
5
- import { useSidebarContext, useAccordionNavContext } from '../Sidebar/SidebarContext.js';
12
+ import { useSidebarContext, useAccordionNavContext, useSidebarDensity } from '../Sidebar/SidebarContext.js';
6
13
  import { Tooltip } from '../Tooltip/Tooltip.js';
7
14
  import '../Tooltip/Tooltip.animations.js';
8
15
  import { Badge } from '../Badge/Badge.js';
9
16
  import { ChevronDownIcon } from '@heroicons/react/20/solid';
10
17
  import { AnimatePresence, motion } from 'motion/react';
11
18
 
12
- const NavItem = React__default.forwardRef(({ children, startContent: propStartContent, endContent: propEndContent, icon, // Legacy
13
- badge, // Legacy
14
- notification, description, shortcut, href, onClick, active = false, disabled = false, isDisabled: propIsDisabled, isDanger = false, hasSubmenu: propHasSubmenu = false, expanded: controlledExpanded, onToggleExpanded, items, defaultExpanded = false, level = 0, showTooltipWhenCollapsed = true, className, theme: customTheme = {}, ...props }, ref) => {
19
+ const NavItem = React__default.forwardRef(({ children, startContent, endContent, notification, description, shortcut, href, onClick, active = false, isDisabled = false, hasSubmenu: propHasSubmenu = false, expanded: controlledExpanded, onToggleExpanded, items, defaultExpanded = false, level = 0, showTooltipWhenCollapsed = true, className, theme: customTheme = {}, ...props }, ref) => {
15
20
  var _a, _b;
16
21
  const sidebarContext = useSidebarContext();
17
22
  const accordionNav = useAccordionNavContext();
@@ -19,8 +24,53 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
19
24
  const collapsed = (sidebarContext === null || sidebarContext === void 0 ? void 0 : sidebarContext.collapsed) || false;
20
25
  const isInSidebar = !!sidebarContext;
21
26
  const isMobile = (sidebarContext === null || sidebarContext === void 0 ? void 0 : sidebarContext.isMobile) || false;
27
+ const density = useSidebarDensity();
28
+ const defaultExpandedRegisteredRef = useRef(false);
22
29
  // Self-managed submenu state
23
30
  const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
31
+ // Dropdown open state for collapsed sidebar hover submenu
32
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
33
+ const hoverTimeoutRef = useRef(null);
34
+ const handleMouseEnter = useCallback(() => {
35
+ if (hoverTimeoutRef.current) {
36
+ clearTimeout(hoverTimeoutRef.current);
37
+ hoverTimeoutRef.current = null;
38
+ }
39
+ setIsDropdownOpen(true);
40
+ }, []);
41
+ const handleMouseLeave = useCallback(() => {
42
+ if (hoverTimeoutRef.current) {
43
+ clearTimeout(hoverTimeoutRef.current);
44
+ }
45
+ hoverTimeoutRef.current = setTimeout(() => {
46
+ setIsDropdownOpen(false);
47
+ }, 150);
48
+ }, []);
49
+ useEffect(() => {
50
+ return () => {
51
+ if (hoverTimeoutRef.current) {
52
+ clearTimeout(hoverTimeoutRef.current);
53
+ }
54
+ };
55
+ }, []);
56
+ // Resolve active keys for Dropdown selection mode
57
+ const activeKeys = useMemo(() => {
58
+ if (!items)
59
+ return [];
60
+ return items
61
+ .map((item, idx) => (item.active ? `sub-item-${idx}` : null))
62
+ .filter((key) => key !== null);
63
+ }, [items]);
64
+ const handleItemAction = useCallback((item) => {
65
+ if (item.isDisabled)
66
+ return;
67
+ if (item.onClick) {
68
+ item.onClick();
69
+ }
70
+ else if (item.href) {
71
+ window.location.href = item.href;
72
+ }
73
+ }, []);
24
74
  // Determine if this item has a submenu
25
75
  const hasSubmenu = propHasSubmenu || (items && items.length > 0);
26
76
  // Determine expanded state: controlled vs accordion vs internal
@@ -52,15 +102,21 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
52
102
  setInternalExpanded(prev => !prev);
53
103
  }
54
104
  }, [isControlled, isAccordionManaged, isExpanded, onToggleExpanded, accordionNav, stableId]);
55
- // Map legacy props
56
- const startContent = propStartContent || icon;
57
- const actualIsDisabled = propIsDisabled || disabled;
58
- // Build end content
59
- let endContent = propEndContent;
60
- if (!endContent && badge) {
61
- endContent = (jsx(Badge, { color: "neutral", variant: "soft", size: "sm", children: badge }));
62
- }
63
- // Notification element
105
+ useEffect(() => {
106
+ if (!defaultExpandedRegisteredRef.current &&
107
+ !isControlled &&
108
+ isAccordionManaged &&
109
+ hasSubmenu &&
110
+ defaultExpanded &&
111
+ accordionNav.openId === null) {
112
+ defaultExpandedRegisteredRef.current = true;
113
+ accordionNav.register(stableId);
114
+ }
115
+ }, [accordionNav, defaultExpanded, hasSubmenu, isAccordionManaged, isControlled, stableId]);
116
+ // Whether there is an active notification (dot or non-zero count)
117
+ const hasNotification = notification === true ||
118
+ (typeof notification === "number" && notification > 0);
119
+ // Expanded view: a dot for boolean, a count Badge for numbers
64
120
  const notificationElement = useMemo(() => {
65
121
  if (notification === undefined || notification === false)
66
122
  return null;
@@ -68,10 +124,10 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
68
124
  return (jsx("span", { className: cn(navItemTheme.notificationDot, customTheme.notificationDot) }));
69
125
  }
70
126
  if (typeof notification === "number" && notification > 0) {
71
- return (jsx("span", { className: cn(navItemTheme.notificationBadge, customTheme.notificationBadge), children: notification > 99 ? "99+" : notification }));
127
+ return (jsx(Badge, { color: "neutral", variant: "soft", size: "sm", children: notification > 99 ? "99+" : notification }));
72
128
  }
73
129
  return null;
74
- }, [notification, customTheme.notificationDot, customTheme.notificationBadge]);
130
+ }, [notification, customTheme.notificationDot]);
75
131
  const theme = useMemo(() => ({
76
132
  ...navItemTheme,
77
133
  ...customTheme,
@@ -79,11 +135,11 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
79
135
  iconStates: { ...navItemTheme.iconStates, ...customTheme.iconStates },
80
136
  levels: { ...navItemTheme.levels, ...customTheme.levels },
81
137
  collapsed: { ...navItemTheme.collapsed, ...customTheme.collapsed },
82
- danger: customTheme.danger || navItemTheme.danger || "text-[var(--color-danger)] hover:bg-[var(--color-danger-50)]",
138
+ density: { ...navItemTheme.density, ...customTheme.density },
83
139
  }), [customTheme]);
84
140
  // Handle click events
85
141
  const handleClick = (e) => {
86
- if (actualIsDisabled) {
142
+ if (isDisabled) {
87
143
  e.preventDefault();
88
144
  return;
89
145
  }
@@ -108,80 +164,127 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
108
164
  };
109
165
  const isActive = active;
110
166
  const isCollapsedView = isInSidebar && collapsed && !isMobile;
111
- // Get state classes
167
+ const isHoveredOrDropdownOpen = isCollapsedView ? isDropdownOpen : (hasSubmenu && isExpanded);
168
+ // State styling resolved in JS to plain utility classes so `className` overrides win
169
+ // (data-[active]/data-[disabled] are still emitted below as styling/test hooks)
112
170
  const getStateClasses = () => {
113
- if (actualIsDisabled)
171
+ if (isDisabled)
114
172
  return theme.states.disabled;
115
173
  if (isActive)
116
174
  return theme.states.active;
117
175
  return theme.states.default;
118
176
  };
119
- // Danger overrides
120
- const dangerClasses = isDanger ? theme.danger : "";
121
- // Active indicator
122
- const activeIndicatorClasses = isActive && level === 0 ? theme.activeIndicator : "";
123
- const containerClasses = cn(theme.baseStyle, getStateClasses(), theme.levels[level], isCollapsedView && ((_a = theme.collapsed) === null || _a === void 0 ? void 0 : _a.container), dangerClasses, activeIndicatorClasses, className);
124
- // Get icon state classes
177
+ const containerClasses = cn(theme.baseStyle, theme.focusStyle, getStateClasses(), theme.levels[level], density === "compact" && theme.density.compact, hasSubmenu && isExpanded && !isActive && "text-[var(--color-text-primary)]", isCollapsedView && ((_a = theme.collapsed) === null || _a === void 0 ? void 0 : _a.container), isHoveredOrDropdownOpen && "bg-[var(--color-surface-hover)] text-[var(--color-text-primary)]", className);
125
178
  const getIconStateClasses = () => {
126
- var _a, _b, _c;
127
- if (actualIsDisabled)
128
- return (_a = theme.iconStates) === null || _a === void 0 ? void 0 : _a.disabled;
179
+ if (isDisabled)
180
+ return theme.iconStates.disabled;
129
181
  if (isActive)
130
- return (_b = theme.iconStates) === null || _b === void 0 ? void 0 : _b.active;
131
- return (_c = theme.iconStates) === null || _c === void 0 ? void 0 : _c.default;
182
+ return theme.iconStates.active;
183
+ return theme.iconStates.default;
132
184
  };
133
- // Build icon classes
134
- const iconClasses = cn(isCollapsedView ? (_b = theme.collapsed) === null || _b === void 0 ? void 0 : _b.icon : theme.icon, getIconStateClasses());
185
+ const iconClasses = cn(theme.icon, getIconStateClasses(), hasSubmenu && isExpanded && !isActive && "opacity-100", isCollapsedView && ((_b = theme.collapsed) === null || _b === void 0 ? void 0 : _b.icon), isHoveredOrDropdownOpen && "opacity-100");
135
186
  const textClasses = cn(theme.text);
136
187
  // Chevron for submenu
137
- const chevron = hasSubmenu && !isCollapsedView ? (jsx(ChevronDownIcon, { className: cn("size-4 transition-transform duration-200 text-[var(--color-text-muted)]", isExpanded && "rotate-180") })) : null;
138
- // Content component
139
- const content = (jsxs("div", { ref: ref, className: containerClasses, role: href ? "link" : "button", tabIndex: actualIsDisabled ? -1 : 0, "aria-disabled": actualIsDisabled, "aria-expanded": hasSubmenu ? isExpanded : undefined, "data-active": isActive, "data-disabled": actualIsDisabled, "data-level": level, onClick: handleClick, onKeyDown: (e) => {
140
- if (e.key === "Enter" || e.key === " ") {
141
- e.preventDefault();
142
- handleClick(e);
143
- }
144
- }, ...props, children: [startContent && (jsxs("div", { className: "flex items-center justify-center flex-shrink-0 relative", children: [React__default.isValidElement(startContent)
188
+ const chevron = hasSubmenu && !isCollapsedView ? (jsx(ChevronDownIcon, { strokeWidth: 2, className: cn("size-4 transition-transform duration-200 text-[var(--color-text-muted)]", isExpanded && "text-[var(--color-text-primary)]", isExpanded && "rotate-180") })) : null;
189
+ // Strip drag/animation DOM handlers that collide with motion's prop types
190
+ const { onAnimationStart, onAnimationEnd, onDrag, onDragStart, onDragEnd, ...motionSafeProps } = props;
191
+ const interactionProps = {
192
+ className: cn("relative overflow-hidden", containerClasses),
193
+ "aria-disabled": isDisabled || undefined,
194
+ "aria-expanded": hasSubmenu ? isExpanded : undefined,
195
+ "data-active": isActive,
196
+ "data-disabled": isDisabled,
197
+ "data-level": level,
198
+ onClick: handleClick,
199
+ whileHover: isDisabled ? undefined : (isCollapsedView ? { scale: 1.05 } : undefined),
200
+ whileTap: isDisabled ? undefined : { scale: 0.98 },
201
+ transition: { type: "spring", stiffness: 400, damping: 25 },
202
+ ...motionSafeProps,
203
+ };
204
+ const innerContent = (jsxs(Fragment, { children: [startContent && (jsxs("div", { className: "flex items-center justify-center flex-shrink-0 relative", children: [React__default.isValidElement(startContent)
145
205
  ? React__default.cloneElement(startContent, {
146
206
  className: cn(iconClasses, startContent.props.className),
147
207
  })
148
- : startContent, isCollapsedView && notificationElement && (jsx("span", { className: "absolute -top-1 -right-1", children: notificationElement }))] })), jsx("div", { "aria-hidden": isCollapsedView || undefined, style: {
149
- display: 'grid',
150
- gridTemplateColumns: isCollapsedView ? '0fr' : '1fr',
151
- overflow: 'hidden',
152
- flex: '1 1 auto',
153
- opacity: isCollapsedView ? 0 : 1,
154
- transition: 'grid-template-columns 0.18s cubic-bezier(0.4,0,0.2,1), opacity 0.12s ease-out',
155
- }, children: jsxs("div", { style: { overflow: 'hidden', minWidth: 0 }, children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsx("span", { className: cn("truncate", textClasses), children: children }), shortcut && (jsx("kbd", { className: "hidden group-hover:inline-block text-sm text-[var(--color-text-muted)] font-sans border border-[var(--color-border)] rounded px-1.5 py-0.5", children: shortcut }))] }), description && (jsx("div", { className: "text-sm text-[var(--color-text-muted)] mt-0.5 truncate", children: description }))] }) }), jsx("div", { style: {
156
- display: 'grid',
157
- gridTemplateColumns: isCollapsedView ? '0fr' : '1fr',
158
- overflow: 'hidden',
159
- flexShrink: 0,
160
- opacity: isCollapsedView ? 0 : 1,
161
- transition: 'grid-template-columns 0.18s cubic-bezier(0.4,0,0.2,1), opacity 0.12s ease-out',
162
- }, children: jsxs("div", { className: "flex items-center gap-1.5", style: { overflow: 'hidden', minWidth: 0 }, children: [notificationElement, endContent, chevron] }) }), isCollapsedView && (jsx("span", { className: "sr-only", children: children }))] }));
208
+ : startContent, isCollapsedView && hasNotification && (jsx("span", { className: cn("absolute -top-0.5 -right-0.5 ring-2 ring-[var(--color-surface)]", navItemTheme.notificationDot, customTheme.notificationDot), "aria-hidden": "true" }))] })), jsx(AnimatePresence, { initial: false, children: !isCollapsedView && (jsxs(motion.span, { initial: { opacity: 0, x: -4 }, animate: { opacity: 1, x: 0 }, exit: { opacity: 0, x: -4 }, transition: {
209
+ opacity: { duration: 0.15, ease: [0.4, 0, 0.2, 1] },
210
+ x: { duration: 0.2, ease: [0.4, 0, 0.2, 1] }
211
+ }, className: "flex-1 min-w-0 flex flex-col overflow-hidden whitespace-nowrap", children: [jsxs("span", { className: "flex items-center justify-between gap-2 w-full min-w-0", children: [jsx("span", { className: cn("truncate flex-1 min-w-0", textClasses), children: children }), jsxs("span", { className: "flex items-center gap-1.5 flex-shrink-0 ml-2", children: [shortcut && (jsx("kbd", { className: "hidden group-hover:inline-flex h-[18px] items-center text-[10px] text-[var(--color-text-muted)] font-sans border border-[var(--color-border)] rounded px-1.5 leading-none flex-shrink-0", children: shortcut })), notificationElement, endContent, chevron] })] }), description && (jsx("span", { className: "block text-xs text-[var(--color-text-muted)] mt-0.5 truncate w-full", children: description }))] }, "expanded-content")) }), isCollapsedView && (jsxs("span", { className: "sr-only", children: [children, typeof notification === "number" && notification > 0
212
+ ? ` (${notification} unread)`
213
+ : notification === true
214
+ ? " (unread)"
215
+ : null] }))] }));
216
+ // Content component
217
+ const content = href && !hasSubmenu ? (jsx(motion.a, { ref: ref, href: isDisabled ? undefined : href, tabIndex: isDisabled ? -1 : undefined, ...interactionProps, children: innerContent })) : (jsx(motion.button, { ref: ref, type: "button", disabled: isDisabled, ...interactionProps, children: innerContent }));
163
218
  // Self-contained submenu
164
219
  const submenu = hasSubmenu && items && items.length > 0 && !isCollapsedView ? (jsx(AnimatePresence, { initial: false, children: isExpanded && (jsx(motion.div, { initial: "collapsed", animate: "open", exit: "collapsed", variants: {
165
- open: { opacity: 1, height: "auto" },
166
- collapsed: { opacity: 0, height: 0 },
167
- }, transition: { duration: 0.2, ease: "easeInOut" }, className: "overflow-hidden", children: items.map((item, idx) => (jsx(NavItem, { level: Math.min((level + 1), 2), startContent: item.startContent, active: item.active, isDisabled: item.isDisabled, badge: item.badge, notification: item.notification, href: item.href, onClick: item.onClick, children: item.children }, idx))) })) })) : null;
168
- // Wrap with link if href is provided
169
- const renderWrapped = (node) => {
170
- if (href && !actualIsDisabled) {
171
- return (jsx("a", { href: href, className: "block group", children: node }));
172
- }
173
- return node;
220
+ open: {
221
+ opacity: 1,
222
+ height: "auto",
223
+ transition: {
224
+ height: { duration: 0.18, ease: "easeOut" },
225
+ opacity: { duration: 0.12 },
226
+ },
227
+ },
228
+ collapsed: {
229
+ opacity: 0,
230
+ height: 0,
231
+ transition: {
232
+ height: { duration: 0.16, ease: "easeInOut" },
233
+ opacity: { duration: 0.1 },
234
+ },
235
+ },
236
+ }, className: "overflow-hidden", children: jsx("div", { className: "relative space-y-0.5 pl-6", children: items.map((item, idx) => (jsxs(motion.div, { className: "relative", children: [idx < items.length - 1 && (jsx(motion.span, { initial: { opacity: 0, scaleY: 0 }, animate: { opacity: 1, scaleY: 1 }, exit: { opacity: 0, scaleY: 0 }, transition: {
237
+ delay: idx * 0.055,
238
+ duration: 0.16,
239
+ ease: "easeOut",
240
+ }, className: "absolute left-[-6px] top-1/2 h-[calc(100%+0.125rem)] w-px origin-top bg-[var(--color-neutral-400)] dark:bg-[var(--color-neutral-600)]", "aria-hidden": "true" })), jsx(motion.span, { initial: { opacity: 0, scale: 0.5 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.5 }, transition: {
241
+ delay: idx * 0.055,
242
+ type: "spring",
243
+ stiffness: 520,
244
+ damping: 30,
245
+ mass: 0.6,
246
+ }, className: cn("absolute left-[-8.5px] top-1/2 z-10 size-1.5 -translate-y-1/2 rounded-full", item.active
247
+ ? "bg-[var(--color-primary)]"
248
+ : "bg-[var(--color-neutral-400)] dark:bg-[var(--color-neutral-600)]"), "aria-hidden": "true" }), jsx(motion.div, { initial: { opacity: 0, x: -6 }, animate: { opacity: 1, x: 0 }, exit: { opacity: 0, x: -6 }, transition: {
249
+ delay: idx * 0.055 + 0.035,
250
+ type: "spring",
251
+ stiffness: 460,
252
+ damping: 34,
253
+ mass: 0.7,
254
+ }, className: "ml-2", children: jsx(NavItem, { level: Math.min((level + 1), 2), startContent: item.startContent, active: item.active, isDisabled: item.isDisabled, notification: item.notification, href: item.href, onClick: item.onClick, className: "px-2.5", children: item.children }) })] }, idx))) }) })) })) : null;
255
+ const renderContent = () => {
256
+ if (hasSubmenu && items && items.length > 0) {
257
+ return (jsxs(Dropdown, { isOpen: isCollapsedView ? isDropdownOpen : false, onOpenChange: isCollapsedView ? setIsDropdownOpen : undefined, placement: "right-start", offset: 8, selectionMode: "single", selectedKeys: activeKeys, children: [jsx("div", { onMouseEnter: isCollapsedView ? handleMouseEnter : undefined, onMouseLeave: isCollapsedView ? handleMouseLeave : undefined, className: "w-full", children: jsx(Dropdown.Trigger, { children: content }) }), isCollapsedView && (jsx(Dropdown.Menu, { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: items.map((item, idx) => {
258
+ const itemKey = `sub-item-${idx}`;
259
+ const subNotificationElement = (() => {
260
+ if (item.notification === undefined || item.notification === false)
261
+ return null;
262
+ if (item.notification === true) {
263
+ return (jsx("span", { className: cn(theme.notificationDot, customTheme.notificationDot) }));
264
+ }
265
+ if (typeof item.notification === "number" && item.notification > 0) {
266
+ return (jsx(Badge, { color: "neutral", variant: "soft", size: "sm", children: item.notification > 99 ? "99+" : item.notification }));
267
+ }
268
+ return null;
269
+ })();
270
+ return (jsx(Dropdown.Item, { itemKey: itemKey, startContent: item.startContent, endContent: subNotificationElement, isDisabled: item.isDisabled, onAction: () => handleItemAction(item), className: "hover:bg-[var(--color-surface-hover)] dark:hover:bg-[var(--color-surface-hover)]", children: item.children }, idx));
271
+ }) }))] }));
272
+ }
273
+ return content;
174
274
  };
175
275
  // Always render Tooltip when in a sidebar (keeps tree structure stable across
176
276
  // collapse/expand so CSS transitions aren't interrupted by DOM remounts).
177
- // The tooltip is disabled when not in collapsed view.
277
+ // The tooltip is *disabled* (not unmounted) when out of collapsed view or while
278
+ // the dropdown flyout is open — unmounting it would swap the stable `block w-full`
279
+ // wrapper for the Dropdown's `display:contents` root, which drops the nav's
280
+ // `space-y-1` top margin and shifts every item below it up on hover.
178
281
  const renderWithTooltip = (node) => {
179
282
  if (!isInSidebar || !showTooltipWhenCollapsed) {
180
283
  return node;
181
284
  }
182
- return (jsx(Tooltip, { content: children, placement: "right", disabled: !isCollapsedView, triggerClassName: "block w-full", children: node }));
285
+ return (jsx(Tooltip, { content: children, placement: "right", disabled: !isCollapsedView || isDropdownOpen, triggerClassName: "block w-full", children: node }));
183
286
  };
184
- return (jsxs(Fragment, { children: [renderWithTooltip(renderWrapped(content)), submenu] }));
287
+ return (jsxs("div", { className: "flex flex-col gap-0.5 w-full", children: [renderWithTooltip(renderContent()), submenu] }));
185
288
  });
186
289
  NavItem.displayName = "NavItem";
187
290
 
@@ -1,30 +1,38 @@
1
1
  const navItemTheme = {
2
- baseStyle: "relative flex items-center gap-2 px-2 py-1.5 text-sm font-medium cursor-pointer select-none transition-colors duration-150 w-full rounded-[var(--nav-item-radius)] outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] group overflow-hidden",
3
- icon: "size-4 text-[var(--color-text-secondary)]",
2
+ baseStyle: "group relative flex items-center gap-3 px-2.5 py-2 text-sm font-medium cursor-pointer select-none w-full rounded-[var(--nav-item-radius)] outline-none overflow-hidden transition-[padding,gap,background-color,border-color,color,box-shadow] duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] text-left",
3
+ icon: "size-5",
4
4
  text: "flex-1 min-w-0 truncate",
5
+ // State styling resolved in JS to plain utility classes so `className` overrides win
6
+ // (data-[state] variants carry attribute-selector specificity and can't be overridden
7
+ // by a plain className — see Button.theme.ts for the same rationale).
5
8
  states: {
6
- default: "text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)]",
7
- active: "bg-[var(--color-primary)]/10 text-[var(--color-primary)] font-semibold",
9
+ default: "text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)]",
10
+ active: "bg-[var(--color-primary)]/10 text-[var(--color-primary)] dark:text-[var(--color-text-primary)] dark:bg-white/10",
8
11
  disabled: "opacity-60 cursor-not-allowed pointer-events-none text-[var(--color-text-placeholder)]",
9
- hover: "hover:bg-[var(--color-background-secondary)]",
10
12
  },
13
+ // Icons inherit the item's text color via `currentColor` — we only adjust
14
+ // opacity so the icon reads slightly lighter than the label by default.
11
15
  iconStates: {
12
- default: "text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]",
13
- active: "text-[var(--color-primary)]",
16
+ default: "opacity-70 group-hover:opacity-100",
17
+ active: "opacity-100",
14
18
  disabled: "opacity-60",
15
19
  },
20
+ // Keyboard focus ring
21
+ focusStyle: "focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)] " +
22
+ "dark:focus-visible:ring-[var(--color-primary-400)]",
16
23
  levels: {
17
24
  0: "",
18
- 1: "pl-6",
25
+ 1: "pl-11",
19
26
  2: "pl-10",
20
27
  },
21
28
  collapsed: {
22
- container: "!gap-0 justify-center !p-2",
29
+ container: "!gap-0 !px-[14px] !py-2",
23
30
  icon: "size-5",
24
31
  },
25
- activeIndicator: "before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:h-5 before:w-[3px] before:rounded-full before:bg-[var(--color-primary)]",
26
- notificationDot: "size-2 rounded-full bg-[var(--color-danger)]",
27
- notificationBadge: "min-w-[18px] h-[18px] px-1 text-[10px] font-semibold rounded-full bg-[var(--color-danger)] text-[var(--color-danger-contrast)] flex items-center justify-center leading-none",
32
+ density: {
33
+ compact: "px-2 py-1.5 text-[13px]",
34
+ },
35
+ notificationDot: "size-2 rounded-full bg-[var(--color-primary)]",
28
36
  };
29
37
 
30
38
  export { navItemTheme };
@@ -10,24 +10,22 @@ export interface NavItemSubmenuItem {
10
10
  active?: boolean;
11
11
  /** Whether this sub-item is disabled */
12
12
  isDisabled?: boolean;
13
- /** Badge text/number on the sub-item */
14
- badge?: string | number;
15
13
  /** Notification count/dot on the sub-item */
16
14
  notification?: number | boolean;
17
15
  /** Start content (icon) for the sub-item */
18
16
  startContent?: ReactNode;
19
17
  }
20
- export interface NavItemProps extends React.HTMLAttributes<HTMLDivElement> {
18
+ export interface NavItemProps extends React.HTMLAttributes<HTMLElement> {
21
19
  /**
22
20
  * Content of the navigation item
23
21
  */
24
22
  children: ReactNode;
25
23
  /**
26
- * Start content (icon), replaces `icon`
24
+ * Start content (icon)
27
25
  */
28
26
  startContent?: ReactNode;
29
27
  /**
30
- * End content (badge/arrow), replaces `badge`
28
+ * End content (badge/arrow)
31
29
  */
32
30
  endContent?: ReactNode;
33
31
  /**
@@ -38,16 +36,6 @@ export interface NavItemProps extends React.HTMLAttributes<HTMLDivElement> {
38
36
  * Keyboard shortcut (optional)
39
37
  */
40
38
  shortcut?: string;
41
- /**
42
- * Legacy icon prop (mapped to startContent)
43
- * @deprecated Use startContent instead
44
- */
45
- icon?: ReactNode;
46
- /**
47
- * Legacy badge prop (mapped to endContent)
48
- * @deprecated Use endContent instead
49
- */
50
- badge?: string | number;
51
39
  /**
52
40
  * Notification indicator. Pass a number for a count badge, or true for a dot.
53
41
  */
@@ -70,15 +58,6 @@ export interface NavItemProps extends React.HTMLAttributes<HTMLDivElement> {
70
58
  * @default false
71
59
  */
72
60
  isDisabled?: boolean;
73
- /**
74
- * Alias for isDisabled
75
- * @deprecated Use isDisabled
76
- */
77
- disabled?: boolean;
78
- /**
79
- * Whether the item represents a danger action
80
- */
81
- isDanger?: boolean;
82
61
  /**
83
62
  * Whether the item has a submenu (manual mode).
84
63
  * If `items` is provided, this is set automatically.
@@ -128,14 +107,14 @@ export interface NavItemTheme {
128
107
  default: string;
129
108
  active: string;
130
109
  disabled: string;
131
- hover: string;
132
110
  };
133
- iconStates?: {
134
- default?: string;
135
- active?: string;
136
- disabled?: string;
137
- hover?: string;
111
+ iconStates: {
112
+ default: string;
113
+ active: string;
114
+ disabled: string;
138
115
  };
116
+ /** Keyboard focus-visible ring */
117
+ focusStyle: string;
139
118
  levels: {
140
119
  0: string;
141
120
  1: string;
@@ -145,10 +124,10 @@ export interface NavItemTheme {
145
124
  container: string;
146
125
  icon: string;
147
126
  };
148
- activeIndicator?: string;
149
- notificationDot?: string;
150
- notificationBadge?: string;
151
- danger?: string;
127
+ density: {
128
+ compact: string;
129
+ };
130
+ notificationDot: string;
152
131
  }
153
132
  export interface NavItemThemeOverrides {
154
133
  baseStyle?: string;
@@ -158,14 +137,13 @@ export interface NavItemThemeOverrides {
158
137
  default: string;
159
138
  active: string;
160
139
  disabled: string;
161
- hover: string;
162
140
  }>;
163
141
  iconStates?: Partial<{
164
142
  default: string;
165
143
  active: string;
166
144
  disabled: string;
167
- hover: string;
168
145
  }>;
146
+ focusStyle?: string;
169
147
  levels?: Partial<{
170
148
  0: string;
171
149
  1: string;
@@ -175,8 +153,8 @@ export interface NavItemThemeOverrides {
175
153
  container: string;
176
154
  icon: string;
177
155
  }>;
178
- activeIndicator?: string;
156
+ density?: Partial<{
157
+ compact: string;
158
+ }>;
179
159
  notificationDot?: string;
180
- notificationBadge?: string;
181
- danger?: string;
182
160
  }
@@ -13,15 +13,15 @@ const paginationTheme = {
13
13
  // Base state - light
14
14
  "cursor-pointer bg-white border border-transparent text-[var(--color-text-muted)] " +
15
15
  // Base state - dark
16
- "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-400)] dark:border-transparent " +
16
+ "dark:bg-transparent dark:text-[var(--color-text-secondary)] dark:border-transparent " +
17
17
  // Hover state - light
18
18
  "hover:text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)] hover:border-[var(--color-border)] " +
19
19
  // Hover state - dark
20
- "dark:hover:bg-[var(--color-neutral-700)] dark:hover:text-[var(--color-neutral-200)] dark:hover:border-[var(--color-neutral-600)] " +
20
+ "dark:hover:bg-[var(--color-surface-hover)] dark:hover:text-[var(--color-text-primary)] dark:hover:border-[var(--color-border)]/0 " +
21
21
  // Active state - light
22
22
  "data-[active=true]:bg-white data-[active=true]:border-[var(--color-border)] data-[active=true]:text-[var(--color-text-primary)] " +
23
23
  // Active state - dark (uses primary color accent)
24
- "dark:data-[active=true]:bg-[var(--color-primary-900)] dark:data-[active=true]:border-[var(--color-primary-700)] dark:data-[active=true]:text-[var(--color-primary-300)] " +
24
+ "dark:data-[active=true]:bg-[var(--color-neutral-800)] dark:data-[active=true]:border-none dark:data-[active=true]:text-[var(--color-text-primary)] " +
25
25
  // Disabled state
26
26
  "data-[disabled=true]:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:pointer-events-none",
27
27
  // Unified item sizes
@@ -5,7 +5,7 @@ const popoverTheme = {
5
5
  // Base styles for the popover
6
6
  baseStyle: "z-50 outline-none",
7
7
  // Body styles
8
- bodyStyle: "bg-[var(--color-surface)] border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-real-xl p-4 max-w-[min(24rem,calc(100vw-2rem))] dark:bg-[var(--color-background-secondary)] ",
8
+ bodyStyle: "bg-[var(--color-surface-overlay)] border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-real-xl p-4 max-w-[min(24rem,calc(100vw-2rem))] dark:bg-[var(--color-surface-overlay)] ",
9
9
  };
10
10
 
11
11
  export { popoverTheme };
@@ -5,7 +5,7 @@ const progressTheme = {
5
5
  // Container styles
6
6
  containerStyle: "w-full",
7
7
  // Track (background) styles
8
- trackStyle: "relative w-full rounded-full bg-[var(--color-background-tertiary)] overflow-hidden",
8
+ trackStyle: "relative w-full rounded-full bg-[var(--color-surface-sunken)] overflow-hidden",
9
9
  // Fill (progress bar) styles — includes default primary color
10
10
  fillStyle: "h-full rounded-full bg-[var(--color-primary)]",
11
11
  // Label text styles
@@ -155,12 +155,12 @@ const ScrollArea = React__default.forwardRef(({ children, type = 'hover', size =
155
155
  case 'always':
156
156
  return [
157
157
  '[&::-webkit-scrollbar-thumb]:bg-[var(--color-border)]',
158
- '[&::-webkit-scrollbar-track]:bg-[var(--color-background-secondary)]',
158
+ '[&::-webkit-scrollbar-track]:bg-[var(--color-surface-sunken)]',
159
159
  ].join(' ');
160
160
  case 'scroll':
161
161
  return [
162
162
  '[&::-webkit-scrollbar-thumb]:bg-transparent',
163
- '[&[data-scrolling]::-webkit-scrollbar-thumb]:bg-black/30',
163
+ '[&[data-scrolling]::-webkit-scrollbar-thumb]:bg-[var(--color-border)]',
164
164
  '[&::-webkit-scrollbar-thumb]:transition-colors',
165
165
  '[&::-webkit-scrollbar-thumb]:duration-300',
166
166
  ].join(' ');
@@ -5,7 +5,7 @@
5
5
  const scrollAreaTheme = {
6
6
  baseStyle: 'relative h-full w-full',
7
7
  scrollbarStyle: 'flex touch-none select-none transition-colors duration-150',
8
- thumbStyle: 'relative flex-1 rounded-full bg-[var(--color-border)]',
8
+ thumbStyle: 'relative flex-1 rounded-full bg-[var(--color-border)]/60',
9
9
  };
10
10
 
11
11
  export { scrollAreaTheme };
@@ -19,13 +19,15 @@ const SegmentedComponent = React__default.forwardRef(({ value, onChange, size =
19
19
  return;
20
20
  const activeButton = containerRef.current.querySelector(`[data-value="${value}"]`);
21
21
  if (activeButton) {
22
- const containerRect = containerRef.current.getBoundingClientRect();
23
- const buttonRect = activeButton.getBoundingClientRect();
22
+ // Use offsetTop/offsetLeft (measured from the offsetParent's padding
23
+ // edge) so the sliding background aligns correctly when the container
24
+ // has a border. getBoundingClientRect() returns border-box coords,
25
+ // which would offset the bg by the container's border width.
24
26
  setActiveStyle({
25
- width: buttonRect.width,
26
- height: buttonRect.height,
27
- top: buttonRect.top - containerRect.top,
28
- transform: `translateX(${buttonRect.left - containerRect.left}px)`,
27
+ width: activeButton.offsetWidth,
28
+ height: activeButton.offsetHeight,
29
+ top: activeButton.offsetTop,
30
+ transform: `translateX(${activeButton.offsetLeft}px)`,
29
31
  });
30
32
  }
31
33
  }, [value]);
@@ -3,7 +3,7 @@
3
3
  */
4
4
  const segmentedTheme = {
5
5
  // Base styles for the segmented container
6
- baseStyle: "relative flex rounded-[var(--segmented-radius)] bg-[var(--color-background-tertiary)]/50 border-0 border-[var(--color-border)]/50 p-1 shadow-inner dark:bg-[var(--color-background-secondary)]",
6
+ baseStyle: "relative flex rounded-[var(--segmented-radius)] bg-[var(--color-surface-sunken)]/10 border border-[var(--color-border)]/60 p-[var(--segmented-padding)] shadow-inner dark:bg-[var(--color-surface-sunken)]",
7
7
  // Size variants using CSS variables
8
8
  sizes: {
9
9
  sm: "min-h-[var(--segmented-min-h-sm)]",
@@ -15,14 +15,14 @@ const segmentedTheme = {
15
15
  // Disabled style
16
16
  disabledStyle: "opacity-50 cursor-not-allowed pointer-events-none",
17
17
  // Sliding background style with CSS variables
18
- slidingBackgroundStyle: "absolute top-[0px] left-[0px] rounded-[calc(var(--segmented-radius)-4px)] transition-transform duration-200 ease-out pointer-events-none z-0 bg-white dark:bg-[var(--color-background-tertiary)] shadow-real-md",
18
+ slidingBackgroundStyle: "absolute top-[0px] left-[0px] rounded-[var(--segmented-inner-radius)] transition-transform duration-200 ease-out pointer-events-none z-0 bg-white dark:bg-[var(--color-surface-raised)] shadow-real-lg",
19
19
  };
20
20
  /**
21
21
  * Default theme for the SegmentedItem component
22
22
  */
23
23
  const segmentedItemTheme = {
24
24
  // Base styles for the segmented item
25
- baseStyle: "relative flex min-w-fit flex-1 items-center justify-center transition-all duration-200 rounded-[calc(var(--segmented-radius)-4px)] font-medium cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary-500)] focus-visible:ring-offset-1",
25
+ baseStyle: "relative flex min-w-fit flex-1 items-center justify-center whitespace-nowrap transition-all duration-200 rounded-[var(--segmented-inner-radius)] font-medium cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary-500)] focus-visible:ring-offset-1",
26
26
  // Size variants using CSS variables
27
27
  sizes: {
28
28
  sm: "text-sm px-[var(--segmented-px-sm)]",