@dxos/react-ui 0.7.4 → 0.7.5-feature-compute.4d9d99a
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 +454 -290
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +712 -560
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +454 -290
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Buttons/IconButton.d.ts +4 -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 +11 -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 +0 -2
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Menus/ContextMenu.d.ts.map +1 -1
- 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/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 +13 -12
- package/src/components/Buttons/IconButton.tsx +22 -5
- 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 +62 -0
- package/src/components/Lists/Tree.tsx +3 -0
- package/src/components/Lists/TreeDropIndicator.tsx +70 -0
- package/src/components/Main/Main.tsx +1 -38
- 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/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
|
@@ -6,7 +6,7 @@ import '@dxos-theme';
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
|
-
import { baseSurface, modalSurface, groupSurface, mx,
|
|
9
|
+
import { baseSurface, modalSurface, groupSurface, mx, surfaceShadow } from '@dxos/react-ui-theme';
|
|
10
10
|
import { type MessageValence } from '@dxos/react-ui-types';
|
|
11
11
|
|
|
12
12
|
import { Input } from './Input';
|
|
@@ -61,10 +61,10 @@ const StoryInput = (props: StoryInputProps) => {
|
|
|
61
61
|
<div className={mx(baseSurface, 'p-4')}>
|
|
62
62
|
<StoryInputContent {...props} />
|
|
63
63
|
</div>
|
|
64
|
-
<div className={mx(groupSurface, 'p-4 rounded-lg',
|
|
64
|
+
<div className={mx(groupSurface, 'p-4 rounded-lg', surfaceShadow({ elevation: 'positioned' }))}>
|
|
65
65
|
<StoryInputContent {...props} />
|
|
66
66
|
</div>
|
|
67
|
-
<div className={mx(modalSurface, 'p-4 rounded-lg',
|
|
67
|
+
<div className={mx(modalSurface, 'p-4 rounded-lg', surfaceShadow({ elevation: 'dialog' }))}>
|
|
68
68
|
<StoryInputContent {...props} />
|
|
69
69
|
</div>
|
|
70
70
|
</div>
|
|
@@ -214,8 +214,6 @@ export const Switch = {
|
|
|
214
214
|
args: {
|
|
215
215
|
label: 'This is a switch',
|
|
216
216
|
type: 'switch',
|
|
217
|
-
description: 'It’s
|
|
218
|
-
size: 5,
|
|
219
|
-
weight: 'bold',
|
|
217
|
+
description: 'It’s either off... or on.',
|
|
220
218
|
},
|
|
221
219
|
};
|
|
@@ -2,19 +2,10 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
Root as CheckboxPrimitive,
|
|
8
|
-
type CheckboxProps as CheckboxPrimitiveProps,
|
|
9
|
-
Indicator as CheckboxIndicatorPrimitive,
|
|
10
|
-
} from '@radix-ui/react-checkbox';
|
|
11
|
-
import {
|
|
12
|
-
Root as SwitchPrimitive,
|
|
13
|
-
Thumb as SwitchThumbPrimitive,
|
|
14
|
-
type SwitchProps as SwitchPrimitiveProps,
|
|
15
|
-
} from '@radix-ui/react-switch';
|
|
5
|
+
import { type IconWeight } from '@phosphor-icons/react';
|
|
6
|
+
import { Root as CheckboxPrimitive, type CheckboxProps as CheckboxPrimitiveProps } from '@radix-ui/react-checkbox';
|
|
16
7
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
17
|
-
import React, { forwardRef, type ForwardRefExoticComponent,
|
|
8
|
+
import React, { type ComponentPropsWithRef, forwardRef, type ForwardRefExoticComponent, useCallback } from 'react';
|
|
18
9
|
|
|
19
10
|
import {
|
|
20
11
|
InputRoot,
|
|
@@ -41,6 +32,7 @@ import { type Density, type Elevation, type ClassNameValue, type Size } from '@d
|
|
|
41
32
|
|
|
42
33
|
import { useDensityContext, useElevationContext, useThemeContext } from '../../hooks';
|
|
43
34
|
import { type ThemedClassName } from '../../util';
|
|
35
|
+
import { Icon } from '../Icon';
|
|
44
36
|
|
|
45
37
|
type InputVariant = 'default' | 'subdued';
|
|
46
38
|
|
|
@@ -262,7 +254,7 @@ const Checkbox: ForwardRefExoticComponent<CheckboxProps> = forwardRef<
|
|
|
262
254
|
});
|
|
263
255
|
const { id, validationValence, descriptionId, errorMessageId } = useInputContext(INPUT_NAME, __inputScope);
|
|
264
256
|
const { tx } = useThemeContext();
|
|
265
|
-
|
|
257
|
+
|
|
266
258
|
return (
|
|
267
259
|
<CheckboxPrimitive
|
|
268
260
|
{...{
|
|
@@ -279,63 +271,56 @@ const Checkbox: ForwardRefExoticComponent<CheckboxProps> = forwardRef<
|
|
|
279
271
|
}}
|
|
280
272
|
ref={forwardedRef}
|
|
281
273
|
>
|
|
282
|
-
<
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
className: tx('input.checkboxIndicator', 'input--checkbox__indicator', { size }),
|
|
287
|
-
})}
|
|
288
|
-
/>
|
|
289
|
-
</CheckboxIndicatorPrimitive>
|
|
274
|
+
<Icon
|
|
275
|
+
icon={checked === 'indeterminate' ? 'ph--minus--regular' : 'ph--check--regular'}
|
|
276
|
+
classNames={tx('input.checkboxIndicator', 'input--checkbox__indicator', { size, checked })}
|
|
277
|
+
/>
|
|
290
278
|
</CheckboxPrimitive>
|
|
291
279
|
);
|
|
292
280
|
},
|
|
293
281
|
);
|
|
294
282
|
|
|
295
|
-
type SwitchProps = ThemedClassName<
|
|
283
|
+
type SwitchProps = ThemedClassName<
|
|
284
|
+
Omit<ComponentPropsWithRef<'input'>, 'children' | 'onChange'> & { onCheckedChange?: (checked: boolean) => void }
|
|
285
|
+
>;
|
|
296
286
|
|
|
297
|
-
const Switch
|
|
287
|
+
const Switch = forwardRef<HTMLInputElement, InputScopedProps<SwitchProps>>(
|
|
298
288
|
(
|
|
299
289
|
{
|
|
300
290
|
__inputScope,
|
|
301
291
|
checked: propsChecked,
|
|
302
292
|
defaultChecked: propsDefaultChecked,
|
|
303
293
|
onCheckedChange: propsOnCheckedChange,
|
|
304
|
-
size = 5,
|
|
305
294
|
classNames,
|
|
306
295
|
...props
|
|
307
296
|
},
|
|
308
297
|
forwardedRef,
|
|
309
298
|
) => {
|
|
310
|
-
const { tx } = useThemeContext();
|
|
311
|
-
|
|
312
299
|
const [checked, onCheckedChange] = useControllableState({
|
|
313
300
|
prop: propsChecked,
|
|
314
|
-
defaultProp: propsDefaultChecked,
|
|
301
|
+
defaultProp: propsDefaultChecked ?? false,
|
|
315
302
|
onChange: propsOnCheckedChange,
|
|
316
303
|
});
|
|
317
304
|
|
|
318
305
|
const { id, validationValence, descriptionId, errorMessageId } = useInputContext(INPUT_NAME, __inputScope);
|
|
306
|
+
|
|
319
307
|
return (
|
|
320
|
-
<
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
'aria-describedby': descriptionId,
|
|
327
|
-
...(validationValence === 'error' && {
|
|
328
|
-
'aria-invalid': 'true' as const,
|
|
329
|
-
'aria-errormessage': errorMessageId,
|
|
330
|
-
}),
|
|
331
|
-
className: tx('input.switch', 'input--switch', { size }, classNames),
|
|
308
|
+
<input
|
|
309
|
+
type='checkbox'
|
|
310
|
+
className='ch-checkbox--switch ch-focus-ring'
|
|
311
|
+
checked={checked}
|
|
312
|
+
onChange={(event) => {
|
|
313
|
+
onCheckedChange(event.target.checked);
|
|
332
314
|
}}
|
|
315
|
+
id={id}
|
|
316
|
+
aria-describedby={descriptionId}
|
|
317
|
+
{...props}
|
|
318
|
+
{...(validationValence === 'error' && {
|
|
319
|
+
'aria-invalid': 'true' as const,
|
|
320
|
+
'aria-errormessage': errorMessageId,
|
|
321
|
+
})}
|
|
333
322
|
ref={forwardedRef}
|
|
334
|
-
|
|
335
|
-
{/* TODO(wittjosiah): Embed icons/text for on/off states.
|
|
336
|
-
e.g., https://codepen.io/alvarotrigo/pen/oNoJePo (#13) */}
|
|
337
|
-
<SwitchThumbPrimitive className={tx('input.switchThumb', 'input--switch__thumb', { size })} />
|
|
338
|
-
</SwitchPrimitive>
|
|
323
|
+
/>
|
|
339
324
|
);
|
|
340
325
|
},
|
|
341
326
|
);
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
ghostSelected,
|
|
18
18
|
ghostSelectedTrackingInterFromNormal,
|
|
19
19
|
mx,
|
|
20
|
-
|
|
20
|
+
surfaceShadow,
|
|
21
21
|
} from '@dxos/react-ui-theme';
|
|
22
22
|
|
|
23
23
|
import { List, ListItem, type ListScopedProps } from './List';
|
|
@@ -124,7 +124,7 @@ export const ManySizesDraggable = {
|
|
|
124
124
|
<p
|
|
125
125
|
className={mx(
|
|
126
126
|
index % 3 === 0 ? 'bs-20' : index % 2 === 0 ? 'bs-12' : 'bs-8',
|
|
127
|
-
|
|
127
|
+
surfaceShadow({ elevation: 'positioned' }),
|
|
128
128
|
'mbe-2 p-2 bg-white dark:bg-neutral-800 rounded',
|
|
129
129
|
)}
|
|
130
130
|
>{`List item ${index + 1}`}</p>
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '@dxos/react-list';
|
|
27
27
|
import { type Density } from '@dxos/react-ui-types';
|
|
28
28
|
|
|
29
|
+
import { ListDropIndicator } from './ListDropIndicator';
|
|
29
30
|
import { useDensityContext, useThemeContext } from '../../hooks';
|
|
30
31
|
import { type ThemedClassName } from '../../util';
|
|
31
32
|
import { DensityProvider } from '../DensityProvider';
|
|
@@ -150,6 +151,7 @@ export const ListItem: {
|
|
|
150
151
|
OpenTrigger: ForwardRefExoticComponent<ListItemOpenTriggerProps>;
|
|
151
152
|
CollapsibleContent: ForwardRefExoticComponent<ListItemCollapsibleContentProps>;
|
|
152
153
|
MockOpenTrigger: FC<ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'children'>>>;
|
|
154
|
+
DropIndicator: typeof ListDropIndicator;
|
|
153
155
|
} = {
|
|
154
156
|
Root: ListItemRoot,
|
|
155
157
|
Endcap: ListItemEndcap,
|
|
@@ -157,6 +159,7 @@ export const ListItem: {
|
|
|
157
159
|
OpenTrigger: ListItemOpenTrigger,
|
|
158
160
|
CollapsibleContent: ListItemCollapsibleContent,
|
|
159
161
|
MockOpenTrigger: MockListItemOpenTrigger,
|
|
162
|
+
DropIndicator: ListDropIndicator,
|
|
160
163
|
};
|
|
161
164
|
|
|
162
165
|
export { List, useListContext, useListItemContext, LIST_NAME, LIST_ITEM_NAME };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
|
|
6
|
+
import React, { type CSSProperties, type HTMLAttributes } from 'react';
|
|
7
|
+
|
|
8
|
+
type Orientation = 'horizontal' | 'vertical';
|
|
9
|
+
|
|
10
|
+
const edgeToOrientationMap: Record<Edge, Orientation> = {
|
|
11
|
+
top: 'horizontal',
|
|
12
|
+
bottom: 'horizontal',
|
|
13
|
+
left: 'vertical',
|
|
14
|
+
right: 'vertical',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const orientationStyles: Record<Orientation, HTMLAttributes<HTMLElement>['className']> = {
|
|
18
|
+
horizontal: 'h-[--line-thickness] left-[--terminal-radius] right-0 before:left-[--negative-terminal-size]',
|
|
19
|
+
vertical: 'w-[--line-thickness] top-[--terminal-radius] bottom-0 before:top-[--negative-terminal-size]',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const edgeStyles: Record<Edge, HTMLAttributes<HTMLElement>['className']> = {
|
|
23
|
+
top: 'top-[--line-offset] before:top-[--offset-terminal]',
|
|
24
|
+
right: 'right-[--line-offset] before:right-[--offset-terminal]',
|
|
25
|
+
bottom: 'bottom-[--line-offset] before:bottom-[--offset-terminal]',
|
|
26
|
+
left: 'left-[--line-offset] before:left-[--offset-terminal]',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const strokeSize = 2;
|
|
30
|
+
const terminalSize = 8;
|
|
31
|
+
const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
|
|
32
|
+
|
|
33
|
+
export type DropIndicatorProps = {
|
|
34
|
+
edge: Edge;
|
|
35
|
+
gap?: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* This is a tailwind port of `@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box`
|
|
40
|
+
*/
|
|
41
|
+
export const ListDropIndicator = ({ edge, gap = 0 }: DropIndicatorProps) => {
|
|
42
|
+
const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
|
|
43
|
+
|
|
44
|
+
const orientation = edgeToOrientationMap[edge];
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
role='none'
|
|
49
|
+
style={
|
|
50
|
+
{
|
|
51
|
+
'--line-thickness': `${strokeSize}px`,
|
|
52
|
+
'--line-offset': `${lineOffset}`,
|
|
53
|
+
'--terminal-size': `${terminalSize}px`,
|
|
54
|
+
'--terminal-radius': `${terminalSize / 2}px`,
|
|
55
|
+
'--negative-terminal-size': `-${terminalSize}px`,
|
|
56
|
+
'--offset-terminal': `${offsetToAlignTerminalWithLine}px`,
|
|
57
|
+
} as CSSProperties
|
|
58
|
+
}
|
|
59
|
+
className={`absolute z-10 pointer-events-none bg-accentSurface before:content-[''] before:w-[--terminal-size] before:h-[--terminal-size] box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accentSurface before:rounded-full ${orientationStyles[orientation]} ${edgeStyles[edge]}`}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
LIST_ITEM_NAME,
|
|
17
17
|
useListItemContext,
|
|
18
18
|
} from './List';
|
|
19
|
+
import { TreeDropIndicator } from './TreeDropIndicator';
|
|
19
20
|
import { type ThemedClassName } from '../../util';
|
|
20
21
|
|
|
21
22
|
type TreeRootProps = ListProps;
|
|
@@ -60,12 +61,14 @@ export const TreeItem: {
|
|
|
60
61
|
Body: ForwardRefExoticComponent<TreeItemBodyProps>;
|
|
61
62
|
OpenTrigger: ForwardRefExoticComponent<TreeItemOpenTriggerProps>;
|
|
62
63
|
MockOpenTrigger: FC<ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'children'>>>;
|
|
64
|
+
DropIndicator: typeof TreeDropIndicator;
|
|
63
65
|
} = {
|
|
64
66
|
Root: TreeItemRoot,
|
|
65
67
|
Heading: TreeItemHeading,
|
|
66
68
|
Body: TreeItemBody,
|
|
67
69
|
OpenTrigger: TreeItemOpenTrigger,
|
|
68
70
|
MockOpenTrigger: MockTreeItemOpenTrigger,
|
|
71
|
+
DropIndicator: TreeDropIndicator,
|
|
69
72
|
};
|
|
70
73
|
|
|
71
74
|
export type { TreeRootProps, TreeItemProps, TreeItemHeadingProps, TreeItemBodyProps, TreeItemOpenTriggerProps };
|
|
@@ -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
|
+
};
|
|
@@ -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';
|
|
@@ -227,7 +225,7 @@ const MainSidebar = forwardRef<HTMLDivElement, MainSidebarProps>(
|
|
|
227
225
|
{...(!open && { inert: 'true' })}
|
|
228
226
|
ref={ref}
|
|
229
227
|
>
|
|
230
|
-
|
|
228
|
+
{children}
|
|
231
229
|
</Root>
|
|
232
230
|
</DialogRoot>
|
|
233
231
|
);
|
|
@@ -334,47 +332,12 @@ const MainOverlay = forwardRef<HTMLDivElement, MainOverlayProps>(({ classNames,
|
|
|
334
332
|
);
|
|
335
333
|
});
|
|
336
334
|
|
|
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
335
|
export const Main = {
|
|
372
336
|
Root: MainRoot,
|
|
373
337
|
Content: MainContent,
|
|
374
338
|
Overlay: MainOverlay,
|
|
375
339
|
NavigationSidebar: MainNavigationSidebar,
|
|
376
340
|
ComplementarySidebar: MainComplementarySidebar,
|
|
377
|
-
Notch: MainNotch,
|
|
378
341
|
};
|
|
379
342
|
|
|
380
343
|
export { useMainContext, useSidebars };
|
|
@@ -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
|
|