@flikk/ui 1.0.0-beta.23 → 1.0.0-beta.25
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/charts/AreaChart/AreaChart.types.d.ts +2 -2
- package/dist/components/charts/BarChart/BarChart.types.d.ts +2 -2
- package/dist/components/charts/ComboChart/ComboChart.types.d.ts +2 -2
- package/dist/components/charts/LineChart/LineChart.types.d.ts +2 -2
- package/dist/components/charts/ScatterPlot/ScatterPlot.types.d.ts +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.types.d.ts +2 -2
- package/dist/components/core/Accordion/Accordion.theme.js +2 -2
- package/dist/components/core/Accordion/AccordionTrigger.js +28 -1
- package/dist/components/core/Alert/Alert.js +2 -1
- package/dist/components/core/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/core/Badge/Badge.js +6 -17
- package/dist/components/core/Breadcrumbs/Breadcrumbs.js +17 -28
- package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +2 -2
- 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 +1 -1
- package/dist/components/core/Carousel/CarouselBody.js +6 -1
- package/dist/components/core/ContextMenu/ContextMenuBody.js +6 -3
- package/dist/components/core/ContextMenu/ContextMenuSubBody.js +6 -3
- package/dist/components/core/DragDrop/DragDrop.js +170 -17
- package/dist/components/core/DragDrop/DragDrop.types.d.ts +6 -0
- package/dist/components/core/Drawer/Drawer.d.ts +1 -1
- package/dist/components/core/Drawer/Drawer.js +2 -0
- package/dist/components/core/Drawer/Drawer.types.d.ts +2 -0
- package/dist/components/core/Drawer/DrawerTitle.d.ts +1 -1
- package/dist/components/core/Drawer/DrawerTitle.js +2 -2
- package/dist/components/core/Dropdown/DropdownMenu.js +2 -30
- package/dist/components/core/Empty/Empty.theme.js +1 -1
- package/dist/components/core/Link/Link.js +1 -1
- package/dist/components/core/Masonry/Masonry.js +7 -2
- package/dist/components/core/Modal/Modal.d.ts +1 -1
- package/dist/components/core/Modal/Modal.js +3 -3
- package/dist/components/core/Modal/Modal.types.d.ts +2 -0
- package/dist/components/core/Modal/ModalTitle.d.ts +1 -1
- package/dist/components/core/Modal/ModalTitle.js +2 -2
- package/dist/components/core/NavItem/NavItem.js +13 -8
- package/dist/components/core/Pagination/Pagination.js +1 -1
- package/dist/components/core/Popover/PopoverBody.js +3 -27
- package/dist/components/core/Popover/PopoverTrigger.js +1 -1
- package/dist/components/core/Progress/Progress.js +4 -4
- package/dist/components/core/Rating/Rating.js +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +3 -2
- package/dist/components/core/Segmented/Segmented.js +6 -6
- package/dist/components/core/Segmented/SegmentedItem.js +28 -2
- package/dist/components/core/Skeleton/Skeleton.js +2 -2
- package/dist/components/core/Sortable/Sortable.d.ts +1 -1
- package/dist/components/core/Sortable/Sortable.js +20 -4
- package/dist/components/core/Sortable/Sortable.types.d.ts +2 -0
- package/dist/components/core/Tabs/Tabs.js +6 -4
- package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
- package/dist/components/core/Tabs/TabsBody.js +3 -3
- package/dist/components/core/Tabs/TabsList.js +19 -21
- package/dist/components/core/Tabs/TabsTrigger.js +47 -28
- package/dist/components/core/Toast/Toast.js +1 -1
- package/dist/components/core/Toast/ToastProvider.js +3 -2
- package/dist/components/core/Tooltip/Tooltip.js +25 -34
- package/dist/components/core/Tree/Tree.js +178 -8
- package/dist/components/data-display/GanttChart/GanttSplitter.js +15 -1
- package/dist/components/data-display/Table/Table.js +2 -2
- package/dist/components/data-display/Table/Table.types.d.ts +2 -0
- package/dist/components/data-display/Table/TableFilter.js +21 -18
- 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/CustomCursor/CustomCursor.js +3 -7
- package/dist/components/effects/Overlay/Overlay.js +4 -9
- package/dist/components/effects/PageTransition/PageTransition.js +17 -6
- package/dist/components/effects/SpotlightBorder/SpotlightBorder.js +3 -4
- package/dist/components/effects/index.d.ts +7 -0
- package/dist/components/effects/index.js +3 -0
- package/dist/components/forms/Checkbox/Checkbox.js +11 -1
- package/dist/components/forms/Checkbox/Checkbox.theme.js +4 -1
- package/dist/components/forms/Checkbox/Checkbox.types.d.ts +7 -5
- package/dist/components/forms/Checkbox/CheckboxGroup.js +9 -4
- package/dist/components/forms/ColorPicker/ColorPicker.js +7 -4
- package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +2 -2
- package/dist/components/forms/ColorPicker/ColorPickerBody.js +5 -3
- package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +3 -3
- package/dist/components/forms/ColorPicker/ColorPickerGradient.js +8 -8
- package/dist/components/forms/ColorPicker/ColorPickerInput.js +1 -1
- package/dist/components/forms/ColorPicker/index.d.ts +1 -1
- package/dist/components/forms/Combobox/Combobox.js +20 -45
- package/dist/components/forms/Combobox/Combobox.types.d.ts +4 -2
- package/dist/components/forms/CronInput/CronInput.js +10 -4
- package/dist/components/forms/CronInput/CronInput.types.d.ts +12 -1
- package/dist/components/forms/DatePicker/DatePicker.js +2 -2
- package/dist/components/forms/DatePicker/DatePicker.types.d.ts +4 -2
- package/dist/components/forms/DatePicker/DatePickerBody.js +1 -29
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +2 -2
- package/dist/components/forms/DateRangePicker/DateRangePicker.js +3 -3
- package/dist/components/forms/DateRangePicker/DateRangePicker.types.d.ts +4 -2
- package/dist/components/forms/DateRangePicker/DateRangePickerBody.js +1 -28
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +2 -2
- package/dist/components/forms/FileUpload/FileUpload.js +14 -10
- package/dist/components/forms/FileUpload/FileUpload.types.d.ts +15 -0
- package/dist/components/forms/FormLabel/FormLabel.js +2 -2
- package/dist/components/forms/Input/Input.js +5 -3
- package/dist/components/forms/Input/Input.types.d.ts +2 -0
- package/dist/components/forms/InputAddress/InputAddress.d.ts +1 -1
- package/dist/components/forms/InputAddress/InputAddress.js +8 -9
- package/dist/components/forms/InputCounter/InputCounter.js +25 -18
- package/dist/components/forms/InputCounter/InputCounter.types.d.ts +8 -1
- package/dist/components/forms/InputCreditCard/InputCreditCard.d.ts +1 -1
- package/dist/components/forms/InputCreditCard/InputCreditCard.js +27 -9
- package/dist/components/forms/InputCreditCard/InputCreditCard.types.d.ts +5 -0
- package/dist/components/forms/InputOTP/InputOTP.js +26 -17
- package/dist/components/forms/InputOTP/InputOTP.types.d.ts +21 -4
- package/dist/components/forms/InputTag/InputTag.js +12 -39
- package/dist/components/forms/InputTag/InputTag.types.d.ts +2 -2
- package/dist/components/forms/Mention/Mention.js +13 -6
- package/dist/components/forms/Mention/Mention.types.d.ts +9 -0
- package/dist/components/forms/Radio/Radio.js +12 -2
- package/dist/components/forms/Radio/Radio.theme.js +5 -1
- package/dist/components/forms/Radio/Radio.types.d.ts +7 -5
- package/dist/components/forms/Radio/RadioGroup.js +8 -3
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +21 -21
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +2 -2
- package/dist/components/forms/Select/Select.d.ts +2 -0
- package/dist/components/forms/Select/Select.js +27 -57
- package/dist/components/forms/Select/Select.types.d.ts +14 -0
- package/dist/components/forms/Signature/Signature.js +1 -1
- package/dist/components/forms/Signature/Signature.types.d.ts +3 -3
- package/dist/components/forms/Slider/Slider.js +18 -4
- package/dist/components/forms/Slider/Slider.types.d.ts +2 -2
- package/dist/components/forms/Switch/Switch.js +12 -19
- package/dist/components/forms/Switch/Switch.theme.js +12 -2
- package/dist/components/forms/Switch/Switch.types.d.ts +20 -2
- package/dist/components/forms/Textarea/Textarea.js +8 -3
- package/dist/components/forms/Textarea/Textarea.types.d.ts +2 -0
- package/dist/components/forms/TimePicker/TimePicker.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.types.d.ts +6 -2
- package/dist/components/forms/TimePicker/TimePickerContent.js +2 -29
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +2 -2
- package/dist/components/forms/index.js +1 -1
- package/dist/components/layout/index.js +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useClickOutside.d.ts +10 -4
- package/dist/hooks/useClickOutside.js +44 -24
- package/dist/hooks/useDarkMode.d.ts +1 -0
- package/dist/hooks/useDarkMode.js +42 -0
- package/dist/hooks/useFormStateMachine.d.ts +1 -1
- package/dist/hooks/useNetworkStatus.js +1 -1
- package/dist/hooks/useOverlay.js +4 -0
- package/dist/hooks/useScaleBackground.js +5 -2
- package/dist/hooks/useSelectPortal.js +14 -5
- package/dist/index.d.ts +0 -2
- package/dist/index.js +1 -57
- package/dist/shadcn-compat.css +80 -0
- package/dist/styles.css +1 -1
- package/dist/utils/stateMachine.d.ts +4 -4
- package/package.json +11 -10
- package/tailwind.preset.cjs +32 -3
- /package/{src/theme-plugin.css → dist/theme.css} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import React__default, { createContext, useState, useRef, useCallback, useMemo, useEffect, useContext } from 'react';
|
|
3
3
|
import { motion } from 'motion/react';
|
|
4
4
|
export { AnimatePresence } from 'motion/react';
|
|
@@ -6,20 +6,48 @@ import { cn } from '../../../utils/cn.js';
|
|
|
6
6
|
import { dragDropTheme } from './DragDrop.theme.js';
|
|
7
7
|
|
|
8
8
|
const DragDropContext = createContext(null);
|
|
9
|
-
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Provider
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const DragDropProvider = React__default.forwardRef(({ children }, _ref) => {
|
|
13
|
+
// pointer drag state
|
|
10
14
|
const [activeDrag, setActiveDrag] = useState(null);
|
|
11
15
|
const pointerRef = useRef(null);
|
|
12
16
|
const dropZones = useRef(new Map());
|
|
13
17
|
const groupIdRef = useRef(`dd-${Math.random().toString(36).slice(2)}`);
|
|
18
|
+
// keyboard drag state
|
|
19
|
+
const [keyboardDragId, setKeyboardDragId] = useState(null);
|
|
20
|
+
const [keyboardDragLabel, setKeyboardDragLabel] = useState('');
|
|
21
|
+
const [announcement, setAnnouncement] = useState('');
|
|
22
|
+
// Stable ordered list of drop-zone IDs so Arrow-key cycling is deterministic
|
|
23
|
+
const dropZoneOrder = useRef([]);
|
|
14
24
|
const registerDropZone = useCallback((id, element) => {
|
|
15
25
|
dropZones.current.set(id, element);
|
|
26
|
+
if (!dropZoneOrder.current.includes(id)) {
|
|
27
|
+
dropZoneOrder.current.push(id);
|
|
28
|
+
}
|
|
16
29
|
}, []);
|
|
17
30
|
const unregisterDropZone = useCallback((id) => {
|
|
18
31
|
dropZones.current.delete(id);
|
|
32
|
+
dropZoneOrder.current = dropZoneOrder.current.filter((zid) => zid !== id);
|
|
19
33
|
}, []);
|
|
20
34
|
const setPointer = useCallback((point) => {
|
|
21
35
|
pointerRef.current = point;
|
|
22
36
|
}, []);
|
|
37
|
+
const startKeyboardDrag = useCallback((id, label) => {
|
|
38
|
+
setKeyboardDragId(id);
|
|
39
|
+
setKeyboardDragLabel(label);
|
|
40
|
+
}, []);
|
|
41
|
+
const endKeyboardDrag = useCallback(() => {
|
|
42
|
+
setKeyboardDragId(null);
|
|
43
|
+
setKeyboardDragLabel('');
|
|
44
|
+
}, []);
|
|
45
|
+
const announce = useCallback((message) => {
|
|
46
|
+
// Briefly clear then set to guarantee re-announcement of the same string
|
|
47
|
+
setAnnouncement('');
|
|
48
|
+
// Use a microtask so the DOM sees the empty value first
|
|
49
|
+
setTimeout(() => setAnnouncement(message), 0);
|
|
50
|
+
}, []);
|
|
23
51
|
const contextValue = useMemo(() => ({
|
|
24
52
|
activeDrag,
|
|
25
53
|
setActiveDrag,
|
|
@@ -29,8 +57,24 @@ const DragDropProvider = React__default.forwardRef(({ children }, ref) => {
|
|
|
29
57
|
registerDropZone,
|
|
30
58
|
unregisterDropZone,
|
|
31
59
|
dropZones: dropZones.current,
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
keyboardDragId,
|
|
61
|
+
keyboardDragLabel,
|
|
62
|
+
startKeyboardDrag,
|
|
63
|
+
endKeyboardDrag,
|
|
64
|
+
dropZoneOrder,
|
|
65
|
+
announce,
|
|
66
|
+
}), [
|
|
67
|
+
activeDrag,
|
|
68
|
+
setPointer,
|
|
69
|
+
registerDropZone,
|
|
70
|
+
unregisterDropZone,
|
|
71
|
+
keyboardDragId,
|
|
72
|
+
keyboardDragLabel,
|
|
73
|
+
startKeyboardDrag,
|
|
74
|
+
endKeyboardDrag,
|
|
75
|
+
announce,
|
|
76
|
+
]);
|
|
77
|
+
return (jsxs(DragDropContext.Provider, { value: contextValue, children: [children, jsx("div", { className: "sr-only", "aria-live": "assertive", "aria-atomic": "true", "aria-relevant": "additions text", children: announcement })] }));
|
|
34
78
|
});
|
|
35
79
|
DragDropProvider.displayName = 'DragDropProvider';
|
|
36
80
|
const useDragDropContext = () => {
|
|
@@ -40,7 +84,10 @@ const useDragDropContext = () => {
|
|
|
40
84
|
}
|
|
41
85
|
return context;
|
|
42
86
|
};
|
|
43
|
-
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Draggable
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
const Draggable = React__default.forwardRef(({ children, dragData, dragLabel, className, theme: customTheme = {}, onDragStart, onDrag, onDragEnd, disabled = false, }, ref) => {
|
|
44
91
|
var _a;
|
|
45
92
|
const context = useDragDropContext();
|
|
46
93
|
const dragRef = useRef(null);
|
|
@@ -48,6 +95,9 @@ const Draggable = React__default.forwardRef(({ children, dragData, className, th
|
|
|
48
95
|
...dragDropTheme,
|
|
49
96
|
...customTheme,
|
|
50
97
|
};
|
|
98
|
+
// Resolve the human-readable label used in announcements
|
|
99
|
+
const resolvedLabel = dragLabel !== null && dragLabel !== void 0 ? dragLabel : dragData.id;
|
|
100
|
+
// ----- pointer drag handlers (unchanged) --------------------------------
|
|
51
101
|
const handleDragStart = useCallback((_event, info) => {
|
|
52
102
|
if (disabled)
|
|
53
103
|
return;
|
|
@@ -73,7 +123,7 @@ const Draggable = React__default.forwardRef(({ children, dragData, className, th
|
|
|
73
123
|
point.y <= dropRect.bottom) {
|
|
74
124
|
const dropEvent = new CustomEvent('motion-drop', {
|
|
75
125
|
detail: dragData,
|
|
76
|
-
bubbles: true
|
|
126
|
+
bubbles: true,
|
|
77
127
|
});
|
|
78
128
|
dropZone.dispatchEvent(dropEvent);
|
|
79
129
|
}
|
|
@@ -82,7 +132,58 @@ const Draggable = React__default.forwardRef(({ children, dragData, className, th
|
|
|
82
132
|
context.setPointer(null);
|
|
83
133
|
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(dragData, info);
|
|
84
134
|
}, [dragData, onDragEnd, context]);
|
|
85
|
-
|
|
135
|
+
// ----- keyboard drag handler (new) --------------------------------------
|
|
136
|
+
const handleKeyDown = useCallback((e) => {
|
|
137
|
+
var _a, _b, _c;
|
|
138
|
+
if (disabled)
|
|
139
|
+
return;
|
|
140
|
+
const isGrabbed = context.keyboardDragId === dragData.id;
|
|
141
|
+
if ((e.key === ' ' || e.key === 'Enter') && !isGrabbed) {
|
|
142
|
+
// Initiate keyboard drag
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
context.startKeyboardDrag(dragData.id, resolvedLabel);
|
|
145
|
+
context.announce(`Grabbed ${resolvedLabel}. Use arrow keys to move between drop zones. Press Space or Enter to drop, or Escape to cancel.`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (isGrabbed) {
|
|
149
|
+
if (e.key === 'Escape') {
|
|
150
|
+
// Cancel keyboard drag
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
context.endKeyboardDrag();
|
|
153
|
+
context.announce(`Drop cancelled. ${resolvedLabel} returned to original position.`);
|
|
154
|
+
// Return focus to this draggable
|
|
155
|
+
(_a = dragRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
const order = context.dropZoneOrder.current;
|
|
161
|
+
if (order.length === 0)
|
|
162
|
+
return;
|
|
163
|
+
// Find the currently focused drop zone, advance to next
|
|
164
|
+
const focusedDropId = (_b = document.activeElement) === null || _b === void 0 ? void 0 : _b.getAttribute('data-dropzone-id');
|
|
165
|
+
const currentIdx = focusedDropId ? order.indexOf(focusedDropId) : -1;
|
|
166
|
+
const nextIdx = (currentIdx + 1) % order.length;
|
|
167
|
+
const nextEl = context.dropZones.get(order[nextIdx]);
|
|
168
|
+
nextEl === null || nextEl === void 0 ? void 0 : nextEl.focus();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
const order = context.dropZoneOrder.current;
|
|
174
|
+
if (order.length === 0)
|
|
175
|
+
return;
|
|
176
|
+
const focusedDropId = (_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.getAttribute('data-dropzone-id');
|
|
177
|
+
const currentIdx = focusedDropId ? order.indexOf(focusedDropId) : 0;
|
|
178
|
+
const prevIdx = (currentIdx - 1 + order.length) % order.length;
|
|
179
|
+
const prevEl = context.dropZones.get(order[prevIdx]);
|
|
180
|
+
prevEl === null || prevEl === void 0 ? void 0 : prevEl.focus();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}, [disabled, context, dragData.id, resolvedLabel]);
|
|
185
|
+
const isPointerDragging = ((_a = context.activeDrag) === null || _a === void 0 ? void 0 : _a.id) === dragData.id;
|
|
186
|
+
const isKeyboardGrabbed = context.keyboardDragId === dragData.id;
|
|
86
187
|
return (jsx(motion.div, { ref: (node) => {
|
|
87
188
|
dragRef.current = node;
|
|
88
189
|
if (typeof ref === 'function') {
|
|
@@ -104,12 +205,21 @@ const Draggable = React__default.forwardRef(({ children, dragData, className, th
|
|
|
104
205
|
x: { type: 'spring', stiffness: 1000, damping: 50 },
|
|
105
206
|
y: { type: 'spring', stiffness: 1000, damping: 50 },
|
|
106
207
|
}, style: {
|
|
107
|
-
position:
|
|
108
|
-
zIndex:
|
|
109
|
-
isolation:
|
|
110
|
-
|
|
208
|
+
position: 'relative',
|
|
209
|
+
zIndex: isPointerDragging ? 99999 : 'auto',
|
|
210
|
+
isolation: isPointerDragging ? 'isolate' : 'auto',
|
|
211
|
+
outline: isKeyboardGrabbed ? '2px solid var(--color-primary)' : undefined,
|
|
212
|
+
outlineOffset: isKeyboardGrabbed ? '2px' : undefined,
|
|
213
|
+
}, className: cn(theme.draggableStyle, disabled && 'opacity-50 cursor-not-allowed', !disabled && 'cursor-grab active:cursor-grabbing', isPointerDragging && '[&]:!z-[99999]', className),
|
|
214
|
+
// Pointer drag callbacks
|
|
215
|
+
onDragStart: handleDragStart, onDrag: handleDrag, onDragEnd: handleDragEnd,
|
|
216
|
+
// Keyboard accessibility
|
|
217
|
+
role: "button", tabIndex: disabled ? -1 : 0, "aria-label": `Drag ${resolvedLabel}`, "aria-grabbed": isKeyboardGrabbed, onKeyDown: handleKeyDown, children: children }));
|
|
111
218
|
});
|
|
112
219
|
Draggable.displayName = 'Draggable';
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// Droppable
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
113
223
|
const Droppable = React__default.forwardRef(({ children, acceptedTypes, className, theme: customTheme = {}, onDrop, onDragEnter, onDragLeave, id, }, ref) => {
|
|
114
224
|
const context = useDragDropContext();
|
|
115
225
|
const [isDragOver, setIsDragOver] = useState(false);
|
|
@@ -120,7 +230,9 @@ const Droppable = React__default.forwardRef(({ children, acceptedTypes, classNam
|
|
|
120
230
|
...dragDropTheme,
|
|
121
231
|
...customTheme,
|
|
122
232
|
};
|
|
123
|
-
//
|
|
233
|
+
// Whether a keyboard drag is currently active (any item grabbed)
|
|
234
|
+
const isKeyboardDragActive = context.keyboardDragId !== null;
|
|
235
|
+
// ----- registration (unchanged) -----------------------------------------
|
|
124
236
|
useEffect(() => {
|
|
125
237
|
if (dropRef.current) {
|
|
126
238
|
context.registerDropZone(stableId, dropRef.current);
|
|
@@ -129,7 +241,7 @@ const Droppable = React__default.forwardRef(({ children, acceptedTypes, classNam
|
|
|
129
241
|
context.unregisterDropZone(stableId);
|
|
130
242
|
};
|
|
131
243
|
}, [stableId, context]);
|
|
132
|
-
//
|
|
244
|
+
// ----- pointer drag-over detection (unchanged) --------------------------
|
|
133
245
|
useEffect(() => {
|
|
134
246
|
if (!context.activeDrag) {
|
|
135
247
|
if (isDragOver) {
|
|
@@ -173,12 +285,11 @@ const Droppable = React__default.forwardRef(({ children, acceptedTypes, classNam
|
|
|
173
285
|
cancelAnimationFrame(rafIdRef.current);
|
|
174
286
|
};
|
|
175
287
|
}, [acceptedTypes, isDragOver, onDragEnter, onDragLeave, context.activeDrag]);
|
|
176
|
-
//
|
|
288
|
+
// ----- pointer drop handler (unchanged) ---------------------------------
|
|
177
289
|
useEffect(() => {
|
|
178
290
|
const handleDrop = (event) => {
|
|
179
291
|
const customEvent = event;
|
|
180
292
|
const data = customEvent.detail;
|
|
181
|
-
// Check if type is accepted
|
|
182
293
|
if (acceptedTypes && acceptedTypes.length > 0) {
|
|
183
294
|
if (!acceptedTypes.includes(data.type || '')) {
|
|
184
295
|
return;
|
|
@@ -197,6 +308,46 @@ const Droppable = React__default.forwardRef(({ children, acceptedTypes, classNam
|
|
|
197
308
|
}
|
|
198
309
|
};
|
|
199
310
|
}, [acceptedTypes, onDrop]);
|
|
311
|
+
// ----- keyboard: announce when this zone receives focus -----------------
|
|
312
|
+
const handleFocus = useCallback(() => {
|
|
313
|
+
if (!isKeyboardDragActive)
|
|
314
|
+
return;
|
|
315
|
+
const order = context.dropZoneOrder.current;
|
|
316
|
+
const zoneIndex = order.indexOf(stableId);
|
|
317
|
+
const zoneNumber = zoneIndex === -1 ? '' : ` ${zoneIndex + 1}`;
|
|
318
|
+
context.announce(`Over drop zone${zoneNumber}.`);
|
|
319
|
+
}, [isKeyboardDragActive, context, stableId]);
|
|
320
|
+
// ----- keyboard: Space/Enter completes the drop -------------------------
|
|
321
|
+
const handleKeyDown = useCallback((e) => {
|
|
322
|
+
if (!isKeyboardDragActive)
|
|
323
|
+
return;
|
|
324
|
+
if (e.key !== ' ' && e.key !== 'Enter')
|
|
325
|
+
return;
|
|
326
|
+
e.preventDefault();
|
|
327
|
+
const grabbedId = context.keyboardDragId;
|
|
328
|
+
const grabbedLabel = context.keyboardDragLabel;
|
|
329
|
+
if (!grabbedId)
|
|
330
|
+
return;
|
|
331
|
+
// Check type acceptance
|
|
332
|
+
const draggedDragData = { id: grabbedId };
|
|
333
|
+
if (acceptedTypes && acceptedTypes.length > 0) ;
|
|
334
|
+
const order = context.dropZoneOrder.current;
|
|
335
|
+
const zoneIndex = order.indexOf(stableId);
|
|
336
|
+
const zoneNumber = zoneIndex === -1 ? '' : ` ${zoneIndex + 1}`;
|
|
337
|
+
// Fire the drop callback
|
|
338
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(draggedDragData);
|
|
339
|
+
// Also fire as a custom event so compound setups with `motion-drop`
|
|
340
|
+
// listeners on the DOM element are notified
|
|
341
|
+
if (dropRef.current) {
|
|
342
|
+
const dropEvent = new CustomEvent('motion-drop', {
|
|
343
|
+
detail: draggedDragData,
|
|
344
|
+
bubbles: true,
|
|
345
|
+
});
|
|
346
|
+
dropRef.current.dispatchEvent(dropEvent);
|
|
347
|
+
}
|
|
348
|
+
context.announce(`${grabbedLabel} dropped in position${zoneNumber}.`);
|
|
349
|
+
context.endKeyboardDrag();
|
|
350
|
+
}, [isKeyboardDragActive, context, stableId, acceptedTypes, onDrop]);
|
|
200
351
|
return (jsx(motion.div, { ref: (node) => {
|
|
201
352
|
dropRef.current = node;
|
|
202
353
|
if (typeof ref === 'function') {
|
|
@@ -210,8 +361,10 @@ const Droppable = React__default.forwardRef(({ children, acceptedTypes, classNam
|
|
|
210
361
|
zIndex: 0,
|
|
211
362
|
}, className: cn(theme.droppableStyle, isDragOver && theme.dragOverStyle, className), animate: isDragOver ? 'dragOver' : 'idle', variants: {
|
|
212
363
|
idle: { scale: 1 },
|
|
213
|
-
dragOver: { scale: 1.01 }
|
|
214
|
-
}, transition: { duration: 0.15 },
|
|
364
|
+
dragOver: { scale: 1.01 },
|
|
365
|
+
}, transition: { duration: 0.15 },
|
|
366
|
+
// Keyboard accessibility: become reachable only while a keyboard drag is active
|
|
367
|
+
tabIndex: isKeyboardDragActive ? 0 : undefined, role: isKeyboardDragActive ? 'button' : undefined, "aria-label": isKeyboardDragActive ? 'Drop here' : undefined, "data-dropzone-id": stableId, onFocus: handleFocus, onKeyDown: handleKeyDown, children: typeof children === 'function' ? children(isDragOver) : children }));
|
|
215
368
|
});
|
|
216
369
|
Droppable.displayName = 'Droppable';
|
|
217
370
|
|
|
@@ -34,6 +34,12 @@ export interface DraggableProps {
|
|
|
34
34
|
onDragEnd?: (data: DragData, info: PanInfo) => void;
|
|
35
35
|
/** Disable dragging */
|
|
36
36
|
disabled?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Accessible label used in keyboard-drag announcements.
|
|
39
|
+
* Defaults to the dragData.id when omitted.
|
|
40
|
+
* Example: "Task card – Fix login bug"
|
|
41
|
+
*/
|
|
42
|
+
dragLabel?: string;
|
|
37
43
|
}
|
|
38
44
|
export interface DroppableProps {
|
|
39
45
|
/** Content of the drop zone */
|
|
@@ -9,7 +9,7 @@ export declare const Drawer: {
|
|
|
9
9
|
displayName: string;
|
|
10
10
|
};
|
|
11
11
|
Title: {
|
|
12
|
-
({ children, className, ...props }: import("./Drawer.types").DrawerTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
({ children, className, as: Tag, ...props }: import("./Drawer.types").DrawerTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
displayName: string;
|
|
14
14
|
};
|
|
15
15
|
Subtitle: {
|
|
@@ -17,6 +17,8 @@ function useCloseOnBack(isOpen, onClose, enabled) {
|
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
if (!enabled || !isOpen)
|
|
19
19
|
return;
|
|
20
|
+
if (typeof window === "undefined")
|
|
21
|
+
return;
|
|
20
22
|
closedByPopstate.current = false;
|
|
21
23
|
history.pushState({ flikDrawer: true }, "");
|
|
22
24
|
const handlePopstate = () => {
|
|
@@ -78,6 +78,8 @@ export interface DrawerHeaderProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
78
78
|
export interface DrawerTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
|
|
79
79
|
children: React.ReactNode;
|
|
80
80
|
className?: string;
|
|
81
|
+
/** Heading level to render. Defaults to 'h2'. */
|
|
82
|
+
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
81
83
|
}
|
|
82
84
|
export interface DrawerSubtitleProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
83
85
|
children: React.ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DrawerTitleProps } from "./Drawer.types";
|
|
2
2
|
export declare const DrawerTitle: {
|
|
3
|
-
({ children, className, ...props }: DrawerTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
({ children, className, as: Tag, ...props }: DrawerTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
displayName: string;
|
|
5
5
|
};
|
|
@@ -2,9 +2,9 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { cn } from '../../../utils/cn.js';
|
|
3
3
|
import { useDrawerContext } from './Drawer.js';
|
|
4
4
|
|
|
5
|
-
const DrawerTitle = ({ children, className, ...props }) => {
|
|
5
|
+
const DrawerTitle = ({ children, className, as: Tag = 'h2', ...props }) => {
|
|
6
6
|
const { theme, titleId } = useDrawerContext();
|
|
7
|
-
return (jsx(
|
|
7
|
+
return (jsx(Tag, { id: titleId, className: cn(theme.title, className), ...props, children: children }));
|
|
8
8
|
};
|
|
9
9
|
DrawerTitle.displayName = "Drawer.Title";
|
|
10
10
|
|
|
@@ -7,36 +7,8 @@ import { useDropdownContext } from './DropdownContext.js';
|
|
|
7
7
|
import { useClickOutside } from '../../../hooks/useClickOutside.js';
|
|
8
8
|
import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
|
|
9
9
|
import { useIsClient } from '../../../hooks/useIsClient.js';
|
|
10
|
+
import { useDarkMode } from '../../../hooks/useDarkMode.js';
|
|
10
11
|
|
|
11
|
-
/**
|
|
12
|
-
* Hook to detect dark mode state from document
|
|
13
|
-
*/
|
|
14
|
-
const useDarkMode = () => {
|
|
15
|
-
const [isDark, setIsDark] = useState(false);
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (typeof document === "undefined")
|
|
18
|
-
return;
|
|
19
|
-
const checkDarkMode = () => {
|
|
20
|
-
const hasDarkClass = document.documentElement.classList.contains("dark") ||
|
|
21
|
-
document.body.classList.contains("dark") ||
|
|
22
|
-
document.querySelector(".dark") !== null;
|
|
23
|
-
setIsDark(hasDarkClass);
|
|
24
|
-
};
|
|
25
|
-
checkDarkMode();
|
|
26
|
-
// Observe class changes on html and body
|
|
27
|
-
const observer = new MutationObserver(checkDarkMode);
|
|
28
|
-
observer.observe(document.documentElement, {
|
|
29
|
-
attributes: true,
|
|
30
|
-
attributeFilter: ["class"],
|
|
31
|
-
});
|
|
32
|
-
observer.observe(document.body, {
|
|
33
|
-
attributes: true,
|
|
34
|
-
attributeFilter: ["class"],
|
|
35
|
-
});
|
|
36
|
-
return () => observer.disconnect();
|
|
37
|
-
}, []);
|
|
38
|
-
return isDark;
|
|
39
|
-
};
|
|
40
12
|
/**
|
|
41
13
|
* DropdownMenu component - renders the menu with keyboard navigation
|
|
42
14
|
*/
|
|
@@ -208,7 +180,7 @@ const DropdownMenu = React__default.forwardRef(({ children, className, animation
|
|
|
208
180
|
...cssVariables,
|
|
209
181
|
top: `${position.top}px`,
|
|
210
182
|
left: `${position.left}px`,
|
|
211
|
-
}, id: menuId, role: "menu", "aria-label": ariaLabel ||
|
|
183
|
+
}, id: menuId, role: "menu", "aria-label": ariaLabel || undefined, "aria-orientation": horizontal ? "horizontal" : "vertical", tabIndex: -1, onKeyDown: handleKeyDown, variants: shouldReduceMotion || !animation ? {} : menuVariants, initial: shouldReduceMotion || !animation ? undefined : "hidden", animate: shouldReduceMotion || !animation ? undefined : "visible", exit: shouldReduceMotion || !animation ? undefined : "exit", transition: shouldReduceMotion || !animation
|
|
212
184
|
? { duration: 0 }
|
|
213
185
|
: {
|
|
214
186
|
type: "spring",
|
|
@@ -5,7 +5,7 @@ const emptyTheme = {
|
|
|
5
5
|
// Base container styles - customizable spacing, colors, and layout
|
|
6
6
|
baseStyle: "flex flex-col items-center justify-center text-center w-full max-w-md mx-auto space-y-3 py-12 px-6 ",
|
|
7
7
|
// Title text styles - customizable typography and colors
|
|
8
|
-
titleStyle: "text-
|
|
8
|
+
titleStyle: "text-sm font-semibold text-[var(--color-text-primary)]",
|
|
9
9
|
// Description text styles - customizable typography and colors
|
|
10
10
|
subtitleStyle: "text-sm text-[var(--color-text-muted)]",
|
|
11
11
|
};
|
|
@@ -35,7 +35,7 @@ onAnimationStart: _onAnimationStart, onAnimationEnd: _onAnimationEnd, onDrag: _o
|
|
|
35
35
|
}, [shouldReduceMotion]);
|
|
36
36
|
return (jsx(motion.a, { ref: ref, href: disabled ? undefined : href, className: cn(buttonTheme.baseStyle, themeClasses.colorClasses, themeClasses.variantClasses, themeClasses.sizeClasses, themeClasses.stateClasses,
|
|
37
37
|
// Special case for link variant to have an underline
|
|
38
|
-
"underline underline-offset-4 rounded-none font-semibold", className), "data-color": color, "data-variant": resolvedVariant, "data-size": size, "aria-disabled": disabled || undefined, ...(disabled ? {} : animationProps), ...props, children: children }));
|
|
38
|
+
"underline underline-offset-4 rounded-none font-semibold text-sm", className), "data-color": color, "data-variant": resolvedVariant, "data-size": size, "aria-disabled": disabled || undefined, ...(disabled ? {} : animationProps), ...props, children: children }));
|
|
39
39
|
});
|
|
40
40
|
Link.displayName = "Link";
|
|
41
41
|
|
|
@@ -13,6 +13,7 @@ const MASONRY_ITEM_TRANSITION_BASE = {
|
|
|
13
13
|
};
|
|
14
14
|
const Masonry = React__default.forwardRef(({ children, columns = 3, gap = 16, gapBreakpoints, className, style, minColumns = 1, maxColumns = 10, sequential = false, themeOverrides, loading = false, ...props }, ref) => {
|
|
15
15
|
const containerRef = useRef(null);
|
|
16
|
+
const arrangeItemsRef = useRef(() => { });
|
|
16
17
|
const [currentColumns, setCurrentColumns] = useState(typeof columns === 'number' ? columns : 3);
|
|
17
18
|
const [currentGap, setCurrentGap] = useState(gap);
|
|
18
19
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
@@ -174,6 +175,10 @@ const Masonry = React__default.forwardRef(({ children, columns = 3, gap = 16, ga
|
|
|
174
175
|
}, 0);
|
|
175
176
|
return () => clearTimeout(timer);
|
|
176
177
|
}, [calculateLayout, arrangeItems, children, containerWidth]);
|
|
178
|
+
// Keep ref in sync so the MutationObserver always calls the latest version
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
arrangeItemsRef.current = arrangeItems;
|
|
181
|
+
}, [arrangeItems]);
|
|
177
182
|
// Re-arrange when children change (with debouncing)
|
|
178
183
|
useEffect(() => {
|
|
179
184
|
let timeoutId;
|
|
@@ -181,7 +186,7 @@ const Masonry = React__default.forwardRef(({ children, columns = 3, gap = 16, ga
|
|
|
181
186
|
// Debounce multiple rapid changes
|
|
182
187
|
clearTimeout(timeoutId);
|
|
183
188
|
timeoutId = setTimeout(() => {
|
|
184
|
-
|
|
189
|
+
arrangeItemsRef.current();
|
|
185
190
|
}, 10);
|
|
186
191
|
});
|
|
187
192
|
if (containerRef.current) {
|
|
@@ -194,7 +199,7 @@ const Masonry = React__default.forwardRef(({ children, columns = 3, gap = 16, ga
|
|
|
194
199
|
observer.disconnect();
|
|
195
200
|
clearTimeout(timeoutId);
|
|
196
201
|
};
|
|
197
|
-
}, [
|
|
202
|
+
}, []);
|
|
198
203
|
// Generate container classes
|
|
199
204
|
const containerClasses = cn(theme.container.base, loading && theme.container.loading, className);
|
|
200
205
|
// Wrap each child in a positioning div with theme styles
|
|
@@ -11,7 +11,7 @@ export declare const Modal: {
|
|
|
11
11
|
displayName: string;
|
|
12
12
|
};
|
|
13
13
|
Title: {
|
|
14
|
-
({ children, className, ...props }: import("./Modal.types").ModalTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
({ children, className, as: Tag, ...props }: import("./Modal.types").ModalTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
15
15
|
displayName: string;
|
|
16
16
|
};
|
|
17
17
|
Subtitle: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext, useId, useState, useEffect, useContext } from 'react';
|
|
2
|
+
import { createContext, useId, useState, useEffect, useMemo, useContext } from 'react';
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
4
|
import { Overlay } from '../../effects/Overlay/Overlay.js';
|
|
5
5
|
import { modalTheme, modalSizeVariants } from './Modal.theme.js';
|
|
@@ -45,7 +45,7 @@ const ModalRoot = ({ isOpen, onClose, size = "md", variant = "default", closeOnO
|
|
|
45
45
|
},
|
|
46
46
|
};
|
|
47
47
|
// Context value
|
|
48
|
-
const contextValue = {
|
|
48
|
+
const contextValue = useMemo(() => ({
|
|
49
49
|
isOpen,
|
|
50
50
|
onClose,
|
|
51
51
|
size,
|
|
@@ -58,7 +58,7 @@ const ModalRoot = ({ isOpen, onClose, size = "md", variant = "default", closeOnO
|
|
|
58
58
|
setIsBodyScrollable,
|
|
59
59
|
titleId,
|
|
60
60
|
subtitleId,
|
|
61
|
-
};
|
|
61
|
+
}), [isOpen, onClose, size, isSizeToken, closeOnOverlayClick, closeOnEsc, showCloseButton, theme, isBodyScrollable, setIsBodyScrollable, titleId, subtitleId]);
|
|
62
62
|
return (jsx(Overlay, { isOpen: isOpen, onClose: onClose, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, position: "center", role: role, ariaModal: true, ariaLabelledBy: titleId, ariaDescribedBy: subtitleId, contentClassName: cn(theme.container, (_a = theme.containerVariants) === null || _a === void 0 ? void 0 : _a[variant], isSizeToken ? modalSizeVariants[size] : size, className), animations: {
|
|
63
63
|
overlay: modalOverlayAnimations,
|
|
64
64
|
content: modalContentAnimations,
|
|
@@ -89,6 +89,8 @@ export interface ModalFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
89
89
|
export interface ModalTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
|
|
90
90
|
children: React.ReactNode;
|
|
91
91
|
className?: string;
|
|
92
|
+
/** Heading level to render. Defaults to 'h2'. */
|
|
93
|
+
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
92
94
|
}
|
|
93
95
|
export interface ModalSubtitleProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
94
96
|
children: React.ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ModalTitleProps } from "./Modal.types";
|
|
2
2
|
export declare const ModalTitle: {
|
|
3
|
-
({ children, className, ...props }: ModalTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
({ children, className, as: Tag, ...props }: ModalTitleProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
displayName: string;
|
|
5
5
|
};
|
|
@@ -2,9 +2,9 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { cn } from '../../../utils/cn.js';
|
|
3
3
|
import { useModalContext } from './Modal.js';
|
|
4
4
|
|
|
5
|
-
const ModalTitle = ({ children, className, ...props }) => {
|
|
5
|
+
const ModalTitle = ({ children, className, as: Tag = 'h2', ...props }) => {
|
|
6
6
|
const { theme, titleId } = useModalContext();
|
|
7
|
-
return (jsx(
|
|
7
|
+
return (jsx(Tag, { id: titleId, className: cn(theme.title, className), ...props, children: children }));
|
|
8
8
|
};
|
|
9
9
|
ModalTitle.displayName = "Modal.Title";
|
|
10
10
|
|
|
@@ -145,16 +145,21 @@ notification, description, shortcut, href, onClick, active = false, disabled = f
|
|
|
145
145
|
? React__default.cloneElement(startContent, {
|
|
146
146
|
className: cn(iconClasses, startContent.props.className),
|
|
147
147
|
})
|
|
148
|
-
: startContent, isCollapsedView && notificationElement && (jsx("span", { className: "absolute -top-1 -right-1", children: notificationElement }))] })),
|
|
149
|
-
|
|
150
|
-
|
|
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',
|
|
151
153
|
opacity: isCollapsedView ? 0 : 1,
|
|
152
|
-
transition:
|
|
153
|
-
}, 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 }))] }),
|
|
154
|
-
|
|
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,
|
|
155
160
|
opacity: isCollapsedView ? 0 : 1,
|
|
156
|
-
transition:
|
|
157
|
-
}, children: [notificationElement, endContent, chevron] }), isCollapsedView && (jsx("span", { className: "sr-only", children: children }))] }));
|
|
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 }))] }));
|
|
158
163
|
// Self-contained submenu
|
|
159
164
|
const submenu = hasSubmenu && items && items.length > 0 && !isCollapsedView ? (jsx(AnimatePresence, { initial: false, children: isExpanded && (jsx(motion.div, { initial: "collapsed", animate: "open", exit: "collapsed", variants: {
|
|
160
165
|
open: { opacity: 1, height: "auto" },
|
|
@@ -79,7 +79,7 @@ const Pagination = React__default.forwardRef(({ currentPage, totalPages, onPageC
|
|
|
79
79
|
const isLastPage = currentPage === totalPages;
|
|
80
80
|
return (jsxs("nav", { ref: ref, role: "navigation", "aria-label": "Pagination Navigation", className: cn(theme.baseStyle, className), ...props, children: [showFirstLast && (jsxs(PaginationItem, { size: size, isDisabled: isFirstPage, onClick: () => handlePageChange(1), "aria-label": "Go to first page", children: [jsx(ChevronDoubleLeftIcon, { className: "w-4 h-4" }), jsx("span", { className: "sr-only", children: "First" })] })), showPrevNext && (jsxs(PaginationItem, { size: size, isDisabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "aria-label": `Go to previous page (${currentPage - 1})`, children: [jsx(ChevronLeftIcon, { className: "w-4 h-4" }), jsx("span", { className: "sr-only", children: "Previous" })] })), paginationRange.map((pageNumber, index) => {
|
|
81
81
|
if (pageNumber === "...") {
|
|
82
|
-
return (
|
|
82
|
+
return (jsx("span", { role: "separator", "aria-hidden": "true", children: "\u2026" }, `ellipsis-${index}`));
|
|
83
83
|
}
|
|
84
84
|
const page = pageNumber;
|
|
85
85
|
const isActive = page === currentPage;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import React__default, { useRef, useEffect, useCallback
|
|
2
|
+
import React__default, { useRef, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useReducedMotion, AnimatePresence, motion } from 'motion/react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
5
|
import { cn } from '../../../utils/cn.js';
|
|
@@ -9,6 +9,7 @@ import { popoverTransitions, popoverContentVariants } from './Popover.animations
|
|
|
9
9
|
import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
|
|
10
10
|
import { Overlay } from '../../effects/Overlay/Overlay.js';
|
|
11
11
|
import { useIsClient } from '../../../hooks/useIsClient.js';
|
|
12
|
+
import { useDarkMode } from '../../../hooks/useDarkMode.js';
|
|
12
13
|
|
|
13
14
|
/** Overlay backdrop animations (fade in/out) */
|
|
14
15
|
const overlayBackdropAnimations = {
|
|
@@ -22,31 +23,6 @@ const overlayContentAnimations = {
|
|
|
22
23
|
animate: { opacity: 1, scale: 1, transition: { duration: 0.2 } },
|
|
23
24
|
exit: { opacity: 0, scale: 0.95, transition: { duration: 0.15 } },
|
|
24
25
|
};
|
|
25
|
-
const useDarkMode = () => {
|
|
26
|
-
const [isDark, setIsDark] = useState(false);
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (typeof document === "undefined")
|
|
29
|
-
return;
|
|
30
|
-
const checkDarkMode = () => {
|
|
31
|
-
const hasDarkClass = document.documentElement.classList.contains("dark") ||
|
|
32
|
-
document.body.classList.contains("dark") ||
|
|
33
|
-
document.querySelector(".dark") !== null;
|
|
34
|
-
setIsDark(hasDarkClass);
|
|
35
|
-
};
|
|
36
|
-
checkDarkMode();
|
|
37
|
-
const observer = new MutationObserver(checkDarkMode);
|
|
38
|
-
observer.observe(document.documentElement, {
|
|
39
|
-
attributes: true,
|
|
40
|
-
attributeFilter: ["class"],
|
|
41
|
-
});
|
|
42
|
-
observer.observe(document.body, {
|
|
43
|
-
attributes: true,
|
|
44
|
-
attributeFilter: ["class"],
|
|
45
|
-
});
|
|
46
|
-
return () => observer.disconnect();
|
|
47
|
-
}, []);
|
|
48
|
-
return isDark;
|
|
49
|
-
};
|
|
50
26
|
/**
|
|
51
27
|
* PopoverBody component displays the body/content of the popover
|
|
52
28
|
*/
|
|
@@ -140,7 +116,7 @@ const PopoverBody = React__default.forwardRef(({ children, className, animation
|
|
|
140
116
|
: undefined, children: jsx("div", { id: contentId, "data-state": isOpen ? "open" : "closed", "data-placement": placement, "data-trigger": triggerType, ...domProps, children: children }) }));
|
|
141
117
|
}
|
|
142
118
|
// Without backdrop: manual portal + positioning + escape + click-outside
|
|
143
|
-
const popoverContent = (jsx(AnimatePresence, { children: isOpen && (jsx(motion.div, { ref: handleRef, id: contentId, className: cn("fixed z-50", contentClasses), style: contentPositionStyle,
|
|
119
|
+
const popoverContent = (jsx(AnimatePresence, { children: isOpen && (jsx(motion.div, { ref: handleRef, id: contentId, className: cn("fixed z-50", contentClasses), style: contentPositionStyle, variants: shouldReduceMotion || !animation ? {} : popoverContentVariants, initial: shouldReduceMotion || !animation ? undefined : "hidden", animate: shouldReduceMotion || !animation ? undefined : (isReady ? "visible" : "hidden"), exit: shouldReduceMotion || !animation ? undefined : "exit", transition: shouldReduceMotion || !animation
|
|
144
120
|
? { duration: 0 }
|
|
145
121
|
: popoverTransitions.content, "data-state": isOpen ? "open" : "closed", "data-placement": placement, "data-trigger": triggerType, onClick: (e) => e.stopPropagation(), ...domProps, children: children })) }));
|
|
146
122
|
if (portal && isClient) {
|