@dxos/react-ui-stack 0.8.4-main.c1de068 → 0.8.4-main.c85a9c8dae

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 (107) hide show
  1. package/dist/lib/browser/index.mjs +743 -57
  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 +4 -0
  5. package/dist/lib/browser/playwright/index.mjs.map +2 -2
  6. package/dist/lib/node-esm/index.mjs +744 -57
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/playwright/index.mjs +4 -0
  10. package/dist/lib/node-esm/playwright/index.mjs.map +2 -2
  11. package/dist/types/src/components/Stack/Stack.d.ts +17 -9
  12. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  13. package/dist/types/src/components/Stack/Stack.stories.d.ts +12 -3
  14. package/dist/types/src/components/Stack/Stack.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/StackContext.d.ts +3 -2
  16. package/dist/types/src/components/StackContext.d.ts.map +1 -1
  17. package/dist/types/src/components/StackItem/MenuSignifier.d.ts.map +1 -1
  18. package/dist/types/src/components/StackItem/StackItem.d.ts +10 -13
  19. package/dist/types/src/components/StackItem/StackItem.d.ts.map +1 -1
  20. package/dist/types/src/components/StackItem/StackItem.stories.d.ts +13 -5
  21. package/dist/types/src/components/StackItem/StackItem.stories.d.ts.map +1 -1
  22. package/dist/types/src/components/StackItem/StackItemContent.d.ts +4 -37
  23. package/dist/types/src/components/StackItem/StackItemContent.d.ts.map +1 -1
  24. package/dist/types/src/components/StackItem/StackItemDragHandle.d.ts.map +1 -1
  25. package/dist/types/src/components/StackItem/StackItemHeading.d.ts +1 -1
  26. package/dist/types/src/components/StackItem/StackItemHeading.d.ts.map +1 -1
  27. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts +1 -1
  28. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts.map +1 -1
  29. package/dist/types/src/components/StackItem/StackItemSigil.d.ts +2 -2
  30. package/dist/types/src/components/StackItem/StackItemSigil.d.ts.map +1 -1
  31. package/dist/types/src/components/index.d.ts +1 -1
  32. package/dist/types/src/components/index.d.ts.map +1 -1
  33. package/dist/types/src/components/{defs.d.ts → types.d.ts} +1 -1
  34. package/dist/types/src/components/types.d.ts.map +1 -0
  35. package/dist/types/src/hooks/useStackDropForElements.d.ts +9 -7
  36. package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -1
  37. package/dist/types/src/index.d.ts +0 -1
  38. package/dist/types/src/index.d.ts.map +1 -1
  39. package/dist/types/src/translations.d.ts +2 -2
  40. package/dist/types/src/translations.d.ts.map +1 -1
  41. package/dist/types/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +41 -38
  43. package/src/components/Stack/Stack.stories.tsx +8 -9
  44. package/src/components/Stack/Stack.tsx +230 -31
  45. package/src/components/StackContext.tsx +3 -2
  46. package/src/components/StackItem/MenuSignifier.tsx +2 -9
  47. package/src/components/StackItem/StackItem.stories.tsx +21 -17
  48. package/src/components/StackItem/StackItem.tsx +51 -31
  49. package/src/components/StackItem/StackItemContent.tsx +25 -44
  50. package/src/components/StackItem/StackItemDragHandle.tsx +4 -3
  51. package/src/components/StackItem/StackItemHeading.tsx +15 -18
  52. package/src/components/StackItem/StackItemResizeHandle.tsx +3 -2
  53. package/src/components/StackItem/StackItemSigil.tsx +10 -6
  54. package/src/components/index.ts +2 -1
  55. package/src/hooks/useStackDropForElements.ts +59 -45
  56. package/src/index.ts +0 -3
  57. package/src/playwright/playwright.config.ts +1 -1
  58. package/src/translations.ts +1 -1
  59. package/dist/lib/browser/chunk-P3TQV4BA.mjs +0 -1198
  60. package/dist/lib/browser/chunk-P3TQV4BA.mjs.map +0 -7
  61. package/dist/lib/browser/testing/index.mjs +0 -31
  62. package/dist/lib/browser/testing/index.mjs.map +0 -7
  63. package/dist/lib/node-esm/chunk-3WVEPAJ4.mjs +0 -1200
  64. package/dist/lib/node-esm/chunk-3WVEPAJ4.mjs.map +0 -7
  65. package/dist/lib/node-esm/testing/index.mjs +0 -32
  66. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  67. package/dist/types/src/components/defs.d.ts.map +0 -1
  68. package/dist/types/src/components/deprecated/LayoutControls.d.ts +0 -19
  69. package/dist/types/src/components/deprecated/LayoutControls.d.ts.map +0 -1
  70. package/dist/types/src/exemplars/Card/Card.d.ts +0 -58
  71. package/dist/types/src/exemplars/Card/Card.d.ts.map +0 -1
  72. package/dist/types/src/exemplars/Card/Card.stories.d.ts +0 -13
  73. package/dist/types/src/exemplars/Card/Card.stories.d.ts.map +0 -1
  74. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts +0 -6
  75. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts.map +0 -1
  76. package/dist/types/src/exemplars/Card/fragments.d.ts +0 -12
  77. package/dist/types/src/exemplars/Card/fragments.d.ts.map +0 -1
  78. package/dist/types/src/exemplars/Card/index.d.ts +0 -4
  79. package/dist/types/src/exemplars/Card/index.d.ts.map +0 -1
  80. package/dist/types/src/exemplars/CardStack/CardStack.d.ts +0 -40
  81. package/dist/types/src/exemplars/CardStack/CardStack.d.ts.map +0 -1
  82. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts +0 -9
  83. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts.map +0 -1
  84. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts +0 -9
  85. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts.map +0 -1
  86. package/dist/types/src/exemplars/CardStack/index.d.ts +0 -3
  87. package/dist/types/src/exemplars/CardStack/index.d.ts.map +0 -1
  88. package/dist/types/src/exemplars/index.d.ts +0 -3
  89. package/dist/types/src/exemplars/index.d.ts.map +0 -1
  90. package/dist/types/src/testing/CardContainer.d.ts +0 -6
  91. package/dist/types/src/testing/CardContainer.d.ts.map +0 -1
  92. package/dist/types/src/testing/index.d.ts +0 -2
  93. package/dist/types/src/testing/index.d.ts.map +0 -1
  94. package/src/components/deprecated/LayoutControls.tsx +0 -109
  95. package/src/exemplars/Card/Card.stories.tsx +0 -78
  96. package/src/exemplars/Card/Card.tsx +0 -186
  97. package/src/exemplars/Card/CardDragPreview.tsx +0 -22
  98. package/src/exemplars/Card/fragments.ts +0 -23
  99. package/src/exemplars/Card/index.ts +0 -7
  100. package/src/exemplars/CardStack/CardStack.stories.tsx +0 -172
  101. package/src/exemplars/CardStack/CardStack.tsx +0 -136
  102. package/src/exemplars/CardStack/CardStackDragPreview.tsx +0 -61
  103. package/src/exemplars/CardStack/index.ts +0 -6
  104. package/src/exemplars/index.ts +0 -6
  105. package/src/testing/CardContainer.tsx +0 -34
  106. package/src/testing/index.ts +0 -5
  107. /package/src/components/{defs.ts → types.ts} +0 -0
@@ -7,52 +7,57 @@ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-d
7
7
  import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
8
8
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
9
9
  import {
10
+ type Edge,
10
11
  attachClosestEdge,
11
12
  extractClosestEdge,
12
- type Edge,
13
13
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
14
14
  import { useFocusableGroup } from '@fluentui/react-tabster';
15
15
  import { composeRefs } from '@radix-ui/react-compose-refs';
16
16
  import React, {
17
- forwardRef,
18
- useLayoutEffect,
19
- useState,
20
17
  type ComponentPropsWithRef,
21
- useCallback,
22
18
  type ReactNode,
19
+ forwardRef,
20
+ useCallback,
21
+ useLayoutEffect,
23
22
  useMemo,
23
+ useState,
24
24
  } from 'react';
25
25
  import { createPortal } from 'react-dom';
26
26
 
27
- import { type ThemedClassName, ListItem } from '@dxos/react-ui';
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
+
31
+ import { type ItemDragState, StackItemContext, idle, useStack, useStackItem } from '../StackContext';
32
+ import { type StackItemData, type StackItemSize } from '../types';
30
33
 
31
34
  import { StackItemContent, type StackItemContentProps } from './StackItemContent';
32
35
  import { StackItemDragHandle, type StackItemDragHandleProps } from './StackItemDragHandle';
33
36
  import {
34
37
  StackItemHeading,
35
38
  StackItemHeadingLabel,
36
- type StackItemHeadingProps,
37
39
  type StackItemHeadingLabelProps,
40
+ type StackItemHeadingProps,
38
41
  StackItemHeadingStickyContent,
39
42
  } from './StackItemHeading';
40
43
  import { StackItemResizeHandle, type StackItemResizeHandleProps } from './StackItemResizeHandle';
41
44
  import {
42
45
  StackItemSigil,
43
- type StackItemSigilProps,
44
46
  type StackItemSigilAction,
45
- type StackItemSigilButtonProps,
46
47
  StackItemSigilButton,
48
+ type StackItemSigilButtonProps,
49
+ type StackItemSigilProps,
47
50
  } from './StackItemSigil';
48
- import { useStack, StackItemContext, idle, type ItemDragState, useStackItem } from '../StackContext';
49
- import { type StackItemSize, type StackItemData } from '../defs';
50
51
 
51
52
  // NOTE: 48rem fills the screen on a MacbookPro with the sidebars closed.
52
53
  export const DEFAULT_HORIZONTAL_SIZE = 48 satisfies StackItemSize;
53
54
  export const DEFAULT_VERTICAL_SIZE = 'min-content' satisfies StackItemSize;
54
55
  export const DEFAULT_EXTRINSIC_SIZE = DEFAULT_HORIZONTAL_SIZE satisfies StackItemSize;
55
56
 
57
+ //
58
+ // StackItemRoot
59
+ //
60
+
56
61
  type StackItemRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
57
62
  item: Omit<StackItemData, 'type'>;
58
63
  order?: number;
@@ -62,7 +67,7 @@ type StackItemRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
62
67
  onSizeChange?: (nextSize: StackItemSize) => void;
63
68
  role?: 'article' | 'section';
64
69
  disableRearrange?: boolean;
65
- focusIndicatorVariant?: 'over-all' | 'group';
70
+ focusIndicatorVariant?: 'over-all' | 'group' | 'over-all-always' | 'group-always';
66
71
  };
67
72
 
68
73
  const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
@@ -85,18 +90,17 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
85
90
  forwardedRef,
86
91
  ) => {
87
92
  const [itemElement, itemRef] = useState<HTMLDivElement | null>(null);
93
+ const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
88
94
  const [selfDragHandleElement, selfDragHandleRef] = useState<HTMLDivElement | null>(null);
89
95
  const [closestEdge, setEdge] = useState<Edge | null>(null);
90
96
  const [sourceId, setSourceId] = useState<string | null>(null);
91
97
  const [dragState, setDragState] = useState<ItemDragState>(idle);
92
- const { orientation, rail, onRearrange } = useStack();
98
+ const { orientation, rail, onRearrange, size: stackSize, stackId } = useStack();
93
99
  const [size = orientation === 'horizontal' ? DEFAULT_HORIZONTAL_SIZE : DEFAULT_VERTICAL_SIZE, setInternalSize] =
94
100
  useState(propsSize);
95
101
 
96
102
  const Root = role ?? 'div';
97
103
 
98
- const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
99
-
100
104
  const setSize = useCallback(
101
105
  (nextSize: StackItemSize, commit?: boolean) => {
102
106
  setInternalSize(nextSize);
@@ -109,6 +113,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
109
113
 
110
114
  const type = orientation === 'horizontal' ? 'column' : 'card';
111
115
 
116
+ // TODO(burdon): Factor out?
112
117
  useLayoutEffect(() => {
113
118
  if (!itemElement || !onRearrange || disableRearrange) {
114
119
  return;
@@ -138,7 +143,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
138
143
  onDragStart: () => {
139
144
  document.body.removeAttribute('data-drag-preview');
140
145
  itemElement?.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'active');
141
- setDragState({ type: 'is-dragging', item });
146
+ setDragState({ type: 'w-dragging', item });
142
147
  },
143
148
  onDrop: () => {
144
149
  itemElement?.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'idle');
@@ -182,18 +187,18 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
182
187
 
183
188
  const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
184
189
 
185
- // Determine if the drop would result in any changes
190
+ // Determine if the drop would result in any changes.
186
191
  const shouldShowDropIndicator = () => {
187
192
  if (!closestEdge || !sourceId) {
188
193
  return false;
189
194
  }
190
195
 
191
- // Don't show indicator when dragged item is over itself
196
+ // Don't show indicator when dragged item is over itself.
192
197
  if (sourceId === item.id) {
193
198
  return false;
194
199
  }
195
200
 
196
- // Don't show indicator when dragged item is over the trailing edge of its previous sibling
201
+ // Don't show indicator when dragged item is over the trailing edge of its previous sibling.
197
202
  const isTrailingEdgeOfPrevSibling =
198
203
  prevSiblingId !== undefined &&
199
204
  sourceId === prevSiblingId &&
@@ -231,18 +236,25 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
231
236
  'group/stack-item grid relative',
232
237
  focusIndicatorVariant === 'over-all'
233
238
  ? 'dx-focus-ring-inset-over-all'
234
- : orientation === 'horizontal'
235
- ? 'dx-focus-ring-group-x'
236
- : 'dx-focus-ring-group-y',
239
+ : focusIndicatorVariant === 'over-all-always'
240
+ ? 'dx-focus-ring-inset-over-all-always'
241
+ : orientation === 'horizontal'
242
+ ? focusIndicatorVariant === 'group-always'
243
+ ? 'dx-focus-ring-group-x-always'
244
+ : 'dx-focus-ring-group-x'
245
+ : focusIndicatorVariant === 'group-always'
246
+ ? 'dx-focus-ring-group-y-always'
247
+ : 'dx-focus-ring-group-y',
237
248
  orientation === 'horizontal' ? 'grid-rows-subgrid' : 'grid-cols-subgrid',
238
249
  rail && (orientation === 'horizontal' ? 'row-span-2' : 'col-span-2'),
239
- role === 'section' && orientation !== 'horizontal' && 'border-be border-subduedSeparator',
250
+ role === 'section' && orientation !== 'horizontal' && 'border-b border-subdued-separator',
240
251
  classNames,
241
252
  )}
242
- data-dx-stack-item
253
+ data-dx-stack-item={stackId}
254
+ data-dx-item-id={item.id}
243
255
  {...resizeAttributes}
244
256
  style={{
245
- ...sizeStyle(size, orientation),
257
+ ...(stackSize !== 'split' && sizeStyle(size, orientation)),
246
258
  ...(Number.isFinite(order) && {
247
259
  [orientation === 'horizontal' ? 'gridColumn' : 'gridRow']: `${order}`,
248
260
  }),
@@ -260,37 +272,45 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
260
272
  },
261
273
  );
262
274
 
275
+ //
276
+ // StackItemDragPreview
277
+ //
278
+
263
279
  type StackItemDragPreviewProps = {
264
280
  children: ({ item }: { item: any }) => ReactNode;
265
281
  };
266
282
 
267
- export const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
283
+ const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
268
284
  const { state } = useStackItem();
269
285
  return state?.type === 'preview' ? createPortal(children({ item: state.item }), state.container) : null;
270
286
  };
271
287
 
288
+ //
289
+ // StackItem
290
+ //
291
+
272
292
  export const StackItem = {
273
293
  Root: StackItemRoot,
274
294
  Content: StackItemContent,
295
+ DragHandle: StackItemDragHandle,
296
+ DragPreview: StackItemDragPreview,
275
297
  Heading: StackItemHeading,
276
298
  HeadingLabel: StackItemHeadingLabel,
277
299
  HeadingStickyContent: StackItemHeadingStickyContent,
278
300
  ResizeHandle: StackItemResizeHandle,
279
- DragHandle: StackItemDragHandle,
280
301
  Sigil: StackItemSigil,
281
302
  SigilButton: StackItemSigilButton,
282
- DragPreview: StackItemDragPreview,
283
303
  };
284
304
 
285
305
  export type {
286
306
  StackItemRootProps,
287
307
  StackItemContentProps,
308
+ StackItemDragHandleProps,
309
+ StackItemDragPreviewProps,
288
310
  StackItemHeadingProps,
289
311
  StackItemHeadingLabelProps,
290
312
  StackItemResizeHandleProps,
291
- StackItemDragHandleProps,
292
313
  StackItemSigilProps,
293
314
  StackItemSigilButtonProps,
294
315
  StackItemSigilAction,
295
- StackItemDragPreviewProps,
296
316
  };
@@ -5,70 +5,49 @@
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
  );
36
+
57
37
  return (
58
38
  <div
59
- role='none'
60
39
  {...props}
40
+ role='none'
41
+ style={style}
61
42
  className={mx(
62
- 'group grid grid-cols-[100%] density-coarse',
63
- stackItemSize === 'contain' && 'min-bs-0 overflow-hidden',
64
- size === 'video' ? 'aspect-video' : size === 'square' && 'aspect-square',
65
- toolbar && '[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-be [&>.dx-toolbar]:border-subduedSeparator',
66
- role === 'section' &&
67
- toolbar &&
68
- '[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:block-start-0 [&_.dx-toolbar]:-mbe-px [&_.dx-toolbar]:min-is-0',
43
+ 'group grid grid-cols-[100%] dx-density-coarse',
44
+ stackItemSize === 'contain' && 'min-h-0 overflow-hidden',
45
+ toolbar &&
46
+ role === 'section' &&
47
+ '[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:top-0 [&_.dx-toolbar]:-mb-px [&_.dx-toolbar]:min-w-0',
48
+ toolbar && '[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-b [&>.dx-toolbar]:border-subdued-separator',
69
49
  classNames,
70
50
  )}
71
- style={style}
72
51
  data-popover-collision-boundary={true}
73
52
  ref={forwardedRef}
74
53
  >
@@ -77,3 +56,5 @@ export const StackItemContent = forwardRef<HTMLDivElement, StackItemContentProps
77
56
  );
78
57
  },
79
58
  );
59
+
60
+ 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,18 +2,18 @@
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
- type ComponentPropsWithoutRef,
9
8
  type ComponentPropsWithRef,
10
- forwardRef,
9
+ type ComponentPropsWithoutRef,
11
10
  type PropsWithChildren,
11
+ forwardRef,
12
12
  } from 'react';
13
13
 
14
14
  import { type ThemedClassName } from '@dxos/react-ui';
15
- import { useAttention, type AttendableId, type Related } from '@dxos/react-ui-attention';
16
- import { mx } from '@dxos/react-ui-theme';
15
+ import { type AttendableId, type Related, useAttention } from '@dxos/react-ui-attention';
16
+ import { mx } from '@dxos/ui-theme';
17
17
 
18
18
  import { useStack } from '../StackContext';
19
19
 
@@ -30,34 +30,31 @@ export const StackItemHeading = ({
30
30
  ...props
31
31
  }: StackItemHeadingProps) => {
32
32
  const { orientation } = useStack();
33
- const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
34
33
 
35
- const Root = asChild ? Slot : 'div';
34
+ const Comp = asChild ? Slot : Primitive.div;
36
35
 
37
36
  return (
38
- <Root
37
+ <Comp
39
38
  role='heading'
40
39
  {...props}
41
- tabIndex={0}
42
- {...focusableGroupAttrs}
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
56
  return (
60
- <div role='none' className='sticky block-start-0 bg-[--sticky-bg] p-1 is-full'>
57
+ <div role='none' className='sticky top-0 bg-(--sticky-bg) p-1 w-full'>
61
58
  {children}
62
59
  </div>
63
60
  );
@@ -74,7 +71,7 @@ export const StackItemHeadingLabel = forwardRef<HTMLHeadingElement, StackItemHea
74
71
  {...props}
75
72
  data-attention={((related && isRelated) || hasAttention || isAncestor).toString()}
76
73
  className={mx(
77
- 'pli-1 min-is-0 is-0 grow truncate font-medium text-baseText data-[attention=true]:text-accentText self-center',
74
+ 'px-1 min-w-0 w-0 grow truncate font-medium text-base-surface-text data-[attention=true]:text-accent-text self-center',
78
75
  classNames,
79
76
  )}
80
77
  ref={forwardedRef}
@@ -6,15 +6,16 @@ import React from 'react';
6
6
 
7
7
  import { ResizeHandle } from '@dxos/react-ui-dnd';
8
8
 
9
- import { DEFAULT_EXTRINSIC_SIZE } from './StackItem';
10
9
  import { useStack, useStackItem } from '../StackContext';
11
10
 
11
+ import { DEFAULT_EXTRINSIC_SIZE } from './StackItem';
12
+
12
13
  const MIN_WIDTH = 20;
13
14
  const MIN_HEIGHT = 3;
14
15
 
15
16
  export type StackItemResizeHandleProps = {};
16
17
 
17
- export const StackItemResizeHandle = () => {
18
+ export const StackItemResizeHandle = (_: StackItemResizeHandleProps) => {
18
19
  const { orientation } = useStack();
19
20
  const { setSize, size } = useStackItem();
20
21
 
@@ -4,16 +4,17 @@
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 { MenuSignifierHorizontal } from './MenuSignifier';
15
14
  import { translationKey } from '../../translations';
16
15
 
16
+ import { MenuSignifierHorizontal } from './MenuSignifier';
17
+
17
18
  export type KeyBinding = {
18
19
  windows?: string;
19
20
  macos?: string;
@@ -22,7 +23,7 @@ export type KeyBinding = {
22
23
  unknown?: string;
23
24
  };
24
25
 
25
- export type StackItemSigilAction = Pick<ActionLike, 'id' | 'properties' | 'data'>;
26
+ export type StackItemSigilAction = Pick<Node.ActionLike, 'id' | 'properties' | 'data'>;
26
27
 
27
28
  export type StackItemSigilButtonProps = Omit<ButtonProps, 'variant'> &
28
29
  AttendableId &
@@ -39,7 +40,10 @@ export const StackItemSigilButton = forwardRef<HTMLButtonElement, StackItemSigil
39
40
  <Button
40
41
  {...props}
41
42
  variant={variant}
42
- 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
+ ]}
43
47
  ref={forwardedRef}
44
48
  >
45
49
  {isMenu && <MenuSignifierHorizontal />}
@@ -132,7 +136,7 @@ export const StackItemSigil = forwardRef<HTMLButtonElement, StackItemSigilProps>
132
136
  </DropdownMenu.ItemIndicator>
133
137
  )}
134
138
  {shortcut && (
135
- <span className={mx('shrink-0', descriptionText)}>{keySymbols(shortcut).join('')}</span>
139
+ <span className={mx('shrink-0', 'text-description')}>{keySymbols(shortcut).join('')}</span>
136
140
  )}
137
141
  </Root>
138
142
  );
@@ -2,7 +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
7
  export * from './Stack';
8
+
8
9
  export * from './StackItem';
@@ -8,70 +8,84 @@ import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-sc
8
8
  import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
9
9
  import { useLayoutEffect, useState } from 'react';
10
10
 
11
- import { type StackItemRearrangeHandler, type StackItemData, type Orientation } from '../components';
11
+ import { type Orientation, type StackItemData, type StackItemRearrangeHandler } from '../components';
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
+ };
12
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,5 @@
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
6
  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
  },
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { type Resource } from '@dxos/react-ui';
6
6
 
7
- export const translationKey = 'react-ui-stack';
7
+ export const translationKey = '@dxos/react-ui-stack';
8
8
 
9
9
  export const translations = [
10
10
  {