@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,144 +0,0 @@
|
|
|
1
|
-
import { useMemo, useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
-
import { SuggestionInput, type SuggestionOption } from './SuggestionInput';
|
|
4
|
-
|
|
5
|
-
const meta = {
|
|
6
|
-
title: 'Components/SuggestionInput',
|
|
7
|
-
component: SuggestionInput,
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: 'padded',
|
|
10
|
-
docs: {
|
|
11
|
-
description: {
|
|
12
|
-
component:
|
|
13
|
-
'A text field with an anchored, keyboard-navigable list of async suggestions, plus an optional trailing "create new" row so free text is always a valid commit.',
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
args: {
|
|
18
|
-
value: '',
|
|
19
|
-
onChange: () => {},
|
|
20
|
-
options: [],
|
|
21
|
-
onSelect: () => {},
|
|
22
|
-
'aria-label': 'Add an item',
|
|
23
|
-
},
|
|
24
|
-
} satisfies Meta<typeof SuggestionInput>;
|
|
25
|
-
|
|
26
|
-
export default meta;
|
|
27
|
-
type Story = StoryObj<typeof meta>;
|
|
28
|
-
|
|
29
|
-
const CATALOG: SuggestionOption[] = [
|
|
30
|
-
{ id: '1', label: 'Bananas', icon: '🍌', meta: 'bought 4× recently' },
|
|
31
|
-
{ id: '2', label: 'Banana bread mix', icon: '🍞' },
|
|
32
|
-
{ id: '3', label: 'Milk', icon: '🥛' },
|
|
33
|
-
{ id: '4', label: 'Eggs', icon: '🥚' },
|
|
34
|
-
{ id: '5', label: 'Olive oil', icon: '🫒' },
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
function ControlledSuggestionInput({ withCreateRow = true }: { withCreateRow?: boolean }) {
|
|
38
|
-
const [value, setValue] = useState('');
|
|
39
|
-
const [selected, setSelected] = useState<string | null>(null);
|
|
40
|
-
const options = useMemo(
|
|
41
|
-
() =>
|
|
42
|
-
value.trim()
|
|
43
|
-
? CATALOG.filter((c) => c.label.toLowerCase().includes(value.trim().toLowerCase()))
|
|
44
|
-
: [],
|
|
45
|
-
[value],
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<div style={{ width: 320 }}>
|
|
50
|
-
<SuggestionInput
|
|
51
|
-
value={value}
|
|
52
|
-
onChange={setValue}
|
|
53
|
-
options={options}
|
|
54
|
-
onSelect={(option) => {
|
|
55
|
-
setSelected(option.label);
|
|
56
|
-
setValue('');
|
|
57
|
-
}}
|
|
58
|
-
placeholder="Add an item…"
|
|
59
|
-
aria-label="Add an item"
|
|
60
|
-
createLabel={withCreateRow ? (v) => `Add "${v}" as a new item` : undefined}
|
|
61
|
-
onCreate={
|
|
62
|
-
withCreateRow
|
|
63
|
-
? (v) => {
|
|
64
|
-
setSelected(v);
|
|
65
|
-
setValue('');
|
|
66
|
-
}
|
|
67
|
-
: undefined
|
|
68
|
-
}
|
|
69
|
-
/>
|
|
70
|
-
{selected && <p style={{ marginTop: 12, fontSize: 13 }}>Added: {selected}</p>}
|
|
71
|
-
</div>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const Default: Story = {
|
|
76
|
-
render: () => <ControlledSuggestionInput />,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const NoCreateRow: Story = {
|
|
80
|
-
name: 'Without create row (matched options only)',
|
|
81
|
-
render: () => <ControlledSuggestionInput withCreateRow={false} />,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const OpenWithOptions: Story = {
|
|
85
|
-
render: () => (
|
|
86
|
-
<div style={{ width: 320 }}>
|
|
87
|
-
<SuggestionInput
|
|
88
|
-
value="ban"
|
|
89
|
-
onChange={() => {}}
|
|
90
|
-
options={CATALOG.slice(0, 2)}
|
|
91
|
-
onSelect={() => {}}
|
|
92
|
-
aria-label="Add an item"
|
|
93
|
-
createLabel={(v) => `Add "${v}" as a new item`}
|
|
94
|
-
onCreate={() => {}}
|
|
95
|
-
/>
|
|
96
|
-
</div>
|
|
97
|
-
),
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export const Loading: Story = {
|
|
101
|
-
render: () => (
|
|
102
|
-
<div style={{ width: 320 }}>
|
|
103
|
-
<SuggestionInput
|
|
104
|
-
value="ban"
|
|
105
|
-
onChange={() => {}}
|
|
106
|
-
options={[]}
|
|
107
|
-
onSelect={() => {}}
|
|
108
|
-
loading
|
|
109
|
-
aria-label="Add an item"
|
|
110
|
-
/>
|
|
111
|
-
</div>
|
|
112
|
-
),
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
export const Empty: Story = {
|
|
116
|
-
name: 'Empty (no matches, no create row)',
|
|
117
|
-
render: () => (
|
|
118
|
-
<div style={{ width: 320 }}>
|
|
119
|
-
<SuggestionInput
|
|
120
|
-
value="xyz"
|
|
121
|
-
onChange={() => {}}
|
|
122
|
-
options={[]}
|
|
123
|
-
onSelect={() => {}}
|
|
124
|
-
aria-label="Add an item"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
),
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export const Disabled: Story = {
|
|
131
|
-
render: () => (
|
|
132
|
-
<div style={{ width: 320 }}>
|
|
133
|
-
<SuggestionInput
|
|
134
|
-
value=""
|
|
135
|
-
onChange={() => {}}
|
|
136
|
-
options={[]}
|
|
137
|
-
onSelect={() => {}}
|
|
138
|
-
disabled
|
|
139
|
-
placeholder="Add an item…"
|
|
140
|
-
aria-label="Add an item"
|
|
141
|
-
/>
|
|
142
|
-
</div>
|
|
143
|
-
),
|
|
144
|
-
};
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useId, useRef, useState, type KeyboardEvent, type ReactNode } from 'react';
|
|
4
|
-
import { Popover } from '../Popover/Popover';
|
|
5
|
-
import styles from './SuggestionInput.module.css';
|
|
6
|
-
|
|
7
|
-
export interface SuggestionOption {
|
|
8
|
-
id: string;
|
|
9
|
-
label: string;
|
|
10
|
-
icon?: ReactNode;
|
|
11
|
-
/** Secondary text shown right-aligned on the row, e.g. "bought 4× recently". */
|
|
12
|
-
meta?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface SuggestionInputProps {
|
|
16
|
-
value: string;
|
|
17
|
-
onChange: (value: string) => void;
|
|
18
|
-
options: SuggestionOption[];
|
|
19
|
-
onSelect: (option: SuggestionOption) => void;
|
|
20
|
-
placeholder?: string;
|
|
21
|
-
'aria-label': string;
|
|
22
|
-
id?: string;
|
|
23
|
-
disabled?: boolean;
|
|
24
|
-
/** Shown in place of the options list while a suggestion fetch is in flight. */
|
|
25
|
-
loading?: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Label for a trailing, always-selectable row that commits the raw typed
|
|
28
|
-
* text instead of a matched option — e.g. `(v) => \`Add "${v}" as a new item\`}`.
|
|
29
|
-
* Shown whenever `value` is non-empty and `onCreate` is provided, even
|
|
30
|
-
* when `options` is empty, so the input is never a dead end.
|
|
31
|
-
*/
|
|
32
|
-
createLabel?: (value: string) => string;
|
|
33
|
-
onCreate?: (value: string) => void;
|
|
34
|
-
className?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* SuggestionInput — a text field with an anchored, keyboard-navigable list
|
|
39
|
-
* of async suggestions (a combobox), plus an optional trailing "create new"
|
|
40
|
-
* row so free text is always a valid commit, not just a matched option.
|
|
41
|
-
*
|
|
42
|
-
* Fully controlled: the caller owns `value`/`onChange` and supplies
|
|
43
|
-
* `options` (e.g. debounced server-fetched results) — this component only
|
|
44
|
-
* handles open/close, keyboard navigation, and selection. Built on `Popover`
|
|
45
|
-
* for positioning (`width: 'trigger'`, so the panel always matches the
|
|
46
|
-
* input's own width).
|
|
47
|
-
*/
|
|
48
|
-
export function SuggestionInput({
|
|
49
|
-
value,
|
|
50
|
-
onChange,
|
|
51
|
-
options,
|
|
52
|
-
onSelect,
|
|
53
|
-
placeholder,
|
|
54
|
-
'aria-label': ariaLabel,
|
|
55
|
-
id,
|
|
56
|
-
disabled = false,
|
|
57
|
-
loading = false,
|
|
58
|
-
createLabel,
|
|
59
|
-
onCreate,
|
|
60
|
-
className,
|
|
61
|
-
}: SuggestionInputProps) {
|
|
62
|
-
const generatedId = useId();
|
|
63
|
-
const inputId = id ?? generatedId;
|
|
64
|
-
const listId = `${inputId}-suggestions`;
|
|
65
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
66
|
-
const [focused, setFocused] = useState(false);
|
|
67
|
-
const [activeIndex, setActiveIndex] = useState(-1);
|
|
68
|
-
|
|
69
|
-
const showCreateRow = Boolean(onCreate && createLabel && value.trim());
|
|
70
|
-
const rowCount = options.length + (showCreateRow ? 1 : 0);
|
|
71
|
-
const open = focused && (rowCount > 0 || loading);
|
|
72
|
-
|
|
73
|
-
function close() {
|
|
74
|
-
setFocused(false);
|
|
75
|
-
setActiveIndex(-1);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function commitIndex(index: number) {
|
|
79
|
-
if (index < 0 || index >= rowCount) return;
|
|
80
|
-
const option = options[index];
|
|
81
|
-
if (option) {
|
|
82
|
-
onSelect(option);
|
|
83
|
-
} else if (onCreate) {
|
|
84
|
-
onCreate(value);
|
|
85
|
-
}
|
|
86
|
-
close();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function handleKeyDown(e: KeyboardEvent<HTMLInputElement>) {
|
|
90
|
-
if (!open) return;
|
|
91
|
-
// Some synthetic input sources (seen from automated/CDP-driven key
|
|
92
|
-
// dispatch) send a keydown with `key`/`code` as "Unidentified" or empty
|
|
93
|
-
// and no `keyCode` either — nothing here can special-case that further,
|
|
94
|
-
// but checking the legacy numeric code costs nothing and covers sources
|
|
95
|
-
// that do populate it even when `key` doesn't (older browsers, some
|
|
96
|
-
// assistive tech, IME edge cases).
|
|
97
|
-
const isArrowDown = e.key === 'ArrowDown' || e.keyCode === 40;
|
|
98
|
-
const isArrowUp = e.key === 'ArrowUp' || e.keyCode === 38;
|
|
99
|
-
const isEnter = e.key === 'Enter' || e.keyCode === 13;
|
|
100
|
-
const isEscape = e.key === 'Escape' || e.keyCode === 27;
|
|
101
|
-
|
|
102
|
-
if (isArrowDown) {
|
|
103
|
-
e.preventDefault();
|
|
104
|
-
setActiveIndex((i) => (i + 1) % rowCount);
|
|
105
|
-
} else if (isArrowUp) {
|
|
106
|
-
e.preventDefault();
|
|
107
|
-
setActiveIndex((i) => (i <= 0 ? rowCount - 1 : i - 1));
|
|
108
|
-
} else if (isEnter) {
|
|
109
|
-
e.preventDefault();
|
|
110
|
-
commitIndex(activeIndex === -1 ? 0 : activeIndex);
|
|
111
|
-
} else if (isEscape) {
|
|
112
|
-
close();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const trigger = (
|
|
117
|
-
<input
|
|
118
|
-
ref={inputRef}
|
|
119
|
-
id={inputId}
|
|
120
|
-
type="text"
|
|
121
|
-
role="combobox"
|
|
122
|
-
aria-expanded={open}
|
|
123
|
-
aria-controls={listId}
|
|
124
|
-
aria-autocomplete="list"
|
|
125
|
-
aria-activedescendant={activeIndex >= 0 ? `${listId}-option-${activeIndex}` : undefined}
|
|
126
|
-
aria-label={ariaLabel}
|
|
127
|
-
className={[styles.input, className].filter(Boolean).join(' ')}
|
|
128
|
-
value={value}
|
|
129
|
-
placeholder={placeholder}
|
|
130
|
-
disabled={disabled}
|
|
131
|
-
autoComplete="off"
|
|
132
|
-
onChange={(e) => {
|
|
133
|
-
onChange(e.target.value);
|
|
134
|
-
setActiveIndex(-1);
|
|
135
|
-
}}
|
|
136
|
-
onFocus={() => setFocused(true)}
|
|
137
|
-
onKeyDown={handleKeyDown}
|
|
138
|
-
/>
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
return (
|
|
142
|
-
<Popover
|
|
143
|
-
trigger={trigger}
|
|
144
|
-
open={open}
|
|
145
|
-
onClose={close}
|
|
146
|
-
width="trigger"
|
|
147
|
-
aria-label={`${ariaLabel} suggestions`}
|
|
148
|
-
>
|
|
149
|
-
<ul id={listId} role="listbox" className={styles.list}>
|
|
150
|
-
{loading ? (
|
|
151
|
-
<li className={styles.status}>Loading…</li>
|
|
152
|
-
) : (
|
|
153
|
-
<>
|
|
154
|
-
{options.map((option, index) => (
|
|
155
|
-
<li key={option.id} role="none">
|
|
156
|
-
<button
|
|
157
|
-
id={`${listId}-option-${index}`}
|
|
158
|
-
role="option"
|
|
159
|
-
aria-selected={index === activeIndex}
|
|
160
|
-
type="button"
|
|
161
|
-
className={[styles.option, index === activeIndex ? styles.optionActive : '']
|
|
162
|
-
.filter(Boolean)
|
|
163
|
-
.join(' ')}
|
|
164
|
-
// Selecting via mouse fires before the input's blur — use
|
|
165
|
-
// onMouseDown (not onClick) so the click doesn't lose focus
|
|
166
|
-
// and close the popover before the selection registers.
|
|
167
|
-
onMouseDown={(e) => {
|
|
168
|
-
e.preventDefault();
|
|
169
|
-
commitIndex(index);
|
|
170
|
-
}}
|
|
171
|
-
>
|
|
172
|
-
{option.icon && <span className={styles.optionIcon}>{option.icon}</span>}
|
|
173
|
-
<span className={styles.optionLabel}>{option.label}</span>
|
|
174
|
-
{option.meta && <span className={styles.optionMeta}>{option.meta}</span>}
|
|
175
|
-
</button>
|
|
176
|
-
</li>
|
|
177
|
-
))}
|
|
178
|
-
{showCreateRow && createLabel && (
|
|
179
|
-
<li role="none">
|
|
180
|
-
{options.length > 0 && <div className={styles.divider} />}
|
|
181
|
-
<button
|
|
182
|
-
id={`${listId}-option-${options.length}`}
|
|
183
|
-
role="option"
|
|
184
|
-
aria-selected={options.length === activeIndex}
|
|
185
|
-
type="button"
|
|
186
|
-
className={[
|
|
187
|
-
styles.option,
|
|
188
|
-
styles.optionCreate,
|
|
189
|
-
options.length === activeIndex ? styles.optionActive : '',
|
|
190
|
-
]
|
|
191
|
-
.filter(Boolean)
|
|
192
|
-
.join(' ')}
|
|
193
|
-
onMouseDown={(e) => {
|
|
194
|
-
e.preventDefault();
|
|
195
|
-
commitIndex(options.length);
|
|
196
|
-
}}
|
|
197
|
-
>
|
|
198
|
-
{createLabel(value)}
|
|
199
|
-
</button>
|
|
200
|
-
</li>
|
|
201
|
-
)}
|
|
202
|
-
</>
|
|
203
|
-
)}
|
|
204
|
-
</ul>
|
|
205
|
-
</Popover>
|
|
206
|
-
);
|
|
207
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
.wrap {
|
|
2
|
-
position: relative;
|
|
3
|
-
height: 100%;
|
|
4
|
-
width: 100%;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.scroller {
|
|
8
|
-
height: 100%;
|
|
9
|
-
width: 100%;
|
|
10
|
-
display: flex;
|
|
11
|
-
overflow-x: auto;
|
|
12
|
-
overflow-y: hidden;
|
|
13
|
-
scroll-snap-type: x mandatory;
|
|
14
|
-
/* Momentum + rubber-banding come from the browser's native scroll physics —
|
|
15
|
-
no hand-rolled pointer/touch dragging. Deliberately NOT
|
|
16
|
-
-webkit-overflow-scrolling: touch: that legacy iOS <13 hint promotes its
|
|
17
|
-
element to its own compositing layer for GPU-accelerated momentum
|
|
18
|
-
scroll, and that layer's paint order relative to siblings/fixed
|
|
19
|
-
descendants elsewhere in the tree isn't always reliable on real iOS
|
|
20
|
-
Safari (confirmed via sovereign-tasks' and sovereign-shopper's own
|
|
21
|
-
carousels, which hit and fixed this exact bug — a position:fixed
|
|
22
|
-
overlay opened above the scroller painted BEHIND it instead of above).
|
|
23
|
-
Removing it doesn't disable momentum scrolling on any iOS version this
|
|
24
|
-
platform realistically targets. */
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.slide {
|
|
28
|
-
flex: 0 0 100%;
|
|
29
|
-
width: 100%;
|
|
30
|
-
height: 100%;
|
|
31
|
-
min-width: 0;
|
|
32
|
-
overflow: hidden;
|
|
33
|
-
scroll-snap-align: start;
|
|
34
|
-
scroll-snap-stop: always;
|
|
35
|
-
/* Slide content is a flex column so Header/Footer stay their natural size
|
|
36
|
-
and Body (flex: 1 1 auto, min-height: 0) fills and scrolls the rest —
|
|
37
|
-
see SwipableMobileCarouselSlideParts.module.css. */
|
|
38
|
-
display: flex;
|
|
39
|
-
flex-direction: column;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.indicatorSlot {
|
|
43
|
-
/* Overlays the bottom of .wrap rather than taking its own layout row —
|
|
44
|
-
matches both sovereign-tasks' and sovereign-shopper's existing dots
|
|
45
|
-
placement. Applied by the carousel itself around WHATEVER
|
|
46
|
-
renderIndicator returns (the default SwipableMobileCarouselDots or a
|
|
47
|
-
caller-supplied override) — a custom renderIndicator has no way to
|
|
48
|
-
import this module's locally-scoped class itself (CSS Modules classnames
|
|
49
|
-
aren't cross-file importable), so positioning must live here, not be
|
|
50
|
-
something each indicator implementation opts into. Previously this class
|
|
51
|
-
was only ever applied to the *default* indicator branch, which silently
|
|
52
|
-
left any custom renderIndicator unpositioned — a static, in-flow sibling
|
|
53
|
-
pushed below the full-height .scroller and clipped out of view instead
|
|
54
|
-
of overlaid on top of it. */
|
|
55
|
-
position: absolute;
|
|
56
|
-
left: 0;
|
|
57
|
-
right: 0;
|
|
58
|
-
bottom: var(--sv-space-3);
|
|
59
|
-
pointer-events: none;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.indicatorSlot > * {
|
|
63
|
-
pointer-events: auto;
|
|
64
|
-
}
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Children,
|
|
5
|
-
isValidElement,
|
|
6
|
-
useEffect,
|
|
7
|
-
useLayoutEffect,
|
|
8
|
-
useMemo,
|
|
9
|
-
useRef,
|
|
10
|
-
type ReactElement,
|
|
11
|
-
type ReactNode,
|
|
12
|
-
} from 'react';
|
|
13
|
-
import { useSnapCarousel } from '../../hooks/useSnapCarousel';
|
|
14
|
-
import { SwipableMobileCarouselDots } from '../SwipableMobileCarouselDots/SwipableMobileCarouselDots';
|
|
15
|
-
import { SwipableMobileCarouselSlide } from './SwipableMobileCarouselSlide';
|
|
16
|
-
import { CarouselSlideMountContext } from './context';
|
|
17
|
-
import styles from './SwipableMobileCarousel.module.css';
|
|
18
|
-
|
|
19
|
-
export interface SwipableMobileCarouselIndicatorProps {
|
|
20
|
-
count: number;
|
|
21
|
-
activeIndex: number;
|
|
22
|
-
labels: (string | undefined)[];
|
|
23
|
-
onJump: (index: number) => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface SwipableMobileCarouselProps {
|
|
27
|
-
/** Controlled active slide index — the caller owns this (typically via
|
|
28
|
-
* useCarouselRouteSync, or plain useState). */
|
|
29
|
-
activeIndex: number;
|
|
30
|
-
/** Called when a swipe gesture settles on a different index, or when the
|
|
31
|
-
* reorder-jump fix re-snaps after the active slide's position changes.
|
|
32
|
-
* The caller is responsible for updating `activeIndex` in response. */
|
|
33
|
-
onSettle: (index: number) => void;
|
|
34
|
-
/** How many slides on each side of the active one stay mounted. Default 1
|
|
35
|
-
* matches both sovereign-tasks' and sovereign-shopper's existing "swipe
|
|
36
|
-
* never shows a spinner" behavior. Slides outside this window keep their
|
|
37
|
-
* DOM slot (so scroll-snap's position-based indexing stays correct) but
|
|
38
|
-
* their children are not mounted at all. */
|
|
39
|
-
prefetchDistance?: number;
|
|
40
|
-
/** Passed straight through to the internal useSnapCarousel. */
|
|
41
|
-
settleDebounceMs?: number;
|
|
42
|
-
/** Required — labels the scroller region for assistive tech. No generic
|
|
43
|
-
* fallback, since one would be wrong for every actual consumer. */
|
|
44
|
-
'aria-label': string;
|
|
45
|
-
/** Renders the indicator. Defaults to SwipableMobileCarouselDots. Pass
|
|
46
|
-
* `null` to render no indicator at all. */
|
|
47
|
-
renderIndicator?: null | ((props: SwipableMobileCarouselIndicatorProps) => ReactNode);
|
|
48
|
-
className?: string;
|
|
49
|
-
/** Must be SwipableMobileCarouselSlide elements (nullish/boolean children
|
|
50
|
-
* are safely skipped for conditional slides). A dev-mode warning is
|
|
51
|
-
* logged for any other child type — see resolveSlides below. */
|
|
52
|
-
children: ReactNode;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface ResolvedSlide {
|
|
56
|
-
key: string;
|
|
57
|
-
label: string | undefined;
|
|
58
|
-
element: ReactElement;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function describeChild(child: unknown): string {
|
|
62
|
-
if (isValidElement(child)) {
|
|
63
|
-
const type = child.type;
|
|
64
|
-
if (typeof type === 'string') return `<${type}>`;
|
|
65
|
-
if (typeof type === 'function') {
|
|
66
|
-
const named = type as { displayName?: string; name?: string };
|
|
67
|
-
return `<${named.displayName ?? named.name ?? 'Component'}>`;
|
|
68
|
-
}
|
|
69
|
-
return '<unknown>';
|
|
70
|
-
}
|
|
71
|
-
if (typeof child === 'string') return `string "${child}"`;
|
|
72
|
-
return String(child);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function resolveSlides(children: ReactNode): ResolvedSlide[] {
|
|
76
|
-
const slides: ResolvedSlide[] = [];
|
|
77
|
-
Children.forEach(children, (child, index) => {
|
|
78
|
-
if (child === null || child === undefined || child === false || child === true) return;
|
|
79
|
-
if (!isValidElement(child) || child.type !== SwipableMobileCarouselSlide) {
|
|
80
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
81
|
-
console.error(
|
|
82
|
-
'[SwipableMobileCarousel] Every child must be a <SwipableMobileCarouselSlide>. ' +
|
|
83
|
-
`Found ${describeChild(child)} at position ${index}. A non-Slide child shifts every ` +
|
|
84
|
-
"subsequent slide's index, desyncing scroll-snap position from activeIndex.",
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const slideProps = child.props as { slideKey: string; label?: string };
|
|
90
|
-
if (process.env.NODE_ENV !== 'production' && !slideProps.label) {
|
|
91
|
-
console.warn(
|
|
92
|
-
`[SwipableMobileCarousel] SwipableMobileCarouselSlide "${slideProps.slideKey}" has no ` +
|
|
93
|
-
'label — it will show as "Slide N of count" in the default dots indicator.',
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
slides.push({ key: slideProps.slideKey, label: slideProps.label, element: child });
|
|
97
|
-
});
|
|
98
|
-
return slides;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* SwipableMobileCarousel — a compound component for swiping between full-
|
|
103
|
-
* width slides (each an independent route/view on mobile), wrapping
|
|
104
|
-
* useSnapCarousel. This library's first compound component: every other
|
|
105
|
-
* component here is flat/prop-based, but slide content is large, arbitrary,
|
|
106
|
-
* per-plugin subtrees that need a header-known/body-loading split an
|
|
107
|
-
* array-of-objects prop would only express with worse JSX ergonomics.
|
|
108
|
-
*
|
|
109
|
-
* Owns rendering and mount-window mechanics only — it has no opinion on
|
|
110
|
-
* where slide data lives. Do NOT: (a) aggregate cross-slide data inside a
|
|
111
|
-
* SwipableMobileCarouselSlideBody (that recomputes on every slide render
|
|
112
|
-
* regardless of which slide is active — belongs in the parent, which
|
|
113
|
-
* already knows every slide exists); (b) mount a detail overlay (Sheet,
|
|
114
|
-
* Dialog) inside a Slide's children — mount it as a sibling of
|
|
115
|
-
* SwipableMobileCarousel instead, controlled by the same state that would
|
|
116
|
-
* otherwise drive a routed page's overlay. sovereign-tasks' current
|
|
117
|
-
* hand-rolled carousel does both and is measurably laggier than
|
|
118
|
-
* sovereign-shopper's equivalent, which keeps its overlay in the routed pane.
|
|
119
|
-
*/
|
|
120
|
-
export function SwipableMobileCarousel({
|
|
121
|
-
activeIndex,
|
|
122
|
-
onSettle,
|
|
123
|
-
prefetchDistance = 1,
|
|
124
|
-
settleDebounceMs = 120,
|
|
125
|
-
'aria-label': ariaLabel,
|
|
126
|
-
renderIndicator,
|
|
127
|
-
className,
|
|
128
|
-
children,
|
|
129
|
-
}: SwipableMobileCarouselProps) {
|
|
130
|
-
const slides = useMemo(() => resolveSlides(children), [children]);
|
|
131
|
-
const count = slides.length;
|
|
132
|
-
const clampedActiveIndex = count === 0 ? 0 : Math.max(0, Math.min(count - 1, activeIndex));
|
|
133
|
-
|
|
134
|
-
// Initial scroll position, once — subsequent activeIndex changes come
|
|
135
|
-
// either from the user's own swipe (already reflected in DOM scroll
|
|
136
|
-
// position; re-syncing to the same index below is a harmless no-op) or an
|
|
137
|
-
// external navigation, which the effect below scrolls to explicitly.
|
|
138
|
-
const initialActiveIndexRef = useRef(clampedActiveIndex);
|
|
139
|
-
|
|
140
|
-
const { scrollRef, scrollToIndex, liveIndex } = useSnapCarousel({
|
|
141
|
-
itemCount: count,
|
|
142
|
-
onSettle,
|
|
143
|
-
debounceMs: settleDebounceMs,
|
|
144
|
-
initialIndex: initialActiveIndexRef.current,
|
|
145
|
-
});
|
|
146
|
-
useLayoutEffect(() => {
|
|
147
|
-
scrollToIndex(initialActiveIndexRef.current, 'instant');
|
|
148
|
-
// Runs once on mount only, matching both existing plugins' identical pattern.
|
|
149
|
-
}, []);
|
|
150
|
-
|
|
151
|
-
const didMountActiveIndexSyncRef = useRef(false);
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
if (!didMountActiveIndexSyncRef.current) {
|
|
154
|
-
didMountActiveIndexSyncRef.current = true;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
scrollToIndex(clampedActiveIndex, 'smooth');
|
|
158
|
-
}, [clampedActiveIndex, scrollToIndex]);
|
|
159
|
-
|
|
160
|
-
// Reorder-jump fix: scroll-snap position tracks DOM order, not slide
|
|
161
|
-
// identity. If the previously-active slide's key still exists but moved
|
|
162
|
-
// (a caller re-sorted their slide array while mounted), re-snap to its
|
|
163
|
-
// new position and report it via onSettle so the caller's activeIndex
|
|
164
|
-
// stays in sync — otherwise scroll position silently desyncs from slide
|
|
165
|
-
// identity. Runs every commit (no dependency array) since it needs to
|
|
166
|
-
// notice any children change, not just a specific prop.
|
|
167
|
-
const prevKeysRef = useRef<string[] | null>(null);
|
|
168
|
-
useLayoutEffect(() => {
|
|
169
|
-
const currentKeys = slides.map((s) => s.key);
|
|
170
|
-
const prevKeys = prevKeysRef.current;
|
|
171
|
-
if (prevKeys) {
|
|
172
|
-
const sameOrder =
|
|
173
|
-
prevKeys.length === currentKeys.length && prevKeys.every((k, i) => k === currentKeys[i]);
|
|
174
|
-
if (!sameOrder) {
|
|
175
|
-
const activeKey = prevKeys[clampedActiveIndex];
|
|
176
|
-
if (activeKey !== undefined) {
|
|
177
|
-
const newIndex = currentKeys.indexOf(activeKey);
|
|
178
|
-
if (newIndex !== -1 && newIndex !== clampedActiveIndex) {
|
|
179
|
-
scrollToIndex(newIndex, 'instant');
|
|
180
|
-
onSettle(newIndex);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
prevKeysRef.current = currentKeys;
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
function handleJump(index: number) {
|
|
189
|
-
// scrollToIndex sets useSnapCarousel's own dedupe ref synchronously, so
|
|
190
|
-
// the natural scroll-settle detection will NOT re-report this index —
|
|
191
|
-
// onSettle must be called directly here, same pairing as the
|
|
192
|
-
// reorder-jump fix above.
|
|
193
|
-
scrollToIndex(index, 'smooth');
|
|
194
|
-
onSettle(index);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const labels = slides.map((s) => s.label);
|
|
198
|
-
const indicator =
|
|
199
|
-
renderIndicator === null ? null : renderIndicator ? (
|
|
200
|
-
renderIndicator({ count, activeIndex: clampedActiveIndex, labels, onJump: handleJump })
|
|
201
|
-
) : (
|
|
202
|
-
<SwipableMobileCarouselDots
|
|
203
|
-
count={count}
|
|
204
|
-
activeIndex={clampedActiveIndex}
|
|
205
|
-
labels={labels}
|
|
206
|
-
aria-label={ariaLabel}
|
|
207
|
-
onJump={handleJump}
|
|
208
|
-
/>
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
return (
|
|
212
|
-
<div className={[styles.wrap, className].filter(Boolean).join(' ')}>
|
|
213
|
-
<div className={styles.scroller} ref={scrollRef} role="region" aria-label={ariaLabel}>
|
|
214
|
-
{slides.map((slide, i) => (
|
|
215
|
-
<div className={styles.slide} key={slide.key}>
|
|
216
|
-
<CarouselSlideMountContext.Provider
|
|
217
|
-
value={{
|
|
218
|
-
// Union of the settled index and the live (real-time,
|
|
219
|
-
// pre-settle) scroll position — see useSnapCarousel's own
|
|
220
|
-
// liveIndex doc comment. A single fast flick can carry
|
|
221
|
-
// native scroll-snap momentum past an intermediate slide to
|
|
222
|
-
// one two-or-more away before settle-detection's debounce
|
|
223
|
-
// window ever reports it; without also checking liveIndex,
|
|
224
|
-
// the slide the container had already visually scrolled to
|
|
225
|
-
// stays unmounted (rendering nothing at all, not even a
|
|
226
|
-
// loading skeleton) for that entire window.
|
|
227
|
-
isMounted:
|
|
228
|
-
Math.abs(i - clampedActiveIndex) <= prefetchDistance ||
|
|
229
|
-
Math.abs(i - liveIndex) <= prefetchDistance,
|
|
230
|
-
}}
|
|
231
|
-
>
|
|
232
|
-
{slide.element}
|
|
233
|
-
</CarouselSlideMountContext.Provider>
|
|
234
|
-
</div>
|
|
235
|
-
))}
|
|
236
|
-
</div>
|
|
237
|
-
{/* Positioning (overlay the bottom of .wrap) lives here, applied around
|
|
238
|
-
whatever renderIndicator returns — see .indicatorSlot's own doc
|
|
239
|
-
comment for why this can't be delegated to the indicator itself. */}
|
|
240
|
-
{indicator && <div className={styles.indicatorSlot}>{indicator}</div>}
|
|
241
|
-
</div>
|
|
242
|
-
);
|
|
243
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useContext, type ReactNode } from 'react';
|
|
4
|
-
import { CarouselSlideMountContext } from './context';
|
|
5
|
-
|
|
6
|
-
export interface SwipableMobileCarouselSlideProps {
|
|
7
|
-
/** Stable identity for this slide, independent of its position among
|
|
8
|
-
* siblings — required. This is what makes SwipableMobileCarousel's
|
|
9
|
-
* reorder-jump fix possible: a plain array index can't distinguish "this
|
|
10
|
-
* slide moved to position 2" from "this slide was removed and a
|
|
11
|
-
* different one is now at position 2." Reuse whatever id the caller
|
|
12
|
-
* already keys their `.map()` on (e.g. a list's own id). */
|
|
13
|
-
slideKey: string;
|
|
14
|
-
/** Accessible label surfaced to the default dots indicator (e.g.
|
|
15
|
-
* "Groceries"). Falls back to "Slide N of count" if omitted — omitting it
|
|
16
|
-
* logs a dev-mode warning, since every real slide usually has a title
|
|
17
|
-
* available synchronously already. */
|
|
18
|
-
label?: string;
|
|
19
|
-
/** SwipableMobileCarouselSlideHeader/Body/Footer, in any order/subset. */
|
|
20
|
-
children: ReactNode;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* SwipableMobileCarouselSlide — a single slide of a SwipableMobileCarousel.
|
|
25
|
-
* Renders its children only while within the carousel's mount window (the
|
|
26
|
-
* active slide ± its configured prefetchDistance); outside that window it
|
|
27
|
-
* renders nothing, matching both sovereign-tasks and sovereign-shopper's
|
|
28
|
-
* existing "never fetch/render a non-neighbor slide" behavior, now
|
|
29
|
-
* centralized instead of hand-rolled per plugin.
|
|
30
|
-
*/
|
|
31
|
-
export function SwipableMobileCarouselSlide({ children }: SwipableMobileCarouselSlideProps) {
|
|
32
|
-
const ctx = useContext(CarouselSlideMountContext);
|
|
33
|
-
if (!ctx?.isMounted) return null;
|
|
34
|
-
return <>{children}</>;
|
|
35
|
-
}
|