@dxos/react-ui-stack 0.8.4-main.c4373fc → 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 (112) hide show
  1. package/dist/lib/browser/index.mjs +743 -65
  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/node-esm/index.mjs +744 -65
  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 +10 -23
  10. package/dist/lib/node-esm/playwright/index.mjs.map +2 -2
  11. package/dist/types/src/components/Stack/Stack.d.ts +8 -8
  12. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  13. package/dist/types/src/components/StackContext.d.ts +2 -2
  14. package/dist/types/src/components/StackContext.d.ts.map +1 -1
  15. package/dist/types/src/components/StackItem/MenuSignifier.d.ts.map +1 -1
  16. package/dist/types/src/components/StackItem/StackItem.d.ts +6 -10
  17. package/dist/types/src/components/StackItem/StackItem.d.ts.map +1 -1
  18. package/dist/types/src/components/StackItem/StackItem.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/StackItem/StackItemContent.d.ts +2 -43
  20. package/dist/types/src/components/StackItem/StackItemContent.d.ts.map +1 -1
  21. package/dist/types/src/components/StackItem/StackItemDragHandle.d.ts.map +1 -1
  22. package/dist/types/src/components/StackItem/StackItemHeading.d.ts.map +1 -1
  23. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts +1 -1
  24. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts.map +1 -1
  25. package/dist/types/src/components/StackItem/StackItemSigil.d.ts +2 -2
  26. package/dist/types/src/components/StackItem/StackItemSigil.d.ts.map +1 -1
  27. package/dist/types/src/components/index.d.ts +1 -2
  28. package/dist/types/src/components/index.d.ts.map +1 -1
  29. package/dist/types/src/components/{defs.d.ts → types.d.ts} +1 -1
  30. package/dist/types/src/components/types.d.ts.map +1 -0
  31. package/dist/types/src/hooks/useStackDropForElements.d.ts +8 -6
  32. package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -1
  33. package/dist/types/src/index.d.ts +0 -1
  34. package/dist/types/src/index.d.ts.map +1 -1
  35. package/dist/types/src/translations.d.ts +2 -2
  36. package/dist/types/src/translations.d.ts.map +1 -1
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +41 -38
  39. package/src/components/Stack/Stack.stories.tsx +2 -2
  40. package/src/components/Stack/Stack.tsx +27 -25
  41. package/src/components/StackContext.tsx +2 -2
  42. package/src/components/StackItem/MenuSignifier.tsx +2 -9
  43. package/src/components/StackItem/StackItem.stories.tsx +6 -4
  44. package/src/components/StackItem/StackItem.tsx +26 -14
  45. package/src/components/StackItem/StackItemContent.tsx +23 -54
  46. package/src/components/StackItem/StackItemDragHandle.tsx +4 -3
  47. package/src/components/StackItem/StackItemHeading.tsx +12 -11
  48. package/src/components/StackItem/StackItemResizeHandle.tsx +1 -1
  49. package/src/components/StackItem/StackItemSigil.tsx +8 -5
  50. package/src/components/index.ts +2 -2
  51. package/src/hooks/useStackDropForElements.ts +58 -44
  52. package/src/index.ts +0 -3
  53. package/src/playwright/playwright.config.ts +1 -1
  54. package/src/translations.ts +1 -1
  55. package/dist/lib/browser/chunk-SM27YTH3.mjs +0 -1418
  56. package/dist/lib/browser/chunk-SM27YTH3.mjs.map +0 -7
  57. package/dist/lib/browser/testing/index.mjs +0 -31
  58. package/dist/lib/browser/testing/index.mjs.map +0 -7
  59. package/dist/lib/node-esm/chunk-MMAOXKOM.mjs +0 -1420
  60. package/dist/lib/node-esm/chunk-MMAOXKOM.mjs.map +0 -7
  61. package/dist/lib/node-esm/testing/index.mjs +0 -32
  62. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  63. package/dist/types/src/components/Image/Image.d.ts +0 -11
  64. package/dist/types/src/components/Image/Image.d.ts.map +0 -1
  65. package/dist/types/src/components/Image/Image.stories.d.ts +0 -30
  66. package/dist/types/src/components/Image/Image.stories.d.ts.map +0 -1
  67. package/dist/types/src/components/Image/index.d.ts +0 -2
  68. package/dist/types/src/components/Image/index.d.ts.map +0 -1
  69. package/dist/types/src/components/defs.d.ts.map +0 -1
  70. package/dist/types/src/components/deprecated/LayoutControls.d.ts +0 -19
  71. package/dist/types/src/components/deprecated/LayoutControls.d.ts.map +0 -1
  72. package/dist/types/src/exemplars/Card/Card.d.ts +0 -65
  73. package/dist/types/src/exemplars/Card/Card.d.ts.map +0 -1
  74. package/dist/types/src/exemplars/Card/Card.stories.d.ts +0 -21
  75. package/dist/types/src/exemplars/Card/Card.stories.d.ts.map +0 -1
  76. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts +0 -6
  77. package/dist/types/src/exemplars/Card/CardDragPreview.d.ts.map +0 -1
  78. package/dist/types/src/exemplars/Card/fragments.d.ts +0 -13
  79. package/dist/types/src/exemplars/Card/fragments.d.ts.map +0 -1
  80. package/dist/types/src/exemplars/Card/index.d.ts +0 -4
  81. package/dist/types/src/exemplars/Card/index.d.ts.map +0 -1
  82. package/dist/types/src/exemplars/CardStack/CardStack.d.ts +0 -42
  83. package/dist/types/src/exemplars/CardStack/CardStack.d.ts.map +0 -1
  84. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts +0 -15
  85. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts.map +0 -1
  86. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts +0 -9
  87. package/dist/types/src/exemplars/CardStack/CardStackDragPreview.d.ts.map +0 -1
  88. package/dist/types/src/exemplars/CardStack/index.d.ts +0 -3
  89. package/dist/types/src/exemplars/CardStack/index.d.ts.map +0 -1
  90. package/dist/types/src/exemplars/index.d.ts +0 -3
  91. package/dist/types/src/exemplars/index.d.ts.map +0 -1
  92. package/dist/types/src/testing/CardContainer.d.ts +0 -6
  93. package/dist/types/src/testing/CardContainer.d.ts.map +0 -1
  94. package/dist/types/src/testing/index.d.ts +0 -2
  95. package/dist/types/src/testing/index.d.ts.map +0 -1
  96. package/src/components/Image/Image.stories.tsx +0 -56
  97. package/src/components/Image/Image.tsx +0 -137
  98. package/src/components/Image/index.ts +0 -5
  99. package/src/components/deprecated/LayoutControls.tsx +0 -109
  100. package/src/exemplars/Card/Card.stories.tsx +0 -64
  101. package/src/exemplars/Card/Card.tsx +0 -204
  102. package/src/exemplars/Card/CardDragPreview.tsx +0 -22
  103. package/src/exemplars/Card/fragments.ts +0 -24
  104. package/src/exemplars/Card/index.ts +0 -7
  105. package/src/exemplars/CardStack/CardStack.stories.tsx +0 -173
  106. package/src/exemplars/CardStack/CardStack.tsx +0 -139
  107. package/src/exemplars/CardStack/CardStackDragPreview.tsx +0 -61
  108. package/src/exemplars/CardStack/index.ts +0 -6
  109. package/src/exemplars/index.ts +0 -6
  110. package/src/testing/CardContainer.tsx +0 -37
  111. package/src/testing/index.ts +0 -5
  112. /package/src/components/{defs.ts → types.ts} +0 -0
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-stack",
3
- "version": "0.8.4-main.c4373fc",
3
+ "version": "0.8.4-main.c85a9c8dae",
4
4
  "description": "A stack component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
- "sideEffects": true,
13
+ "sideEffects": false,
10
14
  "type": "module",
11
15
  "exports": {
12
16
  ".": {
@@ -18,11 +22,6 @@
18
22
  "types": "./dist/types/src/playwright/index.d.ts",
19
23
  "browser": "./dist/lib/browser/playwright/index.mjs",
20
24
  "node": "./dist/lib/node-esm/playwright/index.mjs"
21
- },
22
- "./testing": {
23
- "types": "./dist/types/src/testing/index.d.ts",
24
- "browser": "./dist/lib/browser/testing/index.mjs",
25
- "node": "./dist/lib/node-esm/testing/index.mjs"
26
25
  }
27
26
  },
28
27
  "types": "dist/types/src/index.d.ts",
@@ -41,11 +40,11 @@
41
40
  "src"
42
41
  ],
43
42
  "dependencies": {
44
- "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
45
- "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.0",
46
- "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
47
- "@fluentui/react-tabster": "^9.24.2",
48
- "@preact-signals/safe-react": "^0.9.0",
43
+ "@atlaskit/pragmatic-drag-and-drop": "1.7.7",
44
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.2",
45
+ "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
46
+ "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "3.2.10",
47
+ "@fluentui/react-tabster": "9.26.11",
49
48
  "@radix-ui/primitive": "1.1.1",
50
49
  "@radix-ui/react-compose-refs": "1.1.1",
51
50
  "@radix-ui/react-context": "1.1.1",
@@ -54,36 +53,40 @@
54
53
  "@radix-ui/react-slot": "1.1.2",
55
54
  "@radix-ui/react-use-controllable-state": "1.1.0",
56
55
  "react-resize-detector": "^11.0.1",
57
- "@dxos/echo": "0.8.4-main.c4373fc",
58
- "@dxos/live-object": "0.8.4-main.c4373fc",
59
- "@dxos/keyboard": "0.8.4-main.c4373fc",
60
- "@dxos/react-ui-dnd": "0.8.4-main.c4373fc",
61
- "@dxos/util": "0.8.4-main.c4373fc",
62
- "@dxos/storybook-utils": "0.8.4-main.c4373fc",
63
- "@dxos/react-ui-attention": "0.8.4-main.c4373fc"
56
+ "@dxos/echo": "0.8.4-main.c85a9c8dae",
57
+ "@dxos/react-ui-dnd": "0.8.4-main.c85a9c8dae",
58
+ "@dxos/react-ui-attention": "0.8.4-main.c85a9c8dae",
59
+ "@dxos/keyboard": "0.8.4-main.c85a9c8dae",
60
+ "@dxos/react-ui-mosaic": "0.8.4-main.c85a9c8dae",
61
+ "@dxos/util": "0.8.4-main.c85a9c8dae"
64
62
  },
65
63
  "devDependencies": {
66
- "@types/react": "~19.2.2",
67
- "@types/react-dom": "~19.2.1",
68
- "react": "~19.2.0",
69
- "react-dom": "~19.2.0",
70
- "vite": "7.1.9",
71
- "@dxos/app-graph": "0.8.4-main.c4373fc",
72
- "@dxos/client": "0.8.4-main.c4373fc",
73
- "@dxos/echo": "0.8.4-main.c4373fc",
74
- "@dxos/random": "0.8.4-main.c4373fc",
75
- "@dxos/react-ui": "0.8.4-main.c4373fc",
76
- "@dxos/react-ui-theme": "0.8.4-main.c4373fc",
77
- "@dxos/storybook-utils": "0.8.4-main.c4373fc",
78
- "@dxos/test-utils": "0.8.4-main.c4373fc"
64
+ "@types/react": "~19.2.7",
65
+ "@types/react-dom": "~19.2.3",
66
+ "react": "~19.2.3",
67
+ "react-dom": "~19.2.3",
68
+ "vite": "^7.1.11",
69
+ "@dxos/app-graph": "0.8.4-main.c85a9c8dae",
70
+ "@dxos/client": "0.8.4-main.c85a9c8dae",
71
+ "@dxos/app-framework": "0.8.4-main.c85a9c8dae",
72
+ "@dxos/echo": "0.8.4-main.c85a9c8dae",
73
+ "@dxos/echo-db": "0.8.4-main.c85a9c8dae",
74
+ "@dxos/random": "0.8.4-main.c85a9c8dae",
75
+ "@dxos/react-client": "0.8.4-main.c85a9c8dae",
76
+ "@dxos/react-ui": "0.8.4-main.c85a9c8dae",
77
+ "@dxos/storybook-utils": "0.8.4-main.c85a9c8dae",
78
+ "@dxos/types": "0.8.4-main.c85a9c8dae",
79
+ "@dxos/test-utils": "0.8.4-main.c85a9c8dae",
80
+ "@dxos/ui-theme": "0.8.4-main.c85a9c8dae",
81
+ "@dxos/schema": "0.8.4-main.c85a9c8dae"
79
82
  },
80
83
  "peerDependencies": {
81
- "react": "^19.0.0",
82
- "react-dom": "^19.0.0",
83
- "@dxos/random": "0.8.4-main.c4373fc",
84
- "@dxos/client": "0.8.4-main.c4373fc",
85
- "@dxos/react-ui": "0.8.4-main.c4373fc",
86
- "@dxos/react-ui-theme": "0.8.4-main.c4373fc"
84
+ "react": "~19.2.3",
85
+ "react-dom": "~19.2.3",
86
+ "@dxos/client": "0.8.4-main.c85a9c8dae",
87
+ "@dxos/random": "0.8.4-main.c85a9c8dae",
88
+ "@dxos/ui-theme": "0.8.4-main.c85a9c8dae",
89
+ "@dxos/react-ui": "0.8.4-main.c85a9c8dae"
87
90
  },
88
91
  "publishConfig": {
89
92
  "access": "public"
@@ -9,8 +9,8 @@ import React, { useCallback, useState } from 'react';
9
9
  import { faker } from '@dxos/random';
10
10
  import { withTheme } from '@dxos/react-ui/testing';
11
11
 
12
- import { type StackItemData } from '../defs';
13
12
  import { StackItem } from '../StackItem';
13
+ import { type StackItemData } from '../types';
14
14
 
15
15
  import { Stack } from './Stack';
16
16
 
@@ -132,7 +132,7 @@ const meta = {
132
132
  title: 'ui/react-ui-stack/Stack',
133
133
  component: DefaultStory,
134
134
  argTypes: { orientation: { control: 'radio', options: ['horizontal', 'vertical'] } },
135
- decorators: [withTheme],
135
+ decorators: [withTheme()],
136
136
  } satisfies Meta<typeof DefaultStory>;
137
137
 
138
138
  export default meta;
@@ -7,6 +7,7 @@ import React, {
7
7
  type CSSProperties,
8
8
  Children,
9
9
  type ComponentPropsWithRef,
10
+ type FocusEvent,
10
11
  type KeyboardEvent,
11
12
  forwardRef,
12
13
  useCallback,
@@ -16,13 +17,14 @@ import React, {
16
17
  } from 'react';
17
18
 
18
19
  import { ListItem, type ThemedClassName, useId } from '@dxos/react-ui';
19
- import { mx } from '@dxos/react-ui-theme';
20
+ import { mx } from '@dxos/ui-theme';
20
21
 
21
22
  import { useStackDropForElements } from '../../hooks';
22
- import { type StackContextValue } from '../defs';
23
23
  import { StackContext } from '../StackContext';
24
+ import { type StackContextValue } from '../types';
24
25
 
25
26
  export type Orientation = 'horizontal' | 'vertical';
27
+
26
28
  /**
27
29
  * Size is how Stack and its StackItems coordinate the dimensions of the items with the available space.
28
30
  * - `intrinsic` signals to Stack and its StackItems to occupy their intrinsic size
@@ -32,22 +34,14 @@ export type Orientation = 'horizontal' | 'vertical';
32
34
  */
33
35
  export type Size = 'intrinsic' | 'contain' | 'split';
34
36
 
35
- export type StackProps = Omit<ThemedClassName<ComponentPropsWithRef<'div'>>, 'aria-orientation'> &
36
- Partial<StackContextValue> & {
37
- itemsCount?: number;
38
- getDropElement?: (stackElement: HTMLDivElement) => HTMLDivElement;
39
- separatorOnScroll?: number;
40
- circularFocus?: boolean;
41
- };
42
-
43
- export const railGridHorizontal = 'grid-rows-[[rail-start]_var(--rail-size)_[content-start]_1fr_[content-end]]';
44
- export const railGridVertical = 'grid-cols-[[rail-start]_var(--rail-size)_[content-start]_1fr_[content-end]]';
37
+ export const railGridHorizontal = 'grid-rows-[[rail-start]_var(--dx-rail-size)_[content-start]_1fr_[content-end]]';
38
+ export const railGridVertical = 'grid-cols-[[rail-start]_var(--dx-rail-size)_[content-start]_1fr_[content-end]]';
45
39
 
46
40
  // TODO(ZaymonFC): Magic 2px to stop overflow.
47
41
  export const railGridHorizontalContainFitContent =
48
- 'grid-rows-[[rail-start]_var(--rail-size)_[content-start]_fit-content(calc(100%-var(--rail-size)*2+2px))_[content-end]]';
42
+ 'grid-rows-[[rail-start]_var(--dx-rail-size)_[content-start]_fit-content(calc(100%-var(--dx-rail-size)*2+2px))_[content-end]]';
49
43
  export const railGridVerticalContainFitContent =
50
- 'grid-cols-[[rail-start]_var(--rail-size)_[content-start]_fit-content(calc(100%-var(--rail-size)*2+2px))_[content-end]]';
44
+ 'grid-cols-[[rail-start]_var(--dx-rail-size)_[content-start]_fit-content(calc(100%-var(--dx-rail-size)*2+2px))_[content-end]]';
51
45
 
52
46
  export const autoScrollRootAttributes = { 'data-drag-autoscroll': 'idle' };
53
47
 
@@ -61,6 +55,14 @@ const scrollIntoViewAndFocus = (el: HTMLElement, orientation: StackProps['orient
61
55
  return el.focus();
62
56
  };
63
57
 
58
+ export type StackProps = Omit<ThemedClassName<ComponentPropsWithRef<'div'>>, 'aria-orientation'> &
59
+ Partial<StackContextValue> & {
60
+ itemsCount?: number;
61
+ getDropElement?: (stackElement: HTMLDivElement) => HTMLDivElement;
62
+ separatorOnScroll?: number;
63
+ circularFocus?: boolean;
64
+ };
65
+
64
66
  export const Stack = forwardRef<HTMLDivElement, StackProps>(
65
67
  (
66
68
  {
@@ -68,7 +70,7 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
68
70
  classNames,
69
71
  style,
70
72
  orientation = 'vertical',
71
- rail = true,
73
+ rail = true, // TODO(burdon): Change default to false.
72
74
  size = 'intrinsic',
73
75
  onRearrange,
74
76
  itemsCount = Children.count(children),
@@ -121,7 +123,7 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
121
123
  * Handles blur events to track the last focused item within this stack.
122
124
  */
123
125
  const handleBlur = useCallback(
124
- (event: React.FocusEvent<HTMLDivElement>) => {
126
+ (event: FocusEvent<HTMLDivElement>) => {
125
127
  if (event.target) {
126
128
  const target = event.target as HTMLElement;
127
129
  const closestStackItem = target.closest(`[data-dx-item-id]`) as HTMLElement | null;
@@ -135,9 +137,9 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
135
137
  );
136
138
 
137
139
  /**
138
- * Handles moving focus using the arrow keys. Focus is only handled by the nearest stack; if the arrow key matches the
139
- * orientation, focus cycles between items, otherwise focus is passed to an adjacent stack item; or, if there is no
140
- * such stack item, focus is passed to the adjacent empty stack if one can be found.
140
+ * Handles moving focus using the arrow keys. Focus is only handled by the nearest stack;
141
+ * if the arrow key matches the orientation, focus cycles between items, otherwise focus is passed to an adjacent stack item;
142
+ * or, if there is no such stack item, focus is passed to the adjacent empty stack if one can be found.
141
143
  */
142
144
  const handleKeyDown = useCallback(
143
145
  (event: KeyboardEvent<HTMLDivElement>) => {
@@ -193,6 +195,7 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
193
195
  scrollIntoViewAndFocus(adjacentItem, closestStackOrientation);
194
196
  }
195
197
  }
198
+
196
199
  if (perpendicularDelta !== 0) {
197
200
  if (ancestorStack && ancestorOrientation !== closestStackOrientation) {
198
201
  const siblingStacks = Array.from(
@@ -241,12 +244,10 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
241
244
  closestStackOrientation === 'vertical' ? ownedItemRect.top : ownedItemRect.left;
242
245
 
243
246
  let closestDistance = Infinity;
244
-
245
247
  for (const item of adjacentStackItems) {
246
248
  const itemRect = item.getBoundingClientRect();
247
249
  const itemPosition = closestStackOrientation === 'vertical' ? itemRect.top : itemRect.left;
248
250
  const distance = Math.abs(itemPosition - targetPosition);
249
-
250
251
  if (distance < closestDistance) {
251
252
  closestDistance = distance;
252
253
  closestItem = item;
@@ -292,8 +293,9 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
292
293
 
293
294
  const gridClasses = useMemo(() => {
294
295
  if (!rail) {
295
- return orientation === 'horizontal' ? 'grid-rows-1 pli-[--stack-gap]' : 'grid-cols-1 plb-[--stack-gap]';
296
+ return orientation === 'horizontal' ? 'grid-rows-1 px-(--stack-gap)' : 'grid-cols-1 py-(--stack-gap)';
296
297
  }
298
+
297
299
  if (orientation === 'horizontal') {
298
300
  return railGridHorizontal;
299
301
  } else {
@@ -322,12 +324,12 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
322
324
  <div
323
325
  {...props}
324
326
  className={mx(
325
- 'grid relative [--stack-gap:var(--dx-trimXs)]',
327
+ 'grid relative [--stack-gap:var(--spacing-trim-xs)]',
326
328
  gridClasses,
327
329
  size === 'contain' &&
328
330
  (orientation === 'horizontal'
329
- ? 'overflow-x-auto overscroll-x-contain min-bs-0 max-bs-full bs-full'
330
- : 'overflow-y-auto min-is-0 max-is-full is-full'),
331
+ ? 'overflow-x-auto overscroll-x-contain min-h-0 max-h-full h-full'
332
+ : 'overflow-y-auto min-w-0 max-w-full w-full'),
331
333
  classNames,
332
334
  )}
333
335
  onKeyDown={handleKeyDown}
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { createContext, useContext } from 'react';
6
6
 
7
- import { type StackItemRearrangeHandler, type StackItemSize } from './defs';
8
7
  import { type Orientation, type Size } from './Stack';
8
+ import { type StackItemRearrangeHandler, type StackItemSize } from './types';
9
9
 
10
10
  export type StackContextValue = {
11
11
  orientation: Orientation;
@@ -33,7 +33,7 @@ export type ItemDragState =
33
33
  item: any;
34
34
  }
35
35
  | {
36
- type: 'is-dragging';
36
+ type: 'w-dragging';
37
37
  item: any;
38
38
  };
39
39
 
@@ -5,14 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  export const MenuSignifierHorizontal = () => (
8
- <svg
9
- className='absolute block-end-[7px]'
10
- width={20}
11
- height={2}
12
- viewBox='0 0 20 2'
13
- stroke='currentColor'
14
- opacity={0.5}
15
- >
8
+ <svg className='absolute bottom-[7px]' width={20} height={2} viewBox='0 0 20 2' stroke='currentColor' opacity={0.5}>
16
9
  <line
17
10
  x1={0.5}
18
11
  y1={0.75}
@@ -27,7 +20,7 @@ export const MenuSignifierHorizontal = () => (
27
20
  );
28
21
 
29
22
  export const MenuSignifierVertical = () => (
30
- <svg className='absolute inline-start-1' width={2} height={18} viewBox='0 0 2 18' stroke='currentColor'>
23
+ <svg className='absolute left-1' width={2} height={18} viewBox='0 0 2 18' stroke='currentColor'>
31
24
  <line x1={1} y1={3} x2={1} y2={18} strokeWidth={1.5} strokeLinecap='round' strokeDasharray='0 6' />
32
25
  </svg>
33
26
  );
@@ -13,9 +13,9 @@ import { StackItem, type StackItemRootProps } from './StackItem';
13
13
  const DefaultStory = (props: StackItemRootProps) => {
14
14
  return (
15
15
  <StackItem.Root role='section' {...props} classNames='w-[20rem] border border-separator'>
16
- <StackItem.Heading>
16
+ <StackItem.Heading classNames='w-full border-b border-separator'>
17
17
  <span className='sr-only'>Title</span>
18
- <div role='none' className='sticky -block-start-px bg-[--sticky-bg] p-1 is-full'>
18
+ <div role='none' className='sticky -top-px bg-(--sticky-bg) p-1 w-full'>
19
19
  <DropdownMenu.Root>
20
20
  <DropdownMenu.Trigger asChild>
21
21
  <StackItem.SigilButton>
@@ -25,7 +25,9 @@ const DefaultStory = (props: StackItemRootProps) => {
25
25
  </DropdownMenu.Root>
26
26
  </div>
27
27
  </StackItem.Heading>
28
- <StackItem.Content>Content</StackItem.Content>
28
+ <StackItem.Content>
29
+ <div className='p-4 text-center'>Content</div>
30
+ </StackItem.Content>
29
31
  </StackItem.Root>
30
32
  );
31
33
  };
@@ -34,7 +36,7 @@ const meta = {
34
36
  title: 'ui/react-ui-stack/StackItem',
35
37
  component: StackItem.Root as any,
36
38
  render: DefaultStory,
37
- decorators: [withTheme],
39
+ decorators: [withTheme()],
38
40
  parameters: {
39
41
  layout: 'centered',
40
42
  },
@@ -26,10 +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';
32
+ import { type StackItemData, type StackItemSize } from '../types';
33
33
 
34
34
  import { StackItemContent, type StackItemContentProps } from './StackItemContent';
35
35
  import { StackItemDragHandle, type StackItemDragHandleProps } from './StackItemDragHandle';
@@ -54,6 +54,10 @@ export const DEFAULT_HORIZONTAL_SIZE = 48 satisfies StackItemSize;
54
54
  export const DEFAULT_VERTICAL_SIZE = 'min-content' satisfies StackItemSize;
55
55
  export const DEFAULT_EXTRINSIC_SIZE = DEFAULT_HORIZONTAL_SIZE satisfies StackItemSize;
56
56
 
57
+ //
58
+ // StackItemRoot
59
+ //
60
+
57
61
  type StackItemRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
58
62
  item: Omit<StackItemData, 'type'>;
59
63
  order?: number;
@@ -86,6 +90,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
86
90
  forwardedRef,
87
91
  ) => {
88
92
  const [itemElement, itemRef] = useState<HTMLDivElement | null>(null);
93
+ const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
89
94
  const [selfDragHandleElement, selfDragHandleRef] = useState<HTMLDivElement | null>(null);
90
95
  const [closestEdge, setEdge] = useState<Edge | null>(null);
91
96
  const [sourceId, setSourceId] = useState<string | null>(null);
@@ -96,8 +101,6 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
96
101
 
97
102
  const Root = role ?? 'div';
98
103
 
99
- const composedItemRef = composeRefs<HTMLDivElement>(itemRef, forwardedRef);
100
-
101
104
  const setSize = useCallback(
102
105
  (nextSize: StackItemSize, commit?: boolean) => {
103
106
  setInternalSize(nextSize);
@@ -110,6 +113,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
110
113
 
111
114
  const type = orientation === 'horizontal' ? 'column' : 'card';
112
115
 
116
+ // TODO(burdon): Factor out?
113
117
  useLayoutEffect(() => {
114
118
  if (!itemElement || !onRearrange || disableRearrange) {
115
119
  return;
@@ -139,7 +143,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
139
143
  onDragStart: () => {
140
144
  document.body.removeAttribute('data-drag-preview');
141
145
  itemElement?.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'active');
142
- setDragState({ type: 'is-dragging', item });
146
+ setDragState({ type: 'w-dragging', item });
143
147
  },
144
148
  onDrop: () => {
145
149
  itemElement?.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'idle');
@@ -183,18 +187,18 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
183
187
 
184
188
  const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
185
189
 
186
- // Determine if the drop would result in any changes
190
+ // Determine if the drop would result in any changes.
187
191
  const shouldShowDropIndicator = () => {
188
192
  if (!closestEdge || !sourceId) {
189
193
  return false;
190
194
  }
191
195
 
192
- // Don't show indicator when dragged item is over itself
196
+ // Don't show indicator when dragged item is over itself.
193
197
  if (sourceId === item.id) {
194
198
  return false;
195
199
  }
196
200
 
197
- // 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.
198
202
  const isTrailingEdgeOfPrevSibling =
199
203
  prevSiblingId !== undefined &&
200
204
  sourceId === prevSiblingId &&
@@ -243,7 +247,7 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
243
247
  : 'dx-focus-ring-group-y',
244
248
  orientation === 'horizontal' ? 'grid-rows-subgrid' : 'grid-cols-subgrid',
245
249
  rail && (orientation === 'horizontal' ? 'row-span-2' : 'col-span-2'),
246
- role === 'section' && orientation !== 'horizontal' && 'border-be border-subduedSeparator',
250
+ role === 'section' && orientation !== 'horizontal' && 'border-b border-subdued-separator',
247
251
  classNames,
248
252
  )}
249
253
  data-dx-stack-item={stackId}
@@ -268,37 +272,45 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
268
272
  },
269
273
  );
270
274
 
275
+ //
276
+ // StackItemDragPreview
277
+ //
278
+
271
279
  type StackItemDragPreviewProps = {
272
280
  children: ({ item }: { item: any }) => ReactNode;
273
281
  };
274
282
 
275
- export const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
283
+ const StackItemDragPreview = ({ children }: StackItemDragPreviewProps) => {
276
284
  const { state } = useStackItem();
277
285
  return state?.type === 'preview' ? createPortal(children({ item: state.item }), state.container) : null;
278
286
  };
279
287
 
288
+ //
289
+ // StackItem
290
+ //
291
+
280
292
  export const StackItem = {
281
293
  Root: StackItemRoot,
282
294
  Content: StackItemContent,
295
+ DragHandle: StackItemDragHandle,
296
+ DragPreview: StackItemDragPreview,
283
297
  Heading: StackItemHeading,
284
298
  HeadingLabel: StackItemHeadingLabel,
285
299
  HeadingStickyContent: StackItemHeadingStickyContent,
286
300
  ResizeHandle: StackItemResizeHandle,
287
- DragHandle: StackItemDragHandle,
288
301
  Sigil: StackItemSigil,
289
302
  SigilButton: StackItemSigilButton,
290
- DragPreview: StackItemDragPreview,
291
303
  };
292
304
 
293
305
  export type {
294
306
  StackItemRootProps,
295
307
  StackItemContentProps,
308
+ StackItemDragHandleProps,
309
+ StackItemDragPreviewProps,
296
310
  StackItemHeadingProps,
297
311
  StackItemHeadingLabelProps,
298
312
  StackItemResizeHandleProps,
299
- StackItemDragHandleProps,
300
313
  StackItemSigilProps,
301
314
  StackItemSigilButtonProps,
302
315
  StackItemSigilAction,
303
- StackItemDragPreviewProps,
304
316
  };
@@ -5,82 +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
- // TODO(burdon): Add prop for container-max-width?
13
12
  export type StackItemContentProps = ThemedClassName<Omit<ComponentPropsWithoutRef<'div'>, 'role' | 'scrollable'>> & {
14
- /**
15
- * This flag is required in order to clarify a developer experience that seemed like it needed extra boilerplate
16
- * (`row-span-2`) or was buggy. See the description of the StackItem.Content component itself for more information.
17
- */
18
13
  toolbar?: boolean;
19
-
20
- /**
21
- * Whether to provide for the layout of a statusbar after the content.
22
- */
23
14
  statusbar?: boolean;
24
-
25
- /**
26
- * Whether to support y-axis scrolling.
27
- */
28
- scrollable?: boolean;
29
-
30
- /**
31
- * Whether the consumer intends to do something custom and typical affordances should not apply.
32
- */
33
- // TODO(burdon): This is cryptic; can we remove (only used by plugin-inbox?) Normalize toolbar?
34
- layoutManaged?: boolean;
35
-
36
- /**
37
- * Whether to set a certain aspect ratio on the content, including the toolbar and statusbar.
38
- * This is provided for convenience and consistency; it can instead be specified by the `classNames` or `style` props as needed.
39
- */
40
- size?: 'intrinsic' | 'video' | 'square';
41
15
  };
42
16
 
43
17
  /**
44
- * This component should be used by plugins for rendering content within a stack item, a.k.a. a “plank” or “section”.
45
- * 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”).
46
19
  */
47
20
  export const StackItemContent = forwardRef<HTMLDivElement, StackItemContentProps>(
48
- (
49
- { children, toolbar, statusbar, layoutManaged, classNames, size = 'intrinsic', scrollable, ...props },
50
- forwardedRef,
51
- ) => {
21
+ ({ classNames, children, toolbar, statusbar, ...props }, forwardedRef) => {
52
22
  const { size: stackItemSize } = useStack();
53
23
  const { role } = useStackItem();
54
24
  const style = useMemo(
55
- () =>
56
- layoutManaged
57
- ? {}
58
- : {
59
- gridTemplateRows: [
60
- ...(toolbar ? [role === 'section' ? 'calc(var(--toolbar-size) - 1px)' : 'var(--toolbar-size)'] : []),
61
- '1fr',
62
- ...(statusbar ? ['var(--statusbar-size)'] : []),
63
- ].join(' '),
64
- },
65
- [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],
66
35
  );
67
36
 
68
37
  return (
69
38
  <div
70
- role='none'
71
39
  {...props}
40
+ role='none'
41
+ style={style}
72
42
  className={mx(
73
- 'group grid grid-cols-[100%] density-coarse',
74
- stackItemSize === 'contain' && 'min-bs-0 overflow-hidden',
75
- size === 'video' ? 'aspect-video' : size === 'square' && 'aspect-square',
76
- toolbar && '[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-be [&>.dx-toolbar]:border-subduedSeparator',
77
- scrollable ? 'min-bs-0 overflow-y-auto scrollbar-thin contain-layout' : 'overflow-hidden',
78
- role === 'section' &&
79
- toolbar &&
80
- '[&_.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',
81
49
  classNames,
82
50
  )}
83
- style={style}
84
51
  data-popover-collision-boundary={true}
85
52
  ref={forwardedRef}
86
53
  >
@@ -89,3 +56,5 @@ export const StackItemContent = forwardRef<HTMLDivElement, StackItemContentProps
89
56
  );
90
57
  },
91
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
  };