@dxos/react-ui-stack 0.6.12-main.ed7cda7 → 0.6.12-staging.e11e696

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 (33) hide show
  1. package/dist/lib/browser/index.mjs +3 -4
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +1 -1
  5. package/dist/lib/browser/testing/index.mjs.map +3 -3
  6. package/dist/lib/node/index.cjs +2 -3
  7. package/dist/lib/node/index.cjs.map +3 -3
  8. package/dist/lib/node/meta.json +1 -1
  9. package/dist/lib/node/testing/index.cjs.map +2 -2
  10. package/dist/lib/node-esm/index.mjs +3 -4
  11. package/dist/lib/node-esm/index.mjs.map +3 -3
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/Section.d.ts.map +1 -1
  16. package/dist/types/src/next/Stack.d.ts +9 -0
  17. package/dist/types/src/next/Stack.d.ts.map +1 -0
  18. package/dist/types/src/next/Stack.stories.d.ts +8 -0
  19. package/dist/types/src/next/Stack.stories.d.ts.map +1 -0
  20. package/dist/types/src/next/StackItem.d.ts +14 -0
  21. package/dist/types/src/next/StackItem.d.ts.map +1 -0
  22. package/dist/types/src/next/index.d.ts +2 -0
  23. package/dist/types/src/next/index.d.ts.map +1 -0
  24. package/dist/types/src/testing/generator.d.ts +1 -1
  25. package/dist/types/src/testing/generator.d.ts.map +1 -1
  26. package/package.json +21 -17
  27. package/src/components/Deck.stories.tsx +10 -10
  28. package/src/components/Section.tsx +3 -5
  29. package/src/next/Stack.stories.tsx +146 -0
  30. package/src/next/Stack.tsx +30 -0
  31. package/src/next/StackItem.tsx +78 -0
  32. package/src/next/index.ts +5 -0
  33. package/src/testing/generator.ts +3 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-stack",
3
- "version": "0.6.12-main.ed7cda7",
3
+ "version": "0.6.12-staging.e11e696",
4
4
  "description": "A stack component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -37,6 +37,10 @@
37
37
  "src"
38
38
  ],
39
39
  "dependencies": {
40
+ "@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
41
+ "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
42
+ "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.3",
43
+ "@effect/schema": "^0.67.16",
40
44
  "@fluentui/react-tabster": "^9.19.0",
41
45
  "@radix-ui/primitive": "^1.0.0",
42
46
  "@radix-ui/react-collapsible": "^1.0.2",
@@ -45,11 +49,12 @@
45
49
  "@radix-ui/react-menu": "^2.0.6",
46
50
  "@radix-ui/react-use-controllable-state": "^1.0.0",
47
51
  "react-resize-detector": "^11.0.1",
48
- "@dxos/react-ui": "0.6.12-main.ed7cda7",
49
- "@dxos/react-ui-attention": "0.6.12-main.ed7cda7",
50
- "@dxos/react-ui-deck": "0.6.12-main.ed7cda7",
51
- "@dxos/react-ui-mosaic": "0.6.12-main.ed7cda7",
52
- "@dxos/react-ui-theme": "0.6.12-main.ed7cda7"
52
+ "@dxos/echo-schema": "0.6.12-staging.e11e696",
53
+ "@dxos/react-ui": "0.6.12-staging.e11e696",
54
+ "@dxos/react-ui-attention": "0.6.12-staging.e11e696",
55
+ "@dxos/react-ui-deck": "0.6.12-staging.e11e696",
56
+ "@dxos/react-ui-theme": "0.6.12-staging.e11e696",
57
+ "@dxos/react-ui-mosaic": "0.6.12-staging.e11e696"
53
58
  },
54
59
  "devDependencies": {
55
60
  "@phosphor-icons/react": "^2.1.5",
@@ -58,22 +63,21 @@
58
63
  "react": "~18.2.0",
59
64
  "react-dom": "~18.2.0",
60
65
  "vite": "5.4.7",
61
- "@dxos/client": "0.6.12-main.ed7cda7",
62
- "@dxos/random": "0.6.12-main.ed7cda7",
63
- "@dxos/react-ui-editor": "0.6.12-main.ed7cda7",
64
- "@dxos/echo-schema": "0.6.12-main.ed7cda7",
65
- "@dxos/react-ui-table": "0.6.12-main.ed7cda7",
66
- "@dxos/storybook-utils": "0.6.12-main.ed7cda7",
67
- "@dxos/util": "0.6.12-main.ed7cda7",
68
- "@dxos/test-utils": "0.6.12-main.ed7cda7"
66
+ "@dxos/echo-schema": "0.6.12-staging.e11e696",
67
+ "@dxos/random": "0.6.12-staging.e11e696",
68
+ "@dxos/react-ui-editor": "0.6.12-staging.e11e696",
69
+ "@dxos/react-ui-table": "0.6.12-staging.e11e696",
70
+ "@dxos/storybook-utils": "0.6.12-staging.e11e696",
71
+ "@dxos/client": "0.6.12-staging.e11e696",
72
+ "@dxos/test-utils": "0.6.12-staging.e11e696",
73
+ "@dxos/util": "0.6.12-staging.e11e696"
69
74
  },
70
75
  "peerDependencies": {
71
76
  "@phosphor-icons/react": "^2.1.5",
72
77
  "react": "~18.2.0",
73
78
  "react-dom": "~18.2.0",
74
- "@dxos/echo-schema": "0.6.12-main.ed7cda7",
75
- "@dxos/client": "0.6.12-main.ed7cda7",
76
- "@dxos/random": "0.6.12-main.ed7cda7"
79
+ "@dxos/random": "0.6.12-staging.e11e696",
80
+ "@dxos/client": "0.6.12-staging.e11e696"
77
81
  },
78
82
  "publishConfig": {
79
83
  "access": "public"
@@ -9,7 +9,7 @@ import React, { type PropsWithChildren, useState, type ComponentProps } from 're
9
9
 
10
10
  import { faker } from '@dxos/random';
11
11
  import { Button, Icon, Main } from '@dxos/react-ui';
12
- import { AttentionProvider } from '@dxos/react-ui-attention';
12
+ import { RootAttentionProvider } from '@dxos/react-ui-attention';
13
13
  import { PlankHeading, Deck as NaturalDeck, Plank } from '@dxos/react-ui-deck';
14
14
  import { Mosaic, type MosaicDataItem } from '@dxos/react-ui-mosaic';
15
15
  import { withTheme } from '@dxos/storybook-utils';
@@ -102,10 +102,10 @@ export default {
102
102
  export const StaticBasicStacks = {
103
103
  args: {},
104
104
  render: () => {
105
- const [attended] = useState(new Set<string>());
105
+ const [attention] = useState({ attended: [] });
106
106
  return (
107
107
  <Mosaic.Root>
108
- <AttentionProvider attended={attended}>
108
+ <RootAttentionProvider attention={attention}>
109
109
  <Mosaic.DragOverlay />
110
110
  <NaturalDeck.Root classNames='fixed inset-0 z-0'>
111
111
  <DemoStackPlank />
@@ -116,7 +116,7 @@ export const StaticBasicStacks = {
116
116
  <DemoStackPlank />
117
117
  <DemoStackPlank />
118
118
  </NaturalDeck.Root>
119
- </AttentionProvider>
119
+ </RootAttentionProvider>
120
120
  </Mosaic.Root>
121
121
  );
122
122
  },
@@ -125,10 +125,10 @@ export const StaticBasicStacks = {
125
125
  export const StaticBasicStacksWithOverscrolling = {
126
126
  args: {},
127
127
  render: () => {
128
- const [attended] = useState(new Set<string>());
128
+ const [attention] = useState({ attended: [] });
129
129
  return (
130
130
  <Mosaic.Root>
131
- <AttentionProvider attended={attended}>
131
+ <RootAttentionProvider attention={attention}>
132
132
  <Mosaic.DragOverlay />
133
133
  <NaturalDeck.Root classNames='fixed inset-0 z-0'>
134
134
  <DemoStackPlank />
@@ -139,7 +139,7 @@ export const StaticBasicStacksWithOverscrolling = {
139
139
  <DemoStackPlank />
140
140
  <DemoStackPlank />
141
141
  </NaturalDeck.Root>
142
- </AttentionProvider>
142
+ </RootAttentionProvider>
143
143
  </Mosaic.Root>
144
144
  );
145
145
  },
@@ -195,7 +195,7 @@ export const DynamicBasicStacks = () => {
195
195
  return acc;
196
196
  }, {}),
197
197
  );
198
- const [attended] = useState(new Set<string>());
198
+ const [attention] = useState({ attended: [] });
199
199
 
200
200
  const [navOpen, setNavOpen] = useState(true);
201
201
  const [c11yOpen, setC11yOpen] = useState(false);
@@ -285,7 +285,7 @@ export const DynamicBasicStacks = () => {
285
285
 
286
286
  return (
287
287
  <Mosaic.Root>
288
- <AttentionProvider attended={attended}>
288
+ <RootAttentionProvider attention={attention}>
289
289
  <Main.Root complementarySidebarOpen={c11yOpen} navigationSidebarOpen={navOpen}>
290
290
  <Main.Overlay />
291
291
  <Mosaic.DragOverlay />
@@ -359,7 +359,7 @@ export const DynamicBasicStacks = () => {
359
359
  )}
360
360
  </NaturalDeck.Root>
361
361
  </Main.Root>
362
- </AttentionProvider>
362
+ </RootAttentionProvider>
363
363
  </Mosaic.Root>
364
364
  );
365
365
  };
@@ -28,7 +28,7 @@ import {
28
28
  toLocalizedString,
29
29
  useTranslation,
30
30
  } from '@dxos/react-ui';
31
- import { createAttendableAttributes, useHasAttention } from '@dxos/react-ui-attention';
31
+ import { useAttendableAttributes } from '@dxos/react-ui-attention';
32
32
  import { DropDownMenuDragHandleTrigger, resizeHandle, resizeHandleHorizontal } from '@dxos/react-ui-deck';
33
33
  import {
34
34
  type MosaicActiveType,
@@ -150,8 +150,7 @@ export const Section: ForwardRefExoticComponent<SectionProps & RefAttributes<HTM
150
150
  mover: { cyclic: true, direction: 1, memorizeCurrent: false },
151
151
  });
152
152
  const sectionContentGroup = useFocusableGroup({});
153
- const attendableAttrs = createAttendableAttributes(id);
154
- const hasAttention = useHasAttention(id);
153
+ const attendableAttrs = useAttendableAttributes(id);
155
154
 
156
155
  return (
157
156
  <CollapsiblePrimitive.Root
@@ -173,10 +172,9 @@ export const Section: ForwardRefExoticComponent<SectionProps & RefAttributes<HTM
173
172
  role='none'
174
173
  className={mx(
175
174
  'grid col-span-2 grid-cols-subgrid',
176
- 'bg-base focus-within:border-separator focus-within:attention-within',
175
+ 'bg-base attention-surface',
177
176
  hoverableControls,
178
177
  hoverableFocusedWithinControls,
179
- (active || hasAttention) && 'attention-surface border-separator',
180
178
  (active === 'origin' || active === 'rearrange' || active === 'destination') && 'opacity-0',
181
179
  )}
182
180
  >
@@ -0,0 +1,146 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
6
+ import { type Meta, type StoryObj } from '@storybook/react';
7
+ import React, { useState, useCallback } from 'react';
8
+
9
+ import { withTheme } from '@dxos/storybook-utils';
10
+
11
+ import { Stack } from './Stack';
12
+ import { StackItem } from './StackItem';
13
+
14
+ type CardItem = {
15
+ id: string;
16
+ type: 'card';
17
+ content: string;
18
+ };
19
+
20
+ type ColumnItem = {
21
+ id: string;
22
+ type: 'column';
23
+ title: string;
24
+ cards: CardItem[];
25
+ };
26
+
27
+ const KanbanBlock = ({ item }: { item: CardItem }) => {
28
+ return (
29
+ <div className='is-64 bs-24 bg-input rounded-lg border border-separator shadow-sm grid place-content-center'>
30
+ <span className='text-sm font-medium'>{item.content}</span>
31
+ </div>
32
+ );
33
+ };
34
+
35
+ const StorybookStack = () => {
36
+ const [columns, setColumns] = useState<ColumnItem[]>([
37
+ {
38
+ id: 'col-0',
39
+ type: 'column',
40
+ title: 'To Do',
41
+ cards: [
42
+ { id: 'banana', type: 'card', content: 'Banana' },
43
+ { id: 'pickle', type: 'card', content: 'Pickle' },
44
+ { id: 'wombat', type: 'card', content: 'Wombat' },
45
+ { id: 'kazoo', type: 'card', content: 'Kazoo' },
46
+ ],
47
+ },
48
+ {
49
+ id: 'col-1',
50
+ type: 'column',
51
+ title: 'In Progress',
52
+ cards: [
53
+ { id: 'noodle', type: 'card', content: 'Noodle' },
54
+ { id: 'squish', type: 'card', content: 'Squish' },
55
+ { id: 'wobble', type: 'card', content: 'Wobble' },
56
+ { id: 'floof', type: 'card', content: 'Floof' },
57
+ ],
58
+ },
59
+ {
60
+ id: 'col-2',
61
+ type: 'column',
62
+ title: 'Done',
63
+ cards: [
64
+ { id: 'snorkel', type: 'card', content: 'Snorkel' },
65
+ { id: 'bloop', type: 'card', content: 'Bloop' },
66
+ { id: 'wiggle', type: 'card', content: 'Wiggle' },
67
+ { id: 'zoop', type: 'card', content: 'Zoop' },
68
+ ],
69
+ },
70
+ ]);
71
+
72
+ const reorderItem = useCallback((sourceId: string, targetId: string, closestEdge: Edge | null) => {
73
+ setColumns((prevColumns) => {
74
+ const newColumns = [...prevColumns];
75
+ const sourceColumn = newColumns.find(
76
+ (col) => col.id === sourceId || col.cards.some((card) => card.id === sourceId),
77
+ );
78
+ const targetColumn = newColumns.find(
79
+ (col) => col.id === targetId || col.cards.some((card) => card.id === targetId),
80
+ );
81
+
82
+ if (sourceColumn && targetColumn) {
83
+ if (sourceId.startsWith('col-') && targetId.startsWith('col-')) {
84
+ // Reordering columns
85
+ const sourceIndex = newColumns.findIndex((col) => col.id === sourceId);
86
+ const targetIndex = newColumns.findIndex((col) => col.id === targetId);
87
+ const [movedColumn] = newColumns.splice(sourceIndex, 1);
88
+ const insertIndex = closestEdge === 'right' ? targetIndex + 1 : targetIndex;
89
+ newColumns.splice(insertIndex, 0, movedColumn);
90
+ } else {
91
+ // Reordering cards within a column
92
+ const sourceCardIndex = sourceColumn.cards.findIndex((card) => card.id === sourceId);
93
+ const targetCardIndex = targetColumn.cards.findIndex((card) => card.id === targetId);
94
+ const [movedCard] = sourceColumn.cards.splice(sourceCardIndex, 1);
95
+
96
+ let insertIndex;
97
+ if (sourceColumn === targetColumn && sourceCardIndex < targetCardIndex) {
98
+ insertIndex = closestEdge === 'bottom' ? targetCardIndex : targetCardIndex - 1;
99
+ } else {
100
+ insertIndex = closestEdge === 'bottom' ? targetCardIndex + 1 : targetCardIndex;
101
+ }
102
+ targetColumn.cards.splice(insertIndex, 0, movedCard);
103
+ }
104
+ }
105
+
106
+ return newColumns;
107
+ });
108
+ }, []);
109
+
110
+ return (
111
+ <Stack orientation={'horizontal'} classNames='gap-1'>
112
+ {columns.map((column) => (
113
+ <StackItem
114
+ key={column.id}
115
+ item={column}
116
+ orientation={'horizontal'}
117
+ classNames='p-4 bg-deck rounded-md'
118
+ onReorder={reorderItem}
119
+ >
120
+ <Stack orientation={'vertical'} classNames='gap-1'>
121
+ {column.cards.map((card) => (
122
+ <StackItem key={card.id} item={card} orientation={'vertical'} onReorder={reorderItem}>
123
+ <KanbanBlock item={card} />
124
+ </StackItem>
125
+ ))}
126
+ </Stack>
127
+ </StackItem>
128
+ ))}
129
+ </Stack>
130
+ );
131
+ };
132
+
133
+ const meta: Meta<typeof StorybookStack> = {
134
+ title: 'react-ui-stack-next/Stack',
135
+ component: StorybookStack,
136
+ decorators: [withTheme],
137
+ argTypes: { orientation: { control: 'radio', options: ['horizontal', 'vertical'] } },
138
+ };
139
+
140
+ export default meta;
141
+
142
+ type Story = StoryObj<typeof StorybookStack>;
143
+
144
+ export const Default: Story = {
145
+ args: { orientation: 'horizontal' },
146
+ };
@@ -0,0 +1,30 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { type CSSProperties, type ComponentPropsWithoutRef } from 'react';
6
+
7
+ import { type ThemedClassName } from '@dxos/react-ui';
8
+ import { mx } from '@dxos/react-ui-theme';
9
+
10
+ type Orientation = 'horizontal' | 'vertical';
11
+
12
+ export type StackProps = Omit<ThemedClassName<ComponentPropsWithoutRef<'div'>>, 'aria-orientation'> & {
13
+ orientation?: Orientation;
14
+ };
15
+
16
+ export const Stack = ({ children, classNames, style, orientation, ...props }: StackProps) => {
17
+ const childrenCount = React.Children.count(children);
18
+
19
+ const styles: CSSProperties = {
20
+ [orientation === 'horizontal' ? 'gridTemplateColumns' : 'gridTemplateRows']:
21
+ `repeat(${childrenCount}, min-content)`,
22
+ ...style,
23
+ };
24
+
25
+ return (
26
+ <div className={mx('grid relative', classNames)} aria-orientation={orientation} style={styles} {...props}>
27
+ {children}
28
+ </div>
29
+ );
30
+ };
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
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 {
8
+ attachClosestEdge,
9
+ type Edge,
10
+ extractClosestEdge,
11
+ } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
12
+ import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
13
+ import React, { useRef, useState, type ComponentPropsWithoutRef } from 'react';
14
+
15
+ import { type ThemedClassName } from '@dxos/react-ui';
16
+ import { mx } from '@dxos/react-ui-theme';
17
+
18
+ import { type StackProps } from './Stack';
19
+
20
+ export type StackItemProps = Omit<ThemedClassName<ComponentPropsWithoutRef<'div'>>, 'aria-orientation'> & {
21
+ item: { id: string; type: 'column' | 'card' };
22
+ orientation?: StackProps['orientation'];
23
+ onReorder: (sourceId: string, targetId: string, closestEdge: Edge | null) => void;
24
+ };
25
+
26
+ export const StackItem = ({ item, children, classNames, orientation, onReorder, ...props }: StackItemProps) => {
27
+ const ref = useRef<HTMLDivElement>(null);
28
+ const [closestEdge, setEdge] = useState<Edge | null>(null);
29
+
30
+ React.useEffect(() => {
31
+ if (!ref.current) {
32
+ return;
33
+ }
34
+
35
+ const element = ref.current;
36
+
37
+ return combine(
38
+ draggable({ element, getInitialData: () => ({ id: item.id, type: item.type }) }),
39
+ dropTargetForElements({
40
+ element,
41
+ getData: ({ input, element }) => {
42
+ return attachClosestEdge(
43
+ { id: item.id, type: item.type },
44
+ { input, element, allowedEdges: orientation === 'vertical' ? ['top', 'bottom'] : ['left', 'right'] },
45
+ );
46
+ },
47
+ onDragEnter: ({ self, source }) => {
48
+ if (source.data.type === self.data.type) {
49
+ setEdge(extractClosestEdge(self.data));
50
+ }
51
+ },
52
+ onDrag: ({ self, source }) => {
53
+ if (source.data.type === self.data.type) {
54
+ setEdge(extractClosestEdge(self.data));
55
+ }
56
+ },
57
+ onDragLeave: () => setEdge(null),
58
+ onDrop: ({ self, source }) => {
59
+ setEdge(null);
60
+ if (source.data.type === self.data.type) {
61
+ onReorder(source.data.id as string, self.data.id as string, extractClosestEdge(self.data));
62
+ }
63
+ },
64
+ }),
65
+ );
66
+ }, [orientation, item, onReorder]);
67
+
68
+ return (
69
+ <div
70
+ ref={ref}
71
+ className={mx('relative', orientation === 'horizontal' ? 'grid-cols-subgrid' : 'grid-rows-subgrid', classNames)}
72
+ {...props}
73
+ >
74
+ {children}
75
+ {closestEdge && <DropIndicator edge={closestEdge} />}
76
+ </div>
77
+ );
78
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './Stack';
@@ -2,13 +2,13 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { create, type EchoReactiveObject, S } from '@dxos/echo-schema';
6
+ import { faker } from '@dxos/random';
7
+
5
8
  // TODO(burdon): Reconcile with @dxos/plugin-debug, @dxos/react-ui/testing.
6
9
 
7
10
  // TODO(burdon): Bug when adding stale objects to space (e.g., static objects already added in previous story invocation).
8
11
 
9
- import { S, create, type EchoReactiveObject } from '@dxos/echo-schema';
10
- import { faker } from '@dxos/random';
11
-
12
12
  // TODO(burdon): Util.
13
13
  export const range = <T>(fn: (i: number) => T | undefined, length: number): T[] =>
14
14
  Array.from({ length })