@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,56 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import styles from './SegmentedControl.module.css';
|
|
4
|
-
|
|
5
|
-
export interface SegmentedOption<T extends string = string> {
|
|
6
|
-
label: string;
|
|
7
|
-
value: T;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface SegmentedControlProps<T extends string = string> {
|
|
11
|
-
value: T;
|
|
12
|
-
onChange: (value: T) => void;
|
|
13
|
-
options: SegmentedOption<T>[];
|
|
14
|
-
size?: 'sm' | 'md';
|
|
15
|
-
'aria-label': string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* SegmentedControl — pill-based 2–3 option picker for inline use in table rows
|
|
20
|
-
* and dialogs (e.g. User / Admin / Owner role switcher).
|
|
21
|
-
*
|
|
22
|
-
* Renders as `<div role="radiogroup">` with `<button role="radio">` children —
|
|
23
|
-
* correct semantics without a native `<input type="radio">` (which needs an id/name
|
|
24
|
-
* pair and a `<form>` context to function correctly in all browsers).
|
|
25
|
-
*/
|
|
26
|
-
export function SegmentedControl<T extends string = string>({
|
|
27
|
-
value,
|
|
28
|
-
onChange,
|
|
29
|
-
options,
|
|
30
|
-
size = 'md',
|
|
31
|
-
'aria-label': ariaLabel,
|
|
32
|
-
}: SegmentedControlProps<T>) {
|
|
33
|
-
return (
|
|
34
|
-
<div
|
|
35
|
-
role="radiogroup"
|
|
36
|
-
aria-label={ariaLabel}
|
|
37
|
-
className={[styles.track, styles[size]].join(' ')}
|
|
38
|
-
>
|
|
39
|
-
{options.map((opt) => {
|
|
40
|
-
const active = opt.value === value;
|
|
41
|
-
return (
|
|
42
|
-
<button
|
|
43
|
-
key={opt.value}
|
|
44
|
-
type="button"
|
|
45
|
-
role="radio"
|
|
46
|
-
aria-checked={active}
|
|
47
|
-
className={[styles.segment, active ? styles.active : styles.inactive].join(' ')}
|
|
48
|
-
onClick={() => onChange(opt.value)}
|
|
49
|
-
>
|
|
50
|
-
{opt.label}
|
|
51
|
-
</button>
|
|
52
|
-
);
|
|
53
|
-
})}
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
-
|
|
5
|
-
afterEach(cleanup);
|
|
6
|
-
import { SegmentedControl } from '../SegmentedControl';
|
|
7
|
-
|
|
8
|
-
const options = [
|
|
9
|
-
{ label: 'User', value: 'user' as const },
|
|
10
|
-
{ label: 'Admin', value: 'admin' as const },
|
|
11
|
-
{ label: 'Owner', value: 'owner' as const },
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
describe('SegmentedControl', () => {
|
|
15
|
-
it('renders all options as radio buttons', () => {
|
|
16
|
-
render(
|
|
17
|
-
<SegmentedControl value="user" onChange={() => {}} options={options} aria-label="Role" />,
|
|
18
|
-
);
|
|
19
|
-
expect(screen.getAllByRole('radio').length).toBe(3);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('marks the active option as checked', () => {
|
|
23
|
-
render(
|
|
24
|
-
<SegmentedControl value="admin" onChange={() => {}} options={options} aria-label="Role" />,
|
|
25
|
-
);
|
|
26
|
-
expect(screen.getByRole('radio', { name: 'Admin' }).getAttribute('aria-checked')).toBe('true');
|
|
27
|
-
expect(screen.getByRole('radio', { name: 'User' }).getAttribute('aria-checked')).toBe('false');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('calls onChange with the selected value on click', () => {
|
|
31
|
-
const onChange = vi.fn();
|
|
32
|
-
render(
|
|
33
|
-
<SegmentedControl value="user" onChange={onChange} options={options} aria-label="Role" />,
|
|
34
|
-
);
|
|
35
|
-
fireEvent.click(screen.getByRole('radio', { name: 'Admin' }));
|
|
36
|
-
expect(onChange).toHaveBeenCalledWith('admin');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('exposes a radiogroup with the given aria-label', () => {
|
|
40
|
-
render(
|
|
41
|
-
<SegmentedControl
|
|
42
|
-
value="user"
|
|
43
|
-
onChange={() => {}}
|
|
44
|
-
options={options}
|
|
45
|
-
aria-label="Select role"
|
|
46
|
-
/>,
|
|
47
|
-
);
|
|
48
|
-
expect(screen.getByRole('radiogroup', { name: 'Select role' })).toBeDefined();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('applies size class to the track', () => {
|
|
52
|
-
const { container } = render(
|
|
53
|
-
<SegmentedControl
|
|
54
|
-
value="user"
|
|
55
|
-
onChange={() => {}}
|
|
56
|
-
options={options}
|
|
57
|
-
size="sm"
|
|
58
|
-
aria-label="Role"
|
|
59
|
-
/>,
|
|
60
|
-
);
|
|
61
|
-
expect((container.firstChild as HTMLElement).className).toContain('sm');
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/* Wrapper provides the positioning context for the custom chevron */
|
|
2
|
-
.wrapper {
|
|
3
|
-
position: relative;
|
|
4
|
-
display: block;
|
|
5
|
-
width: 100%;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.select {
|
|
9
|
-
display: block;
|
|
10
|
-
width: 100%;
|
|
11
|
-
/* 36px rendered height. Explicit height + border-box, same technique as
|
|
12
|
-
Input. Right-pad to clear the custom chevron. */
|
|
13
|
-
height: 36px;
|
|
14
|
-
box-sizing: border-box;
|
|
15
|
-
padding: 4px var(--sv-space-8) 4px var(--sv-space-3);
|
|
16
|
-
font-family: var(--sv-font-family);
|
|
17
|
-
font-size: var(--sv-font-size-sm);
|
|
18
|
-
line-height: 1.5;
|
|
19
|
-
color: var(--sv-color-text-primary);
|
|
20
|
-
background-color: var(--sv-color-surface);
|
|
21
|
-
border: var(--sv-border-width-hairline) solid var(--sv-color-border-strong);
|
|
22
|
-
border-radius: var(--sv-radius-md);
|
|
23
|
-
cursor: pointer;
|
|
24
|
-
/* Remove native OS chevron */
|
|
25
|
-
appearance: none;
|
|
26
|
-
transition:
|
|
27
|
-
border-color 0.15s ease,
|
|
28
|
-
box-shadow 0.15s ease;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/* sm — compact for table cells and inline controls. 32px height. */
|
|
32
|
-
.sm .select {
|
|
33
|
-
height: 32px;
|
|
34
|
-
padding: 2px var(--sv-space-6) 2px var(--sv-space-2);
|
|
35
|
-
font-size: var(--sv-font-size-sm);
|
|
36
|
-
line-height: 1.4;
|
|
37
|
-
border-radius: var(--sv-radius-sm);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/* iOS Safari zooms the page when a <select> under 16px receives focus, exactly
|
|
41
|
-
as it does for text inputs. Lift the default size to >=16px on touch devices;
|
|
42
|
-
the compact `.sm` variant is for dense desktop tables and is left untouched. */
|
|
43
|
-
@media (pointer: coarse) {
|
|
44
|
-
.select {
|
|
45
|
-
font-size: var(--sv-font-size-md);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.select:focus-visible {
|
|
50
|
-
outline: none;
|
|
51
|
-
border-color: var(--sv-color-accent);
|
|
52
|
-
box-shadow: 0 0 0 2px var(--sv-color-focus-ring);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.select:disabled {
|
|
56
|
-
opacity: 0.5;
|
|
57
|
-
cursor: not-allowed;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/* Compact size variant — reduced padding for table-cell usage */
|
|
61
|
-
.sm .select {
|
|
62
|
-
padding-top: var(--sv-space-1);
|
|
63
|
-
padding-bottom: var(--sv-space-1);
|
|
64
|
-
font-size: var(--sv-font-size-sm);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/* SVG chevron — matches the icon stroke style used across the UI */
|
|
68
|
-
.chevron {
|
|
69
|
-
pointer-events: none;
|
|
70
|
-
position: absolute;
|
|
71
|
-
right: var(--sv-space-3);
|
|
72
|
-
top: 50%;
|
|
73
|
-
transform: translateY(-50%);
|
|
74
|
-
color: var(--sv-color-text-muted);
|
|
75
|
-
flex-shrink: 0;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.sm .chevron {
|
|
79
|
-
right: var(--sv-space-2);
|
|
80
|
-
width: 10px;
|
|
81
|
-
height: 10px;
|
|
82
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
import { Select } from './Select';
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: 'Components/Select',
|
|
6
|
-
component: Select,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: 'centered',
|
|
9
|
-
docs: {
|
|
10
|
-
description: {
|
|
11
|
-
component:
|
|
12
|
-
'Styled native `<select>` — same visual language as `Input`. Preserves native picker on mobile for maximum accessibility. RSC-safe.',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
argTypes: {
|
|
17
|
-
disabled: { control: 'boolean' },
|
|
18
|
-
},
|
|
19
|
-
} satisfies Meta<typeof Select>;
|
|
20
|
-
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
export const Default: Story = {
|
|
27
|
-
render: (_args) => (
|
|
28
|
-
<div style={{ width: 280, fontFamily: 'var(--sv-font-family)' }}>
|
|
29
|
-
<label
|
|
30
|
-
htmlFor="role-select"
|
|
31
|
-
style={{
|
|
32
|
-
display: 'block',
|
|
33
|
-
marginBottom: 4,
|
|
34
|
-
fontSize: 'var(--sv-font-size-sm)',
|
|
35
|
-
fontWeight: 'var(--sv-font-weight-medium)',
|
|
36
|
-
color: 'var(--sv-color-text-primary)',
|
|
37
|
-
}}
|
|
38
|
-
>
|
|
39
|
-
Role
|
|
40
|
-
</label>
|
|
41
|
-
<Select id="role-select" defaultValue="user">
|
|
42
|
-
<option value="user">User</option>
|
|
43
|
-
<option value="admin">Admin</option>
|
|
44
|
-
<option value="owner">Owner</option>
|
|
45
|
-
</Select>
|
|
46
|
-
</div>
|
|
47
|
-
),
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const Disabled: Story = {
|
|
51
|
-
render: (_args) => (
|
|
52
|
-
<div style={{ width: 280 }}>
|
|
53
|
-
<Select disabled defaultValue="user">
|
|
54
|
-
<option value="user">User</option>
|
|
55
|
-
<option value="admin">Admin</option>
|
|
56
|
-
</Select>
|
|
57
|
-
</div>
|
|
58
|
-
),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/** Form context — several fields together matching the spec layout. */
|
|
62
|
-
export const FormContext: Story = {
|
|
63
|
-
render: (_args) => {
|
|
64
|
-
const fieldStyle: React.CSSProperties = {
|
|
65
|
-
display: 'flex',
|
|
66
|
-
flexDirection: 'column',
|
|
67
|
-
gap: 4,
|
|
68
|
-
};
|
|
69
|
-
const labelStyle: React.CSSProperties = {
|
|
70
|
-
fontSize: 'var(--sv-font-size-sm)',
|
|
71
|
-
fontWeight: 'var(--sv-font-weight-medium)',
|
|
72
|
-
color: 'var(--sv-color-text-primary)',
|
|
73
|
-
fontFamily: 'var(--sv-font-family)',
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<div style={{ width: 320, display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
78
|
-
<div style={fieldStyle}>
|
|
79
|
-
<label htmlFor="lang-select" style={labelStyle}>
|
|
80
|
-
Language
|
|
81
|
-
</label>
|
|
82
|
-
<Select id="lang-select" defaultValue="en-us">
|
|
83
|
-
<option value="en-us">English (US)</option>
|
|
84
|
-
<option value="en-gb">English (UK)</option>
|
|
85
|
-
<option value="fr">Français</option>
|
|
86
|
-
<option value="de">Deutsch</option>
|
|
87
|
-
<option value="ja">日本語</option>
|
|
88
|
-
</Select>
|
|
89
|
-
</div>
|
|
90
|
-
<div style={fieldStyle}>
|
|
91
|
-
<label htmlFor="tz-select" style={labelStyle}>
|
|
92
|
-
Timezone
|
|
93
|
-
</label>
|
|
94
|
-
<Select id="tz-select" defaultValue="asia-colombo">
|
|
95
|
-
<option value="asia-colombo">Asia/Colombo (UTC+5:30)</option>
|
|
96
|
-
<option value="utc">UTC</option>
|
|
97
|
-
<option value="america-ny">America/New_York (UTC−5)</option>
|
|
98
|
-
<option value="europe-london">Europe/London (UTC+0)</option>
|
|
99
|
-
</Select>
|
|
100
|
-
</div>
|
|
101
|
-
<div style={fieldStyle}>
|
|
102
|
-
<label htmlFor="poll-select" style={labelStyle}>
|
|
103
|
-
Poll interval
|
|
104
|
-
</label>
|
|
105
|
-
<Select id="poll-select" defaultValue="30">
|
|
106
|
-
<option value="15">Every 15 seconds</option>
|
|
107
|
-
<option value="30">Every 30 seconds</option>
|
|
108
|
-
<option value="60">Every minute</option>
|
|
109
|
-
<option value="300">Every 5 minutes</option>
|
|
110
|
-
</Select>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
);
|
|
114
|
-
},
|
|
115
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { SelectHTMLAttributes } from 'react';
|
|
2
|
-
import styles from './Select.module.css';
|
|
3
|
-
|
|
4
|
-
export type SelectProps = Omit<SelectHTMLAttributes<HTMLSelectElement>, 'size'> & {
|
|
5
|
-
/** 'md' (default) — standard form field height. 'sm' — compact for table cells and inline controls. */
|
|
6
|
-
size?: 'sm' | 'md';
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Select — styled wrapper around the native `<select>`. Inherits the same
|
|
11
|
-
* height, border, radius, and focus ring as `Input` for visual consistency.
|
|
12
|
-
* Uses the native picker on mobile — no custom dropdown, maximum a11y coverage.
|
|
13
|
-
*
|
|
14
|
-
* RSC-safe: presentational, no hooks, forwards all native select props.
|
|
15
|
-
*
|
|
16
|
-
* `className` sizes the outer box (the wrapper), not the `<select>` itself —
|
|
17
|
-
* the chevron is absolutely positioned against the wrapper, so a className
|
|
18
|
-
* that constrains only the `<select>` (e.g. `max-width`) shrinks the select
|
|
19
|
-
* while the wrapper (and thus the chevron) stays full width, leaving the
|
|
20
|
-
* chevron stranded past the visible box.
|
|
21
|
-
*/
|
|
22
|
-
export function Select({ className, size = 'md', children, ...rest }: SelectProps) {
|
|
23
|
-
return (
|
|
24
|
-
<div
|
|
25
|
-
className={[styles.wrapper, size === 'sm' ? styles.sm : undefined, className]
|
|
26
|
-
.filter(Boolean)
|
|
27
|
-
.join(' ')}
|
|
28
|
-
>
|
|
29
|
-
<select className={styles.select} {...rest}>
|
|
30
|
-
{children}
|
|
31
|
-
</select>
|
|
32
|
-
<svg
|
|
33
|
-
className={styles.chevron}
|
|
34
|
-
aria-hidden="true"
|
|
35
|
-
width="12"
|
|
36
|
-
height="12"
|
|
37
|
-
viewBox="0 0 24 24"
|
|
38
|
-
fill="none"
|
|
39
|
-
stroke="currentColor"
|
|
40
|
-
strokeWidth="2"
|
|
41
|
-
strokeLinecap="round"
|
|
42
|
-
strokeLinejoin="round"
|
|
43
|
-
>
|
|
44
|
-
<polyline points="6 9 12 15 18 9" />
|
|
45
|
-
</svg>
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
-
import { Select } from '../Select';
|
|
5
|
-
|
|
6
|
-
afterEach(cleanup);
|
|
7
|
-
|
|
8
|
-
describe('Select', () => {
|
|
9
|
-
it('renders a combobox', () => {
|
|
10
|
-
render(
|
|
11
|
-
<Select aria-label="Role">
|
|
12
|
-
<option value="user">User</option>
|
|
13
|
-
<option value="admin">Admin</option>
|
|
14
|
-
</Select>,
|
|
15
|
-
);
|
|
16
|
-
expect(screen.getByRole('combobox', { name: 'Role' })).toBeDefined();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('renders provided options', () => {
|
|
20
|
-
render(
|
|
21
|
-
<Select aria-label="Role">
|
|
22
|
-
<option value="user">User</option>
|
|
23
|
-
<option value="admin">Admin</option>
|
|
24
|
-
<option value="owner">Owner</option>
|
|
25
|
-
</Select>,
|
|
26
|
-
);
|
|
27
|
-
expect(screen.getAllByRole('option').length).toBe(3);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('forwards value and onChange', () => {
|
|
31
|
-
const onChange = vi.fn();
|
|
32
|
-
render(
|
|
33
|
-
<Select aria-label="Role" value="user" onChange={onChange}>
|
|
34
|
-
<option value="user">User</option>
|
|
35
|
-
<option value="admin">Admin</option>
|
|
36
|
-
</Select>,
|
|
37
|
-
);
|
|
38
|
-
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'admin' } });
|
|
39
|
-
expect(onChange).toHaveBeenCalled();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('is disabled when the disabled prop is set', () => {
|
|
43
|
-
render(
|
|
44
|
-
<Select aria-label="Role" disabled>
|
|
45
|
-
<option value="user">User</option>
|
|
46
|
-
</Select>,
|
|
47
|
-
);
|
|
48
|
-
expect((screen.getByRole('combobox') as HTMLSelectElement).disabled).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('renders a decorative chevron element', () => {
|
|
52
|
-
const { container } = render(
|
|
53
|
-
<Select aria-label="Role">
|
|
54
|
-
<option value="user">User</option>
|
|
55
|
-
</Select>,
|
|
56
|
-
);
|
|
57
|
-
expect(container.querySelector('[aria-hidden]')).toBeDefined();
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/* Sheet — fills the same rect as a plugin's content area (between the shell's
|
|
2
|
-
* sticky header and footer nav — see --sv-shell-header-height /
|
|
3
|
-
* --sv-shell-footer-height, set by the platform shell or, for a plugin that
|
|
4
|
-
* self-renders MobileHeader/MobileFooter instead (shellConfig.mobileHeader/
|
|
5
|
-
* mobileFooter: false), by that component itself — see
|
|
6
|
-
* usePublishShellChromeHeight), sliding in from an edge
|
|
7
|
-
* instead of Dialog's centered box or Drawer's partial-height sheet-over-
|
|
8
|
-
* scrim. z-index matches Dialog/Drawer's scrim so it layers consistently
|
|
9
|
-
* with any other overlay. No scrim of its own — see the component doc
|
|
10
|
-
* comment for why. */
|
|
11
|
-
|
|
12
|
-
.panel {
|
|
13
|
-
position: fixed;
|
|
14
|
-
left: 0;
|
|
15
|
-
right: 0;
|
|
16
|
-
top: var(--sv-shell-header-height, 0);
|
|
17
|
-
bottom: var(--sv-shell-footer-height, 0);
|
|
18
|
-
z-index: 100;
|
|
19
|
-
display: flex;
|
|
20
|
-
flex-direction: column;
|
|
21
|
-
background: var(--sv-color-surface);
|
|
22
|
-
outline: none;
|
|
23
|
-
transform: translateY(100%);
|
|
24
|
-
transition: transform var(--sv-motion-duration-base) var(--sv-motion-ease-out);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.panelOpen {
|
|
28
|
-
transform: translateY(0);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/* Opt-in top variant (slideFrom="top") — a short options/actions menu opened
|
|
32
|
-
* from a header button reads more naturally sliding down from that button's
|
|
33
|
-
* edge than traveling up from off-screen bottom. :not(.panelOpen) is what
|
|
34
|
-
* lets this coexist with .panelOpen above despite equal-looking single-class
|
|
35
|
-
* specificity elsewhere in this file: its (0,2,0) beats .panelOpen's (0,1,0)
|
|
36
|
-
* while closed/entering/closing, and yields to it (transform: translateY(0),
|
|
37
|
-
* same value either direction) once open. */
|
|
38
|
-
.panelFromTop:not(.panelOpen) {
|
|
39
|
-
transform: translateY(-100%);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/* See Dialog.module.css's identical rule for why 0.01ms rather than 0. */
|
|
43
|
-
@media (prefers-reduced-motion: reduce) {
|
|
44
|
-
.panel {
|
|
45
|
-
transition-duration: 0.01ms;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* Always the scroll container, with or without OverlayHeader present (see
|
|
50
|
-
* Sheet.tsx). No opinionated padding here — matches Drawer's convention of
|
|
51
|
-
* leaving horizontal/top padding and safe-area-bottom clearance to the
|
|
52
|
-
* content itself, since a Sheet's content shape varies far more than a
|
|
53
|
-
* fixed-size Dialog's. */
|
|
54
|
-
.content {
|
|
55
|
-
flex: 1 1 auto;
|
|
56
|
-
overflow-y: auto;
|
|
57
|
-
overscroll-behavior: contain;
|
|
58
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { type ReactNode, useRef } from 'react';
|
|
4
|
-
import { useMountTransition, usePrefersReducedMotion } from '../../motion';
|
|
5
|
-
import {
|
|
6
|
-
OVERLAY_MOTION_DURATION_MS,
|
|
7
|
-
useOverlayFocusCapture,
|
|
8
|
-
useOverlayKeyboardTrap,
|
|
9
|
-
useOverlayScrollLock,
|
|
10
|
-
} from '../../overlay-shell';
|
|
11
|
-
import { OverlayHeader } from '../OverlayHeader/OverlayHeader';
|
|
12
|
-
import styles from './Sheet.module.css';
|
|
13
|
-
|
|
14
|
-
export interface SheetProps {
|
|
15
|
-
/** Whether the sheet is shown. When false, nothing renders. */
|
|
16
|
-
open: boolean;
|
|
17
|
-
/** Called on Esc, or the built-in `OverlayHeader`'s close button. There is
|
|
18
|
-
* no scrim to tap — a Sheet replaces the content area it fills, not a
|
|
19
|
-
* layer floating above it (see the component doc comment). */
|
|
20
|
-
onClose: () => void;
|
|
21
|
-
/** Accessible name for the sheet. Defaults to `title` when omitted. */
|
|
22
|
-
'aria-label'?: string;
|
|
23
|
-
/** Renders a built-in `OverlayHeader` (title + close, optional back button
|
|
24
|
-
* and trailing action). Omit when the content supplies its own header —
|
|
25
|
-
* e.g. a form whose title doubles as an editable field. */
|
|
26
|
-
title?: string;
|
|
27
|
-
/** Forwarded to `OverlayHeader` — see its own `onBack` doc. Has no effect
|
|
28
|
-
* without `title`. */
|
|
29
|
-
onBack?: () => void;
|
|
30
|
-
/** Forwarded to `OverlayHeader`'s trailing-action slot. Has no effect
|
|
31
|
-
* without `title`. */
|
|
32
|
-
headerAction?: ReactNode;
|
|
33
|
-
/**
|
|
34
|
-
* Which edge the panel slides in from. Defaults to `'bottom'` (detail
|
|
35
|
-
* views, forms — content the user is reaching down into). `'top'` suits a
|
|
36
|
-
* short options/actions menu opened from a header button near the top of
|
|
37
|
-
* the screen, where sliding up from the bottom would travel past empty
|
|
38
|
-
* space before reaching content that visually belongs near the trigger.
|
|
39
|
-
*/
|
|
40
|
-
slideFrom?: 'bottom' | 'top';
|
|
41
|
-
children: ReactNode;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Sheet — a full-page overlay that replaces a plugin's content area between
|
|
46
|
-
* the shell's fixed header and footer (RFC 0013's mobile chrome stays visible
|
|
47
|
-
* and interactive around it), sliding in from an edge instead of centering
|
|
48
|
-
* like `Dialog`. Promoted from the tasks plugin's `MobileFullPageOverlay`
|
|
49
|
-
* (now the reference pattern for this component). Desktop has no equivalent
|
|
50
|
-
* presentation — a desktop layout shows the same content inline (columns,
|
|
51
|
-
* panes) instead of mounting a `Sheet` at all; this component is for the
|
|
52
|
-
* mobile case specifically.
|
|
53
|
-
*
|
|
54
|
-
* Unlike `Dialog`/`Drawer` there is no scrim: a Sheet visually *replaces* the
|
|
55
|
-
* region it covers rather than floating a layer above it, so there is no
|
|
56
|
-
* "outside" to tap-dismiss. Behaviour: Esc dismisses; focus moves into the
|
|
57
|
-
* panel on open and is restored on close; Tab is trapped within the panel;
|
|
58
|
-
* animated open/close via the same two-phase mount as `Dialog`/`Drawer`,
|
|
59
|
-
* respecting `prefers-reduced-motion`.
|
|
60
|
-
*/
|
|
61
|
-
export function Sheet({
|
|
62
|
-
open,
|
|
63
|
-
onClose,
|
|
64
|
-
'aria-label': ariaLabel,
|
|
65
|
-
title,
|
|
66
|
-
onBack,
|
|
67
|
-
headerAction,
|
|
68
|
-
slideFrom = 'bottom',
|
|
69
|
-
children,
|
|
70
|
-
}: SheetProps) {
|
|
71
|
-
const panelRef = useRef<HTMLDivElement>(null);
|
|
72
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
73
|
-
const { mounted, phase } = useMountTransition(
|
|
74
|
-
open,
|
|
75
|
-
reducedMotion ? 0 : OVERLAY_MOTION_DURATION_MS,
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
useOverlayScrollLock(mounted);
|
|
79
|
-
useOverlayFocusCapture(panelRef, mounted);
|
|
80
|
-
useOverlayKeyboardTrap(panelRef, open, onClose);
|
|
81
|
-
|
|
82
|
-
if (!mounted) return null;
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<div
|
|
86
|
-
ref={panelRef}
|
|
87
|
-
role="dialog"
|
|
88
|
-
aria-modal="true"
|
|
89
|
-
aria-label={ariaLabel ?? title}
|
|
90
|
-
tabIndex={-1}
|
|
91
|
-
className={[
|
|
92
|
-
styles.panel,
|
|
93
|
-
slideFrom === 'top' ? styles.panelFromTop : '',
|
|
94
|
-
phase === 'open' ? styles.panelOpen : '',
|
|
95
|
-
]
|
|
96
|
-
.filter(Boolean)
|
|
97
|
-
.join(' ')}
|
|
98
|
-
>
|
|
99
|
-
{title && (
|
|
100
|
-
<OverlayHeader title={title} onClose={onClose} onBack={onBack} action={headerAction} />
|
|
101
|
-
)}
|
|
102
|
-
{/* Content is always the scroll container — with or without a header —
|
|
103
|
-
so a header's sibling stays fixed and any content-owned internal
|
|
104
|
-
sticky positioning (e.g. a form's own sub-header) resolves against
|
|
105
|
-
this same scrolling ancestor either way. */}
|
|
106
|
-
<div className={styles.content}>{children}</div>
|
|
107
|
-
</div>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
-
import { Sheet } from '../Sheet';
|
|
5
|
-
|
|
6
|
-
// Sheet's exit animation reads prefers-reduced-motion via matchMedia, which
|
|
7
|
-
// jsdom does not implement — see Dialog.test.tsx's identical setup.
|
|
8
|
-
function installMatchMedia() {
|
|
9
|
-
vi.stubGlobal(
|
|
10
|
-
'matchMedia',
|
|
11
|
-
vi.fn().mockImplementation((query: string) => ({
|
|
12
|
-
matches: false,
|
|
13
|
-
media: query,
|
|
14
|
-
addEventListener: vi.fn(),
|
|
15
|
-
removeEventListener: vi.fn(),
|
|
16
|
-
addListener: vi.fn(),
|
|
17
|
-
removeListener: vi.fn(),
|
|
18
|
-
dispatchEvent: vi.fn(),
|
|
19
|
-
})),
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
describe('Sheet', () => {
|
|
24
|
-
beforeEach(installMatchMedia);
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
vi.unstubAllGlobals();
|
|
27
|
-
cleanup();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('renders nothing when closed', () => {
|
|
31
|
-
render(
|
|
32
|
-
<Sheet open={false} onClose={() => {}}>
|
|
33
|
-
Body
|
|
34
|
-
</Sheet>,
|
|
35
|
-
);
|
|
36
|
-
expect(screen.queryByRole('dialog')).toBeNull();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('renders the panel with its accessible name when open', () => {
|
|
40
|
-
render(
|
|
41
|
-
<Sheet open onClose={() => {}} aria-label="Task detail">
|
|
42
|
-
Body
|
|
43
|
-
</Sheet>,
|
|
44
|
-
);
|
|
45
|
-
const panel = screen.getByRole('dialog', { name: 'Task detail' });
|
|
46
|
-
expect(panel.getAttribute('aria-modal')).toBe('true');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('falls back to title for the accessible name when aria-label is omitted', () => {
|
|
50
|
-
render(
|
|
51
|
-
<Sheet open onClose={() => {}} title="Edit list">
|
|
52
|
-
Body
|
|
53
|
-
</Sheet>,
|
|
54
|
-
);
|
|
55
|
-
expect(screen.getByRole('dialog', { name: 'Edit list' })).toBeTruthy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('does not render OverlayHeader when title is omitted (headerless escape hatch)', () => {
|
|
59
|
-
render(
|
|
60
|
-
<Sheet open onClose={() => {}} aria-label="Custom">
|
|
61
|
-
<button type="button">Own close button</button>
|
|
62
|
-
</Sheet>,
|
|
63
|
-
);
|
|
64
|
-
// Only the content's own button — no OverlayHeader close button.
|
|
65
|
-
expect(screen.getAllByRole('button')).toHaveLength(1);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('renders OverlayHeader (title + close) when title is provided', () => {
|
|
69
|
-
const onClose = vi.fn();
|
|
70
|
-
render(
|
|
71
|
-
<Sheet open onClose={onClose} title="Edit list">
|
|
72
|
-
Body
|
|
73
|
-
</Sheet>,
|
|
74
|
-
);
|
|
75
|
-
expect(screen.getByText('Edit list')).toBeTruthy();
|
|
76
|
-
fireEvent.click(screen.getByRole('button', { name: 'Close' }));
|
|
77
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('calls onClose on Escape', () => {
|
|
81
|
-
const onClose = vi.fn();
|
|
82
|
-
render(
|
|
83
|
-
<Sheet open onClose={onClose} aria-label="Panel">
|
|
84
|
-
Body
|
|
85
|
-
</Sheet>,
|
|
86
|
-
);
|
|
87
|
-
fireEvent.keyDown(document, { key: 'Escape' });
|
|
88
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('applies the top slide-from variant class', () => {
|
|
92
|
-
render(
|
|
93
|
-
<Sheet open onClose={() => {}} aria-label="Menu" slideFrom="top">
|
|
94
|
-
Body
|
|
95
|
-
</Sheet>,
|
|
96
|
-
);
|
|
97
|
-
expect(screen.getByRole('dialog').className).toMatch(/panelFromTop/);
|
|
98
|
-
});
|
|
99
|
-
});
|