@flikk/ui 1.0.0-beta.24 → 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.
- package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
- package/dist/components/ai/PromptInput/PromptInput.js +1 -0
- package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -0
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +1 -1
- package/dist/components/ai/TokenCounter/TokenCounter.theme.js +1 -1
- package/dist/components/charts/BarChart/BarChart.js +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.js +1 -1
- package/dist/components/charts/shared/BarRenderer/BarRenderer.js +2 -2
- package/dist/components/core/Accordion/Accordion.theme.js +2 -2
- package/dist/components/core/Breadcrumbs/Breadcrumbs.js +1 -1
- package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +2 -2
- package/dist/components/core/Button/Button.js +1 -1
- package/dist/components/core/Button/Button.theme.js +4 -4
- package/dist/components/core/Calendar/Calendar.js +1 -1
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +4 -2
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +2 -2
- package/dist/components/core/ContextMenu/ContextMenu.theme.js +1 -1
- package/dist/components/core/Drawer/Drawer.theme.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.theme.js +2 -2
- package/dist/components/core/Empty/Empty.js +1 -1
- package/dist/components/core/Empty/Empty.theme.js +1 -1
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
- package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
- package/dist/components/core/Link/Link.js +1 -1
- package/dist/components/core/Message/Message.theme.js +1 -1
- package/dist/components/core/Modal/Modal.theme.js +1 -1
- package/dist/components/core/NavItem/NavItem.d.ts +1 -1
- package/dist/components/core/NavItem/NavItem.js +171 -68
- package/dist/components/core/NavItem/NavItem.theme.js +20 -12
- package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
- package/dist/components/core/Pagination/Pagination.theme.js +3 -3
- package/dist/components/core/Popover/Popover.theme.js +1 -1
- package/dist/components/core/Progress/Progress.theme.js +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
- package/dist/components/core/Segmented/Segmented.js +8 -6
- package/dist/components/core/Segmented/Segmented.theme.js +3 -3
- package/dist/components/core/Sidebar/Sidebar.d.ts +1 -1
- package/dist/components/core/Sidebar/Sidebar.js +42 -13
- package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +33 -4
- package/dist/components/core/Sidebar/SidebarContent.js +6 -6
- package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
- package/dist/components/core/Sidebar/SidebarContext.js +42 -19
- package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
- package/dist/components/core/Sidebar/SidebarHeader.js +4 -9
- package/dist/components/core/Sidebar/SidebarLogo.js +3 -7
- package/dist/components/core/Sidebar/SidebarNav.js +4 -3
- package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
- package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
- package/dist/components/core/Sidebar/index.d.ts +2 -3
- package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
- package/dist/components/core/Spinner/Spinner.theme.js +1 -1
- package/dist/components/core/Tabs/Tabs.js +6 -1
- package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
- package/dist/components/core/Tabs/TabsBody.js +5 -3
- package/dist/components/core/Tag/Tag.theme.js +1 -1
- package/dist/components/core/index.d.ts +1 -0
- package/dist/components/core/index.js +2 -2
- package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
- package/dist/components/data-display/KPI/KPI.js +13 -3
- package/dist/components/data-display/KPI/KPI.theme.js +3 -3
- package/dist/components/data-display/Metric/Metric.theme.js +3 -3
- package/dist/components/data-display/Table/Table.js +4 -3
- package/dist/components/data-display/Table/Table.theme.js +11 -1
- package/dist/components/data-display/Table/Table.types.d.ts +15 -0
- package/dist/components/data-display/Table/TableColumnManager.js +1 -1
- package/dist/components/data-display/Table/index.d.ts +2 -2
- package/dist/components/data-display/Timeline/Timeline.animations.d.ts +0 -7
- package/dist/components/data-display/Timeline/Timeline.animations.js +1 -27
- package/dist/components/data-display/Timeline/Timeline.js +3 -4
- package/dist/components/data-display/Timeline/Timeline.types.d.ts +0 -13
- package/dist/components/data-display/Timeline/TimelineContent.js +3 -7
- package/dist/components/data-display/Timeline/TimelineItem.js +4 -17
- package/dist/components/data-display/Timeline/index.d.ts +2 -2
- package/dist/components/effects/Aurora/Aurora.js +79 -40
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
- package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
- package/dist/components/effects/MorphingText/MorphingText.js +40 -7
- package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
- package/dist/components/effects/StripePattern/StripePattern.js +54 -0
- package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
- package/dist/components/effects/StripePattern/index.d.ts +2 -0
- package/dist/components/effects/index.d.ts +9 -0
- package/dist/components/effects/index.js +4 -0
- package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
- package/dist/components/forms/CronInput/CronInput.theme.js +16 -16
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
- package/dist/components/forms/FileUpload/FileUpload.js +1 -1
- package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
- package/dist/components/forms/Input/Input.theme.js +9 -11
- package/dist/components/forms/Mention/Mention.theme.js +3 -3
- package/dist/components/forms/Radio/Radio.theme.js +1 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
- package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
- package/dist/components/forms/Select/Select.js +2 -2
- package/dist/components/forms/Slider/Slider.theme.js +1 -1
- package/dist/components/forms/Switch/Switch.theme.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
- package/dist/components/forms/TimePicker/TimePickerContent.js +1 -0
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
- package/dist/components/forms/forms.theme.js +12 -12
- package/dist/components/forms/index.js +1 -0
- package/dist/components/layout/FormLayout/FormLayout.js +6 -4
- package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
- package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
- package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
- package/dist/components/layout/PageLayout/PageLayout.js +23 -5
- package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
- package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
- package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
- package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
- package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
- package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
- package/dist/components/layout/PageLayout/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/theme.css +127 -92
- package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
- 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:
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
138
|
+
density: { ...navItemTheme.density, ...customTheme.density },
|
|
83
139
|
}), [customTheme]);
|
|
84
140
|
// Handle click events
|
|
85
141
|
const handleClick = (e) => {
|
|
86
|
-
if (
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
|
131
|
-
return
|
|
182
|
+
return theme.iconStates.active;
|
|
183
|
+
return theme.iconStates.default;
|
|
132
184
|
};
|
|
133
|
-
|
|
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
|
-
//
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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 &&
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
overflow:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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: {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
|
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(
|
|
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-
|
|
3
|
-
icon: "size-
|
|
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-
|
|
7
|
-
active: "bg-[var(--color-primary)]/10 text-[var(--color-primary)]
|
|
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: "
|
|
13
|
-
active: "
|
|
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-
|
|
25
|
+
1: "pl-11",
|
|
19
26
|
2: "pl-10",
|
|
20
27
|
},
|
|
21
28
|
collapsed: {
|
|
22
|
-
container: "!gap-0
|
|
29
|
+
container: "!gap-0 !px-[14px] !py-2",
|
|
23
30
|
icon: "size-5",
|
|
24
31
|
},
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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<
|
|
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)
|
|
24
|
+
* Start content (icon)
|
|
27
25
|
*/
|
|
28
26
|
startContent?: ReactNode;
|
|
29
27
|
/**
|
|
30
|
-
* End content (badge/arrow)
|
|
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
|
|
135
|
-
active
|
|
136
|
-
disabled
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
23
|
-
|
|
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:
|
|
26
|
-
height:
|
|
27
|
-
top:
|
|
28
|
-
transform: `translateX(${
|
|
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-
|
|
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-[
|
|
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-[
|
|
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)]",
|