@dxos/react-ui 0.7.4-staging.f7e8224 → 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.
Files changed (88) hide show
  1. package/dist/lib/browser/index.mjs +454 -290
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +712 -560
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +454 -290
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/Buttons/IconButton.d.ts +4 -2
  11. package/dist/types/src/components/Buttons/IconButton.d.ts.map +1 -1
  12. package/dist/types/src/components/Dialogs/AlertDialog.d.ts.map +1 -1
  13. package/dist/types/src/components/Dialogs/Dialog.d.ts.map +1 -1
  14. package/dist/types/src/components/Input/Input.d.ts +5 -6
  15. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  16. package/dist/types/src/components/Input/Input.stories.d.ts +1 -3
  17. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  18. package/dist/types/src/components/Lists/List.d.ts +2 -0
  19. package/dist/types/src/components/Lists/List.d.ts.map +1 -1
  20. package/dist/types/src/components/Lists/ListDropIndicator.d.ts +11 -0
  21. package/dist/types/src/components/Lists/ListDropIndicator.d.ts.map +1 -0
  22. package/dist/types/src/components/Lists/Tree.d.ts +2 -0
  23. package/dist/types/src/components/Lists/Tree.d.ts.map +1 -1
  24. package/dist/types/src/components/Lists/TreeDropIndicator.d.ts +8 -0
  25. package/dist/types/src/components/Lists/TreeDropIndicator.d.ts.map +1 -0
  26. package/dist/types/src/components/Main/Main.d.ts +0 -2
  27. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  28. package/dist/types/src/components/Menus/ContextMenu.d.ts.map +1 -1
  29. package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +1 -1
  30. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  31. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  32. package/dist/types/src/components/Separator/Separator.d.ts +3 -1
  33. package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
  34. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +4 -2
  35. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  36. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -0
  37. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  38. package/dist/types/src/components/Toolbar/Toolbar.d.ts +15 -5
  39. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  40. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +7 -2
  41. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  43. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +13 -1
  44. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  45. package/dist/types/src/hooks/index.d.ts +1 -0
  46. package/dist/types/src/hooks/index.d.ts.map +1 -1
  47. package/dist/types/src/hooks/useSafeArea.d.ts +9 -0
  48. package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -0
  49. package/dist/types/src/hooks/useSafeCollisionPadding.d.ts +10 -0
  50. package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -0
  51. package/dist/types/src/hooks/useVisualViewport.d.ts +1 -1
  52. package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
  53. package/dist/types/src/util/ThemedClassName.d.ts +1 -1
  54. package/dist/types/src/util/ThemedClassName.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -0
  56. package/package.json +13 -12
  57. package/src/components/Buttons/IconButton.tsx +22 -5
  58. package/src/components/Clipboard/CopyButton.tsx +1 -1
  59. package/src/components/Dialogs/AlertDialog.tsx +6 -2
  60. package/src/components/Dialogs/Dialog.tsx +7 -11
  61. package/src/components/Input/Input.stories.tsx +4 -6
  62. package/src/components/Input/Input.tsx +29 -44
  63. package/src/components/Lists/List.stories.tsx +2 -2
  64. package/src/components/Lists/List.tsx +3 -0
  65. package/src/components/Lists/ListDropIndicator.tsx +62 -0
  66. package/src/components/Lists/Tree.tsx +3 -0
  67. package/src/components/Lists/TreeDropIndicator.tsx +70 -0
  68. package/src/components/Main/Main.tsx +1 -38
  69. package/src/components/Menus/ContextMenu.tsx +8 -6
  70. package/src/components/Menus/DropdownMenu.tsx +7 -4
  71. package/src/components/Popover/Popover.tsx +8 -2
  72. package/src/components/ScrollArea/ScrollArea.stories.tsx +2 -2
  73. package/src/components/Select/Select.tsx +7 -3
  74. package/src/components/Separator/Separator.tsx +14 -11
  75. package/src/components/ThemeProvider/ThemeProvider.tsx +13 -5
  76. package/src/components/Toast/Toast.tsx +1 -1
  77. package/src/components/Toolbar/Toolbar.tsx +40 -10
  78. package/src/components/Tooltip/Tooltip.stories.tsx +13 -2
  79. package/src/components/Tooltip/Tooltip.tsx +18 -13
  80. package/src/hooks/index.ts +1 -0
  81. package/src/hooks/useSafeArea.ts +25 -0
  82. package/src/hooks/useSafeCollisionPadding.ts +39 -0
  83. package/src/hooks/useVisualViewport.ts +11 -12
  84. package/src/testing/decorators/withVariants.tsx +4 -4
  85. package/src/util/ThemedClassName.ts +1 -1
  86. package/dist/types/src/playground/Surfaces.stories.d.ts +0 -21
  87. package/dist/types/src/playground/Surfaces.stories.d.ts.map +0 -1
  88. 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, surfaceElevation } from '@dxos/react-ui-theme';
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', surfaceElevation({ elevation: 'group' }))}>
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', surfaceElevation({ elevation: 'chrome' }))}>
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 checked, indeterminate, or unchecked',
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 { Check, type IconWeight, Minus } from '@phosphor-icons/react';
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, Fragment, useCallback } from 'react';
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
- const Icon = checked === 'indeterminate' ? Minus : checked ? Check : Fragment;
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
- <CheckboxIndicatorPrimitive asChild>
283
- <Icon
284
- {...(checked && {
285
- weight,
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<Omit<SwitchPrimitiveProps, 'children'>> & { size?: Size };
283
+ type SwitchProps = ThemedClassName<
284
+ Omit<ComponentPropsWithRef<'input'>, 'children' | 'onChange'> & { onCheckedChange?: (checked: boolean) => void }
285
+ >;
296
286
 
297
- const Switch: ForwardRefExoticComponent<SwitchProps> = forwardRef<HTMLButtonElement, InputScopedProps<SwitchProps>>(
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
- <SwitchPrimitive
321
- {...{
322
- ...props,
323
- checked,
324
- onCheckedChange,
325
- id,
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
- surfaceElevation,
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
- surfaceElevation({ elevation: 'group' }),
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
- <ElevationProvider elevation='group'>{children}</ElevationProvider>
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
- className={tx('menu.content', 'menu', {}, classNames)}
37
+ collisionPadding={safeCollisionPadding}
38
+ className={tx('menu.content', 'menu', { elevation }, classNames)}
37
39
  ref={forwardedRef}
38
40
  >
39
- <ElevationProvider elevation='chrome'>{children}</ElevationProvider>
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
- className={tx('popover.content', 'popover', {}, classNames)}
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, surfaceElevation } from '@dxos/react-ui-theme';
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, surfaceElevation({ elevation: 'group' })]}
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
- className={tx('select.content', 'select__content', {}, classNames)}
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 = ({ classNames, orientation = 'horizontal', ...props }: SeparatorProps) => {
16
- const { tx } = useThemeContext();
17
- return (
18
- <SeparatorPrimitive
19
- orientation={orientation}
20
- {...props}
21
- className={tx('separator.root', 'separator', { orientation }, classNames)}
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