@flikk/ui 1.0.0-beta.26 → 1.0.0-beta.27
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/PromptInput/PromptInput.js +3 -0
- package/dist/components/ai/PromptInput/VoiceRecorder.js +3 -0
- package/dist/components/core/Button/Button.theme.js +1 -1
- package/dist/components/core/Calendar/Calendar.theme.js +1 -1
- package/dist/components/core/CommandPalette/CommandItem.js +4 -5
- package/dist/components/core/CommandPalette/CommandPalette.js +1 -1
- package/dist/components/core/CommandPalette/CommandPalette.theme.js +11 -13
- package/dist/components/core/CommandPalette/CommandPalette.types.d.ts +0 -2
- package/dist/components/core/ContextMenu/ContextMenu.theme.js +13 -14
- package/dist/components/core/DotSeparator/DotSeparator.d.ts +3 -0
- package/dist/components/core/DotSeparator/DotSeparator.js +19 -0
- package/dist/components/core/DotSeparator/DotSeparator.theme.d.ts +2 -0
- package/dist/components/core/DotSeparator/DotSeparator.theme.js +10 -0
- package/dist/components/core/DotSeparator/DotSeparator.types.d.ts +25 -0
- package/dist/components/core/DotSeparator/index.d.ts +3 -0
- package/dist/components/core/Dropdown/Dropdown.theme.js +2 -3
- package/dist/components/core/Dropdown/DropdownItem.js +1 -1
- package/dist/components/core/Dropdown/DropdownMenu.js +1 -1
- package/dist/components/core/MenuItem/MenuItem.js +5 -2
- package/dist/components/core/MenuItem/MenuItem.theme.d.ts +6 -0
- package/dist/components/core/MenuItem/MenuItem.theme.js +19 -16
- package/dist/components/core/MenuItem/MenuItem.types.d.ts +2 -0
- package/dist/components/core/NavItem/NavItem.js +20 -4
- package/dist/components/core/NavItem/NavItem.theme.js +13 -2
- package/dist/components/core/Popover/Popover.types.d.ts +6 -2
- package/dist/components/core/Popover/PopoverBody.js +10 -3
- package/dist/components/core/Segmented/Segmented.theme.js +1 -1
- package/dist/components/core/Sidebar/Sidebar.d.ts +2 -0
- package/dist/components/core/Sidebar/Sidebar.js +15 -7
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +92 -4
- package/dist/components/core/Sidebar/SidebarCard.d.ts +25 -0
- package/dist/components/core/Sidebar/SidebarCard.js +68 -0
- package/dist/components/core/Sidebar/SidebarCard.theme.d.ts +8 -0
- package/dist/components/core/Sidebar/SidebarCard.theme.js +18 -0
- package/dist/components/core/Sidebar/SidebarContent.js +5 -1
- package/dist/components/core/Sidebar/SidebarContext.js +1 -1
- package/dist/components/core/Sidebar/SidebarHeader.js +10 -2
- package/dist/components/core/Sidebar/SidebarLogo.js +38 -3
- package/dist/components/core/Sidebar/SidebarSearch.d.ts +22 -0
- package/dist/components/core/Sidebar/SidebarSearch.js +135 -0
- package/dist/components/core/Sidebar/SidebarToggle.js +1 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.js +2 -2
- package/dist/components/core/Sidebar/index.d.ts +3 -1
- package/dist/components/core/Tag/Tag.js +29 -5
- package/dist/components/core/Tag/Tag.theme.js +13 -8
- package/dist/components/core/Tag/Tag.types.d.ts +7 -0
- package/dist/components/core/Tooltip/Tooltip.js +1 -1
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -2
- package/dist/components/core/index.d.ts +1 -0
- package/dist/components/core/index.js +4 -0
- package/dist/components/data-display/GanttChart/GanttChart.d.ts +1 -1
- package/dist/components/data-display/GanttChart/GanttChart.js +31 -4
- package/dist/components/data-display/GanttChart/GanttChart.theme.js +19 -17
- package/dist/components/data-display/GanttChart/GanttChart.types.d.ts +19 -0
- package/dist/components/data-display/GanttChart/GanttChart.utils.js +1 -1
- package/dist/components/data-display/GanttChart/GanttChartPanel.d.ts +1 -1
- package/dist/components/data-display/GanttChart/GanttChartPanel.js +3 -3
- package/dist/components/data-display/GanttChart/GanttDependencyArrows.js +7 -4
- package/dist/components/data-display/GanttChart/GanttMilestone.js +5 -5
- package/dist/components/data-display/GanttChart/GanttTablePanel.js +1 -1
- package/dist/components/data-display/GanttChart/GanttTableTaskRow.js +2 -2
- package/dist/components/data-display/GanttChart/GanttTaskBar.js +37 -16
- package/dist/components/data-display/GanttChart/GanttTimelineGrid.js +2 -1
- package/dist/components/data-display/GanttChart/GanttTimelineHeader.js +35 -11
- package/dist/components/data-display/GanttChart/GanttToolbar.js +2 -2
- package/dist/components/data-display/GanttChart/hooks/useGanttDrag.js +3 -2
- package/dist/components/data-display/GanttChart/index.d.ts +1 -1
- package/dist/components/data-display/Table/Table.theme.js +3 -5
- package/dist/components/effects/Aurora/Aurora.d.ts +6 -17
- package/dist/components/effects/Aurora/Aurora.js +297 -131
- package/dist/components/effects/Aurora/Aurora.types.d.ts +6 -0
- package/dist/components/forms/Combobox/Combobox.js +1 -1
- package/dist/components/forms/Combobox/Combobox.theme.js +2 -4
- package/dist/components/forms/CronInput/CronInput.js +1 -1
- package/dist/components/forms/CronInput/CronInput.theme.js +14 -23
- package/dist/components/forms/DatePicker/DatePicker.theme.js +11 -18
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +6 -13
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
- package/dist/components/forms/FileUpload/FileUpload.animations.d.ts +29 -0
- package/dist/components/forms/FileUpload/FileUpload.animations.js +19 -0
- package/dist/components/forms/FileUpload/FileUpload.js +87 -48
- package/dist/components/forms/FileUpload/FileUpload.theme.d.ts +2 -10
- package/dist/components/forms/FileUpload/FileUpload.theme.js +16 -30
- package/dist/components/forms/FileUpload/FileUpload.types.d.ts +26 -10
- package/dist/components/forms/Input/Input.theme.js +13 -10
- package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
- package/dist/components/forms/Mention/Mention.js +152 -57
- package/dist/components/forms/Mention/Mention.theme.js +16 -23
- package/dist/components/forms/Mention/Mention.types.d.ts +12 -12
- package/dist/components/forms/Mention/Mention.utils.js +32 -4
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +3 -3
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +5 -5
- package/dist/components/forms/Select/Select.js +2 -2
- package/dist/components/forms/Select/Select.theme.js +3 -3
- package/dist/components/forms/TimePicker/TimePickerContent.js +3 -0
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
- package/dist/components/forms/forms.theme.js +21 -16
- package/dist/components/forms/index.js +3 -0
- package/dist/components/layout/AppShell/AppShell.d.ts +10 -0
- package/dist/components/layout/AppShell/AppShell.js +84 -0
- package/dist/components/layout/AppShell/AppShell.theme.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShell.theme.js +42 -0
- package/dist/components/layout/AppShell/AppShell.types.d.ts +127 -0
- package/dist/components/layout/AppShell/AppShellContext.d.ts +14 -0
- package/dist/components/layout/AppShell/AppShellContext.js +19 -0
- package/dist/components/layout/AppShell/AppShellFooter.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellFooter.js +12 -0
- package/dist/components/layout/AppShell/AppShellHeader.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellHeader.js +12 -0
- package/dist/components/layout/AppShell/AppShellMain.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellMain.js +19 -0
- package/dist/components/layout/AppShell/AppShellRightPanel.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellRightPanel.js +16 -0
- package/dist/components/layout/AppShell/AppShellSidebar.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellSidebar.js +16 -0
- package/dist/components/layout/AppShell/AppShellTopbar.d.ts +3 -0
- package/dist/components/layout/AppShell/AppShellTopbar.js +12 -0
- package/dist/components/layout/AppShell/index.d.ts +3 -0
- package/dist/components/layout/FormLayout/FormLayout.js +3 -0
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/hooks/useSelectPortal.d.ts +10 -2
- package/dist/hooks/useSelectPortal.js +45 -24
- package/dist/index.js +6 -0
- package/dist/registry.json +10021 -0
- package/dist/styles.css +1 -1
- package/dist/utils/dateUtils.js +11 -1
- package/package.json +4 -2
- package/src/global.scss +29 -8
- package/src/styles/theme.css +51 -12
|
@@ -50,6 +50,7 @@ import '../../core/Dropdown/DropdownItem.js';
|
|
|
50
50
|
import '../../core/Dropdown/DropdownSection.js';
|
|
51
51
|
import '../../core/Dropdown/DropdownSeparator.js';
|
|
52
52
|
import '../../core/Dropdown/Dropdown.theme.js';
|
|
53
|
+
import '../../core/DotSeparator/DotSeparator.js';
|
|
53
54
|
import '../../core/Kbd/Kbd.js';
|
|
54
55
|
import '../../core/MenuItem/MenuItem.js';
|
|
55
56
|
import '../../core/Link/Link.js';
|
|
@@ -100,6 +101,8 @@ import '../../core/Sidebar/SidebarToggle.js';
|
|
|
100
101
|
import '../../core/Sidebar/SidebarMobileTrigger.js';
|
|
101
102
|
import '../../core/Sidebar/SidebarUserProfile.js';
|
|
102
103
|
import '../../core/Sidebar/SidebarLogo.js';
|
|
104
|
+
import '../../core/Sidebar/SidebarSearch.js';
|
|
105
|
+
import '../../core/Sidebar/SidebarCard.js';
|
|
103
106
|
import '../../core/Sidebar/SidebarContext.js';
|
|
104
107
|
import '../../core/OfflineIndicator/OfflineIndicator.js';
|
|
105
108
|
import '../../core/ContextMenu/ContextMenu.js';
|
|
@@ -32,6 +32,7 @@ import '../../core/Dropdown/DropdownItem.js';
|
|
|
32
32
|
import '../../core/Dropdown/DropdownSection.js';
|
|
33
33
|
import '../../core/Dropdown/DropdownSeparator.js';
|
|
34
34
|
import '../../core/Dropdown/Dropdown.theme.js';
|
|
35
|
+
import '../../core/DotSeparator/DotSeparator.js';
|
|
35
36
|
import '../../core/Kbd/Kbd.js';
|
|
36
37
|
import '../../core/MenuItem/MenuItem.js';
|
|
37
38
|
import '../../core/Link/Link.js';
|
|
@@ -82,6 +83,8 @@ import '../../core/Sidebar/SidebarToggle.js';
|
|
|
82
83
|
import '../../core/Sidebar/SidebarMobileTrigger.js';
|
|
83
84
|
import '../../core/Sidebar/SidebarUserProfile.js';
|
|
84
85
|
import '../../core/Sidebar/SidebarLogo.js';
|
|
86
|
+
import '../../core/Sidebar/SidebarSearch.js';
|
|
87
|
+
import '../../core/Sidebar/SidebarCard.js';
|
|
85
88
|
import '../../core/Sidebar/SidebarContext.js';
|
|
86
89
|
import '../../core/OfflineIndicator/OfflineIndicator.js';
|
|
87
90
|
import '../../core/ContextMenu/ContextMenu.js';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
const buttonTheme = {
|
|
5
5
|
// Base styles for the button element
|
|
6
|
-
baseStyle: "relative inline-flex items-center justify-center gap-2 focus:outline-none rounded-[var(--button-radius)] overflow-hidden cursor-pointer transition-all duration-300 ease-in-out min-w-fit flex-shrink-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 cursor-pointer",
|
|
6
|
+
baseStyle: "relative inline-flex items-center justify-center gap-2 focus:outline-none rounded-[var(--button-radius)] overflow-hidden cursor-pointer transition-all duration-300 ease-in-out min-w-fit flex-shrink-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 cursor-pointer backdrop-blur-sm",
|
|
7
7
|
// Visual style variants - STRUCTURE only (no colors)
|
|
8
8
|
variantStyles: {
|
|
9
9
|
filled: "border hover:brightness-[0.9] dark:hover:brightness-[1.15]",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Uses design tokens and data-[state=*] selectors
|
|
4
4
|
*/
|
|
5
5
|
const calendarTheme = {
|
|
6
|
-
baseStyle: "select-none w-full bg-
|
|
6
|
+
baseStyle: "select-none w-full bg-[var(--color-surface)]",
|
|
7
7
|
headerStyle: "flex items-center justify-between mb-4",
|
|
8
8
|
titleStyle: "text-sm font-semibold text-[var(--color-text-primary)] " + "",
|
|
9
9
|
headerDropdownsStyle: "grid grid-cols-2 items-center gap-2 flex-1 justify-center mx-3",
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import React__default from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { MenuItem } from '../MenuItem/MenuItem.js';
|
|
4
4
|
import { Kbd } from '../Kbd/Kbd.js';
|
|
5
|
-
import { commandPaletteTheme } from './CommandPalette.theme.js';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Map string shortcuts to KbdKey types
|
|
@@ -100,7 +99,7 @@ const Shortcut = ({ keys }) => {
|
|
|
100
99
|
* />
|
|
101
100
|
* ```
|
|
102
101
|
*/
|
|
103
|
-
const CommandItem = ({ command, index, isHighlighted, contentStart, contentEnd, className, onSelect, onMouseEnter,
|
|
102
|
+
const CommandItem = ({ command, index, isHighlighted, contentStart, contentEnd, className, onSelect, onMouseEnter, }) => {
|
|
104
103
|
const handleClick = () => {
|
|
105
104
|
if (!command.disabled) {
|
|
106
105
|
onSelect(command);
|
|
@@ -126,7 +125,7 @@ const CommandItem = ({ command, index, isHighlighted, contentStart, contentEnd,
|
|
|
126
125
|
}
|
|
127
126
|
return null;
|
|
128
127
|
};
|
|
129
|
-
return (
|
|
128
|
+
return (jsx(MenuItem, { role: "option", selected: isHighlighted, disabled: command.disabled, startContent: finalContentStart, subtitle: command.subtitle, endContent: renderContentEnd(), onActivate: handleClick, onMouseEnter: handleMouseEnter, "aria-selected": isHighlighted, "data-command-index": index, "data-highlighted": isHighlighted, className: className, children: command.label }));
|
|
130
129
|
};
|
|
131
130
|
|
|
132
131
|
export { CommandItem };
|
|
@@ -211,7 +211,7 @@ const CommandPalette = React__default.forwardRef(({ isOpen, onClose, commands =
|
|
|
211
211
|
// Otherwise render flat list
|
|
212
212
|
return displayCommands.map((command, index) => (jsx(CommandItem, { command: command, index: index, isHighlighted: index === highlightedIndex, onSelect: handleSelectCommand, onMouseEnter: setHighlightedIndex, theme: theme }, command.id)));
|
|
213
213
|
};
|
|
214
|
-
return (jsxs(Overlay, { ref: ref, isOpen: isOpen, onClose: onClose, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, position: "top", overlayClassName: overlayClassName, contentClassName: cn(theme.container, className), animations: {
|
|
214
|
+
return (jsxs(Overlay, { ref: ref, isOpen: isOpen, onClose: onClose, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, position: "top", overlayClassName: cn(theme.overlay, overlayClassName), contentClassName: cn(theme.container, className), animations: {
|
|
215
215
|
overlay: overlayAnimations,
|
|
216
216
|
content: containerAnimations,
|
|
217
217
|
}, children: [jsx("div", { className: theme.searchWrapper, children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(MagnifyingGlassIcon, { className: "w-5 h-5 text-[var(--color-text-muted)]", strokeWidth: 2 }), jsx("input", { ref: searchInputRef, type: "text", className: theme.searchInput, placeholder: placeholder, value: searchValue, onChange: handleSearchChange, autoComplete: "off", autoCorrect: "off", spellCheck: false, "aria-label": "Search commands" })] }) }), jsx(ScrollArea, { ref: listContainerRef, type: "hover", className: "overscroll-contain px-1", style: {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
const commandPaletteTheme = {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Applied to the Overlay backdrop (positioning/z-index come from Overlay).
|
|
3
|
+
// Overrides the shared 65%-black scrim (--overlay-bg) with a lighter dim so
|
|
4
|
+
// real page content sits behind the container — that's what the container's
|
|
5
|
+
// backdrop-blur frosts into the glass effect. A heavy scrim would leave only
|
|
6
|
+
// a flat dark layer to blur, making backdrop-blur look like it does nothing.
|
|
7
|
+
overlay: "bg-black/30",
|
|
4
8
|
container: "relative w-full max-h-[calc(100vh-2rem)] max-w-lg " +
|
|
5
|
-
"bg-[var(--color-
|
|
9
|
+
"bg-[var(--color-surface-overlay)] backdrop-blur-md rounded-[var(--modal-radius)] shadow-2xl shadow-black/30 " +
|
|
6
10
|
"border border-[var(--color-border)] ring-4 ring-[var(--color-background)]/20 " +
|
|
7
11
|
"flex flex-col my-4 min-h-0 overflow-hidden " +
|
|
8
12
|
// Dark mode
|
|
@@ -11,18 +15,12 @@ const commandPaletteTheme = {
|
|
|
11
15
|
searchInput: "w-full px-0 py-0 text-sm bg-transparent border-none outline-none " +
|
|
12
16
|
"text-[var(--color-text-primary)] placeholder:text-[var(--color-text-placeholder)] " +
|
|
13
17
|
"focus:outline-none focus:ring-0 " +
|
|
14
|
-
// Dark mode
|
|
15
|
-
"dark:text-[var(--color-
|
|
18
|
+
// Dark mode — matches Input's controlBaseStyle text/placeholder tokens
|
|
19
|
+
"dark:text-[var(--color-text-primary)] dark:placeholder:text-[var(--color-neutral-500)]",
|
|
16
20
|
groupLabel: "px-4 py-1 text-xs font-semibold text-[var(--color-text-muted)]/50 uppercase " +
|
|
17
21
|
"dark:text-[var(--color-neutral-500)]",
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"data-[highlighted=true]:bg-[var(--color-primary)] data-[highlighted=true]:hover:bg-[var(--color-primary)] " +
|
|
21
|
-
"data-[highlighted=true]:text-[var(--color-primary-contrast)] " +
|
|
22
|
-
"data-[disabled=true]:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:hover:bg-transparent " +
|
|
23
|
-
// Dark mode - adjust hover state
|
|
24
|
-
"dark:text-[var(--color-neutral-200)] dark:hover:bg-[var(--color-primary-600)] " +
|
|
25
|
-
"dark:data-[highlighted=true]:bg-[var(--color-primary-600)]",
|
|
22
|
+
// Command rows render via the shared MenuItem primitive and use its default
|
|
23
|
+
// styling (subtle highlight + standard padding) — no per-row theme here.
|
|
26
24
|
emptyState: "px-4 py-12 text-center text-sm text-[var(--color-text-muted)] " +
|
|
27
25
|
"dark:text-[var(--color-neutral-500)]",
|
|
28
26
|
footer: "border-t border-[var(--color-border)] px-4 py-2 text-xs text-[var(--color-text-muted)]font-medium",
|
|
@@ -86,8 +86,6 @@ export interface CommandPaletteThemeOverrides {
|
|
|
86
86
|
searchInput?: string;
|
|
87
87
|
/** Style for group labels */
|
|
88
88
|
groupLabel?: string;
|
|
89
|
-
/** Style for command items (uses data-[highlighted] and data-[disabled] selectors) */
|
|
90
|
-
commandItem?: string;
|
|
91
89
|
/** Style for empty state */
|
|
92
90
|
emptyState?: string;
|
|
93
91
|
/** Style for the footer area */
|
|
@@ -5,21 +5,20 @@ const contextMenuTheme = {
|
|
|
5
5
|
...dropdownTheme,
|
|
6
6
|
// Content uses the same styling as Dropdown menu
|
|
7
7
|
contentStyle: dropdownTheme.menuStyle.replace("flex", "flex-col p-1"),
|
|
8
|
-
// Items use exact same styling as Dropdown items
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
// Items use exact same styling as Dropdown items. The left padding for the
|
|
9
|
+
// check icon is applied per-item in ContextMenuItem (className) when checked.
|
|
10
|
+
itemStyle: dropdownTheme.itemBaseStyle,
|
|
11
|
+
// Checked state - tick icon positioning (absolute left).
|
|
12
|
+
// --color-text-primary flips for dark mode on its own.
|
|
13
|
+
itemCheckedStyle: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--color-text-primary)]",
|
|
14
|
+
// Submenu trigger - based on Dropdown item style with chevron space.
|
|
15
|
+
// --color-surface-hover is a translucent tint that lightens in dark on its own.
|
|
16
|
+
subTriggerStyle: `${dropdownTheme.itemBaseStyle} pr-8 data-[state=open]:bg-[var(--color-surface-hover)]`,
|
|
17
|
+
// Submenu content - floating anchored overlay, matches main dropdown menu
|
|
17
18
|
subContentStyle: "min-w-[180px] max-h-[400px] overflow-y-auto rounded-[var(--dropdown-radius)] border border-[var(--color-border)] " +
|
|
18
|
-
"bg-[var(--color-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
separatorStyle: "h-px bg-[var(--color-border)] my-1 -mx-1 " +
|
|
22
|
-
"dark:bg-[var(--color-neutral-700)]",
|
|
19
|
+
"bg-[var(--color-surface-overlay)] shadow-real-xl flex flex-col p-1 focus:outline-none",
|
|
20
|
+
// Separator - horizontal divider (--color-border flips for dark on its own)
|
|
21
|
+
separatorStyle: "h-px bg-[var(--color-border)] my-1 -mx-1",
|
|
23
22
|
// Label - section header (matches Dropdown section title)
|
|
24
23
|
labelStyle: dropdownTheme.sectionTitleStyle,
|
|
25
24
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React__default, { useMemo } from 'react';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { dotSeparatorTheme } from './DotSeparator.theme.js';
|
|
5
|
+
|
|
6
|
+
const DotSeparator = React__default.forwardRef(({ size = 'md', className, theme: customTheme = {}, ...props }, ref) => {
|
|
7
|
+
const theme = useMemo(() => ({
|
|
8
|
+
...dotSeparatorTheme,
|
|
9
|
+
...customTheme,
|
|
10
|
+
sizes: {
|
|
11
|
+
...dotSeparatorTheme.sizes,
|
|
12
|
+
...customTheme.sizes,
|
|
13
|
+
},
|
|
14
|
+
}), [customTheme]);
|
|
15
|
+
return (jsx("span", { ref: ref, "aria-hidden": "true", className: cn(theme.baseStyle, theme.sizes[size], className), ...props }));
|
|
16
|
+
});
|
|
17
|
+
DotSeparator.displayName = 'DotSeparator';
|
|
18
|
+
|
|
19
|
+
export { DotSeparator };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const dotSeparatorTheme = {
|
|
2
|
+
baseStyle: 'inline-block shrink-0 rounded-full align-middle bg-[var(--color-text-muted)]',
|
|
3
|
+
sizes: {
|
|
4
|
+
sm: 'size-0.5 mx-1', // 2px dot
|
|
5
|
+
md: 'size-1 mx-1.5', // 4px dot
|
|
6
|
+
lg: 'size-1.5 mx-2', // 6px dot
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { dotSeparatorTheme };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export type DotSeparatorSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
export interface DotSeparatorTheme {
|
|
4
|
+
baseStyle: string;
|
|
5
|
+
sizes: Record<DotSeparatorSize, string>;
|
|
6
|
+
}
|
|
7
|
+
export interface DotSeparatorThemeOverrides {
|
|
8
|
+
baseStyle?: string;
|
|
9
|
+
sizes?: Partial<Record<DotSeparatorSize, string>>;
|
|
10
|
+
}
|
|
11
|
+
export interface DotSeparatorProps extends HTMLAttributes<HTMLSpanElement> {
|
|
12
|
+
/**
|
|
13
|
+
* The size of the dot (also scales its horizontal spacing)
|
|
14
|
+
* @default 'md'
|
|
15
|
+
*/
|
|
16
|
+
size?: DotSeparatorSize;
|
|
17
|
+
/**
|
|
18
|
+
* Custom class name for the dot
|
|
19
|
+
*/
|
|
20
|
+
className?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Component-level theme overrides
|
|
23
|
+
*/
|
|
24
|
+
theme?: DotSeparatorThemeOverrides;
|
|
25
|
+
}
|
|
@@ -12,9 +12,8 @@ const dropdownTheme = {
|
|
|
12
12
|
sectionTitleStyle: "px-2 py-1.5 text-xs font-semibold text-[var(--color-text-muted)] uppercase tracking-tight",
|
|
13
13
|
// Section container styling
|
|
14
14
|
sectionStyle: "py-1",
|
|
15
|
-
// Separator between sections
|
|
16
|
-
separatorStyle: "my-1 h-px bg-[var(--color-border)]
|
|
17
|
-
"dark:bg-[var(--color-neutral-700)]",
|
|
15
|
+
// Separator between sections (--color-border flips for dark mode on its own)
|
|
16
|
+
separatorStyle: "my-1 h-px bg-[var(--color-border)]",
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
export { dropdownTheme };
|
|
@@ -63,7 +63,7 @@ const DropdownItem = React__default.forwardRef(({ itemKey, children, className,
|
|
|
63
63
|
// Build end content: user's endContent OR selection checkmark
|
|
64
64
|
const resolvedEndContent = endContent ||
|
|
65
65
|
(selectionMode !== "none" ? (jsx("div", { className: cn("flex items-center justify-center flex-shrink-0 w-5 h-5"), children: isSelected && (jsx(CheckIcon, { className: "size-4 text-[var(--color-text-secondary)]" })) })) : undefined);
|
|
66
|
-
return (jsx(MenuItem, { ref: ref, role: itemRole, disabled: disabled, isDanger: isDanger, startContent: startContent, endContent: resolvedEndContent, subtitle: subtitle, shortcut: shortcut, onActivate: handleActivate,
|
|
66
|
+
return (jsx(MenuItem, { ref: ref, role: itemRole, disabled: disabled, isDanger: isDanger, startContent: startContent, endContent: resolvedEndContent, subtitle: subtitle, shortcut: shortcut, onActivate: handleActivate, selected: isSelected, ...(selectionMode !== "none" ? { "aria-checked": isSelected } : {}), className: className, theme: {
|
|
67
67
|
baseStyle: theme.itemBaseStyle,
|
|
68
68
|
dangerStyle: theme.itemDangerStyle,
|
|
69
69
|
focusStyle: theme.itemFocusStyle,
|
|
@@ -189,7 +189,7 @@ const DropdownMenu = React__default.forwardRef(({ children, className, animation
|
|
|
189
189
|
}, "data-state": isOpen ? "open" : "closed", "data-placement": placement, ...domProps, children: children })) }));
|
|
190
190
|
// Use portal if specified - wrap with dark class for dark mode support
|
|
191
191
|
if (portal && isClient) {
|
|
192
|
-
return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: menuContent }), document.body);
|
|
192
|
+
return createPortal(jsx("div", { "data-flikkui-portal": "", className: isDarkMode ? "dark" : undefined, children: menuContent }), document.body);
|
|
193
193
|
}
|
|
194
194
|
return menuContent;
|
|
195
195
|
});
|
|
@@ -9,12 +9,15 @@ import { menuItemTheme } from './MenuItem.theme.js';
|
|
|
9
9
|
* Handles visual layout, base styling, keyboard activation, and focus tracking.
|
|
10
10
|
* Context-specific behavior (selection, checked state) is handled by consumers.
|
|
11
11
|
*/
|
|
12
|
-
const MenuItem = React__default.forwardRef(({ children, className, startContent, endContent, subtitle, shortcut, disabled = false, isDanger = false, onActivate, theme: themeOverrides, role = "menuitem", ...props }, ref) => {
|
|
12
|
+
const MenuItem = React__default.forwardRef(({ children, className, startContent, endContent, subtitle, shortcut, disabled = false, isDanger = false, selected = false, onActivate, theme: themeOverrides, role = "menuitem", ...props }, ref) => {
|
|
13
13
|
const [isFocused, setIsFocused] = useState(false);
|
|
14
14
|
const theme = {
|
|
15
15
|
...menuItemTheme,
|
|
16
16
|
...themeOverrides,
|
|
17
17
|
};
|
|
18
|
+
// Resolve state to plain utility classes (not data-[state] variants) so a
|
|
19
|
+
// consumer `className` always wins the cascade. See MenuItem.theme.ts.
|
|
20
|
+
const stateKey = disabled ? "disabled" : selected ? "selected" : "default";
|
|
18
21
|
const handleClick = useCallback(() => {
|
|
19
22
|
if (disabled)
|
|
20
23
|
return;
|
|
@@ -26,7 +29,7 @@ const MenuItem = React__default.forwardRef(({ children, className, startContent,
|
|
|
26
29
|
handleClick();
|
|
27
30
|
}
|
|
28
31
|
}, [handleClick]);
|
|
29
|
-
return (jsxs("div", { ref: ref, role: role, tabIndex: disabled ? undefined : -1, "aria-disabled": disabled, "data-focused": isFocused, "data-disabled": disabled, className: cn(theme.baseStyle, theme.
|
|
32
|
+
return (jsxs("div", { ref: ref, role: role, tabIndex: disabled ? undefined : -1, "aria-disabled": disabled, "data-focused": isFocused, "data-disabled": disabled, "data-selected": selected, className: cn(theme.baseStyle, theme.states[stateKey], isFocused && !disabled && !selected && theme.focusedStyle, isDanger && theme.dangerStyle, theme.focusStyle, className), onClick: handleClick, onKeyDown: handleKeyDown, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), ...props, children: [startContent && (jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: startContent })), jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsx("span", { className: "truncate", children: children }), shortcut && (jsx("span", { className: "ml-auto flex-shrink-0", children: shortcut }))] }), subtitle && (typeof subtitle === 'string'
|
|
30
33
|
? jsx("div", { className: theme.subtitleStyle, children: subtitle })
|
|
31
34
|
: subtitle)] }), endContent && (jsx("div", { className: "flex items-center justify-center ml-2", children: endContent }))] }));
|
|
32
35
|
});
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
const menuItemTheme = {
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
" "
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
"
|
|
2
|
+
// Structural base only — layout, spacing, radius, transition. No state colors:
|
|
3
|
+
// those are resolved in JS (see `states`) so a consumer `className` always wins.
|
|
4
|
+
baseStyle: "relative flex items-center gap-2 px-3 py-1.5 text-sm font-[500] cursor-pointer outline-none select-none rounded-[var(--radius-base)] transition-colors duration-300 mb-px last-of-type:mb-0",
|
|
5
|
+
// State styling resolved in JS to plain utility classes so `className` overrides
|
|
6
|
+
// win (data-[state] variants carry attribute-selector specificity and can't be
|
|
7
|
+
// overridden by a plain className — see Button.theme.ts / NavItem.theme.ts for
|
|
8
|
+
// the same rationale). data-* attributes are still emitted as hooks for
|
|
9
|
+
// consumer CSS + tests, just not used for styling here.
|
|
10
|
+
states: {
|
|
11
|
+
default: "text-[var(--color-text-primary)] hover:bg-[var(--color-surface-hover)]",
|
|
12
|
+
selected: "bg-[var(--color-primary)]/5 text-[var(--color-primary)] " +
|
|
13
|
+
"dark:bg-white/10 dark:text-[var(--color-text-primary)]",
|
|
14
|
+
disabled: "opacity-60 cursor-not-allowed pointer-events-none",
|
|
15
|
+
},
|
|
16
|
+
// Keyboard-focus highlight (item received roving focus) — same fill as hover.
|
|
17
|
+
focusedStyle: "bg-[var(--color-surface-hover)]",
|
|
15
18
|
// Danger item styling (e.g., Delete actions)
|
|
16
19
|
dangerStyle: "text-[var(--color-danger)] hover:bg-[var(--color-danger)] hover:text-[var(--color-danger-contrast)] " +
|
|
17
20
|
"dark:text-[var(--color-danger-400)] dark:hover:bg-[var(--color-danger-600)] dark:hover:text-[var(--color-danger-contrast)]",
|
|
18
21
|
// Focus visible styling for keyboard navigation
|
|
19
|
-
focusStyle: "focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
|
|
20
|
-
"dark:focus-visible:ring-[var(--color-primary-400)]
|
|
22
|
+
focusStyle: "focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)] " +
|
|
23
|
+
"dark:focus-visible:ring-[var(--color-primary-400)]",
|
|
21
24
|
// Description text below the label
|
|
22
|
-
subtitleStyle: "text-
|
|
25
|
+
subtitleStyle: "text-sm text-[var(--color-text-secondary)]/80 mt-0.5 truncate",
|
|
23
26
|
};
|
|
24
27
|
|
|
25
28
|
export { menuItemTheme };
|
|
@@ -17,6 +17,8 @@ export interface MenuItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>
|
|
|
17
17
|
disabled?: boolean;
|
|
18
18
|
/** Whether the item has danger/destructive styling */
|
|
19
19
|
isDanger?: boolean;
|
|
20
|
+
/** Whether the item is in a selected state (drives selected styling) */
|
|
21
|
+
selected?: boolean;
|
|
20
22
|
/** Called on click or Enter/Space keyboard activation */
|
|
21
23
|
onActivate?: () => void;
|
|
22
24
|
/** Theme overrides for styling */
|
|
@@ -186,8 +186,15 @@ const NavItem = React__default.forwardRef(({ children, startContent, endContent,
|
|
|
186
186
|
const textClasses = cn(theme.text);
|
|
187
187
|
// Chevron for submenu
|
|
188
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
|
-
|
|
189
|
+
// Strip drag/animation DOM handlers that collide with motion's prop types.
|
|
190
|
+
// `onSubmit`/`onSubmitCapture` are stripped too: NavItem renders as either
|
|
191
|
+
// `motion.a` or `motion.button`, but `NavItemProps extends HTMLAttributes<HTMLElement>`
|
|
192
|
+
// types these as `SubmitEventHandler<HTMLElement>`. Under react@canary types
|
|
193
|
+
// (e.g. Next 16 consumers building from source), `SubmitEvent` gains a
|
|
194
|
+
// T-dependent field, so the generic-element handler is no longer assignable to
|
|
195
|
+
// motion's element-specific `HTMLMotionProps<"a">` — a build-time type error.
|
|
196
|
+
// A NavItem never submits a form, so dropping these is behaviour-neutral.
|
|
197
|
+
const { onAnimationStart, onAnimationEnd, onDrag, onDragStart, onDragEnd, onSubmit, onSubmitCapture, ...motionSafeProps } = props;
|
|
191
198
|
const interactionProps = {
|
|
192
199
|
className: cn("relative overflow-hidden", containerClasses),
|
|
193
200
|
"aria-disabled": isDisabled || undefined,
|
|
@@ -199,15 +206,24 @@ const NavItem = React__default.forwardRef(({ children, startContent, endContent,
|
|
|
199
206
|
whileHover: isDisabled ? undefined : (isCollapsedView ? { scale: 1.05 } : undefined),
|
|
200
207
|
whileTap: isDisabled ? undefined : { scale: 0.98 },
|
|
201
208
|
transition: { type: "spring", stiffness: 400, damping: 25 },
|
|
209
|
+
// Note: tried Framer Motion's canonical `layout` + `LayoutGroup` +
|
|
210
|
+
// `mode="popLayout"` pattern for the row's height shrink — transforms
|
|
211
|
+
// *do* fire (verified via getComputedStyle), but the parent Sidebar's
|
|
212
|
+
// concurrent `motion.aside` width animation re-triggers measurements
|
|
213
|
+
// every frame, which keeps resetting the layout animation before it
|
|
214
|
+
// settles. The row visibly freezes mid-transform. Animating the inner
|
|
215
|
+
// motion.div's height directly (see AnimatePresence below) sidesteps the
|
|
216
|
+
// concurrent-measurement problem and produces a smooth ~200ms shrink.
|
|
202
217
|
...motionSafeProps,
|
|
203
218
|
};
|
|
204
219
|
const innerContent = (jsxs(Fragment, { children: [startContent && (jsxs("div", { className: "flex items-center justify-center flex-shrink-0 relative", children: [React__default.isValidElement(startContent)
|
|
205
220
|
? React__default.cloneElement(startContent, {
|
|
206
221
|
className: cn(iconClasses, startContent.props.className),
|
|
207
222
|
})
|
|
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.
|
|
223
|
+
: 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.div, { initial: { opacity: 0, x: -4, height: 0 }, animate: { opacity: 1, x: 0, height: "auto" }, exit: { opacity: 0, x: -4, height: 0 }, transition: {
|
|
209
224
|
opacity: { duration: 0.15, ease: [0.4, 0, 0.2, 1] },
|
|
210
|
-
x: { duration: 0.2, ease: [0.4, 0, 0.2, 1] }
|
|
225
|
+
x: { duration: 0.2, ease: [0.4, 0, 0.2, 1] },
|
|
226
|
+
height: { duration: 0.2, ease: [0.4, 0, 0.2, 1] },
|
|
211
227
|
}, 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
228
|
? ` (${notification} unread)`
|
|
213
229
|
: notification === true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const navItemTheme = {
|
|
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",
|
|
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,height,background-color,border-color,color,box-shadow] duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] text-left",
|
|
3
3
|
icon: "size-5",
|
|
4
4
|
text: "flex-1 min-w-0 truncate",
|
|
5
5
|
// State styling resolved in JS to plain utility classes so `className` overrides win
|
|
@@ -25,8 +25,19 @@ const navItemTheme = {
|
|
|
25
25
|
1: "pl-11",
|
|
26
26
|
2: "pl-10",
|
|
27
27
|
},
|
|
28
|
+
// Collapsed override gives every nav row a uniform 36×36 square hit-area.
|
|
29
|
+
// CRITICAL: this uses PADDING-based centering, not `justify-center`, so the
|
|
30
|
+
// expanded↔collapsed transition is one continuous animation of the padding
|
|
31
|
+
// + gap properties (which are CSS-transitionable). Toggling `justify-*`
|
|
32
|
+
// would cause a frame-0 flex-layout snap — the label appears at its final
|
|
33
|
+
// position instead of sliding in via AnimatePresence.
|
|
34
|
+
//
|
|
35
|
+
// On a 60px rail (Sidebar.Content px-3 → 36px interior, NavItem w-full):
|
|
36
|
+
// !px-2 (8 each) + size-5 icon (20) = 8 + 20 + 8 = 36 → centered icon.
|
|
37
|
+
// baseStyle's py-2 (8 each) + icon 20 = 36 → square height.
|
|
38
|
+
// !py-2 is repeated explicitly so the compact density's py-1.5 doesn't win.
|
|
28
39
|
collapsed: {
|
|
29
|
-
container: "!gap-0 !px-
|
|
40
|
+
container: "!gap-0 !px-2 !py-2",
|
|
30
41
|
icon: "size-5",
|
|
31
42
|
},
|
|
32
43
|
density: {
|
|
@@ -48,8 +48,12 @@ export interface PopoverBodyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
48
48
|
children: ReactNode;
|
|
49
49
|
animation?: boolean;
|
|
50
50
|
portal?: boolean;
|
|
51
|
-
/**
|
|
52
|
-
*
|
|
51
|
+
/** Cap the body to the viewport-available height (space below/above the
|
|
52
|
+
* trigger, computed by the positioning hook; falls back to 400px) and add
|
|
53
|
+
* `overflow-y-auto`, so tall content scrolls inside the popover instead of
|
|
54
|
+
* extending past the viewport unreachably. `max-height` + `auto` means short
|
|
55
|
+
* popovers show no scrollbar. Set `false` to opt out (uncapped, may overflow).
|
|
56
|
+
* @default true */
|
|
53
57
|
scrollable?: boolean;
|
|
54
58
|
/** Custom max-height when scrollable is true (e.g. "300px", "20rem").
|
|
55
59
|
* Overrides the default viewport-aware height. */
|
|
@@ -26,7 +26,7 @@ const overlayContentAnimations = {
|
|
|
26
26
|
/**
|
|
27
27
|
* PopoverBody component displays the body/content of the popover
|
|
28
28
|
*/
|
|
29
|
-
const PopoverBody = React__default.forwardRef(({ children, className, animation = true, portal = true, scrollable =
|
|
29
|
+
const PopoverBody = React__default.forwardRef(({ children, className, animation = true, portal = true, scrollable = true, maxHeight, ...props }, ref) => {
|
|
30
30
|
const { isOpen, onOpenChange, triggerRef, contentRef, placement, offset, triggerType, closeOnClickOutside, closeOnEsc, preventClose, hasBackdrop, theme, contentId, } = usePopoverContext();
|
|
31
31
|
const shouldReduceMotion = useReducedMotion();
|
|
32
32
|
const localRef = useRef(null);
|
|
@@ -45,13 +45,20 @@ const PopoverBody = React__default.forwardRef(({ children, className, animation
|
|
|
45
45
|
});
|
|
46
46
|
// Click outside detection (active when no backdrop — with backdrop, Overlay handles it)
|
|
47
47
|
useClickOutside(localRef, (e) => {
|
|
48
|
-
var _a;
|
|
48
|
+
var _a, _b, _c;
|
|
49
49
|
if (hasBackdrop)
|
|
50
50
|
return; // Overlay handles click-outside via backdrop
|
|
51
51
|
if (e.target === triggerRef.current ||
|
|
52
52
|
((_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
+
// Ignore clicks that land inside any FlikkUI overlay portal (a nested
|
|
56
|
+
// Select/Tooltip/Dropdown/Popover renders to document.body, outside our
|
|
57
|
+
// content ref — without this it would count as an outside click and
|
|
58
|
+
// dismiss the popover). See the `data-flikkui-portal` convention.
|
|
59
|
+
if ((_c = (_b = e.target) === null || _b === void 0 ? void 0 : _b.closest) === null || _c === void 0 ? void 0 : _c.call(_b, "[data-flikkui-portal]")) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
55
62
|
if (closeOnClickOutside && !preventClose) {
|
|
56
63
|
onOpenChange(false);
|
|
57
64
|
}
|
|
@@ -120,7 +127,7 @@ const PopoverBody = React__default.forwardRef(({ children, className, animation
|
|
|
120
127
|
? { duration: 0 }
|
|
121
128
|
: popoverTransitions.content, "data-state": isOpen ? "open" : "closed", "data-placement": placement, "data-trigger": triggerType, onClick: (e) => e.stopPropagation(), ...domProps, children: children })) }));
|
|
122
129
|
if (portal && isClient) {
|
|
123
|
-
return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: popoverContent }), document.body);
|
|
130
|
+
return createPortal(jsx("div", { "data-flikkui-portal": "", className: isDarkMode ? "dark" : undefined, children: popoverContent }), document.body);
|
|
124
131
|
}
|
|
125
132
|
return popoverContent;
|
|
126
133
|
});
|
|
@@ -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-surface
|
|
6
|
+
baseStyle: "relative flex rounded-[var(--segmented-radius)] bg-[var(--color-surface)] border border-[var(--color-border)]/60 p-[var(--segmented-padding)] shadow-inner",
|
|
7
7
|
// Size variants using CSS variables
|
|
8
8
|
sizes: {
|
|
9
9
|
sm: "min-h-[var(--segmented-min-h-sm)]",
|
|
@@ -11,4 +11,6 @@ export declare const Sidebar: React.ForwardRefExoticComponent<SidebarProps & Rea
|
|
|
11
11
|
MobileTrigger: React.ForwardRefExoticComponent<import("./Sidebar.types").SidebarMobileTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
12
12
|
UserProfile: React.ForwardRefExoticComponent<import("./Sidebar.types").SidebarUserProfileProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
13
|
Logo: React.ForwardRefExoticComponent<import("./Sidebar.types").SidebarLogoProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
|
+
Search: React.ForwardRefExoticComponent<import("./Sidebar.types").SidebarSearchProps & React.RefAttributes<HTMLInputElement>>;
|
|
15
|
+
Card: React.ForwardRefExoticComponent<import("./Sidebar.types").SidebarCardProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
16
|
};
|
|
@@ -14,21 +14,27 @@ import { SidebarToggle } from './SidebarToggle.js';
|
|
|
14
14
|
import { SidebarMobileTrigger } from './SidebarMobileTrigger.js';
|
|
15
15
|
import { SidebarUserProfile } from './SidebarUserProfile.js';
|
|
16
16
|
import { SidebarLogo } from './SidebarLogo.js';
|
|
17
|
+
import { SidebarSearch } from './SidebarSearch.js';
|
|
18
|
+
import { SidebarCard } from './SidebarCard.js';
|
|
17
19
|
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
20
|
+
// Subtle spring on the sidebar's width animation. Stiffness/damping picked so
|
|
21
|
+
// the effective duration sits in the same ~200ms window as the internal CSS
|
|
22
|
+
// transitions on padding/gap (Tailwind `duration-200`), but with a soft
|
|
23
|
+
// organic settle instead of a linear cubic-bezier. Damping ratio ≈ 0.9 — a
|
|
24
|
+
// hair under critical so there's a barely-perceptible easing-into-final
|
|
25
|
+
// rather than an overshoot/bounce.
|
|
21
26
|
const SIDEBAR_TRANSITION = {
|
|
22
|
-
type: "
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
type: "spring",
|
|
28
|
+
stiffness: 320,
|
|
29
|
+
damping: 34,
|
|
30
|
+
mass: 1,
|
|
25
31
|
};
|
|
26
32
|
const SidebarDesktop = React__default.forwardRef(({ side = "left", variant = "sidebar", density, width, children, className, theme: customTheme = {}, ...props }, ref) => {
|
|
27
33
|
var _a, _b, _c, _d;
|
|
28
34
|
const context = useSidebarContext();
|
|
29
35
|
const collapsed = (_a = context === null || context === void 0 ? void 0 : context.collapsed) !== null && _a !== void 0 ? _a : false;
|
|
30
36
|
const expandedWidth = (width === null || width === void 0 ? void 0 : width.expanded) || ((_b = context === null || context === void 0 ? void 0 : context.width) === null || _b === void 0 ? void 0 : _b.expanded) || 280;
|
|
31
|
-
const collapsedWidth = (width === null || width === void 0 ? void 0 : width.collapsed) || ((_c = context === null || context === void 0 ? void 0 : context.width) === null || _c === void 0 ? void 0 : _c.collapsed) ||
|
|
37
|
+
const collapsedWidth = (width === null || width === void 0 ? void 0 : width.collapsed) || ((_c = context === null || context === void 0 ? void 0 : context.width) === null || _c === void 0 ? void 0 : _c.collapsed) || 60;
|
|
32
38
|
const theme = useMemo(() => ({
|
|
33
39
|
...sidebarTheme,
|
|
34
40
|
...customTheme,
|
|
@@ -104,6 +110,8 @@ const Sidebar = Object.assign(SidebarRoot, {
|
|
|
104
110
|
MobileTrigger: SidebarMobileTrigger,
|
|
105
111
|
UserProfile: SidebarUserProfile,
|
|
106
112
|
Logo: SidebarLogo,
|
|
113
|
+
Search: SidebarSearch,
|
|
114
|
+
Card: SidebarCard,
|
|
107
115
|
});
|
|
108
116
|
|
|
109
117
|
export { Sidebar };
|