@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,53 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, render } from '@testing-library/react';
|
|
4
|
-
import { useIsOffline } from '../useIsOffline';
|
|
5
|
-
|
|
6
|
-
function Harness() {
|
|
7
|
-
const isOffline = useIsOffline();
|
|
8
|
-
return <span data-testid="out">{String(isOffline)}</span>;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
describe('useIsOffline', () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: true });
|
|
14
|
-
});
|
|
15
|
-
afterEach(() => {
|
|
16
|
-
vi.unstubAllGlobals();
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('reflects navigator.onLine after mount', () => {
|
|
21
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
22
|
-
const { getByTestId } = render(<Harness />);
|
|
23
|
-
expect(getByTestId('out').textContent).toBe('true');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('does not report offline when navigator.onLine is true', () => {
|
|
27
|
-
const { getByTestId } = render(<Harness />);
|
|
28
|
-
expect(getByTestId('out').textContent).toBe('false');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('flips on the offline event', () => {
|
|
32
|
-
const { getByTestId } = render(<Harness />);
|
|
33
|
-
expect(getByTestId('out').textContent).toBe('false');
|
|
34
|
-
act(() => window.dispatchEvent(new Event('offline')));
|
|
35
|
-
expect(getByTestId('out').textContent).toBe('true');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('flips back on the online event', () => {
|
|
39
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
40
|
-
const { getByTestId } = render(<Harness />);
|
|
41
|
-
expect(getByTestId('out').textContent).toBe('true');
|
|
42
|
-
act(() => window.dispatchEvent(new Event('online')));
|
|
43
|
-
expect(getByTestId('out').textContent).toBe('false');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('removes its listeners on unmount', () => {
|
|
47
|
-
const removeSpy = vi.spyOn(window, 'removeEventListener');
|
|
48
|
-
const { unmount } = render(<Harness />);
|
|
49
|
-
unmount();
|
|
50
|
-
expect(removeSpy).toHaveBeenCalledWith('offline', expect.any(Function));
|
|
51
|
-
expect(removeSpy).toHaveBeenCalledWith('online', expect.any(Function));
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, fireEvent, render } from '@testing-library/react';
|
|
4
|
-
import { useLongPress, type UseLongPressOptions } from '../useLongPress';
|
|
5
|
-
|
|
6
|
-
// Configurable matchMedia mock — usePrefersCoarsePointer reads
|
|
7
|
-
// '(pointer: coarse)', and the SSR-safe hooks read it on mount. Default to a
|
|
8
|
-
// coarse (touch) device so the suppression styles are exercised; individual
|
|
9
|
-
// tests override `coarse` where they assert the desktop path.
|
|
10
|
-
let coarse = true;
|
|
11
|
-
function installMatchMedia() {
|
|
12
|
-
vi.stubGlobal(
|
|
13
|
-
'matchMedia',
|
|
14
|
-
vi.fn().mockImplementation((query: string) => ({
|
|
15
|
-
matches: query.includes('pointer: coarse') ? coarse : false,
|
|
16
|
-
media: query,
|
|
17
|
-
addEventListener: vi.fn(),
|
|
18
|
-
removeEventListener: vi.fn(),
|
|
19
|
-
addListener: vi.fn(),
|
|
20
|
-
removeListener: vi.fn(),
|
|
21
|
-
dispatchEvent: vi.fn(),
|
|
22
|
-
})),
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// A tiny harness component: spreads the hook's handlers onto a div so we can
|
|
27
|
-
// fire real pointer events at it via Testing Library.
|
|
28
|
-
function Harness(props: UseLongPressOptions & { testId?: string }) {
|
|
29
|
-
const { testId = 'target', ...options } = props;
|
|
30
|
-
const handlers = useLongPress(options);
|
|
31
|
-
return (
|
|
32
|
-
<div data-testid={testId} {...handlers}>
|
|
33
|
-
target
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function pointer(type: 'touch' | 'mouse', x = 0, y = 0) {
|
|
39
|
-
return { pointerType: type, clientX: x, clientY: y };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
describe('useLongPress', () => {
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
coarse = true;
|
|
45
|
-
installMatchMedia();
|
|
46
|
-
vi.useFakeTimers();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
afterEach(() => {
|
|
50
|
-
vi.runOnlyPendingTimers();
|
|
51
|
-
vi.useRealTimers();
|
|
52
|
-
vi.unstubAllGlobals();
|
|
53
|
-
cleanup();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('fires onLongPress after the delay on a touch press held still', () => {
|
|
57
|
-
const onLongPress = vi.fn();
|
|
58
|
-
const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
|
|
59
|
-
fireEvent.pointerDown(getByTestId('target'), pointer('touch'));
|
|
60
|
-
expect(onLongPress).not.toHaveBeenCalled();
|
|
61
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
62
|
-
expect(onLongPress).toHaveBeenCalledOnce();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('does not arm for a mouse pointer (desktop keeps its own affordance)', () => {
|
|
66
|
-
const onLongPress = vi.fn();
|
|
67
|
-
const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
|
|
68
|
-
fireEvent.pointerDown(getByTestId('target'), pointer('mouse'));
|
|
69
|
-
act(() => void vi.advanceTimersByTime(1000));
|
|
70
|
-
expect(onLongPress).not.toHaveBeenCalled();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('tolerates finger jitter within moveTolerance', () => {
|
|
74
|
-
const onLongPress = vi.fn();
|
|
75
|
-
const { getByTestId } = render(
|
|
76
|
-
<Harness onLongPress={onLongPress} delay={500} moveTolerance={10} />,
|
|
77
|
-
);
|
|
78
|
-
const el = getByTestId('target');
|
|
79
|
-
fireEvent.pointerDown(el, pointer('touch', 0, 0));
|
|
80
|
-
fireEvent.pointerMove(el, pointer('touch', 4, 4)); // ~5.7px < 10
|
|
81
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
82
|
-
expect(onLongPress).toHaveBeenCalledOnce();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('cancels when movement exceeds moveTolerance', () => {
|
|
86
|
-
const onLongPress = vi.fn();
|
|
87
|
-
const { getByTestId } = render(
|
|
88
|
-
<Harness onLongPress={onLongPress} delay={500} moveTolerance={10} />,
|
|
89
|
-
);
|
|
90
|
-
const el = getByTestId('target');
|
|
91
|
-
fireEvent.pointerDown(el, pointer('touch', 0, 0));
|
|
92
|
-
fireEvent.pointerMove(el, pointer('touch', 20, 0)); // 20px > 10
|
|
93
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
94
|
-
expect(onLongPress).not.toHaveBeenCalled();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('cancels on pointercancel (touch converted to scroll)', () => {
|
|
98
|
-
const onLongPress = vi.fn();
|
|
99
|
-
const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
|
|
100
|
-
const el = getByTestId('target');
|
|
101
|
-
fireEvent.pointerDown(el, pointer('touch'));
|
|
102
|
-
fireEvent.pointerCancel(el, pointer('touch'));
|
|
103
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
104
|
-
expect(onLongPress).not.toHaveBeenCalled();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('suppresses the click that may follow, but only for a bounded window', () => {
|
|
108
|
-
const onLongPress = vi.fn();
|
|
109
|
-
const { getByTestId } = render(
|
|
110
|
-
<Harness onLongPress={onLongPress} delay={500} suppressClickMs={700} />,
|
|
111
|
-
);
|
|
112
|
-
const el = getByTestId('target');
|
|
113
|
-
fireEvent.pointerDown(el, pointer('touch'));
|
|
114
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
115
|
-
expect(onLongPress).toHaveBeenCalledOnce();
|
|
116
|
-
|
|
117
|
-
// A click arriving right after the long-press is swallowed.
|
|
118
|
-
const suppressed = fireEvent.click(el);
|
|
119
|
-
expect(suppressed).toBe(false); // preventDefault called → fireEvent returns false
|
|
120
|
-
|
|
121
|
-
// After the suppression window, a genuinely unrelated later tap is NOT eaten.
|
|
122
|
-
act(() => void vi.advanceTimersByTime(800));
|
|
123
|
-
const allowed = fireEvent.click(el);
|
|
124
|
-
expect(allowed).toBe(true);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('prevents the OS context menu while a press is pending', () => {
|
|
128
|
-
const { getByTestId } = render(<Harness onLongPress={vi.fn()} delay={500} />);
|
|
129
|
-
const el = getByTestId('target');
|
|
130
|
-
fireEvent.pointerDown(el, pointer('touch'));
|
|
131
|
-
const prevented = fireEvent.contextMenu(el);
|
|
132
|
-
expect(prevented).toBe(false); // preventDefault called
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('does nothing when disabled', () => {
|
|
136
|
-
const onLongPress = vi.fn();
|
|
137
|
-
const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} disabled />);
|
|
138
|
-
fireEvent.pointerDown(getByTestId('target'), pointer('touch'));
|
|
139
|
-
act(() => void vi.advanceTimersByTime(500));
|
|
140
|
-
expect(onLongPress).not.toHaveBeenCalled();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('emits suppression styles only on coarse-pointer devices', () => {
|
|
144
|
-
coarse = true;
|
|
145
|
-
installMatchMedia();
|
|
146
|
-
const { getByTestId, rerender } = render(<Harness onLongPress={vi.fn()} testId="coarse" />);
|
|
147
|
-
// jsdom applies the inline style object; user-select none is the tell.
|
|
148
|
-
expect(getByTestId('coarse').style.userSelect).toBe('none');
|
|
149
|
-
|
|
150
|
-
coarse = false;
|
|
151
|
-
installMatchMedia();
|
|
152
|
-
rerender(<Harness onLongPress={vi.fn()} testId="coarse" />);
|
|
153
|
-
// A remount picks up the new (fine-pointer) matchMedia result.
|
|
154
|
-
cleanup();
|
|
155
|
-
const fine = render(<Harness onLongPress={vi.fn()} testId="fine" />);
|
|
156
|
-
expect(fine.getByTestId('fine').style.userSelect).toBe('');
|
|
157
|
-
});
|
|
158
|
-
});
|
|
@@ -1,69 +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 { useOfflineTileState } from '../useOfflineTileState';
|
|
5
|
-
|
|
6
|
-
function Harness({
|
|
7
|
-
offline,
|
|
8
|
-
deviceOnlyAvailable,
|
|
9
|
-
}: {
|
|
10
|
-
offline: 'offline-first' | 'device-only' | undefined;
|
|
11
|
-
deviceOnlyAvailable: boolean;
|
|
12
|
-
}) {
|
|
13
|
-
const state = useOfflineTileState(offline, deviceOnlyAvailable);
|
|
14
|
-
return <span data-testid="out">{String(state)}</span>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
describe('useOfflineTileState', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: true });
|
|
20
|
-
});
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
vi.unstubAllGlobals();
|
|
23
|
-
cleanup();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('is null for a no-tier app while online', () => {
|
|
27
|
-
const { getByTestId } = render(<Harness offline={undefined} deviceOnlyAvailable={false} />);
|
|
28
|
-
expect(getByTestId('out').textContent).toBe('null');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('connectivity-dims a no-tier app while offline', () => {
|
|
32
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
33
|
-
const { getByTestId } = render(<Harness offline={undefined} deviceOnlyAvailable={false} />);
|
|
34
|
-
expect(getByTestId('out').textContent).toBe('connectivity-dimmed');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('never dims an offline-first app, online or offline', () => {
|
|
38
|
-
const online = render(<Harness offline="offline-first" deviceOnlyAvailable={false} />);
|
|
39
|
-
expect(online.getByTestId('out').textContent).toBe('null');
|
|
40
|
-
cleanup();
|
|
41
|
-
|
|
42
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
43
|
-
const offline = render(<Harness offline="offline-first" deviceOnlyAvailable={false} />);
|
|
44
|
-
expect(offline.getByTestId('out').textContent).toBe('null');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('capability-restricts a device-only app when unavailable, regardless of connectivity', () => {
|
|
48
|
-
const online = render(<Harness offline="device-only" deviceOnlyAvailable={false} />);
|
|
49
|
-
expect(online.getByTestId('out').textContent).toBe('capability-restricted');
|
|
50
|
-
cleanup();
|
|
51
|
-
|
|
52
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
53
|
-
const offline = render(<Harness offline="device-only" deviceOnlyAvailable={false} />);
|
|
54
|
-
expect(offline.getByTestId('out').textContent).toBe('capability-restricted');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('is not restricted for a device-only app when available, and not dimmed offline either', () => {
|
|
58
|
-
const online = render(<Harness offline="device-only" deviceOnlyAvailable={true} />);
|
|
59
|
-
expect(online.getByTestId('out').textContent).toBe('null');
|
|
60
|
-
cleanup();
|
|
61
|
-
|
|
62
|
-
// Availability is a capability signal, not a connectivity one — a
|
|
63
|
-
// device-only app that IS available behaves like offline-first once the
|
|
64
|
-
// capability question is settled.
|
|
65
|
-
vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
|
|
66
|
-
const offline = render(<Harness offline="device-only" deviceOnlyAvailable={true} />);
|
|
67
|
-
expect(offline.getByTestId('out').textContent).toBe('null');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, render } from '@testing-library/react';
|
|
4
|
-
import { useRef } from 'react';
|
|
5
|
-
import { usePublishShellChromeHeight } from '../usePublishShellChromeHeight';
|
|
6
|
-
|
|
7
|
-
function Harness() {
|
|
8
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
9
|
-
usePublishShellChromeHeight(ref, '--sv-shell-footer-height');
|
|
10
|
-
return <div ref={ref} />;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function HeaderHarness() {
|
|
14
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
15
|
-
usePublishShellChromeHeight(ref, '--sv-shell-header-height');
|
|
16
|
-
return <div ref={ref} />;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function stubHeight(height: number) {
|
|
20
|
-
return vi.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({
|
|
21
|
-
height,
|
|
22
|
-
width: 0,
|
|
23
|
-
top: 0,
|
|
24
|
-
left: 0,
|
|
25
|
-
right: 0,
|
|
26
|
-
bottom: 0,
|
|
27
|
-
x: 0,
|
|
28
|
-
y: 0,
|
|
29
|
-
toJSON() {},
|
|
30
|
-
} as DOMRect);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
describe('usePublishShellChromeHeight', () => {
|
|
34
|
-
afterEach(() => {
|
|
35
|
-
cleanup();
|
|
36
|
-
document.getElementById('sv-app-shell')?.remove();
|
|
37
|
-
vi.restoreAllMocks();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('re-measures on window resize', () => {
|
|
41
|
-
const shell = document.createElement('div');
|
|
42
|
-
shell.id = 'sv-app-shell';
|
|
43
|
-
document.body.appendChild(shell);
|
|
44
|
-
const rectSpy = stubHeight(50);
|
|
45
|
-
|
|
46
|
-
render(<Harness />);
|
|
47
|
-
expect(shell.style.getPropertyValue('--sv-shell-footer-height')).toBe('50px');
|
|
48
|
-
|
|
49
|
-
rectSpy.mockReturnValue({
|
|
50
|
-
height: 80,
|
|
51
|
-
width: 0,
|
|
52
|
-
top: 0,
|
|
53
|
-
left: 0,
|
|
54
|
-
right: 0,
|
|
55
|
-
bottom: 0,
|
|
56
|
-
x: 0,
|
|
57
|
-
y: 0,
|
|
58
|
-
toJSON() {},
|
|
59
|
-
} as DOMRect);
|
|
60
|
-
act(() => window.dispatchEvent(new Event('resize')));
|
|
61
|
-
|
|
62
|
-
expect(shell.style.getPropertyValue('--sv-shell-footer-height')).toBe('80px');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('removes its resize listener on unmount', () => {
|
|
66
|
-
const shell = document.createElement('div');
|
|
67
|
-
shell.id = 'sv-app-shell';
|
|
68
|
-
document.body.appendChild(shell);
|
|
69
|
-
stubHeight(50);
|
|
70
|
-
const removeSpy = vi.spyOn(window, 'removeEventListener');
|
|
71
|
-
|
|
72
|
-
const { unmount } = render(<Harness />);
|
|
73
|
-
unmount();
|
|
74
|
-
|
|
75
|
-
expect(removeSpy).toHaveBeenCalledWith('resize', expect.any(Function));
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('is a no-op when #sv-app-shell does not exist', () => {
|
|
79
|
-
stubHeight(50);
|
|
80
|
-
expect(() => render(<Harness />)).not.toThrow();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('also mirrors --sv-shell-header-height onto --sv-dialog-inset-top on :root', () => {
|
|
84
|
-
const shell = document.createElement('div');
|
|
85
|
-
shell.id = 'sv-app-shell';
|
|
86
|
-
document.body.appendChild(shell);
|
|
87
|
-
stubHeight(69);
|
|
88
|
-
|
|
89
|
-
render(<HeaderHarness />);
|
|
90
|
-
|
|
91
|
-
expect(shell.style.getPropertyValue('--sv-shell-header-height')).toBe('69px');
|
|
92
|
-
expect(document.documentElement.style.getPropertyValue('--sv-dialog-inset-top')).toBe('69px');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('removes --sv-dialog-inset-top from :root on unmount', () => {
|
|
96
|
-
const shell = document.createElement('div');
|
|
97
|
-
shell.id = 'sv-app-shell';
|
|
98
|
-
document.body.appendChild(shell);
|
|
99
|
-
stubHeight(69);
|
|
100
|
-
|
|
101
|
-
const { unmount } = render(<HeaderHarness />);
|
|
102
|
-
expect(document.documentElement.style.getPropertyValue('--sv-dialog-inset-top')).toBe('69px');
|
|
103
|
-
|
|
104
|
-
unmount();
|
|
105
|
-
expect(document.documentElement.style.getPropertyValue('--sv-dialog-inset-top')).toBe('');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('never touches --sv-dialog-inset-top for the footer variable', () => {
|
|
109
|
-
const shell = document.createElement('div');
|
|
110
|
-
shell.id = 'sv-app-shell';
|
|
111
|
-
document.body.appendChild(shell);
|
|
112
|
-
stubHeight(50);
|
|
113
|
-
|
|
114
|
-
render(<Harness />);
|
|
115
|
-
|
|
116
|
-
expect(document.documentElement.style.getPropertyValue('--sv-dialog-inset-top')).toBe('');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { shouldHandleDndEvent } from '../useReorderSensors';
|
|
4
|
-
|
|
5
|
-
describe('shouldHandleDndEvent', () => {
|
|
6
|
-
it('refuses an element nested inside a data-no-dnd ancestor', () => {
|
|
7
|
-
const wrapper = document.createElement('div');
|
|
8
|
-
wrapper.setAttribute('data-no-dnd', '');
|
|
9
|
-
const child = document.createElement('button');
|
|
10
|
-
wrapper.appendChild(child);
|
|
11
|
-
document.body.appendChild(wrapper);
|
|
12
|
-
|
|
13
|
-
expect(shouldHandleDndEvent(child)).toBe(false);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('allows an element with no data-no-dnd ancestor', () => {
|
|
17
|
-
const el = document.createElement('div');
|
|
18
|
-
document.body.appendChild(el);
|
|
19
|
-
|
|
20
|
-
expect(shouldHandleDndEvent(el)).toBe(true);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('allows a non-Element target', () => {
|
|
24
|
-
expect(shouldHandleDndEvent(null)).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, render } from '@testing-library/react';
|
|
4
|
-
import { useResponsiveLayout } from '../useResponsiveLayout';
|
|
5
|
-
|
|
6
|
-
// Same matchMedia mocking approach as useIsMobile.test.tsx, since this hook
|
|
7
|
-
// is a thin wrapper over it and must not diverge in SSR/breakpoint behavior.
|
|
8
|
-
let changeHandler: ((e: MediaQueryListEvent) => void) | null = null;
|
|
9
|
-
let matches = false;
|
|
10
|
-
let lastQuery = '';
|
|
11
|
-
|
|
12
|
-
function installMatchMedia() {
|
|
13
|
-
changeHandler = null;
|
|
14
|
-
vi.stubGlobal(
|
|
15
|
-
'matchMedia',
|
|
16
|
-
vi.fn().mockImplementation((query: string) => {
|
|
17
|
-
lastQuery = query;
|
|
18
|
-
return {
|
|
19
|
-
matches,
|
|
20
|
-
media: query,
|
|
21
|
-
addEventListener: (_: string, cb: (e: MediaQueryListEvent) => void) => {
|
|
22
|
-
changeHandler = cb;
|
|
23
|
-
},
|
|
24
|
-
removeEventListener: vi.fn(),
|
|
25
|
-
addListener: vi.fn(),
|
|
26
|
-
removeListener: vi.fn(),
|
|
27
|
-
dispatchEvent: vi.fn(),
|
|
28
|
-
};
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function Harness({ breakpointPx }: { breakpointPx?: number }) {
|
|
34
|
-
const { isMobile, value } = useResponsiveLayout({
|
|
35
|
-
web: 'web-tree',
|
|
36
|
-
mobile: 'mobile-tree',
|
|
37
|
-
breakpointPx,
|
|
38
|
-
});
|
|
39
|
-
return (
|
|
40
|
-
<span data-testid="out" data-is-mobile={String(isMobile)}>
|
|
41
|
-
{value}
|
|
42
|
-
</span>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
describe('useResponsiveLayout', () => {
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
matches = false;
|
|
49
|
-
installMatchMedia();
|
|
50
|
-
});
|
|
51
|
-
afterEach(() => {
|
|
52
|
-
vi.unstubAllGlobals();
|
|
53
|
-
cleanup();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('defaults to the web value before/without a mobile match (SSR-safe default)', () => {
|
|
57
|
-
matches = false;
|
|
58
|
-
installMatchMedia();
|
|
59
|
-
const { getByTestId } = render(<Harness />);
|
|
60
|
-
expect(getByTestId('out').textContent).toBe('web-tree');
|
|
61
|
-
expect(getByTestId('out').dataset.isMobile).toBe('false');
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('picks the mobile value once matchMedia reports a match', () => {
|
|
65
|
-
matches = true;
|
|
66
|
-
installMatchMedia();
|
|
67
|
-
const { getByTestId } = render(<Harness />);
|
|
68
|
-
expect(getByTestId('out').textContent).toBe('mobile-tree');
|
|
69
|
-
expect(getByTestId('out').dataset.isMobile).toBe('true');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('swaps live when the viewport crosses the breakpoint', () => {
|
|
73
|
-
matches = false;
|
|
74
|
-
installMatchMedia();
|
|
75
|
-
const { getByTestId } = render(<Harness />);
|
|
76
|
-
expect(getByTestId('out').textContent).toBe('web-tree');
|
|
77
|
-
act(() => changeHandler?.({ matches: true } as MediaQueryListEvent));
|
|
78
|
-
expect(getByTestId('out').textContent).toBe('mobile-tree');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('passes a custom breakpointPx straight through to useIsMobile', () => {
|
|
82
|
-
matches = false;
|
|
83
|
-
installMatchMedia();
|
|
84
|
-
render(<Harness breakpointPx={640} />);
|
|
85
|
-
expect(lastQuery).toBe('(max-width: 640px)');
|
|
86
|
-
});
|
|
87
|
-
});
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { act, cleanup, fireEvent, render } from '@testing-library/react';
|
|
4
|
-
import { useSnapCarousel, type UseSnapCarouselOptions } from '../useSnapCarousel';
|
|
5
|
-
|
|
6
|
-
// jsdom doesn't implement scrollTo on elements.
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
vi.useFakeTimers();
|
|
9
|
-
if (!Element.prototype.scrollTo) {
|
|
10
|
-
Element.prototype.scrollTo = vi.fn();
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
vi.runOnlyPendingTimers();
|
|
16
|
-
vi.useRealTimers();
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
function setLayout(el: HTMLElement, clientWidth: number, scrollLeft: number) {
|
|
21
|
-
Object.defineProperty(el, 'clientWidth', { value: clientWidth, configurable: true });
|
|
22
|
-
Object.defineProperty(el, 'scrollLeft', { value: scrollLeft, configurable: true });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function Harness(
|
|
26
|
-
props: UseSnapCarouselOptions & { onScrollTo?: (fn: (i: number) => void) => void },
|
|
27
|
-
) {
|
|
28
|
-
const { onScrollTo, ...options } = props;
|
|
29
|
-
const { scrollRef, scrollToIndex } = useSnapCarousel(options);
|
|
30
|
-
onScrollTo?.(scrollToIndex);
|
|
31
|
-
return <div data-testid="scroller" ref={scrollRef} />;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe('useSnapCarousel', () => {
|
|
35
|
-
it('calls onSettle with the new index after the debounce window', () => {
|
|
36
|
-
const onSettle = vi.fn();
|
|
37
|
-
const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
|
|
38
|
-
const el = getByTestId('scroller');
|
|
39
|
-
fireEvent.touchStart(el);
|
|
40
|
-
setLayout(el, 300, 300); // scrollLeft 300 / width 300 -> index 1
|
|
41
|
-
fireEvent.scroll(el);
|
|
42
|
-
expect(onSettle).not.toHaveBeenCalled();
|
|
43
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
44
|
-
expect(onSettle).toHaveBeenCalledWith(1);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('debounces repeated scroll events into a single settle call', () => {
|
|
48
|
-
const onSettle = vi.fn();
|
|
49
|
-
const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
|
|
50
|
-
const el = getByTestId('scroller');
|
|
51
|
-
fireEvent.touchStart(el);
|
|
52
|
-
setLayout(el, 300, 0);
|
|
53
|
-
fireEvent.scroll(el);
|
|
54
|
-
act(() => void vi.advanceTimersByTime(60));
|
|
55
|
-
setLayout(el, 300, 300);
|
|
56
|
-
fireEvent.scroll(el);
|
|
57
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
58
|
-
expect(onSettle).toHaveBeenCalledOnce();
|
|
59
|
-
expect(onSettle).toHaveBeenCalledWith(1);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('does not call onSettle again for the same index', () => {
|
|
63
|
-
const onSettle = vi.fn();
|
|
64
|
-
const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
|
|
65
|
-
const el = getByTestId('scroller');
|
|
66
|
-
fireEvent.touchStart(el);
|
|
67
|
-
setLayout(el, 300, 300);
|
|
68
|
-
fireEvent.scroll(el);
|
|
69
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
70
|
-
fireEvent.touchStart(el);
|
|
71
|
-
fireEvent.scroll(el);
|
|
72
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
73
|
-
expect(onSettle).toHaveBeenCalledOnce();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('clamps the settled index within [0, itemCount - 1]', () => {
|
|
77
|
-
const onSettle = vi.fn();
|
|
78
|
-
const { getByTestId } = render(<Harness itemCount={2} onSettle={onSettle} debounceMs={120} />);
|
|
79
|
-
const el = getByTestId('scroller');
|
|
80
|
-
fireEvent.touchStart(el);
|
|
81
|
-
setLayout(el, 300, 900); // rounds to index 3, clamps to itemCount - 1 = 1
|
|
82
|
-
fireEvent.scroll(el);
|
|
83
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
84
|
-
expect(onSettle).toHaveBeenCalledWith(1);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('ignores a scroll event with no active gesture (drift, not a settle)', () => {
|
|
88
|
-
// Regression test: reproduced live via a user screen recording — a
|
|
89
|
-
// slide's content changing size while still loading can nudge
|
|
90
|
-
// scrollLeft enough to round to a different index. Previously any such
|
|
91
|
-
// stray `scroll` event was enough to fire a second, contradicting
|
|
92
|
-
// onSettle, silently "auto-swiping" the carousel back to the wrong
|
|
93
|
-
// slide with no further touch input.
|
|
94
|
-
const onSettle = vi.fn();
|
|
95
|
-
const { getByTestId } = render(<Harness itemCount={10} onSettle={onSettle} debounceMs={120} />);
|
|
96
|
-
const el = getByTestId('scroller');
|
|
97
|
-
fireEvent.touchStart(el);
|
|
98
|
-
setLayout(el, 300, 1800); // settles cleanly on index 6
|
|
99
|
-
fireEvent.scroll(el);
|
|
100
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
101
|
-
expect(onSettle).toHaveBeenCalledExactlyOnceWith(6);
|
|
102
|
-
|
|
103
|
-
// Well outside the grace window and no further touch/wheel/pointer
|
|
104
|
-
// activity — this scroll event is drift, not a resettle.
|
|
105
|
-
act(() => void vi.advanceTimersByTime(1000));
|
|
106
|
-
setLayout(el, 300, 1620); // would round to index 5
|
|
107
|
-
fireEvent.scroll(el);
|
|
108
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
109
|
-
expect(onSettle).toHaveBeenCalledExactlyOnceWith(6);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('still settles on long-running momentum/snap-correction scroll with no further touch input', () => {
|
|
113
|
-
// Regression test for a bug in the FIRST version of the drift fix above:
|
|
114
|
-
// gating on "was there a touch/wheel/pointer event within a fixed
|
|
115
|
-
// debounceMs * 2 slack of settle-check time" dropped real settles once
|
|
116
|
-
// native momentum/snap-correction ran longer than that slack — which it
|
|
117
|
-
// routinely does for a fast flick. That left activeIndex stuck on the
|
|
118
|
-
// old slide while the container had already scrolled to the new one,
|
|
119
|
-
// and since the mount window is keyed off activeIndex, the slide the
|
|
120
|
-
// user was actually looking at could get unmounted — a blank carousel,
|
|
121
|
-
// worse than the bug being fixed. The chain stays trusted for as long as
|
|
122
|
-
// scroll events keep arriving without a debounceMs-or-longer gap,
|
|
123
|
-
// regardless of how long that run lasts or how few touch events back it.
|
|
124
|
-
const onSettle = vi.fn();
|
|
125
|
-
const { getByTestId } = render(<Harness itemCount={10} onSettle={onSettle} debounceMs={120} />);
|
|
126
|
-
const el = getByTestId('scroller');
|
|
127
|
-
fireEvent.touchStart(el);
|
|
128
|
-
setLayout(el, 300, 1700);
|
|
129
|
-
fireEvent.scroll(el); // starts the run — trusted (touchstart just happened)
|
|
130
|
-
fireEvent.touchEnd(el);
|
|
131
|
-
// Momentum keeps producing scroll events, each within debounceMs of the
|
|
132
|
-
// last (so the run never goes quiet), for far longer than any fixed
|
|
133
|
-
// slack window would tolerate — no further touch input at all.
|
|
134
|
-
for (const scrollLeft of [1720, 1740, 1760, 1780, 1800]) {
|
|
135
|
-
act(() => void vi.advanceTimersByTime(80));
|
|
136
|
-
setLayout(el, 300, scrollLeft);
|
|
137
|
-
fireEvent.scroll(el);
|
|
138
|
-
}
|
|
139
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
140
|
-
expect(onSettle).toHaveBeenCalledExactlyOnceWith(6);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('settles correctly on two independent real swipes fired back-to-back', () => {
|
|
144
|
-
// Regression test: two genuine swipes with essentially no gap between
|
|
145
|
-
// them (an impatient fast double-swipe) must not corrupt or drop either
|
|
146
|
-
// settle — each is its own trusted run.
|
|
147
|
-
const onSettle = vi.fn();
|
|
148
|
-
const { getByTestId } = render(<Harness itemCount={10} onSettle={onSettle} debounceMs={120} />);
|
|
149
|
-
const el = getByTestId('scroller');
|
|
150
|
-
fireEvent.touchStart(el);
|
|
151
|
-
setLayout(el, 300, 300);
|
|
152
|
-
fireEvent.scroll(el);
|
|
153
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
154
|
-
expect(onSettle).toHaveBeenCalledExactlyOnceWith(1);
|
|
155
|
-
|
|
156
|
-
fireEvent.touchStart(el);
|
|
157
|
-
setLayout(el, 300, 600);
|
|
158
|
-
fireEvent.scroll(el);
|
|
159
|
-
act(() => void vi.advanceTimersByTime(120));
|
|
160
|
-
expect(onSettle).toHaveBeenCalledTimes(2);
|
|
161
|
-
expect(onSettle).toHaveBeenLastCalledWith(2);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('scrollToIndex scrolls the container to the target slide', () => {
|
|
165
|
-
let scrollToIndex: ((index: number) => void) | undefined;
|
|
166
|
-
const { getByTestId } = render(
|
|
167
|
-
<Harness itemCount={3} onScrollTo={(fn) => (scrollToIndex = fn)} />,
|
|
168
|
-
);
|
|
169
|
-
const el = getByTestId('scroller');
|
|
170
|
-
setLayout(el, 400, 0);
|
|
171
|
-
const spy = vi.spyOn(el, 'scrollTo');
|
|
172
|
-
scrollToIndex?.(2);
|
|
173
|
-
expect(spy).toHaveBeenCalledWith({ left: 800, behavior: 'smooth' });
|
|
174
|
-
});
|
|
175
|
-
});
|