plass-ui 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion/PlAccordion.d.ts +98 -0
- package/dist/components/accordion/PlAccordion.js +131 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +1 -0
- package/dist/components/alert/PlAlert.d.ts +50 -0
- package/dist/components/alert/PlAlert.js +109 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/animate-appear/PlAnimateAppear.d.ts +55 -0
- package/dist/components/animate-appear/PlAnimateAppear.js +71 -0
- package/dist/components/animate-appear/index.d.ts +2 -0
- package/dist/components/animate-appear/index.js +1 -0
- package/dist/components/animate-blink/PlAnimateBlink.d.ts +30 -0
- package/dist/components/animate-blink/PlAnimateBlink.js +47 -0
- package/dist/components/animate-blink/index.d.ts +2 -0
- package/dist/components/animate-blink/index.js +1 -0
- package/dist/components/animate-fade/PlAnimateFade.d.ts +35 -0
- package/dist/components/animate-fade/PlAnimateFade.js +48 -0
- package/dist/components/animate-fade/index.d.ts +2 -0
- package/dist/components/animate-fade/index.js +1 -0
- package/dist/components/animate-grow/PlAnimateGrow.d.ts +45 -0
- package/dist/components/animate-grow/PlAnimateGrow.js +49 -0
- package/dist/components/animate-grow/index.d.ts +2 -0
- package/dist/components/animate-grow/index.js +1 -0
- package/dist/components/animate-headline/PlAnimateHeadline.d.ts +55 -0
- package/dist/components/animate-headline/PlAnimateHeadline.js +120 -0
- package/dist/components/animate-headline/index.d.ts +2 -0
- package/dist/components/animate-headline/index.js +1 -0
- package/dist/components/animate-lighting/PlAnimateLighting.d.ts +67 -0
- package/dist/components/animate-lighting/PlAnimateLighting.js +65 -0
- package/dist/components/animate-lighting/index.d.ts +2 -0
- package/dist/components/animate-lighting/index.js +1 -0
- package/dist/components/animate-marquee/PlAnimateMarquee.d.ts +65 -0
- package/dist/components/animate-marquee/PlAnimateMarquee.js +94 -0
- package/dist/components/animate-marquee/index.d.ts +2 -0
- package/dist/components/animate-marquee/index.js +1 -0
- package/dist/components/animate-rotate/PlAnimateRotate.d.ts +52 -0
- package/dist/components/animate-rotate/PlAnimateRotate.js +50 -0
- package/dist/components/animate-rotate/index.d.ts +2 -0
- package/dist/components/animate-rotate/index.js +1 -0
- package/dist/components/animate-slide/PlAnimateSlide.d.ts +47 -0
- package/dist/components/animate-slide/PlAnimateSlide.js +49 -0
- package/dist/components/animate-slide/index.d.ts +2 -0
- package/dist/components/animate-slide/index.js +1 -0
- package/dist/components/animate-typing/PlAnimateTyping.d.ts +56 -0
- package/dist/components/animate-typing/PlAnimateTyping.js +177 -0
- package/dist/components/animate-typing/index.d.ts +2 -0
- package/dist/components/animate-typing/index.js +1 -0
- package/dist/components/animate-zoom/PlAnimateZoom.d.ts +37 -0
- package/dist/components/animate-zoom/PlAnimateZoom.js +45 -0
- package/dist/components/animate-zoom/index.d.ts +2 -0
- package/dist/components/animate-zoom/index.js +1 -0
- package/dist/components/aspect-ratio/PlAspectRatio.d.ts +64 -0
- package/dist/components/aspect-ratio/PlAspectRatio.js +58 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/aspect-ratio/index.js +1 -0
- package/dist/components/avatar/PlAvatar.d.ts +102 -0
- package/dist/components/avatar/PlAvatar.js +121 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +1 -0
- package/dist/components/badge/PlBadge.d.ts +86 -0
- package/dist/components/badge/PlBadge.js +168 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +1 -0
- package/dist/components/blockquote/PlBlockquote.d.ts +64 -0
- package/dist/components/blockquote/PlBlockquote.js +112 -0
- package/dist/components/blockquote/index.d.ts +2 -0
- package/dist/components/blockquote/index.js +1 -0
- package/dist/components/bottom-navigation/PlBottomNavigation.d.ts +111 -0
- package/dist/components/bottom-navigation/PlBottomNavigation.js +141 -0
- package/dist/components/bottom-navigation/index.d.ts +2 -0
- package/dist/components/bottom-navigation/index.js +1 -0
- package/dist/components/box/PlBox.d.ts +50 -0
- package/dist/components/box/PlBox.js +46 -0
- package/dist/components/box/index.d.ts +2 -0
- package/dist/components/box/index.js +1 -0
- package/dist/components/breadcrumb/PlBreadcrumb.d.ts +138 -0
- package/dist/components/breadcrumb/PlBreadcrumb.js +201 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +1 -0
- package/dist/components/button/{Button.d.ts → PlButton.d.ts} +3 -3
- package/dist/components/button/PlButton.js +196 -0
- package/dist/components/button/index.d.ts +2 -2
- package/dist/components/button/index.js +1 -1
- package/dist/components/button-group/PlButtonGroup.d.ts +32 -0
- package/dist/components/button-group/PlButtonGroup.js +64 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/button-group/index.js +1 -0
- package/dist/components/card/PlCard.d.ts +81 -0
- package/dist/components/card/PlCard.js +102 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +1 -0
- package/dist/components/carousel/PlCarousel.d.ts +78 -0
- package/dist/components/carousel/PlCarousel.js +177 -0
- package/dist/components/carousel/index.d.ts +2 -0
- package/dist/components/carousel/index.js +1 -0
- package/dist/components/chat-bubble/PlChatBubble.d.ts +127 -0
- package/dist/components/chat-bubble/PlChatBubble.js +206 -0
- package/dist/components/chat-bubble/index.d.ts +2 -0
- package/dist/components/chat-bubble/index.js +1 -0
- package/dist/components/checkbox/PlCheckbox.d.ts +39 -0
- package/dist/components/checkbox/PlCheckbox.js +100 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +1 -0
- package/dist/components/chip/PlChip.d.ts +55 -0
- package/dist/components/chip/PlChip.js +144 -0
- package/dist/components/chip/index.d.ts +2 -0
- package/dist/components/chip/index.js +1 -0
- package/dist/components/collapsible/PlCollapsible.d.ts +84 -0
- package/dist/components/collapsible/PlCollapsible.js +65 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +1 -0
- package/dist/components/combobox/PlCombobox.d.ts +140 -0
- package/dist/components/combobox/PlCombobox.js +199 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +1 -0
- package/dist/components/container/PlContainer.d.ts +66 -0
- package/dist/components/container/PlContainer.js +47 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/container/index.js +1 -0
- package/dist/components/date-picker/PlDatePicker.d.ts +73 -0
- package/dist/components/date-picker/PlDatePicker.js +87 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-range-picker/PlDateRangePicker.d.ts +91 -0
- package/dist/components/date-range-picker/PlDateRangePicker.js +152 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.js +1 -0
- package/dist/components/date-time-picker/PlDateTimePicker.d.ts +74 -0
- package/dist/components/date-time-picker/PlDateTimePicker.js +106 -0
- package/dist/components/date-time-picker/index.d.ts +2 -0
- package/dist/components/date-time-picker/index.js +1 -0
- package/dist/components/divider/PlDivider.d.ts +73 -0
- package/dist/components/divider/PlDivider.js +107 -0
- package/dist/components/divider/index.d.ts +2 -0
- package/dist/components/divider/index.js +1 -0
- package/dist/components/drawer/PlDrawer.d.ts +144 -0
- package/dist/components/drawer/PlDrawer.js +190 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +1 -0
- package/dist/components/file-picker/PlFilePicker.d.ts +105 -0
- package/dist/components/file-picker/PlFilePicker.js +274 -0
- package/dist/components/file-picker/index.d.ts +2 -0
- package/dist/components/file-picker/index.js +1 -0
- package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.d.ts +118 -0
- package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.js +291 -0
- package/dist/components/floating-bottom-navigation/index.d.ts +2 -0
- package/dist/components/floating-bottom-navigation/index.js +1 -0
- package/dist/components/grid/PlGrid.d.ts +67 -0
- package/dist/components/grid/PlGrid.js +51 -0
- package/dist/components/grid/PlGridItem.d.ts +50 -0
- package/dist/components/grid/PlGridItem.js +34 -0
- package/dist/components/grid/index.d.ts +4 -0
- package/dist/components/grid/index.js +2 -0
- package/dist/components/highlight/PlHighlight.d.ts +90 -0
- package/dist/components/highlight/PlHighlight.js +185 -0
- package/dist/components/highlight/index.d.ts +2 -0
- package/dist/components/highlight/index.js +1 -0
- package/dist/components/hot-keys/PlHotKeys.d.ts +93 -0
- package/dist/components/hot-keys/PlHotKeys.js +294 -0
- package/dist/components/hot-keys/index.d.ts +2 -0
- package/dist/components/hot-keys/index.js +1 -0
- package/dist/components/icon/PlIcon.d.ts +62 -0
- package/dist/components/icon/PlIcon.js +58 -0
- package/dist/components/icon/index.d.ts +2 -0
- package/dist/components/icon/index.js +1 -0
- package/dist/components/icon-button/PlIconButton.d.ts +39 -0
- package/dist/components/icon-button/PlIconButton.js +37 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/icon-button/index.js +1 -0
- package/dist/components/list/PlList.d.ts +82 -0
- package/dist/components/list/PlList.js +160 -0
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/index.js +1 -0
- package/dist/components/menu/PlMenu.d.ts +210 -0
- package/dist/components/menu/PlMenu.js +209 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/index.js +1 -0
- package/dist/components/modal/PlModal.d.ts +112 -0
- package/dist/components/modal/PlModal.js +150 -0
- package/dist/components/modal/index.d.ts +2 -0
- package/dist/components/modal/index.js +1 -0
- package/dist/components/number-field/PlNumberField.d.ts +133 -0
- package/dist/components/number-field/PlNumberField.js +111 -0
- package/dist/components/number-field/index.d.ts +2 -0
- package/dist/components/number-field/index.js +1 -0
- package/dist/components/otp-field/PlOtpField.d.ts +82 -0
- package/dist/components/otp-field/PlOtpField.js +109 -0
- package/dist/components/otp-field/index.d.ts +2 -0
- package/dist/components/otp-field/index.js +1 -0
- package/dist/components/overlay/PlOverlay.d.ts +96 -0
- package/dist/components/overlay/PlOverlay.js +77 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.js +1 -0
- package/dist/components/pagination/PlPagination.d.ts +88 -0
- package/dist/components/pagination/PlPagination.js +159 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/index.js +1 -0
- package/dist/components/panes/PlPanes.d.ts +79 -0
- package/dist/components/panes/PlPanes.js +324 -0
- package/dist/components/panes/index.d.ts +2 -0
- package/dist/components/panes/index.js +1 -0
- package/dist/components/pill/PlPill.d.ts +81 -0
- package/dist/components/pill/PlPill.js +154 -0
- package/dist/components/pill/index.d.ts +2 -0
- package/dist/components/pill/index.js +1 -0
- package/dist/components/popover/PlPopover.d.ts +107 -0
- package/dist/components/popover/PlPopover.js +113 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +1 -0
- package/dist/components/progress-box/PlProgressBox.d.ts +32 -0
- package/dist/components/progress-box/PlProgressBox.js +34 -0
- package/dist/components/progress-box/index.d.ts +2 -0
- package/dist/components/progress-box/index.js +1 -0
- package/dist/components/progress-circular/PlProgressCircular.d.ts +22 -0
- package/dist/components/progress-circular/PlProgressCircular.js +47 -0
- package/dist/components/progress-circular/index.d.ts +2 -0
- package/dist/components/progress-circular/index.js +1 -0
- package/dist/components/progress-linear/PlProgressLinear.d.ts +31 -0
- package/dist/components/progress-linear/PlProgressLinear.js +40 -0
- package/dist/components/progress-linear/index.d.ts +2 -0
- package/dist/components/progress-linear/index.js +1 -0
- package/dist/components/radio-group/PlRadioGroup.d.ts +54 -0
- package/dist/components/radio-group/PlRadioGroup.js +99 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +1 -0
- package/dist/components/rating/PlRating.d.ts +90 -0
- package/dist/components/rating/PlRating.js +101 -0
- package/dist/components/rating/index.d.ts +2 -0
- package/dist/components/rating/index.js +1 -0
- package/dist/components/scroll-zone/PlScrollZone.d.ts +132 -0
- package/dist/components/scroll-zone/PlScrollZone.js +411 -0
- package/dist/components/scroll-zone/index.d.ts +2 -0
- package/dist/components/scroll-zone/index.js +1 -0
- package/dist/components/segmented-button/PlSegmentedButton.d.ts +79 -0
- package/dist/components/segmented-button/PlSegmentedButton.js +206 -0
- package/dist/components/segmented-button/index.d.ts +2 -0
- package/dist/components/segmented-button/index.js +1 -0
- package/dist/components/select/PlSelect.d.ts +77 -0
- package/dist/components/select/PlSelect.js +115 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +1 -0
- package/dist/components/skeleton/PlSkeleton.d.ts +73 -0
- package/dist/components/skeleton/PlSkeleton.js +142 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/slider/PlSlider.d.ts +44 -0
- package/dist/components/slider/PlSlider.js +132 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/index.js +1 -0
- package/dist/components/spoiler/PlSpoiler.d.ts +84 -0
- package/dist/components/spoiler/PlSpoiler.js +74 -0
- package/dist/components/spoiler/index.d.ts +2 -0
- package/dist/components/spoiler/index.js +1 -0
- package/dist/components/switch/PlSwitch.d.ts +42 -0
- package/dist/components/switch/PlSwitch.js +131 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/table/PlTable.d.ts +112 -0
- package/dist/components/table/PlTable.js +210 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +1 -0
- package/dist/components/tabs/PlTabs.d.ts +94 -0
- package/dist/components/tabs/PlTabs.js +182 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/index.js +1 -0
- package/dist/components/text-field/{TextField.d.ts → PlTextField.d.ts} +5 -5
- package/dist/components/text-field/PlTextField.js +126 -0
- package/dist/components/text-field/index.d.ts +2 -2
- package/dist/components/text-field/index.js +1 -1
- package/dist/components/text-link/PlTextLink.d.ts +80 -0
- package/dist/components/text-link/PlTextLink.js +136 -0
- package/dist/components/text-link/index.d.ts +2 -0
- package/dist/components/text-link/index.js +1 -0
- package/dist/components/time-picker/PlTimePicker.d.ts +88 -0
- package/dist/components/time-picker/PlTimePicker.js +97 -0
- package/dist/components/time-picker/index.d.ts +2 -0
- package/dist/components/time-picker/index.js +1 -0
- package/dist/components/timeline/PlTimeline.d.ts +98 -0
- package/dist/components/timeline/PlTimeline.js +207 -0
- package/dist/components/timeline/index.d.ts +2 -0
- package/dist/components/timeline/index.js +1 -0
- package/dist/components/toast/PlToast.d.ts +122 -0
- package/dist/components/toast/PlToast.js +174 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/index.js +1 -0
- package/dist/components/toolbar/PlToolbar.d.ts +68 -0
- package/dist/components/toolbar/PlToolbar.js +65 -0
- package/dist/components/toolbar/index.d.ts +2 -0
- package/dist/components/toolbar/index.js +1 -0
- package/dist/components/tooltip/PlTooltip.d.ts +92 -0
- package/dist/components/tooltip/PlTooltip.js +117 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +1 -0
- package/dist/components/typography/PlTypography.d.ts +66 -0
- package/dist/components/typography/PlTypography.js +143 -0
- package/dist/components/typography/index.d.ts +2 -0
- package/dist/components/typography/index.js +1 -0
- package/dist/css/accordion.css +2 -0
- package/dist/css/alert.css +2 -0
- package/dist/css/animate-appear.css +2 -0
- package/dist/css/animate-blink.css +2 -0
- package/dist/css/animate-fade.css +2 -0
- package/dist/css/animate-grow.css +2 -0
- package/dist/css/animate-headline.css +2 -0
- package/dist/css/animate-lighting.css +2 -0
- package/dist/css/animate-marquee.css +2 -0
- package/dist/css/animate-rotate.css +2 -0
- package/dist/css/animate-slide.css +2 -0
- package/dist/css/animate-typing.css +2 -0
- package/dist/css/animate-zoom.css +2 -0
- package/dist/css/aspect-ratio.css +2 -0
- package/dist/css/avatar.css +2 -0
- package/dist/css/badge.css +2 -0
- package/dist/css/base.css +4 -0
- package/dist/css/blockquote.css +2 -0
- package/dist/css/bottom-navigation.css +2 -0
- package/dist/css/box.css +2 -0
- package/dist/css/breadcrumb.css +2 -0
- package/dist/css/button-group.css +2 -0
- package/dist/css/button.css +2 -0
- package/dist/css/card.css +2 -0
- package/dist/css/carousel.css +2 -0
- package/dist/css/chat-bubble.css +2 -0
- package/dist/css/checkbox.css +2 -0
- package/dist/css/chip.css +2 -0
- package/dist/css/collapsible.css +2 -0
- package/dist/css/combobox.css +2 -0
- package/dist/css/container.css +2 -0
- package/dist/css/date-picker.css +2 -0
- package/dist/css/date-range-picker.css +2 -0
- package/dist/css/date-time-picker.css +2 -0
- package/dist/css/divider.css +2 -0
- package/dist/css/drawer.css +2 -0
- package/dist/css/file-picker.css +2 -0
- package/dist/css/floating-bottom-navigation.css +2 -0
- package/dist/css/grid.css +2 -0
- package/dist/css/highlight.css +2 -0
- package/dist/css/hot-keys.css +2 -0
- package/dist/css/icon-button.css +2 -0
- package/dist/css/icon.css +2 -0
- package/dist/css/list.css +2 -0
- package/dist/css/menu.css +2 -0
- package/dist/css/modal.css +2 -0
- package/dist/css/number-field.css +2 -0
- package/dist/css/otp-field.css +2 -0
- package/dist/css/overlay.css +2 -0
- package/dist/css/pagination.css +2 -0
- package/dist/css/panes.css +2 -0
- package/dist/css/pill.css +2 -0
- package/dist/css/popover.css +2 -0
- package/dist/css/progress-box.css +2 -0
- package/dist/css/progress-circular.css +2 -0
- package/dist/css/progress-linear.css +2 -0
- package/dist/css/radio-group.css +2 -0
- package/dist/css/rating.css +2 -0
- package/dist/css/scroll-zone.css +2 -0
- package/dist/css/segmented-button.css +2 -0
- package/dist/css/select.css +2 -0
- package/dist/css/skeleton.css +2 -0
- package/dist/css/slider.css +2 -0
- package/dist/css/spoiler.css +2 -0
- package/dist/css/switch.css +2 -0
- package/dist/css/table.css +2 -0
- package/dist/css/tabs.css +2 -0
- package/dist/css/text-field.css +2 -0
- package/dist/css/text-link.css +2 -0
- package/dist/css/time-picker.css +2 -0
- package/dist/css/timeline.css +2 -0
- package/dist/css/toast.css +2 -0
- package/dist/css/toolbar.css +2 -0
- package/dist/css/tooltip.css +2 -0
- package/dist/css/typography.css +2 -0
- package/dist/index.d.ts +75 -3
- package/dist/index.js +75 -1
- package/dist/internal/animate.d.ts +161 -0
- package/dist/internal/animate.js +318 -0
- package/dist/internal/button-group.d.ts +27 -0
- package/dist/internal/button-group.js +19 -0
- package/dist/internal/calendar.d.ts +148 -0
- package/dist/internal/calendar.js +501 -0
- package/dist/internal/date.d.ts +173 -0
- package/dist/internal/date.js +353 -0
- package/dist/internal/format.d.ts +24 -0
- package/dist/internal/format.js +41 -0
- package/dist/internal/grid.d.ts +67 -0
- package/dist/internal/grid.js +143 -0
- package/dist/internal/icons.d.ts +86 -1
- package/dist/internal/icons.js +138 -1
- package/dist/internal/menu.d.ts +20 -0
- package/dist/internal/menu.js +18 -0
- package/dist/internal/picker.d.ts +118 -0
- package/dist/internal/picker.js +139 -0
- package/dist/internal/progress.d.ts +145 -0
- package/dist/internal/progress.js +167 -0
- package/dist/internal/sizer.d.ts +32 -0
- package/dist/internal/sizer.js +35 -0
- package/dist/internal/styles.d.ts +198 -8
- package/dist/internal/styles.js +636 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +899 -125
- package/dist/tokens.css +1275 -0
- package/dist/types.d.ts +150 -8
- package/dist/types.js +1 -1
- package/package.json +31 -27
- package/README.md +0 -111
- package/dist/components/button/Button.js +0 -1
- package/dist/components/text-field/TextField.js +0 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the naming the four pickers share.
|
|
3
|
+
*
|
|
4
|
+
* No date library under it, deliberately. Plass has one runtime dependency —
|
|
5
|
+
* Base UI — and a component library that quietly adds `date-fns`, or worse
|
|
6
|
+
* picks a side in the dayjs/luxon/Temporal argument on its consumer's behalf,
|
|
7
|
+
* has made a decision that was not its to make. Everything here is either
|
|
8
|
+
* `Date` arithmetic, which is a dozen lines, or `Intl`, which the platform
|
|
9
|
+
* already ships and which knows more about month names in more languages than
|
|
10
|
+
* any bundled table ever will.
|
|
11
|
+
*
|
|
12
|
+
* **That is also the whole of the localisation story.** There is no table of
|
|
13
|
+
* translated month names to import and no per-language module to register: the
|
|
14
|
+
* only strings a picker says that `Intl` has no opinion about are the labels on
|
|
15
|
+
* its own buttons, and those are one `labels` prop with English defaults. A
|
|
16
|
+
* project that ships in twelve languages pays nothing for eleven of them.
|
|
17
|
+
*
|
|
18
|
+
* Two rules hold everywhere below:
|
|
19
|
+
*
|
|
20
|
+
* - **Local time, always.** A calendar day is a thing a person is looking at on
|
|
21
|
+
* a wall, not an instant on a line. `makeDate(2026, 6, 27)` is midnight local
|
|
22
|
+
* and every comparison here is made on the local Y/M/D triple, so a picker in
|
|
23
|
+
* Seoul and a picker in São Paulo both light up the cell that says 27.
|
|
24
|
+
* - **Nothing is mutated.** `Date` is mutable and every method on it that
|
|
25
|
+
* sounds like a question is actually a command. Each function here copies
|
|
26
|
+
* first, so a `value` handed in by a caller is never the object that comes
|
|
27
|
+
* back out.
|
|
28
|
+
*/
|
|
29
|
+
import type { PlassWeekday } from '../types.js';
|
|
30
|
+
/** Which unit the calendar is currently letting you pick. */
|
|
31
|
+
export type CalendarView = 'day' | 'month' | 'year';
|
|
32
|
+
/** How many years one page of the year grid holds. Four columns of three. */
|
|
33
|
+
export declare const YEAR_PAGE_SIZE = 12;
|
|
34
|
+
/**
|
|
35
|
+
* A local midnight on the given Y/M/D, with out-of-range parts normalised —
|
|
36
|
+
* month `12` rolls into January, day `0` into the last day of the month before.
|
|
37
|
+
*
|
|
38
|
+
* Built through `setFullYear` rather than `new Date(year, month, day)` because
|
|
39
|
+
* the multi-argument constructor maps years 0–99 onto 1900–1999. Nobody is
|
|
40
|
+
* going to pick a date in the year 47, but a component that silently rewrites
|
|
41
|
+
* the year it was handed is a component that will eventually be blamed for
|
|
42
|
+
* something else.
|
|
43
|
+
*/
|
|
44
|
+
export declare function makeDate(year: number, month: number, day: number): Date;
|
|
45
|
+
/** Is this a `Date` that stands for a real instant? `new Date('nope')` is not. */
|
|
46
|
+
export declare function isValidDate(value: unknown): value is Date;
|
|
47
|
+
/** The same day with the clock wound back to midnight. */
|
|
48
|
+
export declare function startOfDay(date: Date): Date;
|
|
49
|
+
/** The first day of the month this date is in, at midnight. */
|
|
50
|
+
export declare function startOfMonth(date: Date): Date;
|
|
51
|
+
/** How many days a month has, leap years included. */
|
|
52
|
+
export declare function daysInMonth(year: number, month: number): number;
|
|
53
|
+
/** Today, at midnight. The one place the pickers read the clock for a *date*. */
|
|
54
|
+
export declare function today(): Date;
|
|
55
|
+
export declare function addDays(date: Date, amount: number): Date;
|
|
56
|
+
/**
|
|
57
|
+
* Months, with the day of the month clamped rather than allowed to overflow.
|
|
58
|
+
*
|
|
59
|
+
* 31 January plus one month is 28 February, not 3 March. The naive
|
|
60
|
+
* `setMonth(getMonth() + 1)` gives the second answer, which is why stepping a
|
|
61
|
+
* calendar forward from a 31st with it skips February entirely.
|
|
62
|
+
*/
|
|
63
|
+
export declare function addMonths(date: Date, amount: number): Date;
|
|
64
|
+
export declare function addYears(date: Date, amount: number): Date;
|
|
65
|
+
/** Negative, zero or positive, the way a sort comparator wants it. */
|
|
66
|
+
export declare function compareDay(a: Date, b: Date): number;
|
|
67
|
+
export declare function isSameDay(a: Date | null | undefined, b: Date | null | undefined): boolean;
|
|
68
|
+
export declare function isSameMonth(a: Date | null | undefined, b: Date | null | undefined): boolean;
|
|
69
|
+
/** Holds a date inside `[min, max]`, at whatever precision the bounds carry. */
|
|
70
|
+
export declare function clampDate(date: Date, min?: Date | null, max?: Date | null): Date;
|
|
71
|
+
/**
|
|
72
|
+
* Is this calendar *day* outside the allowed span?
|
|
73
|
+
*
|
|
74
|
+
* Day-granular on purpose. A `maxDate` of 27 July at 09:00 still leaves the
|
|
75
|
+
* 27th pickable — the bound is about which days exist, and the time of day is
|
|
76
|
+
* the time picker's problem. `PlDateTimePicker` re-checks at full precision
|
|
77
|
+
* once an hour has been chosen.
|
|
78
|
+
*/
|
|
79
|
+
export declare function isDayOutside(date: Date, min?: Date | null, max?: Date | null): boolean;
|
|
80
|
+
/** Seconds since local midnight — what `minTime`/`maxTime` are compared on. */
|
|
81
|
+
export declare function secondsOfDay(date: Date): number;
|
|
82
|
+
/** Which column of a clock a candidate time is being offered for. */
|
|
83
|
+
export type TimeUnit = 'hour' | 'minute' | 'second' | 'meridiem';
|
|
84
|
+
/**
|
|
85
|
+
* The span of the day one row of one column covers, in seconds since midnight.
|
|
86
|
+
*
|
|
87
|
+
* This is the detail that separates a working time picker from a frustrating
|
|
88
|
+
* one. A bound has to be checked against the *span* a row stands for, not
|
|
89
|
+
* against one instant inside it: with a `minTime` of 09:30, the hour `9` covers
|
|
90
|
+
* 09:00:00–09:59:59, which overlaps what is allowed, so it stays available and
|
|
91
|
+
* the minute column is where `00` through `25` grey out. Comparing the whole
|
|
92
|
+
* candidate instead hides the 9 and makes half past nine unreachable.
|
|
93
|
+
*/
|
|
94
|
+
export declare function timeUnitSpan(unit: TimeUnit, at: Date): [number, number];
|
|
95
|
+
/** The same instant with one or more clock fields replaced. */
|
|
96
|
+
export declare function withTime(date: Date, parts: {
|
|
97
|
+
hours?: number;
|
|
98
|
+
minutes?: number;
|
|
99
|
+
seconds?: number;
|
|
100
|
+
}): Date;
|
|
101
|
+
/** `date`'s calendar day wearing `time`'s clock. */
|
|
102
|
+
export declare function mergeDateAndTime(date: Date, time: Date): Date;
|
|
103
|
+
/**
|
|
104
|
+
* Six weeks of seven days, always — including the leading and trailing days
|
|
105
|
+
* that belong to the neighbouring months.
|
|
106
|
+
*
|
|
107
|
+
* Six rows whatever the month, and that is the whole point. A February that
|
|
108
|
+
* starts on a Sunday needs four rows and a 31-day month starting on a Saturday
|
|
109
|
+
* needs six; a grid that renders only the rows it needs is a grid that changes
|
|
110
|
+
* height when you step a month forward, moving every cell out from under the
|
|
111
|
+
* pointer that just pressed one. The same reason `PlPagination` pins its slot
|
|
112
|
+
* count.
|
|
113
|
+
*/
|
|
114
|
+
export declare function calendarWeeks(month: Date, weekStartsOn: PlassWeekday): Date[][];
|
|
115
|
+
/** The first year on the page a given year falls on. 2026 becomes 2016 at 12 a page. */
|
|
116
|
+
export declare function yearPageStart(year: number): number;
|
|
117
|
+
/** Formats a date, tolerating the `null` a cleared picker holds. */
|
|
118
|
+
export declare function formatDate(date: Date | null | undefined, locale: string | undefined, options: Intl.DateTimeFormatOptions): string;
|
|
119
|
+
/**
|
|
120
|
+
* Every distinct string those instants format to. Deduplicated, because a
|
|
121
|
+
* date-only format collapses twenty-four of them into a handful.
|
|
122
|
+
*/
|
|
123
|
+
export declare function displaySamples(locale: string | undefined, options: Intl.DateTimeFormatOptions): string[];
|
|
124
|
+
/**
|
|
125
|
+
* The samples plus the placeholder, when the placeholder is a string.
|
|
126
|
+
*
|
|
127
|
+
* An empty picker shows the placeholder, which can easily be longer than any
|
|
128
|
+
* date — "Pick a departure date" against "3 Aug 2026" — and a trigger that
|
|
129
|
+
* shrinks the moment the first date is chosen is the same jump from the other
|
|
130
|
+
* direction. A `ReactNode` placeholder is left out: there is nothing to measure
|
|
131
|
+
* without rendering it twice.
|
|
132
|
+
*/
|
|
133
|
+
export declare function withPlaceholder(samples: string[], placeholder: unknown): string[];
|
|
134
|
+
/**
|
|
135
|
+
* The three machine-readable spellings, for the hidden input that makes a
|
|
136
|
+
* picker submit with a form.
|
|
137
|
+
*
|
|
138
|
+
* Local, not UTC, and that is the whole point: `toISOString()` on a `Date`
|
|
139
|
+
* standing for 27 July in Seoul gives `2026-07-26T15:00:00Z`, and a form field
|
|
140
|
+
* that quietly reports the day before the one on screen is the single most
|
|
141
|
+
* expensive bug a date picker can ship. The shapes are the ones the native
|
|
142
|
+
* `<input type="date">`, `type="time"` and `type="datetime-local"` submit, so a
|
|
143
|
+
* server that already parses those needs no new code.
|
|
144
|
+
*/
|
|
145
|
+
export declare function toISODate(date: Date): string;
|
|
146
|
+
export declare function toISOTime(date: Date, withSeconds?: boolean): string;
|
|
147
|
+
export declare function toISODateTime(date: Date, withSeconds?: boolean): string;
|
|
148
|
+
/**
|
|
149
|
+
* The seven column headers, rotated so the first one is `weekStartsOn`.
|
|
150
|
+
*
|
|
151
|
+
* `short` rather than `narrow`: narrow gives `S`, `M`, `T`, `W`, `T`, `F`, `S`
|
|
152
|
+
* in English, where two pairs are indistinguishable. The full name goes on the
|
|
153
|
+
* header's `aria-label` so a screen reader hears "Monday" rather than "Mon".
|
|
154
|
+
*/
|
|
155
|
+
export declare function weekdayLabels(locale: string | undefined, weekStartsOn: PlassWeekday, weekday?: 'narrow' | 'short' | 'long'): string[];
|
|
156
|
+
/** The twelve month names, January first, in the locale's own words. */
|
|
157
|
+
export declare function monthLabels(locale: string | undefined, month?: 'short' | 'long'): string[];
|
|
158
|
+
/**
|
|
159
|
+
* Does this locale write the month before the year?
|
|
160
|
+
*
|
|
161
|
+
* The calendar's header is two separate buttons — one that opens the month grid
|
|
162
|
+
* and one that opens the year grid — so it cannot just print what `Intl` gives
|
|
163
|
+
* it. Asking `formatToParts` which part came first is how the two buttons end
|
|
164
|
+
* up in the order the reader expects: `July 2026` in English, `2026년 7월` in
|
|
165
|
+
* Korean. Getting this wrong is subtle and reads as broken to exactly the
|
|
166
|
+
* people it is wrong for.
|
|
167
|
+
*/
|
|
168
|
+
export declare function isMonthBeforeYear(locale: string | undefined): boolean;
|
|
169
|
+
/** Does this locale put a clock on a 12-hour dial? */
|
|
170
|
+
export declare function isHour12(locale: string | undefined): boolean;
|
|
171
|
+
/** What this locale calls AM and PM. */
|
|
172
|
+
export declare function meridiemLabels(locale: string | undefined): [string, string];
|
|
173
|
+
export declare function localeWeekStart(locale: string | undefined): PlassWeekday;
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the naming the four pickers share.
|
|
3
|
+
*
|
|
4
|
+
* No date library under it, deliberately. Plass has one runtime dependency —
|
|
5
|
+
* Base UI — and a component library that quietly adds `date-fns`, or worse
|
|
6
|
+
* picks a side in the dayjs/luxon/Temporal argument on its consumer's behalf,
|
|
7
|
+
* has made a decision that was not its to make. Everything here is either
|
|
8
|
+
* `Date` arithmetic, which is a dozen lines, or `Intl`, which the platform
|
|
9
|
+
* already ships and which knows more about month names in more languages than
|
|
10
|
+
* any bundled table ever will.
|
|
11
|
+
*
|
|
12
|
+
* **That is also the whole of the localisation story.** There is no table of
|
|
13
|
+
* translated month names to import and no per-language module to register: the
|
|
14
|
+
* only strings a picker says that `Intl` has no opinion about are the labels on
|
|
15
|
+
* its own buttons, and those are one `labels` prop with English defaults. A
|
|
16
|
+
* project that ships in twelve languages pays nothing for eleven of them.
|
|
17
|
+
*
|
|
18
|
+
* Two rules hold everywhere below:
|
|
19
|
+
*
|
|
20
|
+
* - **Local time, always.** A calendar day is a thing a person is looking at on
|
|
21
|
+
* a wall, not an instant on a line. `makeDate(2026, 6, 27)` is midnight local
|
|
22
|
+
* and every comparison here is made on the local Y/M/D triple, so a picker in
|
|
23
|
+
* Seoul and a picker in São Paulo both light up the cell that says 27.
|
|
24
|
+
* - **Nothing is mutated.** `Date` is mutable and every method on it that
|
|
25
|
+
* sounds like a question is actually a command. Each function here copies
|
|
26
|
+
* first, so a `value` handed in by a caller is never the object that comes
|
|
27
|
+
* back out.
|
|
28
|
+
*/
|
|
29
|
+
import { dateFormatter } from './format.js';
|
|
30
|
+
/** How many years one page of the year grid holds. Four columns of three. */
|
|
31
|
+
export const YEAR_PAGE_SIZE = 12;
|
|
32
|
+
/* ---------------------------------------------------------------------------
|
|
33
|
+
* Construction
|
|
34
|
+
* ------------------------------------------------------------------------- */
|
|
35
|
+
/**
|
|
36
|
+
* A local midnight on the given Y/M/D, with out-of-range parts normalised —
|
|
37
|
+
* month `12` rolls into January, day `0` into the last day of the month before.
|
|
38
|
+
*
|
|
39
|
+
* Built through `setFullYear` rather than `new Date(year, month, day)` because
|
|
40
|
+
* the multi-argument constructor maps years 0–99 onto 1900–1999. Nobody is
|
|
41
|
+
* going to pick a date in the year 47, but a component that silently rewrites
|
|
42
|
+
* the year it was handed is a component that will eventually be blamed for
|
|
43
|
+
* something else.
|
|
44
|
+
*/
|
|
45
|
+
export function makeDate(year, month, day) {
|
|
46
|
+
const date = new Date(0);
|
|
47
|
+
date.setFullYear(year, month, day);
|
|
48
|
+
date.setHours(0, 0, 0, 0);
|
|
49
|
+
return date;
|
|
50
|
+
}
|
|
51
|
+
/** Is this a `Date` that stands for a real instant? `new Date('nope')` is not. */
|
|
52
|
+
export function isValidDate(value) {
|
|
53
|
+
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
54
|
+
}
|
|
55
|
+
/** The same day with the clock wound back to midnight. */
|
|
56
|
+
export function startOfDay(date) {
|
|
57
|
+
const next = new Date(date.getTime());
|
|
58
|
+
next.setHours(0, 0, 0, 0);
|
|
59
|
+
return next;
|
|
60
|
+
}
|
|
61
|
+
/** The first day of the month this date is in, at midnight. */
|
|
62
|
+
export function startOfMonth(date) {
|
|
63
|
+
return makeDate(date.getFullYear(), date.getMonth(), 1);
|
|
64
|
+
}
|
|
65
|
+
/** How many days a month has, leap years included. */
|
|
66
|
+
export function daysInMonth(year, month) {
|
|
67
|
+
return makeDate(year, month + 1, 0).getDate();
|
|
68
|
+
}
|
|
69
|
+
/** Today, at midnight. The one place the pickers read the clock for a *date*. */
|
|
70
|
+
export function today() {
|
|
71
|
+
return startOfDay(new Date());
|
|
72
|
+
}
|
|
73
|
+
/* ---------------------------------------------------------------------------
|
|
74
|
+
* Arithmetic
|
|
75
|
+
* ------------------------------------------------------------------------- */
|
|
76
|
+
export function addDays(date, amount) {
|
|
77
|
+
const next = new Date(date.getTime());
|
|
78
|
+
next.setDate(next.getDate() + amount);
|
|
79
|
+
return next;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Months, with the day of the month clamped rather than allowed to overflow.
|
|
83
|
+
*
|
|
84
|
+
* 31 January plus one month is 28 February, not 3 March. The naive
|
|
85
|
+
* `setMonth(getMonth() + 1)` gives the second answer, which is why stepping a
|
|
86
|
+
* calendar forward from a 31st with it skips February entirely.
|
|
87
|
+
*/
|
|
88
|
+
export function addMonths(date, amount) {
|
|
89
|
+
const next = new Date(date.getTime());
|
|
90
|
+
// Normalised through a first-of-month so the day never carries the overflow.
|
|
91
|
+
const target = makeDate(date.getFullYear(), date.getMonth() + amount, 1);
|
|
92
|
+
next.setFullYear(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), daysInMonth(target.getFullYear(), target.getMonth())));
|
|
93
|
+
return next;
|
|
94
|
+
}
|
|
95
|
+
export function addYears(date, amount) {
|
|
96
|
+
return addMonths(date, amount * 12);
|
|
97
|
+
}
|
|
98
|
+
/* ---------------------------------------------------------------------------
|
|
99
|
+
* Comparison
|
|
100
|
+
*
|
|
101
|
+
* All of it on the local Y/M/D triple, never on `getTime()`. Two `Date`s that
|
|
102
|
+
* are the same calendar day differ by milliseconds far more often than not — a
|
|
103
|
+
* value carrying a time of day, a `min` built at noon — and every one of those
|
|
104
|
+
* comparisons has to come out `true`.
|
|
105
|
+
* ------------------------------------------------------------------------- */
|
|
106
|
+
/** Negative, zero or positive, the way a sort comparator wants it. */
|
|
107
|
+
export function compareDay(a, b) {
|
|
108
|
+
return startOfDay(a).getTime() - startOfDay(b).getTime();
|
|
109
|
+
}
|
|
110
|
+
export function isSameDay(a, b) {
|
|
111
|
+
return isValidDate(a) && isValidDate(b) && compareDay(a, b) === 0;
|
|
112
|
+
}
|
|
113
|
+
export function isSameMonth(a, b) {
|
|
114
|
+
return (isValidDate(a) &&
|
|
115
|
+
isValidDate(b) &&
|
|
116
|
+
a.getFullYear() === b.getFullYear() &&
|
|
117
|
+
a.getMonth() === b.getMonth());
|
|
118
|
+
}
|
|
119
|
+
/** Holds a date inside `[min, max]`, at whatever precision the bounds carry. */
|
|
120
|
+
export function clampDate(date, min, max) {
|
|
121
|
+
if (isValidDate(min) && date.getTime() < min.getTime()) {
|
|
122
|
+
return new Date(min.getTime());
|
|
123
|
+
}
|
|
124
|
+
if (isValidDate(max) && date.getTime() > max.getTime()) {
|
|
125
|
+
return new Date(max.getTime());
|
|
126
|
+
}
|
|
127
|
+
return date;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Is this calendar *day* outside the allowed span?
|
|
131
|
+
*
|
|
132
|
+
* Day-granular on purpose. A `maxDate` of 27 July at 09:00 still leaves the
|
|
133
|
+
* 27th pickable — the bound is about which days exist, and the time of day is
|
|
134
|
+
* the time picker's problem. `PlDateTimePicker` re-checks at full precision
|
|
135
|
+
* once an hour has been chosen.
|
|
136
|
+
*/
|
|
137
|
+
export function isDayOutside(date, min, max) {
|
|
138
|
+
if (isValidDate(min) && compareDay(date, min) < 0) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return isValidDate(max) && compareDay(date, max) > 0;
|
|
142
|
+
}
|
|
143
|
+
/* ---------------------------------------------------------------------------
|
|
144
|
+
* Time of day
|
|
145
|
+
* ------------------------------------------------------------------------- */
|
|
146
|
+
/** Seconds since local midnight — what `minTime`/`maxTime` are compared on. */
|
|
147
|
+
export function secondsOfDay(date) {
|
|
148
|
+
return date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The span of the day one row of one column covers, in seconds since midnight.
|
|
152
|
+
*
|
|
153
|
+
* This is the detail that separates a working time picker from a frustrating
|
|
154
|
+
* one. A bound has to be checked against the *span* a row stands for, not
|
|
155
|
+
* against one instant inside it: with a `minTime` of 09:30, the hour `9` covers
|
|
156
|
+
* 09:00:00–09:59:59, which overlaps what is allowed, so it stays available and
|
|
157
|
+
* the minute column is where `00` through `25` grey out. Comparing the whole
|
|
158
|
+
* candidate instead hides the 9 and makes half past nine unreachable.
|
|
159
|
+
*/
|
|
160
|
+
export function timeUnitSpan(unit, at) {
|
|
161
|
+
const seconds = secondsOfDay(at);
|
|
162
|
+
if (unit === 'hour') {
|
|
163
|
+
const start = Math.floor(seconds / 3600) * 3600;
|
|
164
|
+
return [start, start + 3599];
|
|
165
|
+
}
|
|
166
|
+
if (unit === 'minute') {
|
|
167
|
+
const start = Math.floor(seconds / 60) * 60;
|
|
168
|
+
return [start, start + 59];
|
|
169
|
+
}
|
|
170
|
+
if (unit === 'second') {
|
|
171
|
+
return [seconds, seconds];
|
|
172
|
+
}
|
|
173
|
+
const start = at.getHours() < 12 ? 0 : 12 * 3600;
|
|
174
|
+
return [start, start + 12 * 3600 - 1];
|
|
175
|
+
}
|
|
176
|
+
/** The same instant with one or more clock fields replaced. */
|
|
177
|
+
export function withTime(date, parts) {
|
|
178
|
+
const next = new Date(date.getTime());
|
|
179
|
+
next.setHours(parts.hours ?? next.getHours(), parts.minutes ?? next.getMinutes(), parts.seconds ?? next.getSeconds(), 0);
|
|
180
|
+
return next;
|
|
181
|
+
}
|
|
182
|
+
/** `date`'s calendar day wearing `time`'s clock. */
|
|
183
|
+
export function mergeDateAndTime(date, time) {
|
|
184
|
+
return withTime(startOfDay(date), {
|
|
185
|
+
hours: time.getHours(),
|
|
186
|
+
minutes: time.getMinutes(),
|
|
187
|
+
seconds: time.getSeconds()
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/* ---------------------------------------------------------------------------
|
|
191
|
+
* The grid
|
|
192
|
+
* ------------------------------------------------------------------------- */
|
|
193
|
+
/**
|
|
194
|
+
* Six weeks of seven days, always — including the leading and trailing days
|
|
195
|
+
* that belong to the neighbouring months.
|
|
196
|
+
*
|
|
197
|
+
* Six rows whatever the month, and that is the whole point. A February that
|
|
198
|
+
* starts on a Sunday needs four rows and a 31-day month starting on a Saturday
|
|
199
|
+
* needs six; a grid that renders only the rows it needs is a grid that changes
|
|
200
|
+
* height when you step a month forward, moving every cell out from under the
|
|
201
|
+
* pointer that just pressed one. The same reason `PlPagination` pins its slot
|
|
202
|
+
* count.
|
|
203
|
+
*/
|
|
204
|
+
export function calendarWeeks(month, weekStartsOn) {
|
|
205
|
+
const first = startOfMonth(month);
|
|
206
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
207
|
+
const origin = addDays(first, -lead);
|
|
208
|
+
return Array.from({ length: 6 }, (_, week) => Array.from({ length: 7 }, (_, day) => addDays(origin, week * 7 + day)));
|
|
209
|
+
}
|
|
210
|
+
/** The first year on the page a given year falls on. 2026 becomes 2016 at 12 a page. */
|
|
211
|
+
export function yearPageStart(year) {
|
|
212
|
+
return year - (((year % YEAR_PAGE_SIZE) + YEAR_PAGE_SIZE) % YEAR_PAGE_SIZE);
|
|
213
|
+
}
|
|
214
|
+
/* ---------------------------------------------------------------------------
|
|
215
|
+
* Naming
|
|
216
|
+
*
|
|
217
|
+
* Every string a picker draws that is not a number comes from `Intl`, through
|
|
218
|
+
* the memoised formatters in `internal/format.ts` — constructing one is the
|
|
219
|
+
* expensive half of using one, and a calendar builds seven weekday names and
|
|
220
|
+
* twelve month names on every render of the month view.
|
|
221
|
+
* ------------------------------------------------------------------------- */
|
|
222
|
+
/** Formats a date, tolerating the `null` a cleared picker holds. */
|
|
223
|
+
export function formatDate(date, locale, options) {
|
|
224
|
+
return isValidDate(date) ? dateFormatter(locale, options).format(date) : '';
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Twenty-four instants that between them exercise everything a picker's display
|
|
228
|
+
* can vary by: all twelve month names, all seven weekday names, a two-digit
|
|
229
|
+
* day, every hour of the clock and a two-digit minute and second.
|
|
230
|
+
*
|
|
231
|
+
* They exist to be measured, not read. A picker's trigger is sized by its
|
|
232
|
+
* content, so `Jul 1, 2026` and `Sep 28, 2026` are different widths and the
|
|
233
|
+
* field would jump every time a date was chosen — with the whole row of
|
|
234
|
+
* controls beside it shuffling along. Rendering all of these invisibly pins the
|
|
235
|
+
* trigger to the widest thing it could ever say.
|
|
236
|
+
*
|
|
237
|
+
* Both cycles are prime to twelve in the right way — `i % 12` walks the months
|
|
238
|
+
* and `i % 7` walks the days 21…27 — so every name appears without the two
|
|
239
|
+
* being multiplied out into eighty-four samples.
|
|
240
|
+
*/
|
|
241
|
+
const DISPLAY_SAMPLES = /* @__PURE__ */ Array.from({ length: 24 }, (_, index) => new Date(2027, index % 12, 21 + (index % 7), index, 58, 58));
|
|
242
|
+
/**
|
|
243
|
+
* Every distinct string those instants format to. Deduplicated, because a
|
|
244
|
+
* date-only format collapses twenty-four of them into a handful.
|
|
245
|
+
*/
|
|
246
|
+
export function displaySamples(locale, options) {
|
|
247
|
+
const formatter = dateFormatter(locale, options);
|
|
248
|
+
return [...new Set(DISPLAY_SAMPLES.map((date) => formatter.format(date)))];
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* The samples plus the placeholder, when the placeholder is a string.
|
|
252
|
+
*
|
|
253
|
+
* An empty picker shows the placeholder, which can easily be longer than any
|
|
254
|
+
* date — "Pick a departure date" against "3 Aug 2026" — and a trigger that
|
|
255
|
+
* shrinks the moment the first date is chosen is the same jump from the other
|
|
256
|
+
* direction. A `ReactNode` placeholder is left out: there is nothing to measure
|
|
257
|
+
* without rendering it twice.
|
|
258
|
+
*/
|
|
259
|
+
export function withPlaceholder(samples, placeholder) {
|
|
260
|
+
return typeof placeholder === 'string' && placeholder !== ''
|
|
261
|
+
? [...samples, placeholder]
|
|
262
|
+
: samples;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The three machine-readable spellings, for the hidden input that makes a
|
|
266
|
+
* picker submit with a form.
|
|
267
|
+
*
|
|
268
|
+
* Local, not UTC, and that is the whole point: `toISOString()` on a `Date`
|
|
269
|
+
* standing for 27 July in Seoul gives `2026-07-26T15:00:00Z`, and a form field
|
|
270
|
+
* that quietly reports the day before the one on screen is the single most
|
|
271
|
+
* expensive bug a date picker can ship. The shapes are the ones the native
|
|
272
|
+
* `<input type="date">`, `type="time"` and `type="datetime-local"` submit, so a
|
|
273
|
+
* server that already parses those needs no new code.
|
|
274
|
+
*/
|
|
275
|
+
export function toISODate(date) {
|
|
276
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
277
|
+
return `${String(date.getFullYear()).padStart(4, '0')}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
278
|
+
}
|
|
279
|
+
export function toISOTime(date, withSeconds = false) {
|
|
280
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
281
|
+
const base = `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
282
|
+
return withSeconds ? `${base}:${pad(date.getSeconds())}` : base;
|
|
283
|
+
}
|
|
284
|
+
export function toISODateTime(date, withSeconds = false) {
|
|
285
|
+
return `${toISODate(date)}T${toISOTime(date, withSeconds)}`;
|
|
286
|
+
}
|
|
287
|
+
/** A Sunday, used as the origin for every weekday name below. 1 Aug 2021. */
|
|
288
|
+
const WEEKDAY_ORIGIN = /* @__PURE__ */ makeDate(2021, 7, 1);
|
|
289
|
+
/**
|
|
290
|
+
* The seven column headers, rotated so the first one is `weekStartsOn`.
|
|
291
|
+
*
|
|
292
|
+
* `short` rather than `narrow`: narrow gives `S`, `M`, `T`, `W`, `T`, `F`, `S`
|
|
293
|
+
* in English, where two pairs are indistinguishable. The full name goes on the
|
|
294
|
+
* header's `aria-label` so a screen reader hears "Monday" rather than "Mon".
|
|
295
|
+
*/
|
|
296
|
+
export function weekdayLabels(locale, weekStartsOn, weekday = 'short') {
|
|
297
|
+
const formatter = dateFormatter(locale, { weekday });
|
|
298
|
+
return Array.from({ length: 7 }, (_, index) => formatter.format(addDays(WEEKDAY_ORIGIN, (weekStartsOn + index) % 7)));
|
|
299
|
+
}
|
|
300
|
+
/** The twelve month names, January first, in the locale's own words. */
|
|
301
|
+
export function monthLabels(locale, month = 'short') {
|
|
302
|
+
const formatter = dateFormatter(locale, { month });
|
|
303
|
+
return Array.from({ length: 12 }, (_, index) => formatter.format(makeDate(2021, index, 1)));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Does this locale write the month before the year?
|
|
307
|
+
*
|
|
308
|
+
* The calendar's header is two separate buttons — one that opens the month grid
|
|
309
|
+
* and one that opens the year grid — so it cannot just print what `Intl` gives
|
|
310
|
+
* it. Asking `formatToParts` which part came first is how the two buttons end
|
|
311
|
+
* up in the order the reader expects: `July 2026` in English, `2026년 7월` in
|
|
312
|
+
* Korean. Getting this wrong is subtle and reads as broken to exactly the
|
|
313
|
+
* people it is wrong for.
|
|
314
|
+
*/
|
|
315
|
+
export function isMonthBeforeYear(locale) {
|
|
316
|
+
const parts = dateFormatter(locale, { year: 'numeric', month: 'long' }).formatToParts(WEEKDAY_ORIGIN);
|
|
317
|
+
return (parts.findIndex((part) => part.type === 'month') <
|
|
318
|
+
parts.findIndex((part) => part.type === 'year'));
|
|
319
|
+
}
|
|
320
|
+
/** Does this locale put a clock on a 12-hour dial? */
|
|
321
|
+
export function isHour12(locale) {
|
|
322
|
+
const resolved = dateFormatter(locale, { hour: 'numeric' }).resolvedOptions();
|
|
323
|
+
if (resolved.hourCycle) {
|
|
324
|
+
return resolved.hourCycle === 'h11' || resolved.hourCycle === 'h12';
|
|
325
|
+
}
|
|
326
|
+
return resolved.hour12 === true;
|
|
327
|
+
}
|
|
328
|
+
/** What this locale calls AM and PM. */
|
|
329
|
+
export function meridiemLabels(locale) {
|
|
330
|
+
const formatter = dateFormatter(locale, { hour: 'numeric', hour12: true });
|
|
331
|
+
const read = (hours) => {
|
|
332
|
+
const part = formatter
|
|
333
|
+
.formatToParts(withTime(WEEKDAY_ORIGIN, { hours }))
|
|
334
|
+
.find((entry) => entry.type === 'dayPeriod');
|
|
335
|
+
return part?.value ?? (hours < 12 ? 'AM' : 'PM');
|
|
336
|
+
};
|
|
337
|
+
return [read(9), read(21)];
|
|
338
|
+
}
|
|
339
|
+
export function localeWeekStart(locale) {
|
|
340
|
+
try {
|
|
341
|
+
const resolved = locale ?? new Intl.DateTimeFormat().resolvedOptions().locale;
|
|
342
|
+
const info = new Intl.Locale(resolved);
|
|
343
|
+
const week = typeof info.getWeekInfo === 'function' ? info.getWeekInfo() : info.weekInfo;
|
|
344
|
+
// CLDR counts Monday as 1 through Sunday as 7; `getDay` counts Sunday as 0.
|
|
345
|
+
if (typeof week?.firstDay === 'number') {
|
|
346
|
+
return (week.firstDay % 7);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// An unparseable locale tag. Not worth taking the calendar down over.
|
|
351
|
+
}
|
|
352
|
+
return 0;
|
|
353
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Intl` formatters, memoised.
|
|
3
|
+
*
|
|
4
|
+
* Here rather than inline for one reason: constructing a formatter is the
|
|
5
|
+
* expensive half of using one. On V8, `new Intl.DateTimeFormat(...).format(d)`
|
|
6
|
+
* costs about 16us and `format(d)` on a formatter that already exists costs
|
|
7
|
+
* about 0.3us — fifty-five times the work for the same string.
|
|
8
|
+
*
|
|
9
|
+
* That ratio only matters where the call is in a loop or in a render, and in the
|
|
10
|
+
* pickers it is both: a calendar builds seven weekday names and twelve month
|
|
11
|
+
* names for a 42-cell month view, and it builds them again on every step, every
|
|
12
|
+
* hover and every keystroke.
|
|
13
|
+
*
|
|
14
|
+
* The cache is unbounded on purpose. The keys are not user data — they come from
|
|
15
|
+
* a component's own option objects, of which any one page has a handful — so
|
|
16
|
+
* there is nothing here that grows with the size of anything.
|
|
17
|
+
*
|
|
18
|
+
* The options object is deliberately **not** part of the key by identity. A
|
|
19
|
+
* caller writing `format={{ dateStyle: 'medium' }}` inline hands over a new
|
|
20
|
+
* object on every render, which is the ordinary way that prop gets written, and
|
|
21
|
+
* keying on identity would miss every time and cache nothing but garbage.
|
|
22
|
+
*/
|
|
23
|
+
/** A memoised `Intl.DateTimeFormat`. */
|
|
24
|
+
export declare function dateFormatter(locale: string | undefined, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Intl` formatters, memoised.
|
|
3
|
+
*
|
|
4
|
+
* Here rather than inline for one reason: constructing a formatter is the
|
|
5
|
+
* expensive half of using one. On V8, `new Intl.DateTimeFormat(...).format(d)`
|
|
6
|
+
* costs about 16us and `format(d)` on a formatter that already exists costs
|
|
7
|
+
* about 0.3us — fifty-five times the work for the same string.
|
|
8
|
+
*
|
|
9
|
+
* That ratio only matters where the call is in a loop or in a render, and in the
|
|
10
|
+
* pickers it is both: a calendar builds seven weekday names and twelve month
|
|
11
|
+
* names for a 42-cell month view, and it builds them again on every step, every
|
|
12
|
+
* hover and every keystroke.
|
|
13
|
+
*
|
|
14
|
+
* The cache is unbounded on purpose. The keys are not user data — they come from
|
|
15
|
+
* a component's own option objects, of which any one page has a handful — so
|
|
16
|
+
* there is nothing here that grows with the size of anything.
|
|
17
|
+
*
|
|
18
|
+
* The options object is deliberately **not** part of the key by identity. A
|
|
19
|
+
* caller writing `format={{ dateStyle: 'medium' }}` inline hands over a new
|
|
20
|
+
* object on every render, which is the ordinary way that prop gets written, and
|
|
21
|
+
* keying on identity would miss every time and cache nothing but garbage.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* `undefined` locale means the runtime's own, and is a key of its own. The two
|
|
25
|
+
* halves are parted by a NUL, which no locale tag and no option name can
|
|
26
|
+
* contain, so no two different pairs of inputs can spell the same key.
|
|
27
|
+
*/
|
|
28
|
+
function cacheKey(locale, options) {
|
|
29
|
+
return `${locale ?? ''}\u0000${options ? JSON.stringify(options) : ''}`;
|
|
30
|
+
}
|
|
31
|
+
const dateFormatters = new Map();
|
|
32
|
+
/** A memoised `Intl.DateTimeFormat`. */
|
|
33
|
+
export function dateFormatter(locale, options) {
|
|
34
|
+
const key = cacheKey(locale, options);
|
|
35
|
+
let formatter = dateFormatters.get(key);
|
|
36
|
+
if (!formatter) {
|
|
37
|
+
formatter = new Intl.DateTimeFormat(locale, options);
|
|
38
|
+
dateFormatters.set(key, formatter);
|
|
39
|
+
}
|
|
40
|
+
return formatter;
|
|
41
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the vocabulary `PlGrid` and `PlGridItem` share.
|
|
3
|
+
*
|
|
4
|
+
* Like `internal/styles.ts` this is the library talking to itself, and it lives
|
|
5
|
+
* here rather than in either component's folder for one reason: the two are one
|
|
6
|
+
* system in two elements, and neither should have to import the other.
|
|
7
|
+
*
|
|
8
|
+
* What is *not* here is the layout itself. A column width is
|
|
9
|
+
* `(100% + gap) * span / columns - gap`, it has to change at four breakpoints,
|
|
10
|
+
* and it is the width of an element whose column count is declared on its
|
|
11
|
+
* parent — none of which Tailwind can spell, because Tailwind only ever sees
|
|
12
|
+
* class names written out literally and `columns` is a number a caller picks.
|
|
13
|
+
* So the widths are real CSS in `styles.css`, driven by the `--p-*` slots this
|
|
14
|
+
* file generates. That is the same split the rest of the library makes:
|
|
15
|
+
* per-instance values go in inline custom properties, never in class names.
|
|
16
|
+
*/
|
|
17
|
+
import type * as React from 'react';
|
|
18
|
+
import type { PlassAlignItems, PlassAlignSelf, PlassBreakpoint, PlassJustify, PlassResponsive } from '../types.js';
|
|
19
|
+
/** Smallest first, which is also the order the media queries have to be in. */
|
|
20
|
+
export declare const breakpoints: readonly PlassBreakpoint[];
|
|
21
|
+
/**
|
|
22
|
+
* Turns a responsive value into the `--p-{name}-{breakpoint}` slots the CSS
|
|
23
|
+
* reads, emitting only the breakpoints the caller actually named.
|
|
24
|
+
*
|
|
25
|
+
* The gaps are filled in by CSS rather than here: each breakpoint's rule falls
|
|
26
|
+
* back through the ones below it, so `{ md: 6 }` needs one slot and not five.
|
|
27
|
+
* That keeps the inline style on a grid item down to what was asked for.
|
|
28
|
+
*/
|
|
29
|
+
export declare function responsiveSlots<T>(name: string, value: PlassResponsive<T> | undefined, toCss: (value: T) => string): React.CSSProperties;
|
|
30
|
+
/**
|
|
31
|
+
* Fills in the `xs` entry of a partial map with the prop's own default.
|
|
32
|
+
*
|
|
33
|
+
* Without this, `spacing={{ md: 4 }}` would be a grid with no gutter at all
|
|
34
|
+
* below 48rem — the CSS fallback rather than the documented default — and a
|
|
35
|
+
* caller who narrowed one breakpoint would silently lose every other one. A map
|
|
36
|
+
* says "from here up, use this instead"; it does not say "and nothing below".
|
|
37
|
+
*/
|
|
38
|
+
export declare function withBaseline<T>(value: PlassResponsive<T> | undefined, baseline: T): PlassResponsive<T>;
|
|
39
|
+
/**
|
|
40
|
+
* A count of columns, as a plain number for `calc()` to divide by.
|
|
41
|
+
*
|
|
42
|
+
* Rounded and floored at 1 because the value ends up as a divisor: a grid of
|
|
43
|
+
* 2.5 columns is not a thing anybody meant, and a grid of 0 is a division by
|
|
44
|
+
* zero that would take the width declaration down with it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function columnCount(value: number): string;
|
|
47
|
+
/** A span or an offset. Same rounding; an offset of 0 is meaningful. */
|
|
48
|
+
export declare function columnUnits(value: number, min: number): string;
|
|
49
|
+
export declare const spanValue: (value: number) => string;
|
|
50
|
+
export declare const offsetValue: (value: number) => string;
|
|
51
|
+
/**
|
|
52
|
+
* A gutter, as a length.
|
|
53
|
+
*
|
|
54
|
+
* Fractions are the point — `spacing={1.5}` is `0.375rem`, the same step
|
|
55
|
+
* `gap-1.5` is — so the multiplication is rounded to five places rather than
|
|
56
|
+
* left to print `0.30000000000000004rem` into the DOM.
|
|
57
|
+
*/
|
|
58
|
+
export declare function spacingValue(units: number): string;
|
|
59
|
+
export declare const justifyClasses: Record<PlassJustify, string>;
|
|
60
|
+
export declare const alignItemsClasses: Record<PlassAlignItems, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Where the *rows* sit when the grid is shorter than the box holding it. Only
|
|
63
|
+
* ever visible on a grid with a height of its own, which is why it takes the
|
|
64
|
+
* full distribution vocabulary and `alignItems` does not.
|
|
65
|
+
*/
|
|
66
|
+
export declare const alignContentClasses: Record<PlassJustify, string>;
|
|
67
|
+
export declare const alignSelfClasses: Record<PlassAlignSelf, string>;
|