@getmicdrop/svelte-components 5.17.0 → 5.17.3
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/calendar/AboutShow/AboutShow.svelte +187 -187
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
- package/dist/calendar/FAQs/FAQs.svelte +77 -77
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
- package/dist/calendar/OrderSummary/OrderSummary.svelte +457 -457
- package/dist/calendar/PublicCard/PublicCard.svelte +146 -146
- package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
- package/dist/components/Heading.spec.d.ts +2 -0
- package/dist/components/Heading.spec.d.ts.map +1 -0
- package/dist/components/Heading.spec.js +89 -0
- package/dist/components/Heading.svelte +60 -60
- package/dist/components/Layout/AppShell.svelte +104 -104
- package/dist/components/Layout/ContentSection.svelte +80 -80
- package/dist/components/Layout/Grid.svelte +4 -4
- package/dist/components/Layout/Heading.svelte +81 -81
- package/dist/components/Layout/PageContainer.svelte +69 -69
- package/dist/components/Layout/Responsive.svelte +75 -75
- package/dist/components/Layout/Section.svelte +80 -80
- package/dist/components/Layout/ShowOnDesktop.svelte +37 -37
- package/dist/components/Layout/ShowOnMobile.svelte +37 -37
- package/dist/components/Layout/Sidebar.svelte +108 -108
- package/dist/components/Layout/Stack.spec.js +1 -1
- package/dist/components/Layout/Stack.svelte +6 -6
- package/dist/components/Layout/Text.svelte +87 -87
- package/dist/components/Layout/TwoColumn.svelte +108 -108
- package/dist/components/Layout/__tests__/AppShell.test.js +140 -0
- package/dist/components/Text.spec.d.ts +2 -0
- package/dist/components/Text.spec.d.ts.map +1 -0
- package/dist/components/Text.spec.js +89 -0
- package/dist/components/Text.svelte +53 -53
- package/dist/constants/validation.js +91 -91
- package/dist/constants/validation.spec.js +64 -64
- package/dist/datetime/__tests__/format.test.js +1 -1
- package/dist/datetime/__tests__/parse.test.js +1 -1
- package/dist/datetime/__tests__/timezone.test.js +1 -1
- package/dist/datetime/parse.js +1 -1
- package/dist/datetime/timezone.d.ts.map +1 -1
- package/dist/datetime/timezone.js +1 -2
- package/dist/forms/createFormStore.svelte.d.ts +1 -1
- package/dist/forms/createFormStore.svelte.d.ts.map +1 -1
- package/dist/forms/createFormStore.svelte.js +1 -0
- package/dist/forms/createFormStore.svelte.spec.d.ts +2 -0
- package/dist/forms/createFormStore.svelte.spec.d.ts.map +1 -0
- package/dist/forms/createFormStore.svelte.spec.js +388 -0
- package/dist/index.js +57 -57
- package/dist/index.spec.js +369 -369
- package/dist/patterns/chat/ChatActivityNotice.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatActivityNotice.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatActivityNotice.spec.js +59 -0
- package/dist/patterns/chat/ChatActivityNotice.svelte +41 -41
- package/dist/patterns/chat/ChatBubble.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatBubble.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatBubble.spec.js +91 -0
- package/dist/patterns/chat/ChatBubble.svelte +95 -95
- package/dist/patterns/chat/ChatContainer.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatContainer.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatContainer.spec.js +30 -0
- package/dist/patterns/chat/ChatContainer.svelte +46 -46
- package/dist/patterns/chat/ChatDateDivider.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatDateDivider.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatDateDivider.spec.js +30 -0
- package/dist/patterns/chat/ChatDateDivider.svelte +27 -27
- package/dist/patterns/chat/ChatInvitationBubble.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatInvitationBubble.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatInvitationBubble.spec.js +46 -0
- package/dist/patterns/chat/ChatInvitationBubble.svelte +37 -37
- package/dist/patterns/chat/ChatInvitationNotice.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatInvitationNotice.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatInvitationNotice.spec.js +32 -0
- package/dist/patterns/chat/ChatInvitationNotice.svelte +27 -27
- package/dist/patterns/chat/ChatMessageGroup.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatMessageGroup.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatMessageGroup.spec.js +58 -0
- package/dist/patterns/chat/ChatMessageGroup.svelte +57 -57
- package/dist/patterns/chat/ChatSlotUpdate.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatSlotUpdate.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatSlotUpdate.spec.js +65 -0
- package/dist/patterns/chat/ChatSlotUpdate.svelte +46 -46
- package/dist/patterns/chat/ChatStatusBadge.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatStatusBadge.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatStatusBadge.spec.js +79 -0
- package/dist/patterns/chat/ChatStatusBadge.svelte +91 -91
- package/dist/patterns/chat/ChatStatusTransition.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatStatusTransition.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatStatusTransition.spec.js +81 -0
- package/dist/patterns/chat/ChatStatusTransition.svelte +64 -64
- package/dist/patterns/chat/ChatTextBubble.spec.d.ts +2 -0
- package/dist/patterns/chat/ChatTextBubble.spec.d.ts.map +1 -0
- package/dist/patterns/chat/ChatTextBubble.spec.js +35 -0
- package/dist/patterns/chat/ChatTextBubble.svelte +41 -41
- package/dist/patterns/chat/index.js +22 -22
- package/dist/patterns/data/DataGrid.svelte +45 -45
- package/dist/patterns/data/DataList.svelte +24 -24
- package/dist/patterns/data/DataTable.spec.js +61 -0
- package/dist/patterns/data/DataTable.svelte +36 -36
- package/dist/patterns/forms/FormActions.spec.js +95 -95
- package/dist/patterns/forms/FormActions.stories.svelte +97 -97
- package/dist/patterns/forms/FormActions.svelte +46 -46
- package/dist/patterns/forms/FormGrid.spec.js +34 -0
- package/dist/patterns/forms/FormGrid.svelte +33 -33
- package/dist/patterns/forms/FormSection.svelte +32 -32
- package/dist/patterns/forms/FormValidationSummary.stories.svelte +83 -83
- package/dist/patterns/forms/FormValidationSummary.svelte +74 -74
- package/dist/patterns/index.js +21 -21
- package/dist/patterns/layout/Sidebar.spec.js +240 -1
- package/dist/patterns/layout/Sidebar.svelte +39 -39
- package/dist/patterns/layout/SidebarTestWrapper.svelte +34 -0
- package/dist/patterns/layout/SidebarTestWrapper.svelte.d.ts +23 -0
- package/dist/patterns/layout/SidebarTestWrapper.svelte.d.ts.map +1 -0
- package/dist/patterns/layout/index.js +29 -29
- package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
- package/dist/patterns/navigation/BottomNav.svelte +74 -74
- package/dist/patterns/navigation/Header.spec.js +123 -0
- package/dist/patterns/navigation/Header.stories.svelte +77 -77
- package/dist/patterns/navigation/Header.svelte +251 -251
- package/dist/patterns/page/PageHeader.svelte +18 -18
- package/dist/patterns/page/PageLayout.svelte +40 -40
- package/dist/patterns/page/PageLoader.spec.js +57 -57
- package/dist/patterns/page/PageLoader.stories.svelte +137 -137
- package/dist/patterns/page/PageLoader.svelte +24 -24
- package/dist/patterns/page/SectionHeader.svelte +29 -29
- package/dist/presets/badges.js +112 -112
- package/dist/presets/buttons.js +76 -76
- package/dist/presets/index.js +9 -9
- package/dist/primitives/Accordion/Accordion.spec.js +112 -2
- package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
- package/dist/primitives/Accordion/Accordion.svelte +42 -42
- package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
- package/dist/primitives/Accordion/AccordionToggleWrapper.test.svelte +28 -0
- package/dist/primitives/Accordion/AccordionToggleWrapper.test.svelte.d.ts +7 -0
- package/dist/primitives/Accordion/AccordionToggleWrapper.test.svelte.d.ts.map +1 -0
- package/dist/primitives/Alert/Alert.spec.js +173 -173
- package/dist/primitives/Alert/Alert.stories.svelte +88 -88
- package/dist/primitives/Alert/Alert.svelte +27 -27
- package/dist/primitives/Avatar/Avatar.spec.js +23 -0
- package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
- package/dist/primitives/Avatar/Avatar.svelte +66 -66
- package/dist/primitives/AvatarButton/AvatarButton.svelte +57 -57
- package/dist/primitives/Badges/Badge.spec.js +144 -144
- package/dist/primitives/Badges/Badge.stories.svelte +86 -86
- package/dist/primitives/Badges/Badge.svelte +99 -99
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +238 -136
- package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
- package/dist/primitives/BottomSheet/BottomSheet.svelte +115 -115
- package/dist/primitives/BottomSheet/BottomSheetWithActions.test.svelte +20 -0
- package/dist/primitives/BottomSheet/BottomSheetWithActions.test.svelte.d.ts +10 -0
- package/dist/primitives/BottomSheet/BottomSheetWithActions.test.svelte.d.ts.map +1 -0
- package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +123 -123
- package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +99 -99
- package/dist/primitives/Button/Button.spec.js +225 -225
- package/dist/primitives/Button/Button.stories.svelte +76 -76
- package/dist/primitives/Button/Button.svelte +278 -278
- package/dist/primitives/Button/ButtonGroup.spec.d.ts +2 -0
- package/dist/primitives/Button/ButtonGroup.spec.d.ts.map +1 -0
- package/dist/primitives/Button/ButtonGroup.spec.js +44 -0
- package/dist/primitives/Button/ButtonGroup.svelte +50 -50
- package/dist/primitives/Button/ButtonSaveDemo.spec.js +146 -146
- package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
- package/dist/primitives/Card.spec.js +49 -49
- package/dist/primitives/Card.stories.svelte +22 -22
- package/dist/primitives/Card.svelte +28 -28
- package/dist/primitives/CardAction/CardAction.svelte +68 -68
- package/dist/primitives/Checkbox/Checkbox.spec.js +32 -0
- package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
- package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
- package/dist/primitives/DarkModeToggle.spec.js +390 -390
- package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
- package/dist/primitives/DarkModeToggle.svelte +136 -136
- package/dist/primitives/Drawer/Drawer.spec.js +437 -0
- package/dist/primitives/Drawer/Drawer.stories.svelte +80 -80
- package/dist/primitives/Drawer/Drawer.svelte +224 -224
- package/dist/primitives/Drawer/DrawerTestWrapper.svelte +86 -0
- package/dist/primitives/Drawer/DrawerTestWrapper.svelte.d.ts +26 -0
- package/dist/primitives/Drawer/DrawerTestWrapper.svelte.d.ts.map +1 -0
- package/dist/primitives/Dropdown/Dropdown.spec.js +116 -0
- package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
- package/dist/primitives/Dropdown/Dropdown.svelte +170 -170
- package/dist/primitives/Dropdown/DropdownDivider.spec.d.ts +2 -0
- package/dist/primitives/Dropdown/DropdownDivider.spec.d.ts.map +1 -0
- package/dist/primitives/Dropdown/DropdownDivider.spec.js +30 -0
- package/dist/primitives/Dropdown/DropdownDivider.svelte +9 -9
- package/dist/primitives/Dropdown/DropdownItem.spec.js +155 -1
- package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
- package/dist/primitives/Dropdown/DropdownItemTestWrapper.svelte +43 -0
- package/dist/primitives/Dropdown/DropdownItemTestWrapper.svelte.d.ts +17 -0
- package/dist/primitives/Dropdown/DropdownItemTestWrapper.svelte.d.ts.map +1 -0
- package/dist/primitives/Helper/Helper.spec.d.ts +2 -0
- package/dist/primitives/Helper/Helper.spec.d.ts.map +1 -0
- package/dist/primitives/Helper/Helper.spec.js +57 -0
- package/dist/primitives/Helper/Helper.svelte +33 -33
- package/dist/primitives/Icons/ArrowLeft.svelte +8 -8
- package/dist/primitives/Icons/ArrowRight.svelte +8 -8
- package/dist/primitives/Icons/Availability.svelte +14 -14
- package/dist/primitives/Icons/Back.svelte +14 -14
- package/dist/primitives/Icons/CheckCircle.svelte +6 -6
- package/dist/primitives/Icons/CheckCircleOutline.svelte +15 -15
- package/dist/primitives/Icons/ChevronLeft.svelte +4 -4
- package/dist/primitives/Icons/ChevronRight.svelte +4 -4
- package/dist/primitives/Icons/Copy.svelte +15 -15
- package/dist/primitives/Icons/Cross.svelte +5 -5
- package/dist/primitives/Icons/DownArrow.svelte +8 -8
- package/dist/primitives/Icons/ErrorCircle.svelte +6 -6
- package/dist/primitives/Icons/FacebookIcon.svelte +2 -2
- package/dist/primitives/Icons/Home.svelte +15 -15
- package/dist/primitives/Icons/Icon.spec.js +169 -169
- package/dist/primitives/Icons/Icon.stories.svelte +100 -100
- package/dist/primitives/Icons/Icon.svelte +52 -52
- package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
- package/dist/primitives/Icons/Info.svelte +7 -7
- package/dist/primitives/Icons/InstagramIcon.svelte +4 -4
- package/dist/primitives/Icons/LogoInstagram.svelte +2 -2
- package/dist/primitives/Icons/Message.svelte +15 -15
- package/dist/primitives/Icons/MoonIcon.svelte +5 -5
- package/dist/primitives/Icons/More.svelte +21 -21
- package/dist/primitives/Icons/MoreHori.spec.js +61 -61
- package/dist/primitives/Icons/MoreHori.svelte +22 -22
- package/dist/primitives/Icons/Notification.svelte +14 -14
- package/dist/primitives/Icons/Payment.svelte +14 -14
- package/dist/primitives/Icons/Profile.svelte +21 -21
- package/dist/primitives/Icons/Reload.svelte +29 -29
- package/dist/primitives/Icons/Shows.svelte +21 -21
- package/dist/primitives/Icons/Signout.svelte +21 -21
- package/dist/primitives/Icons/SunIcon.svelte +8 -8
- package/dist/primitives/Icons/TiktokIcon.svelte +2 -2
- package/dist/primitives/Icons/TwitterIcon.svelte +2 -2
- package/dist/primitives/Icons/WarningIcon.spec.js +18 -18
- package/dist/primitives/Icons/WarningIcon.svelte +5 -5
- package/dist/primitives/Input/Input.spec.js +1235 -573
- package/dist/primitives/Input/Input.stories.svelte +139 -139
- package/dist/primitives/Input/Input.svelte +423 -423
- package/dist/primitives/Input/Select.spec.js +632 -218
- package/dist/primitives/Input/Select.stories.svelte +112 -112
- package/dist/primitives/Input/Select.svelte +252 -252
- package/dist/primitives/Input/Textarea.stories.svelte +137 -137
- package/dist/primitives/Input/Textarea.svelte +105 -105
- package/dist/primitives/Label/Label.spec.js +9 -0
- package/dist/primitives/Label/Label.svelte +37 -37
- package/dist/primitives/LandingButton/LandingButton.spec.d.ts +2 -0
- package/dist/primitives/LandingButton/LandingButton.spec.d.ts.map +1 -0
- package/dist/primitives/LandingButton/LandingButton.spec.js +61 -0
- package/dist/primitives/LandingButton/LandingButton.svelte +92 -92
- package/dist/primitives/MenuItem/MenuItem.spec.d.ts +2 -0
- package/dist/primitives/MenuItem/MenuItem.spec.d.ts.map +1 -0
- package/dist/primitives/MenuItem/MenuItem.spec.js +130 -0
- package/dist/primitives/MenuItem/MenuItem.svelte +85 -85
- package/dist/primitives/Modal/Modal.spec.js +314 -99
- package/dist/primitives/Modal/Modal.stories.svelte +86 -86
- package/dist/primitives/Modal/Modal.svelte +181 -181
- package/dist/primitives/NavItem/NavItem.spec.d.ts +2 -0
- package/dist/primitives/NavItem/NavItem.spec.d.ts.map +1 -0
- package/dist/primitives/NavItem/NavItem.spec.js +97 -0
- package/dist/primitives/NavItem/NavItem.svelte +75 -75
- package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
- package/dist/primitives/Pagination/Pagination.svelte +261 -261
- package/dist/primitives/Radio/Radio.stories.svelte +80 -80
- package/dist/primitives/Radio/Radio.svelte +67 -67
- package/dist/primitives/SearchResultItem/SearchResultItem.spec.d.ts +2 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.spec.d.ts.map +1 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.spec.js +78 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.svelte +109 -109
- package/dist/primitives/SidebarToggle/SidebarToggle.spec.d.ts +2 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.spec.d.ts.map +1 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.spec.js +61 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.svelte +55 -55
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
- package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
- package/dist/primitives/Skeleton/Skeleton.svelte +26 -26
- package/dist/primitives/Spinner/Spinner.spec.js +84 -71
- package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
- package/dist/primitives/Spinner/Spinner.svelte +20 -20
- package/dist/primitives/Tabs/TabItem.svelte +49 -49
- package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
- package/dist/primitives/Tabs/Tabs.svelte +137 -137
- package/dist/primitives/Toggle.spec.js +221 -146
- package/dist/primitives/Toggle.stories.svelte +92 -92
- package/dist/primitives/Toggle.svelte +141 -141
- package/dist/primitives/ToggleTestWrapper.svelte +30 -0
- package/dist/primitives/ToggleTestWrapper.svelte.d.ts +29 -0
- package/dist/primitives/ToggleTestWrapper.svelte.d.ts.map +1 -0
- package/dist/primitives/Tooltip/Tooltip.spec.d.ts +2 -0
- package/dist/primitives/Tooltip/Tooltip.spec.d.ts.map +1 -0
- package/dist/primitives/Tooltip/Tooltip.spec.js +126 -0
- package/dist/primitives/Tooltip/Tooltip.svelte +83 -83
- package/dist/primitives/Typography/Typography.svelte +53 -53
- package/dist/primitives/ValidationError.spec.js +103 -103
- package/dist/primitives/ValidationError.stories.svelte +69 -69
- package/dist/primitives/ValidationError.svelte +29 -29
- package/dist/primitives/index.js +113 -113
- package/dist/recipes/CropImage/CropImage.spec.js +208 -208
- package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
- package/dist/recipes/CropImage/CropImage.svelte +241 -241
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
- package/dist/recipes/ImageUploader/ImageUploader.svelte +992 -992
- package/dist/recipes/SuperLogin/SuperLogin.spec.js +21 -21
- package/dist/recipes/SuperLogin/SuperLogin.svelte +4 -4
- package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +1 -1
- package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
- package/dist/recipes/feedback/ErrorDisplay.stories.svelte +101 -101
- package/dist/recipes/feedback/ErrorDisplay.svelte +1 -1
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +133 -133
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +157 -157
- package/dist/recipes/fields/CheckboxField.svelte +85 -85
- package/dist/recipes/fields/FormField.svelte +58 -58
- package/dist/recipes/fields/RadioGroup.svelte +95 -95
- package/dist/recipes/fields/SelectField.svelte +82 -82
- package/dist/recipes/fields/TextareaField.svelte +97 -97
- package/dist/recipes/fields/ToggleField.svelte +60 -60
- package/dist/recipes/fields/index.js +7 -7
- package/dist/recipes/inputs/MultiSelect.spec.js +263 -263
- package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
- package/dist/recipes/inputs/MultiSelect.svelte +283 -283
- package/dist/recipes/inputs/OTPInput.spec.js +251 -251
- package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
- package/dist/recipes/inputs/OTPInput.svelte +117 -117
- package/dist/recipes/inputs/PasswordInput.svelte +22 -22
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +131 -131
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +19 -19
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +123 -123
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +336 -339
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/Search.spec.js +66 -2
- package/dist/recipes/inputs/Search.svelte +102 -102
- package/dist/recipes/inputs/index.js +7 -7
- package/dist/recipes/modals/AlertModal.svelte +130 -130
- package/dist/recipes/modals/ConfirmationModal.spec.js +396 -206
- package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
- package/dist/recipes/modals/ConfirmationModal.svelte +162 -162
- package/dist/recipes/modals/InputModal.svelte +182 -182
- package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
- package/dist/recipes/modals/ModalStateManager.svelte +77 -77
- package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
- package/dist/recipes/modals/StatusModal.svelte +206 -206
- package/dist/services/EventService.d.ts +1 -1
- package/dist/services/EventService.d.ts.map +1 -1
- package/dist/services/EventService.js +79 -75
- package/dist/services/EventService.spec.js +217 -217
- package/dist/services/ShowService.js +144 -143
- package/dist/services/ShowService.spec.js +345 -345
- package/dist/stores/auth.svelte.spec.d.ts +2 -0
- package/dist/stores/auth.svelte.spec.d.ts.map +1 -0
- package/dist/stores/auth.svelte.spec.js +112 -0
- package/dist/stores/formDataStore.svelte.spec.d.ts +2 -0
- package/dist/stores/formDataStore.svelte.spec.d.ts.map +1 -0
- package/dist/stores/formDataStore.svelte.spec.js +150 -0
- package/dist/stores/formSave.svelte.spec.d.ts +2 -0
- package/dist/stores/formSave.svelte.spec.d.ts.map +1 -0
- package/dist/stores/formSave.svelte.spec.js +196 -0
- package/dist/stores/navigation.spec.d.ts +2 -0
- package/dist/stores/navigation.spec.d.ts.map +1 -0
- package/dist/stores/navigation.spec.js +53 -0
- package/dist/stores/toaster.js +13 -13
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
- package/dist/stories/ButtonAuditReview.svelte +427 -427
- package/dist/stories/PatternsGallery.stories.svelte +19 -19
- package/dist/stories/PatternsGallery.svelte +206 -206
- package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
- package/dist/stories/PrimitivesGallery.svelte +756 -756
- package/dist/stories/RecipesGallery.stories.svelte +19 -19
- package/dist/stories/RecipesGallery.svelte +454 -454
- package/dist/stories/button-audit-manifest.json +11186 -11186
- package/dist/tailwind/preset.cjs +82 -82
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +402 -405
- package/dist/telemetry.server.js +212 -212
- package/dist/telemetry.server.spec.js +437 -438
- package/dist/telemetry.spec.js +1168 -1169
- package/dist/tokens/tokens.css +87 -87
- package/dist/tokens/typography-base.css +163 -163
- package/dist/tokens/utilities.css +353 -353
- package/dist/utils/apiConfig.js +117 -120
- package/dist/utils/apiConfig.spec.js +219 -219
- package/dist/utils/greetings.js +187 -187
- package/dist/utils/haptic.spec.d.ts +2 -0
- package/dist/utils/haptic.spec.d.ts.map +1 -0
- package/dist/utils/haptic.spec.js +153 -0
- package/dist/utils/imageOptimizer.spec.d.ts +2 -0
- package/dist/utils/imageOptimizer.spec.d.ts.map +1 -0
- package/dist/utils/imageOptimizer.spec.js +201 -0
- package/dist/utils/imageValidation.js +121 -121
- package/dist/utils/logger.spec.d.ts +2 -0
- package/dist/utils/logger.spec.d.ts.map +1 -0
- package/dist/utils/logger.spec.js +95 -0
- package/dist/utils/transitions.js +4 -4
- package/dist/utils/utils.js +693 -693
- package/package.json +292 -294
|
@@ -2,6 +2,7 @@ import { render, screen, waitFor } from '@testing-library/svelte';
|
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { expect, describe, test, vi, beforeEach, afterEach } from 'vitest';
|
|
4
4
|
import Drawer from './Drawer.svelte';
|
|
5
|
+
import DrawerTestWrapper from './DrawerTestWrapper.svelte';
|
|
5
6
|
|
|
6
7
|
describe('Drawer Component', () => {
|
|
7
8
|
beforeEach(() => {
|
|
@@ -209,4 +210,440 @@ describe('Drawer Callbacks', () => {
|
|
|
209
210
|
});
|
|
210
211
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
211
212
|
});
|
|
213
|
+
|
|
214
|
+
test('backdrop click calls onclose', async () => {
|
|
215
|
+
const onclose = vi.fn();
|
|
216
|
+
const { container } = render(Drawer, {
|
|
217
|
+
props: { open: true, closeOnBackdropClick: true, onclose }
|
|
218
|
+
});
|
|
219
|
+
const backdrop = container.querySelector('[role="presentation"]');
|
|
220
|
+
expect(backdrop).toBeInTheDocument();
|
|
221
|
+
await userEvent.click(backdrop);
|
|
222
|
+
expect(onclose).toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('escape key closes drawer', async () => {
|
|
226
|
+
const onclose = vi.fn();
|
|
227
|
+
render(Drawer, {
|
|
228
|
+
props: { open: true, closeOnEscape: true, onclose }
|
|
229
|
+
});
|
|
230
|
+
await userEvent.keyboard('{Escape}');
|
|
231
|
+
expect(onclose).toHaveBeenCalled();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('escape key does not close when closeOnEscape is false', async () => {
|
|
235
|
+
const onclose = vi.fn();
|
|
236
|
+
render(Drawer, {
|
|
237
|
+
props: { open: true, closeOnEscape: false, onclose }
|
|
238
|
+
});
|
|
239
|
+
await userEvent.keyboard('{Escape}');
|
|
240
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('Drawer Additional Props', () => {
|
|
245
|
+
test('xl width applies w-[28rem]', () => {
|
|
246
|
+
const { container } = render(Drawer, { props: { open: true, width: 'xl' } });
|
|
247
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
248
|
+
expect(dialog).toHaveClass('w-[28rem]');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('default placement falls back to left', () => {
|
|
252
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
253
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
254
|
+
expect(dialog).toHaveClass('left-0');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('unknown width falls back to md', () => {
|
|
258
|
+
const { container } = render(Drawer, { props: { open: true, width: 'unknown' } });
|
|
259
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
260
|
+
expect(dialog).toHaveClass('w-80');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('sets aria-labelledby only when title and id both provided', () => {
|
|
264
|
+
const { container } = render(Drawer, { props: { open: true, title: '' } });
|
|
265
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
266
|
+
expect(dialog).not.toHaveAttribute('aria-labelledby');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test('renders header when title is set', () => {
|
|
270
|
+
const { container } = render(Drawer, {
|
|
271
|
+
props: { open: true, title: 'My Title', id: 'test-id' }
|
|
272
|
+
});
|
|
273
|
+
expect(container.querySelector('header')).toBeInTheDocument();
|
|
274
|
+
expect(screen.getByText('My Title')).toBeInTheDocument();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('no header when title is empty and no header snippet', () => {
|
|
278
|
+
const { container } = render(Drawer, { props: { open: true, title: '' } });
|
|
279
|
+
expect(container.querySelector('header')).not.toBeInTheDocument();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('right placement has border-l', () => {
|
|
283
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'right' } });
|
|
284
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
285
|
+
expect(dialog).toHaveClass('border-l');
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('top placement has full width', () => {
|
|
289
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'top' } });
|
|
290
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
291
|
+
expect(dialog).toHaveClass('w-full');
|
|
292
|
+
expect(dialog).toHaveClass('border-b');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('bottom placement has full width', () => {
|
|
296
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'bottom' } });
|
|
297
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
298
|
+
expect(dialog).toHaveClass('w-full');
|
|
299
|
+
expect(dialog).toHaveClass('border-t');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// ─── NEW TESTS: Uncovered branches ───────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
describe('Drawer Snippet Rendering (via TestWrapper)', () => {
|
|
306
|
+
test('renders custom header snippet instead of title', () => {
|
|
307
|
+
const { container } = render(DrawerTestWrapper, {
|
|
308
|
+
props: { open: true, showHeader: true, headerText: 'My Custom Header' }
|
|
309
|
+
});
|
|
310
|
+
expect(container.querySelector('header')).toBeInTheDocument();
|
|
311
|
+
expect(screen.getByTestId('custom-header')).toBeInTheDocument();
|
|
312
|
+
expect(screen.getByText('My Custom Header')).toBeInTheDocument();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('renders header section when header snippet is provided even without title', () => {
|
|
316
|
+
const { container } = render(DrawerTestWrapper, {
|
|
317
|
+
props: { open: true, title: '', showHeader: true }
|
|
318
|
+
});
|
|
319
|
+
// The header section should render because the header snippet is always passed from the wrapper
|
|
320
|
+
expect(container.querySelector('header')).toBeInTheDocument();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test('renders children content', () => {
|
|
324
|
+
const { container } = render(DrawerTestWrapper, {
|
|
325
|
+
props: { open: true, showChildren: true, childrenText: 'Hello Drawer Body' }
|
|
326
|
+
});
|
|
327
|
+
expect(screen.getByTestId('drawer-children')).toBeInTheDocument();
|
|
328
|
+
expect(screen.getByText('Hello Drawer Body')).toBeInTheDocument();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test('renders actions footer when actions snippet is provided', () => {
|
|
332
|
+
const { container } = render(DrawerTestWrapper, {
|
|
333
|
+
props: { open: true, showActions: true, actionsText: 'Save Changes' }
|
|
334
|
+
});
|
|
335
|
+
// The footer element should be rendered (line 219)
|
|
336
|
+
expect(container.querySelector('footer')).toBeInTheDocument();
|
|
337
|
+
expect(screen.getByTestId('drawer-actions')).toBeInTheDocument();
|
|
338
|
+
expect(screen.getByText('Save Changes')).toBeInTheDocument();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test('actions footer has correct styling classes', () => {
|
|
342
|
+
const { container } = render(DrawerTestWrapper, {
|
|
343
|
+
props: { open: true, showActions: true }
|
|
344
|
+
});
|
|
345
|
+
const footer = container.querySelector('footer');
|
|
346
|
+
expect(footer).toBeInTheDocument();
|
|
347
|
+
expect(footer).toHaveClass('shrink-0');
|
|
348
|
+
expect(footer).toHaveClass('p-4');
|
|
349
|
+
expect(footer).toHaveClass('border-t');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test('no footer when actions snippet is not provided', () => {
|
|
353
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
354
|
+
expect(container.querySelector('footer')).not.toBeInTheDocument();
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
describe('Drawer Unknown/Default Placement Branch', () => {
|
|
359
|
+
test('invalid placement falls back to left-0 via default switch case for placementClasses', () => {
|
|
360
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'invalid' } });
|
|
361
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
362
|
+
// The default case in placementClasses returns the same as 'left'
|
|
363
|
+
expect(dialog).toHaveClass('left-0');
|
|
364
|
+
expect(dialog).toHaveClass('h-screen');
|
|
365
|
+
expect(dialog).toHaveClass('border-r');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test('invalid placement falls back to left fly transition via default switch case', () => {
|
|
369
|
+
// This exercises the default case in flyParams (line 69)
|
|
370
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'diagonal' } });
|
|
371
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
372
|
+
// If the default case is hit, it still renders with left-like classes
|
|
373
|
+
expect(dialog).toHaveClass('left-0');
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('Drawer Edge Mode - Edge Click and Callbacks', () => {
|
|
378
|
+
test('edge trigger click opens drawer and calls onopen', async () => {
|
|
379
|
+
const onopen = vi.fn();
|
|
380
|
+
const { container } = render(Drawer, {
|
|
381
|
+
props: { edge: true, placement: 'bottom', open: false, onopen }
|
|
382
|
+
});
|
|
383
|
+
const edgeTrigger = container.querySelector('.cursor-pointer');
|
|
384
|
+
expect(edgeTrigger).toBeInTheDocument();
|
|
385
|
+
await userEvent.click(edgeTrigger);
|
|
386
|
+
expect(onopen).toHaveBeenCalled();
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test('edge trigger does not show when edge=false', () => {
|
|
390
|
+
const { container } = render(Drawer, {
|
|
391
|
+
props: { edge: false, placement: 'bottom', open: false }
|
|
392
|
+
});
|
|
393
|
+
const edgeTrigger = container.querySelector('.cursor-pointer.fixed');
|
|
394
|
+
expect(edgeTrigger).not.toBeInTheDocument();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test('edge trigger does not show when placement is not bottom', () => {
|
|
398
|
+
const { container } = render(Drawer, {
|
|
399
|
+
props: { edge: true, placement: 'left', open: false }
|
|
400
|
+
});
|
|
401
|
+
const edgeTrigger = container.querySelector('.cursor-pointer.fixed');
|
|
402
|
+
expect(edgeTrigger).not.toBeInTheDocument();
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test('edge trigger applies custom edgeOffset style', () => {
|
|
406
|
+
const { container } = render(Drawer, {
|
|
407
|
+
props: { edge: true, placement: 'bottom', open: false, edgeOffset: 100 }
|
|
408
|
+
});
|
|
409
|
+
const edgeTrigger = container.querySelector('.cursor-pointer');
|
|
410
|
+
expect(edgeTrigger).toBeInTheDocument();
|
|
411
|
+
expect(edgeTrigger).toHaveStyle('bottom: 100px');
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
test('edge trigger uses default edgeOffset of 60', () => {
|
|
415
|
+
const { container } = render(Drawer, {
|
|
416
|
+
props: { edge: true, placement: 'bottom', open: false }
|
|
417
|
+
});
|
|
418
|
+
const edgeTrigger = container.querySelector('.cursor-pointer');
|
|
419
|
+
expect(edgeTrigger).toBeInTheDocument();
|
|
420
|
+
expect(edgeTrigger).toHaveStyle('bottom: 60px');
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe('Drawer Backdrop Click Branches', () => {
|
|
425
|
+
test('backdrop click does NOT close when closeOnBackdropClick is false', async () => {
|
|
426
|
+
const onclose = vi.fn();
|
|
427
|
+
const { container } = render(Drawer, {
|
|
428
|
+
props: { open: true, closeOnBackdropClick: false, onclose }
|
|
429
|
+
});
|
|
430
|
+
const backdrop = container.querySelector('[role="presentation"]');
|
|
431
|
+
expect(backdrop).toBeInTheDocument();
|
|
432
|
+
await userEvent.click(backdrop);
|
|
433
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test('clicking inside drawer (not backdrop) does not trigger close', async () => {
|
|
437
|
+
const onclose = vi.fn();
|
|
438
|
+
const { container } = render(Drawer, {
|
|
439
|
+
props: { open: true, closeOnBackdropClick: true, onclose, title: 'Test' }
|
|
440
|
+
});
|
|
441
|
+
// Click the drawer dialog itself, not the backdrop
|
|
442
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
443
|
+
await userEvent.click(dialog);
|
|
444
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
describe('Drawer Focus Management', () => {
|
|
449
|
+
test('drawer receives focus when opened', async () => {
|
|
450
|
+
vi.useFakeTimers();
|
|
451
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
452
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
453
|
+
// The setTimeout in the effect focuses the drawer
|
|
454
|
+
vi.runAllTimers();
|
|
455
|
+
await waitFor(() => {
|
|
456
|
+
expect(dialog).toBe(document.activeElement);
|
|
457
|
+
});
|
|
458
|
+
vi.useRealTimers();
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('focus is restored to previously focused element when drawer closes', async () => {
|
|
462
|
+
vi.useFakeTimers();
|
|
463
|
+
// Create a button to focus before opening the drawer
|
|
464
|
+
const button = document.createElement('button');
|
|
465
|
+
button.textContent = 'Focus Me';
|
|
466
|
+
document.body.appendChild(button);
|
|
467
|
+
button.focus();
|
|
468
|
+
expect(document.activeElement).toBe(button);
|
|
469
|
+
|
|
470
|
+
// Open the drawer - this stores the previously focused element
|
|
471
|
+
const { rerender } = render(Drawer, { props: { open: true } });
|
|
472
|
+
vi.runAllTimers();
|
|
473
|
+
|
|
474
|
+
// Close the drawer - this should restore focus (line 143-145 / line 147)
|
|
475
|
+
await rerender({ open: false });
|
|
476
|
+
vi.runAllTimers();
|
|
477
|
+
|
|
478
|
+
await waitFor(() => {
|
|
479
|
+
expect(document.activeElement).toBe(button);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Clean up
|
|
483
|
+
document.body.removeChild(button);
|
|
484
|
+
vi.useRealTimers();
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
test('closing drawer when previouslyFocusedElement is null does not throw', async () => {
|
|
488
|
+
vi.useFakeTimers();
|
|
489
|
+
// Render open, then close without having a previously focused element
|
|
490
|
+
const { rerender } = render(Drawer, { props: { open: true } });
|
|
491
|
+
vi.runAllTimers();
|
|
492
|
+
|
|
493
|
+
// Close drawer - previouslyFocusedElement should be body or null, no error expected
|
|
494
|
+
await rerender({ open: false });
|
|
495
|
+
vi.runAllTimers();
|
|
496
|
+
vi.useRealTimers();
|
|
497
|
+
// If we get here without throwing, the test passes
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
describe('Drawer Keyboard Interaction - handleKeydown Branches', () => {
|
|
502
|
+
test('keydown handler does nothing when drawer is not visible', async () => {
|
|
503
|
+
const onclose = vi.fn();
|
|
504
|
+
render(Drawer, {
|
|
505
|
+
props: { open: false, closeOnEscape: true, onclose }
|
|
506
|
+
});
|
|
507
|
+
await userEvent.keyboard('{Escape}');
|
|
508
|
+
// handleKeydown returns early because isVisible is false
|
|
509
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test('non-escape key does not close drawer', async () => {
|
|
513
|
+
const onclose = vi.fn();
|
|
514
|
+
render(Drawer, {
|
|
515
|
+
props: { open: true, closeOnEscape: true, onclose }
|
|
516
|
+
});
|
|
517
|
+
await userEvent.keyboard('{Enter}');
|
|
518
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test('Tab key does not close drawer', async () => {
|
|
522
|
+
const onclose = vi.fn();
|
|
523
|
+
render(Drawer, {
|
|
524
|
+
props: { open: true, closeOnEscape: true, onclose }
|
|
525
|
+
});
|
|
526
|
+
await userEvent.keyboard('{Tab}');
|
|
527
|
+
expect(onclose).not.toHaveBeenCalled();
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
describe('Drawer Focus Trap (Tab key)', () => {
|
|
532
|
+
test('forward Tab from last focusable element wraps to first', async () => {
|
|
533
|
+
vi.useFakeTimers();
|
|
534
|
+
const { container } = render(DrawerTestWrapper, {
|
|
535
|
+
props: { open: true, showActions: true, actionsText: 'Save' }
|
|
536
|
+
});
|
|
537
|
+
vi.runAllTimers();
|
|
538
|
+
|
|
539
|
+
// Get focusable elements inside the drawer
|
|
540
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
541
|
+
const buttons = dialog.querySelectorAll('button');
|
|
542
|
+
expect(buttons.length).toBeGreaterThan(0);
|
|
543
|
+
|
|
544
|
+
const lastButton = buttons[buttons.length - 1];
|
|
545
|
+
lastButton.focus();
|
|
546
|
+
expect(document.activeElement).toBe(lastButton);
|
|
547
|
+
|
|
548
|
+
// Simulate Tab (forward) when focus is on the last element
|
|
549
|
+
const tabEvent = new KeyboardEvent('keydown', {
|
|
550
|
+
key: 'Tab',
|
|
551
|
+
shiftKey: false,
|
|
552
|
+
bubbles: true,
|
|
553
|
+
cancelable: true
|
|
554
|
+
});
|
|
555
|
+
window.dispatchEvent(tabEvent);
|
|
556
|
+
|
|
557
|
+
vi.useRealTimers();
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test('Shift+Tab from first focusable element wraps to last', async () => {
|
|
561
|
+
vi.useFakeTimers();
|
|
562
|
+
const { container } = render(DrawerTestWrapper, {
|
|
563
|
+
props: { open: true, showActions: true, actionsText: 'Save' }
|
|
564
|
+
});
|
|
565
|
+
vi.runAllTimers();
|
|
566
|
+
|
|
567
|
+
// Get focusable elements inside the drawer
|
|
568
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
569
|
+
const buttons = dialog.querySelectorAll('button');
|
|
570
|
+
expect(buttons.length).toBeGreaterThan(0);
|
|
571
|
+
|
|
572
|
+
const firstButton = buttons[0];
|
|
573
|
+
firstButton.focus();
|
|
574
|
+
expect(document.activeElement).toBe(firstButton);
|
|
575
|
+
|
|
576
|
+
// Simulate Shift+Tab when focus is on the first element
|
|
577
|
+
const shiftTabEvent = new KeyboardEvent('keydown', {
|
|
578
|
+
key: 'Tab',
|
|
579
|
+
shiftKey: true,
|
|
580
|
+
bubbles: true,
|
|
581
|
+
cancelable: true
|
|
582
|
+
});
|
|
583
|
+
window.dispatchEvent(shiftTabEvent);
|
|
584
|
+
|
|
585
|
+
vi.useRealTimers();
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
describe('Drawer aria-labelledby Edge Cases', () => {
|
|
590
|
+
test('no aria-labelledby when title provided but id is empty', () => {
|
|
591
|
+
const { container } = render(Drawer, {
|
|
592
|
+
props: { open: true, title: 'Test Title', id: '' }
|
|
593
|
+
});
|
|
594
|
+
const dialog = container.querySelector('[role="dialog"]');
|
|
595
|
+
// aria-labelledby is `${id}-label` which is "-label" when id is empty,
|
|
596
|
+
// but the condition is `title ? \`${id}-label\` : undefined`
|
|
597
|
+
// With title truthy and id empty, it produces "-label"
|
|
598
|
+
expect(dialog).toHaveAttribute('aria-labelledby', '-label');
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
test('h5 id is undefined when id prop is empty', () => {
|
|
602
|
+
const { container } = render(Drawer, {
|
|
603
|
+
props: { open: true, title: 'Test Title', id: '' }
|
|
604
|
+
});
|
|
605
|
+
const h5 = container.querySelector('h5');
|
|
606
|
+
expect(h5).toBeInTheDocument();
|
|
607
|
+
// id={id ? `${id}-label` : undefined} -- with empty id, it's undefined
|
|
608
|
+
expect(h5).not.toHaveAttribute('id');
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
test('h5 has id when id prop is provided', () => {
|
|
612
|
+
const { container } = render(Drawer, {
|
|
613
|
+
props: { open: true, title: 'Test Title', id: 'my-drawer' }
|
|
614
|
+
});
|
|
615
|
+
const h5 = container.querySelector('h5');
|
|
616
|
+
expect(h5).toBeInTheDocument();
|
|
617
|
+
expect(h5).toHaveAttribute('id', 'my-drawer-label');
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
describe('Drawer Without onclose/onopen Callbacks', () => {
|
|
622
|
+
test('backdrop click does not throw when onclose is not provided', async () => {
|
|
623
|
+
const { container } = render(Drawer, {
|
|
624
|
+
props: { open: true, closeOnBackdropClick: true }
|
|
625
|
+
});
|
|
626
|
+
const backdrop = container.querySelector('[role="presentation"]');
|
|
627
|
+
expect(backdrop).toBeInTheDocument();
|
|
628
|
+
// Should not throw even though onclose is not provided (tests onclose?.() optional chaining)
|
|
629
|
+
await userEvent.click(backdrop);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test('escape key does not throw when onclose is not provided', async () => {
|
|
633
|
+
render(Drawer, {
|
|
634
|
+
props: { open: true, closeOnEscape: true }
|
|
635
|
+
});
|
|
636
|
+
// Should not throw even though onclose is not provided (tests onclose?.() optional chaining)
|
|
637
|
+
await userEvent.keyboard('{Escape}');
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test('edge click does not throw when onopen is not provided', async () => {
|
|
641
|
+
const { container } = render(Drawer, {
|
|
642
|
+
props: { edge: true, placement: 'bottom', open: false }
|
|
643
|
+
});
|
|
644
|
+
const edgeTrigger = container.querySelector('.cursor-pointer');
|
|
645
|
+
expect(edgeTrigger).toBeInTheDocument();
|
|
646
|
+
// Should not throw even though onopen is not provided (tests onopen?.() optional chaining)
|
|
647
|
+
await userEvent.click(edgeTrigger);
|
|
648
|
+
});
|
|
212
649
|
});
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
<script module>
|
|
2
|
-
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
-
import Drawer from './Drawer.svelte';
|
|
4
|
-
import Button from '../Button/Button.svelte';
|
|
5
|
-
|
|
6
|
-
const { Story } = defineMeta({
|
|
7
|
-
title: 'Primitives/Drawer',
|
|
8
|
-
component: Drawer,
|
|
9
|
-
tags: ['autodocs'],
|
|
10
|
-
argTypes: {
|
|
11
|
-
position: {
|
|
12
|
-
control: 'select',
|
|
13
|
-
options: ['left', 'right'],
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
parameters: {
|
|
17
|
-
docs: {
|
|
18
|
-
description: {
|
|
19
|
-
component: 'Sliding panel overlay that appears from the side of the screen.',
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
let openLeft = $state(false);
|
|
26
|
-
let openRight = $state(false);
|
|
27
|
-
</script>
|
|
28
|
-
|
|
29
|
-
<Story name="Right (Default)">
|
|
30
|
-
{#snippet template()}
|
|
31
|
-
<div>
|
|
32
|
-
<Button onclick={() => openRight = true}>Open Right Drawer</Button>
|
|
33
|
-
<Drawer bind:open={openRight} position="right">
|
|
34
|
-
<div class="p-6">
|
|
35
|
-
<h2 class="text-xl font-semibold mb-4">Drawer Title</h2>
|
|
36
|
-
<p class="text-gray-600 mb-4">
|
|
37
|
-
This drawer slides in from the right side. Click outside or use the close button to dismiss.
|
|
38
|
-
</p>
|
|
39
|
-
<div class="space-y-4">
|
|
40
|
-
<p class="text-sm text-gray-500">Some content here...</p>
|
|
41
|
-
<Button onclick={() => openRight = false}>Close</Button>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
</Drawer>
|
|
45
|
-
</div>
|
|
46
|
-
{/snippet}
|
|
47
|
-
</Story>
|
|
48
|
-
|
|
49
|
-
<Story name="Left">
|
|
50
|
-
{#snippet template()}
|
|
51
|
-
<div>
|
|
52
|
-
<Button onclick={() => openLeft = true}>Open Left Drawer</Button>
|
|
53
|
-
<Drawer bind:open={openLeft} position="left">
|
|
54
|
-
<div class="p-6">
|
|
55
|
-
<h2 class="text-xl font-semibold mb-4">Navigation</h2>
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Drawer from './Drawer.svelte';
|
|
4
|
+
import Button from '../Button/Button.svelte';
|
|
5
|
+
|
|
6
|
+
const { Story } = defineMeta({
|
|
7
|
+
title: 'Primitives/Drawer',
|
|
8
|
+
component: Drawer,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
argTypes: {
|
|
11
|
+
position: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['left', 'right'],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
parameters: {
|
|
17
|
+
docs: {
|
|
18
|
+
description: {
|
|
19
|
+
component: 'Sliding panel overlay that appears from the side of the screen.',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let openLeft = $state(false);
|
|
26
|
+
let openRight = $state(false);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<Story name="Right (Default)">
|
|
30
|
+
{#snippet template()}
|
|
31
|
+
<div>
|
|
32
|
+
<Button onclick={() => openRight = true}>Open Right Drawer</Button>
|
|
33
|
+
<Drawer bind:open={openRight} position="right">
|
|
34
|
+
<div class="p-6">
|
|
35
|
+
<h2 class="text-xl font-semibold mb-4">Drawer Title</h2>
|
|
36
|
+
<p class="text-gray-600 mb-4">
|
|
37
|
+
This drawer slides in from the right side. Click outside or use the close button to dismiss.
|
|
38
|
+
</p>
|
|
39
|
+
<div class="space-y-4">
|
|
40
|
+
<p class="text-sm text-gray-500">Some content here...</p>
|
|
41
|
+
<Button onclick={() => openRight = false}>Close</Button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</Drawer>
|
|
45
|
+
</div>
|
|
46
|
+
{/snippet}
|
|
47
|
+
</Story>
|
|
48
|
+
|
|
49
|
+
<Story name="Left">
|
|
50
|
+
{#snippet template()}
|
|
51
|
+
<div>
|
|
52
|
+
<Button onclick={() => openLeft = true}>Open Left Drawer</Button>
|
|
53
|
+
<Drawer bind:open={openLeft} position="left">
|
|
54
|
+
<div class="p-6">
|
|
55
|
+
<h2 class="text-xl font-semibold mb-4">Navigation</h2>
|
|
56
56
|
<nav class="space-y-2">
|
|
57
57
|
<a href="/dashboard" class="block px-3 py-2 rounded hover:bg-gray-100">Dashboard</a>
|
|
58
58
|
<a href="/shows" class="block px-3 py-2 rounded hover:bg-gray-100">Shows</a>
|
|
59
59
|
<a href="/performers" class="block px-3 py-2 rounded hover:bg-gray-100">Performers</a>
|
|
60
60
|
<a href="/settings" class="block px-3 py-2 rounded hover:bg-gray-100">Settings</a>
|
|
61
61
|
</nav>
|
|
62
|
-
<div class="mt-6">
|
|
63
|
-
<Button variant="ghost" onclick={() => openLeft = false}>Close</Button>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
</Drawer>
|
|
67
|
-
</div>
|
|
68
|
-
{/snippet}
|
|
69
|
-
</Story>
|
|
70
|
-
|
|
71
|
-
<Story name="With Form">
|
|
72
|
-
{#snippet template()}
|
|
73
|
-
<div>
|
|
74
|
-
<Button onclick={() => openRight = true}>Edit Profile</Button>
|
|
75
|
-
<Drawer bind:open={openRight} position="right">
|
|
76
|
-
<div class="p-6">
|
|
77
|
-
<h2 class="text-xl font-semibold mb-6">Edit Profile</h2>
|
|
62
|
+
<div class="mt-6">
|
|
63
|
+
<Button variant="ghost" onclick={() => openLeft = false}>Close</Button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</Drawer>
|
|
67
|
+
</div>
|
|
68
|
+
{/snippet}
|
|
69
|
+
</Story>
|
|
70
|
+
|
|
71
|
+
<Story name="With Form">
|
|
72
|
+
{#snippet template()}
|
|
73
|
+
<div>
|
|
74
|
+
<Button onclick={() => openRight = true}>Edit Profile</Button>
|
|
75
|
+
<Drawer bind:open={openRight} position="right">
|
|
76
|
+
<div class="p-6">
|
|
77
|
+
<h2 class="text-xl font-semibold mb-6">Edit Profile</h2>
|
|
78
78
|
<form class="space-y-4">
|
|
79
79
|
<div>
|
|
80
80
|
<label for="drawer-name" class="block text-sm font-medium mb-1">Name</label>
|
|
@@ -89,12 +89,12 @@
|
|
|
89
89
|
<textarea id="drawer-bio" class="w-full border rounded px-3 py-2" rows="3" placeholder="Tell us about yourself"></textarea>
|
|
90
90
|
</div>
|
|
91
91
|
</form>
|
|
92
|
-
<div class="flex gap-2 mt-6">
|
|
93
|
-
<Button variant="ghost" onclick={() => openRight = false}>Cancel</Button>
|
|
94
|
-
<Button onclick={() => openRight = false}>Save Changes</Button>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
</Drawer>
|
|
98
|
-
</div>
|
|
99
|
-
{/snippet}
|
|
100
|
-
</Story>
|
|
92
|
+
<div class="flex gap-2 mt-6">
|
|
93
|
+
<Button variant="ghost" onclick={() => openRight = false}>Cancel</Button>
|
|
94
|
+
<Button onclick={() => openRight = false}>Save Changes</Button>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</Drawer>
|
|
98
|
+
</div>
|
|
99
|
+
{/snippet}
|
|
100
|
+
</Story>
|