@dxos/react-ui 0.8.4-main.d05673bc65 → 0.8.4-main.dfabb4ec29
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/dist/lib/browser/{chunk-2FKSMWNY.mjs → chunk-BDBC6H6V.mjs} +79 -5
- package/dist/lib/browser/chunk-BDBC6H6V.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +949 -758
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +30 -24
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/translations.mjs +18 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ZNBLTSHI.mjs → chunk-3JSJK2ZY.mjs} +79 -5
- package/dist/lib/node-esm/chunk-3JSJK2ZY.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +949 -758
- 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 +30 -24
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/translations.mjs +20 -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 -51
- 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/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.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/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 -9
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +18 -5
- 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 -17
- 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 +11 -19
- 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 +10 -10
- 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 +1 -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 +21 -14
- 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 +4 -5
- package/dist/types/src/primitives/Container/Container.d.ts.map +1 -1
- package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Flex/Flex.d.ts +5 -7
- 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 +3 -8
- 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 +24 -15
- 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/testing/Loading.d.ts.map +1 -1
- 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/translations.d.ts +3 -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 +28 -25
- 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 +280 -115
- 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/List/List.stories.tsx +1 -2
- 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/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/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 +39 -23
- 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 -34
- 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 +21 -35
- package/src/components/Tooltip/Tooltip.stories.tsx +7 -8
- package/src/components/Tooltip/Tooltip.tsx +15 -16
- package/src/components/index.ts +1 -0
- package/src/exemplars/generics.stories.tsx +7 -15
- package/src/exemplars/slot.stories.tsx +65 -57
- 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 +122 -19
- package/src/primitives/Column/Column.tsx +73 -42
- package/src/primitives/Container/Container.stories.tsx +0 -1
- package/src/primitives/Container/Container.tsx +5 -8
- package/src/primitives/Flex/Flex.stories.tsx +0 -1
- package/src/primitives/Flex/Flex.tsx +10 -12
- package/src/primitives/Grid/Grid.stories.tsx +0 -1
- package/src/primitives/Grid/Grid.tsx +4 -9
- package/src/primitives/Panel/Panel.stories.tsx +9 -8
- package/src/primitives/Panel/Panel.tsx +64 -63
- package/src/testing/Loading.tsx +25 -4
- package/src/testing/decorators/withLayout.tsx +7 -17
- package/src/testing/decorators/withTheme.tsx +10 -7
- package/src/translations.ts +3 -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
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
useArrowNavigationGroup,
|
|
7
|
+
useFocusableGroup,
|
|
8
|
+
useMergedTabsterAttributes_unstable,
|
|
9
|
+
} from '@fluentui/react-tabster';
|
|
10
|
+
import { useComposedRefs } from '@radix-ui/react-compose-refs';
|
|
11
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
12
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
13
|
+
import React, {
|
|
14
|
+
type FocusEvent,
|
|
15
|
+
type KeyboardEvent,
|
|
16
|
+
type MouseEvent,
|
|
17
|
+
createContext,
|
|
18
|
+
useCallback,
|
|
19
|
+
useContext,
|
|
20
|
+
useRef,
|
|
21
|
+
useState,
|
|
22
|
+
} from 'react';
|
|
23
|
+
|
|
24
|
+
import { composableProps, slottable } from '@dxos/ui-theme';
|
|
25
|
+
import { type Axis } from '@dxos/ui-types';
|
|
26
|
+
|
|
27
|
+
import { useThemeContext } from '../../hooks';
|
|
28
|
+
|
|
29
|
+
//
|
|
30
|
+
// Context
|
|
31
|
+
//
|
|
32
|
+
|
|
33
|
+
type FocusState = 'active' | 'error';
|
|
34
|
+
|
|
35
|
+
const FOCUS_STATE_ATTR = 'focus-state';
|
|
36
|
+
|
|
37
|
+
type ContextValue = {
|
|
38
|
+
setFocus?: (state: FocusState | undefined) => void;
|
|
39
|
+
/** True when any item within the group has DOM focus. */
|
|
40
|
+
groupHasFocus?: boolean;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const FocusContext = createContext<ContextValue>({});
|
|
44
|
+
|
|
45
|
+
const useFocus = () => useContext(FocusContext);
|
|
46
|
+
|
|
47
|
+
//
|
|
48
|
+
// Group
|
|
49
|
+
//
|
|
50
|
+
|
|
51
|
+
type GroupProps = {
|
|
52
|
+
orientation?: Axis;
|
|
53
|
+
/** Show a subdued ring when unfocused (e.g., as a cell border). */
|
|
54
|
+
border?: boolean;
|
|
55
|
+
onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Provides arrow-key navigation across focusable children via tabster.
|
|
60
|
+
* Does not manage `aria-current` — use `Focus.Item` on each child for that.
|
|
61
|
+
*/
|
|
62
|
+
// TODO(wittjosiah): Consider how this could integrate with with react-ui-attention.
|
|
63
|
+
// Perhaps react-ui-attention comes under the mosaic umbrella as it supports selection?
|
|
64
|
+
const Group = slottable<HTMLDivElement, GroupProps>(
|
|
65
|
+
({ children, asChild, orientation = 'vertical', border = false, ...props }, forwardedRef) => {
|
|
66
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
67
|
+
const { tx } = useThemeContext();
|
|
68
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
69
|
+
const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited-trap-focus' });
|
|
70
|
+
const arrowNavigationAttrs = useArrowNavigationGroup({ axis: orientation, memorizeCurrent: true });
|
|
71
|
+
const tabsterAttrs = useMergedTabsterAttributes_unstable(focusableGroupAttrs, arrowNavigationAttrs);
|
|
72
|
+
const [state, setState] = useState<FocusState | undefined>();
|
|
73
|
+
const [groupHasFocus, setGroupHasFocus] = useState(false);
|
|
74
|
+
|
|
75
|
+
const handleFocusIn = useCallback(() => setGroupHasFocus(true), []);
|
|
76
|
+
const handleFocusOut = useCallback((event: FocusEvent<HTMLDivElement>) => {
|
|
77
|
+
const related = event.relatedTarget as HTMLElement | null;
|
|
78
|
+
if (!related || !rootRef.current?.contains(related)) {
|
|
79
|
+
setGroupHasFocus(false);
|
|
80
|
+
}
|
|
81
|
+
}, []);
|
|
82
|
+
|
|
83
|
+
const { className, ...rest } = composableProps(props);
|
|
84
|
+
return (
|
|
85
|
+
<FocusContext.Provider value={{ setFocus: setState, groupHasFocus }}>
|
|
86
|
+
<Comp
|
|
87
|
+
{...rest}
|
|
88
|
+
tabIndex={0}
|
|
89
|
+
className={tx('focus.group', { border }, className)}
|
|
90
|
+
{...tabsterAttrs}
|
|
91
|
+
{...(state && {
|
|
92
|
+
[`data-${FOCUS_STATE_ATTR}`]: state,
|
|
93
|
+
})}
|
|
94
|
+
onBlur={handleFocusOut}
|
|
95
|
+
onFocus={handleFocusIn}
|
|
96
|
+
ref={useComposedRefs<HTMLDivElement>(rootRef, forwardedRef)}
|
|
97
|
+
>
|
|
98
|
+
{children}
|
|
99
|
+
</Comp>
|
|
100
|
+
</FocusContext.Provider>
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
//
|
|
106
|
+
// Item
|
|
107
|
+
//
|
|
108
|
+
|
|
109
|
+
type ItemProps = {
|
|
110
|
+
current?: boolean;
|
|
111
|
+
/** Show a subdued ring when unfocused (e.g., as a cell border). */
|
|
112
|
+
border?: boolean;
|
|
113
|
+
onCurrentChange?: () => void;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Focusable item within a `Focus.Group`.
|
|
118
|
+
* Uses `useFocusableGroup` so the parent Group's arrow navigation treats this as a single unit
|
|
119
|
+
* (internal buttons are not arrow-navigation targets; Enter/Escape to go in/out).
|
|
120
|
+
* Supports controlled (`current` prop) and uncontrolled (focus-driven) `aria-current`.
|
|
121
|
+
*/
|
|
122
|
+
const Item = slottable<HTMLDivElement, ItemProps>(
|
|
123
|
+
(
|
|
124
|
+
{ children, asChild, current, border = false, onCurrentChange, onClick, onFocus, onBlur, ...props },
|
|
125
|
+
forwardedRef,
|
|
126
|
+
) => {
|
|
127
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
128
|
+
const { tx } = useThemeContext();
|
|
129
|
+
// Tell tabster's groupper to ignore Enter so it doesn't move focus into the group.
|
|
130
|
+
const focusableGroupAttrs = useFocusableGroup({ ignoreDefaultKeydown: { Enter: true } });
|
|
131
|
+
const [focused, setFocused] = useState(false);
|
|
132
|
+
|
|
133
|
+
const handleClick = useCallback(
|
|
134
|
+
(event: MouseEvent<HTMLDivElement>) => {
|
|
135
|
+
onCurrentChange?.();
|
|
136
|
+
onClick?.(event);
|
|
137
|
+
},
|
|
138
|
+
[onCurrentChange, onClick],
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const handleKeyDown = useCallback(
|
|
142
|
+
(event: KeyboardEvent<HTMLDivElement>) => {
|
|
143
|
+
if (event.key === 'Enter') {
|
|
144
|
+
onCurrentChange?.();
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
[onCurrentChange],
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const handleFocus = useCallback(
|
|
151
|
+
(event: FocusEvent<HTMLDivElement>) => {
|
|
152
|
+
setFocused(true);
|
|
153
|
+
onFocus?.(event);
|
|
154
|
+
},
|
|
155
|
+
[onFocus],
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const handleBlur = useCallback(
|
|
159
|
+
(event: FocusEvent<HTMLDivElement>) => {
|
|
160
|
+
setFocused(false);
|
|
161
|
+
onBlur?.(event);
|
|
162
|
+
},
|
|
163
|
+
[onBlur],
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Controlled `current` prop takes precedence (e.g., virtualized items that scroll back into view).
|
|
167
|
+
// Otherwise fall back to DOM focus state.
|
|
168
|
+
const isCurrent = current ?? focused;
|
|
169
|
+
|
|
170
|
+
const { className, ...rest } = composableProps(props);
|
|
171
|
+
return (
|
|
172
|
+
<Comp
|
|
173
|
+
{...rest}
|
|
174
|
+
tabIndex={0}
|
|
175
|
+
className={tx('focus.item', { border }, className)}
|
|
176
|
+
{...focusableGroupAttrs}
|
|
177
|
+
aria-current={isCurrent || undefined}
|
|
178
|
+
onClick={handleClick}
|
|
179
|
+
onKeyDown={handleKeyDown}
|
|
180
|
+
onFocus={handleFocus}
|
|
181
|
+
onBlur={handleBlur}
|
|
182
|
+
ref={forwardedRef}
|
|
183
|
+
>
|
|
184
|
+
{children}
|
|
185
|
+
</Comp>
|
|
186
|
+
);
|
|
187
|
+
},
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
//
|
|
191
|
+
// Focus
|
|
192
|
+
//
|
|
193
|
+
|
|
194
|
+
export const Focus = {
|
|
195
|
+
Group,
|
|
196
|
+
Item,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export type { GroupProps as FocusGroupProps, ItemProps as FocusItemProps };
|
|
200
|
+
|
|
201
|
+
export { useFocus };
|
|
@@ -6,10 +6,9 @@ import { IconBase, type IconProps, type IconWeight } from '@phosphor-icons/react
|
|
|
6
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
7
|
import React, { type FC, type ReactElement, type SVGProps, forwardRef } from 'react';
|
|
8
8
|
|
|
9
|
-
import { getSize, mx } from '@dxos/ui-theme';
|
|
9
|
+
import { getSize, iconSize, mx } from '@dxos/ui-theme';
|
|
10
10
|
|
|
11
11
|
import { withTheme } from '../../testing';
|
|
12
|
-
|
|
13
12
|
import { Icon } from './Icon';
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -50,29 +49,60 @@ const createIcon = ({
|
|
|
50
49
|
return CustomIcon;
|
|
51
50
|
};
|
|
52
51
|
|
|
53
|
-
const DefaultStory = ({ CustomIcon }: { CustomIcon: FC<IconProps> }) => {
|
|
54
|
-
return (
|
|
55
|
-
<div className='grid grid-cols-2 gap-8'>
|
|
56
|
-
<CustomIcon weight={'regular'} className={mx(getSize(16))} />
|
|
57
|
-
<Icon icon='ph--github-logo--regular' classNames={mx(getSize(16))} />
|
|
58
|
-
</div>
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
52
|
const meta = {
|
|
63
53
|
title: 'ui/react-ui-core/components/Icon',
|
|
64
|
-
|
|
54
|
+
component: Icon,
|
|
65
55
|
decorators: [withTheme()],
|
|
66
56
|
parameters: {
|
|
67
57
|
layout: 'centered',
|
|
68
58
|
},
|
|
69
|
-
} satisfies Meta<typeof
|
|
59
|
+
} satisfies Meta<typeof Icon>;
|
|
70
60
|
|
|
71
61
|
export default meta;
|
|
72
62
|
|
|
73
63
|
type Story = StoryObj<typeof meta>;
|
|
74
64
|
|
|
75
65
|
export const Default: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
icon: 'ph--github-logo--regular',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const Static: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
icon: 'ph--github-logo--regular',
|
|
74
|
+
classNames: getSize(8),
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Dynamic: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
icon: 'ph--github-logo--regular',
|
|
81
|
+
},
|
|
82
|
+
render: (args) => {
|
|
83
|
+
return (
|
|
84
|
+
<div className='flex gap-4'>
|
|
85
|
+
<Icon {...args} />
|
|
86
|
+
<div className='flex gap-4' style={iconSize(8)}>
|
|
87
|
+
<Icon {...args} />
|
|
88
|
+
<div className='flex gap-4' style={iconSize(null)}>
|
|
89
|
+
<Icon {...args} />
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const Custom = {
|
|
98
|
+
render: ({ CustomIcon }: { CustomIcon: FC<IconProps> }) => {
|
|
99
|
+
return (
|
|
100
|
+
<div className='grid grid-cols-2 gap-8'>
|
|
101
|
+
<CustomIcon weight={'regular'} className={mx(getSize(16))} />
|
|
102
|
+
<Icon icon='ph--github-logo--regular' classNames={mx(getSize(16))} />
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
},
|
|
76
106
|
args: {
|
|
77
107
|
CustomIcon: createIcon({
|
|
78
108
|
name: 'GithubLogo',
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Primitive } from '@radix-ui/react-primitive';
|
|
6
|
-
import React, { type ComponentPropsWithRef, forwardRef, memo } from 'react';
|
|
6
|
+
import React, { type ComponentPropsWithRef, forwardRef, memo, useMemo } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type Size } from '@dxos/ui-types';
|
|
9
9
|
|
|
@@ -13,14 +13,25 @@ import { type ThemedClassName } from '../../util';
|
|
|
13
13
|
export type IconProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.svg>> & {
|
|
14
14
|
icon: string;
|
|
15
15
|
size?: Size;
|
|
16
|
+
synchronized?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The Icon's size can be set directly or inherited from the `--dx-icon-size` CSS variable.
|
|
21
|
+
*/
|
|
18
22
|
export const Icon = memo(
|
|
19
|
-
forwardRef<SVGSVGElement, IconProps>(({
|
|
23
|
+
forwardRef<SVGSVGElement, IconProps>(({ classNames, icon, size, synchronized, style, ...props }, forwardedRef) => {
|
|
20
24
|
const { tx } = useThemeContext();
|
|
25
|
+
const spinDelay = useMemo(() => (synchronized ? `${-(Date.now() % 1_000)}ms` : undefined), [synchronized]);
|
|
21
26
|
const href = useIconHref(icon);
|
|
27
|
+
|
|
22
28
|
return (
|
|
23
|
-
<svg
|
|
29
|
+
<svg
|
|
30
|
+
{...props}
|
|
31
|
+
style={{ ...style, animationDelay: spinDelay }}
|
|
32
|
+
className={tx('icon.root', { size }, classNames)}
|
|
33
|
+
ref={forwardedRef}
|
|
34
|
+
>
|
|
24
35
|
<use href={href} />
|
|
25
36
|
</svg>
|
|
26
37
|
);
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React, { useMemo } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { random } from '@dxos/random';
|
|
9
9
|
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
10
|
|
|
11
11
|
import { Image } from './Image';
|
|
12
12
|
|
|
13
13
|
const seed = Math.random();
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
random.seed(seed);
|
|
16
16
|
|
|
17
17
|
const meta = {
|
|
18
18
|
title: 'ui/react-ui-mosaic/Image',
|
|
@@ -34,7 +34,7 @@ type Story = StoryObj<typeof meta>;
|
|
|
34
34
|
|
|
35
35
|
export const Default: Story = {
|
|
36
36
|
args: {
|
|
37
|
-
src:
|
|
37
|
+
src: random.image.url(),
|
|
38
38
|
},
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -13,15 +13,16 @@ export type ImageProps = ThemedClassName<
|
|
|
13
13
|
{
|
|
14
14
|
src: string;
|
|
15
15
|
alt?: string;
|
|
16
|
+
fit?: 'contain' | 'cover';
|
|
16
17
|
crossOrigin?: 'anonymous' | 'use-credentials' | '';
|
|
17
18
|
} & ColorOptions
|
|
18
19
|
>;
|
|
19
20
|
|
|
20
|
-
// TODO(burdon): Option for neutral background color.
|
|
21
21
|
export const Image = ({
|
|
22
22
|
classNames,
|
|
23
23
|
src,
|
|
24
24
|
alt = '',
|
|
25
|
+
fit = 'contain',
|
|
25
26
|
crossOrigin = 'anonymous',
|
|
26
27
|
sampleSize = 64,
|
|
27
28
|
contrast = 0.9,
|
|
@@ -68,7 +69,16 @@ export const Image = ({
|
|
|
68
69
|
|
|
69
70
|
return (
|
|
70
71
|
<div
|
|
71
|
-
|
|
72
|
+
// `isolate` (`isolation: isolate`) creates a new stacking context so
|
|
73
|
+
// the inner <img>'s `z-10` stays scoped to this wrapper. Without it
|
|
74
|
+
// the z-10 leaks into the parent's stacking context and elevates the
|
|
75
|
+
// image above any pseudo-element rings (e.g. Focus.Item's
|
|
76
|
+
// `dx-ring-pseudo` `::after`) painted on ancestors — most visibly,
|
|
77
|
+
// the focus ring on a Card containing a Card.Poster.
|
|
78
|
+
className={mx(
|
|
79
|
+
`relative flex w-full justify-center overflow-hidden transition-all duration-700 isolate`,
|
|
80
|
+
classNames,
|
|
81
|
+
)}
|
|
72
82
|
style={{
|
|
73
83
|
backgroundColor: dominantColor,
|
|
74
84
|
}}
|
|
@@ -94,7 +104,10 @@ export const Image = ({
|
|
|
94
104
|
crossOrigin={crossOriginState}
|
|
95
105
|
onError={handleImageError}
|
|
96
106
|
onLoad={handleImageLoad}
|
|
97
|
-
className=
|
|
107
|
+
className={mx(
|
|
108
|
+
'z-10 transition-opacity duration-500',
|
|
109
|
+
fit === 'cover' ? 'w-full h-full object-cover' : 'object-contain',
|
|
110
|
+
)}
|
|
98
111
|
style={{
|
|
99
112
|
opacity: imageLoaded ? 1 : 0,
|
|
100
113
|
}}
|
|
@@ -162,7 +175,9 @@ const extractDominantColor = (
|
|
|
162
175
|
const alpha = pixels[i + 3];
|
|
163
176
|
|
|
164
177
|
// Skip transparent pixels.
|
|
165
|
-
if (alpha === 0)
|
|
178
|
+
if (alpha === 0) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
166
181
|
|
|
167
182
|
// Calculate saturation to weight vibrant colors more.
|
|
168
183
|
const max = Math.max(red, green, blue);
|
|
@@ -202,21 +217,29 @@ const isTransparent = (pixels: Uint8ClampedArray, sampleSize: number, threshold:
|
|
|
202
217
|
for (let x = 0; x < sampleSize; x++) {
|
|
203
218
|
// Top edge.
|
|
204
219
|
const topIndex = x * 4;
|
|
205
|
-
if (pixels[topIndex + 3] === 0)
|
|
220
|
+
if (pixels[topIndex + 3] === 0) {
|
|
221
|
+
edgeTransparentPixels++;
|
|
222
|
+
}
|
|
206
223
|
|
|
207
224
|
// Bottom edge.
|
|
208
225
|
const bottomIndex = ((sampleSize - 1) * sampleSize + x) * 4;
|
|
209
|
-
if (pixels[bottomIndex + 3] === 0)
|
|
226
|
+
if (pixels[bottomIndex + 3] === 0) {
|
|
227
|
+
edgeTransparentPixels++;
|
|
228
|
+
}
|
|
210
229
|
}
|
|
211
230
|
|
|
212
231
|
for (let y = 1; y < sampleSize - 1; y++) {
|
|
213
232
|
// Left edge.
|
|
214
233
|
const leftIndex = y * sampleSize * 4;
|
|
215
|
-
if (pixels[leftIndex + 3] === 0)
|
|
234
|
+
if (pixels[leftIndex + 3] === 0) {
|
|
235
|
+
edgeTransparentPixels++;
|
|
236
|
+
}
|
|
216
237
|
|
|
217
238
|
// Right edge.
|
|
218
239
|
const rightIndex = (y * sampleSize + sampleSize - 1) * 4;
|
|
219
|
-
if (pixels[rightIndex + 3] === 0)
|
|
240
|
+
if (pixels[rightIndex + 3] === 0) {
|
|
241
|
+
edgeTransparentPixels++;
|
|
242
|
+
}
|
|
220
243
|
}
|
|
221
244
|
|
|
222
245
|
return edgeTransparentPixels / edgePixels > threshold;
|
|
@@ -8,7 +8,6 @@ import React from 'react';
|
|
|
8
8
|
import { type MessageValence } from '@dxos/ui-types';
|
|
9
9
|
|
|
10
10
|
import { withLayoutVariants, withTheme } from '../../testing';
|
|
11
|
-
|
|
12
11
|
import {
|
|
13
12
|
type CheckboxProps,
|
|
14
13
|
Input,
|
|
@@ -28,7 +27,7 @@ type VariantMap = {
|
|
|
28
27
|
|
|
29
28
|
type Variant = { [K in keyof VariantMap]: { type: K } & VariantMap[K] }[keyof VariantMap];
|
|
30
29
|
|
|
31
|
-
type
|
|
30
|
+
type DefaultStoryProps = Partial<{
|
|
32
31
|
kind: keyof VariantMap;
|
|
33
32
|
label: string;
|
|
34
33
|
labelVisuallyHidden: boolean;
|
|
@@ -47,7 +46,7 @@ const DefaultStory = ({
|
|
|
47
46
|
validationValence,
|
|
48
47
|
validationMessage,
|
|
49
48
|
...props
|
|
50
|
-
}:
|
|
49
|
+
}: DefaultStoryProps) => {
|
|
51
50
|
return (
|
|
52
51
|
<Input.Root {...{ validationValence }}>
|
|
53
52
|
<Input.Label srOnly={labelVisuallyHidden}>{label}</Input.Label>
|
|
@@ -75,7 +74,7 @@ const meta = {
|
|
|
75
74
|
|
|
76
75
|
export default meta;
|
|
77
76
|
|
|
78
|
-
type Story = StoryObj<
|
|
77
|
+
type Story = StoryObj<DefaultStoryProps & Variant>;
|
|
79
78
|
|
|
80
79
|
export const DensityCoarse: Story = {
|
|
81
80
|
args: {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
6
6
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
7
7
|
import React, { type ComponentPropsWithRef, type ForwardRefExoticComponent, forwardRef } from 'react';
|
|
8
8
|
|
|
@@ -130,13 +130,13 @@ type TextInputProps = InputSharedProps & ThemedClassName<TextInputPrimitiveProps
|
|
|
130
130
|
|
|
131
131
|
const TextInput = forwardRef<HTMLInputElement, InputScopedProps<TextInputProps>>(
|
|
132
132
|
(
|
|
133
|
-
{ __inputScope, classNames, density:
|
|
133
|
+
{ __inputScope, classNames, density: densityProp, elevation: elevationProp, variant, noAutoFill, ...props },
|
|
134
134
|
forwardedRef,
|
|
135
135
|
) => {
|
|
136
136
|
const { hasIosKeyboard } = useThemeContext();
|
|
137
137
|
const { tx } = useThemeContext();
|
|
138
|
-
const density = useDensityContext(
|
|
139
|
-
const elevation = useElevationContext(
|
|
138
|
+
const density = useDensityContext(densityProp);
|
|
139
|
+
const elevation = useElevationContext(elevationProp);
|
|
140
140
|
const { validationValence } = useInputContext(INPUT_NAME, __inputScope);
|
|
141
141
|
|
|
142
142
|
return (
|
|
@@ -193,7 +193,7 @@ const TextArea = forwardRef<HTMLTextAreaElement, InputScopedProps<TextAreaProps>
|
|
|
193
193
|
},
|
|
194
194
|
);
|
|
195
195
|
|
|
196
|
-
type CheckboxProps = ThemedClassName<Omit<
|
|
196
|
+
type CheckboxProps = ThemedClassName<Omit<CheckboxPrimitive.CheckboxProps, 'children'>> & {
|
|
197
197
|
size?: Size;
|
|
198
198
|
};
|
|
199
199
|
|
|
@@ -222,7 +222,7 @@ const Checkbox: ForwardRefExoticComponent<CheckboxProps> = forwardRef<
|
|
|
222
222
|
const { tx } = useThemeContext();
|
|
223
223
|
|
|
224
224
|
return (
|
|
225
|
-
<CheckboxPrimitive
|
|
225
|
+
<CheckboxPrimitive.Root
|
|
226
226
|
{...{
|
|
227
227
|
...props,
|
|
228
228
|
checked,
|
|
@@ -241,7 +241,7 @@ const Checkbox: ForwardRefExoticComponent<CheckboxProps> = forwardRef<
|
|
|
241
241
|
icon={checked === 'indeterminate' ? 'ph--minus--regular' : 'ph--check--regular'}
|
|
242
242
|
classNames={tx('input.checkboxIndicator', { size, checked })}
|
|
243
243
|
/>
|
|
244
|
-
</CheckboxPrimitive>
|
|
244
|
+
</CheckboxPrimitive.Root>
|
|
245
245
|
);
|
|
246
246
|
},
|
|
247
247
|
);
|
|
@@ -13,7 +13,6 @@ import { getSize, ghostHover, mx, surfaceShadow } from '@dxos/ui-theme';
|
|
|
13
13
|
|
|
14
14
|
import { withTheme } from '../../testing';
|
|
15
15
|
import { Icon } from '../Icon';
|
|
16
|
-
|
|
17
16
|
import { List, ListItem, type ListScopedProps } from './List';
|
|
18
17
|
|
|
19
18
|
const meta = {
|
|
@@ -177,7 +176,7 @@ export const Collapsible: Story = {
|
|
|
177
176
|
<List {...args}>
|
|
178
177
|
{items.map(({ id, text, body }, index) => (
|
|
179
178
|
<ListItem.Root key={id} id={id} collapsible={index !== 2} defaultOpen={index % 2 === 0}>
|
|
180
|
-
<div
|
|
179
|
+
<div className='grow flex'>
|
|
181
180
|
{index !== 2 ? <ListItem.OpenTrigger /> : <ListItem.MockOpenTrigger />}
|
|
182
181
|
<ListItem.Heading classNames='grow pt-2'>{text}</ListItem.Heading>
|
|
183
182
|
<ListItem.Endcap>
|
|
@@ -24,24 +24,25 @@ import {
|
|
|
24
24
|
useListContext,
|
|
25
25
|
useListItemContext,
|
|
26
26
|
} from '@dxos/react-list';
|
|
27
|
+
import { composable, composableProps } from '@dxos/ui-theme';
|
|
27
28
|
import { type Density } from '@dxos/ui-types';
|
|
28
29
|
|
|
29
30
|
import { useDensityContext, useThemeContext } from '../../hooks';
|
|
30
31
|
import { type ThemedClassName } from '../../util';
|
|
31
32
|
import { DensityProvider } from '../DensityProvider';
|
|
32
33
|
import { Icon } from '../Icon';
|
|
33
|
-
|
|
34
34
|
import { ListDropIndicator } from './ListDropIndicator';
|
|
35
35
|
|
|
36
|
-
type ListProps = ThemedClassName<ListPrimitiveProps
|
|
36
|
+
type ListProps = ThemedClassName<ListPrimitiveProps & { density?: Density }>;
|
|
37
37
|
|
|
38
|
-
const List =
|
|
38
|
+
const List = composable<HTMLOListElement, ListProps>(({ children, ...props }, forwardedRef) => {
|
|
39
39
|
const { tx } = useThemeContext();
|
|
40
40
|
const density = useDensityContext(props.density);
|
|
41
|
+
const { className, ...rest } = composableProps(props);
|
|
41
42
|
|
|
42
43
|
return (
|
|
43
44
|
<DensityProvider density={density}>
|
|
44
|
-
<ListPrimitive {...
|
|
45
|
+
<ListPrimitive {...rest} className={tx('list.root', {}, className)} ref={forwardedRef}>
|
|
45
46
|
{children}
|
|
46
47
|
</ListPrimitive>
|
|
47
48
|
</DensityProvider>
|
|
@@ -74,7 +75,7 @@ const MockListItemOpenTrigger = ({
|
|
|
74
75
|
}: ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'children'>>) => {
|
|
75
76
|
const density = useDensityContext();
|
|
76
77
|
const { tx } = useThemeContext();
|
|
77
|
-
return <div
|
|
78
|
+
return <div {...props} className={tx('list.item.openTrigger', { density }, classNames)} />;
|
|
78
79
|
};
|
|
79
80
|
|
|
80
81
|
type ListItemHeadingProps = ThemedClassName<ListPrimitiveItemHeadingProps>;
|
|
@@ -89,7 +90,7 @@ const ListItemHeading = forwardRef<HTMLParagraphElement, ListItemHeadingProps>(
|
|
|
89
90
|
className={tx('list.item.heading', { density }, classNames)}
|
|
90
91
|
ref={forwardedRef}
|
|
91
92
|
>
|
|
92
|
-
{children}
|
|
93
|
+
<span>{children}</span>
|
|
93
94
|
</ListPrimitiveItemHeading>
|
|
94
95
|
);
|
|
95
96
|
},
|
|
@@ -6,7 +6,6 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
8
|
import { withTheme } from '../../testing';
|
|
9
|
-
|
|
10
9
|
import { Tree, TreeItem } from './Tree';
|
|
11
10
|
|
|
12
11
|
type StorybookTreeProps = {
|
|
@@ -25,7 +24,7 @@ const createKey = (key: string, prefix?: string) => (prefix === undefined ? key
|
|
|
25
24
|
const StorybookTreeItem = ({ data, prefix }: StorybookTreeItemProps) => {
|
|
26
25
|
const keys = Array.isArray(data) ? Array.from(data.keys()) : Object.keys(data);
|
|
27
26
|
return (
|
|
28
|
-
<Tree.Root
|
|
27
|
+
<Tree.Root>
|
|
29
28
|
{keys.map((key) => {
|
|
30
29
|
const id = createKey(String(key), prefix);
|
|
31
30
|
const value = data[key as keyof typeof data];
|
|
@@ -33,7 +32,7 @@ const StorybookTreeItem = ({ data, prefix }: StorybookTreeItemProps) => {
|
|
|
33
32
|
|
|
34
33
|
return (
|
|
35
34
|
<TreeItem.Root key={id} id={id} collapsible={!valueIsScalar} defaultOpen>
|
|
36
|
-
<div
|
|
35
|
+
<div className='grow flex'>
|
|
37
36
|
{valueIsScalar ? <TreeItem.MockOpenTrigger /> : <TreeItem.OpenTrigger />}
|
|
38
37
|
<TreeItem.Heading classNames='grow pt-1'>{valueIsScalar ? String(value) : key}</TreeItem.Heading>
|
|
39
38
|
</div>
|