@dxos/react-ui 0.7.4 → 0.7.5-labs.071a3e2
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/index.mjs +510 -347
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +766 -614
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +510 -347
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Avatars/Avatar.d.ts +5 -9
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts +1 -2
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Buttons/IconButton.d.ts +6 -2
- package/dist/types/src/components/Buttons/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Dialogs/AlertDialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialogs/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts +5 -6
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +1 -3
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/Lists/List.d.ts +2 -0
- package/dist/types/src/components/Lists/List.d.ts.map +1 -1
- package/dist/types/src/components/Lists/ListDropIndicator.d.ts +13 -0
- package/dist/types/src/components/Lists/ListDropIndicator.d.ts.map +1 -0
- package/dist/types/src/components/Lists/Tree.d.ts +2 -0
- package/dist/types/src/components/Lists/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Lists/TreeDropIndicator.d.ts +8 -0
- package/dist/types/src/components/Lists/TreeDropIndicator.d.ts.map +1 -0
- package/dist/types/src/components/Main/Main.d.ts +35 -24
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.stories.d.ts +1 -1
- package/dist/types/src/components/Menus/ContextMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menus/DropdownMenu.d.ts +2 -6
- package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.d.ts.map +1 -1
- package/dist/types/src/components/Separator/Separator.d.ts +3 -1
- package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.stories.d.ts +12 -5
- package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +4 -2
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -0
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +15 -5
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +7 -2
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +13 -1
- package/dist/types/src/components/Tooltip/Tooltip.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/useSafeArea.d.ts +9 -0
- package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -0
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts +10 -0
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -0
- package/dist/types/src/hooks/useVisualViewport.d.ts +1 -1
- package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
- package/dist/types/src/util/ThemedClassName.d.ts +1 -1
- package/dist/types/src/util/ThemedClassName.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +43 -42
- package/src/components/Avatars/Avatar.tsx +3 -6
- package/src/components/Buttons/IconButton.tsx +25 -7
- package/src/components/Clipboard/CopyButton.tsx +1 -1
- package/src/components/Dialogs/AlertDialog.tsx +6 -2
- package/src/components/Dialogs/Dialog.tsx +7 -11
- package/src/components/Input/Input.stories.tsx +4 -6
- package/src/components/Input/Input.tsx +29 -44
- package/src/components/Lists/List.stories.tsx +2 -2
- package/src/components/Lists/List.tsx +3 -0
- package/src/components/Lists/ListDropIndicator.tsx +70 -0
- package/src/components/Lists/Tree.tsx +3 -0
- package/src/components/Lists/TreeDropIndicator.tsx +70 -0
- package/src/components/Main/Main.stories.tsx +1 -1
- package/src/components/Main/Main.tsx +79 -110
- package/src/components/Menus/ContextMenu.tsx +8 -6
- package/src/components/Menus/DropdownMenu.tsx +7 -4
- package/src/components/Popover/Popover.tsx +8 -2
- package/src/components/ScrollArea/ScrollArea.stories.tsx +2 -2
- package/src/components/Select/Select.tsx +7 -3
- package/src/components/Separator/Separator.tsx +14 -11
- package/src/components/Tag/Tag.stories.tsx +20 -31
- package/src/components/Tag/Tag.tsx +15 -6
- package/src/components/ThemeProvider/ThemeProvider.tsx +13 -5
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Toolbar/Toolbar.tsx +40 -10
- package/src/components/Tooltip/Tooltip.stories.tsx +13 -2
- package/src/components/Tooltip/Tooltip.tsx +18 -13
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSafeArea.ts +25 -0
- package/src/hooks/useSafeCollisionPadding.ts +39 -0
- package/src/hooks/useVisualViewport.ts +11 -12
- package/src/testing/decorators/withVariants.tsx +4 -4
- package/src/util/ThemedClassName.ts +1 -1
- package/dist/types/src/playground/Surfaces.stories.d.ts +0 -21
- package/dist/types/src/playground/Surfaces.stories.d.ts.map +0 -1
- package/src/playground/Surfaces.stories.tsx +0 -73
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
6
|
+
import React, { type HTMLAttributes, type CSSProperties } from 'react';
|
|
7
|
+
|
|
8
|
+
// Tree item hitbox
|
|
9
|
+
// https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx#tree-item
|
|
10
|
+
|
|
11
|
+
type InstructionType = Exclude<Instruction, { type: 'instruction-blocked' }>['type'];
|
|
12
|
+
type Orientation = 'sibling' | 'child';
|
|
13
|
+
|
|
14
|
+
const edgeToOrientationMap: Record<InstructionType, Orientation> = {
|
|
15
|
+
'reorder-above': 'sibling',
|
|
16
|
+
'reorder-below': 'sibling',
|
|
17
|
+
'make-child': 'child',
|
|
18
|
+
reparent: 'child',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const orientationStyles: Record<Orientation, HTMLAttributes<HTMLElement>['className']> = {
|
|
22
|
+
// TODO(wittjosiah): Stop using left/right here.
|
|
23
|
+
sibling:
|
|
24
|
+
'bs-[--line-thickness] left-[--horizontal-indent] right-0 bg-accentSurface before:left-[--negative-terminal-size]',
|
|
25
|
+
child: 'is-full block-start-0 block-end-0 border-[length:--line-thickness] before:invisible',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const instructionStyles: Record<InstructionType, HTMLAttributes<HTMLElement>['className']> = {
|
|
29
|
+
'reorder-above': 'block-start-[--line-offset] before:block-start-[--offset-terminal]',
|
|
30
|
+
'reorder-below': 'block-end-[--line-offset] before:block-end-[--offset-terminal]',
|
|
31
|
+
'make-child': 'border-accentSurface',
|
|
32
|
+
// TODO(wittjosiah): This is not occurring in the current implementation.
|
|
33
|
+
reparent: '',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const strokeSize = 2;
|
|
37
|
+
const terminalSize = 8;
|
|
38
|
+
const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
|
|
39
|
+
|
|
40
|
+
export type DropIndicatorProps = {
|
|
41
|
+
instruction: Instruction;
|
|
42
|
+
gap?: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const TreeDropIndicator = ({ instruction, gap = 0 }: DropIndicatorProps) => {
|
|
46
|
+
const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
|
|
47
|
+
const isBlocked = instruction.type === 'instruction-blocked';
|
|
48
|
+
const desiredInstruction = isBlocked ? instruction.desired : instruction;
|
|
49
|
+
const orientation = edgeToOrientationMap[desiredInstruction.type];
|
|
50
|
+
if (isBlocked) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
style={
|
|
57
|
+
{
|
|
58
|
+
'--line-thickness': `${strokeSize}px`,
|
|
59
|
+
'--line-offset': `${lineOffset}`,
|
|
60
|
+
'--terminal-size': `${terminalSize}px`,
|
|
61
|
+
'--terminal-radius': `${terminalSize / 2}px`,
|
|
62
|
+
'--negative-terminal-size': `-${terminalSize}px`,
|
|
63
|
+
'--offset-terminal': `${offsetToAlignTerminalWithLine}px`,
|
|
64
|
+
'--horizontal-indent': `${desiredInstruction.currentLevel * desiredInstruction.indentPerLevel + 4}px`,
|
|
65
|
+
} as CSSProperties
|
|
66
|
+
}
|
|
67
|
+
className={`absolute z-10 pointer-events-none before:is-[--terminal-size] before:bs-[--terminal-size] box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accentSurface before:rounded-full ${orientationStyles[orientation]} ${instructionStyles[desiredInstruction.type]}`}
|
|
68
|
+
></div>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -24,7 +24,7 @@ const ComplementarySidebarToggle = () => {
|
|
|
24
24
|
|
|
25
25
|
const StoryMain = (_args: StoryMainArgs) => {
|
|
26
26
|
return (
|
|
27
|
-
<Main.Root
|
|
27
|
+
<Main.Root>
|
|
28
28
|
<Main.Overlay />
|
|
29
29
|
<Main.NavigationSidebar classNames='p-4'>
|
|
30
30
|
<p>Navigation sidebar content, hi!</p>
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { useFocusableGroup } from '@fluentui/react-tabster';
|
|
6
|
-
import { useComposedRefs } from '@radix-ui/react-compose-refs';
|
|
7
6
|
import { createContext } from '@radix-ui/react-context';
|
|
8
7
|
import { Root as DialogRoot, DialogContent } from '@radix-ui/react-dialog';
|
|
9
8
|
import { Primitive } from '@radix-ui/react-primitive';
|
|
@@ -29,7 +28,6 @@ import { useMediaQuery, useForwardedRef } from '@dxos/react-hooks';
|
|
|
29
28
|
import { useSwipeToDismiss } from './useSwipeToDismiss';
|
|
30
29
|
import { useThemeContext } from '../../hooks';
|
|
31
30
|
import { type ThemedClassName } from '../../util';
|
|
32
|
-
import { ElevationProvider } from '../ElevationProvider';
|
|
33
31
|
|
|
34
32
|
const MAIN_ROOT_NAME = 'MainRoot';
|
|
35
33
|
const NAVIGATION_SIDEBAR_NAME = 'NavigationSidebar';
|
|
@@ -37,12 +35,14 @@ const COMPLEMENTARY_SIDEBAR_NAME = 'ComplementarySidebar';
|
|
|
37
35
|
const MAIN_NAME = 'Main';
|
|
38
36
|
const GENERIC_CONSUMER_NAME = 'GenericConsumer';
|
|
39
37
|
|
|
38
|
+
type SidebarState = 'expanded' | 'collapsed' | 'closed';
|
|
39
|
+
|
|
40
40
|
type MainContextValue = {
|
|
41
41
|
resizing: boolean;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
navigationSidebarState: SidebarState;
|
|
43
|
+
setNavigationSidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
44
|
+
complementarySidebarState: SidebarState;
|
|
45
|
+
setComplementarySidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
const landmarkAttr = 'data-main-landmark';
|
|
@@ -75,73 +75,77 @@ const useLandmarkMover = (propsOnKeyDown: ComponentPropsWithoutRef<'div'>['onKey
|
|
|
75
75
|
|
|
76
76
|
const [MainProvider, useMainContext] = createContext<MainContextValue>(MAIN_NAME, {
|
|
77
77
|
resizing: false,
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
navigationSidebarState: 'closed',
|
|
79
|
+
setNavigationSidebarState: (nextState) => {
|
|
80
80
|
// TODO(burdon): Standardize with other context missing errors using raise.
|
|
81
81
|
log.warn('Attempt to set sidebar state without initializing `MainRoot`');
|
|
82
82
|
},
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
complementarySidebarState: 'closed',
|
|
84
|
+
setComplementarySidebarState: (nextState) => {
|
|
85
85
|
// TODO(burdon): Standardize with other context missing errors using raise.
|
|
86
86
|
log.warn('Attempt to set sidebar state without initializing `MainRoot`');
|
|
87
87
|
},
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
const useSidebars = (consumerName = GENERIC_CONSUMER_NAME) => {
|
|
91
|
-
const {
|
|
91
|
+
const { setNavigationSidebarState, navigationSidebarState, setComplementarySidebarState, complementarySidebarState } =
|
|
92
92
|
useMainContext(consumerName);
|
|
93
93
|
return {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
navigationSidebarState,
|
|
95
|
+
setNavigationSidebarState,
|
|
96
96
|
toggleNavigationSidebar: useCallback(
|
|
97
|
-
() =>
|
|
98
|
-
[
|
|
97
|
+
() => setNavigationSidebarState(navigationSidebarState === 'expanded' ? 'closed' : 'expanded'),
|
|
98
|
+
[navigationSidebarState, setNavigationSidebarState],
|
|
99
99
|
),
|
|
100
|
-
openNavigationSidebar: useCallback(() =>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
openNavigationSidebar: useCallback(() => setNavigationSidebarState('expanded'), []),
|
|
101
|
+
collapseNavigationSidebar: useCallback(() => setNavigationSidebarState('collapsed'), []),
|
|
102
|
+
closeNavigationSidebar: useCallback(() => setNavigationSidebarState('closed'), []),
|
|
103
|
+
complementarySidebarState,
|
|
104
|
+
setComplementarySidebarState,
|
|
104
105
|
toggleComplementarySidebar: useCallback(
|
|
105
|
-
() =>
|
|
106
|
-
[
|
|
106
|
+
() => setComplementarySidebarState(complementarySidebarState === 'expanded' ? 'closed' : 'expanded'),
|
|
107
|
+
[complementarySidebarState, setComplementarySidebarState],
|
|
107
108
|
),
|
|
108
|
-
openComplementarySidebar: useCallback(() =>
|
|
109
|
-
|
|
109
|
+
openComplementarySidebar: useCallback(() => setComplementarySidebarState('expanded'), []),
|
|
110
|
+
collapseComplementarySidebar: useCallback(() => setComplementarySidebarState('collapsed'), []),
|
|
111
|
+
closeComplementarySidebar: useCallback(() => setComplementarySidebarState('closed'), []),
|
|
110
112
|
};
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
type MainRootProps = PropsWithChildren<{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
navigationSidebarState?: SidebarState;
|
|
117
|
+
defaultNavigationSidebarState?: SidebarState;
|
|
118
|
+
onNavigationSidebarStateChange?: (nextState: SidebarState) => void;
|
|
119
|
+
complementarySidebarState?: SidebarState;
|
|
120
|
+
defaultComplementarySidebarState?: SidebarState;
|
|
121
|
+
onComplementarySidebarStateChange?: (nextState: SidebarState) => void;
|
|
120
122
|
}>;
|
|
121
123
|
|
|
122
124
|
const resizeDebounce = 3000;
|
|
123
125
|
|
|
124
126
|
const MainRoot = ({
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
navigationSidebarState: propsNavigationSidebarState,
|
|
128
|
+
defaultNavigationSidebarState,
|
|
129
|
+
onNavigationSidebarStateChange,
|
|
130
|
+
complementarySidebarState: propsComplementarySidebarState,
|
|
131
|
+
defaultComplementarySidebarState,
|
|
132
|
+
onComplementarySidebarStateChange,
|
|
131
133
|
children,
|
|
132
134
|
...props
|
|
133
135
|
}: MainRootProps) => {
|
|
134
136
|
const [isLg] = useMediaQuery('lg', { ssr: false });
|
|
135
|
-
const [
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
const [navigationSidebarState = isLg ? 'expanded' : 'collapsed', setNavigationSidebarState] =
|
|
138
|
+
useControllableState<SidebarState>({
|
|
139
|
+
prop: propsNavigationSidebarState,
|
|
140
|
+
defaultProp: defaultNavigationSidebarState,
|
|
141
|
+
onChange: onNavigationSidebarStateChange,
|
|
142
|
+
});
|
|
143
|
+
const [complementarySidebarState = isLg ? 'expanded' : 'collapsed', setComplementarySidebarState] =
|
|
144
|
+
useControllableState<SidebarState>({
|
|
145
|
+
prop: propsComplementarySidebarState,
|
|
146
|
+
defaultProp: defaultComplementarySidebarState,
|
|
147
|
+
onChange: onComplementarySidebarStateChange,
|
|
148
|
+
});
|
|
145
149
|
|
|
146
150
|
const [resizing, setResizing] = useState(false);
|
|
147
151
|
const resizeInterval = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
@@ -166,10 +170,10 @@ const MainRoot = ({
|
|
|
166
170
|
<MainProvider
|
|
167
171
|
{...props}
|
|
168
172
|
{...{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
navigationSidebarState,
|
|
174
|
+
setNavigationSidebarState,
|
|
175
|
+
complementarySidebarState,
|
|
176
|
+
setComplementarySidebarState,
|
|
173
177
|
}}
|
|
174
178
|
resizing={resizing}
|
|
175
179
|
>
|
|
@@ -186,15 +190,15 @@ const handleOpenAutoFocus = (event: Event) => {
|
|
|
186
190
|
|
|
187
191
|
type MainSidebarProps = ThemedClassName<ComponentPropsWithRef<typeof DialogContent>> & {
|
|
188
192
|
swipeToDismiss?: boolean;
|
|
189
|
-
|
|
193
|
+
state?: SidebarState;
|
|
190
194
|
resizing?: boolean;
|
|
191
|
-
|
|
195
|
+
onStateChange?: (nextState: SidebarState) => void;
|
|
192
196
|
side: 'inline-start' | 'inline-end';
|
|
193
197
|
};
|
|
194
198
|
|
|
195
199
|
const MainSidebar = forwardRef<HTMLDivElement, MainSidebarProps>(
|
|
196
200
|
(
|
|
197
|
-
{ classNames, children, swipeToDismiss, onOpenAutoFocus,
|
|
201
|
+
{ classNames, children, swipeToDismiss, onOpenAutoFocus, state, resizing, onStateChange, side, ...props },
|
|
198
202
|
forwardedRef,
|
|
199
203
|
) => {
|
|
200
204
|
const [isLg] = useMediaQuery('lg', { ssr: false });
|
|
@@ -202,7 +206,7 @@ const MainSidebar = forwardRef<HTMLDivElement, MainSidebarProps>(
|
|
|
202
206
|
const ref = useForwardedRef(forwardedRef);
|
|
203
207
|
const noopRef = useRef(null);
|
|
204
208
|
useSwipeToDismiss(swipeToDismiss ? ref : noopRef, {
|
|
205
|
-
onDismiss: () =>
|
|
209
|
+
onDismiss: () => onStateChange?.('closed'),
|
|
206
210
|
});
|
|
207
211
|
const handleKeyDown = useCallback(
|
|
208
212
|
(event: KeyboardEvent<HTMLDivElement>) => {
|
|
@@ -215,36 +219,36 @@ const MainSidebar = forwardRef<HTMLDivElement, MainSidebarProps>(
|
|
|
215
219
|
);
|
|
216
220
|
const Root = isLg ? Primitive.div : DialogContent;
|
|
217
221
|
return (
|
|
218
|
-
<DialogRoot open={
|
|
222
|
+
<DialogRoot open={state !== 'closed'} modal={false}>
|
|
219
223
|
<Root
|
|
220
224
|
{...(!isLg && { forceMount: true, tabIndex: -1, onOpenAutoFocus: onOpenAutoFocus ?? handleOpenAutoFocus })}
|
|
221
225
|
{...props}
|
|
222
226
|
data-side={side === 'inline-end' ? 'ie' : 'is'}
|
|
223
|
-
data-state={
|
|
227
|
+
data-state={state}
|
|
224
228
|
data-resizing={resizing ? 'true' : 'false'}
|
|
225
229
|
className={tx('main.sidebar', 'main__sidebar', {}, classNames)}
|
|
226
230
|
onKeyDown={handleKeyDown}
|
|
227
|
-
{...(
|
|
231
|
+
{...(state === 'closed' && { inert: 'true' })}
|
|
228
232
|
ref={ref}
|
|
229
233
|
>
|
|
230
|
-
|
|
234
|
+
{children}
|
|
231
235
|
</Root>
|
|
232
236
|
</DialogRoot>
|
|
233
237
|
);
|
|
234
238
|
},
|
|
235
239
|
);
|
|
236
240
|
|
|
237
|
-
type MainNavigationSidebarProps = Omit<MainSidebarProps, '
|
|
241
|
+
type MainNavigationSidebarProps = Omit<MainSidebarProps, 'expanded' | 'side'>;
|
|
238
242
|
|
|
239
243
|
const MainNavigationSidebar = forwardRef<HTMLDivElement, MainNavigationSidebarProps>((props, forwardedRef) => {
|
|
240
|
-
const {
|
|
244
|
+
const { navigationSidebarState, setNavigationSidebarState, resizing } = useMainContext(NAVIGATION_SIDEBAR_NAME);
|
|
241
245
|
const mover = useLandmarkMover(props.onKeyDown, '0');
|
|
242
246
|
return (
|
|
243
247
|
<MainSidebar
|
|
244
248
|
{...mover}
|
|
245
249
|
{...props}
|
|
246
|
-
|
|
247
|
-
|
|
250
|
+
state={navigationSidebarState}
|
|
251
|
+
onStateChange={setNavigationSidebarState}
|
|
248
252
|
resizing={resizing}
|
|
249
253
|
side='inline-start'
|
|
250
254
|
ref={forwardedRef}
|
|
@@ -254,18 +258,18 @@ const MainNavigationSidebar = forwardRef<HTMLDivElement, MainNavigationSidebarPr
|
|
|
254
258
|
|
|
255
259
|
MainNavigationSidebar.displayName = NAVIGATION_SIDEBAR_NAME;
|
|
256
260
|
|
|
257
|
-
type MainComplementarySidebarProps = Omit<MainSidebarProps, '
|
|
261
|
+
type MainComplementarySidebarProps = Omit<MainSidebarProps, 'expanded' | 'side'>;
|
|
258
262
|
|
|
259
263
|
const MainComplementarySidebar = forwardRef<HTMLDivElement, MainComplementarySidebarProps>((props, forwardedRef) => {
|
|
260
|
-
const {
|
|
264
|
+
const { complementarySidebarState, setComplementarySidebarState, resizing } =
|
|
261
265
|
useMainContext(COMPLEMENTARY_SIDEBAR_NAME);
|
|
262
266
|
const mover = useLandmarkMover(props.onKeyDown, '2');
|
|
263
267
|
return (
|
|
264
268
|
<MainSidebar
|
|
265
269
|
{...mover}
|
|
266
270
|
{...props}
|
|
267
|
-
|
|
268
|
-
|
|
271
|
+
state={complementarySidebarState}
|
|
272
|
+
onStateChange={setComplementarySidebarState}
|
|
269
273
|
resizing={resizing}
|
|
270
274
|
side='inline-end'
|
|
271
275
|
ref={forwardedRef}
|
|
@@ -283,7 +287,7 @@ type MainProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.div>> &
|
|
|
283
287
|
|
|
284
288
|
const MainContent = forwardRef<HTMLDivElement, MainProps>(
|
|
285
289
|
({ asChild, classNames, bounce, handlesFocus, children, role, ...props }: MainProps, forwardedRef) => {
|
|
286
|
-
const {
|
|
290
|
+
const { navigationSidebarState, complementarySidebarState } = useMainContext(MAIN_NAME);
|
|
287
291
|
const { tx } = useThemeContext();
|
|
288
292
|
const Root = asChild ? Slot : role ? 'div' : 'main';
|
|
289
293
|
|
|
@@ -294,8 +298,8 @@ const MainContent = forwardRef<HTMLDivElement, MainProps>(
|
|
|
294
298
|
role={role}
|
|
295
299
|
{...(handlesFocus && { ...mover })}
|
|
296
300
|
{...props}
|
|
297
|
-
data-sidebar-inline-start-state={
|
|
298
|
-
data-sidebar-inline-end-state={
|
|
301
|
+
data-sidebar-inline-start-state={navigationSidebarState}
|
|
302
|
+
data-sidebar-inline-end-state={complementarySidebarState}
|
|
299
303
|
className={tx('main.content', 'main', { bounce, handlesFocus }, classNames)}
|
|
300
304
|
ref={forwardedRef}
|
|
301
305
|
>
|
|
@@ -311,72 +315,37 @@ type MainOverlayProps = ThemedClassName<Omit<ComponentPropsWithRef<typeof Primit
|
|
|
311
315
|
|
|
312
316
|
const MainOverlay = forwardRef<HTMLDivElement, MainOverlayProps>(({ classNames, ...props }, forwardedRef) => {
|
|
313
317
|
const [isLg] = useMediaQuery('lg', { ssr: false });
|
|
314
|
-
const {
|
|
318
|
+
const { navigationSidebarState, setNavigationSidebarState, complementarySidebarState, setComplementarySidebarState } =
|
|
315
319
|
useMainContext(MAIN_NAME);
|
|
316
320
|
const { tx } = useThemeContext();
|
|
317
321
|
return (
|
|
318
322
|
<div
|
|
319
323
|
onClick={() => {
|
|
320
|
-
|
|
321
|
-
|
|
324
|
+
setNavigationSidebarState('collapsed');
|
|
325
|
+
setComplementarySidebarState('collapsed');
|
|
322
326
|
}}
|
|
323
327
|
{...props}
|
|
324
328
|
className={tx(
|
|
325
329
|
'main.overlay',
|
|
326
330
|
'main__overlay',
|
|
327
|
-
{ isLg, inlineStartSidebarOpen:
|
|
331
|
+
{ isLg, inlineStartSidebarOpen: navigationSidebarState, inlineEndSidebarOpen: complementarySidebarState },
|
|
328
332
|
classNames,
|
|
329
333
|
)}
|
|
330
|
-
data-state={
|
|
334
|
+
data-state={navigationSidebarState === 'expanded' || complementarySidebarState === 'expanded' ? 'open' : 'closed'}
|
|
331
335
|
aria-hidden='true'
|
|
332
336
|
ref={forwardedRef}
|
|
333
337
|
/>
|
|
334
338
|
);
|
|
335
339
|
});
|
|
336
340
|
|
|
337
|
-
type MainNotchProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.div>>;
|
|
338
|
-
|
|
339
|
-
const MainNotch = forwardRef<HTMLDivElement, MainNotchProps>(({ classNames, ...props }, forwardedRef) => {
|
|
340
|
-
const { tx } = useThemeContext();
|
|
341
|
-
// Notch is concerned with the nav sidebar, whichever side it might be on.
|
|
342
|
-
const { navigationSidebarOpen } = useMainContext(MAIN_NAME);
|
|
343
|
-
const notchElement = useRef<HTMLDivElement | null>(null);
|
|
344
|
-
const ref = useComposedRefs(forwardedRef, notchElement);
|
|
345
|
-
|
|
346
|
-
const handleKeyDown = useCallback(
|
|
347
|
-
(event: KeyboardEvent<HTMLDivElement>) => {
|
|
348
|
-
switch (event.key) {
|
|
349
|
-
case 'Escape':
|
|
350
|
-
props?.onKeyDown?.(event);
|
|
351
|
-
notchElement.current?.focus();
|
|
352
|
-
}
|
|
353
|
-
},
|
|
354
|
-
[props?.onKeyDown],
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
const mover = useLandmarkMover(handleKeyDown, '3');
|
|
358
|
-
|
|
359
|
-
return (
|
|
360
|
-
<div
|
|
361
|
-
role='toolbar'
|
|
362
|
-
{...mover}
|
|
363
|
-
{...props}
|
|
364
|
-
data-nav-sidebar-state={navigationSidebarOpen ? 'open' : 'closed'}
|
|
365
|
-
className={tx('main.notch', 'main__notch', {}, classNames)}
|
|
366
|
-
ref={ref}
|
|
367
|
-
/>
|
|
368
|
-
);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
341
|
export const Main = {
|
|
372
342
|
Root: MainRoot,
|
|
373
343
|
Content: MainContent,
|
|
374
344
|
Overlay: MainOverlay,
|
|
375
345
|
NavigationSidebar: MainNavigationSidebar,
|
|
376
346
|
ComplementarySidebar: MainComplementarySidebar,
|
|
377
|
-
Notch: MainNotch,
|
|
378
347
|
};
|
|
379
348
|
|
|
380
|
-
export { useMainContext, useSidebars };
|
|
349
|
+
export { useMainContext, useSidebars, useLandmarkMover };
|
|
381
350
|
|
|
382
|
-
export type { MainRootProps, MainProps, MainOverlayProps, MainNavigationSidebarProps };
|
|
351
|
+
export type { MainRootProps, MainProps, MainOverlayProps, MainNavigationSidebarProps, SidebarState };
|
|
@@ -6,9 +6,9 @@ import { Primitive } from '@radix-ui/react-primitive';
|
|
|
6
6
|
import { Slot } from '@radix-ui/react-slot';
|
|
7
7
|
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
8
8
|
|
|
9
|
-
import { useThemeContext } from '../../hooks';
|
|
9
|
+
import { useElevationContext, useThemeContext } from '../../hooks';
|
|
10
|
+
import { useSafeCollisionPadding } from '../../hooks/useSafeCollisionPadding';
|
|
10
11
|
import { type ThemedClassName } from '../../util';
|
|
11
|
-
import { ElevationProvider } from '../ElevationProvider';
|
|
12
12
|
|
|
13
13
|
type ContextMenuRootProps = ContextMenuPrimitive.ContextMenuProps;
|
|
14
14
|
|
|
@@ -27,16 +27,18 @@ type ContextMenuContentProps = ThemedClassName<ContextMenuPrimitive.ContextMenuC
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const ContextMenuContent = forwardRef<HTMLDivElement, ContextMenuContentProps>(
|
|
30
|
-
({ classNames, children, ...props }, forwardedRef) => {
|
|
30
|
+
({ classNames, children, collisionPadding = 8, ...props }, forwardedRef) => {
|
|
31
31
|
const { tx } = useThemeContext();
|
|
32
|
+
const elevation = useElevationContext();
|
|
33
|
+
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
32
34
|
return (
|
|
33
35
|
<ContextMenuPrimitive.Content
|
|
34
|
-
collisionPadding={8}
|
|
35
36
|
{...props}
|
|
36
|
-
|
|
37
|
+
collisionPadding={safeCollisionPadding}
|
|
38
|
+
className={tx('menu.content', 'menu', { elevation }, classNames)}
|
|
37
39
|
ref={forwardedRef}
|
|
38
40
|
>
|
|
39
|
-
|
|
41
|
+
{children}
|
|
40
42
|
</ContextMenuPrimitive.Content>
|
|
41
43
|
);
|
|
42
44
|
},
|
|
@@ -28,7 +28,8 @@ import React, {
|
|
|
28
28
|
type RefObject,
|
|
29
29
|
} from 'react';
|
|
30
30
|
|
|
31
|
-
import { useThemeContext } from '../../hooks';
|
|
31
|
+
import { useElevationContext, useThemeContext } from '../../hooks';
|
|
32
|
+
import { useSafeCollisionPadding } from '../../hooks/useSafeCollisionPadding';
|
|
32
33
|
import { type ThemedClassName } from '../../util';
|
|
33
34
|
|
|
34
35
|
type Direction = 'ltr' | 'rtl';
|
|
@@ -232,18 +233,20 @@ interface DropdownMenuContentProps extends Omit<MenuContentProps, 'onEntryFocus'
|
|
|
232
233
|
|
|
233
234
|
const DropdownMenuContent = forwardRef<DropdownMenuContentElement, DropdownMenuContentProps>(
|
|
234
235
|
(props: ScopedProps<DropdownMenuContentProps>, forwardedRef) => {
|
|
235
|
-
const { __scopeDropdownMenu, classNames, ...contentProps } = props;
|
|
236
|
+
const { __scopeDropdownMenu, classNames, collisionPadding = 8, ...contentProps } = props;
|
|
236
237
|
const { tx } = useThemeContext();
|
|
237
238
|
const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
|
|
239
|
+
const elevation = useElevationContext();
|
|
238
240
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
239
241
|
const hasInteractedOutsideRef = useRef(false);
|
|
240
|
-
|
|
242
|
+
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
241
243
|
return (
|
|
242
244
|
<MenuPrimitive.Content
|
|
243
245
|
id={context.contentId}
|
|
244
246
|
aria-labelledby={context.triggerId}
|
|
245
247
|
{...menuScope}
|
|
246
248
|
{...contentProps}
|
|
249
|
+
collisionPadding={safeCollisionPadding}
|
|
247
250
|
ref={forwardedRef}
|
|
248
251
|
onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
249
252
|
if (!hasInteractedOutsideRef.current) {
|
|
@@ -261,7 +264,7 @@ const DropdownMenuContent = forwardRef<DropdownMenuContentElement, DropdownMenuC
|
|
|
261
264
|
hasInteractedOutsideRef.current = true;
|
|
262
265
|
}
|
|
263
266
|
})}
|
|
264
|
-
className={tx('menu.content', 'menu', {}, classNames)}
|
|
267
|
+
className={tx('menu.content', 'menu', { elevation }, classNames)}
|
|
265
268
|
style={{
|
|
266
269
|
...props.style,
|
|
267
270
|
// re-namespace exposed content custom properties
|
|
@@ -36,7 +36,8 @@ import React, {
|
|
|
36
36
|
} from 'react';
|
|
37
37
|
import { RemoveScroll } from 'react-remove-scroll';
|
|
38
38
|
|
|
39
|
-
import { useThemeContext } from '../../hooks';
|
|
39
|
+
import { useElevationContext, useThemeContext } from '../../hooks';
|
|
40
|
+
import { useSafeCollisionPadding } from '../../hooks/useSafeCollisionPadding';
|
|
40
41
|
import { type ThemedClassName } from '../../util';
|
|
41
42
|
|
|
42
43
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -258,6 +259,7 @@ const PopoverContent = forwardRef<PopoverContentTypeElement, PopoverContentProps
|
|
|
258
259
|
const portalContext = usePortalContext(CONTENT_NAME, props.__scopePopover);
|
|
259
260
|
const { forceMount = portalContext.forceMount, ...contentProps } = props;
|
|
260
261
|
const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);
|
|
262
|
+
|
|
261
263
|
return (
|
|
262
264
|
<Presence present={forceMount || context.open}>
|
|
263
265
|
{context.modal ? (
|
|
@@ -427,12 +429,15 @@ const PopoverContentImpl = forwardRef<PopoverContentImplElement, PopoverContentI
|
|
|
427
429
|
onPointerDownOutside,
|
|
428
430
|
onFocusOutside,
|
|
429
431
|
onInteractOutside,
|
|
432
|
+
collisionPadding = 8,
|
|
430
433
|
classNames,
|
|
431
434
|
...contentProps
|
|
432
435
|
} = props;
|
|
433
436
|
const context = usePopoverContext(CONTENT_NAME, __scopePopover);
|
|
434
437
|
const popperScope = usePopperScope(__scopePopover);
|
|
435
438
|
const { tx } = useThemeContext();
|
|
439
|
+
const elevation = useElevationContext();
|
|
440
|
+
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
436
441
|
|
|
437
442
|
// Make sure the whole tree has focus guards as our `Popover` may be
|
|
438
443
|
// the last element in the DOM (because of the `Portal`)
|
|
@@ -461,7 +466,8 @@ const PopoverContentImpl = forwardRef<PopoverContentImplElement, PopoverContentI
|
|
|
461
466
|
id={context.contentId}
|
|
462
467
|
{...popperScope}
|
|
463
468
|
{...contentProps}
|
|
464
|
-
|
|
469
|
+
collisionPadding={safeCollisionPadding}
|
|
470
|
+
className={tx('popover.content', 'popover', { elevation }, classNames)}
|
|
465
471
|
ref={forwardedRef}
|
|
466
472
|
style={{
|
|
467
473
|
...contentProps.style,
|
|
@@ -7,7 +7,7 @@ import '@dxos-theme';
|
|
|
7
7
|
import React, { type PropsWithChildren } from 'react';
|
|
8
8
|
|
|
9
9
|
import { faker } from '@dxos/random';
|
|
10
|
-
import { groupSurface,
|
|
10
|
+
import { groupSurface, surfaceShadow } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
12
|
import { ScrollArea } from './ScrollArea';
|
|
13
13
|
import { withTheme } from '../../testing';
|
|
@@ -17,7 +17,7 @@ faker.seed(1234);
|
|
|
17
17
|
const StorybookScrollArea = ({ children }: PropsWithChildren<{}>) => {
|
|
18
18
|
return (
|
|
19
19
|
<ScrollArea.Root
|
|
20
|
-
classNames={['is-[300px] bs-[400px] rounded', groupSurface,
|
|
20
|
+
classNames={['is-[300px] bs-[400px] rounded', groupSurface, surfaceShadow({ elevation: 'positioned' })]}
|
|
21
21
|
>
|
|
22
22
|
<ScrollArea.Viewport classNames='rounded p-4'>
|
|
23
23
|
<p>{children}</p>
|
|
@@ -6,7 +6,8 @@ import { CaretDown, CaretUp } from '@phosphor-icons/react';
|
|
|
6
6
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
7
7
|
import React, { forwardRef } from 'react';
|
|
8
8
|
|
|
9
|
-
import { useThemeContext } from '../../hooks';
|
|
9
|
+
import { useElevationContext, useThemeContext } from '../../hooks';
|
|
10
|
+
import { useSafeCollisionPadding } from '../../hooks/useSafeCollisionPadding';
|
|
10
11
|
import { type ThemedClassName } from '../../util';
|
|
11
12
|
import { Button, type ButtonProps } from '../Buttons';
|
|
12
13
|
import { Icon } from '../Icon';
|
|
@@ -53,12 +54,15 @@ const SelectTriggerButton = forwardRef<HTMLButtonElement, SelectTriggerButtonPro
|
|
|
53
54
|
type SelectContentProps = ThemedClassName<SelectPrimitive.SelectContentProps>;
|
|
54
55
|
|
|
55
56
|
const SelectContent = forwardRef<HTMLDivElement, SelectContentProps>(
|
|
56
|
-
({ classNames, children, ...props }, forwardedRef) => {
|
|
57
|
+
({ classNames, children, collisionPadding = 8, ...props }, forwardedRef) => {
|
|
57
58
|
const { tx } = useThemeContext();
|
|
59
|
+
const elevation = useElevationContext();
|
|
60
|
+
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
58
61
|
return (
|
|
59
62
|
<SelectPrimitive.Content
|
|
60
63
|
{...props}
|
|
61
|
-
|
|
64
|
+
collisionPadding={safeCollisionPadding}
|
|
65
|
+
className={tx('select.content', 'select__content', { elevation }, classNames)}
|
|
62
66
|
position='popper'
|
|
63
67
|
ref={forwardedRef}
|
|
64
68
|
>
|
|
@@ -5,23 +5,26 @@ import {
|
|
|
5
5
|
Separator as SeparatorPrimitive,
|
|
6
6
|
type SeparatorProps as SeparatorPrimitiveProps,
|
|
7
7
|
} from '@radix-ui/react-separator';
|
|
8
|
-
import React from 'react';
|
|
8
|
+
import React, { forwardRef } from 'react';
|
|
9
9
|
|
|
10
10
|
import { useThemeContext } from '../../hooks';
|
|
11
11
|
import { type ThemedClassName } from '../../util';
|
|
12
12
|
|
|
13
13
|
type SeparatorProps = ThemedClassName<SeparatorPrimitiveProps>;
|
|
14
14
|
|
|
15
|
-
const Separator =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
const Separator = forwardRef<HTMLDivElement, SeparatorProps>(
|
|
16
|
+
({ classNames, orientation = 'horizontal', ...props }, forwardedRef) => {
|
|
17
|
+
const { tx } = useThemeContext();
|
|
18
|
+
return (
|
|
19
|
+
<SeparatorPrimitive
|
|
20
|
+
orientation={orientation}
|
|
21
|
+
{...props}
|
|
22
|
+
className={tx('separator.root', 'separator', { orientation }, classNames)}
|
|
23
|
+
ref={forwardedRef}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
);
|
|
25
28
|
|
|
26
29
|
export type { SeparatorProps };
|
|
27
30
|
|