@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,67 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import type { ReactNode } from 'react';
|
|
4
|
-
import { Checkbox } from '../Checkbox/Checkbox';
|
|
5
|
-
import styles from './MemberMultiSelect.module.css';
|
|
6
|
-
|
|
7
|
-
export interface MemberMultiSelectOption {
|
|
8
|
-
id: string;
|
|
9
|
-
label: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface MemberMultiSelectProps {
|
|
13
|
-
options: MemberMultiSelectOption[];
|
|
14
|
-
selectedIds: Set<string>;
|
|
15
|
-
onToggle: (id: string, checked: boolean) => void;
|
|
16
|
-
/** Rendered to the right of a selected row only — e.g. a per-person `CurrencyInput` or share count. */
|
|
17
|
-
renderTrailing?: (id: string) => ReactNode;
|
|
18
|
-
/** Section label above the list, e.g. "Paid by" or "Split between". */
|
|
19
|
-
label?: string;
|
|
20
|
-
/** Helper/validation text below the list, e.g. a running total. */
|
|
21
|
-
hint?: ReactNode;
|
|
22
|
-
className?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* MemberMultiSelect — checkbox list for picking any number of people from an
|
|
27
|
-
* already-resolved set of options (group/project members, collaborators,
|
|
28
|
-
* etc.). Deliberately domain-agnostic about *who* an option represents —
|
|
29
|
-
* instance users and guest members are both just `{id, label}` here, so
|
|
30
|
-
* nothing special is needed to include guests alongside instance users; the
|
|
31
|
-
* caller's `options` array is the only place that distinction exists.
|
|
32
|
-
*
|
|
33
|
-
* Not a directory search or an "add a new guest" flow — pair with
|
|
34
|
-
* `SuggestionInput` (search + add) for that; this component only selects
|
|
35
|
-
* among options already passed in.
|
|
36
|
-
*/
|
|
37
|
-
export function MemberMultiSelect({
|
|
38
|
-
options,
|
|
39
|
-
selectedIds,
|
|
40
|
-
onToggle,
|
|
41
|
-
renderTrailing,
|
|
42
|
-
label,
|
|
43
|
-
hint,
|
|
44
|
-
className,
|
|
45
|
-
}: MemberMultiSelectProps) {
|
|
46
|
-
return (
|
|
47
|
-
<div className={[styles.group, className].filter(Boolean).join(' ')}>
|
|
48
|
-
{label && <span className={styles.label}>{label}</span>}
|
|
49
|
-
{options.map((option) => {
|
|
50
|
-
const checked = selectedIds.has(option.id);
|
|
51
|
-
return (
|
|
52
|
-
<div key={option.id} className={styles.row}>
|
|
53
|
-
<Checkbox
|
|
54
|
-
checked={checked}
|
|
55
|
-
onChange={(next) => onToggle(option.id, next)}
|
|
56
|
-
label={option.label}
|
|
57
|
-
/>
|
|
58
|
-
{checked && renderTrailing && (
|
|
59
|
-
<span className={styles.trailing}>{renderTrailing(option.id)}</span>
|
|
60
|
-
)}
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
})}
|
|
64
|
-
{hint && <span className={styles.hint}>{hint}</span>}
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/* Menu — the item list shared by both presentations (Popover panel on
|
|
2
|
-
* desktop, Drawer panel on mobile); the presentational chrome around it is
|
|
3
|
-
* entirely owned by those two components, not duplicated here.
|
|
4
|
-
*
|
|
5
|
-
* Sizing audit: reviewed against this scale's other compact controls —
|
|
6
|
-
* --sv-radius-sm (6px) and --sv-font-size-sm (14px) already fit. The 44px
|
|
7
|
-
* min-height is a deliberate design choice, kept unconditional (not gated
|
|
8
|
-
* to pointer:coarse like Button/Checkbox) because this menu doubles as a
|
|
9
|
-
* full Drawer sheet on mobile, where every item must stay comfortably
|
|
10
|
-
* tappable. */
|
|
11
|
-
|
|
12
|
-
.list {
|
|
13
|
-
list-style: none;
|
|
14
|
-
margin: 0;
|
|
15
|
-
padding: var(--sv-space-1);
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.item {
|
|
21
|
-
display: flex;
|
|
22
|
-
align-items: center;
|
|
23
|
-
gap: var(--sv-space-2);
|
|
24
|
-
width: 100%;
|
|
25
|
-
/* Min touch target (WCAG 2.5.5 / Apple HIG) — this menu renders as a
|
|
26
|
-
Drawer sheet on mobile, so every item must be comfortably tappable. */
|
|
27
|
-
min-height: var(--sv-touch-target-min, 44px);
|
|
28
|
-
padding: var(--sv-space-2) var(--sv-space-3);
|
|
29
|
-
border: none;
|
|
30
|
-
border-radius: var(--sv-radius-sm);
|
|
31
|
-
background: transparent;
|
|
32
|
-
color: var(--sv-color-text-primary);
|
|
33
|
-
font: inherit;
|
|
34
|
-
font-size: var(--sv-font-size-sm);
|
|
35
|
-
text-align: left;
|
|
36
|
-
text-decoration: none;
|
|
37
|
-
cursor: pointer;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@media (hover: hover) {
|
|
41
|
-
.item:hover:not(:disabled) {
|
|
42
|
-
background: var(--sv-color-surface-sunken);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.item:focus-visible {
|
|
47
|
-
outline: 2px solid var(--sv-color-focus-ring);
|
|
48
|
-
outline-offset: -2px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.item:disabled {
|
|
52
|
-
opacity: 0.5;
|
|
53
|
-
cursor: not-allowed;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.itemDestructive {
|
|
57
|
-
color: var(--sv-color-error-text);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@media (hover: hover) {
|
|
61
|
-
.itemDestructive:hover:not(:disabled) {
|
|
62
|
-
background: var(--sv-color-error-surface);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Reserved checkmark gutter for a checkable item — sized so unchecked
|
|
67
|
-
siblings in the same group still align with the checked one's icon. */
|
|
68
|
-
.check {
|
|
69
|
-
display: inline-flex;
|
|
70
|
-
flex-shrink: 0;
|
|
71
|
-
width: var(--sv-icon-size-sm);
|
|
72
|
-
height: var(--sv-icon-size-sm);
|
|
73
|
-
align-items: center;
|
|
74
|
-
justify-content: center;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.label {
|
|
78
|
-
padding: var(--sv-space-2) var(--sv-space-3) var(--sv-space-1);
|
|
79
|
-
font-size: var(--sv-font-size-label);
|
|
80
|
-
font-weight: var(--sv-font-weight-semibold);
|
|
81
|
-
color: var(--sv-color-text-muted);
|
|
82
|
-
text-transform: uppercase;
|
|
83
|
-
letter-spacing: 0.04em;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.separator {
|
|
87
|
-
height: 1px;
|
|
88
|
-
margin: var(--sv-space-1) var(--sv-space-2);
|
|
89
|
-
background: var(--sv-color-border);
|
|
90
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import type { ReactElement } from 'react';
|
|
4
|
-
import { useIsMobile } from '../../hooks';
|
|
5
|
-
import { Drawer } from '../Drawer/Drawer';
|
|
6
|
-
import { Icon, type IconName } from '../Icon/Icon';
|
|
7
|
-
import { Popover } from '../Popover/Popover';
|
|
8
|
-
import styles from './Menu.module.css';
|
|
9
|
-
|
|
10
|
-
export interface MenuItem {
|
|
11
|
-
type?: 'item';
|
|
12
|
-
label: string;
|
|
13
|
-
/** Optional when `href` is provided (a pure navigation entry needs no
|
|
14
|
-
* extra callback) — required otherwise. Called before the surface closes
|
|
15
|
-
* is the caller's job to avoid; `Menu`'s own wiring always closes first,
|
|
16
|
-
* then calls this. */
|
|
17
|
-
onSelect?: () => void;
|
|
18
|
-
/** Renders the entry as a link (`<a href>`, `role="menuitem"`) instead of
|
|
19
|
-
* a `<button>` — same href-vs-onClick convention as `MobileAppsDrawer`'s
|
|
20
|
-
* items. Framework-agnostic (a plain anchor, not `next/link`), matching
|
|
21
|
-
* every other `packages/ui` href slot. */
|
|
22
|
-
href?: string;
|
|
23
|
-
icon?: IconName;
|
|
24
|
-
/** Styles the item as a destructive action (e.g. "Delete list"). */
|
|
25
|
-
destructive?: boolean;
|
|
26
|
-
disabled?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Marks the item as one of a mutually-exclusive set (e.g. the active sort
|
|
29
|
-
* order) — renders a leading checkmark and `role="menuitemradio"` instead
|
|
30
|
-
* of `role="menuitem"`. Pass this on every item in the group, including
|
|
31
|
-
* the unchecked ones, so their labels stay aligned with the checked one's
|
|
32
|
-
* reserved checkmark gutter. Omit entirely for plain action items (e.g.
|
|
33
|
-
* "Delete list") — they render with no reserved leading space at all.
|
|
34
|
-
*/
|
|
35
|
-
checked?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** A non-interactive section heading above a run of items (e.g. "Sort by"). */
|
|
39
|
-
export interface MenuLabel {
|
|
40
|
-
type: 'label';
|
|
41
|
-
label: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** A visual divider between sections. */
|
|
45
|
-
export interface MenuSeparator {
|
|
46
|
-
type: 'separator';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export type MenuEntry = MenuItem | MenuLabel | MenuSeparator;
|
|
50
|
-
|
|
51
|
-
export interface MenuProps {
|
|
52
|
-
/** The element that opens the menu — rendered as-is; the caller wires its
|
|
53
|
-
* onClick to flip `open` (same controlled pattern as `Popover`). */
|
|
54
|
-
trigger: ReactElement;
|
|
55
|
-
open: boolean;
|
|
56
|
-
onClose: () => void;
|
|
57
|
-
items: MenuEntry[];
|
|
58
|
-
'aria-label': string;
|
|
59
|
-
/** Forwarded to `Popover` on desktop. Has no effect on mobile, where the
|
|
60
|
-
* menu is always a full-width `Drawer`. */
|
|
61
|
-
align?: 'left' | 'right';
|
|
62
|
-
/** Forwarded to `Popover` on desktop (same default: 288). Has no effect
|
|
63
|
-
* on mobile. Narrow this when the trigger lives inside a column
|
|
64
|
-
* narrower than the default width — e.g. a per-row "⋯" menu in a
|
|
65
|
-
* sidebar list — so the panel fits within that column's own bounds
|
|
66
|
-
* instead of overflowing past its edge, where a scrollable ancestor's
|
|
67
|
-
* `overflow-y: auto` (which the CSS Overflow spec computes the paired
|
|
68
|
-
* `overflow-x` to `auto` as well, not `visible`, once either axis is
|
|
69
|
-
* set) would clip it. */
|
|
70
|
-
width?: number | 'trigger';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Menu — an adaptive action menu: `Popover` on desktop, a bottom-sheet
|
|
75
|
-
* `Drawer` on mobile. Replaces the desktop-Popover/mobile-Drawer fork that
|
|
76
|
-
* `⋯` action menus (list options, row actions) otherwise re-derive per
|
|
77
|
-
* plugin. Same list of `items` renders in both presentations — only the
|
|
78
|
-
* surrounding chrome (floating panel vs. bottom sheet) differs, matching the
|
|
79
|
-
* platform's `useIsMobile` breakpoint.
|
|
80
|
-
*
|
|
81
|
-
* `items` accepts three entry shapes: a plain action (`MenuItem`, `type`
|
|
82
|
-
* omitted or `'item'`), a non-interactive section heading (`MenuLabel`,
|
|
83
|
-
* `type: 'label'`), and a `MenuSeparator` (`type: 'separator'`) — enough to
|
|
84
|
-
* express grouped sections like "Filter" / "Sort by" above a run of
|
|
85
|
-
* destructive actions, matching how native OS menus lay out mixed
|
|
86
|
-
* action/selection groups.
|
|
87
|
-
*
|
|
88
|
-
* Selecting an item both closes the menu and calls its `onSelect` — a
|
|
89
|
-
* consumer's `onSelect` never needs to call `onClose` itself.
|
|
90
|
-
*/
|
|
91
|
-
/**
|
|
92
|
-
* MenuEntries — the `<ul role="menu">` item list itself, factored out of
|
|
93
|
-
* `Menu` so other adaptive-surface components (e.g. `ContextMenu`) can
|
|
94
|
-
* render the exact same items/destructive/checked/icon markup inside their
|
|
95
|
-
* own positioning shell, instead of re-deriving it and risking drift.
|
|
96
|
-
*/
|
|
97
|
-
export function MenuEntries({
|
|
98
|
-
items,
|
|
99
|
-
onSelect,
|
|
100
|
-
}: {
|
|
101
|
-
items: MenuEntry[];
|
|
102
|
-
/** Called after an item's own onSelect — typically the surface's onClose. */
|
|
103
|
-
onSelect: (entry: MenuItem) => void;
|
|
104
|
-
}) {
|
|
105
|
-
return (
|
|
106
|
-
<ul className={styles.list} role="menu">
|
|
107
|
-
{items.map((entry, index) => {
|
|
108
|
-
// Entries are a static, order-stable list per render — nothing
|
|
109
|
-
// reorders — so an index key is safe here.
|
|
110
|
-
if (entry.type === 'separator') {
|
|
111
|
-
return <li key={index} role="separator" className={styles.separator} />;
|
|
112
|
-
}
|
|
113
|
-
if (entry.type === 'label') {
|
|
114
|
-
return (
|
|
115
|
-
<li key={index} role="presentation" className={styles.label}>
|
|
116
|
-
{entry.label}
|
|
117
|
-
</li>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
const isCheckable = entry.checked !== undefined;
|
|
121
|
-
const className = [styles.item, entry.destructive ? styles.itemDestructive : '']
|
|
122
|
-
.filter(Boolean)
|
|
123
|
-
.join(' ');
|
|
124
|
-
const content = (
|
|
125
|
-
<>
|
|
126
|
-
{isCheckable && (
|
|
127
|
-
<span className={styles.check} aria-hidden>
|
|
128
|
-
{entry.checked && <Icon name="check" size="sm" aria-hidden />}
|
|
129
|
-
</span>
|
|
130
|
-
)}
|
|
131
|
-
{entry.icon && <Icon name={entry.icon} size="sm" aria-hidden />}
|
|
132
|
-
{entry.label}
|
|
133
|
-
</>
|
|
134
|
-
);
|
|
135
|
-
return (
|
|
136
|
-
<li key={index} role="none">
|
|
137
|
-
{entry.href ? (
|
|
138
|
-
<a
|
|
139
|
-
role="menuitem"
|
|
140
|
-
href={entry.href}
|
|
141
|
-
className={className}
|
|
142
|
-
onClick={() => onSelect(entry)}
|
|
143
|
-
>
|
|
144
|
-
{content}
|
|
145
|
-
</a>
|
|
146
|
-
) : (
|
|
147
|
-
<button
|
|
148
|
-
role={isCheckable ? 'menuitemradio' : 'menuitem'}
|
|
149
|
-
aria-checked={isCheckable ? entry.checked : undefined}
|
|
150
|
-
type="button"
|
|
151
|
-
className={className}
|
|
152
|
-
disabled={entry.disabled}
|
|
153
|
-
onClick={() => onSelect(entry)}
|
|
154
|
-
>
|
|
155
|
-
{content}
|
|
156
|
-
</button>
|
|
157
|
-
)}
|
|
158
|
-
</li>
|
|
159
|
-
);
|
|
160
|
-
})}
|
|
161
|
-
</ul>
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export function Menu({
|
|
166
|
-
trigger,
|
|
167
|
-
open,
|
|
168
|
-
onClose,
|
|
169
|
-
items,
|
|
170
|
-
'aria-label': ariaLabel,
|
|
171
|
-
align,
|
|
172
|
-
width,
|
|
173
|
-
}: MenuProps) {
|
|
174
|
-
const isMobile = useIsMobile();
|
|
175
|
-
|
|
176
|
-
const list = (
|
|
177
|
-
<MenuEntries
|
|
178
|
-
items={items}
|
|
179
|
-
onSelect={(entry) => {
|
|
180
|
-
onClose();
|
|
181
|
-
entry.onSelect?.();
|
|
182
|
-
}}
|
|
183
|
-
/>
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
if (isMobile) {
|
|
187
|
-
return (
|
|
188
|
-
<>
|
|
189
|
-
{trigger}
|
|
190
|
-
<Drawer open={open} onClose={onClose} aria-label={ariaLabel}>
|
|
191
|
-
{list}
|
|
192
|
-
</Drawer>
|
|
193
|
-
</>
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return (
|
|
198
|
-
<Popover
|
|
199
|
-
trigger={trigger}
|
|
200
|
-
open={open}
|
|
201
|
-
onClose={onClose}
|
|
202
|
-
aria-label={ariaLabel}
|
|
203
|
-
align={align}
|
|
204
|
-
width={width}
|
|
205
|
-
>
|
|
206
|
-
{list}
|
|
207
|
-
</Popover>
|
|
208
|
-
);
|
|
209
|
-
}
|
|
@@ -1,227 +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 { Menu, type MenuItem } from '../Menu';
|
|
5
|
-
|
|
6
|
-
let mobile = false;
|
|
7
|
-
function installMatchMedia() {
|
|
8
|
-
vi.stubGlobal(
|
|
9
|
-
'matchMedia',
|
|
10
|
-
vi.fn().mockImplementation((query: string) => ({
|
|
11
|
-
// useIsMobile's query is '(max-width: ...)'; everything else (e.g.
|
|
12
|
-
// Drawer's prefers-reduced-motion check) defaults to false so the
|
|
13
|
-
// mobile-branch Drawer isn't accidentally forced into the
|
|
14
|
-
// reduced-motion path.
|
|
15
|
-
matches: query.includes('max-width') ? mobile : false,
|
|
16
|
-
media: query,
|
|
17
|
-
addEventListener: vi.fn(),
|
|
18
|
-
removeEventListener: vi.fn(),
|
|
19
|
-
addListener: vi.fn(),
|
|
20
|
-
removeListener: vi.fn(),
|
|
21
|
-
dispatchEvent: vi.fn(),
|
|
22
|
-
})),
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function installPointerCapture() {
|
|
27
|
-
if (!Element.prototype.setPointerCapture) {
|
|
28
|
-
Element.prototype.setPointerCapture = () => {};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const items: MenuItem[] = [
|
|
33
|
-
{ label: 'Rename', onSelect: vi.fn() },
|
|
34
|
-
{ label: 'Delete', onSelect: vi.fn(), destructive: true },
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
describe('Menu', () => {
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
mobile = false;
|
|
40
|
-
installMatchMedia();
|
|
41
|
-
installPointerCapture();
|
|
42
|
-
});
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
vi.unstubAllGlobals();
|
|
45
|
-
cleanup();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('renders the trigger regardless of open state', () => {
|
|
49
|
-
render(
|
|
50
|
-
<Menu
|
|
51
|
-
trigger={<button type="button">Open menu</button>}
|
|
52
|
-
open={false}
|
|
53
|
-
onClose={() => {}}
|
|
54
|
-
items={items}
|
|
55
|
-
aria-label="List actions"
|
|
56
|
-
/>,
|
|
57
|
-
);
|
|
58
|
-
expect(screen.getByRole('button', { name: 'Open menu' })).toBeTruthy();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('renders as a Popover on desktop', () => {
|
|
62
|
-
render(
|
|
63
|
-
<Menu
|
|
64
|
-
trigger={<button type="button">Open menu</button>}
|
|
65
|
-
open
|
|
66
|
-
onClose={() => {}}
|
|
67
|
-
items={items}
|
|
68
|
-
aria-label="List actions"
|
|
69
|
-
/>,
|
|
70
|
-
);
|
|
71
|
-
const menu = screen.getByRole('dialog', { name: 'List actions' });
|
|
72
|
-
// Popover's own aria-modal is explicitly false (non-modal floating panel).
|
|
73
|
-
expect(menu.getAttribute('aria-modal')).toBe('false');
|
|
74
|
-
expect(screen.getByRole('menuitem', { name: 'Rename' })).toBeTruthy();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('renders as a Drawer on mobile', () => {
|
|
78
|
-
mobile = true;
|
|
79
|
-
installMatchMedia();
|
|
80
|
-
render(
|
|
81
|
-
<Menu
|
|
82
|
-
trigger={<button type="button">Open menu</button>}
|
|
83
|
-
open
|
|
84
|
-
onClose={() => {}}
|
|
85
|
-
items={items}
|
|
86
|
-
aria-label="List actions"
|
|
87
|
-
/>,
|
|
88
|
-
);
|
|
89
|
-
const menu = screen.getByRole('dialog', { name: 'List actions' });
|
|
90
|
-
expect(menu.getAttribute('aria-modal')).toBe('true');
|
|
91
|
-
expect(screen.getByRole('menuitem', { name: 'Rename' })).toBeTruthy();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('calls both onClose and the item onSelect when an item is chosen', () => {
|
|
95
|
-
const onClose = vi.fn();
|
|
96
|
-
const onSelect = vi.fn();
|
|
97
|
-
render(
|
|
98
|
-
<Menu
|
|
99
|
-
trigger={<button type="button">Open menu</button>}
|
|
100
|
-
open
|
|
101
|
-
onClose={onClose}
|
|
102
|
-
items={[{ label: 'Rename', onSelect }]}
|
|
103
|
-
aria-label="List actions"
|
|
104
|
-
/>,
|
|
105
|
-
);
|
|
106
|
-
fireEvent.click(screen.getByRole('menuitem', { name: 'Rename' }));
|
|
107
|
-
expect(onSelect).toHaveBeenCalledOnce();
|
|
108
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('disables an item and does not fire onSelect when clicked', () => {
|
|
112
|
-
const onSelect = vi.fn();
|
|
113
|
-
render(
|
|
114
|
-
<Menu
|
|
115
|
-
trigger={<button type="button">Open menu</button>}
|
|
116
|
-
open
|
|
117
|
-
onClose={() => {}}
|
|
118
|
-
items={[{ label: 'Archive', onSelect, disabled: true }]}
|
|
119
|
-
aria-label="List actions"
|
|
120
|
-
/>,
|
|
121
|
-
);
|
|
122
|
-
fireEvent.click(screen.getByRole('menuitem', { name: 'Archive' }));
|
|
123
|
-
expect(onSelect).not.toHaveBeenCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('marks a destructive item distinctly from a default one', () => {
|
|
127
|
-
render(
|
|
128
|
-
<Menu
|
|
129
|
-
trigger={<button type="button">Open menu</button>}
|
|
130
|
-
open
|
|
131
|
-
onClose={() => {}}
|
|
132
|
-
items={items}
|
|
133
|
-
aria-label="List actions"
|
|
134
|
-
/>,
|
|
135
|
-
);
|
|
136
|
-
const renameClass = screen.getByRole('menuitem', { name: 'Rename' }).className;
|
|
137
|
-
const deleteClass = screen.getByRole('menuitem', { name: 'Delete' }).className;
|
|
138
|
-
expect(deleteClass).not.toBe(renameClass);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('renders section labels and separators as non-interactive entries', () => {
|
|
142
|
-
render(
|
|
143
|
-
<Menu
|
|
144
|
-
trigger={<button type="button">Open menu</button>}
|
|
145
|
-
open
|
|
146
|
-
onClose={() => {}}
|
|
147
|
-
items={[
|
|
148
|
-
{ type: 'label', label: 'Sort by' },
|
|
149
|
-
{ label: 'Title', onSelect: vi.fn(), checked: true },
|
|
150
|
-
{ type: 'separator' },
|
|
151
|
-
{ label: 'Delete list', onSelect: vi.fn(), destructive: true },
|
|
152
|
-
]}
|
|
153
|
-
aria-label="List actions"
|
|
154
|
-
/>,
|
|
155
|
-
);
|
|
156
|
-
expect(screen.getByText('Sort by').getAttribute('role')).toBe('presentation');
|
|
157
|
-
expect(screen.getByRole('separator')).toBeTruthy();
|
|
158
|
-
// Only the plain action item is a plain menuitem; the checkable one is a menuitemradio.
|
|
159
|
-
expect(screen.getAllByRole('menuitem')).toHaveLength(1);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('renders a checkable item as menuitemradio with aria-checked', () => {
|
|
163
|
-
render(
|
|
164
|
-
<Menu
|
|
165
|
-
trigger={<button type="button">Open menu</button>}
|
|
166
|
-
open
|
|
167
|
-
onClose={() => {}}
|
|
168
|
-
items={[
|
|
169
|
-
{ label: 'Manual', onSelect: vi.fn(), checked: false },
|
|
170
|
-
{ label: 'Title', onSelect: vi.fn(), checked: true },
|
|
171
|
-
]}
|
|
172
|
-
aria-label="List actions"
|
|
173
|
-
/>,
|
|
174
|
-
);
|
|
175
|
-
const unchecked = screen.getByRole('menuitemradio', { name: 'Manual' });
|
|
176
|
-
const checked = screen.getByRole('menuitemradio', { name: 'Title' });
|
|
177
|
-
expect(unchecked.getAttribute('aria-checked')).toBe('false');
|
|
178
|
-
expect(checked.getAttribute('aria-checked')).toBe('true');
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('closes and selects when a checkable item is clicked', () => {
|
|
182
|
-
const onClose = vi.fn();
|
|
183
|
-
const onSelect = vi.fn();
|
|
184
|
-
render(
|
|
185
|
-
<Menu
|
|
186
|
-
trigger={<button type="button">Open menu</button>}
|
|
187
|
-
open
|
|
188
|
-
onClose={onClose}
|
|
189
|
-
items={[{ label: 'Title', onSelect, checked: false }]}
|
|
190
|
-
aria-label="List actions"
|
|
191
|
-
/>,
|
|
192
|
-
);
|
|
193
|
-
fireEvent.click(screen.getByRole('menuitemradio', { name: 'Title' }));
|
|
194
|
-
expect(onSelect).toHaveBeenCalledOnce();
|
|
195
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it('renders an item with href as a link, not a button', () => {
|
|
199
|
-
render(
|
|
200
|
-
<Menu
|
|
201
|
-
trigger={<button type="button">Open menu</button>}
|
|
202
|
-
open
|
|
203
|
-
onClose={() => {}}
|
|
204
|
-
items={[{ label: 'Account', href: '/account' }]}
|
|
205
|
-
aria-label="List actions"
|
|
206
|
-
/>,
|
|
207
|
-
);
|
|
208
|
-
const link = screen.getByRole('menuitem', { name: 'Account' });
|
|
209
|
-
expect(link.tagName).toBe('A');
|
|
210
|
-
expect(link.getAttribute('href')).toBe('/account');
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('closes on click of an href item even with no onSelect', () => {
|
|
214
|
-
const onClose = vi.fn();
|
|
215
|
-
render(
|
|
216
|
-
<Menu
|
|
217
|
-
trigger={<button type="button">Open menu</button>}
|
|
218
|
-
open
|
|
219
|
-
onClose={onClose}
|
|
220
|
-
items={[{ label: 'Account', href: '/account' }]}
|
|
221
|
-
aria-label="List actions"
|
|
222
|
-
/>,
|
|
223
|
-
);
|
|
224
|
-
fireEvent.click(screen.getByRole('menuitem', { name: 'Account' }));
|
|
225
|
-
expect(onClose).toHaveBeenCalledOnce();
|
|
226
|
-
});
|
|
227
|
-
});
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
import { Menubar } from './Menubar';
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: 'Components/Menubar',
|
|
6
|
-
component: Menubar,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: 'padded',
|
|
9
|
-
docs: {
|
|
10
|
-
description: {
|
|
11
|
-
component:
|
|
12
|
-
"Desktop app-style menu bar (File/Edit/View...). A thin composition of NavigationMenu with MenuEntries as each item's flyout content — no positioning or list-rendering logic duplicated.",
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
} satisfies Meta<typeof Menubar>;
|
|
17
|
-
|
|
18
|
-
export default meta;
|
|
19
|
-
type Story = StoryObj<typeof meta>;
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
|
|
23
|
-
export const Default: Story = {
|
|
24
|
-
args: {
|
|
25
|
-
menus: [
|
|
26
|
-
{
|
|
27
|
-
label: 'File',
|
|
28
|
-
items: [
|
|
29
|
-
{ label: 'New conversation', onSelect: () => {} },
|
|
30
|
-
{ label: 'Export', onSelect: () => {} },
|
|
31
|
-
{ type: 'separator' },
|
|
32
|
-
{ label: 'Close', onSelect: () => {} },
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
label: 'Edit',
|
|
37
|
-
items: [
|
|
38
|
-
{ label: 'Undo', onSelect: () => {} },
|
|
39
|
-
{ label: 'Redo', onSelect: () => {} },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
label: 'View',
|
|
44
|
-
items: [
|
|
45
|
-
{ type: 'label', label: 'Layout' },
|
|
46
|
-
{ label: 'Compact', checked: false, onSelect: () => {} },
|
|
47
|
-
{ label: 'Comfortable', checked: true, onSelect: () => {} },
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { NavigationMenu } from '../NavigationMenu/NavigationMenu';
|
|
4
|
-
import { MenuEntries, type MenuEntry } from '../Menu/Menu';
|
|
5
|
-
|
|
6
|
-
export interface MenubarMenu {
|
|
7
|
-
label: string;
|
|
8
|
-
items: MenuEntry[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface MenubarProps {
|
|
12
|
-
menus: MenubarMenu[];
|
|
13
|
-
'aria-label'?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Menubar — desktop app-style menu bar (File / Edit / View...). A thin
|
|
18
|
-
* composition of `NavigationMenu` (top-level triggers, per-item flyout
|
|
19
|
-
* positioning, hover-switches-when-one-is-open, arrow-key navigation) with
|
|
20
|
-
* `MenuEntries` (the same item list markup `Menu`'s dropdowns use) as each
|
|
21
|
-
* item's flyout content — no positioning or list-rendering logic
|
|
22
|
-
* duplicated from either.
|
|
23
|
-
*/
|
|
24
|
-
export function Menubar({ menus, 'aria-label': ariaLabel = 'Menu bar' }: MenubarProps) {
|
|
25
|
-
return (
|
|
26
|
-
<NavigationMenu
|
|
27
|
-
aria-label={ariaLabel}
|
|
28
|
-
items={menus.map((menu) => ({
|
|
29
|
-
label: menu.label,
|
|
30
|
-
content: (close: () => void) => (
|
|
31
|
-
<MenuEntries
|
|
32
|
-
items={menu.items}
|
|
33
|
-
onSelect={(entry) => {
|
|
34
|
-
close();
|
|
35
|
-
entry.onSelect?.();
|
|
36
|
-
}}
|
|
37
|
-
/>
|
|
38
|
-
),
|
|
39
|
-
}))}
|
|
40
|
-
/>
|
|
41
|
-
);
|
|
42
|
-
}
|