@sovereignfs/ui 0.83.1 → 0.89.1
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/LICENSE +373 -661
- package/NOTICE +8 -0
- package/README.md +4 -6
- package/dist/AppsLauncher.module.css +6 -0
- package/dist/Button.module.css +5 -0
- package/dist/Card.module.css +6 -0
- package/dist/CardTile.module.css +6 -0
- package/dist/CheckableListRow.module.css +8 -0
- package/dist/Checkbox.module.css +8 -0
- package/dist/CodeTextarea.module.css +6 -0
- package/dist/ColorPicker.module.css +6 -0
- package/dist/Combobox.module.css +6 -0
- package/dist/Command.module.css +6 -0
- package/dist/ConfirmDialog.module.css +6 -0
- package/dist/DatePicker.module.css +6 -0
- package/dist/Dialog.module.css +1 -1
- package/dist/DragHandleRow.module.css +6 -0
- package/dist/FileDropzone.module.css +25 -1
- package/dist/Header.module.css +6 -0
- package/dist/IconPicker.module.css +14 -4
- package/dist/Input.module.css +6 -0
- package/dist/LegalLinks.module.css +9 -2
- package/dist/Markdown.module.css +5 -0
- package/dist/Message.module.css +9 -0
- package/dist/MobileAppsDrawer.module.css +9 -5
- package/dist/MobileFooter.module.css +6 -0
- package/dist/NavList.module.css +11 -2
- package/dist/NavTabs.module.css +7 -1
- package/dist/NotificationsPanel.module.css +10 -0
- package/dist/QrCode.module.css +17 -0
- package/dist/QuantityStepper.module.css +4 -2
- package/dist/RadioGroup.module.css +6 -0
- package/dist/SegmentedControl.module.css +6 -0
- package/dist/Select.module.css +6 -0
- package/dist/Sheet.module.css +16 -1
- package/dist/SplitPane.module.css +1 -1
- package/dist/StepStrip.module.css +5 -3
- package/dist/SuggestionInput.module.css +12 -1
- package/dist/SwipableMobileCarouselDots.module.css +6 -0
- package/dist/SystemBanner.module.css +6 -0
- package/dist/Tabs.module.css +6 -0
- package/dist/TagInput.module.css +6 -0
- package/dist/Textarea.module.css +6 -0
- package/dist/Toast.module.css +5 -0
- package/dist/Toggle.module.css +7 -0
- package/dist/Tooltip.module.css +6 -0
- package/dist/UserMenu.module.css +5 -0
- package/dist/fonts/OFL.txt +93 -0
- package/dist/fonts/hanken-grotesk-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-vietnamese-wght-normal.woff2 +0 -0
- package/dist/index.d.ts +121 -43
- package/dist/index.js +1410 -1152
- package/dist/tokens/fonts.css +53 -0
- package/dist/tokens/primitives.css +12 -12
- package/dist/tokens.css +2 -1
- package/package.json +24 -13
- package/src/__tests__/motion.test.tsx +0 -105
- package/src/__tests__/package-json.test.ts +0 -8
- package/src/components/Accordion/Accordion.module.css +0 -3
- package/src/components/Accordion/Accordion.stories.tsx +0 -110
- package/src/components/Accordion/Accordion.tsx +0 -53
- package/src/components/Accordion/__tests__/Accordion.test.tsx +0 -61
- package/src/components/Alert/Alert.module.css +0 -62
- package/src/components/Alert/Alert.stories.tsx +0 -96
- package/src/components/Alert/Alert.tsx +0 -58
- package/src/components/Alert/__tests__/Alert.test.tsx +0 -75
- package/src/components/AppsLauncher/AppsLauncher.module.css +0 -96
- package/src/components/AppsLauncher/AppsLauncher.stories.tsx +0 -58
- package/src/components/AppsLauncher/AppsLauncher.tsx +0 -117
- package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +0 -52
- package/src/components/AspectRatio/AspectRatio.module.css +0 -15
- package/src/components/AspectRatio/AspectRatio.stories.tsx +0 -78
- package/src/components/AspectRatio/AspectRatio.tsx +0 -21
- package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +0 -27
- package/src/components/Avatar/Avatar.module.css +0 -38
- package/src/components/Avatar/Avatar.tsx +0 -42
- package/src/components/Badge/Badge.module.css +0 -177
- package/src/components/Badge/Badge.stories.tsx +0 -238
- package/src/components/Badge/Badge.tsx +0 -84
- package/src/components/Badge/__tests__/Badge.test.tsx +0 -90
- package/src/components/BalanceChip/BalanceChip.module.css +0 -32
- package/src/components/BalanceChip/BalanceChip.stories.tsx +0 -45
- package/src/components/BalanceChip/BalanceChip.tsx +0 -33
- package/src/components/Breadcrumb/Breadcrumb.module.css +0 -49
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -47
- package/src/components/Breadcrumb/Breadcrumb.tsx +0 -57
- package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +0 -52
- package/src/components/Button/Button.module.css +0 -169
- package/src/components/Button/Button.stories.tsx +0 -83
- package/src/components/Button/Button.tsx +0 -52
- package/src/components/Button/__tests__/Button.test.tsx +0 -66
- package/src/components/ButtonGroup/ButtonGroup.module.css +0 -29
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -57
- package/src/components/ButtonGroup/ButtonGroup.tsx +0 -27
- package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +0 -29
- package/src/components/Calendar/Calendar.module.css +0 -126
- package/src/components/Calendar/Calendar.tsx +0 -213
- package/src/components/Calendar/__tests__/Calendar.test.tsx +0 -98
- package/src/components/Calendar/dateUtils.ts +0 -97
- package/src/components/Card/Card.module.css +0 -42
- package/src/components/Card/Card.tsx +0 -34
- package/src/components/CardTile/CardTile.module.css +0 -181
- package/src/components/CardTile/CardTile.stories.tsx +0 -86
- package/src/components/CardTile/CardTile.tsx +0 -128
- package/src/components/CardTile/__tests__/CardTile.test.tsx +0 -56
- package/src/components/CheckableListRow/CheckableListRow.module.css +0 -95
- package/src/components/CheckableListRow/CheckableListRow.stories.tsx +0 -99
- package/src/components/CheckableListRow/CheckableListRow.tsx +0 -89
- package/src/components/Checkbox/Checkbox.module.css +0 -111
- package/src/components/Checkbox/Checkbox.tsx +0 -78
- package/src/components/CodeTextarea/CodeTextarea.module.css +0 -53
- package/src/components/CodeTextarea/CodeTextarea.stories.tsx +0 -77
- package/src/components/CodeTextarea/CodeTextarea.tsx +0 -36
- package/src/components/Collapsible/Collapsible.module.css +0 -70
- package/src/components/Collapsible/Collapsible.stories.tsx +0 -62
- package/src/components/Collapsible/Collapsible.tsx +0 -66
- package/src/components/Collapsible/__tests__/Collapsible.test.tsx +0 -71
- package/src/components/ColorPicker/ColorPicker.module.css +0 -132
- package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -80
- package/src/components/ColorPicker/ColorPicker.tsx +0 -157
- package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +0 -117
- package/src/components/Combobox/Combobox.module.css +0 -122
- package/src/components/Combobox/Combobox.stories.tsx +0 -79
- package/src/components/Combobox/Combobox.tsx +0 -186
- package/src/components/Combobox/__tests__/Combobox.test.tsx +0 -158
- package/src/components/Command/Command.module.css +0 -80
- package/src/components/Command/Command.stories.tsx +0 -104
- package/src/components/Command/Command.tsx +0 -168
- package/src/components/Command/__tests__/Command.test.tsx +0 -162
- package/src/components/ConfirmDialog/ConfirmDialog.module.css +0 -113
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +0 -150
- package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +0 -214
- package/src/components/ConsentPrompt/ConsentPrompt.module.css +0 -21
- package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +0 -31
- package/src/components/ConsentPrompt/ConsentPrompt.tsx +0 -66
- package/src/components/ContextMenu/ContextMenu.stories.tsx +0 -81
- package/src/components/ContextMenu/ContextMenu.tsx +0 -100
- package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +0 -87
- package/src/components/CurrencyInput/CurrencyInput.stories.tsx +0 -50
- package/src/components/CurrencyInput/CurrencyInput.tsx +0 -60
- package/src/components/DataTable/DataTable.module.css +0 -28
- package/src/components/DataTable/DataTable.stories.tsx +0 -74
- package/src/components/DataTable/DataTable.tsx +0 -154
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -123
- package/src/components/DatePicker/DatePicker.module.css +0 -61
- package/src/components/DatePicker/DatePicker.tsx +0 -103
- package/src/components/DatePicker/__tests__/DatePicker.test.tsx +0 -89
- package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +0 -58
- package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +0 -45
- package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +0 -100
- package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +0 -119
- package/src/components/Dialog/Dialog.module.css +0 -335
- package/src/components/Dialog/Dialog.stories.tsx +0 -324
- package/src/components/Dialog/Dialog.tsx +0 -254
- package/src/components/Dialog/__tests__/Dialog.test.tsx +0 -318
- package/src/components/DragHandleRow/DragHandleRow.module.css +0 -57
- package/src/components/DragHandleRow/DragHandleRow.tsx +0 -42
- package/src/components/Drawer/Drawer.module.css +0 -121
- package/src/components/Drawer/Drawer.stories.tsx +0 -132
- package/src/components/Drawer/Drawer.tsx +0 -175
- package/src/components/Drawer/__tests__/Drawer.test.tsx +0 -226
- package/src/components/EmptyState/EmptyState.module.css +0 -27
- package/src/components/EmptyState/EmptyState.tsx +0 -27
- package/src/components/FileDropzone/FileDropzone.module.css +0 -63
- package/src/components/FileDropzone/FileDropzone.tsx +0 -109
- package/src/components/FileDropzone/__tests__/FileDropzone.test.tsx +0 -67
- package/src/components/FormField/FormField.module.css +0 -33
- package/src/components/FormField/FormField.tsx +0 -78
- package/src/components/FormField/__tests__/FormField.test.tsx +0 -83
- package/src/components/GripIcon/GripIcon.tsx +0 -27
- package/src/components/Header/Header.module.css +0 -62
- package/src/components/Header/Header.stories.tsx +0 -452
- package/src/components/Header/Header.tsx +0 -102
- package/src/components/Header/__tests__/Header.test.tsx +0 -104
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +0 -21
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +0 -111
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +0 -54
- package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +0 -58
- package/src/components/HoverCard/HoverCard.module.css +0 -3
- package/src/components/HoverCard/HoverCard.stories.tsx +0 -66
- package/src/components/HoverCard/HoverCard.tsx +0 -111
- package/src/components/HoverCard/__tests__/HoverCard.test.tsx +0 -99
- package/src/components/Icon/Icon.module.css +0 -27
- package/src/components/Icon/Icon.stories.tsx +0 -95
- package/src/components/Icon/Icon.tsx +0 -43
- package/src/components/Icon/__tests__/Icon.test.tsx +0 -40
- package/src/components/Icon/icons/activity.tsx +0 -20
- package/src/components/Icon/icons/alert-triangle.tsx +0 -22
- package/src/components/Icon/icons/apple.tsx +0 -21
- package/src/components/Icon/icons/arrow-left-right.tsx +0 -23
- package/src/components/Icon/icons/banana.tsx +0 -21
- package/src/components/Icon/icons/beef.tsx +0 -22
- package/src/components/Icon/icons/beer.tsx +0 -24
- package/src/components/Icon/icons/bell.tsx +0 -21
- package/src/components/Icon/icons/bold.tsx +0 -20
- package/src/components/Icon/icons/calendar.tsx +0 -23
- package/src/components/Icon/icons/candy.tsx +0 -24
- package/src/components/Icon/icons/carrot.tsx +0 -22
- package/src/components/Icon/icons/check.tsx +0 -20
- package/src/components/Icon/icons/chevron-down.tsx +0 -20
- package/src/components/Icon/icons/chevron-left.tsx +0 -20
- package/src/components/Icon/icons/chevron-right.tsx +0 -20
- package/src/components/Icon/icons/chevron-up.tsx +0 -20
- package/src/components/Icon/icons/circle-check.tsx +0 -21
- package/src/components/Icon/icons/circle-chevron-left.tsx +0 -21
- package/src/components/Icon/icons/circle-x.tsx +0 -22
- package/src/components/Icon/icons/code.tsx +0 -21
- package/src/components/Icon/icons/coffee.tsx +0 -23
- package/src/components/Icon/icons/cookie.tsx +0 -25
- package/src/components/Icon/icons/copy.tsx +0 -21
- package/src/components/Icon/icons/credit-card.tsx +0 -21
- package/src/components/Icon/icons/croissant.tsx +0 -24
- package/src/components/Icon/icons/cup-soda.tsx +0 -23
- package/src/components/Icon/icons/database.tsx +0 -22
- package/src/components/Icon/icons/download.tsx +0 -22
- package/src/components/Icon/icons/drumstick.tsx +0 -21
- package/src/components/Icon/icons/egg.tsx +0 -20
- package/src/components/Icon/icons/ellipsis-vertical.tsx +0 -22
- package/src/components/Icon/icons/external-link.tsx +0 -22
- package/src/components/Icon/icons/eye-off.tsx +0 -23
- package/src/components/Icon/icons/eye.tsx +0 -21
- package/src/components/Icon/icons/file-text.tsx +0 -24
- package/src/components/Icon/icons/file.tsx +0 -21
- package/src/components/Icon/icons/fish.tsx +0 -25
- package/src/components/Icon/icons/folder-closed.tsx +0 -21
- package/src/components/Icon/icons/folder-open.tsx +0 -20
- package/src/components/Icon/icons/folder.tsx +0 -20
- package/src/components/Icon/icons/folders.tsx +0 -21
- package/src/components/Icon/icons/grid-2x2.tsx +0 -22
- package/src/components/Icon/icons/hat-glasses.tsx +0 -24
- package/src/components/Icon/icons/history.tsx +0 -22
- package/src/components/Icon/icons/house.tsx +0 -21
- package/src/components/Icon/icons/inbox.tsx +0 -21
- package/src/components/Icon/icons/index.ts +0 -394
- package/src/components/Icon/icons/info.tsx +0 -22
- package/src/components/Icon/icons/italic.tsx +0 -22
- package/src/components/Icon/icons/layers.tsx +0 -22
- package/src/components/Icon/icons/layout-dashboard.tsx +0 -23
- package/src/components/Icon/icons/layout-grid.tsx +0 -23
- package/src/components/Icon/icons/link.tsx +0 -21
- package/src/components/Icon/icons/list-ordered.tsx +0 -25
- package/src/components/Icon/icons/list.tsx +0 -25
- package/src/components/Icon/icons/lock.tsx +0 -21
- package/src/components/Icon/icons/log-out.tsx +0 -22
- package/src/components/Icon/icons/luggage.tsx +0 -24
- package/src/components/Icon/icons/mail.tsx +0 -21
- package/src/components/Icon/icons/map-pin.tsx +0 -21
- package/src/components/Icon/icons/menu.tsx +0 -22
- package/src/components/Icon/icons/milk.tsx +0 -22
- package/src/components/Icon/icons/minus.tsx +0 -20
- package/src/components/Icon/icons/package.tsx +0 -23
- package/src/components/Icon/icons/paint-bucket.tsx +0 -23
- package/src/components/Icon/icons/panel-left.tsx +0 -21
- package/src/components/Icon/icons/pencil.tsx +0 -21
- package/src/components/Icon/icons/pin.tsx +0 -21
- package/src/components/Icon/icons/pizza.tsx +0 -24
- package/src/components/Icon/icons/plus.tsx +0 -21
- package/src/components/Icon/icons/rectangle-ellipsis.tsx +0 -23
- package/src/components/Icon/icons/refresh-cw.tsx +0 -23
- package/src/components/Icon/icons/rotate-ccw.tsx +0 -21
- package/src/components/Icon/icons/rotate-cw.tsx +0 -21
- package/src/components/Icon/icons/route.tsx +0 -22
- package/src/components/Icon/icons/salad.tsx +0 -24
- package/src/components/Icon/icons/search.tsx +0 -21
- package/src/components/Icon/icons/send.tsx +0 -21
- package/src/components/Icon/icons/settings.tsx +0 -21
- package/src/components/Icon/icons/share-2.tsx +0 -24
- package/src/components/Icon/icons/sheet.tsx +0 -24
- package/src/components/Icon/icons/shield.tsx +0 -20
- package/src/components/Icon/icons/shopping-basket.tsx +0 -26
- package/src/components/Icon/icons/sliders-horizontal.tsx +0 -28
- package/src/components/Icon/icons/smartphone.tsx +0 -21
- package/src/components/Icon/icons/snowflake.tsx +0 -31
- package/src/components/Icon/icons/spray-can.tsx +0 -29
- package/src/components/Icon/icons/square-kanban.tsx +0 -23
- package/src/components/Icon/icons/table.tsx +0 -23
- package/src/components/Icon/icons/trash-2.tsx +0 -24
- package/src/components/Icon/icons/upload.tsx +0 -22
- package/src/components/Icon/icons/user-round-plus.tsx +0 -23
- package/src/components/Icon/icons/user.tsx +0 -21
- package/src/components/Icon/icons/users.tsx +0 -23
- package/src/components/Icon/icons/wine.tsx +0 -23
- package/src/components/Icon/icons/x.tsx +0 -21
- package/src/components/IconPicker/IconPicker.module.css +0 -63
- package/src/components/IconPicker/IconPicker.stories.tsx +0 -84
- package/src/components/IconPicker/IconPicker.tsx +0 -90
- package/src/components/Input/Input.module.css +0 -52
- package/src/components/Input/Input.stories.tsx +0 -86
- package/src/components/Input/Input.tsx +0 -20
- package/src/components/Input/__tests__/Input.test.tsx +0 -22
- package/src/components/Item/Item.module.css +0 -70
- package/src/components/Item/Item.stories.tsx +0 -62
- package/src/components/Item/Item.tsx +0 -54
- package/src/components/Item/__tests__/Item.test.tsx +0 -39
- package/src/components/Kbd/Kbd.module.css +0 -14
- package/src/components/Kbd/Kbd.stories.tsx +0 -32
- package/src/components/Kbd/Kbd.tsx +0 -12
- package/src/components/Kbd/__tests__/Kbd.test.tsx +0 -14
- package/src/components/Label/Label.module.css +0 -11
- package/src/components/Label/Label.stories.tsx +0 -40
- package/src/components/Label/Label.tsx +0 -24
- package/src/components/Label/__tests__/Label.test.tsx +0 -32
- package/src/components/LegalLinks/LegalLinks.module.css +0 -24
- package/src/components/LegalLinks/LegalLinks.stories.tsx +0 -22
- package/src/components/LegalLinks/LegalLinks.tsx +0 -40
- package/src/components/Markdown/Markdown.module.css +0 -73
- package/src/components/Markdown/Markdown.stories.tsx +0 -40
- package/src/components/Markdown/Markdown.tsx +0 -305
- package/src/components/Markdown/__tests__/Markdown.test.tsx +0 -144
- package/src/components/Marker/Marker.module.css +0 -33
- package/src/components/Marker/Marker.stories.tsx +0 -39
- package/src/components/Marker/Marker.tsx +0 -34
- package/src/components/Marker/__tests__/Marker.test.tsx +0 -23
- package/src/components/MemberMultiSelect/MemberMultiSelect.module.css +0 -27
- package/src/components/MemberMultiSelect/MemberMultiSelect.stories.tsx +0 -74
- package/src/components/MemberMultiSelect/MemberMultiSelect.tsx +0 -67
- package/src/components/Menu/Menu.module.css +0 -90
- package/src/components/Menu/Menu.tsx +0 -209
- package/src/components/Menu/__tests__/Menu.test.tsx +0 -227
- package/src/components/Menubar/Menubar.stories.tsx +0 -52
- package/src/components/Menubar/Menubar.tsx +0 -42
- package/src/components/Menubar/__tests__/Menubar.test.tsx +0 -45
- package/src/components/Message/Message.module.css +0 -99
- package/src/components/Message/Message.stories.tsx +0 -79
- package/src/components/Message/Message.tsx +0 -41
- package/src/components/Message/__tests__/Message.test.tsx +0 -46
- package/src/components/MessageScroller/MessageScroller.module.css +0 -65
- package/src/components/MessageScroller/MessageScroller.stories.tsx +0 -84
- package/src/components/MessageScroller/MessageScroller.tsx +0 -84
- package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +0 -105
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +0 -82
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +0 -78
- package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +0 -80
- package/src/components/MobileFooter/MobileFooter.module.css +0 -73
- package/src/components/MobileFooter/MobileFooter.stories.tsx +0 -47
- package/src/components/MobileFooter/MobileFooter.tsx +0 -122
- package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +0 -129
- package/src/components/MobileHeader/MobileHeader.module.css +0 -76
- package/src/components/MobileHeader/MobileHeader.stories.tsx +0 -57
- package/src/components/MobileHeader/MobileHeader.tsx +0 -90
- package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +0 -113
- package/src/components/NavList/NavList.module.css +0 -130
- package/src/components/NavList/NavList.tsx +0 -136
- package/src/components/NavList/__tests__/NavList.test.tsx +0 -109
- package/src/components/NavTabs/NavTabs.module.css +0 -50
- package/src/components/NavTabs/NavTabs.tsx +0 -61
- package/src/components/NavigationMenu/NavigationMenu.module.css +0 -53
- package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -58
- package/src/components/NavigationMenu/NavigationMenu.tsx +0 -125
- package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +0 -93
- package/src/components/NotificationsPanel/NotificationsPanel.module.css +0 -258
- package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +0 -61
- package/src/components/NotificationsPanel/NotificationsPanel.tsx +0 -187
- package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +0 -78
- package/src/components/OfflineGate/OfflineGate.tsx +0 -44
- package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +0 -66
- package/src/components/OverlayHeader/OverlayHeader.module.css +0 -98
- package/src/components/OverlayHeader/OverlayHeader.tsx +0 -77
- package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +0 -69
- package/src/components/PageContainer/PageContainer.module.css +0 -82
- package/src/components/PageContainer/PageContainer.tsx +0 -64
- package/src/components/PageContainer/__tests__/PageContainer.test.tsx +0 -70
- package/src/components/PageHeader/PageHeader.module.css +0 -86
- package/src/components/PageHeader/PageHeader.tsx +0 -176
- package/src/components/PageHeader/__tests__/PageHeader.test.tsx +0 -103
- package/src/components/PageLayout/PageLayout.module.css +0 -51
- package/src/components/PageLayout/PageLayout.stories.tsx +0 -73
- package/src/components/PageLayout/PageLayout.tsx +0 -51
- package/src/components/PageLayout/__tests__/PageLayout.test.tsx +0 -34
- package/src/components/Pagination/Pagination.module.css +0 -98
- package/src/components/Pagination/Pagination.stories.tsx +0 -49
- package/src/components/Pagination/Pagination.tsx +0 -87
- package/src/components/Pagination/__tests__/Pagination.test.tsx +0 -56
- package/src/components/Popover/Popover.module.css +0 -74
- package/src/components/Popover/Popover.stories.tsx +0 -357
- package/src/components/Popover/Popover.tsx +0 -290
- package/src/components/Popover/__tests__/Popover.test.tsx +0 -263
- package/src/components/Progress/Progress.module.css +0 -20
- package/src/components/Progress/Progress.stories.tsx +0 -40
- package/src/components/Progress/Progress.tsx +0 -35
- package/src/components/Progress/__tests__/Progress.test.tsx +0 -31
- package/src/components/QuantityStepper/QuantityStepper.module.css +0 -67
- package/src/components/QuantityStepper/QuantityStepper.stories.tsx +0 -79
- package/src/components/QuantityStepper/QuantityStepper.tsx +0 -107
- package/src/components/RadioGroup/RadioGroup.module.css +0 -88
- package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -69
- package/src/components/RadioGroup/RadioGroup.tsx +0 -99
- package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +0 -59
- package/src/components/Resizable/Resizable.module.css +0 -70
- package/src/components/Resizable/Resizable.stories.tsx +0 -82
- package/src/components/Resizable/Resizable.tsx +0 -313
- package/src/components/Resizable/__tests__/Resizable.test.tsx +0 -128
- package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +0 -24
- package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +0 -73
- package/src/components/RootLayout/RootLayout.module.css +0 -12
- package/src/components/RootLayout/RootLayout.stories.tsx +0 -125
- package/src/components/RootLayout/RootLayout.tsx +0 -185
- package/src/components/RootLayout/__tests__/RootLayout.test.tsx +0 -161
- package/src/components/ScrollArea/ScrollArea.module.css +0 -20
- package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -57
- package/src/components/ScrollArea/ScrollArea.tsx +0 -27
- package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +0 -39
- package/src/components/SegmentedControl/SegmentedControl.module.css +0 -55
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +0 -118
- package/src/components/SegmentedControl/SegmentedControl.tsx +0 -56
- package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +0 -63
- package/src/components/Select/Select.module.css +0 -82
- package/src/components/Select/Select.stories.tsx +0 -115
- package/src/components/Select/Select.tsx +0 -48
- package/src/components/Select/__tests__/Select.test.tsx +0 -59
- package/src/components/Sheet/Sheet.module.css +0 -58
- package/src/components/Sheet/Sheet.tsx +0 -109
- package/src/components/Sheet/__tests__/Sheet.test.tsx +0 -99
- package/src/components/Slider/Slider.module.css +0 -95
- package/src/components/Slider/Slider.stories.tsx +0 -64
- package/src/components/Slider/Slider.tsx +0 -77
- package/src/components/Slider/__tests__/Slider.test.tsx +0 -45
- package/src/components/Spinner/Spinner.module.css +0 -39
- package/src/components/Spinner/Spinner.tsx +0 -23
- package/src/components/SplitMethodSelector/SplitMethodSelector.stories.tsx +0 -33
- package/src/components/SplitMethodSelector/SplitMethodSelector.tsx +0 -43
- package/src/components/SplitPane/SplitPane.module.css +0 -85
- package/src/components/SplitPane/SplitPane.stories.tsx +0 -160
- package/src/components/SplitPane/SplitPane.tsx +0 -149
- package/src/components/SplitPane/__tests__/SplitPane.test.tsx +0 -51
- package/src/components/StatusBadge/StatusBadge.module.css +0 -59
- package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -74
- package/src/components/StatusBadge/StatusBadge.tsx +0 -65
- package/src/components/StepStrip/StepStrip.module.css +0 -53
- package/src/components/StepStrip/StepStrip.tsx +0 -74
- package/src/components/SuggestionInput/SuggestionInput.module.css +0 -103
- package/src/components/SuggestionInput/SuggestionInput.stories.tsx +0 -144
- package/src/components/SuggestionInput/SuggestionInput.tsx +0 -207
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +0 -64
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +0 -243
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +0 -35
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +0 -42
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +0 -18
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +0 -21
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +0 -29
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +0 -214
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +0 -61
- package/src/components/SwipableMobileCarousel/context.ts +0 -13
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +0 -64
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +0 -73
- package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +0 -63
- package/src/components/SwipeStack/SwipeStack.module.css +0 -101
- package/src/components/SwipeStack/SwipeStack.tsx +0 -199
- package/src/components/SwipeStack/SwipeStackCard.tsx +0 -22
- package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +0 -169
- package/src/components/SystemBanner/SystemBanner.module.css +0 -79
- package/src/components/SystemBanner/SystemBanner.stories.tsx +0 -86
- package/src/components/SystemBanner/SystemBanner.tsx +0 -50
- package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +0 -50
- package/src/components/Table/Table.module.css +0 -45
- package/src/components/Table/Table.stories.tsx +0 -125
- package/src/components/Table/Table.tsx +0 -51
- package/src/components/Table/__tests__/Table.test.tsx +0 -50
- package/src/components/Tabs/Tabs.module.css +0 -56
- package/src/components/Tabs/Tabs.stories.tsx +0 -100
- package/src/components/Tabs/Tabs.tsx +0 -46
- package/src/components/Tabs/__tests__/Tabs.test.tsx +0 -45
- package/src/components/TagInput/TagInput.module.css +0 -141
- package/src/components/TagInput/TagInput.stories.tsx +0 -109
- package/src/components/TagInput/TagInput.tsx +0 -174
- package/src/components/TagInput/__tests__/TagInput.test.tsx +0 -69
- package/src/components/Textarea/Textarea.module.css +0 -47
- package/src/components/Textarea/Textarea.tsx +0 -38
- package/src/components/Textarea/__tests__/Textarea.test.tsx +0 -51
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +0 -35
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +0 -152
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +0 -87
- package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +0 -78
- package/src/components/Toast/Toast.module.css +0 -191
- package/src/components/Toast/Toast.stories.tsx +0 -191
- package/src/components/Toast/Toast.tsx +0 -139
- package/src/components/Toggle/Toggle.module.css +0 -57
- package/src/components/Toggle/Toggle.stories.tsx +0 -95
- package/src/components/Toggle/Toggle.tsx +0 -39
- package/src/components/Toggle/__tests__/Toggle.test.tsx +0 -47
- package/src/components/Tooltip/Tooltip.module.css +0 -56
- package/src/components/Tooltip/Tooltip.tsx +0 -30
- package/src/components/Typography/Typography.module.css +0 -47
- package/src/components/Typography/Typography.stories.tsx +0 -62
- package/src/components/Typography/Typography.tsx +0 -30
- package/src/components/Typography/__tests__/Typography.test.tsx +0 -34
- package/src/components/UserMenu/UserMenu.module.css +0 -90
- package/src/components/UserMenu/UserMenu.stories.tsx +0 -49
- package/src/components/UserMenu/UserMenu.tsx +0 -132
- package/src/components/UserMenu/__tests__/UserMenu.test.tsx +0 -77
- package/src/css-modules.d.ts +0 -4
- package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +0 -126
- package/src/hooks/__tests__/useDoubleTap.test.tsx +0 -117
- package/src/hooks/__tests__/useIsMobile.test.tsx +0 -80
- package/src/hooks/__tests__/useIsOffline.test.tsx +0 -53
- package/src/hooks/__tests__/useLongPress.test.tsx +0 -158
- package/src/hooks/__tests__/useOfflineTileState.test.tsx +0 -69
- package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +0 -118
- package/src/hooks/__tests__/useReorderSensors.test.ts +0 -26
- package/src/hooks/__tests__/useResponsiveLayout.test.tsx +0 -87
- package/src/hooks/__tests__/useSnapCarousel.test.tsx +0 -175
- package/src/hooks/__tests__/useSwipeReveal.test.tsx +0 -110
- package/src/hooks/__tests__/useSwipeStack.test.tsx +0 -155
- package/src/hooks/index.ts +0 -33
- package/src/hooks/useCarouselRouteSync.ts +0 -92
- package/src/hooks/useCommitOnEnterOrBlur.ts +0 -39
- package/src/hooks/useDoubleTap.ts +0 -91
- package/src/hooks/useIsMobile.ts +0 -33
- package/src/hooks/useIsOffline.ts +0 -41
- package/src/hooks/useLongPress.ts +0 -185
- package/src/hooks/useOfflineTileState.ts +0 -45
- package/src/hooks/usePublishShellChromeHeight.ts +0 -96
- package/src/hooks/useReorderSensors.ts +0 -88
- package/src/hooks/useResponsiveLayout.ts +0 -36
- package/src/hooks/useSnapCarousel.ts +0 -284
- package/src/hooks/useSwipeReveal.ts +0 -107
- package/src/hooks/useSwipeStack.ts +0 -235
- package/src/index.ts +0 -311
- package/src/motion.ts +0 -78
- package/src/overlay-shell.ts +0 -159
- package/src/scroll-lock.ts +0 -22
- package/src/stories/Avatar.stories.tsx +0 -44
- package/src/stories/Card.stories.tsx +0 -35
- package/src/stories/Checkbox.stories.tsx +0 -45
- package/src/stories/DesignSystemOverview.stories.tsx +0 -3793
- package/src/stories/DeviceOnlyGate.stories.tsx +0 -35
- package/src/stories/DeviceStorageKeyGate.stories.tsx +0 -57
- package/src/stories/DragHandleRow.stories.tsx +0 -41
- package/src/stories/EmptyState.stories.tsx +0 -33
- package/src/stories/FileDropzone.stories.tsx +0 -69
- package/src/stories/FormField.stories.tsx +0 -47
- package/src/stories/GripIcon.stories.tsx +0 -29
- package/src/stories/InteractionHooks.stories.tsx +0 -925
- package/src/stories/LayoutSystem.stories.tsx +0 -639
- package/src/stories/MenuEntries.stories.tsx +0 -86
- package/src/stories/MobilePatterns.stories.tsx +0 -1536
- package/src/stories/NavList.stories.tsx +0 -147
- package/src/stories/NavTabs.stories.tsx +0 -53
- package/src/stories/OfflineGate.stories.tsx +0 -42
- package/src/stories/PageContainer.stories.tsx +0 -82
- package/src/stories/PageHeader.stories.tsx +0 -95
- package/src/stories/ResponsiveSurface.stories.tsx +0 -47
- package/src/stories/Spinner.stories.tsx +0 -25
- package/src/stories/StepStrip.stories.tsx +0 -76
- package/src/stories/SwipableMobileCarousel.stories.tsx +0 -362
- package/src/stories/SwipeStack.stories.tsx +0 -200
- package/src/stories/Textarea.stories.tsx +0 -63
- package/src/stories/TokenGallery.stories.tsx +0 -652
- package/src/stories/Tooltip.stories.tsx +0 -59
- package/src/tokens/primitives.css +0 -168
- package/src/tokens/semantic.css +0 -162
- package/src/tokens/theme-presets.css +0 -33
- package/src/tokens/theme-presets.ts +0 -72
- package/src/tokens.css +0 -5
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import styles from './SwipableMobileCarouselSlideParts.module.css';
|
|
3
|
-
|
|
4
|
-
export interface SwipableMobileCarouselSlideBodyProps {
|
|
5
|
-
children: ReactNode;
|
|
6
|
-
/** While true, renders `loadingFallback` INSTEAD OF children — scoped to
|
|
7
|
-
* just this region, not the whole slide. This is what fixes the
|
|
8
|
-
* "whole slide blanks out, title included, until its own fetch resolves"
|
|
9
|
-
* bug: a caller renders `<SwipableMobileCarouselSlideHeader>` from
|
|
10
|
-
* already-known metadata unconditionally, and gates only this component's
|
|
11
|
-
* `loading` on the slower fetch — the natural way to compose
|
|
12
|
-
* Header/Body/Footer as siblings already produces that behavior, instead
|
|
13
|
-
* of gating the entire slide behind one boolean. */
|
|
14
|
-
loading?: boolean;
|
|
15
|
-
loadingFallback?: ReactNode;
|
|
16
|
-
className?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const defaultLoadingFallback = <div className={styles.loading}>Loading…</div>;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* SwipableMobileCarouselSlideBody — the scrollable region of a slide.
|
|
23
|
-
*
|
|
24
|
-
* Deliberately does not set `touch-action: pan-y` on its scroll container
|
|
25
|
-
* (see SwipableMobileCarouselSlideParts.module.css's `.body` rule) — that
|
|
26
|
-
* would intersect-to-empty against the carousel's own horizontal
|
|
27
|
-
* touch-action handling (docs/architecture-rules.md's touch-action
|
|
28
|
-
* intersection rule), breaking both the vertical scroll here and the
|
|
29
|
-
* horizontal swipe between slides.
|
|
30
|
-
*/
|
|
31
|
-
export function SwipableMobileCarouselSlideBody({
|
|
32
|
-
children,
|
|
33
|
-
loading = false,
|
|
34
|
-
loadingFallback,
|
|
35
|
-
className,
|
|
36
|
-
}: SwipableMobileCarouselSlideBodyProps) {
|
|
37
|
-
return (
|
|
38
|
-
<div className={[styles.body, className].filter(Boolean).join(' ')}>
|
|
39
|
-
{loading ? (loadingFallback ?? defaultLoadingFallback) : children}
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import styles from './SwipableMobileCarouselSlideParts.module.css';
|
|
3
|
-
|
|
4
|
-
export interface SwipableMobileCarouselSlideFooterProps {
|
|
5
|
-
children: ReactNode;
|
|
6
|
-
className?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* SwipableMobileCarouselSlideFooter — always renders its children, no
|
|
11
|
-
* loading concept. See SwipableMobileCarouselSlideHeader's doc comment.
|
|
12
|
-
*/
|
|
13
|
-
export function SwipableMobileCarouselSlideFooter({
|
|
14
|
-
children,
|
|
15
|
-
className,
|
|
16
|
-
}: SwipableMobileCarouselSlideFooterProps) {
|
|
17
|
-
return <div className={[styles.footer, className].filter(Boolean).join(' ')}>{children}</div>;
|
|
18
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import styles from './SwipableMobileCarouselSlideParts.module.css';
|
|
3
|
-
|
|
4
|
-
export interface SwipableMobileCarouselSlideHeaderProps {
|
|
5
|
-
children: ReactNode;
|
|
6
|
-
className?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* SwipableMobileCarouselSlideHeader — always renders its children, no
|
|
11
|
-
* loading concept. Meant for content already known synchronously (a list's
|
|
12
|
-
* title, color, item count from data the caller already has) so it can
|
|
13
|
-
* render immediately even while SwipableMobileCarouselSlideBody's own
|
|
14
|
-
* content is still loading — see that component's doc comment.
|
|
15
|
-
*/
|
|
16
|
-
export function SwipableMobileCarouselSlideHeader({
|
|
17
|
-
children,
|
|
18
|
-
className,
|
|
19
|
-
}: SwipableMobileCarouselSlideHeaderProps) {
|
|
20
|
-
return <div className={[styles.header, className].filter(Boolean).join(' ')}>{children}</div>;
|
|
21
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
.header,
|
|
2
|
-
.footer {
|
|
3
|
-
flex: 0 0 auto;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.body {
|
|
7
|
-
flex: 1 1 auto;
|
|
8
|
-
min-height: 0; /* allow shrinking inside the slide's flex column, so it can scroll instead of overflowing */
|
|
9
|
-
overflow-y: auto;
|
|
10
|
-
overflow-x: hidden;
|
|
11
|
-
/* Deliberately does NOT set touch-action: pan-y here. touch-action's
|
|
12
|
-
effective value is the INTERSECTION of this element's and every
|
|
13
|
-
ancestor's value (docs/architecture-rules.md) — the ancestor .scroller
|
|
14
|
-
(SwipableMobileCarousel.module.css) needs the horizontal swipe gesture,
|
|
15
|
-
so pan-y here ∩ that horizontal handling would resolve to neither axis
|
|
16
|
-
working natively. Relying on the browser's default touch-action (auto)
|
|
17
|
-
here lets native gesture arbitration between the two nested scrollers
|
|
18
|
-
sort out which axis wins per-gesture — don't "fix" perceived nested-
|
|
19
|
-
scroll jank by adding pan-y; it silently breaks horizontal swipe instead. */
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.loading {
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
justify-content: center;
|
|
26
|
-
height: 100%;
|
|
27
|
-
color: var(--sv-color-text-subtle);
|
|
28
|
-
font-size: var(--sv-font-size-sm);
|
|
29
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
-
import { SwipableMobileCarousel } from '../SwipableMobileCarousel';
|
|
5
|
-
import { SwipableMobileCarouselSlide } from '../SwipableMobileCarouselSlide';
|
|
6
|
-
import { SwipableMobileCarouselSlideHeader } from '../SwipableMobileCarouselSlideHeader';
|
|
7
|
-
import { SwipableMobileCarouselSlideBody } from '../SwipableMobileCarouselSlideBody';
|
|
8
|
-
|
|
9
|
-
// Same jsdom scroll polyfill/fake-timer setup as useSnapCarousel.test.tsx,
|
|
10
|
-
// since this component wraps that hook directly.
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
vi.useFakeTimers();
|
|
13
|
-
if (!Element.prototype.scrollTo) {
|
|
14
|
-
Element.prototype.scrollTo = vi.fn();
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
vi.runOnlyPendingTimers();
|
|
20
|
-
vi.useRealTimers();
|
|
21
|
-
cleanup();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
function setLayout(el: HTMLElement, clientWidth: number, scrollLeft: number) {
|
|
25
|
-
Object.defineProperty(el, 'clientWidth', { value: clientWidth, configurable: true });
|
|
26
|
-
Object.defineProperty(el, 'scrollLeft', { value: scrollLeft, configurable: true });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const KEYS = ['a', 'b', 'c', 'd', 'e'];
|
|
30
|
-
|
|
31
|
-
function FiveSlides({
|
|
32
|
-
activeIndex,
|
|
33
|
-
onSettle,
|
|
34
|
-
}: {
|
|
35
|
-
activeIndex: number;
|
|
36
|
-
onSettle: (i: number) => void;
|
|
37
|
-
}) {
|
|
38
|
-
return (
|
|
39
|
-
<SwipableMobileCarousel activeIndex={activeIndex} onSettle={onSettle} aria-label="Test slides">
|
|
40
|
-
{KEYS.map((key) => (
|
|
41
|
-
<SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
|
|
42
|
-
<SwipableMobileCarouselSlideHeader>{`header-${key}`}</SwipableMobileCarouselSlideHeader>
|
|
43
|
-
<SwipableMobileCarouselSlideBody>{`body-${key}`}</SwipableMobileCarouselSlideBody>
|
|
44
|
-
</SwipableMobileCarouselSlide>
|
|
45
|
-
))}
|
|
46
|
-
</SwipableMobileCarousel>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
describe('SwipableMobileCarousel', () => {
|
|
51
|
-
it('only mounts the active slide and its immediate neighbors (default prefetchDistance=1)', () => {
|
|
52
|
-
render(<FiveSlides activeIndex={2} onSettle={() => {}} />);
|
|
53
|
-
// active (c) and neighbors (b, d) are mounted
|
|
54
|
-
expect(screen.getByText('header-b')).toBeDefined();
|
|
55
|
-
expect(screen.getByText('header-c')).toBeDefined();
|
|
56
|
-
expect(screen.getByText('header-d')).toBeDefined();
|
|
57
|
-
// out-of-window slides (a, e) render nothing at all
|
|
58
|
-
expect(screen.queryByText('header-a')).toBeNull();
|
|
59
|
-
expect(screen.queryByText('body-a')).toBeNull();
|
|
60
|
-
expect(screen.queryByText('header-e')).toBeNull();
|
|
61
|
-
expect(screen.queryByText('body-e')).toBeNull();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("SlideBody's loading prop only hides that region, not the Header", () => {
|
|
65
|
-
render(
|
|
66
|
-
<SwipableMobileCarousel activeIndex={0} onSettle={() => {}} aria-label="Test slides">
|
|
67
|
-
<SwipableMobileCarouselSlide slideKey="only" label="Only">
|
|
68
|
-
<SwipableMobileCarouselSlideHeader>the-title</SwipableMobileCarouselSlideHeader>
|
|
69
|
-
<SwipableMobileCarouselSlideBody loading>tasks-content</SwipableMobileCarouselSlideBody>
|
|
70
|
-
</SwipableMobileCarouselSlide>
|
|
71
|
-
</SwipableMobileCarousel>,
|
|
72
|
-
);
|
|
73
|
-
expect(screen.getByText('the-title')).toBeDefined();
|
|
74
|
-
expect(screen.queryByText('tasks-content')).toBeNull();
|
|
75
|
-
expect(screen.getByText('Loading…')).toBeDefined();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('calls onSettle with the new index after a swipe settles', () => {
|
|
79
|
-
const onSettle = vi.fn();
|
|
80
|
-
render(<FiveSlides activeIndex={0} onSettle={onSettle} />);
|
|
81
|
-
const scroller = screen.getByRole('region', { name: 'Test slides' });
|
|
82
|
-
fireEvent.touchStart(scroller);
|
|
83
|
-
setLayout(scroller, 300, 300); // scrollLeft 300 / width 300 -> index 1
|
|
84
|
-
fireEvent.scroll(scroller);
|
|
85
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
86
|
-
expect(onSettle).toHaveBeenCalledWith(1);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('clicking a dot calls onSettle directly with that index', () => {
|
|
90
|
-
const onSettle = vi.fn();
|
|
91
|
-
render(<FiveSlides activeIndex={0} onSettle={onSettle} />);
|
|
92
|
-
const dots = screen.getAllByRole('tab');
|
|
93
|
-
const fourthDot = dots[3];
|
|
94
|
-
if (!fourthDot) throw new Error('expected a 4th dot');
|
|
95
|
-
setLayout(screen.getByRole('region', { name: 'Test slides' }), 300, 0);
|
|
96
|
-
fireEvent.click(fourthDot);
|
|
97
|
-
expect(onSettle).toHaveBeenCalledWith(3);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('positions both the default and a custom renderIndicator inside the same overlay slot', () => {
|
|
101
|
-
// Regression test: the overlay-positioning class used to be applied
|
|
102
|
-
// directly to the default SwipableMobileCarouselDots instance, so any
|
|
103
|
-
// caller-supplied renderIndicator rendered as a plain static element
|
|
104
|
-
// instead — pushed out of view below the full-height scroller. The
|
|
105
|
-
// carousel must own positioning for whatever renderIndicator returns.
|
|
106
|
-
const { unmount } = render(<FiveSlides activeIndex={0} onSettle={() => {}} />);
|
|
107
|
-
const defaultTablist = screen.getByRole('tablist');
|
|
108
|
-
expect(defaultTablist.parentElement?.className).toMatch(/indicatorSlot/);
|
|
109
|
-
unmount();
|
|
110
|
-
|
|
111
|
-
render(
|
|
112
|
-
<SwipableMobileCarousel
|
|
113
|
-
activeIndex={0}
|
|
114
|
-
onSettle={() => {}}
|
|
115
|
-
aria-label="Test slides"
|
|
116
|
-
renderIndicator={({ count, activeIndex, onJump }) => (
|
|
117
|
-
<div role="tablist" aria-label="Custom">
|
|
118
|
-
{Array.from({ length: count }, (_, i) => (
|
|
119
|
-
<button key={i} type="button" role="tab" onClick={() => onJump(i)}>
|
|
120
|
-
{i === activeIndex ? 'active' : 'inactive'}
|
|
121
|
-
</button>
|
|
122
|
-
))}
|
|
123
|
-
</div>
|
|
124
|
-
)}
|
|
125
|
-
>
|
|
126
|
-
{KEYS.map((key) => (
|
|
127
|
-
<SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
|
|
128
|
-
{`slide-${key}`}
|
|
129
|
-
</SwipableMobileCarouselSlide>
|
|
130
|
-
))}
|
|
131
|
-
</SwipableMobileCarousel>,
|
|
132
|
-
);
|
|
133
|
-
const customTablist = screen.getByRole('tablist', { name: 'Custom' });
|
|
134
|
-
expect(customTablist.parentElement?.className).toMatch(/indicatorSlot/);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('re-snaps and reports the new index when the active slide moves position (reorder-jump fix)', () => {
|
|
138
|
-
function Reorderable({ order, onSettle }: { order: string[]; onSettle: (i: number) => void }) {
|
|
139
|
-
return (
|
|
140
|
-
<SwipableMobileCarousel activeIndex={1} onSettle={onSettle} aria-label="Test slides">
|
|
141
|
-
{order.map((key) => (
|
|
142
|
-
<SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
|
|
143
|
-
<SwipableMobileCarouselSlideHeader>{`header-${key}`}</SwipableMobileCarouselSlideHeader>
|
|
144
|
-
</SwipableMobileCarouselSlide>
|
|
145
|
-
))}
|
|
146
|
-
</SwipableMobileCarousel>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
const onSettle = vi.fn();
|
|
150
|
-
const { rerender } = render(<Reorderable order={['a', 'b', 'c']} onSettle={onSettle} />);
|
|
151
|
-
const scroller = screen.getByRole('region', { name: 'Test slides' });
|
|
152
|
-
setLayout(scroller, 300, 0);
|
|
153
|
-
const spy = vi.spyOn(scroller, 'scrollTo');
|
|
154
|
-
|
|
155
|
-
// 'b' (index 1, active) moves to index 0.
|
|
156
|
-
rerender(<Reorderable order={['b', 'a', 'c']} onSettle={onSettle} />);
|
|
157
|
-
|
|
158
|
-
expect(onSettle).toHaveBeenCalledWith(0);
|
|
159
|
-
expect(spy).toHaveBeenCalledWith({ left: 0, behavior: 'instant' });
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('mounts a slide reached by a fast multi-slide flick before settle-detection reports it', () => {
|
|
163
|
-
// Regression test, found via a user screen recording: a fast flick can
|
|
164
|
-
// carry native scroll-snap momentum straight past an intermediate slide
|
|
165
|
-
// to one two-or-more away in a single continuous gesture. Settle-
|
|
166
|
-
// detection deliberately still waits out the full debounce window before
|
|
167
|
-
// calling onSettle (to distinguish a real settle from drift — see
|
|
168
|
-
// useSnapCarousel's chainTrustedRef comment), but the mount window used
|
|
169
|
-
// to be keyed *only* off that settled index — so the slide the container
|
|
170
|
-
// had already scrolled to, visually, sat completely unmounted (not even
|
|
171
|
-
// a loading skeleton, per SwipableMobileCarouselSlide's `return null`)
|
|
172
|
-
// for the entire debounce window. liveIndex closes that gap.
|
|
173
|
-
const onSettle = vi.fn();
|
|
174
|
-
const KEYS8 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
|
175
|
-
function EightSlides({ onSettle }: { onSettle: (i: number) => void }) {
|
|
176
|
-
return (
|
|
177
|
-
<SwipableMobileCarousel activeIndex={0} onSettle={onSettle} aria-label="Test slides">
|
|
178
|
-
{KEYS8.map((key) => (
|
|
179
|
-
<SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
|
|
180
|
-
<SwipableMobileCarouselSlideHeader>{`header-${key}`}</SwipableMobileCarouselSlideHeader>
|
|
181
|
-
</SwipableMobileCarouselSlide>
|
|
182
|
-
))}
|
|
183
|
-
</SwipableMobileCarousel>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
render(<EightSlides onSettle={onSettle} />);
|
|
187
|
-
const scroller = screen.getByRole('region', { name: 'Test slides' });
|
|
188
|
-
// Slide 'e' (index 4) is well outside the default prefetchDistance=1
|
|
189
|
-
// window around the settled index 0.
|
|
190
|
-
expect(screen.queryByText('header-e')).toBeNull();
|
|
191
|
-
|
|
192
|
-
fireEvent.touchStart(scroller);
|
|
193
|
-
setLayout(scroller, 300, 1200); // scrollLeft 1200 / width 300 -> index 4
|
|
194
|
-
fireEvent.scroll(scroller);
|
|
195
|
-
// Well short of the 120ms settle debounce — onSettle must not have fired
|
|
196
|
-
// yet, but the rAF-throttled liveIndex update has had time to run.
|
|
197
|
-
act(() => void vi.advanceTimersByTime(20));
|
|
198
|
-
expect(onSettle).not.toHaveBeenCalled();
|
|
199
|
-
expect(screen.getByText('header-e')).toBeDefined();
|
|
200
|
-
|
|
201
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
202
|
-
expect(onSettle).toHaveBeenCalledWith(4);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('does not re-snap when slide order is unchanged', () => {
|
|
206
|
-
function Reorderable({ onSettle }: { onSettle: (i: number) => void }) {
|
|
207
|
-
return <FiveSlides activeIndex={2} onSettle={onSettle} />;
|
|
208
|
-
}
|
|
209
|
-
const onSettle = vi.fn();
|
|
210
|
-
const { rerender } = render(<Reorderable onSettle={onSettle} />);
|
|
211
|
-
rerender(<Reorderable onSettle={onSettle} />);
|
|
212
|
-
expect(onSettle).not.toHaveBeenCalled();
|
|
213
|
-
});
|
|
214
|
-
});
|
package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, render } from '@testing-library/react';
|
|
4
|
-
import { SwipableMobileCarousel } from '../SwipableMobileCarousel';
|
|
5
|
-
import { SwipableMobileCarouselSlide } from '../SwipableMobileCarouselSlide';
|
|
6
|
-
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
if (!Element.prototype.scrollTo) {
|
|
9
|
-
Element.prototype.scrollTo = vi.fn();
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
cleanup();
|
|
15
|
-
vi.restoreAllMocks();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
function renderWithStrayChild() {
|
|
19
|
-
return render(
|
|
20
|
-
<SwipableMobileCarousel activeIndex={0} onSettle={() => {}} aria-label="Test slides">
|
|
21
|
-
<SwipableMobileCarouselSlide slideKey="a" label="A">
|
|
22
|
-
content
|
|
23
|
-
</SwipableMobileCarouselSlide>
|
|
24
|
-
{/* stray non-Slide child — shifts index math for anything after it */}
|
|
25
|
-
<div>oops</div>
|
|
26
|
-
<SwipableMobileCarouselSlide slideKey="b" label="B">
|
|
27
|
-
content
|
|
28
|
-
</SwipableMobileCarouselSlide>
|
|
29
|
-
</SwipableMobileCarousel>,
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
describe('SwipableMobileCarousel dev-mode child-type guard', () => {
|
|
34
|
-
it('warns via console.error in development, mentioning the offending child', () => {
|
|
35
|
-
const originalEnv = process.env.NODE_ENV;
|
|
36
|
-
vi.stubEnv('NODE_ENV', 'development');
|
|
37
|
-
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
38
|
-
|
|
39
|
-
expect(() => renderWithStrayChild()).not.toThrow();
|
|
40
|
-
|
|
41
|
-
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('<div>'));
|
|
42
|
-
vi.stubEnv('NODE_ENV', originalEnv ?? 'test');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('does not call console.error in production', () => {
|
|
46
|
-
const originalEnv = process.env.NODE_ENV;
|
|
47
|
-
vi.stubEnv('NODE_ENV', 'production');
|
|
48
|
-
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
49
|
-
|
|
50
|
-
expect(() => renderWithStrayChild()).not.toThrow();
|
|
51
|
-
|
|
52
|
-
expect(errorSpy).not.toHaveBeenCalled();
|
|
53
|
-
vi.stubEnv('NODE_ENV', originalEnv ?? 'test');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('never throws, even with a stray child (a miscounted slide degrades, it does not crash)', () => {
|
|
57
|
-
vi.stubEnv('NODE_ENV', 'development');
|
|
58
|
-
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
59
|
-
expect(() => renderWithStrayChild()).not.toThrow();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { createContext } from 'react';
|
|
4
|
-
|
|
5
|
-
export interface CarouselSlideMountContextValue {
|
|
6
|
-
/** Whether this slide is within the carousel's mount window (the active
|
|
7
|
-
* slide ± its configured prefetchDistance). Kept out of the main .tsx
|
|
8
|
-
* file for React Fast Refresh hygiene (a file exporting only components
|
|
9
|
-
* refreshes more reliably than one mixing components and plain values). */
|
|
10
|
-
isMounted: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const CarouselSlideMountContext = createContext<CarouselSlideMountContextValue | null>(null);
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
.dots {
|
|
2
|
-
display: flex;
|
|
3
|
-
align-items: center;
|
|
4
|
-
justify-content: center;
|
|
5
|
-
gap: var(--sv-space-2);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/* Opt-in — see the `density` prop doc comment. Shrinks both the gap and each
|
|
9
|
-
dot's own hit target (20px -> 16px) — for a carousel with enough slides
|
|
10
|
-
that even the space-1 gap alone still read as too wide. The visible 6px
|
|
11
|
-
dot is unchanged; only the surrounding tap-target box shrinks, via the
|
|
12
|
-
descendant override below rather than a second dot variant, so this stays
|
|
13
|
-
a pure CSS opt-in with no JS/prop plumbing beyond `density` itself. */
|
|
14
|
-
.dotsCompact {
|
|
15
|
-
gap: var(--sv-space-1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.dotsCompact .dot {
|
|
19
|
-
width: 16px;
|
|
20
|
-
height: 16px;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.dot {
|
|
24
|
-
/* A 6px visible dot is too small a hit target on its own — the button's
|
|
25
|
-
real box is larger (20px) with the dot itself painted by ::before and
|
|
26
|
-
centered inside, so tap area grows without changing the visible dot
|
|
27
|
-
size or the row's gap-based spacing math. */
|
|
28
|
-
position: relative;
|
|
29
|
-
width: 20px;
|
|
30
|
-
height: 20px;
|
|
31
|
-
padding: 0;
|
|
32
|
-
border: none;
|
|
33
|
-
background: transparent;
|
|
34
|
-
cursor: pointer;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.dot::before {
|
|
38
|
-
content: '';
|
|
39
|
-
position: absolute;
|
|
40
|
-
top: 50%;
|
|
41
|
-
left: 50%;
|
|
42
|
-
width: 6px;
|
|
43
|
-
height: 6px;
|
|
44
|
-
border-radius: 50%;
|
|
45
|
-
background: var(--sv-color-border-strong);
|
|
46
|
-
transform: translate(-50%, -50%);
|
|
47
|
-
transition: background 0.15s ease;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.dot:focus-visible {
|
|
51
|
-
outline: 2px solid var(--sv-color-focus-ring);
|
|
52
|
-
outline-offset: 2px;
|
|
53
|
-
border-radius: 50%;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.dotActive::before {
|
|
57
|
-
background: var(--sv-color-text-primary);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@media (hover: hover) {
|
|
61
|
-
.dot:not(.dotActive):hover::before {
|
|
62
|
-
background: var(--sv-color-text-muted);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import styles from './SwipableMobileCarouselDots.module.css';
|
|
4
|
-
|
|
5
|
-
export interface SwipableMobileCarouselDotsProps {
|
|
6
|
-
count: number;
|
|
7
|
-
activeIndex: number;
|
|
8
|
-
onJump: (index: number) => void;
|
|
9
|
-
/** Per-dot accessible names, e.g. ["Lists", "Starred", "Groceries"]. Falls
|
|
10
|
-
* back to "Slide N of count" for any index without one. */
|
|
11
|
-
labels?: (string | undefined)[];
|
|
12
|
-
/** Labels the whole group — required, no generic fallback (mirrors
|
|
13
|
-
* SwipableMobileCarousel's own required aria-label). */
|
|
14
|
-
'aria-label': string;
|
|
15
|
-
/** `'compact'` halves the gap between dots (`--sv-space-2` → `--sv-space-1`)
|
|
16
|
-
* and shrinks each dot's own hit target (20px → 16px) — for a carousel
|
|
17
|
-
* with enough slides that even the reduced gap alone still reads as too
|
|
18
|
-
* wide on a narrow viewport (e.g. a many-list mobile app). The visible
|
|
19
|
-
* 6px dot itself is unchanged; only its surrounding tap-target box
|
|
20
|
-
* shrinks. Defaults to `'default'` — every existing consumer's spacing is
|
|
21
|
-
* unaffected unless it opts in. */
|
|
22
|
-
density?: 'default' | 'compact';
|
|
23
|
-
className?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* SwipableMobileCarouselDots — a real, tappable, labeled slide indicator.
|
|
28
|
-
* Standalone (not carousel-only): reusable anywhere a set of positions needs
|
|
29
|
-
* a dot indicator (e.g. an image gallery, an onboarding stepper), and is also
|
|
30
|
-
* SwipableMobileCarousel's default `renderIndicator`.
|
|
31
|
-
*
|
|
32
|
-
* Replaces the `aria-hidden`, non-interactive dots pattern both
|
|
33
|
-
* sovereign-tasks and sovereign-shopper currently hand-roll — every dot here
|
|
34
|
-
* is a real `role="tab"` button with its own accessible name, reachable by
|
|
35
|
-
* keyboard. No roving tabIndex/arrow-key handling: `Tabs` (this library's
|
|
36
|
-
* other `role="tablist"` component) has none either, so this stays
|
|
37
|
-
* consistent with it rather than gold-plating past its sibling.
|
|
38
|
-
*/
|
|
39
|
-
export function SwipableMobileCarouselDots({
|
|
40
|
-
count,
|
|
41
|
-
activeIndex,
|
|
42
|
-
onJump,
|
|
43
|
-
labels,
|
|
44
|
-
'aria-label': ariaLabel,
|
|
45
|
-
density = 'default',
|
|
46
|
-
className,
|
|
47
|
-
}: SwipableMobileCarouselDotsProps) {
|
|
48
|
-
return (
|
|
49
|
-
<div
|
|
50
|
-
role="tablist"
|
|
51
|
-
aria-label={ariaLabel}
|
|
52
|
-
className={[styles.dots, density === 'compact' ? styles.dotsCompact : '', className]
|
|
53
|
-
.filter(Boolean)
|
|
54
|
-
.join(' ')}
|
|
55
|
-
>
|
|
56
|
-
{Array.from({ length: count }, (_, i) => {
|
|
57
|
-
const active = i === activeIndex;
|
|
58
|
-
const label = labels?.[i] ?? `Slide ${i + 1} of ${count}`;
|
|
59
|
-
return (
|
|
60
|
-
<button
|
|
61
|
-
key={i}
|
|
62
|
-
type="button"
|
|
63
|
-
role="tab"
|
|
64
|
-
aria-selected={active}
|
|
65
|
-
aria-label={label}
|
|
66
|
-
className={[styles.dot, active ? styles.dotActive : ''].filter(Boolean).join(' ')}
|
|
67
|
-
onClick={() => onJump(i)}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
})}
|
|
71
|
-
</div>
|
|
72
|
-
);
|
|
73
|
-
}
|
package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
-
import { SwipableMobileCarouselDots } from '../SwipableMobileCarouselDots';
|
|
5
|
-
|
|
6
|
-
afterEach(cleanup);
|
|
7
|
-
|
|
8
|
-
describe('SwipableMobileCarouselDots', () => {
|
|
9
|
-
it('renders a tablist with one tab per count, none aria-hidden', () => {
|
|
10
|
-
render(
|
|
11
|
-
<SwipableMobileCarouselDots count={3} activeIndex={0} onJump={() => {}} aria-label="Lists" />,
|
|
12
|
-
);
|
|
13
|
-
const list = screen.getByRole('tablist', { name: 'Lists' });
|
|
14
|
-
expect(list.getAttribute('aria-hidden')).toBeNull();
|
|
15
|
-
const tabs = screen.getAllByRole('tab');
|
|
16
|
-
expect(tabs).toHaveLength(3);
|
|
17
|
-
tabs.forEach((tab) => expect(tab.getAttribute('aria-hidden')).toBeNull());
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('marks only the active dot as aria-selected', () => {
|
|
21
|
-
render(
|
|
22
|
-
<SwipableMobileCarouselDots count={3} activeIndex={1} onJump={() => {}} aria-label="Lists" />,
|
|
23
|
-
);
|
|
24
|
-
const tabs = screen.getAllByRole('tab');
|
|
25
|
-
expect(tabs[0]?.getAttribute('aria-selected')).toBe('false');
|
|
26
|
-
expect(tabs[1]?.getAttribute('aria-selected')).toBe('true');
|
|
27
|
-
expect(tabs[2]?.getAttribute('aria-selected')).toBe('false');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('uses the provided per-dot labels, falling back to "Slide N of count"', () => {
|
|
31
|
-
render(
|
|
32
|
-
<SwipableMobileCarouselDots
|
|
33
|
-
count={3}
|
|
34
|
-
activeIndex={0}
|
|
35
|
-
onJump={() => {}}
|
|
36
|
-
labels={['Lists', undefined, 'Groceries']}
|
|
37
|
-
aria-label="Lists"
|
|
38
|
-
/>,
|
|
39
|
-
);
|
|
40
|
-
expect(screen.getByRole('tab', { name: 'Lists' })).toBeDefined();
|
|
41
|
-
expect(screen.getByRole('tab', { name: 'Slide 2 of 3' })).toBeDefined();
|
|
42
|
-
expect(screen.getByRole('tab', { name: 'Groceries' })).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('clicking a dot calls onJump with its index', () => {
|
|
46
|
-
const onJump = vi.fn();
|
|
47
|
-
render(
|
|
48
|
-
<SwipableMobileCarouselDots count={3} activeIndex={0} onJump={onJump} aria-label="Lists" />,
|
|
49
|
-
);
|
|
50
|
-
const thirdTab = screen.getAllByRole('tab')[2];
|
|
51
|
-
if (!thirdTab) throw new Error('expected a 3rd tab');
|
|
52
|
-
fireEvent.click(thirdTab);
|
|
53
|
-
expect(onJump).toHaveBeenCalledWith(2);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('every dot is a real, focusable button (not a decorative element)', () => {
|
|
57
|
-
render(
|
|
58
|
-
<SwipableMobileCarouselDots count={2} activeIndex={0} onJump={() => {}} aria-label="Lists" />,
|
|
59
|
-
);
|
|
60
|
-
const tabs = screen.getAllByRole('tab');
|
|
61
|
-
tabs.forEach((tab) => expect(tab.tagName).toBe('BUTTON'));
|
|
62
|
-
});
|
|
63
|
-
});
|