@dxos/react-ui 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a
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 +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/chunk-A5QCIG5R.mjs +24 -0
- package/dist/lib/browser/chunk-A5QCIG5R.mjs.map +7 -0
- package/dist/lib/browser/{chunk-2FKSMWNY.mjs → chunk-LY5XDQR5.mjs} +84 -12
- package/dist/lib/browser/chunk-LY5XDQR5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1559 -1062
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +44 -20
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/browser/translations.mjs +9 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ZNBLTSHI.mjs → chunk-NGKLIKP3.mjs} +84 -12
- package/dist/lib/node-esm/chunk-NGKLIKP3.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-XCFLA74M.mjs +26 -0
- package/dist/lib/node-esm/chunk-XCFLA74M.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1559 -1062
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +44 -20
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/lib/node-esm/translations.mjs +10 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/Avatars/Avatar.d.ts +1 -1
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
- package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/Button.d.ts +2 -2
- package/dist/types/src/components/Button/Button.d.ts.map +1 -1
- package/dist/types/src/components/Button/Button.stories.d.ts +1 -1
- package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/IconButton.d.ts +1 -0
- package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Button/IconButton.stories.d.ts +3 -0
- package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/Toggle.d.ts +2 -2
- package/dist/types/src/components/Button/Toggle.d.ts.map +1 -1
- package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -1
- package/dist/types/src/components/Button/ToggleGroup.d.ts +6 -6
- package/dist/types/src/components/Button/ToggleGroup.d.ts.map +1 -1
- package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +2 -2
- package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -1
- package/dist/types/src/components/Card/Card.d.ts +68 -65
- package/dist/types/src/components/Card/Card.d.ts.map +1 -1
- package/dist/types/src/components/Card/Card.stories.d.ts +2 -2
- package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
- package/dist/types/src/components/Carousel/Carousel.d.ts +106 -0
- package/dist/types/src/components/Carousel/Carousel.d.ts.map +1 -0
- package/dist/types/src/components/Carousel/index.d.ts +2 -0
- package/dist/types/src/components/Carousel/index.d.ts.map +1 -0
- package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
- package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
- package/dist/types/src/components/Clipboard/index.d.ts +10 -1
- package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
- package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/AlertDialog.d.ts +42 -31
- package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.d.ts +47 -30
- package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts +3 -2
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +14 -3
- package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -1
- package/dist/types/src/components/Focus/Focus.d.ts +36 -0
- package/dist/types/src/components/Focus/Focus.d.ts.map +1 -0
- package/dist/types/src/components/Focus/Focus.stories.d.ts +9 -0
- package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -0
- package/dist/types/src/components/Focus/index.d.ts +2 -0
- package/dist/types/src/components/Focus/index.d.ts.map +1 -0
- package/dist/types/src/components/Icon/Icon.d.ts +4 -0
- package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
- package/dist/types/src/components/Icon/Icon.stories.d.ts +11 -3
- package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
- package/dist/types/src/components/Image/Image.d.ts +2 -1
- package/dist/types/src/components/Image/Image.d.ts.map +1 -1
- package/dist/types/src/components/Image/Image.stories.d.ts +3 -2
- package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts +14 -17
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +3 -3
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/Link/Link.d.ts.map +1 -1
- package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts +5 -3
- package/dist/types/src/components/List/List.d.ts.map +1 -1
- package/dist/types/src/components/List/List.stories.d.ts +3 -1
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/ListDropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/List/Tree.d.ts +2 -2
- package/dist/types/src/components/List/Tree.d.ts.map +1 -1
- package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/List/Treegrid.d.ts +5 -9
- package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
- package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.d.ts +7 -3
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
- package/dist/types/src/components/Main/useSwipeToDismiss.d.ts.map +1 -1
- package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts +46 -0
- package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts.map +1 -0
- package/dist/types/src/components/MediaPlayer/MediaPlayer.stories.d.ts +16 -0
- package/dist/types/src/components/MediaPlayer/MediaPlayer.stories.d.ts.map +1 -0
- package/dist/types/src/components/MediaPlayer/index.d.ts +2 -0
- package/dist/types/src/components/MediaPlayer/index.d.ts.map +1 -0
- package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Menu/DropdownMenu.d.ts +58 -49
- package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts +14 -1
- package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.d.ts +1 -1
- package/dist/types/src/components/Message/Message.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.stories.d.ts +2 -2
- package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts +38 -22
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +12 -11
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +21 -10
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +42 -13
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +5 -6
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.stories.d.ts +2 -2
- package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
- package/dist/types/src/components/Separator/Separator.d.ts +3 -3
- package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
- package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -1
- package/dist/types/src/components/Splitter/Splitter.d.ts +19 -21
- package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -1
- package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
- package/dist/types/src/components/Status/Status.d.ts +3 -4
- package/dist/types/src/components/Status/Status.d.ts.map +1 -1
- package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +54 -55
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/Toast/Toast.d.ts +16 -16
- package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
- package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +10 -20
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts +16 -16
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +2 -2
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +3 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/exemplars/generics.stories.d.ts +6 -5
- package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/slot.stories.d.ts +1 -0
- package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -1
- package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useDensityContext.d.ts +1 -1
- package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
- package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -1
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -1
- package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
- package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
- package/dist/types/src/playground/Custom.stories.d.ts +1 -1
- package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
- package/dist/types/src/playground/Typography.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Column/Column.d.ts +20 -19
- package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
- package/dist/types/src/primitives/Column/Column.stories.d.ts +19 -0
- package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Container/Container.d.ts +7 -0
- package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
- package/dist/types/src/primitives/Container/Container.stories.d.ts +6 -0
- package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Container/index.d.ts +2 -0
- package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
- package/dist/types/src/primitives/Flex/Flex.d.ts +8 -5
- package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -1
- package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Grid/Grid.d.ts +6 -5
- package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -1
- package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Panel/Panel.d.ts +23 -22
- package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
- package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/index.d.ts +1 -0
- package/dist/types/src/primitives/index.d.ts.map +1 -1
- package/dist/types/src/testing/Loading.d.ts +9 -0
- package/dist/types/src/testing/Loading.d.ts.map +1 -0
- package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withTheme.d.ts +1 -1
- package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +8 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/usePx.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -26
- package/src/components/Avatars/Avatar.stories.tsx +2 -3
- package/src/components/Avatars/Avatar.tsx +1 -2
- package/src/components/Avatars/AvatarGroup.stories.tsx +0 -1
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -2
- package/src/components/Button/Button.stories.tsx +0 -1
- package/src/components/Button/Button.tsx +5 -13
- package/src/components/Button/IconButton.stories.tsx +6 -4
- package/src/components/Button/IconButton.tsx +3 -4
- package/src/components/Button/Toggle.stories.tsx +0 -1
- package/src/components/Button/Toggle.tsx +4 -4
- package/src/components/Button/ToggleGroup.stories.tsx +0 -1
- package/src/components/Button/ToggleGroup.tsx +12 -16
- package/src/components/Card/Card.stories.tsx +15 -15
- package/src/components/Card/Card.tsx +294 -132
- package/src/components/Carousel/Carousel.tsx +379 -0
- package/src/components/Carousel/index.ts +5 -0
- package/src/components/Clipboard/CopyButton.tsx +5 -6
- package/src/components/Dialog/AlertDialog.stories.tsx +5 -6
- package/src/components/Dialog/AlertDialog.tsx +67 -126
- package/src/components/Dialog/Dialog.stories.tsx +64 -9
- package/src/components/Dialog/Dialog.tsx +84 -88
- package/src/components/ErrorFallback/ErrorFallback.stories.tsx +3 -8
- package/src/components/ErrorFallback/ErrorStack.tsx +36 -2
- package/src/components/Focus/AUDIT.md +43 -0
- package/src/components/Focus/Focus.stories.tsx +230 -0
- package/src/components/Focus/Focus.tsx +201 -0
- package/src/components/Focus/index.ts +5 -0
- package/src/components/Icon/Icon.stories.tsx +43 -13
- package/src/components/Icon/Icon.tsx +14 -3
- package/src/components/Image/Image.stories.tsx +3 -3
- package/src/components/Image/Image.tsx +31 -8
- package/src/components/Input/Input.stories.tsx +3 -4
- package/src/components/Input/Input.tsx +7 -7
- package/src/components/Link/Link.stories.tsx +0 -1
- package/src/components/Link/Link.tsx +10 -2
- package/src/components/List/List.stories.tsx +3 -4
- package/src/components/List/List.tsx +7 -6
- package/src/components/List/ListDropIndicator.tsx +0 -1
- package/src/components/List/Tree.stories.tsx +2 -3
- package/src/components/List/Tree.tsx +0 -1
- package/src/components/List/TreeDropIndicator.tsx +1 -1
- package/src/components/List/Treegrid.stories.tsx +26 -27
- package/src/components/List/Treegrid.tsx +14 -14
- package/src/components/Main/Main.stories.tsx +0 -1
- package/src/components/Main/Main.tsx +1 -2
- package/src/components/MediaPlayer/MediaPlayer.stories.tsx +50 -0
- package/src/components/MediaPlayer/MediaPlayer.tsx +153 -0
- package/src/components/MediaPlayer/index.ts +5 -0
- package/src/components/Menu/ContextMenu.stories.tsx +0 -1
- package/src/components/Menu/DropdownMenu.stories.tsx +0 -1
- package/src/components/Menu/DropdownMenu.tsx +48 -42
- package/src/components/Message/Message.stories.tsx +7 -8
- package/src/components/Message/Message.tsx +23 -10
- package/src/components/Popover/Popover.stories.tsx +4 -5
- package/src/components/Popover/Popover.tsx +42 -42
- package/src/components/ScrollArea/ScrollArea.stories.tsx +89 -30
- package/src/components/ScrollArea/ScrollArea.tsx +41 -25
- package/src/components/ScrollContainer/ScrollContainer.stories.tsx +20 -18
- package/src/components/ScrollContainer/ScrollContainer.tsx +199 -92
- package/src/components/Select/Select.stories.tsx +5 -6
- package/src/components/Separator/Separator.tsx +4 -7
- package/src/components/Skeleton/Skeleton.stories.tsx +0 -1
- package/src/components/Splitter/Splitter.stories.tsx +29 -29
- package/src/components/Splitter/Splitter.tsx +35 -46
- package/src/components/Status/Status.stories.tsx +0 -1
- package/src/components/Status/Status.tsx +8 -5
- package/src/components/Tag/Tag.stories.tsx +0 -1
- package/src/components/ThemeProvider/ThemeProvider.stories.tsx +0 -1
- package/src/components/ThemeProvider/ThemeProvider.tsx +5 -4
- package/src/components/ThemeProvider/index.ts +1 -1
- package/src/components/Toast/Toast.stories.tsx +0 -1
- package/src/components/Toast/Toast.tsx +16 -31
- package/src/components/Toolbar/Toolbar.stories.tsx +0 -1
- package/src/components/Toolbar/Toolbar.tsx +36 -48
- package/src/components/Tooltip/Tooltip.stories.tsx +7 -8
- package/src/components/Tooltip/Tooltip.tsx +29 -29
- package/src/components/index.ts +3 -0
- package/src/exemplars/generics.stories.tsx +7 -15
- package/src/exemplars/slot.stories.tsx +64 -68
- package/src/exemplars/tabster.stories.tsx +1 -1
- package/src/exemplars/virtualizer.stories.tsx +4 -5
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDensityContext.ts +2 -2
- package/src/playground/Custom.stories.tsx +6 -9
- package/src/primitives/Column/AUDIT.md +148 -0
- package/src/primitives/Column/Column.stories.tsx +128 -19
- package/src/primitives/Column/Column.tsx +89 -80
- package/src/primitives/Container/Container.stories.tsx +29 -0
- package/src/primitives/Container/Container.tsx +19 -0
- package/src/primitives/Container/index.ts +5 -0
- package/src/primitives/Flex/Flex.stories.tsx +0 -1
- package/src/primitives/Flex/Flex.tsx +20 -20
- package/src/primitives/Grid/Grid.stories.tsx +0 -1
- package/src/primitives/Grid/Grid.tsx +23 -36
- package/src/primitives/Panel/Panel.stories.tsx +9 -8
- package/src/primitives/Panel/Panel.tsx +43 -60
- package/src/primitives/index.ts +1 -0
- package/src/testing/Loading.tsx +47 -0
- package/src/testing/decorators/withLayout.tsx +7 -17
- package/src/testing/decorators/withTheme.tsx +10 -7
- package/src/testing/index.ts +2 -0
- package/src/translations.ts +8 -3
- package/src/util/usePx.ts +1 -0
- package/dist/lib/browser/chunk-2FKSMWNY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZNBLTSHI.mjs.map +0 -7
|
@@ -3,33 +3,19 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { createContext } from '@radix-ui/react-context';
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
DialogContent as DialogContentPrimitive,
|
|
10
|
-
DialogDescription as DialogDescriptionPrimitive,
|
|
11
|
-
type DialogDescriptionProps as DialogDescriptionPrimitiveProps,
|
|
12
|
-
DialogOverlay as DialogOverlayPrimitive,
|
|
13
|
-
type DialogOverlayProps as DialogOverlayPrimitiveProps,
|
|
14
|
-
DialogPortal as DialogPortalPrimitive,
|
|
15
|
-
type DialogPortalProps as DialogPortalPrimitiveProps,
|
|
16
|
-
Root as DialogRootPrimitive,
|
|
17
|
-
type DialogProps as DialogRootPrimitiveProps,
|
|
18
|
-
DialogTitle as DialogTitlePrimitive,
|
|
19
|
-
type DialogTitleProps as DialogTitlePrimitiveProps,
|
|
20
|
-
DialogTrigger as DialogTriggerPrimitive,
|
|
21
|
-
type DialogTriggerProps as DialogTriggerPrimitiveProps,
|
|
22
|
-
} from '@radix-ui/react-dialog';
|
|
6
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
7
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
8
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
23
9
|
import React, {
|
|
24
10
|
type ComponentPropsWithRef,
|
|
25
11
|
type ForwardRefExoticComponent,
|
|
26
12
|
type FunctionComponent,
|
|
27
|
-
type PropsWithChildren,
|
|
28
13
|
forwardRef,
|
|
29
14
|
} from 'react';
|
|
30
15
|
import { useTranslation } from 'react-i18next';
|
|
31
16
|
|
|
32
|
-
import { type DialogSize, osTranslations } from '@dxos/ui-theme';
|
|
17
|
+
import { composableProps, type DialogSize, osTranslations, slottable } from '@dxos/ui-theme';
|
|
18
|
+
import { type SlottableProps } from '@dxos/ui-types';
|
|
33
19
|
|
|
34
20
|
import { useThemeContext } from '../../hooks';
|
|
35
21
|
import { Column } from '../../primitives';
|
|
@@ -41,11 +27,16 @@ import { ElevationProvider } from '../ElevationProvider';
|
|
|
41
27
|
// Root
|
|
42
28
|
//
|
|
43
29
|
|
|
44
|
-
type DialogRootProps =
|
|
30
|
+
type DialogRootProps = DialogPrimitive.DialogProps;
|
|
45
31
|
|
|
46
32
|
const DialogRoot: FunctionComponent<DialogRootProps> = (props) => (
|
|
47
33
|
<ElevationProvider elevation='dialog'>
|
|
48
|
-
<
|
|
34
|
+
<DialogPrimitive.Root
|
|
35
|
+
// NOTE: Radix warning unless set to undefined.
|
|
36
|
+
// https://www.radix-ui.com/primitives/docs/components/dialog#description
|
|
37
|
+
aria-describedby={undefined}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
49
40
|
</ElevationProvider>
|
|
50
41
|
);
|
|
51
42
|
|
|
@@ -53,17 +44,17 @@ const DialogRoot: FunctionComponent<DialogRootProps> = (props) => (
|
|
|
53
44
|
// Trigger
|
|
54
45
|
//
|
|
55
46
|
|
|
56
|
-
type DialogTriggerProps =
|
|
47
|
+
type DialogTriggerProps = DialogPrimitive.DialogTriggerProps;
|
|
57
48
|
|
|
58
|
-
const DialogTrigger: FunctionComponent<DialogTriggerProps> =
|
|
49
|
+
const DialogTrigger: FunctionComponent<DialogTriggerProps> = DialogPrimitive.Trigger;
|
|
59
50
|
|
|
60
51
|
//
|
|
61
52
|
// Portal
|
|
62
53
|
//
|
|
63
54
|
|
|
64
|
-
type DialogPortalProps =
|
|
55
|
+
type DialogPortalProps = DialogPrimitive.DialogPortalProps;
|
|
65
56
|
|
|
66
|
-
const DialogPortal: FunctionComponent<DialogPortalProps> =
|
|
57
|
+
const DialogPortal: FunctionComponent<DialogPortalProps> = DialogPrimitive.Portal;
|
|
67
58
|
|
|
68
59
|
//
|
|
69
60
|
// Overlay
|
|
@@ -78,21 +69,23 @@ const [OverlayLayoutProvider, useOverlayLayoutContext] = createContext<OverlayLa
|
|
|
78
69
|
{},
|
|
79
70
|
);
|
|
80
71
|
|
|
81
|
-
type DialogOverlayProps = ThemedClassName<
|
|
72
|
+
type DialogOverlayProps = ThemedClassName<
|
|
73
|
+
DialogPrimitive.DialogOverlayProps & { blockAlign?: 'center' | 'start' | 'end' }
|
|
74
|
+
>;
|
|
82
75
|
|
|
83
76
|
const DialogOverlay: ForwardRefExoticComponent<DialogOverlayProps> = forwardRef<HTMLDivElement, DialogOverlayProps>(
|
|
84
77
|
({ classNames, children, blockAlign, ...props }, forwardedRef) => {
|
|
85
78
|
const { tx } = useThemeContext();
|
|
86
79
|
|
|
87
80
|
return (
|
|
88
|
-
<
|
|
81
|
+
<DialogPrimitive.Overlay
|
|
89
82
|
{...props}
|
|
90
83
|
data-block-align={blockAlign}
|
|
91
84
|
className={tx('dialog.overlay', {}, classNames)}
|
|
92
85
|
ref={forwardedRef}
|
|
93
86
|
>
|
|
94
87
|
<OverlayLayoutProvider inOverlayLayout>{children}</OverlayLayoutProvider>
|
|
95
|
-
</
|
|
88
|
+
</DialogPrimitive.Overlay>
|
|
96
89
|
);
|
|
97
90
|
},
|
|
98
91
|
);
|
|
@@ -105,7 +98,7 @@ DialogOverlay.displayName = DIALOG_OVERLAY_NAME;
|
|
|
105
98
|
|
|
106
99
|
const DIALOG_CONTENT_NAME = 'DialogContent';
|
|
107
100
|
|
|
108
|
-
type DialogContentProps = ThemedClassName<ComponentPropsWithRef<typeof
|
|
101
|
+
type DialogContentProps = ThemedClassName<ComponentPropsWithRef<typeof DialogPrimitive.Content>> & {
|
|
109
102
|
size?: DialogSize;
|
|
110
103
|
inOverlayLayout?: boolean;
|
|
111
104
|
};
|
|
@@ -116,16 +109,25 @@ const DialogContent: ForwardRefExoticComponent<DialogContentProps> = forwardRef<
|
|
|
116
109
|
const { inOverlayLayout } = useOverlayLayoutContext(DIALOG_CONTENT_NAME);
|
|
117
110
|
|
|
118
111
|
return (
|
|
119
|
-
<
|
|
112
|
+
<DialogPrimitive.Content
|
|
120
113
|
{...props}
|
|
121
114
|
// NOTE: Radix warning unless set to undefined.
|
|
122
115
|
// https://www.radix-ui.com/primitives/docs/components/dialog#description
|
|
123
116
|
aria-describedby={undefined}
|
|
124
|
-
className={tx(
|
|
117
|
+
className={tx(
|
|
118
|
+
'dialog.content',
|
|
119
|
+
{
|
|
120
|
+
size,
|
|
121
|
+
inOverlayLayout: propsInOverlayLayout || inOverlayLayout,
|
|
122
|
+
},
|
|
123
|
+
classNames,
|
|
124
|
+
)}
|
|
125
125
|
ref={forwardedRef}
|
|
126
126
|
>
|
|
127
|
-
<Column.Root>
|
|
128
|
-
|
|
127
|
+
<Column.Root classNames='dx-expander' gutter='sm'>
|
|
128
|
+
{children}
|
|
129
|
+
</Column.Root>
|
|
130
|
+
</DialogPrimitive.Content>
|
|
129
131
|
);
|
|
130
132
|
},
|
|
131
133
|
);
|
|
@@ -136,18 +138,18 @@ DialogContent.displayName = DIALOG_CONTENT_NAME;
|
|
|
136
138
|
// Header
|
|
137
139
|
//
|
|
138
140
|
|
|
139
|
-
type DialogHeaderProps =
|
|
141
|
+
type DialogHeaderProps = SlottableProps;
|
|
140
142
|
|
|
141
|
-
const DialogHeader
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
);
|
|
143
|
+
const DialogHeader = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
|
|
144
|
+
const { className, ...rest } = composableProps(props);
|
|
145
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
146
|
+
const { tx } = useThemeContext();
|
|
147
|
+
return (
|
|
148
|
+
<Comp {...rest} className={tx('dialog.header', {}, className)} ref={forwardedRef}>
|
|
149
|
+
{children}
|
|
150
|
+
</Comp>
|
|
151
|
+
);
|
|
152
|
+
});
|
|
151
153
|
|
|
152
154
|
//
|
|
153
155
|
// CloseIconButton
|
|
@@ -161,11 +163,10 @@ const DialogCloseIconButton = forwardRef<HTMLButtonElement, DialogCloseIconButto
|
|
|
161
163
|
return (
|
|
162
164
|
<IconButton
|
|
163
165
|
{...props}
|
|
164
|
-
label={label ?? t('close
|
|
166
|
+
label={label ?? t('close-dialog.label')}
|
|
165
167
|
icon='ph--x--regular'
|
|
166
168
|
iconOnly
|
|
167
169
|
size={4}
|
|
168
|
-
density='fine'
|
|
169
170
|
variant='ghost'
|
|
170
171
|
ref={forwardedRef}
|
|
171
172
|
/>
|
|
@@ -177,32 +178,30 @@ const DialogCloseIconButton = forwardRef<HTMLButtonElement, DialogCloseIconButto
|
|
|
177
178
|
// Body
|
|
178
179
|
//
|
|
179
180
|
|
|
180
|
-
type DialogBodyProps =
|
|
181
|
+
type DialogBodyProps = SlottableProps;
|
|
181
182
|
|
|
182
|
-
const DialogBody
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
},
|
|
193
|
-
);
|
|
183
|
+
const DialogBody = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
|
|
184
|
+
const { className, ...rest } = composableProps(props);
|
|
185
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
186
|
+
const { tx } = useThemeContext();
|
|
187
|
+
return (
|
|
188
|
+
<Comp {...rest} className={tx('dialog.body', {}, className)} ref={forwardedRef}>
|
|
189
|
+
{children}
|
|
190
|
+
</Comp>
|
|
191
|
+
);
|
|
192
|
+
});
|
|
194
193
|
|
|
195
194
|
//
|
|
196
195
|
// Title
|
|
197
196
|
//
|
|
198
197
|
|
|
199
|
-
type DialogTitleProps = ThemedClassName<
|
|
198
|
+
type DialogTitleProps = ThemedClassName<DialogPrimitive.DialogTitleProps> & { srOnly?: boolean };
|
|
200
199
|
|
|
201
|
-
const DialogTitle
|
|
200
|
+
const DialogTitle = forwardRef<HTMLHeadingElement, DialogTitleProps>(
|
|
202
201
|
({ classNames, srOnly, ...props }, forwardedRef) => {
|
|
203
202
|
const { tx } = useThemeContext();
|
|
204
203
|
return (
|
|
205
|
-
<
|
|
204
|
+
<DialogPrimitive.Title {...props} className={tx('dialog.title', { srOnly }, classNames)} ref={forwardedRef} />
|
|
206
205
|
);
|
|
207
206
|
},
|
|
208
207
|
);
|
|
@@ -211,39 +210,35 @@ const DialogTitle: ForwardRefExoticComponent<DialogTitleProps> = forwardRef<HTML
|
|
|
211
210
|
// Description
|
|
212
211
|
//
|
|
213
212
|
|
|
214
|
-
type DialogDescriptionProps = ThemedClassName<
|
|
213
|
+
type DialogDescriptionProps = ThemedClassName<DialogPrimitive.DialogDescriptionProps> & { srOnly?: boolean };
|
|
215
214
|
|
|
216
|
-
const DialogDescription
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
});
|
|
215
|
+
const DialogDescription = forwardRef<HTMLParagraphElement, DialogDescriptionProps>(
|
|
216
|
+
({ classNames, srOnly, ...props }, forwardedRef) => {
|
|
217
|
+
const { tx } = useThemeContext();
|
|
218
|
+
return (
|
|
219
|
+
<DialogPrimitive.Description
|
|
220
|
+
{...props}
|
|
221
|
+
className={tx('dialog.description', { srOnly }, classNames)}
|
|
222
|
+
ref={forwardedRef}
|
|
223
|
+
/>
|
|
224
|
+
);
|
|
225
|
+
},
|
|
226
|
+
);
|
|
229
227
|
|
|
230
228
|
//
|
|
231
229
|
// ActionBar
|
|
232
230
|
//
|
|
233
231
|
|
|
234
|
-
type DialogActionBarProps =
|
|
232
|
+
type DialogActionBarProps = SlottableProps;
|
|
235
233
|
|
|
236
|
-
const DialogActionBar
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
>(({ children, classNames, ...props }, forwardedRef) => {
|
|
234
|
+
const DialogActionBar = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
|
|
235
|
+
const { className: classNames, ...rest } = composableProps(props);
|
|
236
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
240
237
|
const { tx } = useThemeContext();
|
|
241
238
|
return (
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
</div>
|
|
246
|
-
</Column.Segment>
|
|
239
|
+
<Comp {...rest} className={tx('dialog.actionbar', {}, classNames)} ref={forwardedRef}>
|
|
240
|
+
{children}
|
|
241
|
+
</Comp>
|
|
247
242
|
);
|
|
248
243
|
});
|
|
249
244
|
|
|
@@ -251,9 +246,9 @@ const DialogActionBar: ForwardRefExoticComponent<DialogActionBarProps> = forward
|
|
|
251
246
|
// Close
|
|
252
247
|
//
|
|
253
248
|
|
|
254
|
-
type DialogCloseProps =
|
|
249
|
+
type DialogCloseProps = DialogPrimitive.DialogCloseProps;
|
|
255
250
|
|
|
256
|
-
const DialogClose: FunctionComponent<DialogCloseProps> =
|
|
251
|
+
const DialogClose: FunctionComponent<DialogCloseProps> = DialogPrimitive.Close;
|
|
257
252
|
|
|
258
253
|
//
|
|
259
254
|
// Dialog
|
|
@@ -286,4 +281,5 @@ export type {
|
|
|
286
281
|
DialogDescriptionProps,
|
|
287
282
|
DialogActionBarProps,
|
|
288
283
|
DialogCloseProps,
|
|
284
|
+
DialogCloseIconButtonProps,
|
|
289
285
|
};
|
|
@@ -8,11 +8,10 @@ import React from 'react';
|
|
|
8
8
|
import { ErrorBoundary } from '@dxos/react-error-boundary';
|
|
9
9
|
|
|
10
10
|
import { withLayout, withTheme } from '../../testing';
|
|
11
|
-
|
|
12
11
|
import { ErrorFallback } from './ErrorFallback';
|
|
13
12
|
import { ThrowError } from './ThrowError';
|
|
14
13
|
|
|
15
|
-
const
|
|
14
|
+
const DefaultStory = () => {
|
|
16
15
|
return (
|
|
17
16
|
<ErrorBoundary name='story' FallbackComponent={ErrorFallback}>
|
|
18
17
|
<ThrowError />
|
|
@@ -20,10 +19,6 @@ const BasicStory = () => {
|
|
|
20
19
|
);
|
|
21
20
|
};
|
|
22
21
|
|
|
23
|
-
const StringErrorStory = () => {
|
|
24
|
-
return <ErrorFallback error='This is a string error message' data={{ context: 'story' }} />;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
22
|
const meta: Meta = {
|
|
28
23
|
title: 'ui/react-ui-core/components/ErrorFallback',
|
|
29
24
|
component: ErrorFallback,
|
|
@@ -38,7 +33,7 @@ export default meta;
|
|
|
38
33
|
type Story = StoryObj<typeof meta>;
|
|
39
34
|
|
|
40
35
|
export const Default: Story = {
|
|
41
|
-
render:
|
|
36
|
+
render: DefaultStory,
|
|
42
37
|
play: async () => {
|
|
43
38
|
// This story intentionally renders an ErrorBoundary fallback; clear the smoke-test error flag.
|
|
44
39
|
(window as any).__ERROR_BOUNDARY_ERRORS__ = [];
|
|
@@ -46,5 +41,5 @@ export const Default: Story = {
|
|
|
46
41
|
};
|
|
47
42
|
|
|
48
43
|
export const StringError: Story = {
|
|
49
|
-
render:
|
|
44
|
+
render: () => <ErrorFallback error='This is a string error message' data={{ context: 'story' }} />,
|
|
50
45
|
};
|
|
@@ -9,11 +9,45 @@ import { mx } from '@dxos/ui-theme';
|
|
|
9
9
|
|
|
10
10
|
type LocalFrame = { href: string; fileName: string };
|
|
11
11
|
|
|
12
|
+
export type ParsedStackFrame = ReturnType<typeof ErrorStackParser.parse>[number];
|
|
13
|
+
|
|
14
|
+
export type ErrorStackProps = {
|
|
15
|
+
/** When set, these frames are shown instead of parsing `error`. */
|
|
16
|
+
frames?: ParsedStackFrame[];
|
|
17
|
+
/** Used when `frames` is omitted. */
|
|
18
|
+
error?: Error;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parses `captureOwnerStack()` output (React dev) into frames for {@link ErrorStack}.
|
|
23
|
+
* Prefixes a synthetic Error line when needed so `error-stack-parser` can read V8-style stacks.
|
|
24
|
+
*/
|
|
25
|
+
export const parseCaptureOwnerStack = (stack: string | null): ParsedStackFrame[] | null => {
|
|
26
|
+
if (stack == null || stack.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const err = new Error();
|
|
30
|
+
err.stack = stack;
|
|
31
|
+
try {
|
|
32
|
+
return ErrorStackParser.parse(err);
|
|
33
|
+
} catch {
|
|
34
|
+
err.stack = `Error\n${stack}`;
|
|
35
|
+
try {
|
|
36
|
+
return ErrorStackParser.parse(err);
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
12
43
|
/**
|
|
13
44
|
* Renders a parsed error stack trace with tree connector symbols and clickable vscode:// links for local frames.
|
|
14
45
|
*/
|
|
15
|
-
export const ErrorStack = ({ error
|
|
16
|
-
const frames = ErrorStackParser.parse(error);
|
|
46
|
+
export const ErrorStack = ({ error, frames: framesProp }: ErrorStackProps) => {
|
|
47
|
+
const frames = framesProp ?? (error ? ErrorStackParser.parse(error) : []);
|
|
48
|
+
if (frames.length === 0) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
17
51
|
|
|
18
52
|
return (
|
|
19
53
|
<div className='font-mono text-sm'>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Focus
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
Grid cells use `overflow-hidden` which clips outward CSS `ring` (box-shadow) and `outline` styles.
|
|
6
|
+
Using `border` for focus indicators creates doubled lines at grid cell boundaries.
|
|
7
|
+
Inset `box-shadow` alone is obscured by child elements with backgrounds (e.g., toolbar headers).
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
|
|
11
|
+
Uses a `::after` pseudo-element overlay with `ring-inset` to paint the focus ring above all child content.
|
|
12
|
+
The pseudo-element is absolutely positioned, `pointer-events-none`, and inherits `border-radius`.
|
|
13
|
+
|
|
14
|
+
- **Default**: ring is transparent (invisible until focused).
|
|
15
|
+
- **`border` prop**: shows a CSS `border-separator` when unfocused (e.g., for grid cell edges).
|
|
16
|
+
- **Focus/active/error states**: ring color changes to the appropriate indicator color.
|
|
17
|
+
|
|
18
|
+
Both `Focus.Group` and `Focus.Item` support the `border` prop.
|
|
19
|
+
|
|
20
|
+
## Why `::after` overlay
|
|
21
|
+
|
|
22
|
+
| Approach | Clipped? | Obscured by children? | Notes |
|
|
23
|
+
| ------------------------ | -------- | --------------------- | --------------------------------------------------------------------- |
|
|
24
|
+
| `ring` (outward) | Yes | N/A | Extends outside bounds, clipped by parent `overflow-hidden`. |
|
|
25
|
+
| `ring-inset` | No | Yes | Inset box-shadow is part of background layer; children paint over it. |
|
|
26
|
+
| `::after` + `ring-inset` | No | No | Pseudo-element paints above children. Requires `position: relative`. |
|
|
27
|
+
|
|
28
|
+
## Relationship to `dx-focus-ring-inset-over-all`
|
|
29
|
+
|
|
30
|
+
The CSS class `dx-focus-ring-inset-over-all` (in `focus-ring.css`) uses the same `::after` technique
|
|
31
|
+
but only reacts to `:focus-visible`. `Focus.Group/Item` additionally support programmatic states
|
|
32
|
+
via `data-focus-state` (`active`, `error`).
|
|
33
|
+
|
|
34
|
+
## Clean-up
|
|
35
|
+
|
|
36
|
+
- [ ] Unify: extend `dx-focus-ring-inset-over-all` to support `data-focus-state` attributes,
|
|
37
|
+
then have `Focus.Group/Item` use the CSS class instead of inline Tailwind utilities.
|
|
38
|
+
Consumers: Plank, StackItem, Tabs, AttentionProvider, main sidebar.
|
|
39
|
+
|
|
40
|
+
## Audit
|
|
41
|
+
|
|
42
|
+
- [ ] Create a list of all container components (outside of `react-ui`) that directly use `overflow-hidden`;
|
|
43
|
+
Consider containers to be components that have `children` and expand (e.g., `grid`, `grow`, `h-full`, `w-full`).
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { type PropsWithChildren, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { mx } from '@dxos/ui-theme';
|
|
9
|
+
|
|
10
|
+
import { withLayout, withTheme } from '../../testing';
|
|
11
|
+
import { type ThemedClassName } from '../../util';
|
|
12
|
+
import { Focus } from './Focus';
|
|
13
|
+
|
|
14
|
+
type Item = { id: string; label: string };
|
|
15
|
+
|
|
16
|
+
const ITEMS: Item[] = [
|
|
17
|
+
{ id: '1', label: 'Item 1' },
|
|
18
|
+
{ id: '2', label: 'Item 2' },
|
|
19
|
+
{ id: '3', label: 'Item 3' },
|
|
20
|
+
{ id: '4', label: 'Item 4' },
|
|
21
|
+
{ id: '5', label: 'Item 5' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const itemClassName = 'flex items-center gap-3 px-3 py-2 aria-current:bg-neutral-75 dark:aria-current:bg-neutral-800';
|
|
25
|
+
|
|
26
|
+
const Container = ({ classNames, children }: ThemedClassName<PropsWithChildren>) => {
|
|
27
|
+
return (
|
|
28
|
+
<div className='dx-container grid grid-cols-[1fr_2fr_1fr]'>
|
|
29
|
+
<div className='border-e border-separator' />
|
|
30
|
+
<div className='dx-expander grid grid-rows-[1fr_2fr_1fr]'>
|
|
31
|
+
<div className='border-b border-separator' />
|
|
32
|
+
<div className={mx('h-full flex flex-col gap-2', classNames)}>{children}</div>
|
|
33
|
+
<div className='border-t border-separator' />
|
|
34
|
+
</div>
|
|
35
|
+
<div className='border-s border-separator' />
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const Text = ({ children }: PropsWithChildren) => {
|
|
41
|
+
return <p className='p-1 text-sm text-subdued'>{children}</p>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
//
|
|
45
|
+
// Default (vertical list)
|
|
46
|
+
//
|
|
47
|
+
|
|
48
|
+
const DefaultStory = () => {
|
|
49
|
+
const [current, setCurrent] = useState<string | undefined>('1');
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Container>
|
|
53
|
+
<Text>Tab into the group, then use arrow keys to navigate. Press Enter to select.</Text>
|
|
54
|
+
<Focus.Group classNames='h-full'>
|
|
55
|
+
{ITEMS.map((item) => (
|
|
56
|
+
<Focus.Item
|
|
57
|
+
key={item.id}
|
|
58
|
+
current={current === item.id}
|
|
59
|
+
onCurrentChange={() => setCurrent(item.id)}
|
|
60
|
+
className={itemClassName}
|
|
61
|
+
>
|
|
62
|
+
<span className='size-2 bg-primary-500 opacity-0 aria-[current]:opacity-100' />
|
|
63
|
+
<span>{item.label}</span>
|
|
64
|
+
</Focus.Item>
|
|
65
|
+
))}
|
|
66
|
+
</Focus.Group>
|
|
67
|
+
<Text>Selected: {current ?? 'none'}</Text>
|
|
68
|
+
</Container>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
//
|
|
73
|
+
// Horizontal group
|
|
74
|
+
//
|
|
75
|
+
|
|
76
|
+
const HorizontalStory = () => {
|
|
77
|
+
const [current, setCurrent] = useState<string | undefined>();
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Container>
|
|
81
|
+
<Text>Horizontal arrow-key navigation between cards.</Text>
|
|
82
|
+
<Focus.Group classNames='h-full flex flex-row gap-2 items-center justify-center' orientation='horizontal'>
|
|
83
|
+
{ITEMS.map((item) => (
|
|
84
|
+
<Focus.Item
|
|
85
|
+
key={item.id}
|
|
86
|
+
current={current === item.id}
|
|
87
|
+
onCurrentChange={() => setCurrent(item.id)}
|
|
88
|
+
className='flex flex-col items-center justify-center w-20 h-20 border border-separator aria-current:border-primary-500 aria-current:bg-primary-50 dark:aria-current:bg-primary-900/20 cursor-pointer'
|
|
89
|
+
>
|
|
90
|
+
<span className='text-xs mt-1'>{item.label}</span>
|
|
91
|
+
</Focus.Item>
|
|
92
|
+
))}
|
|
93
|
+
</Focus.Group>
|
|
94
|
+
<Text>Selected: {current ?? 'none'}</Text>
|
|
95
|
+
</Container>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
//
|
|
100
|
+
// Grid (demonstrates border prop and overflow-hidden clipping)
|
|
101
|
+
//
|
|
102
|
+
|
|
103
|
+
const GridCell = ({ border, items }: { border?: boolean; items: Item[] }) => {
|
|
104
|
+
const [current, setCurrent] = useState<string | undefined>();
|
|
105
|
+
return (
|
|
106
|
+
<div className='overflow-hidden bg-base-surface'>
|
|
107
|
+
<Focus.Group classNames='h-full' border={border}>
|
|
108
|
+
{items.map((item) => (
|
|
109
|
+
<Focus.Item
|
|
110
|
+
key={item.id}
|
|
111
|
+
current={current === item.id}
|
|
112
|
+
onCurrentChange={() => setCurrent(item.id)}
|
|
113
|
+
className={itemClassName}
|
|
114
|
+
>
|
|
115
|
+
<span>{item.label}</span>
|
|
116
|
+
</Focus.Item>
|
|
117
|
+
))}
|
|
118
|
+
</Focus.Group>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const GridStory = () => {
|
|
124
|
+
return (
|
|
125
|
+
<div className='p-8 space-y-8'>
|
|
126
|
+
<Text>Tab between groups to compare. Each cell has overflow-hidden.</Text>
|
|
127
|
+
|
|
128
|
+
{/* Default vs border. */}
|
|
129
|
+
<div className='grid grid-cols-2 gap-4'>
|
|
130
|
+
<div className='space-y-2'>
|
|
131
|
+
<p className='text-xs font-mono text-subdued'>Default (invisible until focused)</p>
|
|
132
|
+
<div className='h-48'>
|
|
133
|
+
<GridCell items={ITEMS} />
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
<div className='space-y-2'>
|
|
137
|
+
<p className='text-xs font-mono text-subdued'>border (always visible)</p>
|
|
138
|
+
<div className='h-48'>
|
|
139
|
+
<GridCell border items={ITEMS} />
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
{/* Tight grid — border. */}
|
|
145
|
+
<p className='text-xs font-mono text-subdued'>Tight grid — border</p>
|
|
146
|
+
<div className='grid grid-cols-3'>
|
|
147
|
+
{[0, 1, 2].map((col) => (
|
|
148
|
+
<div key={col} className='overflow-hidden'>
|
|
149
|
+
<GridCell border items={ITEMS.slice(0, 3)} />
|
|
150
|
+
</div>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
{/* Tight grid — default. */}
|
|
155
|
+
<p className='text-xs font-mono text-subdued'>Tight grid — default</p>
|
|
156
|
+
<div className='grid grid-cols-3'>
|
|
157
|
+
{[0, 1, 2].map((col) => (
|
|
158
|
+
<div key={col} className='overflow-hidden'>
|
|
159
|
+
<GridCell items={ITEMS.slice(0, 3)} />
|
|
160
|
+
</div>
|
|
161
|
+
))}
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
{/* Item-level border. */}
|
|
165
|
+
<p className='text-xs font-mono text-subdued'>Item-level border</p>
|
|
166
|
+
<div className='h-48 overflow-hidden'>
|
|
167
|
+
<Focus.Group classNames='h-full'>
|
|
168
|
+
{ITEMS.slice(0, 3).map((item) => (
|
|
169
|
+
<Focus.Item key={item.id} border className={itemClassName}>
|
|
170
|
+
<span>{item.label}</span>
|
|
171
|
+
</Focus.Item>
|
|
172
|
+
))}
|
|
173
|
+
</Focus.Group>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
{/* Error state. */}
|
|
177
|
+
<p className='text-xs font-mono text-subdued'>Error state</p>
|
|
178
|
+
<div className='h-48 overflow-hidden'>
|
|
179
|
+
<Focus.Group classNames='h-full' data-focus-state='error'>
|
|
180
|
+
{ITEMS.slice(0, 3).map((item) => (
|
|
181
|
+
<Focus.Item key={item.id} className={itemClassName}>
|
|
182
|
+
<span>{item.label}</span>
|
|
183
|
+
</Focus.Item>
|
|
184
|
+
))}
|
|
185
|
+
</Focus.Group>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
//
|
|
192
|
+
// asChild (slot) usage
|
|
193
|
+
//
|
|
194
|
+
|
|
195
|
+
const AsChildStory = () => {
|
|
196
|
+
const [current, setCurrent] = useState<string | undefined>();
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<Container>
|
|
200
|
+
<Text>Focus.Item rendered as a custom element via asChild.</Text>
|
|
201
|
+
<Focus.Group classNames='h-full'>
|
|
202
|
+
{ITEMS.slice(0, 3).map((item) => (
|
|
203
|
+
<Focus.Item key={item.id} asChild current={current === item.id} onCurrentChange={() => setCurrent(item.id)}>
|
|
204
|
+
<button className='flex w-full items-center gap-3 px-3 py-2 text-left hover:bg-neutral-75 dark:hover:bg-neutral-800 aria-current:bg-primary-50 dark:aria-current:bg-primary-900/20 aria-current:text-primary-600'>
|
|
205
|
+
<span>{item.label}</span>
|
|
206
|
+
</button>
|
|
207
|
+
</Focus.Item>
|
|
208
|
+
))}
|
|
209
|
+
</Focus.Group>
|
|
210
|
+
</Container>
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
//
|
|
215
|
+
// Meta
|
|
216
|
+
//
|
|
217
|
+
|
|
218
|
+
const meta: Meta = {
|
|
219
|
+
title: 'ui/react-ui-core/components/Focus',
|
|
220
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export default meta;
|
|
224
|
+
|
|
225
|
+
type Story = StoryObj<typeof meta>;
|
|
226
|
+
|
|
227
|
+
export const Default: Story = { render: DefaultStory };
|
|
228
|
+
export const Horizontal: Story = { render: HorizontalStory };
|
|
229
|
+
export const Grid: Story = { render: GridStory };
|
|
230
|
+
export const AsChild: Story = { render: AsChildStory };
|