@dxos/react-ui-stack 0.8.4-main.dedc0f3 → 0.8.4-main.dfabb4ec29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/lib/browser/index.mjs +704 -67
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/playwright/index.mjs +10 -23
  5. package/dist/lib/browser/playwright/index.mjs.map +2 -2
  6. package/dist/lib/browser/translations.mjs +23 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/lib/node-esm/index.mjs +705 -67
  9. package/dist/lib/node-esm/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/meta.json +1 -1
  11. package/dist/lib/node-esm/playwright/index.mjs +10 -23
  12. package/dist/lib/node-esm/playwright/index.mjs.map +2 -2
  13. package/dist/lib/node-esm/translations.mjs +25 -0
  14. package/dist/lib/node-esm/translations.mjs.map +7 -0
  15. package/dist/types/src/components/Stack/Stack.d.ts +5 -9
  16. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  17. package/dist/types/src/components/Stack/Stack.stories.d.ts +1 -2
  18. package/dist/types/src/components/Stack/Stack.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/StackContext.d.ts +1 -1
  20. package/dist/types/src/components/StackContext.d.ts.map +1 -1
  21. package/dist/types/src/components/StackItem/MenuSignifier.d.ts.map +1 -1
  22. package/dist/types/src/components/StackItem/StackItem.d.ts +12 -15
  23. package/dist/types/src/components/StackItem/StackItem.d.ts.map +1 -1
  24. package/dist/types/src/components/StackItem/StackItem.stories.d.ts +0 -1
  25. package/dist/types/src/components/StackItem/StackItem.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/StackItem/StackItemContent.d.ts +4 -37
  27. package/dist/types/src/components/StackItem/StackItemContent.d.ts.map +1 -1
  28. package/dist/types/src/components/StackItem/StackItemDragHandle.d.ts.map +1 -1
  29. package/dist/types/src/components/StackItem/StackItemHeading.d.ts +1 -1
  30. package/dist/types/src/components/StackItem/StackItemHeading.d.ts.map +1 -1
  31. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts +1 -1
  32. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts.map +1 -1
  33. package/dist/types/src/components/StackItem/StackItemSigil.d.ts +2 -2
  34. package/dist/types/src/components/StackItem/StackItemSigil.d.ts.map +1 -1
  35. package/dist/types/src/components/index.d.ts +1 -2
  36. package/dist/types/src/components/index.d.ts.map +1 -1
  37. package/dist/types/src/components/{defs.d.ts → types.d.ts} +1 -1
  38. package/dist/types/src/components/types.d.ts.map +1 -0
  39. package/dist/types/src/hooks/useStackDropForElements.d.ts +8 -6
  40. package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -1
  41. package/dist/types/src/index.d.ts +0 -2
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -1
  44. package/dist/types/src/playwright/stack-manager.d.ts.map +1 -1
  45. package/dist/types/src/translations.d.ts +10 -10
  46. package/dist/types/src/translations.d.ts.map +1 -1
  47. package/dist/types/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +49 -47
  49. package/src/components/Stack/Stack.stories.tsx +10 -14
  50. package/src/components/Stack/Stack.tsx +216 -172
  51. package/src/components/StackContext.tsx +1 -1
  52. package/src/components/StackItem/MenuSignifier.tsx +2 -9
  53. package/src/components/StackItem/StackItem.stories.tsx +8 -8
  54. package/src/components/StackItem/StackItem.tsx +48 -31
  55. package/src/components/StackItem/StackItemContent.tsx +23 -44
  56. package/src/components/StackItem/StackItemDragHandle.tsx +4 -3
  57. package/src/components/StackItem/StackItemHeading.tsx +14 -21
  58. package/src/components/StackItem/StackItemResizeHandle.tsx +1 -2
  59. package/src/components/StackItem/StackItemSigil.tsx +10 -7
  60. package/src/components/index.ts +2 -2
  61. package/src/hooks/useStackDropForElements.ts +60 -46
  62. package/src/index.ts +0 -4
  63. package/src/playwright/playwright.config.ts +1 -1
  64. package/src/translations.ts +9 -9
  65. package/dist/lib/browser/chunk-3V2YUQK5.mjs +0 -1375
  66. package/dist/lib/browser/chunk-3V2YUQK5.mjs.map +0 -7
  67. package/dist/lib/browser/testing/index.mjs +0 -31
  68. package/dist/lib/browser/testing/index.mjs.map +0 -7
  69. package/dist/lib/node-esm/chunk-HE3BRF7A.mjs +0 -1377
  70. package/dist/lib/node-esm/chunk-HE3BRF7A.mjs.map +0 -7
  71. package/dist/lib/node-esm/testing/index.mjs +0 -32
  72. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  73. package/dist/types/src/components/Image/Image.d.ts +0 -11
  74. package/dist/types/src/components/Image/Image.d.ts.map +0 -1
  75. package/dist/types/src/components/Image/Image.stories.d.ts +0 -31
  76. package/dist/types/src/components/Image/Image.stories.d.ts.map +0 -1
  77. package/dist/types/src/components/Image/index.d.ts +0 -2
  78. package/dist/types/src/components/Image/index.d.ts.map +0 -1
  79. package/dist/types/src/components/defs.d.ts.map +0 -1
  80. package/dist/types/src/components/deprecated/LayoutControls.d.ts +0 -19
  81. package/dist/types/src/components/deprecated/LayoutControls.d.ts.map +0 -1
  82. package/dist/types/src/exemplars/Card/Card.d.ts +0 -58
  83. package/dist/types/src/exemplars/Card/Card.d.ts.map +0 -1
  84. package/dist/types/src/exemplars/Card/Card.stories.d.ts +0 -44
  85. package/dist/types/src/exemplars/Card/Card.stories.d.ts.map +0 -1
  86. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts +0 -6
  87. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts.map +0 -1
  88. package/dist/types/src/exemplars/Card/fragments.d.ts +0 -13
  89. package/dist/types/src/exemplars/Card/fragments.d.ts.map +0 -1
  90. package/dist/types/src/exemplars/Card/index.d.ts +0 -4
  91. package/dist/types/src/exemplars/Card/index.d.ts.map +0 -1
  92. package/dist/types/src/exemplars/CardStack/CardStack.d.ts +0 -40
  93. package/dist/types/src/exemplars/CardStack/CardStack.d.ts.map +0 -1
  94. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts +0 -13
  95. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts.map +0 -1
  96. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts +0 -9
  97. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts.map +0 -1
  98. package/dist/types/src/exemplars/CardStack/index.d.ts +0 -3
  99. package/dist/types/src/exemplars/CardStack/index.d.ts.map +0 -1
  100. package/dist/types/src/exemplars/index.d.ts +0 -3
  101. package/dist/types/src/exemplars/index.d.ts.map +0 -1
  102. package/dist/types/src/testing/CardContainer.d.ts +0 -6
  103. package/dist/types/src/testing/CardContainer.d.ts.map +0 -1
  104. package/dist/types/src/testing/index.d.ts +0 -2
  105. package/dist/types/src/testing/index.d.ts.map +0 -1
  106. package/src/components/Image/Image.stories.tsx +0 -58
  107. package/src/components/Image/Image.tsx +0 -137
  108. package/src/components/Image/index.ts +0 -5
  109. package/src/components/deprecated/LayoutControls.tsx +0 -109
  110. package/src/exemplars/Card/Card.stories.tsx +0 -88
  111. package/src/exemplars/Card/Card.tsx +0 -186
  112. package/src/exemplars/Card/CardDragPreview.tsx +0 -22
  113. package/src/exemplars/Card/fragments.ts +0 -24
  114. package/src/exemplars/Card/index.ts +0 -7
  115. package/src/exemplars/CardStack/CardStack.stories.tsx +0 -172
  116. package/src/exemplars/CardStack/CardStack.tsx +0 -136
  117. package/src/exemplars/CardStack/CardStackDragPreview.tsx +0 -61
  118. package/src/exemplars/CardStack/index.ts +0 -6
  119. package/src/exemplars/index.ts +0 -6
  120. package/src/testing/CardContainer.tsx +0 -37
  121. package/src/testing/index.ts +0 -5
  122. /package/src/components/{defs.ts → types.ts} +0 -0
@@ -2,15 +2,15 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
- import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
8
- import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
9
5
  import {
10
6
  type Edge,
11
7
  attachClosestEdge,
12
8
  extractClosestEdge,
13
9
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
10
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
11
+ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
12
+ import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
13
+ import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
14
14
  import { useFocusableGroup } from '@fluentui/react-tabster';
15
15
  import { composeRefs } from '@radix-ui/react-compose-refs';
16
16
  import React, {
@@ -26,11 +26,10 @@ import { createPortal } from 'react-dom';
26
26
 
27
27
  import { ListItem, type ThemedClassName } from '@dxos/react-ui';
28
28
  import { resizeAttributes, sizeStyle } from '@dxos/react-ui-dnd';
29
- import { mx } from '@dxos/react-ui-theme';
29
+ import { mx } from '@dxos/ui-theme';
30
30
 
31
- import { type StackItemData, type StackItemSize } from '../defs';
32
31
  import { type ItemDragState, StackItemContext, idle, useStack, useStackItem } from '../StackContext';
33
-
32
+ import { type StackItemData, type StackItemSize } from '../types';
34
33
  import { StackItemContent, type StackItemContentProps } from './StackItemContent';
35
34
  import { StackItemDragHandle, type StackItemDragHandleProps } from './StackItemDragHandle';
36
35
  import {
@@ -49,36 +48,39 @@ import {
49
48
  type StackItemSigilProps,
50
49
  } from './StackItemSigil';
51
50
 
52
- // NOTE: 48rem fills the screen on a MacbookPro with the sidebars closed.
53
- export const DEFAULT_HORIZONTAL_SIZE = 48 satisfies StackItemSize;
54
51
  export const DEFAULT_VERTICAL_SIZE = 'min-content' satisfies StackItemSize;
52
+ export const DEFAULT_HORIZONTAL_SIZE = 50 satisfies StackItemSize;
55
53
  export const DEFAULT_EXTRINSIC_SIZE = DEFAULT_HORIZONTAL_SIZE satisfies StackItemSize;
56
54
 
55
+ //
56
+ // StackItemRoot
57
+ //
58
+
57
59
  type StackItemRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
60
+ role?: 'article' | 'section';
58
61
  item: Omit<StackItemData, 'type'>;
59
62
  order?: number;
60
63
  prevSiblingId?: string;
61
64
  nextSiblingId?: string;
62
65
  size?: StackItemSize;
63
66
  onSizeChange?: (nextSize: StackItemSize) => void;
64
- role?: 'article' | 'section';
65
67
  disableRearrange?: boolean;
66
- focusIndicatorVariant?: 'over-all' | 'group';
68
+ focusIndicatorVariant?: 'over-all' | 'group' | 'over-all-always' | 'group-always';
67
69
  };
68
70
 
69
71
  const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
70
72
  (
71
73
  {
72
- item,
73
- children,
74
74
  classNames,
75
- size: propsSize,
76
- onSizeChange,
75
+ children,
76
+ style,
77
77
  role,
78
+ item,
78
79
  order,
79
80
  prevSiblingId,
80
81
  nextSiblingId,
81
- style,
82
+ size: sizeProp,
83
+ onSizeChange,
82
84
  disableRearrange,
83
85
  focusIndicatorVariant = 'over-all',
84
86
  ...props
@@ -86,18 +88,17 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
86
88
  forwardedRef,
87
89
  ) => {
88
90
  const [itemElement, itemRef] = useState<HTMLDivElement | null>(null);
91
+ const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
89
92
  const [selfDragHandleElement, selfDragHandleRef] = useState<HTMLDivElement | null>(null);
90
93
  const [closestEdge, setEdge] = useState<Edge | null>(null);
91
94
  const [sourceId, setSourceId] = useState<string | null>(null);
92
95
  const [dragState, setDragState] = useState<ItemDragState>(idle);
93
96
  const { orientation, rail, onRearrange, size: stackSize, stackId } = useStack();
94
97
  const [size = orientation === 'horizontal' ? DEFAULT_HORIZONTAL_SIZE : DEFAULT_VERTICAL_SIZE, setInternalSize] =
95
- useState(propsSize);
98
+ useState(sizeProp);
96
99
 
97
100
  const Root = role ?? 'div';
98
101
 
99
- const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
100
-
101
102
  const setSize = useCallback(
102
103
  (nextSize: StackItemSize, commit?: boolean) => {
103
104
  setInternalSize(nextSize);
@@ -110,6 +111,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
110
111
 
111
112
  const type = orientation === 'horizontal' ? 'column' : 'card';
112
113
 
114
+ // TODO(burdon): Factor out?
113
115
  useLayoutEffect(() => {
114
116
  if (!itemElement || !onRearrange || disableRearrange) {
115
117
  return;
@@ -183,18 +185,18 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
183
185
 
184
186
  const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
185
187
 
186
- // Determine if the drop would result in any changes
188
+ // Determine if the drop would result in any changes.
187
189
  const shouldShowDropIndicator = () => {
188
190
  if (!closestEdge || !sourceId) {
189
191
  return false;
190
192
  }
191
193
 
192
- // Don't show indicator when dragged item is over itself
194
+ // Don't show indicator when dragged item is over itself.
193
195
  if (sourceId === item.id) {
194
196
  return false;
195
197
  }
196
198
 
197
- // Don't show indicator when dragged item is over the trailing edge of its previous sibling
199
+ // Don't show indicator when dragged item is over the trailing edge of its previous sibling.
198
200
  const isTrailingEdgeOfPrevSibling =
199
201
  prevSiblingId !== undefined &&
200
202
  sourceId === prevSiblingId &&
@@ -232,15 +234,22 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
232
234
  'group/stack-item grid relative',
233
235
  focusIndicatorVariant === 'over-all'
234
236
  ? 'dx-focus-ring-inset-over-all'
235
- : orientation === 'horizontal'
236
- ? 'dx-focus-ring-group-x'
237
- : 'dx-focus-ring-group-y',
237
+ : focusIndicatorVariant === 'over-all-always'
238
+ ? 'dx-focus-ring-inset-over-all-always'
239
+ : orientation === 'horizontal'
240
+ ? focusIndicatorVariant === 'group-always'
241
+ ? 'dx-focus-ring-group-x-always'
242
+ : 'dx-focus-ring-group-x'
243
+ : focusIndicatorVariant === 'group-always'
244
+ ? 'dx-focus-ring-group-y-always'
245
+ : 'dx-focus-ring-group-y',
238
246
  orientation === 'horizontal' ? 'grid-rows-subgrid' : 'grid-cols-subgrid',
239
247
  rail && (orientation === 'horizontal' ? 'row-span-2' : 'col-span-2'),
240
- role === 'section' && orientation !== 'horizontal' && 'border-be border-subduedSeparator',
248
+ role === 'section' && orientation !== 'horizontal' && 'border-b border-subdued-separator',
241
249
  classNames,
242
250
  )}
243
251
  data-dx-stack-item={stackId}
252
+ data-dx-item-id={item.id}
244
253
  {...resizeAttributes}
245
254
  style={{
246
255
  ...(stackSize !== 'split' && sizeStyle(size, orientation)),
@@ -261,37 +270,45 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
261
270
  },
262
271
  );
263
272
 
273
+ //
274
+ // StackItemDragPreview
275
+ //
276
+
264
277
  type StackItemDragPreviewProps = {
265
278
  children: ({ item }: { item: any }) => ReactNode;
266
279
  };
267
280
 
268
- export const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
281
+ const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
269
282
  const { state } = useStackItem();
270
283
  return state?.type === 'preview' ? createPortal(children({ item: state.item }), state.container) : null;
271
284
  };
272
285
 
286
+ //
287
+ // StackItem
288
+ //
289
+
273
290
  export const StackItem = {
274
291
  Root: StackItemRoot,
275
292
  Content: StackItemContent,
293
+ DragHandle: StackItemDragHandle,
294
+ DragPreview: StackItemDragPreview,
276
295
  Heading: StackItemHeading,
277
296
  HeadingLabel: StackItemHeadingLabel,
278
297
  HeadingStickyContent: StackItemHeadingStickyContent,
279
298
  ResizeHandle: StackItemResizeHandle,
280
- DragHandle: StackItemDragHandle,
281
299
  Sigil: StackItemSigil,
282
300
  SigilButton: StackItemSigilButton,
283
- DragPreview: StackItemDragPreview,
284
301
  };
285
302
 
286
303
  export type {
287
304
  StackItemRootProps,
288
305
  StackItemContentProps,
306
+ StackItemDragHandleProps,
307
+ StackItemDragPreviewProps,
289
308
  StackItemHeadingProps,
290
309
  StackItemHeadingLabelProps,
291
310
  StackItemResizeHandleProps,
292
- StackItemDragHandleProps,
293
311
  StackItemSigilProps,
294
312
  StackItemSigilButtonProps,
295
313
  StackItemSigilAction,
296
- StackItemDragPreviewProps,
297
314
  };
@@ -5,71 +5,48 @@
5
5
  import React, { type ComponentPropsWithoutRef, forwardRef, useMemo } from 'react';
6
6
 
7
7
  import { type ThemedClassName } from '@dxos/react-ui';
8
- import { mx } from '@dxos/react-ui-theme';
8
+ import { mx } from '@dxos/ui-theme';
9
9
 
10
10
  import { useStack, useStackItem } from '../StackContext';
11
11
 
12
- export type StackItemContentProps = ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'role'>> & {
13
- /**
14
- * This flag is required in order to clarify a developer experience that seemed like it needed extra boilerplate
15
- * (`row-span-2`) or was buggy. See the description of the StackItem.Content component itself for more information.
16
- */
12
+ export type StackItemContentProps = ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'role' | 'scrollable'>> & {
17
13
  toolbar?: boolean;
18
-
19
- /**
20
- * Whether to provide for the layout of a statusbar after the content.
21
- */
22
14
  statusbar?: boolean;
23
-
24
- /**
25
- * Whether the consumer intends to do something custom and typical affordances should not apply
26
- */
27
- layoutManaged?: boolean;
28
-
29
- /**
30
- * Whether to set a certain aspect ratio on the content, including the toolbar and statusbar. This is provided for
31
- * convenience and consistency; it can instead be specified by the `classNames` or `style` props as needed.
32
- */
33
- size?: 'intrinsic' | 'video' | 'square';
34
15
  };
35
16
 
36
17
  /**
37
- * This component should be used by plugins for rendering content within a stack item, a.k.a. a “plank” or “section”.
38
- * The `toolbar` flag must be provided since this component provides for the layout of content with the toolbar.
18
+ * This component should be used by plugins for rendering content within a stack item (i.e., a “plank” or “section”).
39
19
  */
40
20
  export const StackItemContent = forwardRef<HTMLDivElement, StackItemContentProps>(
41
- ({ children, toolbar, statusbar, layoutManaged, classNames, size = 'intrinsic', ...props }, forwardedRef) => {
21
+ ({ classNames, children, toolbar, statusbar, ...props }, forwardedRef) => {
42
22
  const { size: stackItemSize } = useStack();
43
23
  const { role } = useStackItem();
44
24
  const style = useMemo(
45
- () =>
46
- layoutManaged
47
- ? {}
48
- : {
49
- gridTemplateRows: [
50
- ...(toolbar ? [role === 'section' ? 'calc(var(--toolbar-size) - 1px)' : 'var(--toolbar-size)'] : []),
51
- '1fr',
52
- ...(statusbar ? ['var(--statusbar-size)'] : []),
53
- ].join(' '),
54
- },
55
- [toolbar, statusbar, layoutManaged],
25
+ () => ({
26
+ gridTemplateRows: [
27
+ toolbar && role === 'section' ? 'calc(var(--dx-toolbar-size) - 1px)' : 'var(--dx-toolbar-size)',
28
+ '1fr',
29
+ statusbar && 'var(--dx-statusbar-size)',
30
+ ]
31
+ .filter(Boolean)
32
+ .join(' '),
33
+ }),
34
+ [toolbar, statusbar],
56
35
  );
57
36
 
58
37
  return (
59
38
  <div
60
- role='none'
61
39
  {...props}
40
+ style={style}
62
41
  className={mx(
63
- 'group grid grid-cols-[100%] density-coarse',
64
- stackItemSize === 'contain' && 'min-bs-0 overflow-hidden',
65
- size === 'video' ? 'aspect-video' : size === 'square' && 'aspect-square',
66
- toolbar && '[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-be [&>.dx-toolbar]:border-subduedSeparator',
67
- role === 'section' &&
68
- toolbar &&
69
- '[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:block-start-0 [&_.dx-toolbar]:-mbe-px [&_.dx-toolbar]:min-is-0',
42
+ 'group grid grid-cols-[100%] dx-density-coarse',
43
+ stackItemSize === 'contain' && 'min-h-0 overflow-hidden',
44
+ toolbar &&
45
+ role === 'section' &&
46
+ '[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:top-0 [&_.dx-toolbar]:-mb-px [&_.dx-toolbar]:min-w-0',
47
+ toolbar && '[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-b [&>.dx-toolbar]:border-subdued-separator',
70
48
  classNames,
71
49
  )}
72
- style={style}
73
50
  data-popover-collision-boundary={true}
74
51
  ref={forwardedRef}
75
52
  >
@@ -78,3 +55,5 @@ export const StackItemContent = forwardRef<HTMLDivElement, StackItemContentProps
78
55
  );
79
56
  },
80
57
  );
58
+
59
+ StackItemContent.displayName = 'StackItemContent';
@@ -2,6 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Primitive } from '@radix-ui/react-primitive';
5
6
  import { Slot } from '@radix-ui/react-slot';
6
7
  import React, { type ComponentPropsWithoutRef } from 'react';
7
8
 
@@ -12,11 +13,11 @@ export type StackItemDragHandleProps = ComponentPropsWithoutRef<'button'> & { as
12
13
  export const StackItemDragHandle = ({ asChild, children }: StackItemDragHandleProps) => {
13
14
  const { selfDragHandleRef } = useStackItem();
14
15
 
15
- const Root = asChild ? Slot : 'div';
16
+ const Comp = asChild ? Slot : Primitive.div;
16
17
 
17
18
  return (
18
- <Root ref={selfDragHandleRef} role='button'>
19
+ <Comp ref={selfDragHandleRef} role='button'>
19
20
  {children}
20
- </Root>
21
+ </Comp>
21
22
  );
22
23
  };
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { useFocusableGroup } from '@fluentui/react-tabster';
5
+ import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import React, {
8
8
  type ComponentPropsWithRef,
@@ -13,7 +13,7 @@ import React, {
13
13
 
14
14
  import { type ThemedClassName } from '@dxos/react-ui';
15
15
  import { type AttendableId, type Related, useAttention } from '@dxos/react-ui-attention';
16
- import { mx } from '@dxos/react-ui-theme';
16
+ import { mx } from '@dxos/ui-theme';
17
17
 
18
18
  import { useStack } from '../StackContext';
19
19
 
@@ -27,40 +27,33 @@ export const StackItemHeading = ({
27
27
  classNames,
28
28
  asChild,
29
29
  separateOnScroll,
30
+ role,
30
31
  ...props
31
32
  }: StackItemHeadingProps) => {
32
33
  const { orientation } = useStack();
33
- const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
34
-
35
- const Root = asChild ? Slot : 'div';
34
+ const Comp = asChild ? Slot : Primitive.div;
36
35
 
37
36
  return (
38
- <Root
39
- role='heading'
37
+ <Comp
40
38
  {...props}
41
- tabIndex={0}
42
- {...focusableGroupAttrs}
39
+ role={role ?? 'heading'}
43
40
  className={mx(
44
- 'flex items-center dx-focus-ring-inset-over-all relative !border-is-0 bg-headerSurface',
41
+ 'flex items-center border-x-0! bg-header-surface',
45
42
  separateOnScroll
46
- ? 'border-transparent [[data-scroll-separator="true"]_&]:border-subduedSeparator'
47
- : 'border-subduedSeparator',
48
- orientation === 'horizontal' ? 'bs-[--rail-size]' : 'is-[--rail-size] flex-col',
49
- orientation === 'horizontal' ? 'border-be' : 'border-ie',
43
+ ? 'border-transparent [[data-scroll-separator="true"]_&]:border-subdued-separator'
44
+ : 'border-subdued-separator',
45
+ orientation === 'horizontal' ? 'h-(--dx-rail-size)' : 'w-(--dx-rail-size) flex-col',
46
+ orientation === 'horizontal' ? 'border-b' : 'border-e',
50
47
  classNames,
51
48
  )}
52
49
  >
53
50
  {children}
54
- </Root>
51
+ </Comp>
55
52
  );
56
53
  };
57
54
 
58
55
  export const StackItemHeadingStickyContent = ({ children }: PropsWithChildren<{}>) => {
59
- return (
60
- <div role='none' className='sticky block-start-0 bg-[--sticky-bg] p-1 is-full'>
61
- {children}
62
- </div>
63
- );
56
+ return <div className='sticky top-0 bg-(--sticky-bg) p-1 w-full'>{children}</div>;
64
57
  };
65
58
 
66
59
  export type StackItemHeadingLabelProps = ThemedClassName<ComponentPropsWithRef<'h1'>> & AttendableId & Related;
@@ -74,7 +67,7 @@ export const StackItemHeadingLabel = forwardRef<HTMLHeadingElement, StackItemHea
74
67
  {...props}
75
68
  data-attention={((related && isRelated) || hasAttention || isAncestor).toString()}
76
69
  className={mx(
77
- 'pli-1 min-is-0 is-0 grow truncate font-medium text-baseText data-[attention=true]:text-accentText self-center',
70
+ 'px-1 min-w-0 w-0 grow truncate font-medium text-base-surface-text data-[attention=true]:text-accent-text self-center',
78
71
  classNames,
79
72
  )}
80
73
  ref={forwardedRef}
@@ -7,7 +7,6 @@ import React from 'react';
7
7
  import { ResizeHandle } from '@dxos/react-ui-dnd';
8
8
 
9
9
  import { useStack, useStackItem } from '../StackContext';
10
-
11
10
  import { DEFAULT_EXTRINSIC_SIZE } from './StackItem';
12
11
 
13
12
  const MIN_WIDTH = 20;
@@ -15,7 +14,7 @@ const MIN_HEIGHT = 3;
15
14
 
16
15
  export type StackItemResizeHandleProps = {};
17
16
 
18
- export const StackItemResizeHandle = () => {
17
+ export const StackItemResizeHandle = (_: StackItemResizeHandleProps) => {
19
18
  const { orientation } = useStack();
20
19
  const { setSize, size } = useStackItem();
21
20
 
@@ -4,14 +4,14 @@
4
4
 
5
5
  import React, { Fragment, type PropsWithChildren, forwardRef, useState } from 'react';
6
6
 
7
- import { type ActionLike } from '@dxos/app-graph';
7
+ import { type Node } from '@dxos/app-graph';
8
8
  import { keySymbols } from '@dxos/keyboard';
9
9
  import { Button, type ButtonProps, DropdownMenu, Icon, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
10
  import { type AttendableId, type Related, useAttention } from '@dxos/react-ui-attention';
11
- import { descriptionText, mx } from '@dxos/react-ui-theme';
11
+ import { mx } from '@dxos/ui-theme';
12
12
  import { getHostPlatform } from '@dxos/util';
13
13
 
14
- import { translationKey } from '../../translations';
14
+ import { translationKey } from '#translations';
15
15
 
16
16
  import { MenuSignifierHorizontal } from './MenuSignifier';
17
17
 
@@ -23,7 +23,7 @@ export type KeyBinding = {
23
23
  unknown?: string;
24
24
  };
25
25
 
26
- export type StackItemSigilAction = Pick<ActionLike, 'id' | 'properties' | 'data'>;
26
+ export type StackItemSigilAction = Pick<Node.ActionLike, 'id' | 'properties' | 'data'>;
27
27
 
28
28
  export type StackItemSigilButtonProps = Omit<ButtonProps, 'variant'> &
29
29
  AttendableId &
@@ -40,7 +40,10 @@ export const StackItemSigilButton = forwardRef<HTMLButtonElement, StackItemSigil
40
40
  <Button
41
41
  {...props}
42
42
  variant={variant}
43
- classNames={['shrink-0 pli-0 min-bs-0 is-[--rail-action] bs-[--rail-action] relative app-no-drag', classNames]}
43
+ classNames={[
44
+ 'shrink-0 px-0 min-h-0 w-(--dx-rail-action) h-(--dx-rail-action) relative dx-app-no-drag',
45
+ classNames,
46
+ ]}
44
47
  ref={forwardedRef}
45
48
  >
46
49
  {isMenu && <MenuSignifierHorizontal />}
@@ -78,7 +81,7 @@ export const StackItemSigil = forwardRef<HTMLButtonElement, StackItemSigilProps>
78
81
  classNames={!hasActions && 'cursor-default'}
79
82
  >
80
83
  <span className='sr-only'>{triggerLabel}</span>
81
- <Icon icon={icon} size={5} />
84
+ <Icon icon={icon} />
82
85
  </StackItemSigilButton>
83
86
  );
84
87
 
@@ -133,7 +136,7 @@ export const StackItemSigil = forwardRef<HTMLButtonElement, StackItemSigilProps>
133
136
  </DropdownMenu.ItemIndicator>
134
137
  )}
135
138
  {shortcut && (
136
- <span className={mx('shrink-0', descriptionText)}>{keySymbols(shortcut).join('')}</span>
139
+ <span className={mx('shrink-0', 'text-description')}>{keySymbols(shortcut).join('')}</span>
137
140
  )}
138
141
  </Root>
139
142
  );
@@ -2,8 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export type * from './defs';
5
+ export type * from './types';
6
6
 
7
- export * from './Image';
8
7
  export * from './Stack';
8
+
9
9
  export * from './StackItem';
@@ -2,76 +2,90 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
5
  import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
8
6
  import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
7
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
8
+ import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
9
9
  import { useLayoutEffect, useState } from 'react';
10
10
 
11
11
  import { type Orientation, type StackItemData, type StackItemRearrangeHandler } from '../components';
12
12
 
13
+ const noop = () => {};
14
+
15
+ export type UseStackDropForElementsProps = {
16
+ id?: string;
17
+ element: HTMLDivElement | null;
18
+ scrollElement?: HTMLDivElement | null;
19
+ orientation: Orientation;
20
+ selfDroppable: boolean;
21
+ onRearrange?: StackItemRearrangeHandler;
22
+ };
23
+
24
+ export type UseStackDropForElements = {
25
+ dropping: boolean;
26
+ };
27
+
13
28
  /**
14
- * Hook to handle drag and drop functionality for Stack components.
29
+ * Hook to handle drag-and-drop functionality for Stack components.
15
30
  */
16
31
  export const useStackDropForElements = ({
17
32
  id,
18
33
  element,
19
34
  scrollElement = element,
20
- selfDroppable,
21
35
  orientation,
36
+ selfDroppable,
22
37
  onRearrange,
23
- }: {
24
- id?: string;
25
- element: HTMLDivElement | null;
26
- scrollElement?: HTMLDivElement | null;
27
- selfDroppable: boolean;
28
- orientation: Orientation;
29
- onRearrange?: StackItemRearrangeHandler;
30
- }) => {
38
+ }: UseStackDropForElementsProps): UseStackDropForElements => {
31
39
  const [dropping, setDropping] = useState(false);
32
40
 
33
41
  useLayoutEffect(() => {
34
- if (!element || !selfDroppable) {
42
+ if (!element) {
35
43
  return;
36
44
  }
37
45
 
38
46
  const acceptSourceType = orientation === 'horizontal' ? 'column' : 'card';
39
47
 
48
+ // TODO(burdon): Use monitor?
40
49
  return combine(
41
- dropTargetForElements({
42
- element,
43
- getData: ({ input, element }) => {
44
- return attachClosestEdge(
45
- { id, type: orientation === 'horizontal' ? 'card' : 'column' },
46
- { input, element, allowedEdges: [orientation === 'horizontal' ? 'left' : 'top'] },
47
- );
48
- },
49
- onDragEnter: ({ source }) => {
50
- if (source.data.type === acceptSourceType) {
51
- setDropping(true);
52
- }
53
- },
54
- onDrag: ({ source }) => {
55
- if (source.data.type === acceptSourceType) {
56
- setDropping(true);
57
- }
58
- },
59
- onDragLeave: () => {
60
- return setDropping(false);
61
- },
62
- onDrop: ({ self, source }) => {
63
- setDropping(false);
64
- if (source.data.type === acceptSourceType && selfDroppable && onRearrange) {
65
- onRearrange(source.data as StackItemData, self.data as StackItemData, extractClosestEdge(self.data));
66
- }
67
- },
68
- }),
69
- autoScrollForElements({
70
- element: scrollElement as Element,
71
- getAllowedAxis: () => orientation,
72
- }),
50
+ selfDroppable
51
+ ? dropTargetForElements({
52
+ element,
53
+ getData: ({ input, element }) => {
54
+ return attachClosestEdge(
55
+ { id, type: orientation === 'horizontal' ? 'card' : 'column' },
56
+ { input, element, allowedEdges: [orientation === 'horizontal' ? 'left' : 'top'] },
57
+ );
58
+ },
59
+ onDragEnter: ({ source }) => {
60
+ if (source.data.type === acceptSourceType) {
61
+ setDropping(true);
62
+ }
63
+ },
64
+ onDrag: ({ source }) => {
65
+ if (source.data.type === acceptSourceType) {
66
+ setDropping(true);
67
+ }
68
+ },
69
+ onDragLeave: () => {
70
+ return setDropping(false);
71
+ },
72
+ onDrop: ({ self, source }) => {
73
+ setDropping(false);
74
+ if (source.data.type === acceptSourceType && selfDroppable && onRearrange) {
75
+ onRearrange(source.data as StackItemData, self.data as StackItemData, extractClosestEdge(self.data));
76
+ }
77
+ },
78
+ })
79
+ : noop,
80
+
81
+ scrollElement
82
+ ? autoScrollForElements({
83
+ element: scrollElement,
84
+ getAllowedAxis: () => orientation,
85
+ })
86
+ : noop,
73
87
  );
74
- }, [element, scrollElement, selfDroppable, orientation, id, onRearrange]);
88
+ }, [id, element, scrollElement, selfDroppable, orientation, onRearrange]);
75
89
 
76
90
  return { dropping };
77
91
  };
package/src/index.ts CHANGED
@@ -2,8 +2,4 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- // TODO(thure): Consider exporting exemplars from separate endpoints.
6
-
7
5
  export * from './components';
8
- export * from './exemplars';
9
- export * from './translations';
@@ -10,7 +10,7 @@ export default defineConfig({
10
10
  ...e2ePreset(import.meta.dirname),
11
11
  // TODO(wittjosiah): Avoid hard-coding ports.
12
12
  webServer: {
13
- command: 'moon run storybook:serve-e2e -- --port=9003',
13
+ command: 'pnpm storybook dev --ci --quiet --port=9003 --config-dir=.storybook',
14
14
  port: 9003,
15
15
  reuseExistingServer: false,
16
16
  },