@flikk/ui 1.0.0-beta.14 → 1.0.0-beta.16
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/README.md +52 -0
- package/dist/components/ai/CodeBlock/CodeBlock.theme.js +1 -1
- package/dist/components/ai/PromptInput/PromptInput.js +3 -1
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +4 -4
- package/dist/components/ai/StreamingResponse/AnimatedText.js +3 -3
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +22 -22
- package/dist/components/ai/StreamingResponse/StreamingCursor.js +1 -1
- package/dist/components/ai/StreamingResponse/StreamingResponse.animations.js +10 -10
- package/dist/components/ai/StreamingResponse/StreamingResponse.js +9 -3
- package/dist/components/ai/StreamingResponse/WordAnimationContext.d.ts +1 -1
- package/dist/components/ai/StreamingResponse/WordAnimationContext.js +11 -11
- package/dist/components/ai/index.d.ts +0 -7
- package/dist/components/ai/index.js +8 -6
- package/dist/components/charts/DonutChart/DonutChart.js +1 -1
- package/dist/components/charts/DonutChart/MultiSegmentDonutChart.js +1 -1
- package/dist/components/charts/shared/ChartLegend/ChartLegend.types.d.ts +13 -1
- package/dist/components/charts/shared/ChartLegend/ChartLegendContent.js +1 -1
- package/dist/components/charts/shared/ChartTooltip/ChartTooltip.types.d.ts +13 -2
- package/dist/components/core/Accordion/AccordionItem.js +1 -1
- package/dist/components/core/Accordion/AccordionTrigger.js +1 -1
- package/dist/components/core/Alert/Alert.animations.d.ts +11 -0
- package/dist/components/core/Alert/Alert.animations.js +44 -0
- package/dist/components/core/Alert/Alert.js +16 -3
- package/dist/components/core/Avatar/Avatar.js +12 -7
- package/dist/components/core/Avatar/Avatar.theme.d.ts +4 -6
- package/dist/components/core/Avatar/Avatar.theme.js +22 -12
- package/dist/components/core/Avatar/Avatar.types.d.ts +9 -0
- package/dist/components/core/AvatarGroup/AvatarGroup.animations.js +2 -2
- package/dist/components/core/AvatarGroup/AvatarGroup.js +1 -2
- package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +1 -1
- package/dist/components/core/Badge/Badge.animations.js +1 -1
- package/dist/components/core/Badge/Badge.js +23 -47
- package/dist/components/core/Badge/Badge.theme.js +48 -62
- package/dist/components/core/Badge/Badge.types.d.ts +5 -29
- package/dist/components/core/Button/Button.js +2 -2
- package/dist/components/core/Button/Button.theme.js +2 -2
- package/dist/components/core/ButtonGroup/ButtonGroup.theme.js +6 -6
- package/dist/components/core/ButtonGroup/ButtonGroupText.js +1 -3
- package/dist/components/core/Calendar/Calendar.js +29 -3
- package/dist/components/core/Calendar/Calendar.theme.js +11 -7
- package/dist/components/core/Calendar/Calendar.types.d.ts +3 -0
- package/dist/components/core/Carousel/CarouselBody.js +0 -1
- package/dist/components/core/CommandPalette/CommandItem.js +1 -1
- package/dist/components/core/CommandPalette/CommandPalette.js +6 -4
- package/dist/components/core/CommandPalette/CommandPalette.theme.js +1 -0
- package/dist/components/core/CommandPalette/CommandPalette.types.d.ts +6 -0
- package/dist/components/core/ContextMenu/ContextMenu.js +5 -4
- package/dist/components/core/ContextMenu/ContextMenuTrigger.js +5 -6
- package/dist/components/core/Drawer/Drawer.d.ts +1 -1
- package/dist/components/core/Drawer/Drawer.js +25 -2
- package/dist/components/core/Drawer/Drawer.theme.js +2 -2
- package/dist/components/core/Drawer/Drawer.types.d.ts +6 -0
- package/dist/components/core/Dropdown/Dropdown.d.ts +1 -1
- package/dist/components/core/Dropdown/Dropdown.js +5 -1
- package/dist/components/core/Dropdown/Dropdown.types.d.ts +1 -0
- package/dist/components/core/Dropdown/DropdownItem.js +1 -1
- package/dist/components/core/Dropdown/DropdownMenu.js +4 -4
- package/dist/components/core/Dropdown/DropdownSection.js +1 -1
- package/dist/components/core/Dropdown/DropdownSeparator.js +1 -1
- package/dist/components/core/Dropdown/DropdownTrigger.d.ts +6 -1
- package/dist/components/core/Dropdown/DropdownTrigger.js +10 -8
- package/dist/components/core/Kbd/Kbd.theme.js +3 -3
- package/dist/components/core/Link/Link.js +3 -1
- package/dist/components/core/Message/Message.d.ts +9 -0
- package/dist/components/core/Message/Message.js +44 -3
- package/dist/components/core/Message/Message.theme.js +22 -0
- package/dist/components/core/Message/Message.types.d.ts +115 -0
- package/dist/components/core/Message/MessageAudio.d.ts +8 -0
- package/dist/components/core/Message/MessageAudio.js +11 -0
- package/dist/components/core/Message/MessageContext.d.ts +3 -1
- package/dist/components/core/Message/MessageDateDivider.d.ts +6 -0
- package/dist/components/core/Message/MessageDateDivider.js +10 -0
- package/dist/components/core/Message/MessageFile.d.ts +9 -0
- package/dist/components/core/Message/MessageFile.js +15 -0
- package/dist/components/core/Message/MessageImage.d.ts +11 -0
- package/dist/components/core/Message/MessageImage.js +13 -0
- package/dist/components/core/Message/MessageLink.d.ts +10 -0
- package/dist/components/core/Message/MessageLink.js +15 -0
- package/dist/components/core/Message/MessageReactions.d.ts +8 -0
- package/dist/components/core/Message/MessageReactions.js +12 -0
- package/dist/components/core/Message/MessageReply.d.ts +8 -0
- package/dist/components/core/Message/MessageReply.js +10 -0
- package/dist/components/core/Message/MessageSenderName.d.ts +6 -0
- package/dist/components/core/Message/MessageSenderName.js +10 -0
- package/dist/components/core/Message/MessageStatusIndicator.d.ts +9 -0
- package/dist/components/core/Message/MessageStatusIndicator.js +45 -0
- package/dist/components/core/Message/index.d.ts +19 -1
- package/dist/components/core/Modal/Modal.animations.d.ts +1 -0
- package/dist/components/core/Modal/Modal.animations.js +14 -11
- package/dist/components/core/Pagination/Pagination.theme.js +1 -1
- package/dist/components/core/Popover/Popover.d.ts +1 -1
- package/dist/components/core/Popover/PopoverBody.js +2 -2
- package/dist/components/core/Popover/PopoverTrigger.d.ts +1 -1
- package/dist/components/core/Popover/PopoverTrigger.js +11 -11
- package/dist/components/core/Progress/Progress.d.ts +9 -8
- package/dist/components/core/Progress/Progress.js +16 -16
- package/dist/components/core/Progress/Progress.theme.js +4 -15
- package/dist/components/core/Progress/Progress.types.d.ts +2 -20
- package/dist/components/core/Progress/index.d.ts +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +49 -7
- package/dist/components/core/ScrollArea/ScrollArea.types.d.ts +12 -3
- package/dist/components/core/ScrollArea/index.d.ts +1 -1
- package/dist/components/core/Segmented/SegmentedItem.js +1 -1
- package/dist/components/core/Sidebar/Sidebar.js +2 -1
- package/dist/components/core/Sidebar/SidebarMobileTrigger.js +2 -1
- package/dist/components/core/Sidebar/SidebarToggle.js +2 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.js +1 -1
- package/dist/components/core/SocialIcon/SocialIcon.js +1 -1
- package/dist/components/core/Sortable/Sortable.js +2 -2
- package/dist/components/core/Sortable/Sortable.theme.js +1 -1
- package/dist/components/core/Sortable/Sortable.types.d.ts +7 -5
- package/dist/components/core/Tabs/TabsBody.js +1 -1
- package/dist/components/core/Tabs/TabsTrigger.js +1 -1
- package/dist/components/core/Tag/Tag.js +2 -2
- package/dist/components/core/Toast/Toast.d.ts +2 -2
- package/dist/components/core/Toast/Toast.js +30 -21
- package/dist/components/core/Toast/Toast.theme.js +4 -9
- package/dist/components/core/Toast/Toast.types.d.ts +4 -21
- package/dist/components/core/Toast/index.d.ts +1 -1
- package/dist/components/core/Tooltip/Tooltip.js +1 -1
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
- package/dist/components/core/index.js +9 -0
- package/dist/components/data-display/GanttChart/GanttChart.types.d.ts +2 -2
- package/dist/components/data-display/Table/Table.types.d.ts +8 -8
- package/dist/components/effects/CustomCursor/CustomCursor.js +2 -2
- package/dist/components/effects/GlassSurface/GlassSurface.d.ts +1 -1
- package/dist/components/effects/GlassSurface/GlassSurface.js +17 -9
- package/dist/components/effects/GlassSurface/GlassSurface.types.d.ts +6 -0
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.animations.d.ts +39 -0
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.animations.js +98 -0
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.d.ts +3 -0
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +104 -0
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.types.d.ts +30 -0
- package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.d.ts +3 -0
- package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +36 -0
- package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.d.ts +3 -0
- package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +36 -0
- package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.d.ts +3 -0
- package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +37 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useBlink.d.ts +14 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useBlink.js +41 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useIdleAnimation.d.ts +25 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useIdleAnimation.js +84 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useMouseTracking.d.ts +18 -0
- package/dist/components/effects/InteractiveCharacters/hooks/useMouseTracking.js +35 -0
- package/dist/components/effects/InteractiveCharacters/index.d.ts +2 -0
- package/dist/components/effects/MorphingText/MorphingText.d.ts +1 -1
- package/dist/components/effects/MorphingText/MorphingText.js +6 -5
- package/dist/components/effects/Neumorphic/InsetCircleButton.d.ts +10 -0
- package/dist/components/effects/Neumorphic/InsetCircleButton.js +10 -0
- package/dist/components/effects/Neumorphic/InsetPill.d.ts +8 -0
- package/dist/components/effects/Neumorphic/InsetPill.js +7 -0
- package/dist/components/effects/Neumorphic/index.d.ts +4 -0
- package/dist/components/effects/NoiseOverlay/NoiseOverlay.d.ts +1 -1
- package/dist/components/effects/NoiseOverlay/NoiseOverlay.js +4 -4
- package/dist/components/effects/Overlay/Overlay.js +6 -4
- package/dist/components/effects/PageTransition/PageTransition.animations.d.ts +8 -0
- package/dist/components/effects/PageTransition/PageTransition.animations.js +53 -0
- package/dist/components/effects/PageTransition/PageTransition.d.ts +3 -0
- package/dist/components/effects/PageTransition/PageTransition.js +71 -0
- package/dist/components/effects/PageTransition/PageTransition.types.d.ts +15 -0
- package/dist/components/effects/PageTransition/index.d.ts +2 -0
- package/dist/components/effects/index.d.ts +6 -0
- package/dist/components/effects/index.js +4 -0
- package/dist/components/forms/Checkbox/Checkbox.animations.d.ts +14 -0
- package/dist/components/forms/Checkbox/Checkbox.animations.js +53 -0
- package/dist/components/forms/Checkbox/Checkbox.js +4 -2
- package/dist/components/forms/Checkbox/Checkbox.theme.js +3 -3
- package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerBody.js +3 -3
- package/dist/components/forms/Combobox/Combobox.js +5 -3
- package/dist/components/forms/DatePicker/DatePickerBody.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.animations.d.ts +1 -0
- package/dist/components/forms/DateRangePicker/DateRangePicker.d.ts +37 -0
- package/dist/components/forms/DateRangePicker/DateRangePicker.js +110 -0
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.d.ts +5 -0
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +52 -0
- package/dist/components/forms/DateRangePicker/DateRangePicker.types.d.ts +154 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerBody.d.ts +6 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerBody.js +208 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerPresets.d.ts +6 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerPresets.js +41 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.d.ts +6 -0
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +32 -0
- package/dist/components/forms/DateRangePicker/dateRangePresets.d.ts +5 -0
- package/dist/components/forms/DateRangePicker/dateRangePresets.js +59 -0
- package/dist/components/forms/DateRangePicker/index.d.ts +4 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.animations.d.ts +36 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.animations.js +22 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.d.ts +3 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.js +111 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.d.ts +19 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +27 -0
- package/dist/components/forms/FileUpload/FileUploadProgress.types.d.ts +33 -0
- package/dist/components/forms/FileUpload/index.d.ts +3 -0
- package/dist/components/forms/Input/Input.js +8 -13
- package/dist/components/forms/Input/Input.types.d.ts +6 -0
- package/dist/components/forms/InputAddress/InputAddress.theme.js +1 -1
- package/dist/components/forms/InputCounter/InputCounter.js +1 -1
- package/dist/components/forms/InputCreditCard/InputCreditCard.theme.js +1 -1
- package/dist/components/forms/InputOTP/InputOTP.theme.js +1 -1
- package/dist/components/forms/Radio/Radio.animations.d.ts +10 -0
- package/dist/components/forms/Radio/Radio.animations.js +33 -0
- package/dist/components/forms/Radio/Radio.js +11 -2
- package/dist/components/forms/Radio/Radio.theme.js +3 -3
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +13 -4
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +2 -2
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +11 -0
- package/dist/components/forms/Select/Select.d.ts +1 -1
- package/dist/components/forms/Select/Select.js +7 -7
- package/dist/components/forms/Select/Select.types.d.ts +3 -3
- package/dist/components/forms/SelectableCard/SelectableCard.js +1 -1
- package/dist/components/forms/Slider/Slider.js +10 -3
- package/dist/components/forms/Slider/Slider.theme.js +3 -3
- package/dist/components/forms/Switch/Switch.js +10 -2
- package/dist/components/forms/Switch/Switch.theme.js +3 -3
- package/dist/components/forms/forms.theme.js +1 -1
- package/dist/components/forms/index.d.ts +6 -3
- package/dist/components/forms/index.js +8 -2
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useMediaQuery.d.ts +5 -0
- package/dist/hooks/useMediaQuery.js +21 -0
- package/dist/index.js +21 -2
- package/dist/styles.css +1 -1
- package/dist/utils/dateUtils.js +56 -5
- package/dist/utils/formatUtils.d.ts +10 -0
- package/dist/utils/formatUtils.js +24 -0
- package/dist/utils/index.d.ts +1 -1
- package/package.json +12 -4
- package/src/global.scss +319 -39
- package/src/styles/theme.css +105 -16
- package/src/theme-plugin.css +13 -0
- package/dist/components/ai/ApprovalCard/ApprovalCard.d.ts +0 -3
- package/dist/components/ai/ApprovalCard/ApprovalCard.js +0 -16
- package/dist/components/ai/ApprovalCard/ApprovalCard.theme.d.ts +0 -13
- package/dist/components/ai/ApprovalCard/ApprovalCard.theme.js +0 -15
- package/dist/components/ai/ApprovalCard/ApprovalCard.types.d.ts +0 -43
- package/dist/components/ai/ApprovalCard/index.d.ts +0 -2
- package/dist/components/ai/MessageHistory/MessageHistory.d.ts +0 -18
- package/dist/components/ai/MessageHistory/MessageHistory.js +0 -98
- package/dist/components/ai/MessageHistory/MessageHistory.theme.d.ts +0 -2
- package/dist/components/ai/MessageHistory/MessageHistory.theme.js +0 -8
- package/dist/components/ai/MessageHistory/MessageHistory.types.d.ts +0 -94
- package/dist/components/ai/MessageHistory/index.d.ts +0 -3
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.animations.d.ts +0 -10
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.animations.js +0 -47
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.d.ts +0 -20
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.js +0 -55
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.theme.d.ts +0 -2
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.theme.js +0 -20
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.types.d.ts +0 -67
- package/dist/components/ai/ThinkingIndicator/index.d.ts +0 -3
- package/dist/components/forms/TransferList/TransferList.animations.d.ts +0 -10
- package/dist/components/forms/TransferList/TransferList.animations.js +0 -32
- package/dist/components/forms/TransferList/TransferList.d.ts +0 -28
- package/dist/components/forms/TransferList/TransferList.js +0 -199
- package/dist/components/forms/TransferList/TransferList.theme.d.ts +0 -6
- package/dist/components/forms/TransferList/TransferList.theme.js +0 -60
- package/dist/components/forms/TransferList/TransferList.types.d.ts +0 -101
- package/dist/components/forms/TransferList/index.d.ts +0 -3
- package/dist/icons/Icon.d.ts +0 -24
- package/dist/icons/Icon.js +0 -30
- package/dist/icons/Index.d.ts +0 -16
- package/dist/icons/core/ChevronUpDown.d.ts +0 -1
- package/dist/icons/core/ChevronUpDown.js +0 -7
- package/dist/icons/core/DollarIcon.d.ts +0 -1
- package/dist/icons/core/DollarIcon.js +0 -5
- package/dist/icons/core/LockIcon.d.ts +0 -1
- package/dist/icons/core/LockIcon.js +0 -5
- package/dist/icons/core/MinusIcon.d.ts +0 -1
- package/dist/icons/core/MinusIcon.js +0 -7
- package/dist/icons/core/PlusIcon.d.ts +0 -1
- package/dist/icons/core/PlusIcon.js +0 -7
- package/dist/icons/core/SearchIcon.d.ts +0 -1
- package/dist/icons/core/SearchIcon.js +0 -7
- package/dist/icons/core/TickIcon.d.ts +0 -1
- package/dist/icons/core/TickIcon.js +0 -5
- package/dist/icons/core/User.d.ts +0 -1
- package/dist/utils/useClickOutside.d.ts +0 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import React__default, { createContext, useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
+
import { dateRangePickerTheme } from './DateRangePicker.theme.js';
|
|
4
|
+
import { DEFAULT_DATE_RANGE_PRESETS } from './dateRangePresets.js';
|
|
5
|
+
import { FormLabel } from '../FormLabel/FormLabel.js';
|
|
6
|
+
import { DateRangePickerTrigger } from './DateRangePickerTrigger.js';
|
|
7
|
+
import { DateRangePickerBody } from './DateRangePickerBody.js';
|
|
8
|
+
import { DateRangePickerPresets } from './DateRangePickerPresets.js';
|
|
9
|
+
import { cn } from '../../../utils/cn.js';
|
|
10
|
+
import { formatDateCustom } from '../../../utils/dateUtils.js';
|
|
11
|
+
|
|
12
|
+
const DateRangePickerContext = createContext(undefined);
|
|
13
|
+
/**
|
|
14
|
+
* Format date for display
|
|
15
|
+
*/
|
|
16
|
+
const formatDate = (date, formatString, options = {
|
|
17
|
+
year: "numeric",
|
|
18
|
+
month: "short",
|
|
19
|
+
day: "numeric",
|
|
20
|
+
}) => {
|
|
21
|
+
if (formatString) {
|
|
22
|
+
return formatDateCustom(date, formatString);
|
|
23
|
+
}
|
|
24
|
+
return date.toLocaleDateString(undefined, options);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Format date range for display
|
|
28
|
+
*/
|
|
29
|
+
const formatDateRange = (range, formatString, options) => {
|
|
30
|
+
if (!range.start && !range.end)
|
|
31
|
+
return "";
|
|
32
|
+
if (range.start && !range.end)
|
|
33
|
+
return formatDate(range.start, formatString, options);
|
|
34
|
+
if (!range.start && range.end)
|
|
35
|
+
return formatDate(range.end, formatString, options);
|
|
36
|
+
return `${formatDate(range.start, formatString, options)} - ${formatDate(range.end, formatString, options)}`;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* DateRangePicker Component — dedicated range picker with presets and dual calendars
|
|
40
|
+
*/
|
|
41
|
+
const DateRangePickerComponent = React__default.forwardRef(({ id, name, size = "md", state = "default", value, defaultValue, placeholder = "Select date range...", disabled = false, required = false, label, helperText, onChange, onFocus, onBlur, presets = DEFAULT_DATE_RANGE_PRESETS, showPresets = true, minDate, maxDate, isDateDisabled, showToday = true, weekdays, months, dateFormat, formatString, yearRange, className = "", wrapperClassName = "", portal = true, placement = "bottom-start", offset = 4, ...rest }, ref) => {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const theme = { ...dateRangePickerTheme };
|
|
44
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
45
|
+
const [selectedRange, setSelectedRange] = useState(value || defaultValue);
|
|
46
|
+
const triggerRef = useRef(null);
|
|
47
|
+
const contentRef = useRef(null);
|
|
48
|
+
// Sync controlled value
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (value !== undefined) {
|
|
51
|
+
setSelectedRange(value);
|
|
52
|
+
}
|
|
53
|
+
}, [value]);
|
|
54
|
+
const handleRangeSelect = useCallback((newRange) => {
|
|
55
|
+
setSelectedRange(newRange);
|
|
56
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(newRange);
|
|
57
|
+
}, [onChange]);
|
|
58
|
+
const handleButtonClick = useCallback(() => {
|
|
59
|
+
if (!disabled) {
|
|
60
|
+
setIsOpen((prev) => !prev);
|
|
61
|
+
}
|
|
62
|
+
}, [disabled]);
|
|
63
|
+
const displayValue = selectedRange
|
|
64
|
+
? formatDateRange(selectedRange, formatString, dateFormat)
|
|
65
|
+
: placeholder;
|
|
66
|
+
const generatedId = React__default.useId();
|
|
67
|
+
const pickerId = id || generatedId;
|
|
68
|
+
return (jsx(DateRangePickerContext.Provider, { value: useMemo(() => ({
|
|
69
|
+
isOpen,
|
|
70
|
+
setIsOpen,
|
|
71
|
+
selectedRange,
|
|
72
|
+
handleRangeSelect,
|
|
73
|
+
minDate,
|
|
74
|
+
maxDate,
|
|
75
|
+
isDateDisabled,
|
|
76
|
+
showToday,
|
|
77
|
+
weekdays,
|
|
78
|
+
months,
|
|
79
|
+
yearRange,
|
|
80
|
+
size,
|
|
81
|
+
state,
|
|
82
|
+
theme,
|
|
83
|
+
triggerRef,
|
|
84
|
+
contentRef,
|
|
85
|
+
}), [
|
|
86
|
+
isOpen,
|
|
87
|
+
selectedRange,
|
|
88
|
+
handleRangeSelect,
|
|
89
|
+
minDate,
|
|
90
|
+
maxDate,
|
|
91
|
+
isDateDisabled,
|
|
92
|
+
showToday,
|
|
93
|
+
weekdays,
|
|
94
|
+
months,
|
|
95
|
+
yearRange,
|
|
96
|
+
size,
|
|
97
|
+
state,
|
|
98
|
+
theme,
|
|
99
|
+
]), children: jsxs("div", { ref: ref, className: cn(theme.containerStyle, wrapperClassName), ...rest, children: [label && (jsx(FormLabel, { htmlFor: pickerId, required: required, children: label })), jsx(DateRangePickerTrigger, { id: pickerId, disabled: disabled, isOpen: isOpen, state: state, size: size, onClick: handleButtonClick, onFocus: onFocus, onBlur: onBlur, className: className, children: jsx("span", { className: cn("block truncate", selectedRange && (selectedRange.start || selectedRange.end)
|
|
100
|
+
? theme.valueTextStyle
|
|
101
|
+
: theme.placeholderTextStyle), children: displayValue }) }), jsx(DateRangePickerBody, { isOpen: isOpen, onClose: () => setIsOpen(false), portal: portal, placement: placement, offset: offset, presets: presets, showPresets: showPresets }), helperText && (jsx("p", { className: cn(theme.helperTextStyle, theme.helperTextStates[state]), children: helperText })), name && selectedRange && (jsxs(Fragment, { children: [jsx("input", { type: "hidden", name: `${name}[start]`, value: ((_a = selectedRange.start) === null || _a === void 0 ? void 0 : _a.toISOString()) || "" }), jsx("input", { type: "hidden", name: `${name}[end]`, value: ((_b = selectedRange.end) === null || _b === void 0 ? void 0 : _b.toISOString()) || "" })] }))] }) }));
|
|
102
|
+
});
|
|
103
|
+
DateRangePickerComponent.displayName = "DateRangePicker";
|
|
104
|
+
// Compound component
|
|
105
|
+
const DateRangePickerWithCompounds = DateRangePickerComponent;
|
|
106
|
+
DateRangePickerWithCompounds.Trigger = DateRangePickerTrigger;
|
|
107
|
+
DateRangePickerWithCompounds.Body = DateRangePickerBody;
|
|
108
|
+
DateRangePickerWithCompounds.Presets = DateRangePickerPresets;
|
|
109
|
+
|
|
110
|
+
export { DateRangePickerWithCompounds as DateRangePicker, DateRangePickerBody, DateRangePickerContext, DateRangePickerPresets, DateRangePickerTrigger };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { formsBaseTheme } from '../forms.theme.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DateRangePicker theme — mirrors DatePicker theme with added checkmark style
|
|
5
|
+
*/
|
|
6
|
+
const dateRangePickerTheme = {
|
|
7
|
+
containerStyle: formsBaseTheme.wrapperStyle,
|
|
8
|
+
baseStyle: formsBaseTheme.inputGroupBaseStyle + " justify-between cursor-pointer",
|
|
9
|
+
triggerButtonStyle: "w-full cursor-pointer bg-white dark:bg-[var(--color-neutral-900)]",
|
|
10
|
+
placeholderTextStyle: "text-[var(--color-text-placeholder)]",
|
|
11
|
+
valueTextStyle: "text-[var(--color-text-primary)]",
|
|
12
|
+
triggerSizes: {
|
|
13
|
+
sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
|
|
14
|
+
md: `${formsBaseTheme.sizes.md.text} ${formsBaseTheme.sizes.md.padding} ${formsBaseTheme.sizes.md.height}`,
|
|
15
|
+
lg: `${formsBaseTheme.sizes.lg.text} ${formsBaseTheme.sizes.lg.padding} ${formsBaseTheme.sizes.lg.height}`,
|
|
16
|
+
},
|
|
17
|
+
triggerStates: formsBaseTheme.states,
|
|
18
|
+
triggerHoverStates: formsBaseTheme.hoverStates,
|
|
19
|
+
triggerFocusStates: formsBaseTheme.focusStates,
|
|
20
|
+
iconEndStyle: formsBaseTheme.iconStyles.right,
|
|
21
|
+
iconEndPadding: formsBaseTheme.iconStyles.padding.right,
|
|
22
|
+
bodyStyle: "flex flex-col sm:flex-row w-fit max-w-[calc(100vw-2rem)] sm:max-w-none bg-white border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-lg p-0 overflow-hidden z-[1000] fixed " +
|
|
23
|
+
"dark:bg-[var(--color-neutral-900)] dark:border-[var(--color-neutral-700)]",
|
|
24
|
+
presetsContainerStyle: "hidden sm:flex flex-col gap-1 p-3 sm:border-r border-[var(--color-border)] bg-[var(--color-neutral-50)] sm:min-w-[180px] " +
|
|
25
|
+
"dark:bg-[var(--color-neutral-800)] ",
|
|
26
|
+
presetButtonStyle: "w-full text-left px-3 py-2 text-base font-medium rounded-[calc(var(--radius-base)*0.75)] transition-colors cursor-pointer " +
|
|
27
|
+
"flex items-center justify-between gap-2 " +
|
|
28
|
+
"text-[var(--color-text-secondary)] hover:bg-white hover:text-[var(--color-text-primary)] " +
|
|
29
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
|
|
30
|
+
"data-[active=true]:bg-white data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium " +
|
|
31
|
+
"dark:hover:bg-[var(--color-neutral-700)] " +
|
|
32
|
+
"dark:data-[active=true]:bg-[var(--color-neutral-700)] dark:data-[active=true]:text-[var(--color-neutral-100)] " +
|
|
33
|
+
"dark:focus-visible:ring-offset-[var(--color-neutral-800)]",
|
|
34
|
+
presetCheckmarkStyle: "size-4 text-[var(--color-primary)] shrink-0",
|
|
35
|
+
mobilePresetsContainerStyle: "sm:hidden px-3 pt-3 pb-1",
|
|
36
|
+
mobilePresetButtonStyle: "whitespace-nowrap px-3 py-1.5 text-sm font-medium rounded-full transition-colors cursor-pointer shrink-0 " +
|
|
37
|
+
"bg-[var(--color-background-secondary)] text-[var(--color-text-secondary)] " +
|
|
38
|
+
"hover:bg-[var(--color-background-tertiary)] hover:text-[var(--color-text-primary)] " +
|
|
39
|
+
"data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary)] " +
|
|
40
|
+
"dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-300)] " +
|
|
41
|
+
"dark:hover:bg-[var(--color-neutral-700)] " +
|
|
42
|
+
"dark:data-[active=true]:bg-[var(--color-primary-950)] dark:data-[active=true]:text-[var(--color-primary-300)]",
|
|
43
|
+
mobileRangeDisplayStyle: "sm:hidden text-sm text-center py-2 text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
|
|
44
|
+
helperTextStyle: formsBaseTheme.helperText,
|
|
45
|
+
helperTextStates: {
|
|
46
|
+
default: "text-[var(--color-text-muted)] dark:text-[var(--color-neutral-400)]",
|
|
47
|
+
disabled: "text-[var(--color-text-disabled)] dark:text-[var(--color-neutral-600)]",
|
|
48
|
+
invalid: "text-[var(--color-danger)] dark:text-[var(--color-danger-400)]",
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { dateRangePickerTheme };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DateRange } from "../../core/Calendar/Calendar.types";
|
|
3
|
+
export type { DateRange };
|
|
4
|
+
/**
|
|
5
|
+
* Size variants for DateRangePicker
|
|
6
|
+
*/
|
|
7
|
+
export type DateRangePickerSize = "sm" | "md" | "lg";
|
|
8
|
+
/**
|
|
9
|
+
* State variants for DateRangePicker
|
|
10
|
+
*/
|
|
11
|
+
export type DateRangePickerState = "default" | "disabled" | "invalid";
|
|
12
|
+
/**
|
|
13
|
+
* Placement options for DateRangePicker popover
|
|
14
|
+
*/
|
|
15
|
+
export type DateRangePickerPlacement = "bottom-start" | "bottom-end" | "top-start" | "top-end";
|
|
16
|
+
/**
|
|
17
|
+
* Preset for quick date range selection
|
|
18
|
+
*/
|
|
19
|
+
export interface DateRangePreset {
|
|
20
|
+
label: string;
|
|
21
|
+
getValue: () => DateRange;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Main DateRangePicker component props
|
|
25
|
+
* Always operates on DateRange — no single date mode
|
|
26
|
+
*/
|
|
27
|
+
export interface DateRangePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue" | "onFocus" | "onBlur"> {
|
|
28
|
+
/** Unique identifier */
|
|
29
|
+
id?: string;
|
|
30
|
+
/** Form field name */
|
|
31
|
+
name?: string;
|
|
32
|
+
/** Size variant */
|
|
33
|
+
size?: DateRangePickerSize;
|
|
34
|
+
/** State variant */
|
|
35
|
+
state?: DateRangePickerState;
|
|
36
|
+
/** The selected date range (controlled mode) */
|
|
37
|
+
value?: DateRange;
|
|
38
|
+
/** Default selected date range (uncontrolled mode) */
|
|
39
|
+
defaultValue?: DateRange;
|
|
40
|
+
/** Placeholder text when no range selected */
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
/** Whether the field is disabled */
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
/** Whether the field is required */
|
|
45
|
+
required?: boolean;
|
|
46
|
+
/** Label for the field */
|
|
47
|
+
label?: string;
|
|
48
|
+
/** Helper text below the field */
|
|
49
|
+
helperText?: string;
|
|
50
|
+
/** Callback fired when a range is applied */
|
|
51
|
+
onChange?: (range: DateRange | null) => void;
|
|
52
|
+
/** Array of preset date ranges */
|
|
53
|
+
presets?: DateRangePreset[];
|
|
54
|
+
/** Whether to show presets sidebar (default: true) */
|
|
55
|
+
showPresets?: boolean;
|
|
56
|
+
/** Focus event handler */
|
|
57
|
+
onFocus?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
58
|
+
/** Blur event handler */
|
|
59
|
+
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
60
|
+
/** Minimum selectable date */
|
|
61
|
+
minDate?: Date;
|
|
62
|
+
/** Maximum selectable date */
|
|
63
|
+
maxDate?: Date;
|
|
64
|
+
/** Function to determine if a specific date should be disabled */
|
|
65
|
+
isDateDisabled?: (date: Date) => boolean;
|
|
66
|
+
/** Whether to highlight today's date (default: true) */
|
|
67
|
+
showToday?: boolean;
|
|
68
|
+
/** Custom weekday labels */
|
|
69
|
+
weekdays?: string[];
|
|
70
|
+
/** Custom month names */
|
|
71
|
+
months?: string[];
|
|
72
|
+
/** Format for displaying selected date (Intl API) */
|
|
73
|
+
dateFormat?: Intl.DateTimeFormatOptions;
|
|
74
|
+
/** Custom format string (e.g., 'DD MMM YYYY') - takes precedence over dateFormat */
|
|
75
|
+
formatString?: string;
|
|
76
|
+
/** Year range for the year dropdown */
|
|
77
|
+
yearRange?: {
|
|
78
|
+
start: number;
|
|
79
|
+
end: number;
|
|
80
|
+
};
|
|
81
|
+
/** Additional class name for trigger button */
|
|
82
|
+
className?: string;
|
|
83
|
+
/** Additional class name for wrapper */
|
|
84
|
+
wrapperClassName?: string;
|
|
85
|
+
/** Whether to use portal rendering (default: true) */
|
|
86
|
+
portal?: boolean;
|
|
87
|
+
/** Popover placement */
|
|
88
|
+
placement?: DateRangePickerPlacement;
|
|
89
|
+
/** Offset from trigger element */
|
|
90
|
+
offset?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* DateRangePicker trigger button props
|
|
94
|
+
*/
|
|
95
|
+
export interface DateRangePickerTriggerProps {
|
|
96
|
+
id?: string;
|
|
97
|
+
disabled?: boolean;
|
|
98
|
+
isOpen?: boolean;
|
|
99
|
+
state?: DateRangePickerState;
|
|
100
|
+
size?: DateRangePickerSize;
|
|
101
|
+
className?: string;
|
|
102
|
+
onClick?: () => void;
|
|
103
|
+
onFocus?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
104
|
+
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
105
|
+
children?: React.ReactNode;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* DateRangePicker body props
|
|
109
|
+
*/
|
|
110
|
+
export interface DateRangePickerBodyProps {
|
|
111
|
+
isOpen?: boolean;
|
|
112
|
+
className?: string;
|
|
113
|
+
onClose?: () => void;
|
|
114
|
+
portal?: boolean;
|
|
115
|
+
placement?: DateRangePickerPlacement;
|
|
116
|
+
offset?: number;
|
|
117
|
+
presets?: DateRangePreset[];
|
|
118
|
+
showPresets?: boolean;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* DateRangePicker presets props
|
|
122
|
+
*/
|
|
123
|
+
export interface DateRangePickerPresetsProps {
|
|
124
|
+
presets: DateRangePreset[];
|
|
125
|
+
className?: string;
|
|
126
|
+
tempRange?: DateRange;
|
|
127
|
+
setTempRange?: React.Dispatch<React.SetStateAction<DateRange | undefined>>;
|
|
128
|
+
onPresetSelect?: (range: DateRange) => void;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Theme interface for DateRangePicker (flat structure following library pattern)
|
|
132
|
+
*/
|
|
133
|
+
export interface DateRangePickerTheme {
|
|
134
|
+
containerStyle: string;
|
|
135
|
+
baseStyle: string;
|
|
136
|
+
triggerButtonStyle: string;
|
|
137
|
+
placeholderTextStyle: string;
|
|
138
|
+
valueTextStyle: string;
|
|
139
|
+
triggerSizes: Record<DateRangePickerSize, string>;
|
|
140
|
+
triggerStates: Record<DateRangePickerState, string>;
|
|
141
|
+
triggerHoverStates: Record<DateRangePickerState, string>;
|
|
142
|
+
triggerFocusStates: Record<DateRangePickerState, string>;
|
|
143
|
+
iconEndStyle: string;
|
|
144
|
+
iconEndPadding: string;
|
|
145
|
+
bodyStyle: string;
|
|
146
|
+
presetsContainerStyle: string;
|
|
147
|
+
presetButtonStyle: string;
|
|
148
|
+
presetCheckmarkStyle: string;
|
|
149
|
+
mobilePresetsContainerStyle: string;
|
|
150
|
+
mobilePresetButtonStyle: string;
|
|
151
|
+
mobileRangeDisplayStyle: string;
|
|
152
|
+
helperTextStyle: string;
|
|
153
|
+
helperTextStates: Record<DateRangePickerState, string>;
|
|
154
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import React__default, { useContext, useState, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
+
import { AnimatePresence, motion } from 'motion/react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
import { Calendar } from '../../core/Calendar/Calendar.js';
|
|
6
|
+
import '../../core/Calendar/CalendarMini/CalendarMini.js';
|
|
7
|
+
import { Button } from '../../core/Button/Button.js';
|
|
8
|
+
import { cn } from '../../../utils/cn.js';
|
|
9
|
+
import { DateRangePickerContext } from './DateRangePicker.js';
|
|
10
|
+
import { DateRangePickerPresets } from './DateRangePickerPresets.js';
|
|
11
|
+
import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
|
|
12
|
+
import { formatDateCustom } from '../../../utils/dateUtils.js';
|
|
13
|
+
import { createDropdownAnimations } from '../DatePicker/DatePicker.animations.js';
|
|
14
|
+
import { useIsClient } from '../../../hooks/useIsClient.js';
|
|
15
|
+
import { useMediaQuery } from '../../../hooks/useMediaQuery.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook to detect dark mode state from document
|
|
19
|
+
*/
|
|
20
|
+
const useDarkMode = () => {
|
|
21
|
+
const [isDark, setIsDark] = useState(false);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (typeof document === "undefined")
|
|
24
|
+
return;
|
|
25
|
+
const checkDarkMode = () => {
|
|
26
|
+
const hasDarkClass = document.documentElement.classList.contains("dark") ||
|
|
27
|
+
document.body.classList.contains("dark") ||
|
|
28
|
+
document.querySelector(".dark") !== null;
|
|
29
|
+
setIsDark(hasDarkClass);
|
|
30
|
+
};
|
|
31
|
+
checkDarkMode();
|
|
32
|
+
const observer = new MutationObserver(checkDarkMode);
|
|
33
|
+
observer.observe(document.documentElement, {
|
|
34
|
+
attributes: true,
|
|
35
|
+
attributeFilter: ["class"],
|
|
36
|
+
});
|
|
37
|
+
observer.observe(document.body, {
|
|
38
|
+
attributes: true,
|
|
39
|
+
attributeFilter: ["class"],
|
|
40
|
+
});
|
|
41
|
+
return () => observer.disconnect();
|
|
42
|
+
}, []);
|
|
43
|
+
return isDark;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* DateRangePicker Body Component — dual calendars + presets sidebar + footer
|
|
47
|
+
*/
|
|
48
|
+
const DateRangePickerBody = ({ isOpen, className, onClose, portal = true, placement = "bottom-start", offset = 4, presets, showPresets = true, }) => {
|
|
49
|
+
const context = useContext(DateRangePickerContext);
|
|
50
|
+
if (!context) {
|
|
51
|
+
throw new Error("DateRangePickerBody must be used within a DateRangePicker");
|
|
52
|
+
}
|
|
53
|
+
const { theme, triggerRef, contentRef, selectedRange, minDate, maxDate, isDateDisabled, showToday, weekdays, months, handleRangeSelect, yearRange, } = context;
|
|
54
|
+
const hasPresets = showPresets && presets && presets.length > 0;
|
|
55
|
+
const isDarkMode = useDarkMode();
|
|
56
|
+
const isClient = useIsClient();
|
|
57
|
+
const isMobile = useMediaQuery("(max-width: 639px)");
|
|
58
|
+
// Temp range state — not committed until Apply is clicked
|
|
59
|
+
const [tempRange, setTempRange] = useState(selectedRange);
|
|
60
|
+
// Sync temp range when panel opens
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (isOpen) {
|
|
63
|
+
setTempRange(selectedRange);
|
|
64
|
+
}
|
|
65
|
+
}, [isOpen, selectedRange]);
|
|
66
|
+
// Handle preset selection — update calendar view to show the range
|
|
67
|
+
const handlePresetSelect = useCallback((range) => {
|
|
68
|
+
if (range.start) {
|
|
69
|
+
setLeftCalendarDate(new Date(range.start.getFullYear(), range.start.getMonth(), 1));
|
|
70
|
+
}
|
|
71
|
+
}, []);
|
|
72
|
+
// Dual calendar state
|
|
73
|
+
const getInitialLeftDate = () => {
|
|
74
|
+
if (tempRange === null || tempRange === void 0 ? void 0 : tempRange.start) {
|
|
75
|
+
return new Date(tempRange.start.getFullYear(), tempRange.start.getMonth(), 1);
|
|
76
|
+
}
|
|
77
|
+
if (selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.start) {
|
|
78
|
+
return new Date(selectedRange.start.getFullYear(), selectedRange.start.getMonth(), 1);
|
|
79
|
+
}
|
|
80
|
+
return new Date();
|
|
81
|
+
};
|
|
82
|
+
const [leftCalendarDate, setLeftCalendarDate] = useState(getInitialLeftDate);
|
|
83
|
+
const rightCalendarDate = useMemo(() => {
|
|
84
|
+
const nextMonth = new Date(leftCalendarDate);
|
|
85
|
+
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
|
86
|
+
return nextMonth;
|
|
87
|
+
}, [leftCalendarDate]);
|
|
88
|
+
const handleNavigatePrev = useCallback(() => {
|
|
89
|
+
setLeftCalendarDate((prev) => {
|
|
90
|
+
const newDate = new Date(prev);
|
|
91
|
+
newDate.setMonth(newDate.getMonth() - 1);
|
|
92
|
+
return newDate;
|
|
93
|
+
});
|
|
94
|
+
}, []);
|
|
95
|
+
const handleNavigateNext = useCallback(() => {
|
|
96
|
+
setLeftCalendarDate((prev) => {
|
|
97
|
+
const newDate = new Date(prev);
|
|
98
|
+
newDate.setMonth(newDate.getMonth() + 1);
|
|
99
|
+
return newDate;
|
|
100
|
+
});
|
|
101
|
+
}, []);
|
|
102
|
+
// Footer handlers
|
|
103
|
+
const handleApply = useCallback(() => {
|
|
104
|
+
if (tempRange) {
|
|
105
|
+
handleRangeSelect(tempRange);
|
|
106
|
+
}
|
|
107
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
108
|
+
}, [tempRange, handleRangeSelect, onClose]);
|
|
109
|
+
const handleCancel = useCallback(() => {
|
|
110
|
+
setTempRange(selectedRange);
|
|
111
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
112
|
+
}, [selectedRange, onClose]);
|
|
113
|
+
// Format range for footer display
|
|
114
|
+
const formatRangeDisplay = (range) => {
|
|
115
|
+
if (!(range === null || range === void 0 ? void 0 : range.start) && !(range === null || range === void 0 ? void 0 : range.end))
|
|
116
|
+
return "Select start and end dates";
|
|
117
|
+
if (!range.end)
|
|
118
|
+
return `${formatDateCustom(range.start, "DD/MM/YYYY")} - ...`;
|
|
119
|
+
return `${formatDateCustom(range.start, "DD/MM/YYYY")} - ${formatDateCustom(range.end, "DD/MM/YYYY")}`;
|
|
120
|
+
};
|
|
121
|
+
// Portal positioning
|
|
122
|
+
const { position, cssVariables, contentRef: portalContentRef, isFlipped, isReady, } = useSelectPortal({
|
|
123
|
+
triggerRef,
|
|
124
|
+
isOpen: isOpen || false,
|
|
125
|
+
placement,
|
|
126
|
+
offset,
|
|
127
|
+
autoWidth: true,
|
|
128
|
+
});
|
|
129
|
+
const animations = createDropdownAnimations(isFlipped);
|
|
130
|
+
// Combine refs
|
|
131
|
+
const combinedRef = React__default.useCallback((el) => {
|
|
132
|
+
if (contentRef &&
|
|
133
|
+
typeof contentRef === "object" &&
|
|
134
|
+
"current" in contentRef) {
|
|
135
|
+
contentRef.current =
|
|
136
|
+
el;
|
|
137
|
+
}
|
|
138
|
+
if (portalContentRef &&
|
|
139
|
+
typeof portalContentRef === "object" &&
|
|
140
|
+
"current" in portalContentRef) {
|
|
141
|
+
portalContentRef.current = el;
|
|
142
|
+
}
|
|
143
|
+
}, [contentRef, portalContentRef]);
|
|
144
|
+
// Click outside to close
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (!isOpen)
|
|
147
|
+
return;
|
|
148
|
+
const handleClickOutside = (event) => {
|
|
149
|
+
var _a;
|
|
150
|
+
const target = event.target;
|
|
151
|
+
if ((_a = target.closest) === null || _a === void 0 ? void 0 : _a.call(target, '[role="listbox"]')) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const currentContentRef = portal
|
|
155
|
+
? portalContentRef.current
|
|
156
|
+
: contentRef.current;
|
|
157
|
+
if (currentContentRef &&
|
|
158
|
+
!currentContentRef.contains(target) &&
|
|
159
|
+
triggerRef.current &&
|
|
160
|
+
!triggerRef.current.contains(target)) {
|
|
161
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
165
|
+
return () => {
|
|
166
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
167
|
+
};
|
|
168
|
+
}, [isOpen, onClose, triggerRef, contentRef, portalContentRef, portal]);
|
|
169
|
+
// Escape key
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (!isOpen)
|
|
172
|
+
return;
|
|
173
|
+
const handleKeyDown = (event) => {
|
|
174
|
+
if (event.key === "Escape") {
|
|
175
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
179
|
+
return () => {
|
|
180
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
181
|
+
};
|
|
182
|
+
}, [isOpen, onClose]);
|
|
183
|
+
const contentElement = (jsx(AnimatePresence, { mode: "wait", children: isOpen && (jsxs(motion.div, { ref: combinedRef, className: cn(theme.bodyStyle, className), style: {
|
|
184
|
+
...cssVariables,
|
|
185
|
+
...(portal
|
|
186
|
+
? {
|
|
187
|
+
top: `${position.top}px`,
|
|
188
|
+
left: `${position.left}px`,
|
|
189
|
+
minWidth: `${position.width}px`,
|
|
190
|
+
}
|
|
191
|
+
: {}),
|
|
192
|
+
}, variants: animations, initial: "initial", animate: isReady ? "visible" : "initial", exit: "exit", children: [hasPresets && presets && (jsx(DateRangePickerPresets, { presets: presets, tempRange: tempRange, setTempRange: setTempRange, onPresetSelect: handlePresetSelect })), jsxs("div", { className: "flex flex-col flex-1", children: [jsxs("div", { className: "flex flex-col sm:flex-row justify-between items-center sm:items-start gap-2 sm:gap-6 p-3 sm:p-4", children: [jsx("div", { className: "flex-1 min-w-fit", children: jsx(Calendar, { mode: "range", value: tempRange, onChange: (value) => {
|
|
193
|
+
setTempRange(value);
|
|
194
|
+
}, viewDate: leftCalendarDate, onViewDateChange: setLeftCalendarDate, onNavigatePrev: handleNavigatePrev, onNavigateNext: isMobile ? handleNavigateNext : null, minDate: minDate, maxDate: maxDate, isDateDisabled: isDateDisabled, showToday: showToday, selectTodayByDefault: false, weekdays: weekdays, months: months, yearRange: yearRange, showOtherMonthDays: false, headerMode: "static", size: "md" }) }), jsx("div", { className: "hidden sm:block flex-1 min-w-fit", children: jsx(Calendar, { mode: "range", value: tempRange, onChange: (value) => {
|
|
195
|
+
setTempRange(value);
|
|
196
|
+
}, viewDate: rightCalendarDate, onViewDateChange: (newDate) => {
|
|
197
|
+
const adjustedLeft = new Date(newDate);
|
|
198
|
+
adjustedLeft.setMonth(adjustedLeft.getMonth() - 1);
|
|
199
|
+
setLeftCalendarDate(adjustedLeft);
|
|
200
|
+
}, onNavigatePrev: null, onNavigateNext: handleNavigateNext, minDate: minDate, maxDate: maxDate, isDateDisabled: isDateDisabled, showToday: showToday, selectTodayByDefault: false, weekdays: weekdays, months: months, yearRange: yearRange, showOtherMonthDays: false, headerMode: "static", size: "md" }) })] }), jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 px-3 sm:px-4 py-3 border-t border-[var(--color-border)]", children: [jsx("div", { className: "text-sm text-center sm:text-left text-[var(--color-text-muted)]", children: formatRangeDisplay(tempRange) }), jsxs("div", { className: "flex w-full sm:w-auto items-center gap-2", children: [jsx(Button, { variant: "outline", color: "neutral", size: "sm", className: "flex-1 sm:flex-initial", onClick: handleCancel, children: "Cancel" }), jsx(Button, { variant: "filled", size: "sm", className: "flex-1 sm:flex-initial", onClick: handleApply, disabled: !(tempRange === null || tempRange === void 0 ? void 0 : tempRange.start) || !(tempRange === null || tempRange === void 0 ? void 0 : tempRange.end), children: "Apply" })] })] })] })] })) }));
|
|
201
|
+
if (portal && isClient) {
|
|
202
|
+
return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: contentElement }), document.body);
|
|
203
|
+
}
|
|
204
|
+
return contentElement;
|
|
205
|
+
};
|
|
206
|
+
DateRangePickerBody.displayName = "DateRangePicker.Body";
|
|
207
|
+
|
|
208
|
+
export { DateRangePickerBody };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DateRangePickerPresetsProps } from "./DateRangePicker.types";
|
|
3
|
+
/**
|
|
4
|
+
* DateRangePicker Presets Component — shows preset buttons with checkmarks
|
|
5
|
+
*/
|
|
6
|
+
export declare const DateRangePickerPresets: React.FC<DateRangePickerPresetsProps>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { CheckIcon } from '@heroicons/react/24/outline';
|
|
4
|
+
import { DateRangePickerContext } from './DateRangePicker.js';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* DateRangePicker Presets Component — shows preset buttons with checkmarks
|
|
9
|
+
*/
|
|
10
|
+
const DateRangePickerPresets = ({ presets, className, tempRange, setTempRange, onPresetSelect, }) => {
|
|
11
|
+
const context = useContext(DateRangePickerContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error("DateRangePickerPresets must be used within a DateRangePicker");
|
|
14
|
+
}
|
|
15
|
+
const { theme } = context;
|
|
16
|
+
const isSameDate = (d1, d2) => {
|
|
17
|
+
if (!d1 || !d2)
|
|
18
|
+
return d1 === d2;
|
|
19
|
+
return (d1.getFullYear() === d2.getFullYear() &&
|
|
20
|
+
d1.getMonth() === d2.getMonth() &&
|
|
21
|
+
d1.getDate() === d2.getDate());
|
|
22
|
+
};
|
|
23
|
+
const isPresetActive = (preset) => {
|
|
24
|
+
if (!tempRange)
|
|
25
|
+
return false;
|
|
26
|
+
const presetRange = preset.getValue();
|
|
27
|
+
return (isSameDate(tempRange.start, presetRange.start) &&
|
|
28
|
+
isSameDate(tempRange.end, presetRange.end));
|
|
29
|
+
};
|
|
30
|
+
const handlePresetClick = (preset) => {
|
|
31
|
+
const range = preset.getValue();
|
|
32
|
+
setTempRange === null || setTempRange === void 0 ? void 0 : setTempRange(range);
|
|
33
|
+
onPresetSelect === null || onPresetSelect === void 0 ? void 0 : onPresetSelect(range);
|
|
34
|
+
};
|
|
35
|
+
return (jsx("div", { className: cn(theme.presetsContainerStyle, className), children: presets.map((preset, index) => {
|
|
36
|
+
const active = isPresetActive(preset);
|
|
37
|
+
return (jsxs("button", { type: "button", onClick: () => handlePresetClick(preset), className: theme.presetButtonStyle, "data-active": active, children: [jsx("span", { children: preset.label }), active && jsx(CheckIcon, { className: theme.presetCheckmarkStyle })] }, index));
|
|
38
|
+
}) }));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { DateRangePickerPresets };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { CalendarIcon } from '@heroicons/react/24/outline';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
import { DateRangePickerContext } from './DateRangePicker.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* DateRangePicker Trigger Component — styled like form input
|
|
9
|
+
*/
|
|
10
|
+
const DateRangePickerTrigger = ({ id, disabled, isOpen, state = "default", size = "md", className, onClick, onFocus, onBlur, children, }) => {
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
|
+
const context = useContext(DateRangePickerContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
throw new Error("DateRangePickerTrigger must be used within a DateRangePicker");
|
|
15
|
+
}
|
|
16
|
+
const { theme, triggerRef } = context;
|
|
17
|
+
const baseStyle = theme.baseStyle || "";
|
|
18
|
+
const sizeStyle = ((_a = theme.triggerSizes) === null || _a === void 0 ? void 0 : _a[size]) || "";
|
|
19
|
+
const stateStyle = ((_b = theme.triggerStates) === null || _b === void 0 ? void 0 : _b[state]) || "";
|
|
20
|
+
const hoverStateStyle = ((_c = theme.triggerHoverStates) === null || _c === void 0 ? void 0 : _c[state]) || "";
|
|
21
|
+
const focusStateStyle = ((_d = theme.triggerFocusStates) === null || _d === void 0 ? void 0 : _d[state]) || "";
|
|
22
|
+
const iconEndStyle = theme.iconEndStyle || "";
|
|
23
|
+
const iconEndPadding = theme.iconEndPadding || "";
|
|
24
|
+
const triggerButtonStyle = theme.triggerButtonStyle || "";
|
|
25
|
+
const activeFocusState = isOpen
|
|
26
|
+
? focusStateStyle ||
|
|
27
|
+
"outline-2 outline-primary-600 -outline-offset-1 ring-4 ring-[var(--color-primary)]/10"
|
|
28
|
+
: "";
|
|
29
|
+
return (jsx("div", { className: "relative w-full", children: jsxs("button", { ref: triggerRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconEndPadding, triggerButtonStyle, "text-left", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Open date range picker", children: [children, jsx("span", { className: iconEndStyle, children: jsx(CalendarIcon, { className: "h-4 w-4" }) })] }) }));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export { DateRangePickerTrigger };
|