@exsto/ds 0.0.1-rc.14 → 0.0.1-rc.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/dist/index.js +2 -1
- package/dist/source-hash.txt +1 -1
- package/dist/styles.css +79 -1
- package/dist/theme.css +1 -2
- package/dist/ui/src/components/edyn/date-picker/date-picker.d.ts +1 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.js +23 -3
- package/dist/ui/src/components/edyn/date-picker/date-picker.js.map +1 -1
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.js +13 -2
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.js.map +1 -1
- package/dist/ui/src/components/edyn/multi-select/multi-select.js +8 -2
- package/dist/ui/src/components/edyn/multi-select/multi-select.js.map +1 -1
- package/dist/ui/src/components/edyn/presence/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/presence/presence.d.ts +15 -0
- package/dist/ui/src/components/edyn/presence/presence.js +54 -0
- package/dist/ui/src/components/edyn/presence/presence.js.map +1 -0
- package/dist/ui/src/components/edyn/presence/presence.test.d.ts +8 -0
- package/dist/ui/src/components/ui/alert-dialog/alert-dialog.js +2 -0
- package/dist/ui/src/components/ui/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/ui/src/components/ui/badge/badge.js +1 -1
- package/dist/ui/src/components/ui/badge/badge.js.map +1 -1
- package/dist/ui/src/components/ui/context-menu/context-menu.js +2 -0
- package/dist/ui/src/components/ui/context-menu/context-menu.js.map +1 -1
- package/dist/ui/src/components/ui/dialog/dialog.js +2 -0
- package/dist/ui/src/components/ui/dialog/dialog.js.map +1 -1
- package/dist/ui/src/components/ui/drawer/drawer.js +2 -0
- package/dist/ui/src/components/ui/drawer/drawer.js.map +1 -1
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js +2 -0
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js +2 -0
- package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js.map +1 -1
- package/dist/ui/src/components/ui/popover/popover.js +2 -0
- package/dist/ui/src/components/ui/popover/popover.js.map +1 -1
- package/dist/ui/src/components/ui/select/select.js +2 -0
- package/dist/ui/src/components/ui/select/select.js.map +1 -1
- package/dist/ui/src/components/ui/sheet/sheet.js +2 -0
- package/dist/ui/src/components/ui/sheet/sheet.js.map +1 -1
- package/dist/ui/src/index.d.ts +1 -0
- package/dist/ui/src/lib/focus-guards.d.ts +2 -0
- package/dist/ui/src/lib/focus-guards.js +52 -0
- package/dist/ui/src/lib/focus-guards.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { useMergedRefs } from "./ui/src/hooks/use-merged-refs.js";
|
|
|
14
14
|
import { ScrollArea, ScrollBar } from "./ui/src/components/ui/scroll-area/scroll-area.js";
|
|
15
15
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/src/components/ui/tooltip/tooltip.js";
|
|
16
16
|
import { DEFAULT_MULTI_SELECT_LABELS, MultiSelect, VIRTUALIZE_FROM, fullSelection, resolveChosen, summarize } from "./ui/src/components/edyn/multi-select/multi-select.js";
|
|
17
|
+
import { DEFAULT_PRESENCE_LABELS, PRESENCE_STATES, Presence } from "./ui/src/components/edyn/presence/presence.js";
|
|
17
18
|
import { PROGRESS_LINE_COLOR, ProgressLine } from "./ui/src/components/edyn/progress-line/progress-line.js";
|
|
18
19
|
import { RICH_TEXT_ATTRIBUTES, RICH_TEXT_ELEMENTS, RICH_TEXT_LINK_PROTOCOLS, isAllowedRichTextHref } from "./ui/src/components/edyn/rich-text-content/allow-list.js";
|
|
19
20
|
import { RICH_TEXT_BODY_CLASS, RICH_TEXT_MENTION_CLASS, RichTextContent, richTextToNodes } from "./ui/src/components/edyn/rich-text-content/rich-text-content.js";
|
|
@@ -73,4 +74,4 @@ import { Tabs, TabsContent, TabsList, TabsTrigger, tabsListVariants } from "./ui
|
|
|
73
74
|
import { Toast, ToastAction, ToastClose, ToastContent, ToastDescription, ToastPortal, ToastProvider, ToastTitle, ToastViewport, Toaster, createToastManager, toast, useToastManager } from "./ui/src/components/ui/toast/toast.js";
|
|
74
75
|
import { Toggle, toggleVariants } from "./ui/src/components/ui/toggle/toggle.js";
|
|
75
76
|
import { ToggleGroup, ToggleGroupItem } from "./ui/src/components/ui/toggle-group/toggle-group.js";
|
|
76
|
-
export { AVATAR_TONES, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedNumber, AspectRatio, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AudioPlayer, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_MULTI_SELECT_LABELS, DateRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldDescription, FieldError, FieldLabel, HoverCard, HoverCardContent, HoverCardTrigger, Indicator, InitialsAvatar, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MultiSelect, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuPositioner, NavigationMenuTrigger, NumberText, PROGRESS_DURATION, PROGRESS_EASE, PROGRESS_LINE_COLOR, Pagination, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, ProgressLine, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RICH_TEXT_ATTRIBUTES, RICH_TEXT_BODY_CLASS, RICH_TEXT_ELEMENTS, RICH_TEXT_LINK_PROTOCOLS, RICH_TEXT_MENTION_CLASS, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTextContent, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toast, ToastAction, ToastClose, ToastContent, ToastDescription, ToastPortal, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VIRTUALIZE_FROM, VideoPlayer, avatarTone, badgeVariants, buttonVariants, clampPage, cn, createToastManager, dateToDay, dayToDate, formatCount, formatMediaTime, fullSelection, getPaginationRange, indicatorVariants, initialsOf, isAllowedRichTextHref, markerVariants, navigationMenuTriggerStyle, progressFill, progressTrack, resolveChosen, richTextToNodes, spinnerVariants, summarize, tabsListVariants, toast, toggleVariants, useAnimatedValues, useCarousel, useDirection, useIsMobile, useMediaPlayer, useMergedRefs, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useToastManager };
|
|
77
|
+
export { AVATAR_TONES, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedNumber, AspectRatio, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AudioPlayer, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_MULTI_SELECT_LABELS, DEFAULT_PRESENCE_LABELS, DateRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldDescription, FieldError, FieldLabel, HoverCard, HoverCardContent, HoverCardTrigger, Indicator, InitialsAvatar, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MultiSelect, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuPositioner, NavigationMenuTrigger, NumberText, PRESENCE_STATES, PROGRESS_DURATION, PROGRESS_EASE, PROGRESS_LINE_COLOR, Pagination, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Presence, Progress, ProgressLine, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RICH_TEXT_ATTRIBUTES, RICH_TEXT_BODY_CLASS, RICH_TEXT_ELEMENTS, RICH_TEXT_LINK_PROTOCOLS, RICH_TEXT_MENTION_CLASS, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTextContent, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toast, ToastAction, ToastClose, ToastContent, ToastDescription, ToastPortal, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VIRTUALIZE_FROM, VideoPlayer, avatarTone, badgeVariants, buttonVariants, clampPage, cn, createToastManager, dateToDay, dayToDate, formatCount, formatMediaTime, fullSelection, getPaginationRange, indicatorVariants, initialsOf, isAllowedRichTextHref, markerVariants, navigationMenuTriggerStyle, progressFill, progressTrack, resolveChosen, richTextToNodes, spinnerVariants, summarize, tabsListVariants, toast, toggleVariants, useAnimatedValues, useCarousel, useDirection, useIsMobile, useMediaPlayer, useMergedRefs, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useToastManager };
|
package/dist/source-hash.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
e02db65d6034fdeb69accb2fd27d311f2f426b050ddf45dcc35078a5659e9466
|
package/dist/styles.css
CHANGED
|
@@ -120,6 +120,7 @@
|
|
|
120
120
|
--font-sans: "Inter", sans-serif;
|
|
121
121
|
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
|
122
122
|
"Courier New", monospace;
|
|
123
|
+
--color-red-300: oklch(80.8% .114 19.571);
|
|
123
124
|
--spacing: .25rem;
|
|
124
125
|
--container-xs: 20rem;
|
|
125
126
|
--container-sm: 24rem;
|
|
@@ -786,6 +787,10 @@
|
|
|
786
787
|
margin-inline-start: var(--scroll-bar-gap);
|
|
787
788
|
}
|
|
788
789
|
|
|
790
|
+
.ms-2 {
|
|
791
|
+
margin-inline-start: calc(var(--spacing) * 2);
|
|
792
|
+
}
|
|
793
|
+
|
|
789
794
|
.ms-auto {
|
|
790
795
|
margin-inline-start: auto;
|
|
791
796
|
}
|
|
@@ -1920,6 +1925,11 @@
|
|
|
1920
1925
|
border-width: 0;
|
|
1921
1926
|
}
|
|
1922
1927
|
|
|
1928
|
+
.border-2 {
|
|
1929
|
+
border-style: var(--tw-border-style);
|
|
1930
|
+
border-width: 2px;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1923
1933
|
.border-\[1\.5px\] {
|
|
1924
1934
|
border-style: var(--tw-border-style);
|
|
1925
1935
|
border-width: 1.5px;
|
|
@@ -1978,6 +1988,10 @@
|
|
|
1978
1988
|
border-color: var(--input);
|
|
1979
1989
|
}
|
|
1980
1990
|
|
|
1991
|
+
.border-muted-foreground {
|
|
1992
|
+
border-color: var(--muted-foreground);
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1981
1995
|
.border-primary\/50 {
|
|
1982
1996
|
border-color: var(--primary);
|
|
1983
1997
|
}
|
|
@@ -2128,6 +2142,10 @@
|
|
|
2128
2142
|
background-color: var(--sidebar-border);
|
|
2129
2143
|
}
|
|
2130
2144
|
|
|
2145
|
+
.bg-success {
|
|
2146
|
+
background-color: var(--success);
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2131
2149
|
.bg-success-ring\/40 {
|
|
2132
2150
|
background-color: var(--success-ring);
|
|
2133
2151
|
}
|
|
@@ -2142,6 +2160,10 @@
|
|
|
2142
2160
|
background-color: #0000;
|
|
2143
2161
|
}
|
|
2144
2162
|
|
|
2163
|
+
.bg-warning {
|
|
2164
|
+
background-color: var(--warning);
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2145
2167
|
.bg-warning-ring\/40 {
|
|
2146
2168
|
background-color: var(--warning-ring);
|
|
2147
2169
|
}
|
|
@@ -3622,6 +3644,11 @@
|
|
|
3622
3644
|
inset-inline: calc(var(--spacing) * -3);
|
|
3623
3645
|
}
|
|
3624
3646
|
|
|
3647
|
+
.after\:inset-x-0\.5:after {
|
|
3648
|
+
content: var(--tw-content);
|
|
3649
|
+
inset-inline: calc(var(--spacing) * .5);
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3625
3652
|
.after\:-inset-y-2:after {
|
|
3626
3653
|
content: var(--tw-content);
|
|
3627
3654
|
inset-block: calc(var(--spacing) * -2);
|
|
@@ -3637,11 +3664,26 @@
|
|
|
3637
3664
|
inset-inline-start: 50%;
|
|
3638
3665
|
}
|
|
3639
3666
|
|
|
3667
|
+
.after\:-top-px:after {
|
|
3668
|
+
content: var(--tw-content);
|
|
3669
|
+
top: -1px;
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
.after\:top-1\/2:after {
|
|
3673
|
+
content: var(--tw-content);
|
|
3674
|
+
top: 50%;
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3640
3677
|
.after\:top-full:after {
|
|
3641
3678
|
content: var(--tw-content);
|
|
3642
3679
|
top: 100%;
|
|
3643
3680
|
}
|
|
3644
3681
|
|
|
3682
|
+
.after\:-right-px:after {
|
|
3683
|
+
content: var(--tw-content);
|
|
3684
|
+
right: -1px;
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3645
3687
|
.after\:right-0:after {
|
|
3646
3688
|
content: var(--tw-content);
|
|
3647
3689
|
right: 0;
|
|
@@ -3662,6 +3704,17 @@
|
|
|
3662
3704
|
margin-left: var(--spacing);
|
|
3663
3705
|
}
|
|
3664
3706
|
|
|
3707
|
+
.after\:size-1\.5:after {
|
|
3708
|
+
content: var(--tw-content);
|
|
3709
|
+
width: calc(var(--spacing) * 1.5);
|
|
3710
|
+
height: calc(var(--spacing) * 1.5);
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
.after\:h-0\.5:after {
|
|
3714
|
+
content: var(--tw-content);
|
|
3715
|
+
height: calc(var(--spacing) * .5);
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3665
3718
|
.after\:h-\[calc\(var\(--gap\)\+1px\)\]:after {
|
|
3666
3719
|
content: var(--tw-content);
|
|
3667
3720
|
height: calc(var(--gap) + 1px);
|
|
@@ -3708,6 +3761,12 @@
|
|
|
3708
3761
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
3709
3762
|
}
|
|
3710
3763
|
|
|
3764
|
+
.after\:-translate-y-1\/2:after {
|
|
3765
|
+
content: var(--tw-content);
|
|
3766
|
+
--tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
|
|
3767
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3711
3770
|
.after\:rounded-full:after {
|
|
3712
3771
|
content: var(--tw-content);
|
|
3713
3772
|
border-radius: 3.40282e38px;
|
|
@@ -3724,6 +3783,11 @@
|
|
|
3724
3783
|
border-color: var(--border);
|
|
3725
3784
|
}
|
|
3726
3785
|
|
|
3786
|
+
.after\:bg-background:after {
|
|
3787
|
+
content: var(--tw-content);
|
|
3788
|
+
background-color: var(--background);
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3727
3791
|
.after\:bg-border:after {
|
|
3728
3792
|
content: var(--tw-content);
|
|
3729
3793
|
background-color: var(--border);
|
|
@@ -5802,6 +5866,16 @@
|
|
|
5802
5866
|
}
|
|
5803
5867
|
}
|
|
5804
5868
|
|
|
5869
|
+
.dark\:bg-destructive\/20:is(.dark *) {
|
|
5870
|
+
background-color: var(--destructive);
|
|
5871
|
+
}
|
|
5872
|
+
|
|
5873
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5874
|
+
.dark\:bg-destructive\/20:is(.dark *) {
|
|
5875
|
+
background-color: color-mix(in oklab, var(--destructive) 20%, transparent);
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5805
5879
|
.dark\:bg-info-ring\/30:is(.dark *) {
|
|
5806
5880
|
background-color: var(--info-ring);
|
|
5807
5881
|
}
|
|
@@ -5864,6 +5938,10 @@
|
|
|
5864
5938
|
color: var(--muted-foreground);
|
|
5865
5939
|
}
|
|
5866
5940
|
|
|
5941
|
+
.dark\:text-red-300:is(.dark *) {
|
|
5942
|
+
color: var(--color-red-300);
|
|
5943
|
+
}
|
|
5944
|
+
|
|
5867
5945
|
.dark\:group-data-checked\/questionnaire-choice\:bg-primary:is(.dark *):is(:is(:where(.group\/questionnaire-choice):where([data-state="checked"]), :where(.group\/questionnaire-choice):where([data-checked]:not([data-checked="false"]))) *) {
|
|
5868
5946
|
background-color: var(--primary);
|
|
5869
5947
|
}
|
|
@@ -7461,7 +7539,7 @@
|
|
|
7461
7539
|
--muted-foreground: oklch(70.8% 0 0);
|
|
7462
7540
|
--accent: oklch(26.9% 0 0);
|
|
7463
7541
|
--accent-foreground: oklch(98.5% 0 0);
|
|
7464
|
-
--destructive: oklch(
|
|
7542
|
+
--destructive: oklch(70.4% .191 22.216);
|
|
7465
7543
|
--destructive-foreground: oklch(98.5% 0 0);
|
|
7466
7544
|
--success: oklch(79.2% .209 151.711);
|
|
7467
7545
|
--success-foreground: oklch(26.2% .051 172.552);
|
package/dist/theme.css
CHANGED
|
@@ -183,8 +183,7 @@
|
|
|
183
183
|
--accent: oklch(0.269 0 0);
|
|
184
184
|
--accent-foreground: oklch(0.985 0 0);
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
--destructive: oklch(0.76 0.145 22.216);
|
|
186
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
188
187
|
--destructive-foreground: oklch(0.985 0 0);
|
|
189
188
|
|
|
190
189
|
--success: oklch(0.792 0.209 151.711);
|
|
@@ -72,5 +72,6 @@ export interface IDatePickerProps {
|
|
|
72
72
|
/**
|
|
73
73
|
* One calendar day, typed or picked. The field takes the day in the locale's order (05/03/2026 in en-GB) and reads it
|
|
74
74
|
* when it loses focus, saying inline what is wrong with it; the button, or Alt+ArrowDown in the field, opens a calendar.
|
|
75
|
+
* Escape closes the calendar and gives the focus back to whichever of the two opened it; a day picked puts it on the field.
|
|
75
76
|
*/
|
|
76
77
|
export declare const DatePicker: ({ id, value, onValueChange, min, max, disabledDates, disabled, locale, calendarLocale, placeholder, "aria-label": ariaLabel, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, labels: labelOverrides, className, }: IDatePickerProps) => import('react').JSX.Element;
|
|
@@ -30,6 +30,7 @@ var problemText = (problem, labels, locale, limits, pattern) => {
|
|
|
30
30
|
/**
|
|
31
31
|
* One calendar day, typed or picked. The field takes the day in the locale's order (05/03/2026 in en-GB) and reads it
|
|
32
32
|
* when it loses focus, saying inline what is wrong with it; the button, or Alt+ArrowDown in the field, opens a calendar.
|
|
33
|
+
* Escape closes the calendar and gives the focus back to whichever of the two opened it; a day picked puts it on the field.
|
|
33
34
|
*/
|
|
34
35
|
var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled = false, locale = "en-GB", calendarLocale, placeholder, "aria-label": ariaLabel, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, labels: labelOverrides, className }) => {
|
|
35
36
|
const labels = useMemo(() => ({
|
|
@@ -41,6 +42,9 @@ var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled
|
|
|
41
42
|
const errorId = useId();
|
|
42
43
|
const refField = useRef(null);
|
|
43
44
|
const refInput = useRef(null);
|
|
45
|
+
const refButton = useRef(null);
|
|
46
|
+
const refOpener = useRef("button");
|
|
47
|
+
const refPicked = useRef(false);
|
|
44
48
|
const refPointer = useRef(false);
|
|
45
49
|
const refKnown = useRef(current);
|
|
46
50
|
const refRefused = useRef(null);
|
|
@@ -101,8 +105,16 @@ var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled
|
|
|
101
105
|
setProblem(null);
|
|
102
106
|
setText(formatDay(day, locale));
|
|
103
107
|
if (day !== current || refRefused.current !== null) report(day, { kind: "day" });
|
|
108
|
+
refPicked.current = true;
|
|
104
109
|
setOpen(false);
|
|
105
110
|
};
|
|
111
|
+
const openFrom = (opener) => {
|
|
112
|
+
refOpener.current = opener;
|
|
113
|
+
refPicked.current = false;
|
|
114
|
+
setOpen(true);
|
|
115
|
+
};
|
|
116
|
+
/** Where the focus goes when the calendar closes: the field after a day is chosen, else whatever opened it. */
|
|
117
|
+
const focusAfterClose = () => refPicked.current || refOpener.current === "field" ? refInput.current : refButton.current;
|
|
106
118
|
/**
|
|
107
119
|
* Text is read as the person leaves the field. A day (or nothing) is taken at once; a message about text that is not a
|
|
108
120
|
* day is shown too, unless they are only on the way to the calendar: a press of the mouse on the button, or focus
|
|
@@ -130,12 +142,13 @@ var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled
|
|
|
130
142
|
const handleKeyDown = (event) => {
|
|
131
143
|
if (event.key === "ArrowDown" && event.altKey && !disabled) {
|
|
132
144
|
event.preventDefault();
|
|
133
|
-
|
|
145
|
+
openFrom("field");
|
|
134
146
|
return;
|
|
135
147
|
}
|
|
136
148
|
if (event.key === "Escape" && open) {
|
|
137
149
|
event.preventDefault();
|
|
138
150
|
event.stopPropagation();
|
|
151
|
+
refOpener.current = "field";
|
|
139
152
|
setOpen(false);
|
|
140
153
|
return;
|
|
141
154
|
}
|
|
@@ -202,11 +215,18 @@ var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled
|
|
|
202
215
|
onKeyDown: handleKeyDown
|
|
203
216
|
}), /* @__PURE__ */ jsxs(Popover, {
|
|
204
217
|
open,
|
|
205
|
-
onOpenChange:
|
|
218
|
+
onOpenChange: (next) => {
|
|
219
|
+
if (next) {
|
|
220
|
+
openFrom("button");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
setOpen(false);
|
|
224
|
+
},
|
|
206
225
|
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
207
226
|
render: /* @__PURE__ */ jsx(Button, {
|
|
208
227
|
variant: "ghost",
|
|
209
228
|
size: "icon-sm",
|
|
229
|
+
ref: refButton,
|
|
210
230
|
"data-slot": "date-picker-trigger",
|
|
211
231
|
"aria-label": labels.choose,
|
|
212
232
|
disabled,
|
|
@@ -218,7 +238,7 @@ var DatePicker = ({ id, value, onValueChange, min, max, disabledDates, disabled
|
|
|
218
238
|
anchor: refField,
|
|
219
239
|
align: "start",
|
|
220
240
|
className: "w-auto p-0",
|
|
221
|
-
finalFocus:
|
|
241
|
+
finalFocus: focusAfterClose,
|
|
222
242
|
onBlur: handleBlur,
|
|
223
243
|
children: /* @__PURE__ */ jsx(Calendar, {
|
|
224
244
|
mode: "single",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date-picker.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/date-picker/date-picker.tsx"],"sourcesContent":["import { dateToDay, dayToDate } from '@edyn/ui/components/edyn/date-range-picker';\nimport { Button } from '@edyn/ui/components/ui/button';\nimport { Calendar } from '@edyn/ui/components/ui/calendar';\nimport { Input } from '@edyn/ui/components/ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { firstWeekdayOf } from '@edyn/ui/lib/first-weekday';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCalendar } from '@tabler/icons-react';\nimport { type ChangeEvent, type FocusEvent, type KeyboardEvent, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { Locale } from 'react-day-picker';\nimport { datePatternOf, dayProblem, formatDay, parseDateText, type TDateProblem, type TDisabledDays } from './date-text';\n\n/** Every word the component prints, so a product can translate it. */\nexport interface IDatePickerLabels {\n /** The calendar button's accessible name. */\n choose: string;\n /** Said when the text is not a date; `pattern` is what to type, written the locale's way (`DD/MM/YYYY`). */\n format: (pattern: string) => string;\n notReal: string;\n /** `min` and `max` are written the locale's way. */\n beforeMin: (min: string) => string;\n afterMax: (max: string) => string;\n unavailable: string;\n}\n\nexport const DEFAULT_DATE_PICKER_LABELS: IDatePickerLabels = {\n choose: 'Choose date',\n format: (pattern) => `Enter a date as ${pattern}.`,\n notReal: 'That date does not exist.',\n beforeMin: (min) => `Choose ${min} or later.`,\n afterMax: (max) => `Choose ${max} or earlier.`,\n unavailable: 'That date is not available.',\n};\n\n/**\n * What the field holds when it reports, so a parent can tell three things apart that all arrive as `undefined`:\n * - `day`: a usable day, typed or picked.\n * - `empty`: the field was emptied, or nothing has been put in it. A required field is right to ask for a date.\n * - `refused`: the field holds text it will not take (not a day, not a real one, or outside `min`, `max` or\n * `disabledDates`). `text` is what was typed and `problem` the message the picker shows under the field, already\n * in the picker's `labels`. The picker is saying so itself, so the page should not add a second message.\n */\nexport type TDatePickerState = { kind: 'day' } | { kind: 'empty' } | { kind: 'refused'; text: string; problem: string };\n\nexport interface IDatePickerProps {\n /** For a Label's htmlFor; inside a Field the Field's label is already wired. */\n id?: string;\n /**\n * The chosen day as `yyyy-mm-dd`, or `undefined` for none (an empty string counts as none, so a value kept for an\n * `<input type=\"date\">` drops in). A string and not a Date, on purpose: a Date is an instant, and the instant for\n * \"5 March\" is another calendar day in another time zone, so a Date serialised for an API drifts a day. The text is\n * what `<input type=\"date\">`, JSON and a .NET `DateOnly` use, and it compares as a day.\n */\n value: string | undefined;\n /**\n * Called with a valid day, or with `undefined` when the field is emptied or its text is not a usable day. The second\n * argument says which of the two it was (see `TDatePickerState`); a caller that has no use for it can ignore it.\n * Text that is refused is reported each time it changes, also when the field held no day before, so a form that\n * tracks the state hears about it. Emptying the field after that reports `empty`.\n */\n onValueChange: (value: string | undefined, state: TDatePickerState) => void;\n /** The earliest and latest day that can be chosen, as `yyyy-mm-dd`, both included. */\n min?: string;\n max?: string;\n /** Days that cannot be chosen: a list of `yyyy-mm-dd`, or a function that says so for one (weekends, say). */\n disabledDates?: TDisabledDays;\n disabled?: boolean;\n /** How a day is written and in which order it is typed (BCP 47); en-GB reads 05/03/2026. */\n locale?: string;\n /** The calendar's own words (month and weekday names), as a date-fns locale; English by default. The first weekday follows `locale`. */\n calendarLocale?: Locale;\n /** What the empty field shows; the pattern for the locale (`DD/MM/YYYY`) by default. */\n placeholder?: string;\n /** An accessible name, when there is no visible label to point at. */\n 'aria-label'?: string;\n /** Marks the field invalid (the kit's destructive border), as a Field's invalid state does. */\n 'aria-invalid'?: boolean | 'true' | 'false';\n /** The id of the text that explains it. Added to what a Field names already, and to the picker's own error. */\n 'aria-describedby'?: string;\n labels?: Partial<IDatePickerLabels>;\n /** Layout only (a width); the look is the kit's. */\n className?: string;\n}\n\nconst problemText = (\n problem: TDateProblem,\n labels: IDatePickerLabels,\n locale: string,\n limits: { min?: string; max?: string },\n pattern: string,\n): string => {\n switch (problem) {\n case 'format':\n return labels.format(pattern);\n case 'notReal':\n return labels.notReal;\n case 'beforeMin':\n return labels.beforeMin(limits.min === undefined ? '' : formatDay(limits.min, locale));\n case 'afterMax':\n return labels.afterMax(limits.max === undefined ? '' : formatDay(limits.max, locale));\n default:\n return labels.unavailable;\n }\n};\n\n/**\n * One calendar day, typed or picked. The field takes the day in the locale's order (05/03/2026 in en-GB) and reads it\n * when it loses focus, saying inline what is wrong with it; the button, or Alt+ArrowDown in the field, opens a calendar.\n */\nexport const DatePicker = ({\n id,\n value,\n onValueChange,\n min,\n max,\n disabledDates,\n disabled = false,\n locale = 'en-GB',\n calendarLocale,\n placeholder,\n 'aria-label': ariaLabel,\n 'aria-invalid': ariaInvalid,\n 'aria-describedby': ariaDescribedBy,\n labels: labelOverrides,\n className,\n}: IDatePickerProps) => {\n const labels = useMemo(() => ({ ...DEFAULT_DATE_PICKER_LABELS, ...labelOverrides }), [labelOverrides]);\n const pattern = useMemo(() => datePatternOf(locale), [locale]);\n const current = value === '' ? undefined : value;\n const errorId = useId();\n const refField = useRef<HTMLDivElement | null>(null);\n const refInput = useRef<HTMLInputElement | null>(null);\n // The mouse is down inside the picker, so a blur of the field is a click on something in it, not a Tab.\n const refPointer = useRef(false);\n // The day the field last agreed on with the page, so a change from outside is told from our own report of it.\n const refKnown = useRef<string | undefined>(current);\n // The refused text last reported (with its message), or null: told apart from a fresh refusal so it is reported once,\n // and so that emptying a field that held a refused text is reported although it held no day.\n const refRefused = useRef<string | null>(null);\n const [text, setText] = useState(current === undefined ? '' : formatDay(current, locale));\n const [problem, setProblem] = useState<TDateProblem | null>(null);\n const [open, setOpen] = useState(false);\n\n useEffect(() => {\n if (current !== refKnown.current) {\n refKnown.current = current;\n refRefused.current = null;\n setText(current === undefined ? '' : formatDay(current, locale));\n setProblem(null);\n }\n }, [current, locale]);\n\n const report = (day: string | undefined, state: TDatePickerState) => {\n refKnown.current = day;\n refRefused.current = state.kind === 'refused' ? `${state.text}\\u0000${state.problem}` : null;\n onValueChange(day, state);\n };\n\n /**\n * Reads the text: a day is reported and written back in full, anything else is said inline and reported as no day,\n * with the state saying whether the field is empty or holds text it refused.\n */\n const commit = (typed: string) => {\n const parsed = parseDateText(typed, locale);\n if (parsed.kind === 'empty') {\n setProblem(null);\n if (current !== undefined || refRefused.current !== null) {\n report(undefined, { kind: 'empty' });\n }\n return;\n }\n const found = parsed.kind === 'problem' ? parsed.problem : dayProblem(parsed.day, { min, max, disabledDates });\n if (found !== undefined) {\n setProblem(found);\n const message = problemText(found, labels, locale, { min, max }, pattern);\n if (current !== undefined || refRefused.current !== `${typed}\\u0000${message}`) {\n report(undefined, { kind: 'refused', text: typed, problem: message });\n }\n return;\n }\n if (parsed.kind === 'day') {\n setProblem(null);\n setText(formatDay(parsed.day, locale));\n if (parsed.day !== current || refRefused.current !== null) {\n report(parsed.day, { kind: 'day' });\n }\n }\n };\n\n const pick = (date: Date | undefined) => {\n const day = dateToDay(date);\n if (day === undefined) {\n return;\n }\n setProblem(null);\n setText(formatDay(day, locale));\n if (day !== current || refRefused.current !== null) {\n report(day, { kind: 'day' });\n }\n setOpen(false);\n };\n\n /**\n * Text is read as the person leaves the field. A day (or nothing) is taken at once; a message about text that is not a\n * day is shown too, unless they are only on the way to the calendar: a press of the mouse on the button, or focus\n * going into the calendar that Alt+ArrowDown opened, with the text half typed. Leaving the picker for anywhere else\n * reads whatever is typed.\n */\n const handleBlur = (event: FocusEvent<HTMLElement>) => {\n const next = event.relatedTarget as Element | null;\n const intoCalendar = next?.closest('[data-slot=\"popover-content\"]') != null;\n const intoButton = next?.closest('[data-slot=\"date-picker-trigger\"]') != null;\n const typed = refInput.current?.value ?? '';\n if (!(intoCalendar || intoButton || (next !== null && refField.current?.contains(next) === true))) {\n commit(typed);\n return;\n }\n if (event.target !== refInput.current) {\n return;\n }\n const onTheWay = intoCalendar || (intoButton && refPointer.current);\n const parsed = parseDateText(typed, locale);\n const usable = parsed.kind === 'empty' || (parsed.kind === 'day' && dayProblem(parsed.day, { min, max, disabledDates }) === undefined);\n if (usable || !onTheWay) {\n commit(typed);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'ArrowDown' && event.altKey && !disabled) {\n event.preventDefault();\n setOpen(true);\n return;\n }\n // The field has no key handler of Base UI's to close the calendar, so the key would reach the Sheet or Dialog around\n // it and close that too. While the calendar is open it is this field's key; when it is closed it is the page's.\n if (event.key === 'Escape' && open) {\n event.preventDefault();\n event.stopPropagation();\n setOpen(false);\n return;\n }\n if (event.key === 'Enter') {\n const parsed = parseDateText(event.currentTarget.value, locale);\n if (parsed.kind !== 'empty' && (parsed.kind === 'problem' || dayProblem(parsed.day, { min, max, disabledDates }) !== undefined)) {\n event.preventDefault();\n }\n commit(event.currentTarget.value);\n }\n };\n\n const selected = dayToDate(current);\n const limits = { min, max };\n const invalid = problem !== null || ariaInvalid === true || ariaInvalid === 'true';\n const describedBy = [ariaDescribedBy, problem === null ? undefined : errorId].filter(Boolean).join(' ') || undefined;\n const isOff = (date: Date): boolean => {\n const day = dateToDay(date);\n return day !== undefined && dayProblem(day, { min, max, disabledDates }) !== undefined;\n };\n const today = new Date();\n const start = dayToDate(min);\n const end = dayToDate(max);\n const month = selected ?? (start !== undefined && today < start ? start : end !== undefined && today > end ? end : today);\n\n return (\n <div data-slot=\"date-picker\" className={cn('flex flex-col gap-1.5', className)}>\n <div\n ref={refField}\n className=\"relative\"\n onPointerDownCapture={() => {\n refPointer.current = true;\n }}\n onPointerUpCapture={() => {\n refPointer.current = false;\n }}\n >\n <Input\n ref={refInput}\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n data-slot=\"date-picker-input\"\n value={text}\n placeholder={placeholder ?? pattern}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={invalid ? true : undefined}\n aria-describedby={describedBy}\n className=\"pr-9\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => {\n setText(event.target.value);\n setProblem(null);\n }}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n />\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n data-slot=\"date-picker-trigger\"\n aria-label={labels.choose}\n disabled={disabled}\n className=\"absolute top-0.5 right-0.5\"\n onBlur={handleBlur}\n />\n }\n >\n <IconCalendar aria-hidden=\"true\" />\n </PopoverTrigger>\n <PopoverContent anchor={refField} align=\"start\" className=\"w-auto p-0\" finalFocus={refInput} onBlur={handleBlur}>\n <Calendar\n mode=\"single\"\n required\n autoFocus\n locale={calendarLocale}\n weekStartsOn={firstWeekdayOf(locale)}\n defaultMonth={month}\n startMonth={start}\n endMonth={end}\n selected={selected}\n disabled={isOff}\n onSelect={pick}\n />\n </PopoverContent>\n </Popover>\n </div>\n {problem !== null && (\n <p id={errorId} data-slot=\"date-picker-error\" role=\"alert\" className=\"text-sm text-destructive\">\n {problemText(problem, labels, locale, limits, pattern)}\n </p>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"date-picker.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/date-picker/date-picker.tsx"],"sourcesContent":["import { dateToDay, dayToDate } from '@edyn/ui/components/edyn/date-range-picker';\nimport { Button } from '@edyn/ui/components/ui/button';\nimport { Calendar } from '@edyn/ui/components/ui/calendar';\nimport { Input } from '@edyn/ui/components/ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { firstWeekdayOf } from '@edyn/ui/lib/first-weekday';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCalendar } from '@tabler/icons-react';\nimport { type ChangeEvent, type FocusEvent, type KeyboardEvent, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { Locale } from 'react-day-picker';\nimport { datePatternOf, dayProblem, formatDay, parseDateText, type TDateProblem, type TDisabledDays } from './date-text';\n\n/** Every word the component prints, so a product can translate it. */\nexport interface IDatePickerLabels {\n /** The calendar button's accessible name. */\n choose: string;\n /** Said when the text is not a date; `pattern` is what to type, written the locale's way (`DD/MM/YYYY`). */\n format: (pattern: string) => string;\n notReal: string;\n /** `min` and `max` are written the locale's way. */\n beforeMin: (min: string) => string;\n afterMax: (max: string) => string;\n unavailable: string;\n}\n\nexport const DEFAULT_DATE_PICKER_LABELS: IDatePickerLabels = {\n choose: 'Choose date',\n format: (pattern) => `Enter a date as ${pattern}.`,\n notReal: 'That date does not exist.',\n beforeMin: (min) => `Choose ${min} or later.`,\n afterMax: (max) => `Choose ${max} or earlier.`,\n unavailable: 'That date is not available.',\n};\n\n/**\n * What the field holds when it reports, so a parent can tell three things apart that all arrive as `undefined`:\n * - `day`: a usable day, typed or picked.\n * - `empty`: the field was emptied, or nothing has been put in it. A required field is right to ask for a date.\n * - `refused`: the field holds text it will not take (not a day, not a real one, or outside `min`, `max` or\n * `disabledDates`). `text` is what was typed and `problem` the message the picker shows under the field, already\n * in the picker's `labels`. The picker is saying so itself, so the page should not add a second message.\n */\nexport type TDatePickerState = { kind: 'day' } | { kind: 'empty' } | { kind: 'refused'; text: string; problem: string };\n\nexport interface IDatePickerProps {\n /** For a Label's htmlFor; inside a Field the Field's label is already wired. */\n id?: string;\n /**\n * The chosen day as `yyyy-mm-dd`, or `undefined` for none (an empty string counts as none, so a value kept for an\n * `<input type=\"date\">` drops in). A string and not a Date, on purpose: a Date is an instant, and the instant for\n * \"5 March\" is another calendar day in another time zone, so a Date serialised for an API drifts a day. The text is\n * what `<input type=\"date\">`, JSON and a .NET `DateOnly` use, and it compares as a day.\n */\n value: string | undefined;\n /**\n * Called with a valid day, or with `undefined` when the field is emptied or its text is not a usable day. The second\n * argument says which of the two it was (see `TDatePickerState`); a caller that has no use for it can ignore it.\n * Text that is refused is reported each time it changes, also when the field held no day before, so a form that\n * tracks the state hears about it. Emptying the field after that reports `empty`.\n */\n onValueChange: (value: string | undefined, state: TDatePickerState) => void;\n /** The earliest and latest day that can be chosen, as `yyyy-mm-dd`, both included. */\n min?: string;\n max?: string;\n /** Days that cannot be chosen: a list of `yyyy-mm-dd`, or a function that says so for one (weekends, say). */\n disabledDates?: TDisabledDays;\n disabled?: boolean;\n /** How a day is written and in which order it is typed (BCP 47); en-GB reads 05/03/2026. */\n locale?: string;\n /** The calendar's own words (month and weekday names), as a date-fns locale; English by default. The first weekday follows `locale`. */\n calendarLocale?: Locale;\n /** What the empty field shows; the pattern for the locale (`DD/MM/YYYY`) by default. */\n placeholder?: string;\n /** An accessible name, when there is no visible label to point at. */\n 'aria-label'?: string;\n /** Marks the field invalid (the kit's destructive border), as a Field's invalid state does. */\n 'aria-invalid'?: boolean | 'true' | 'false';\n /** The id of the text that explains it. Added to what a Field names already, and to the picker's own error. */\n 'aria-describedby'?: string;\n labels?: Partial<IDatePickerLabels>;\n /** Layout only (a width); the look is the kit's. */\n className?: string;\n}\n\nconst problemText = (\n problem: TDateProblem,\n labels: IDatePickerLabels,\n locale: string,\n limits: { min?: string; max?: string },\n pattern: string,\n): string => {\n switch (problem) {\n case 'format':\n return labels.format(pattern);\n case 'notReal':\n return labels.notReal;\n case 'beforeMin':\n return labels.beforeMin(limits.min === undefined ? '' : formatDay(limits.min, locale));\n case 'afterMax':\n return labels.afterMax(limits.max === undefined ? '' : formatDay(limits.max, locale));\n default:\n return labels.unavailable;\n }\n};\n\n/**\n * One calendar day, typed or picked. The field takes the day in the locale's order (05/03/2026 in en-GB) and reads it\n * when it loses focus, saying inline what is wrong with it; the button, or Alt+ArrowDown in the field, opens a calendar.\n * Escape closes the calendar and gives the focus back to whichever of the two opened it; a day picked puts it on the field.\n */\nexport const DatePicker = ({\n id,\n value,\n onValueChange,\n min,\n max,\n disabledDates,\n disabled = false,\n locale = 'en-GB',\n calendarLocale,\n placeholder,\n 'aria-label': ariaLabel,\n 'aria-invalid': ariaInvalid,\n 'aria-describedby': ariaDescribedBy,\n labels: labelOverrides,\n className,\n}: IDatePickerProps) => {\n const labels = useMemo(() => ({ ...DEFAULT_DATE_PICKER_LABELS, ...labelOverrides }), [labelOverrides]);\n const pattern = useMemo(() => datePatternOf(locale), [locale]);\n const current = value === '' ? undefined : value;\n const errorId = useId();\n const refField = useRef<HTMLDivElement | null>(null);\n const refInput = useRef<HTMLInputElement | null>(null);\n const refButton = useRef<HTMLButtonElement | null>(null);\n // What opened the calendar, so that Escape gives the focus back to it: the button when the button did it, the field\n // when Alt+ArrowDown did. Choosing a day is different (see `pick`): the field then shows the day, so it gets the focus.\n const refOpener = useRef<'button' | 'field'>('button');\n const refPicked = useRef(false);\n // The mouse is down inside the picker, so a blur of the field is a click on something in it, not a Tab.\n const refPointer = useRef(false);\n // The day the field last agreed on with the page, so a change from outside is told from our own report of it.\n const refKnown = useRef<string | undefined>(current);\n // The refused text last reported (with its message), or null: told apart from a fresh refusal so it is reported once,\n // and so that emptying a field that held a refused text is reported although it held no day.\n const refRefused = useRef<string | null>(null);\n const [text, setText] = useState(current === undefined ? '' : formatDay(current, locale));\n const [problem, setProblem] = useState<TDateProblem | null>(null);\n const [open, setOpen] = useState(false);\n\n useEffect(() => {\n if (current !== refKnown.current) {\n refKnown.current = current;\n refRefused.current = null;\n setText(current === undefined ? '' : formatDay(current, locale));\n setProblem(null);\n }\n }, [current, locale]);\n\n const report = (day: string | undefined, state: TDatePickerState) => {\n refKnown.current = day;\n refRefused.current = state.kind === 'refused' ? `${state.text}\\u0000${state.problem}` : null;\n onValueChange(day, state);\n };\n\n /**\n * Reads the text: a day is reported and written back in full, anything else is said inline and reported as no day,\n * with the state saying whether the field is empty or holds text it refused.\n */\n const commit = (typed: string) => {\n const parsed = parseDateText(typed, locale);\n if (parsed.kind === 'empty') {\n setProblem(null);\n if (current !== undefined || refRefused.current !== null) {\n report(undefined, { kind: 'empty' });\n }\n return;\n }\n const found = parsed.kind === 'problem' ? parsed.problem : dayProblem(parsed.day, { min, max, disabledDates });\n if (found !== undefined) {\n setProblem(found);\n const message = problemText(found, labels, locale, { min, max }, pattern);\n if (current !== undefined || refRefused.current !== `${typed}\\u0000${message}`) {\n report(undefined, { kind: 'refused', text: typed, problem: message });\n }\n return;\n }\n if (parsed.kind === 'day') {\n setProblem(null);\n setText(formatDay(parsed.day, locale));\n if (parsed.day !== current || refRefused.current !== null) {\n report(parsed.day, { kind: 'day' });\n }\n }\n };\n\n const pick = (date: Date | undefined) => {\n const day = dateToDay(date);\n if (day === undefined) {\n return;\n }\n setProblem(null);\n setText(formatDay(day, locale));\n if (day !== current || refRefused.current !== null) {\n report(day, { kind: 'day' });\n }\n refPicked.current = true;\n setOpen(false);\n };\n\n const openFrom = (opener: 'button' | 'field') => {\n refOpener.current = opener;\n refPicked.current = false;\n setOpen(true);\n };\n\n /** Where the focus goes when the calendar closes: the field after a day is chosen, else whatever opened it. */\n const focusAfterClose = (): HTMLElement | null => (refPicked.current || refOpener.current === 'field' ? refInput.current : refButton.current);\n\n /**\n * Text is read as the person leaves the field. A day (or nothing) is taken at once; a message about text that is not a\n * day is shown too, unless they are only on the way to the calendar: a press of the mouse on the button, or focus\n * going into the calendar that Alt+ArrowDown opened, with the text half typed. Leaving the picker for anywhere else\n * reads whatever is typed.\n */\n const handleBlur = (event: FocusEvent<HTMLElement>) => {\n const next = event.relatedTarget as Element | null;\n const intoCalendar = next?.closest('[data-slot=\"popover-content\"]') != null;\n const intoButton = next?.closest('[data-slot=\"date-picker-trigger\"]') != null;\n const typed = refInput.current?.value ?? '';\n if (!(intoCalendar || intoButton || (next !== null && refField.current?.contains(next) === true))) {\n commit(typed);\n return;\n }\n if (event.target !== refInput.current) {\n return;\n }\n const onTheWay = intoCalendar || (intoButton && refPointer.current);\n const parsed = parseDateText(typed, locale);\n const usable = parsed.kind === 'empty' || (parsed.kind === 'day' && dayProblem(parsed.day, { min, max, disabledDates }) === undefined);\n if (usable || !onTheWay) {\n commit(typed);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'ArrowDown' && event.altKey && !disabled) {\n event.preventDefault();\n openFrom('field');\n return;\n }\n // The field has no key handler of Base UI's to close the calendar, so the key would reach the Sheet or Dialog around\n // it and close that too. While the calendar is open it is this field's key; when it is closed it is the page's.\n if (event.key === 'Escape' && open) {\n event.preventDefault();\n event.stopPropagation();\n // The focus is on the field already, whatever opened the calendar: it stays there.\n refOpener.current = 'field';\n setOpen(false);\n return;\n }\n if (event.key === 'Enter') {\n const parsed = parseDateText(event.currentTarget.value, locale);\n if (parsed.kind !== 'empty' && (parsed.kind === 'problem' || dayProblem(parsed.day, { min, max, disabledDates }) !== undefined)) {\n event.preventDefault();\n }\n commit(event.currentTarget.value);\n }\n };\n\n const selected = dayToDate(current);\n const limits = { min, max };\n const invalid = problem !== null || ariaInvalid === true || ariaInvalid === 'true';\n const describedBy = [ariaDescribedBy, problem === null ? undefined : errorId].filter(Boolean).join(' ') || undefined;\n const isOff = (date: Date): boolean => {\n const day = dateToDay(date);\n return day !== undefined && dayProblem(day, { min, max, disabledDates }) !== undefined;\n };\n const today = new Date();\n const start = dayToDate(min);\n const end = dayToDate(max);\n const month = selected ?? (start !== undefined && today < start ? start : end !== undefined && today > end ? end : today);\n\n return (\n <div data-slot=\"date-picker\" className={cn('flex flex-col gap-1.5', className)}>\n <div\n ref={refField}\n className=\"relative\"\n onPointerDownCapture={() => {\n refPointer.current = true;\n }}\n onPointerUpCapture={() => {\n refPointer.current = false;\n }}\n >\n <Input\n ref={refInput}\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n data-slot=\"date-picker-input\"\n value={text}\n placeholder={placeholder ?? pattern}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={invalid ? true : undefined}\n aria-describedby={describedBy}\n className=\"pr-9\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => {\n setText(event.target.value);\n setProblem(null);\n }}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n />\n <Popover\n open={open}\n onOpenChange={(next) => {\n // Only the button opens it from here (Alt+ArrowDown in the field sets the state itself, through `openFrom`).\n if (next) {\n openFrom('button');\n return;\n }\n setOpen(false);\n }}\n >\n <PopoverTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n ref={refButton}\n data-slot=\"date-picker-trigger\"\n aria-label={labels.choose}\n disabled={disabled}\n className=\"absolute top-0.5 right-0.5\"\n onBlur={handleBlur}\n />\n }\n >\n <IconCalendar aria-hidden=\"true\" />\n </PopoverTrigger>\n <PopoverContent anchor={refField} align=\"start\" className=\"w-auto p-0\" finalFocus={focusAfterClose} onBlur={handleBlur}>\n <Calendar\n mode=\"single\"\n required\n autoFocus\n locale={calendarLocale}\n weekStartsOn={firstWeekdayOf(locale)}\n defaultMonth={month}\n startMonth={start}\n endMonth={end}\n selected={selected}\n disabled={isOff}\n onSelect={pick}\n />\n </PopoverContent>\n </Popover>\n </div>\n {problem !== null && (\n <p id={errorId} data-slot=\"date-picker-error\" role=\"alert\" className=\"text-sm text-destructive\">\n {problemText(problem, labels, locale, limits, pattern)}\n </p>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAyBA,IAAa,6BAAgD;CAC3D,QAAQ;CACR,SAAS,YAAY,mBAAmB,QAAQ;CAChD,SAAS;CACT,YAAY,QAAQ,UAAU,IAAI;CAClC,WAAW,QAAQ,UAAU,IAAI;CACjC,aAAa;AACf;AAoDA,IAAM,eACJ,SACA,QACA,QACA,QACA,YACW;CACX,QAAQ,SAAR;EACE,KAAK,UACH,OAAO,OAAO,OAAO,OAAO;EAC9B,KAAK,WACH,OAAO,OAAO;EAChB,KAAK,aACH,OAAO,OAAO,UAAU,OAAO,QAAQ,KAAA,IAAY,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC;EACvF,KAAK,YACH,OAAO,OAAO,SAAS,OAAO,QAAQ,KAAA,IAAY,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC;EACtF,SACE,OAAO,OAAO;CAClB;AACF;;;;;;AAOA,IAAa,cAAc,EACzB,IACA,OACA,eACA,KACA,KACA,eACA,WAAW,OACX,SAAS,SACT,gBACA,aACA,cAAc,WACd,gBAAgB,aAChB,oBAAoB,iBACpB,QAAQ,gBACR,gBACsB;CACtB,MAAM,SAAS,eAAe;EAAE,GAAG;EAA4B,GAAG;CAAe,IAAI,CAAC,cAAc,CAAC;CACrG,MAAM,UAAU,cAAc,cAAc,MAAM,GAAG,CAAC,MAAM,CAAC;CAC7D,MAAM,UAAU,UAAU,KAAK,KAAA,IAAY;CAC3C,MAAM,UAAU,MAAM;CACtB,MAAM,WAAW,OAA8B,IAAI;CACnD,MAAM,WAAW,OAAgC,IAAI;CACrD,MAAM,YAAY,OAAiC,IAAI;CAGvD,MAAM,YAAY,OAA2B,QAAQ;CACrD,MAAM,YAAY,OAAO,KAAK;CAE9B,MAAM,aAAa,OAAO,KAAK;CAE/B,MAAM,WAAW,OAA2B,OAAO;CAGnD,MAAM,aAAa,OAAsB,IAAI;CAC7C,MAAM,CAAC,MAAM,WAAW,SAAS,YAAY,KAAA,IAAY,KAAK,UAAU,SAAS,MAAM,CAAC;CACxF,MAAM,CAAC,SAAS,cAAc,SAA8B,IAAI;CAChE,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,gBAAgB;EACd,IAAI,YAAY,SAAS,SAAS;GAChC,SAAS,UAAU;GACnB,WAAW,UAAU;GACrB,QAAQ,YAAY,KAAA,IAAY,KAAK,UAAU,SAAS,MAAM,CAAC;GAC/D,WAAW,IAAI;EACjB;CACF,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,MAAM,UAAU,KAAyB,UAA4B;EACnE,SAAS,UAAU;EACnB,WAAW,UAAU,MAAM,SAAS,YAAY,GAAG,MAAM,KAAK,QAAQ,MAAM,YAAY;EACxF,cAAc,KAAK,KAAK;CAC1B;;;;;CAMA,MAAM,UAAU,UAAkB;EAChC,MAAM,SAAS,cAAc,OAAO,MAAM;EAC1C,IAAI,OAAO,SAAS,SAAS;GAC3B,WAAW,IAAI;GACf,IAAI,YAAY,KAAA,KAAa,WAAW,YAAY,MAClD,OAAO,KAAA,GAAW,EAAE,MAAM,QAAQ,CAAC;GAErC;EACF;EACA,MAAM,QAAQ,OAAO,SAAS,YAAY,OAAO,UAAU,WAAW,OAAO,KAAK;GAAE;GAAK;GAAK;EAAc,CAAC;EAC7G,IAAI,UAAU,KAAA,GAAW;GACvB,WAAW,KAAK;GAChB,MAAM,UAAU,YAAY,OAAO,QAAQ,QAAQ;IAAE;IAAK;GAAI,GAAG,OAAO;GACxE,IAAI,YAAY,KAAA,KAAa,WAAW,YAAY,GAAG,MAAM,QAAQ,WACnE,OAAO,KAAA,GAAW;IAAE,MAAM;IAAW,MAAM;IAAO,SAAS;GAAQ,CAAC;GAEtE;EACF;EACA,IAAI,OAAO,SAAS,OAAO;GACzB,WAAW,IAAI;GACf,QAAQ,UAAU,OAAO,KAAK,MAAM,CAAC;GACrC,IAAI,OAAO,QAAQ,WAAW,WAAW,YAAY,MACnD,OAAO,OAAO,KAAK,EAAE,MAAM,MAAM,CAAC;EAEtC;CACF;CAEA,MAAM,QAAQ,SAA2B;EACvC,MAAM,MAAM,UAAU,IAAI;EAC1B,IAAI,QAAQ,KAAA,GACV;EAEF,WAAW,IAAI;EACf,QAAQ,UAAU,KAAK,MAAM,CAAC;EAC9B,IAAI,QAAQ,WAAW,WAAW,YAAY,MAC5C,OAAO,KAAK,EAAE,MAAM,MAAM,CAAC;EAE7B,UAAU,UAAU;EACpB,QAAQ,KAAK;CACf;CAEA,MAAM,YAAY,WAA+B;EAC/C,UAAU,UAAU;EACpB,UAAU,UAAU;EACpB,QAAQ,IAAI;CACd;;CAGA,MAAM,wBAA6C,UAAU,WAAW,UAAU,YAAY,UAAU,SAAS,UAAU,UAAU;;;;;;;CAQrI,MAAM,cAAc,UAAmC;EACrD,MAAM,OAAO,MAAM;EACnB,MAAM,eAAe,MAAM,QAAQ,iCAA+B,KAAK;EACvE,MAAM,aAAa,MAAM,QAAQ,qCAAmC,KAAK;EACzE,MAAM,QAAQ,SAAS,SAAS,SAAS;EACzC,IAAI,EAAE,gBAAgB,cAAe,SAAS,QAAQ,SAAS,SAAS,SAAS,IAAI,MAAM,OAAQ;GACjG,OAAO,KAAK;GACZ;EACF;EACA,IAAI,MAAM,WAAW,SAAS,SAC5B;EAEF,MAAM,WAAW,gBAAiB,cAAc,WAAW;EAC3D,MAAM,SAAS,cAAc,OAAO,MAAM;EAE1C,IADe,OAAO,SAAS,WAAY,OAAO,SAAS,SAAS,WAAW,OAAO,KAAK;GAAE;GAAK;GAAK;EAAc,CAAC,MAAM,KAAA,KAC9G,CAAC,UACb,OAAO,KAAK;CAEhB;CAEA,MAAM,iBAAiB,UAA2C;EAChE,IAAI,MAAM,QAAQ,eAAe,MAAM,UAAU,CAAC,UAAU;GAC1D,MAAM,eAAe;GACrB,SAAS,OAAO;GAChB;EACF;EAGA,IAAI,MAAM,QAAQ,YAAY,MAAM;GAClC,MAAM,eAAe;GACrB,MAAM,gBAAgB;GAEtB,UAAU,UAAU;GACpB,QAAQ,KAAK;GACb;EACF;EACA,IAAI,MAAM,QAAQ,SAAS;GACzB,MAAM,SAAS,cAAc,MAAM,cAAc,OAAO,MAAM;GAC9D,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,aAAa,WAAW,OAAO,KAAK;IAAE;IAAK;IAAK;GAAc,CAAC,MAAM,KAAA,IACnH,MAAM,eAAe;GAEvB,OAAO,MAAM,cAAc,KAAK;EAClC;CACF;CAEA,MAAM,WAAW,UAAU,OAAO;CAClC,MAAM,SAAS;EAAE;EAAK;CAAI;CAC1B,MAAM,UAAU,YAAY,QAAQ,gBAAgB,QAAQ,gBAAgB;CAC5E,MAAM,cAAc,CAAC,iBAAiB,YAAY,OAAO,KAAA,IAAY,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;CAC3G,MAAM,SAAS,SAAwB;EACrC,MAAM,MAAM,UAAU,IAAI;EAC1B,OAAO,QAAQ,KAAA,KAAa,WAAW,KAAK;GAAE;GAAK;GAAK;EAAc,CAAC,MAAM,KAAA;CAC/E;CACA,MAAM,wBAAQ,IAAI,KAAK;CACvB,MAAM,QAAQ,UAAU,GAAG;CAC3B,MAAM,MAAM,UAAU,GAAG;CACzB,MAAM,QAAQ,aAAa,UAAU,KAAA,KAAa,QAAQ,QAAQ,QAAQ,QAAQ,KAAA,KAAa,QAAQ,MAAM,MAAM;CAEnH,OACE,qBAAC,OAAD;EAAK,aAAU;EAAc,WAAW,GAAG,yBAAyB,SAAS;EAA7E,UAAA,CACE,qBAAC,OAAD;GACE,KAAK;GACL,WAAU;GACV,4BAA4B;IAC1B,WAAW,UAAU;GACvB;GACA,0BAA0B;IACxB,WAAW,UAAU;GACvB;GARF,UAAA,CAUE,oBAAC,OAAD;IACE,KAAK;IACD;IACJ,MAAK;IACL,WAAU;IACV,cAAa;IACb,aAAU;IACV,OAAO;IACP,aAAa,eAAe;IAClB;IACV,cAAY;IACZ,gBAAc,UAAU,OAAO,KAAA;IAC/B,oBAAkB;IAClB,WAAU;IACV,WAAW,UAAyC;KAClD,QAAQ,MAAM,OAAO,KAAK;KAC1B,WAAW,IAAI;IACjB;IACA,QAAQ;IACR,WAAW;GACZ,CAAA,GACD,qBAAC,SAAD;IACQ;IACN,eAAe,SAAS;KAEtB,IAAI,MAAM;MACR,SAAS,QAAQ;MACjB;KACF;KACA,QAAQ,KAAK;IACf;IATF,UAAA,CAWE,oBAAC,gBAAD;KACE,QACE,oBAAC,QAAD;MACE,SAAQ;MACR,MAAK;MACL,KAAK;MACL,aAAU;MACV,cAAY,OAAO;MACT;MACV,WAAU;MACV,QAAQ;KACT,CAAA;KAGH,UAAA,oBAAC,cAAD,EAAc,eAAY,OAAQ,CAAA;IACpB,CAAA,GAChB,oBAAC,gBAAD;KAAgB,QAAQ;KAAU,OAAM;KAAQ,WAAU;KAAa,YAAY;KAAiB,QAAQ;KAC1G,UAAA,oBAAC,UAAD;MACE,MAAK;MACL,UAAA;MACA,WAAA;MACA,QAAQ;MACR,cAAc,eAAe,MAAM;MACnC,cAAc;MACd,YAAY;MACZ,UAAU;MACA;MACV,UAAU;MACV,UAAU;KACX,CAAA;IACa,CAAA,CACT;GACN,CAAA,CAAA;EACJ,CAAA,GAAA,YAAY,QACX,oBAAC,KAAD;GAAG,IAAI;GAAS,aAAU;GAAoB,MAAK;GAAQ,WAAU;GAClE,UAAA,YAAY,SAAS,QAAQ,QAAQ,QAAQ,OAAO;EACpD,CAAA,CAEF;;AAET"}
|
|
@@ -9,6 +9,16 @@ import { IconCalendar } from "@tabler/icons-react";
|
|
|
9
9
|
//#region ../ui/src/components/edyn/date-range-picker/date-range-picker.tsx
|
|
10
10
|
var dayToDate = (value) => value === void 0 ? void 0 : /* @__PURE__ */ new Date(`${value}T12:00:00`);
|
|
11
11
|
var dateToDay = (date) => date === void 0 ? void 0 : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
12
|
+
/**
|
|
13
|
+
* The trigger's accessible name when it is given an `aria-label`: the label, then what the button shows ("Created between:
|
|
14
|
+
* 01 Mar 2026 – 05 Mar 2026"). An aria-label replaces the text inside the button, so on its own it hides the chosen dates from
|
|
15
|
+
* a screen reader and breaks WCAG 2.5.3 (Label in Name: the visible text must be part of the name, so that a person who says
|
|
16
|
+
* what they see can operate it). A label that already contains the visible text is left as it is.
|
|
17
|
+
*/
|
|
18
|
+
var nameWith = (label, shown) => {
|
|
19
|
+
if (label === void 0) return;
|
|
20
|
+
return label.toLowerCase().includes(shown.toLowerCase()) ? label : `${label}: ${shown}`;
|
|
21
|
+
};
|
|
12
22
|
/** A range of calendar days, either end optional; two months side by side, one on a phone. */
|
|
13
23
|
var DateRangePicker = ({ id, value, onValueChange, placeholder = "Select date range", locale = "en-GB", summary = "range", "aria-label": ariaLabel, className, ...props }) => {
|
|
14
24
|
const isMobile = useIsMobile();
|
|
@@ -20,11 +30,12 @@ var DateRangePicker = ({ id, value, onValueChange, placeholder = "Select date ra
|
|
|
20
30
|
year: "numeric"
|
|
21
31
|
});
|
|
22
32
|
const ends = [from, to].filter((date) => date !== void 0).map((date) => format.format(date));
|
|
33
|
+
const shown = ends.length === 0 || summary === "label" ? placeholder : ends.join(" – ");
|
|
23
34
|
return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
|
|
24
35
|
render: /* @__PURE__ */ jsx(Button, {
|
|
25
36
|
...props,
|
|
26
37
|
id,
|
|
27
|
-
"aria-label": ariaLabel,
|
|
38
|
+
"aria-label": nameWith(ariaLabel, shown),
|
|
28
39
|
"data-slot": "date-range-picker-trigger",
|
|
29
40
|
"data-set": ends.length > 0 ? "" : void 0,
|
|
30
41
|
variant: "outline",
|
|
@@ -32,7 +43,7 @@ var DateRangePicker = ({ id, value, onValueChange, placeholder = "Select date ra
|
|
|
32
43
|
}),
|
|
33
44
|
children: [/* @__PURE__ */ jsx(IconCalendar, { "aria-hidden": "true" }), /* @__PURE__ */ jsx("span", {
|
|
34
45
|
className: "truncate",
|
|
35
|
-
children:
|
|
46
|
+
children: shown
|
|
36
47
|
})]
|
|
37
48
|
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
38
49
|
align: "start",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date-range-picker.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/date-range-picker/date-range-picker.tsx"],"sourcesContent":["import { Button } from '@edyn/ui/components/ui/button';\nimport { Calendar } from '@edyn/ui/components/ui/calendar';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { useIsMobile } from '@edyn/ui/hooks/use-mobile';\nimport { firstWeekdayOf } from '@edyn/ui/lib/first-weekday';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCalendar } from '@tabler/icons-react';\nimport type { ComponentPropsWithoutRef } from 'react';\n\n/** A range of calendar days as yyyy-mm-dd, either end optional. */\nexport type TDateRange = { from?: string; to?: string };\n\n// A calendar day is read and written at midday local time, so no time zone or daylight\n// saving change can move it onto the day before or after.\nexport const dayToDate = (value: string | undefined): Date | undefined => (value === undefined ? undefined : new Date(`${value}T12:00:00`));\n\nexport const dateToDay = (date: Date | undefined): string | undefined =>\n date === undefined ? undefined : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;\n\n/** Anything else a button takes (data-*, aria-*, title) goes to the trigger. */\nexport interface IDateRangePickerProps\n extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'defaultValue' | 'placeholder' | 'id' | 'className' | 'children' | 'onChange' | 'type'> {\n id?: string;\n value: TDateRange;\n onValueChange: (value: TDateRange) => void;\n placeholder?: string;\n /**\n * What the trigger says once a range is set. `range` (default) writes the ends; `label` keeps the label, so a\n * range the page shows elsewhere (as a removable chip, say) is not repeated here. In both, the trigger carries\n * `data-set` while either end is set, for a look of its own.\n */\n summary?: 'range' | 'label';\n /** How the ends are written on the trigger, and which weekday the calendar starts on (BCP 47); en-GB reads 05 Mar 2026 and starts on Monday. */\n locale?: string;\n /** An accessible name for the trigger, when there is no visible label to point at. */\n 'aria-label'?: string;\n className?: string;\n}\n\n/** A range of calendar days, either end optional; two months side by side, one on a phone. */\nexport const DateRangePicker = ({\n id,\n value,\n onValueChange,\n placeholder = 'Select date range',\n locale = 'en-GB',\n summary = 'range',\n 'aria-label': ariaLabel,\n className,\n ...props\n}: IDateRangePickerProps) => {\n const isMobile = useIsMobile();\n const from = dayToDate(value.from);\n const to = dayToDate(value.to);\n const format = new Intl.DateTimeFormat(locale, { day: '2-digit', month: 'short', year: 'numeric' });\n const ends = [from, to].filter((date) => date !== undefined).map((date) => format.format(date));\n return (\n <Popover>\n <PopoverTrigger\n render={\n <Button\n {...props}\n id={id}\n aria-label={ariaLabel}\n data-slot=\"date-range-picker-trigger\"\n data-set={ends.length > 0 ? '' : undefined}\n variant=\"outline\"\n className={cn('w-full min-w-0 justify-start font-normal', ends.length === 0 && 'text-muted-foreground', className)}\n />\n }\n >\n <IconCalendar aria-hidden=\"true\" />\n <span className=\"truncate\">{
|
|
1
|
+
{"version":3,"file":"date-range-picker.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/date-range-picker/date-range-picker.tsx"],"sourcesContent":["import { Button } from '@edyn/ui/components/ui/button';\nimport { Calendar } from '@edyn/ui/components/ui/calendar';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { useIsMobile } from '@edyn/ui/hooks/use-mobile';\nimport { firstWeekdayOf } from '@edyn/ui/lib/first-weekday';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCalendar } from '@tabler/icons-react';\nimport type { ComponentPropsWithoutRef } from 'react';\n\n/** A range of calendar days as yyyy-mm-dd, either end optional. */\nexport type TDateRange = { from?: string; to?: string };\n\n// A calendar day is read and written at midday local time, so no time zone or daylight\n// saving change can move it onto the day before or after.\nexport const dayToDate = (value: string | undefined): Date | undefined => (value === undefined ? undefined : new Date(`${value}T12:00:00`));\n\nexport const dateToDay = (date: Date | undefined): string | undefined =>\n date === undefined ? undefined : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;\n\n/** Anything else a button takes (data-*, aria-*, title) goes to the trigger. */\nexport interface IDateRangePickerProps\n extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'defaultValue' | 'placeholder' | 'id' | 'className' | 'children' | 'onChange' | 'type'> {\n id?: string;\n value: TDateRange;\n onValueChange: (value: TDateRange) => void;\n placeholder?: string;\n /**\n * What the trigger says once a range is set. `range` (default) writes the ends; `label` keeps the label, so a\n * range the page shows elsewhere (as a removable chip, say) is not repeated here. In both, the trigger carries\n * `data-set` while either end is set, for a look of its own.\n */\n summary?: 'range' | 'label';\n /** How the ends are written on the trigger, and which weekday the calendar starts on (BCP 47); en-GB reads 05 Mar 2026 and starts on Monday. */\n locale?: string;\n /** An accessible name for the trigger, when there is no visible label to point at. */\n 'aria-label'?: string;\n className?: string;\n}\n\n/**\n * The trigger's accessible name when it is given an `aria-label`: the label, then what the button shows (\"Created between:\n * 01 Mar 2026 – 05 Mar 2026\"). An aria-label replaces the text inside the button, so on its own it hides the chosen dates from\n * a screen reader and breaks WCAG 2.5.3 (Label in Name: the visible text must be part of the name, so that a person who says\n * what they see can operate it). A label that already contains the visible text is left as it is.\n */\nconst nameWith = (label: string | undefined, shown: string): string | undefined => {\n if (label === undefined) {\n return undefined;\n }\n return label.toLowerCase().includes(shown.toLowerCase()) ? label : `${label}: ${shown}`;\n};\n\n/** A range of calendar days, either end optional; two months side by side, one on a phone. */\nexport const DateRangePicker = ({\n id,\n value,\n onValueChange,\n placeholder = 'Select date range',\n locale = 'en-GB',\n summary = 'range',\n 'aria-label': ariaLabel,\n className,\n ...props\n}: IDateRangePickerProps) => {\n const isMobile = useIsMobile();\n const from = dayToDate(value.from);\n const to = dayToDate(value.to);\n const format = new Intl.DateTimeFormat(locale, { day: '2-digit', month: 'short', year: 'numeric' });\n const ends = [from, to].filter((date) => date !== undefined).map((date) => format.format(date));\n const shown = ends.length === 0 || summary === 'label' ? placeholder : ends.join(' – ');\n return (\n <Popover>\n <PopoverTrigger\n render={\n <Button\n {...props}\n id={id}\n aria-label={nameWith(ariaLabel, shown)}\n data-slot=\"date-range-picker-trigger\"\n data-set={ends.length > 0 ? '' : undefined}\n variant=\"outline\"\n className={cn('w-full min-w-0 justify-start font-normal', ends.length === 0 && 'text-muted-foreground', className)}\n />\n }\n >\n <IconCalendar aria-hidden=\"true\" />\n <span className=\"truncate\">{shown}</span>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-auto p-0\">\n <Calendar\n mode=\"range\"\n defaultMonth={from}\n numberOfMonths={isMobile ? 1 : 2}\n weekStartsOn={firstWeekdayOf(locale)}\n selected={{ from, to }}\n onSelect={(range) => onValueChange({ from: dateToDay(range?.from), to: dateToDay(range?.to) })}\n />\n </PopoverContent>\n </Popover>\n );\n};\n"],"mappings":";;;;;;;;;AAcA,IAAa,aAAa,UAAiD,UAAU,KAAA,IAAY,KAAA,oBAAY,IAAI,KAAK,GAAG,MAAM,UAAU;AAEzI,IAAa,aAAa,SACxB,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,KAAK,YAAY,EAAE,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;;;;;;;AA4BlJ,IAAM,YAAY,OAA2B,UAAsC;CACjF,IAAI,UAAU,KAAA,GACZ;CAEF,OAAO,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,YAAY,CAAC,IAAI,QAAQ,GAAG,MAAM,IAAI;AAClF;;AAGA,IAAa,mBAAmB,EAC9B,IACA,OACA,eACA,cAAc,qBACd,SAAS,SACT,UAAU,SACV,cAAc,WACd,WACA,GAAG,YACwB;CAC3B,MAAM,WAAW,YAAY;CAC7B,MAAM,OAAO,UAAU,MAAM,IAAI;CACjC,MAAM,KAAK,UAAU,MAAM,EAAE;CAC7B,MAAM,SAAS,IAAI,KAAK,eAAe,QAAQ;EAAE,KAAK;EAAW,OAAO;EAAS,MAAM;CAAU,CAAC;CAClG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,SAAS,SAAS,KAAA,CAAS,CAAC,CAAC,KAAK,SAAS,OAAO,OAAO,IAAI,CAAC;CAC9F,MAAM,QAAQ,KAAK,WAAW,KAAK,YAAY,UAAU,cAAc,KAAK,KAAK,KAAK;CACtF,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,qBAAC,gBAAD;EACE,QACE,oBAAC,QAAD;GACE,GAAI;GACA;GACJ,cAAY,SAAS,WAAW,KAAK;GACrC,aAAU;GACV,YAAU,KAAK,SAAS,IAAI,KAAK,KAAA;GACjC,SAAQ;GACR,WAAW,GAAG,4CAA4C,KAAK,WAAW,KAAK,yBAAyB,SAAS;EAClH,CAAA;EAVL,UAAA,CAaE,oBAAC,cAAD,EAAc,eAAY,OAAQ,CAAA,GAClC,oBAAC,QAAD;GAAM,WAAU;GAAY,UAAA;EAAY,CAAA,CAC1B;CAChB,CAAA,GAAA,oBAAC,gBAAD;EAAgB,OAAM;EAAQ,WAAU;EACtC,UAAA,oBAAC,UAAD;GACE,MAAK;GACL,cAAc;GACd,gBAAgB,WAAW,IAAI;GAC/B,cAAc,eAAe,MAAM;GACnC,UAAU;IAAE;IAAM;GAAG;GACrB,WAAW,UAAU,cAAc;IAAE,MAAM,UAAU,OAAO,IAAI;IAAG,IAAI,UAAU,OAAO,EAAE;GAAE,CAAC;EAC9F,CAAA;CACa,CAAA,CACT,EAAA,CAAA;AAEb"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { useExposedFocusGuards } from "../../../lib/focus-guards.js";
|
|
2
3
|
import { ScrollArea } from "../../ui/scroll-area/scroll-area.js";
|
|
3
4
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip/tooltip.js";
|
|
4
5
|
import { popupItemClass } from "../../../lib/popup-list.js";
|
|
@@ -147,6 +148,11 @@ var Options = ({ scroller, scrollTo, busy, highlightedValue }) => {
|
|
|
147
148
|
})
|
|
148
149
|
});
|
|
149
150
|
};
|
|
151
|
+
/** Rendered inside the portal, so it exists only while the list is open: the focus guards around the list are not aria-hidden. */
|
|
152
|
+
var ExposedFocusGuards = () => {
|
|
153
|
+
useExposedFocusGuards();
|
|
154
|
+
return null;
|
|
155
|
+
};
|
|
150
156
|
/**
|
|
151
157
|
* A choice of several from a list: a trigger shaped like a Select that says what is picked
|
|
152
158
|
* (the placeholder, the one picked, or a count), and a popup with a search field and checkbox
|
|
@@ -250,7 +256,7 @@ var MultiSelect = ({ placeholder, searchPlaceholder, options, value, onValueChan
|
|
|
250
256
|
className: "size-4 shrink-0 text-muted-foreground"
|
|
251
257
|
})]
|
|
252
258
|
}), /* @__PURE__ */ jsx(TooltipContent, { children: fullSelection(chosen, placeholder, labels, summary) })]
|
|
253
|
-
}), /* @__PURE__ */
|
|
259
|
+
}), /* @__PURE__ */ jsxs(Combobox.Portal, { children: [/* @__PURE__ */ jsx(ExposedFocusGuards, {}), /* @__PURE__ */ jsx(Combobox.Positioner, {
|
|
254
260
|
sideOffset: 4,
|
|
255
261
|
align: "start",
|
|
256
262
|
className: "z-50",
|
|
@@ -323,7 +329,7 @@ var MultiSelect = ({ placeholder, searchPlaceholder, options, value, onValueChan
|
|
|
323
329
|
})
|
|
324
330
|
]
|
|
325
331
|
})
|
|
326
|
-
}) })]
|
|
332
|
+
})] })]
|
|
327
333
|
});
|
|
328
334
|
};
|
|
329
335
|
//#endregion
|