@dxos/react-ui-stack 0.8.3-staging.0fa589b → 0.8.4-main.28f8d3d

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 (99) hide show
  1. package/dist/lib/browser/chunk-FV7KWSG5.mjs +1198 -0
  2. package/dist/lib/browser/chunk-FV7KWSG5.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +40 -1160
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/{node/testing/index.cjs → browser/playwright/index.mjs} +8 -28
  7. package/dist/lib/{node/testing/index.cjs.map → browser/playwright/index.mjs.map} +3 -3
  8. package/dist/lib/browser/testing/index.mjs +25 -51
  9. package/dist/lib/browser/testing/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/chunk-ISLFXOAT.mjs +1200 -0
  11. package/dist/lib/node-esm/chunk-ISLFXOAT.mjs.map +7 -0
  12. package/dist/lib/node-esm/index.mjs +40 -1161
  13. package/dist/lib/node-esm/index.mjs.map +4 -4
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/playwright/index.mjs +63 -0
  16. package/dist/lib/node-esm/playwright/index.mjs.map +7 -0
  17. package/dist/lib/node-esm/testing/index.mjs +24 -51
  18. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  19. package/dist/types/src/components/Stack/Stack.d.ts +1 -1
  20. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  21. package/dist/types/src/components/Stack/Stack.stories.d.ts +1 -1
  22. package/dist/types/src/components/Stack/Stack.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/StackContext.d.ts +1 -1
  24. package/dist/types/src/components/StackContext.d.ts.map +1 -1
  25. package/dist/types/src/components/StackItem/StackItem.d.ts +4 -4
  26. package/dist/types/src/components/StackItem/StackItem.d.ts.map +1 -1
  27. package/dist/types/src/components/StackItem/StackItem.stories.d.ts +1 -1
  28. package/dist/types/src/components/StackItem/StackItem.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/StackItem/StackItemContent.d.ts +2 -2
  30. package/dist/types/src/components/StackItem/StackItemContent.d.ts.map +1 -1
  31. package/dist/types/src/components/StackItem/StackItemHeading.d.ts +1 -1
  32. package/dist/types/src/components/StackItem/StackItemHeading.d.ts.map +1 -1
  33. package/dist/types/src/components/StackItem/StackItemResizeHandle.d.ts.map +1 -1
  34. package/dist/types/src/components/StackItem/StackItemSigil.d.ts.map +1 -1
  35. package/dist/types/src/components/index.d.ts +1 -1
  36. package/dist/types/src/components/index.d.ts.map +1 -1
  37. package/dist/types/src/exemplars/Card/Card.d.ts +6 -10
  38. package/dist/types/src/exemplars/Card/Card.d.ts.map +1 -1
  39. package/dist/types/src/exemplars/Card/Card.stories.d.ts +13 -0
  40. package/dist/types/src/exemplars/Card/Card.stories.d.ts.map +1 -0
  41. package/dist/types/src/exemplars/Card/fragments.d.ts +1 -2
  42. package/dist/types/src/exemplars/Card/fragments.d.ts.map +1 -1
  43. package/dist/types/src/exemplars/CardStack/CardStack.d.ts +7 -1
  44. package/dist/types/src/exemplars/CardStack/CardStack.d.ts.map +1 -1
  45. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts +9 -0
  46. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts.map +1 -0
  47. package/dist/types/src/hooks/useStackDropForElements.d.ts +1 -1
  48. package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -1
  49. package/dist/types/src/index.d.ts +1 -1
  50. package/dist/types/src/index.d.ts.map +1 -1
  51. package/dist/types/src/playwright/index.d.ts +2 -0
  52. package/dist/types/src/playwright/index.d.ts.map +1 -0
  53. package/dist/types/src/playwright/playwright.config.d.ts +3 -0
  54. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
  55. package/dist/types/src/playwright/stack-manager.d.ts.map +1 -0
  56. package/dist/types/src/testing/CardContainer.d.ts +6 -0
  57. package/dist/types/src/testing/CardContainer.d.ts.map +1 -0
  58. package/dist/types/src/testing/index.d.ts +1 -1
  59. package/dist/types/src/translations.d.ts +13 -14
  60. package/dist/types/src/translations.d.ts.map +1 -1
  61. package/dist/types/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +29 -25
  63. package/src/components/Stack/Stack.stories.tsx +5 -4
  64. package/src/components/Stack/Stack.tsx +5 -5
  65. package/src/components/StackContext.tsx +1 -1
  66. package/src/components/StackItem/StackItem.stories.tsx +2 -2
  67. package/src/components/StackItem/StackItem.tsx +12 -11
  68. package/src/components/StackItem/StackItemContent.tsx +4 -3
  69. package/src/components/StackItem/StackItemHeading.tsx +3 -3
  70. package/src/components/StackItem/StackItemResizeHandle.tsx +2 -1
  71. package/src/components/StackItem/StackItemSigil.tsx +2 -1
  72. package/src/components/index.ts +1 -1
  73. package/src/exemplars/Card/Card.stories.tsx +78 -0
  74. package/src/exemplars/Card/Card.tsx +36 -31
  75. package/src/exemplars/Card/CardDragPreview.tsx +2 -2
  76. package/src/exemplars/Card/fragments.ts +1 -3
  77. package/src/exemplars/CardStack/CardStack.stories.tsx +173 -0
  78. package/src/exemplars/CardStack/CardStack.tsx +19 -2
  79. package/src/hooks/useStackDropForElements.ts +5 -2
  80. package/src/index.ts +3 -4
  81. package/src/playwright/index.ts +5 -0
  82. package/src/playwright/playwright.config.ts +17 -0
  83. package/src/playwright/smoke.spec.ts +7 -5
  84. package/src/testing/CardContainer.tsx +37 -0
  85. package/src/testing/index.ts +1 -1
  86. package/src/translations.ts +5 -3
  87. package/dist/lib/node/index.cjs +0 -1220
  88. package/dist/lib/node/index.cjs.map +0 -7
  89. package/dist/lib/node/meta.json +0 -1
  90. package/dist/types/src/exemplars/Card/Card.stories-todo.d.ts +0 -1
  91. package/dist/types/src/exemplars/Card/Card.stories-todo.d.ts.map +0 -1
  92. package/dist/types/src/exemplars/CardStack/CardStack.stories-todo.d.ts +0 -1
  93. package/dist/types/src/exemplars/CardStack/CardStack.stories-todo.d.ts.map +0 -1
  94. package/dist/types/src/testing/stack-manager.d.ts.map +0 -1
  95. package/src/exemplars/Card/Card.stories-todo.tsx +0 -135
  96. package/src/exemplars/CardStack/CardStack.stories-todo.tsx +0 -80
  97. package/src/playwright/playwright.config.cts +0 -18
  98. /package/dist/types/src/{testing → playwright}/stack-manager.d.ts +0 -0
  99. /package/src/{testing → playwright}/stack-manager.ts +0 -0
@@ -0,0 +1,173 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
8
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
9
+ import React, { useCallback, useState } from 'react';
10
+
11
+ import { faker } from '@dxos/random';
12
+ import { IconButton } from '@dxos/react-ui';
13
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
14
+
15
+ import { StackItem } from '../../components';
16
+ import { Card, CardDragPreview } from '../Card';
17
+
18
+ import { CardStack } from './CardStack';
19
+
20
+ // Set a seed for reproducible random values
21
+ faker.seed(0);
22
+
23
+ type CardItem = {
24
+ id: string;
25
+ title: string;
26
+ description: string;
27
+ image: string;
28
+ };
29
+
30
+ type StackItemData = {
31
+ id: string;
32
+ type?: 'column' | 'card';
33
+ };
34
+
35
+ const CardStackStory = () => {
36
+ const [column, setColumn] = useState<CardItem[]>(
37
+ faker.helpers.multiple(
38
+ () => ({
39
+ id: faker.string.uuid(),
40
+ title: faker.commerce.productName(),
41
+ description: faker.lorem.paragraph(),
42
+ image: faker.image.url(),
43
+ }),
44
+ { count: 12 },
45
+ ),
46
+ );
47
+
48
+ const handleRearrange = useCallback((source: StackItemData, target: StackItemData, closestEdge: Edge | null) => {
49
+ setColumn((prevColumn) => {
50
+ const newColumns = [...prevColumn];
51
+ // Reordering cards within a column
52
+ const sourceCardIndex = prevColumn.findIndex((card) => card.id === source.id);
53
+ const targetCardIndex = prevColumn.findIndex((card) => card.id === target.id);
54
+
55
+ if (typeof sourceCardIndex === 'number' && typeof targetCardIndex === 'number') {
56
+ const [movedCard] = newColumns.splice(sourceCardIndex, 1);
57
+
58
+ let insertIndex;
59
+ if (sourceCardIndex < targetCardIndex) {
60
+ insertIndex = closestEdge === 'bottom' ? targetCardIndex : targetCardIndex - 1;
61
+ } else {
62
+ insertIndex = closestEdge === 'bottom' ? targetCardIndex + 1 : targetCardIndex;
63
+ }
64
+ newColumns.splice(insertIndex, 0, movedCard);
65
+ }
66
+ return newColumns;
67
+ });
68
+ }, []);
69
+
70
+ const handleAddCard = useCallback(() => {
71
+ setColumn((prevColumn) => {
72
+ const newColumn = [...prevColumn];
73
+ const newCard = {
74
+ id: faker.string.uuid(),
75
+ title: faker.commerce.productName(),
76
+ description: faker.lorem.paragraph(),
77
+ image: faker.image.url(),
78
+ } satisfies CardItem;
79
+ newColumn.push(newCard);
80
+ console.log('[add card]', prevColumn.length, newColumn.length);
81
+ return newColumn;
82
+ });
83
+ }, []);
84
+
85
+ const handleRemoveCard = useCallback((cardId: string) => {
86
+ setColumn((prevColumn) => {
87
+ const newColumn = [...prevColumn];
88
+
89
+ const cardIndex = prevColumn.findIndex((card) => card.id === cardId);
90
+ if (cardIndex !== -1) {
91
+ newColumn.splice(cardIndex, 1);
92
+ }
93
+
94
+ return newColumn;
95
+ });
96
+ }, []);
97
+
98
+ return (
99
+ <CardStack.Root classNames='is-96'>
100
+ <CardStack.Content>
101
+ <CardStack.Stack id='story column' onRearrange={handleRearrange} itemsCount={column.length}>
102
+ {column.map((card, cardIndex, cardsArray) => {
103
+ const cardItem = { id: card.id, type: 'card' as const };
104
+ const prevCardId = cardIndex > 0 ? cardsArray[cardIndex - 1].id : undefined;
105
+ const nextCardId = cardIndex < cardsArray.length - 1 ? cardsArray[cardIndex + 1].id : undefined;
106
+
107
+ return (
108
+ <CardStack.Item asChild key={card.id}>
109
+ <StackItem.Root
110
+ item={cardItem}
111
+ focusIndicatorVariant='group'
112
+ prevSiblingId={prevCardId}
113
+ nextSiblingId={nextCardId}
114
+ >
115
+ <Card.StaticRoot>
116
+ <Card.Toolbar>
117
+ <StackItem.DragHandle asChild>
118
+ <Card.DragHandle toolbarItem />
119
+ </StackItem.DragHandle>
120
+ <Card.ToolbarSeparator variant='gap' />
121
+ <Card.ToolbarIconButton
122
+ iconOnly
123
+ variant='ghost'
124
+ icon='ph--x--regular'
125
+ label='Remove card'
126
+ onClick={() => handleRemoveCard(card.id)}
127
+ />
128
+ </Card.Toolbar>
129
+ <Card.Poster alt={card.title} image={card.image} />
130
+ <Card.Heading>{card.title}</Card.Heading>
131
+ <Card.Text classNames='line-clamp-2'>{card.description}</Card.Text>
132
+ </Card.StaticRoot>
133
+ <StackItem.DragPreview>
134
+ {({ item }) => (
135
+ <CardDragPreview.Root>
136
+ <CardDragPreview.Content>
137
+ <Card.Toolbar>
138
+ <Card.DragHandle toolbarItem />
139
+ </Card.Toolbar>
140
+ <Card.Poster alt={card.title} image={card.image} />
141
+ <Card.Heading>{card.title}</Card.Heading>
142
+ <Card.Text classNames='line-clamp-2'>{card.description}</Card.Text>
143
+ </CardDragPreview.Content>
144
+ </CardDragPreview.Root>
145
+ )}
146
+ </StackItem.DragPreview>
147
+ </StackItem.Root>
148
+ </CardStack.Item>
149
+ );
150
+ })}
151
+ </CardStack.Stack>
152
+
153
+ <CardStack.Footer>
154
+ <IconButton icon='ph--plus--regular' label='Add card' onClick={handleAddCard} classNames='is-full' />
155
+ </CardStack.Footer>
156
+
157
+ <CardStack.Heading>{faker.company.name()}</CardStack.Heading>
158
+ </CardStack.Content>
159
+ </CardStack.Root>
160
+ );
161
+ };
162
+
163
+ const meta: Meta<typeof CardStackStory> = {
164
+ title: 'ui/react-ui-stack/CardStack',
165
+ component: CardStackStory,
166
+ decorators: [withTheme, withLayout({ fullscreen: true })],
167
+ };
168
+
169
+ export default meta;
170
+
171
+ type Story = StoryObj<typeof CardStackStory>;
172
+
173
+ export const Default: Story = {};
@@ -8,7 +8,7 @@ import React, { type ComponentPropsWithoutRef, forwardRef } from 'react';
8
8
  import type { ThemedClassName } from '@dxos/react-ui';
9
9
  import { mx } from '@dxos/react-ui-theme';
10
10
 
11
- import { railGridHorizontalContainFitContent, Stack, type StackProps } from '../../components';
11
+ import { Stack, type StackProps, railGridHorizontalContainFitContent } from '../../components';
12
12
  import { Card } from '../Card';
13
13
 
14
14
  type SharedCardStackProps = ThemedClassName<ComponentPropsWithoutRef<'div'>> & { asChild?: boolean };
@@ -107,6 +107,22 @@ const CardStackRoot = forwardRef<HTMLDivElement, SharedCardStackProps>(
107
107
  },
108
108
  );
109
109
 
110
+ const cardStackItem = 'contain-layout pli-2 plb-1 first-of-type:pbs-0 last-of-type:pbe-0';
111
+
112
+ const CardStackItem = forwardRef<HTMLDivElement, SharedCardStackProps>(
113
+ ({ children, classNames, asChild, role = 'none', ...props }, forwardedRef) => {
114
+ const Root = asChild ? Slot : 'div';
115
+ const rootProps = asChild
116
+ ? { classNames: [cardStackItem, classNames] }
117
+ : { className: mx(cardStackItem, classNames), role };
118
+ return (
119
+ <Root {...props} {...rootProps} ref={forwardedRef}>
120
+ {children}
121
+ </Root>
122
+ );
123
+ },
124
+ );
125
+
110
126
  export const CardStack = {
111
127
  Root: CardStackRoot,
112
128
  Content: CardStackContent,
@@ -114,6 +130,7 @@ export const CardStack = {
114
130
  Heading: CardStackHeading,
115
131
  Footer: CardStackFooter,
116
132
  DragHandle: CardStackDragHandle,
133
+ Item: CardStackItem,
117
134
  };
118
135
 
119
- export { cardStackRoot, cardStackFooter, cardStackHeading, cardStackContent };
136
+ export { cardStackRoot, cardStackFooter, cardStackHeading, cardStackContent, cardStackItem };
@@ -8,7 +8,7 @@ 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
12
 
13
13
  /**
14
14
  * Hook to handle drag and drop functionality for Stack components.
@@ -66,7 +66,10 @@ export const useStackDropForElements = ({
66
66
  }
67
67
  },
68
68
  }),
69
- autoScrollForElements({ element: scrollElement as Element, getAllowedAxis: () => orientation }),
69
+ autoScrollForElements({
70
+ element: scrollElement as Element,
71
+ getAllowedAxis: () => orientation,
72
+ }),
70
73
  );
71
74
  }, [element, scrollElement, selfDroppable, orientation, id, onRearrange]);
72
75
 
package/src/index.ts CHANGED
@@ -2,9 +2,8 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export * from './components';
6
-
7
5
  // TODO(thure): Consider exporting exemplars from separate endpoints.
8
- export * from './exemplars';
9
6
 
10
- export { default as translations } from './translations';
7
+ export * from './components';
8
+ export * from './exemplars';
9
+ export * from './translations';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './stack-manager';
@@ -0,0 +1,17 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { defineConfig } from '@playwright/test';
6
+
7
+ import { e2ePreset } from '@dxos/test-utils/playwright';
8
+
9
+ export default defineConfig({
10
+ ...e2ePreset(import.meta.dirname),
11
+ // TODO(wittjosiah): Avoid hard-coding ports.
12
+ webServer: {
13
+ command: 'moon run storybook:serve-e2e -- --port=9003',
14
+ port: 9003,
15
+ reuseExistingServer: false,
16
+ },
17
+ });
@@ -6,12 +6,14 @@ import { expect, test } from '@playwright/test';
6
6
 
7
7
  import { setupPage, storybookUrl } from '@dxos/test-utils/playwright';
8
8
 
9
- import { StackManager } from '../testing';
9
+ import { StackManager } from './stack-manager';
10
+
11
+ const PORT = 9003;
10
12
 
11
13
  // TODO(wittjosiah): Update for new stack.
12
14
  test.describe.skip('Stack', () => {
13
15
  test('remove', async ({ browser }) => {
14
- const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer') });
16
+ const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer', PORT) });
15
17
  await page.getByTestId('stack-transfer').waitFor({ state: 'visible' });
16
18
 
17
19
  const stack = new StackManager(page.getByTestId('stack-1'));
@@ -24,7 +26,7 @@ test.describe.skip('Stack', () => {
24
26
  });
25
27
 
26
28
  test('rearrange', async ({ browser }) => {
27
- const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer') });
29
+ const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer', PORT) });
28
30
  await page.getByTestId('stack-transfer').waitFor({ state: 'visible' });
29
31
 
30
32
  const stack = new StackManager(page.getByTestId('stack-1'));
@@ -41,7 +43,7 @@ test.describe.skip('Stack', () => {
41
43
  test.skip();
42
44
  }
43
45
 
44
- const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer') });
46
+ const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--transfer', PORT) });
45
47
  await page.getByTestId('stack-transfer').waitFor({ state: 'visible' });
46
48
 
47
49
  const stack1 = new StackManager(page.getByTestId('stack-1'));
@@ -61,7 +63,7 @@ test.describe.skip('Stack', () => {
61
63
  });
62
64
 
63
65
  test('copy', async ({ browser }) => {
64
- const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--copy') });
66
+ const { page } = await setupPage(browser, { url: storybookUrl('ui-react-ui-stack-stack--copy', PORT) });
65
67
  await page.getByTestId('stack-copy').waitFor({ state: 'visible' });
66
68
 
67
69
  const stack1 = new StackManager(page.getByTestId('stack-1'));
@@ -0,0 +1,37 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren } from 'react';
6
+
7
+ import { ExtrinsicCardContainer, IntrinsicCardContainer, PopoverCardContainer } from '@dxos/storybook-utils';
8
+
9
+ import { Card } from '../exemplars';
10
+
11
+ export const CardContainer = ({
12
+ children,
13
+ icon = 'ph--placeholder--regular',
14
+ role,
15
+ }: PropsWithChildren<{ icon?: string; role?: string }>) => {
16
+ switch (role) {
17
+ case 'card--popover':
18
+ return <PopoverCardContainer icon={icon}>{children}</PopoverCardContainer>;
19
+
20
+ case 'card--extrinsic':
21
+ return (
22
+ <ExtrinsicCardContainer>
23
+ <Card.StaticRoot>{children}</Card.StaticRoot>
24
+ </ExtrinsicCardContainer>
25
+ );
26
+
27
+ case 'card--intrinsic':
28
+ return (
29
+ <IntrinsicCardContainer>
30
+ <Card.StaticRoot>{children}</Card.StaticRoot>
31
+ </IntrinsicCardContainer>
32
+ );
33
+
34
+ default:
35
+ return <Card.StaticRoot>{children}</Card.StaticRoot>;
36
+ }
37
+ };
@@ -2,4 +2,4 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './stack-manager';
5
+ export * from './CardContainer';
@@ -2,9 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export const translationKey = 'stack';
5
+ import { type Resource } from '@dxos/react-ui';
6
6
 
7
- export default [
7
+ export const translationKey = 'react-ui-stack';
8
+
9
+ export const translations = [
8
10
  {
9
11
  'en-US': {
10
12
  [translationKey]: {
@@ -19,4 +21,4 @@ export default [
19
21
  },
20
22
  },
21
23
  },
22
- ];
24
+ ] as const satisfies Resource[];