@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,110 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, fireEvent, render } from '@testing-library/react';
|
|
4
|
-
import { useSwipeReveal, type UseSwipeRevealOptions } from '../useSwipeReveal';
|
|
5
|
-
|
|
6
|
-
// jsdom doesn't implement pointer capture — stub it as a no-op so
|
|
7
|
-
// `e.currentTarget.setPointerCapture(...)` doesn't throw.
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
if (!HTMLElement.prototype.setPointerCapture) {
|
|
10
|
-
HTMLElement.prototype.setPointerCapture = vi.fn();
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
afterEach(cleanup);
|
|
15
|
-
|
|
16
|
-
function Harness(props: UseSwipeRevealOptions) {
|
|
17
|
-
const { rowRef, handlers } = useSwipeReveal(props);
|
|
18
|
-
return (
|
|
19
|
-
<div data-testid="row" ref={rowRef} {...handlers}>
|
|
20
|
-
row
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function pointer(x: number, y: number) {
|
|
26
|
-
return { clientX: x, clientY: y, pointerId: 1 };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe('useSwipeReveal', () => {
|
|
30
|
-
it('calls onOpen when a horizontal drag crosses the halfway point', () => {
|
|
31
|
-
const onOpen = vi.fn();
|
|
32
|
-
const onClose = vi.fn();
|
|
33
|
-
const { getByTestId } = render(
|
|
34
|
-
<Harness revealWidth={100} open={false} onOpen={onOpen} onClose={onClose} />,
|
|
35
|
-
);
|
|
36
|
-
const el = getByTestId('row');
|
|
37
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
38
|
-
fireEvent.pointerMove(el, pointer(-60, 0));
|
|
39
|
-
fireEvent.pointerUp(el, pointer(-60, 0));
|
|
40
|
-
expect(onOpen).toHaveBeenCalledOnce();
|
|
41
|
-
expect(onClose).not.toHaveBeenCalled();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('calls onClose when the drag does not cross the halfway point', () => {
|
|
45
|
-
const onOpen = vi.fn();
|
|
46
|
-
const onClose = vi.fn();
|
|
47
|
-
const { getByTestId } = render(
|
|
48
|
-
<Harness revealWidth={100} open={false} onOpen={onOpen} onClose={onClose} />,
|
|
49
|
-
);
|
|
50
|
-
const el = getByTestId('row');
|
|
51
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
52
|
-
fireEvent.pointerMove(el, pointer(-20, 0));
|
|
53
|
-
fireEvent.pointerUp(el, pointer(-20, 0));
|
|
54
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
55
|
-
expect(onOpen).not.toHaveBeenCalled();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('locks to vertical and ignores a mostly-vertical drag', () => {
|
|
59
|
-
const onOpen = vi.fn();
|
|
60
|
-
const onClose = vi.fn();
|
|
61
|
-
const { getByTestId } = render(
|
|
62
|
-
<Harness revealWidth={100} open={false} onOpen={onOpen} onClose={onClose} />,
|
|
63
|
-
);
|
|
64
|
-
const el = getByTestId('row');
|
|
65
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
66
|
-
fireEvent.pointerMove(el, pointer(2, 60));
|
|
67
|
-
fireEvent.pointerUp(el, pointer(2, 60));
|
|
68
|
-
expect(onOpen).not.toHaveBeenCalled();
|
|
69
|
-
expect(onClose).not.toHaveBeenCalled();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('does nothing when disabled', () => {
|
|
73
|
-
const onOpen = vi.fn();
|
|
74
|
-
const onClose = vi.fn();
|
|
75
|
-
const { getByTestId } = render(
|
|
76
|
-
<Harness revealWidth={100} open={false} onOpen={onOpen} onClose={onClose} disabled />,
|
|
77
|
-
);
|
|
78
|
-
const el = getByTestId('row');
|
|
79
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
80
|
-
fireEvent.pointerMove(el, pointer(-60, 0));
|
|
81
|
-
fireEvent.pointerUp(el, pointer(-60, 0));
|
|
82
|
-
expect(onOpen).not.toHaveBeenCalled();
|
|
83
|
-
expect(onClose).not.toHaveBeenCalled();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('closes from an already-open state when dragged back past halfway', () => {
|
|
87
|
-
const onOpen = vi.fn();
|
|
88
|
-
const onClose = vi.fn();
|
|
89
|
-
const { getByTestId } = render(
|
|
90
|
-
<Harness revealWidth={100} open onOpen={onOpen} onClose={onClose} />,
|
|
91
|
-
);
|
|
92
|
-
const el = getByTestId('row');
|
|
93
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
94
|
-
fireEvent.pointerMove(el, pointer(60, 0));
|
|
95
|
-
fireEvent.pointerUp(el, pointer(60, 0));
|
|
96
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
97
|
-
expect(onOpen).not.toHaveBeenCalled();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('ignores pointerup without a preceding pointerdown', () => {
|
|
101
|
-
const onOpen = vi.fn();
|
|
102
|
-
const onClose = vi.fn();
|
|
103
|
-
const { getByTestId } = render(
|
|
104
|
-
<Harness revealWidth={100} open={false} onOpen={onOpen} onClose={onClose} />,
|
|
105
|
-
);
|
|
106
|
-
fireEvent.pointerUp(getByTestId('row'), pointer(-60, 0));
|
|
107
|
-
expect(onOpen).not.toHaveBeenCalled();
|
|
108
|
-
expect(onClose).not.toHaveBeenCalled();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, fireEvent, render } from '@testing-library/react';
|
|
4
|
-
import { useSwipeStack, type SwipeDirection, type UseSwipeStackOptions } from '../useSwipeStack';
|
|
5
|
-
|
|
6
|
-
// jsdom doesn't implement pointer capture — stub it as a no-op so
|
|
7
|
-
// `e.currentTarget.setPointerCapture(...)` doesn't throw.
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
if (!HTMLElement.prototype.setPointerCapture) {
|
|
10
|
-
HTMLElement.prototype.setPointerCapture = vi.fn();
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
afterEach(cleanup);
|
|
15
|
-
|
|
16
|
-
function Harness(props: UseSwipeStackOptions & { triggerDirection?: SwipeDirection }) {
|
|
17
|
-
const { triggerDirection, ...options } = props;
|
|
18
|
-
const { cardRef, wrapRef, handlers, touchAction, triggerCommit } = useSwipeStack(options);
|
|
19
|
-
return (
|
|
20
|
-
<div data-testid="wrap" ref={wrapRef}>
|
|
21
|
-
<div data-testid="card" ref={cardRef} data-touch-action={touchAction} {...handlers}>
|
|
22
|
-
card
|
|
23
|
-
</div>
|
|
24
|
-
{triggerDirection && (
|
|
25
|
-
<button data-testid="trigger" onClick={() => triggerCommit(triggerDirection)}>
|
|
26
|
-
trigger
|
|
27
|
-
</button>
|
|
28
|
-
)}
|
|
29
|
-
</div>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function pointer(x: number, y: number) {
|
|
34
|
-
return { clientX: x, clientY: y, pointerId: 1 };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function drag(el: HTMLElement, dx: number, dy: number) {
|
|
38
|
-
fireEvent.pointerDown(el, pointer(0, 0));
|
|
39
|
-
fireEvent.pointerMove(el, pointer(dx, dy));
|
|
40
|
-
fireEvent.pointerUp(el, pointer(dx, dy));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
describe('useSwipeStack', () => {
|
|
44
|
-
it('commits when a drag crosses threshold in a live direction', () => {
|
|
45
|
-
const onCommit = vi.fn();
|
|
46
|
-
const { getByTestId } = render(
|
|
47
|
-
<Harness directions={['up', 'down', 'left', 'right']} threshold={100} onCommit={onCommit} />,
|
|
48
|
-
);
|
|
49
|
-
drag(getByTestId('card'), 0, -120);
|
|
50
|
-
expect(onCommit).toHaveBeenCalledWith('up');
|
|
51
|
-
expect(onCommit).toHaveBeenCalledOnce();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('springs back without committing when under threshold', () => {
|
|
55
|
-
const onCommit = vi.fn();
|
|
56
|
-
const { getByTestId } = render(
|
|
57
|
-
<Harness directions={['up', 'down', 'left', 'right']} threshold={100} onCommit={onCommit} />,
|
|
58
|
-
);
|
|
59
|
-
drag(getByTestId('card'), 0, -40);
|
|
60
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('does not commit within the deadzone even if threshold is set very low', () => {
|
|
64
|
-
const onCommit = vi.fn();
|
|
65
|
-
const { getByTestId } = render(
|
|
66
|
-
<Harness directions={['up']} threshold={2} onCommit={onCommit} />,
|
|
67
|
-
);
|
|
68
|
-
drag(getByTestId('card'), 0, -5);
|
|
69
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('treats a non-configured direction as a wall — no commit even past what would be threshold distance', () => {
|
|
73
|
-
const onCommit = vi.fn();
|
|
74
|
-
const { getByTestId } = render(
|
|
75
|
-
<Harness directions={['up', 'down']} threshold={100} onCommit={onCommit} />,
|
|
76
|
-
);
|
|
77
|
-
drag(getByTestId('card'), 150, 0);
|
|
78
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('does nothing when disabled', () => {
|
|
82
|
-
const onCommit = vi.fn();
|
|
83
|
-
const { getByTestId } = render(
|
|
84
|
-
<Harness
|
|
85
|
-
directions={['up', 'down', 'left', 'right']}
|
|
86
|
-
threshold={100}
|
|
87
|
-
onCommit={onCommit}
|
|
88
|
-
disabled
|
|
89
|
-
/>,
|
|
90
|
-
);
|
|
91
|
-
drag(getByTestId('card'), 0, -150);
|
|
92
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('ignores pointerup without a preceding pointerdown', () => {
|
|
96
|
-
const onCommit = vi.fn();
|
|
97
|
-
const { getByTestId } = render(
|
|
98
|
-
<Harness directions={['up', 'down', 'left', 'right']} threshold={100} onCommit={onCommit} />,
|
|
99
|
-
);
|
|
100
|
-
fireEvent.pointerUp(getByTestId('card'), pointer(0, -150));
|
|
101
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('triggerCommit commits a live direction without a drag', () => {
|
|
105
|
-
const onCommit = vi.fn();
|
|
106
|
-
const { getByTestId } = render(
|
|
107
|
-
<Harness directions={['up']} onCommit={onCommit} triggerDirection="up" />,
|
|
108
|
-
);
|
|
109
|
-
fireEvent.click(getByTestId('trigger'));
|
|
110
|
-
expect(onCommit).toHaveBeenCalledWith('up');
|
|
111
|
-
expect(onCommit).toHaveBeenCalledOnce();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('triggerCommit no-ops for a direction that is not live', () => {
|
|
115
|
-
const onCommit = vi.fn();
|
|
116
|
-
const { getByTestId } = render(
|
|
117
|
-
<Harness directions={['up']} onCommit={onCommit} triggerDirection="down" />,
|
|
118
|
-
);
|
|
119
|
-
fireEvent.click(getByTestId('trigger'));
|
|
120
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('triggerCommit does nothing when disabled', () => {
|
|
124
|
-
const onCommit = vi.fn();
|
|
125
|
-
const { getByTestId } = render(
|
|
126
|
-
<Harness directions={['up']} onCommit={onCommit} triggerDirection="up" disabled />,
|
|
127
|
-
);
|
|
128
|
-
fireEvent.click(getByTestId('trigger'));
|
|
129
|
-
expect(onCommit).not.toHaveBeenCalled();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('touchAction', () => {
|
|
133
|
-
it('is none when both axes have a live direction', () => {
|
|
134
|
-
const { getByTestId } = render(
|
|
135
|
-
<Harness directions={['left', 'right', 'up', 'down']} onCommit={vi.fn()} />,
|
|
136
|
-
);
|
|
137
|
-
expect(getByTestId('card').dataset.touchAction).toBe('none');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('is pan-y when only horizontal directions are live', () => {
|
|
141
|
-
const { getByTestId } = render(<Harness directions={['left', 'right']} onCommit={vi.fn()} />);
|
|
142
|
-
expect(getByTestId('card').dataset.touchAction).toBe('pan-y');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('is pan-x when only vertical directions are live', () => {
|
|
146
|
-
const { getByTestId } = render(<Harness directions={['up', 'down']} onCommit={vi.fn()} />);
|
|
147
|
-
expect(getByTestId('card').dataset.touchAction).toBe('pan-x');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('is auto when no directions are live', () => {
|
|
151
|
-
const { getByTestId } = render(<Harness directions={[]} onCommit={vi.fn()} />);
|
|
152
|
-
expect(getByTestId('card').dataset.touchAction).toBe('auto');
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
});
|
package/src/hooks/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export { useLongPress } from './useLongPress';
|
|
2
|
-
export type { UseLongPressOptions, LongPressHandlers } from './useLongPress';
|
|
3
|
-
export { useDoubleTapHandler, useSingleOrDoubleTap } from './useDoubleTap';
|
|
4
|
-
export { useIsMobile, MOBILE_BREAKPOINT_PX } from './useIsMobile';
|
|
5
|
-
export { useIsOffline } from './useIsOffline';
|
|
6
|
-
export { useOfflineTileState } from './useOfflineTileState';
|
|
7
|
-
export type { OfflineTileState } from './useOfflineTileState';
|
|
8
|
-
export { useCommitOnEnterOrBlur } from './useCommitOnEnterOrBlur';
|
|
9
|
-
export type { CommitOnEnterOrBlurHandlers } from './useCommitOnEnterOrBlur';
|
|
10
|
-
export { useSwipeReveal } from './useSwipeReveal';
|
|
11
|
-
export type {
|
|
12
|
-
UseSwipeRevealOptions,
|
|
13
|
-
UseSwipeRevealHandlers,
|
|
14
|
-
UseSwipeRevealResult,
|
|
15
|
-
} from './useSwipeReveal';
|
|
16
|
-
export { useSnapCarousel } from './useSnapCarousel';
|
|
17
|
-
export type { UseSnapCarouselOptions, UseSnapCarouselResult } from './useSnapCarousel';
|
|
18
|
-
export { useResponsiveLayout } from './useResponsiveLayout';
|
|
19
|
-
export type { UseResponsiveLayoutOptions, UseResponsiveLayoutResult } from './useResponsiveLayout';
|
|
20
|
-
export { useCarouselRouteSync } from './useCarouselRouteSync';
|
|
21
|
-
export type {
|
|
22
|
-
UseCarouselRouteSyncOptions,
|
|
23
|
-
UseCarouselRouteSyncResult,
|
|
24
|
-
} from './useCarouselRouteSync';
|
|
25
|
-
export { useReorderSensors, shouldHandleDndEvent } from './useReorderSensors';
|
|
26
|
-
export type { UseReorderSensorsOptions } from './useReorderSensors';
|
|
27
|
-
export { useSwipeStack, SWIPE_STACK_TRANSITION_MS } from './useSwipeStack';
|
|
28
|
-
export type {
|
|
29
|
-
SwipeDirection,
|
|
30
|
-
UseSwipeStackOptions,
|
|
31
|
-
UseSwipeStackHandlers,
|
|
32
|
-
UseSwipeStackResult,
|
|
33
|
-
} from './useSwipeStack';
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
|
4
|
-
|
|
5
|
-
export interface UseCarouselRouteSyncOptions {
|
|
6
|
-
/** Maps the current pathname to a slide index — the caller's own routing
|
|
7
|
-
* logic (e.g. special-casing a virtual "starred" slide), unchanged from
|
|
8
|
-
* whatever a plugin already has today. This hook has no idea what a
|
|
9
|
-
* plugin's routes look like, by design — it never imports a router. */
|
|
10
|
-
indexForPathname: (pathname: string) => number;
|
|
11
|
-
/** Inverse mapping — given a settled slide index, the path to navigate to. */
|
|
12
|
-
pathForIndex: (index: number) => string;
|
|
13
|
-
/** The current pathname. The caller reads this via their own router (e.g.
|
|
14
|
-
* `usePathname()` from `next/navigation`) and passes it in every render —
|
|
15
|
-
* this package stays framework-generic and has zero runtime dependencies. */
|
|
16
|
-
pathname: string;
|
|
17
|
-
/** Called when this hook wants to navigate — typically
|
|
18
|
-
* `(path) => router.replace(path, { scroll: false })`. */
|
|
19
|
-
onNavigate: (path: string) => void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface UseCarouselRouteSyncResult {
|
|
23
|
-
/** Feed directly into SwipableMobileCarousel's `activeIndex` prop. */
|
|
24
|
-
activeIndex: number;
|
|
25
|
-
/** Feed directly into SwipableMobileCarousel's `onSettle` prop. */
|
|
26
|
-
onSettle: (index: number) => void;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* useCarouselRouteSync — centralizes the pathname↔slide-index mapping and the
|
|
31
|
-
* "was this pathname change our own settle, or an external navigation"
|
|
32
|
-
* distinction that carousel-driving plugins otherwise hand-roll per plugin
|
|
33
|
-
* (a tapped `<Link>`, browser back/forward, vs. this hook's own
|
|
34
|
-
* `router.replace` after a swipe settles). Router-agnostic on purpose: the
|
|
35
|
-
* caller owns the actual `usePathname()`/`router.replace()` calls and only
|
|
36
|
-
* hands this hook plain values/callbacks.
|
|
37
|
-
*
|
|
38
|
-
* Deliberately does not own neighbor-prefetch (SwipableMobileCarousel's
|
|
39
|
-
* `prefetchDistance`/mount-window covers that) or scroll mechanics (the
|
|
40
|
-
* carousel component reacts to `activeIndex` changes itself) — this hook is
|
|
41
|
-
* pathname↔index mapping only, keeping routing glue decoupled from
|
|
42
|
-
* data-fetching and DOM scrolling.
|
|
43
|
-
*/
|
|
44
|
-
export function useCarouselRouteSync({
|
|
45
|
-
indexForPathname,
|
|
46
|
-
pathForIndex,
|
|
47
|
-
pathname,
|
|
48
|
-
onNavigate,
|
|
49
|
-
}: UseCarouselRouteSyncOptions): UseCarouselRouteSyncResult {
|
|
50
|
-
// Kept in refs and refreshed every render (not effect deps) so an inline
|
|
51
|
-
// arrow function passed by the caller each render doesn't retrigger the
|
|
52
|
-
// pathname-sync effect below — only an actual pathname change should.
|
|
53
|
-
const indexForPathnameRef = useRef(indexForPathname);
|
|
54
|
-
indexForPathnameRef.current = indexForPathname;
|
|
55
|
-
const pathForIndexRef = useRef(pathForIndex);
|
|
56
|
-
pathForIndexRef.current = pathForIndex;
|
|
57
|
-
const onNavigateRef = useRef(onNavigate);
|
|
58
|
-
onNavigateRef.current = onNavigate;
|
|
59
|
-
|
|
60
|
-
const [activeIndex, setActiveIndex] = useState(() => indexForPathname(pathname));
|
|
61
|
-
// Set synchronously inside onSettle, right before this hook's own
|
|
62
|
-
// navigation call — lets the pathname-sync effect below tell "this
|
|
63
|
-
// pathname change is our own settle, already reflected in activeIndex"
|
|
64
|
-
// apart from a genuinely external navigation.
|
|
65
|
-
const isInternalNavRef = useRef(false);
|
|
66
|
-
const didMountRef = useRef(false);
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (!didMountRef.current) {
|
|
70
|
-
// The very first render's activeIndex already reflects pathname via
|
|
71
|
-
// the lazy useState initializer above — nothing to resync on mount.
|
|
72
|
-
didMountRef.current = true;
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (isInternalNavRef.current) {
|
|
76
|
-
isInternalNavRef.current = false;
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const newIndex = indexForPathnameRef.current(pathname);
|
|
80
|
-
setActiveIndex((current) => (newIndex === current ? current : newIndex));
|
|
81
|
-
// Only re-run when pathname itself changes — indexForPathname is read
|
|
82
|
-
// through a ref precisely so its identity doesn't matter here.
|
|
83
|
-
}, [pathname]);
|
|
84
|
-
|
|
85
|
-
function onSettle(index: number) {
|
|
86
|
-
isInternalNavRef.current = true;
|
|
87
|
-
setActiveIndex(index);
|
|
88
|
-
onNavigateRef.current(pathForIndexRef.current(index));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return { activeIndex, onSettle };
|
|
92
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import type { KeyboardEvent } from 'react';
|
|
4
|
-
|
|
5
|
-
export interface CommitOnEnterOrBlurHandlers {
|
|
6
|
-
onKeyDown: (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
7
|
-
onBlur: () => void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* useCommitOnEnterOrBlur — spreads onto a quick-entry input/textarea so
|
|
12
|
-
* Enter and losing focus both commit through the same callback.
|
|
13
|
-
*
|
|
14
|
-
* iOS Safari adds its own "Previous / Next / Done" toolbar above the
|
|
15
|
-
* software keyboard whenever more than one focusable field is nearby (a
|
|
16
|
-
* Sheet with several fields, a form, etc.) — there is no supported way to
|
|
17
|
-
* suppress it, since it's WebKit's own field-detection heuristic, not
|
|
18
|
-
* something the page controls. Tapping that toolbar's Done/checkmark only
|
|
19
|
-
* ever fires a native `blur`; it is not a form submit and dispatches no
|
|
20
|
-
* keydown, so a field that commits only on Enter silently discards whatever
|
|
21
|
-
* was typed the moment a user dismisses the keyboard that way instead of
|
|
22
|
-
* pressing the on-screen Return key — the two dismissal paths look
|
|
23
|
-
* identical to the user but produce different outcomes.
|
|
24
|
-
*
|
|
25
|
-
* `onCommit` is called unconditionally on both Enter and blur — it owns any
|
|
26
|
-
* empty-value no-op itself, matching how every call site's own commit
|
|
27
|
-
* function already guards against an empty value before doing anything.
|
|
28
|
-
* Callers needing more key handling (e.g. Escape-to-cancel) compose their
|
|
29
|
-
* own `onKeyDown` around the returned one rather than this hook growing
|
|
30
|
-
* options for every caller's own key bindings.
|
|
31
|
-
*/
|
|
32
|
-
export function useCommitOnEnterOrBlur(onCommit: () => void): CommitOnEnterOrBlurHandlers {
|
|
33
|
-
return {
|
|
34
|
-
onKeyDown: (e) => {
|
|
35
|
-
if (e.key === 'Enter') onCommit();
|
|
36
|
-
},
|
|
37
|
-
onBlur: onCommit,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useRef } from 'react';
|
|
4
|
-
|
|
5
|
-
// Real double-clicks (desktop mouse) report e.detail === 2 natively — no extra
|
|
6
|
-
// work needed there. Touch-generated click events always report detail === 1
|
|
7
|
-
// (no browser synthesizes a dblclick-style count from two taps), so
|
|
8
|
-
// double-tap has to be detected by timing two clicks against each other
|
|
9
|
-
// instead. Sharing one implementation for both means every double-click-style
|
|
10
|
-
// affordance behaves the same way on mouse and touch without the caller
|
|
11
|
-
// duplicating the two code paths.
|
|
12
|
-
const DOUBLE_TAP_MS = 350;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* useDoubleTapHandler — fires `onDoubleTap` on a real double-click (desktop)
|
|
16
|
-
* or two taps within `DOUBLE_TAP_MS` (touch).
|
|
17
|
-
*
|
|
18
|
-
* Only safe when the *single* tap/click has no default action of its own to
|
|
19
|
-
* preempt — e.g. a colour swatch with nothing to cancel. If the single tap
|
|
20
|
-
* navigates, opens something, or otherwise does something a following double
|
|
21
|
-
* needs to be able to undo before it happens, use `useSingleOrDoubleTap`
|
|
22
|
-
* instead: this hook fires `onDoubleTap` only, leaving any single-tap handling
|
|
23
|
-
* to the caller's own `onClick`, which already ran immediately and can't be
|
|
24
|
-
* un-done here.
|
|
25
|
-
*
|
|
26
|
-
* The event is passed through to `onDoubleTap` rather than calling
|
|
27
|
-
* `preventDefault` internally — not every call site needs to cancel
|
|
28
|
-
* something, so the decision is left to the caller.
|
|
29
|
-
*/
|
|
30
|
-
export function useDoubleTapHandler<E extends { detail: number }>(
|
|
31
|
-
onDoubleTap: (e: E) => void,
|
|
32
|
-
): (e: E) => void {
|
|
33
|
-
const lastTime = useRef(0);
|
|
34
|
-
return (e: E) => {
|
|
35
|
-
if (e.detail === 2) {
|
|
36
|
-
onDoubleTap(e);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const now = Date.now();
|
|
40
|
-
if (now - lastTime.current < DOUBLE_TAP_MS) {
|
|
41
|
-
lastTime.current = 0;
|
|
42
|
-
onDoubleTap(e);
|
|
43
|
-
} else {
|
|
44
|
-
lastTime.current = now;
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* useSingleOrDoubleTap — for call sites where the single tap/click *does*
|
|
51
|
-
* have a default action (e.g. navigating) that a following double-tap must be
|
|
52
|
-
* able to preempt.
|
|
53
|
-
*
|
|
54
|
-
* A real double-click gets away with firing the single action immediately and
|
|
55
|
-
* only detecting the double afterward, because `e.detail === 2` is the
|
|
56
|
-
* browser's own resolved signal, arriving on the very click that matters. A
|
|
57
|
-
* touch double-tap has no equivalent "hold on, there might be a second one"
|
|
58
|
-
* signal — the only way to know is to wait out the window before committing
|
|
59
|
-
* to the single action, which is what this hook does: `onSingle` is deferred
|
|
60
|
-
* by `DOUBLE_TAP_MS` and only actually runs if no second tap arrives in that
|
|
61
|
-
* time. This means every single tap through this hook incurs that latency —
|
|
62
|
-
* only use it where a genuine double-tap gesture must be able to preempt the
|
|
63
|
-
* single action; `useDoubleTapHandler` above has no such delay.
|
|
64
|
-
*/
|
|
65
|
-
export function useSingleOrDoubleTap<E extends { detail: number }>(
|
|
66
|
-
onSingle: (e: E) => void,
|
|
67
|
-
onDouble: (e: E) => void,
|
|
68
|
-
): (e: E) => void {
|
|
69
|
-
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
70
|
-
|
|
71
|
-
return (e: E) => {
|
|
72
|
-
if (e.detail === 2) {
|
|
73
|
-
if (timer.current) {
|
|
74
|
-
clearTimeout(timer.current);
|
|
75
|
-
timer.current = null;
|
|
76
|
-
}
|
|
77
|
-
onDouble(e);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (timer.current) {
|
|
81
|
-
clearTimeout(timer.current);
|
|
82
|
-
timer.current = null;
|
|
83
|
-
onDouble(e);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
timer.current = setTimeout(() => {
|
|
87
|
-
timer.current = null;
|
|
88
|
-
onSingle(e);
|
|
89
|
-
}, DOUBLE_TAP_MS);
|
|
90
|
-
};
|
|
91
|
-
}
|
package/src/hooks/useIsMobile.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
|
|
5
|
-
// The platform's canonical mobile breakpoint — matches the shell chrome and
|
|
6
|
-
// Dialog's own full-screen-sheet switch (`runtime/app/globals.css`,
|
|
7
|
-
// `Dialog.module.css`). A plugin whose own layout genuinely needs a different
|
|
8
|
-
// threshold may still hardcode its own value (e.g. a three-column layout that
|
|
9
|
-
// only needs to fork earlier than 768px) — this constant is the *default* every
|
|
10
|
-
// consumer should reach for first, so the platform's idea of "mobile" doesn't
|
|
11
|
-
// silently drift across components again.
|
|
12
|
-
export const MOBILE_BREAKPOINT_PX = 768;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* useIsMobile — whether the viewport is at or below the platform's mobile
|
|
16
|
-
* breakpoint. SSR-safe: defaults to `false` (desktop) until the client mounts
|
|
17
|
-
* and reads the real viewport, avoiding a hydration mismatch on first paint.
|
|
18
|
-
*/
|
|
19
|
-
export function useIsMobile(breakpointPx: number = MOBILE_BREAKPOINT_PX): boolean {
|
|
20
|
-
const [isMobile, setIsMobile] = useState(false);
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
const mql = window.matchMedia(`(max-width: ${breakpointPx}px)`);
|
|
24
|
-
setIsMobile(mql.matches);
|
|
25
|
-
function handleChange(e: MediaQueryListEvent) {
|
|
26
|
-
setIsMobile(e.matches);
|
|
27
|
-
}
|
|
28
|
-
mql.addEventListener('change', handleChange);
|
|
29
|
-
return () => mql.removeEventListener('change', handleChange);
|
|
30
|
-
}, [breakpointPx]);
|
|
31
|
-
|
|
32
|
-
return isMobile;
|
|
33
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* useIsOffline — whether the browser currently has no network connection.
|
|
7
|
-
*
|
|
8
|
-
* SSR-safe: always initialises to `false` (online) so the server-rendered HTML
|
|
9
|
-
* matches the first client render, then reads the real `navigator.onLine`
|
|
10
|
-
* value in `useEffect`. This picks up the case where the page loaded already
|
|
11
|
-
* offline (e.g. served from the service-worker cache) at the cost of an
|
|
12
|
-
* imperceptible one-frame delay before the offline state appears — the same
|
|
13
|
-
* trade-off `OfflineBanner` makes, which this hook was extracted from so every
|
|
14
|
-
* consumer shares one connectivity source instead of re-deriving it slightly
|
|
15
|
-
* differently (research 0012, epic task 2.32).
|
|
16
|
-
*
|
|
17
|
-
* Reflects only `navigator.onLine` — true whenever the OS reports a network
|
|
18
|
-
* interface is up, even without real upstream connectivity (e.g. Wi-Fi with no
|
|
19
|
-
* internet). That is a known limitation of the browser API itself, not of this
|
|
20
|
-
* hook; there is currently no better cross-browser signal available.
|
|
21
|
-
*/
|
|
22
|
-
export function useIsOffline(): boolean {
|
|
23
|
-
const [isOffline, setIsOffline] = useState(false);
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
setIsOffline(!navigator.onLine);
|
|
27
|
-
|
|
28
|
-
const handleOffline = () => setIsOffline(true);
|
|
29
|
-
const handleOnline = () => setIsOffline(false);
|
|
30
|
-
|
|
31
|
-
window.addEventListener('offline', handleOffline);
|
|
32
|
-
window.addEventListener('online', handleOnline);
|
|
33
|
-
|
|
34
|
-
return () => {
|
|
35
|
-
window.removeEventListener('offline', handleOffline);
|
|
36
|
-
window.removeEventListener('online', handleOnline);
|
|
37
|
-
};
|
|
38
|
-
}, []);
|
|
39
|
-
|
|
40
|
-
return isOffline;
|
|
41
|
-
}
|