@dxos/react-ui-stack 0.7.5-labs.ea4b4c2 → 0.7.5-labs.f400bbc
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.
- package/dist/lib/browser/index.mjs +98 -127
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +144 -173
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +98 -127
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/MenuSignifier.d.ts +2 -3
- package/dist/types/src/components/MenuSignifier.d.ts.map +1 -1
- package/dist/types/src/components/Stack.d.ts +3 -1
- package/dist/types/src/components/Stack.d.ts.map +1 -1
- package/dist/types/src/components/Stack.stories.d.ts +1 -2
- package/dist/types/src/components/Stack.stories.d.ts.map +1 -1
- package/dist/types/src/components/StackContext.d.ts +5 -2
- package/dist/types/src/components/StackContext.d.ts.map +1 -1
- package/dist/types/src/components/StackItem.d.ts +7 -7
- package/dist/types/src/components/StackItem.d.ts.map +1 -1
- package/dist/types/src/components/StackItemContent.d.ts +1 -1
- package/dist/types/src/components/StackItemDragHandle.d.ts +2 -2
- package/dist/types/src/components/StackItemDragHandle.d.ts.map +1 -1
- package/dist/types/src/components/StackItemHeading.d.ts +1 -1
- package/dist/types/src/components/StackItemHeading.d.ts.map +1 -1
- package/dist/types/src/components/StackItemResizeHandle.d.ts +1 -2
- package/dist/types/src/components/StackItemResizeHandle.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useStackDropForElements.d.ts +15 -0
- package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -0
- package/package.json +21 -20
- package/src/components/Stack.stories.tsx +1 -1
- package/src/components/Stack.tsx +33 -61
- package/src/components/StackContext.tsx +6 -4
- package/src/components/StackItem.tsx +5 -5
- package/src/components/StackItemResizeHandle.tsx +10 -107
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useStackDropForElements.ts +73 -0
- package/dist/types/src/playwright/playwright.config.d.ts +0 -3
- package/dist/types/src/playwright/playwright.config.d.ts.map +0 -1
- /package/src/playwright/{playwright.config.ts → playwright.config.cts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackItemHeading.d.ts","sourceRoot":"","sources":["../../../../src/components/StackItemHeading.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAErG,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAgB,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAKzF,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC;AAErF,eAAO,MAAM,gBAAgB,uCAAwC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"StackItemHeading.d.ts","sourceRoot":"","sources":["../../../../src/components/StackItemHeading.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAErG,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAgB,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAKzF,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC;AAErF,eAAO,MAAM,gBAAgB,uCAAwC,qBAAqB,4CAkBzF,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,eAAe,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,GAAG,OAAO,CAAC;AAE/G,eAAO,MAAM,qBAAqB,oHAejC,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
export type StackItemResizeHandleProps = {};
|
|
3
|
-
export declare const StackItemResizeHandle: () =>
|
|
2
|
+
export declare const StackItemResizeHandle: () => import("react/jsx-runtime").JSX.Element;
|
|
4
3
|
//# sourceMappingURL=StackItemResizeHandle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackItemResizeHandle.d.ts","sourceRoot":"","sources":["../../../../src/components/StackItemResizeHandle.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StackItemResizeHandle.d.ts","sourceRoot":"","sources":["../../../../src/components/StackItemResizeHandle.tsx"],"names":[],"mappings":"AAcA,MAAM,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAE5C,eAAO,MAAM,qBAAqB,+CAajC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Orientation } from '../components/Stack';
|
|
2
|
+
import { type StackItemRearrangeHandler } from '../components/StackContext';
|
|
3
|
+
/**
|
|
4
|
+
* Hook to handle drag and drop functionality for Stack components.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useStackDropForElements: ({ element, selfDroppable, orientation, id, onRearrange, }: {
|
|
7
|
+
element: HTMLDivElement | null;
|
|
8
|
+
selfDroppable: boolean;
|
|
9
|
+
orientation: Orientation;
|
|
10
|
+
id?: string;
|
|
11
|
+
onRearrange?: StackItemRearrangeHandler;
|
|
12
|
+
}) => {
|
|
13
|
+
dropping: boolean;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=useStackDropForElements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStackDropForElements.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useStackDropForElements.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,KAAK,yBAAyB,EAAsB,MAAM,4BAA4B,CAAC;AAEhG;;GAEG;AACH,eAAO,MAAM,uBAAuB,8DAMjC;IACD,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,yBAAyB,CAAC;CACzC;;CA4CA,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-stack",
|
|
3
|
-
"version": "0.7.5-labs.
|
|
3
|
+
"version": "0.7.5-labs.f400bbc",
|
|
4
4
|
"description": "A stack component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"author": "DXOS.org",
|
|
9
9
|
"sideEffects": true,
|
|
10
|
+
"type": "module",
|
|
10
11
|
"exports": {
|
|
11
12
|
".": {
|
|
12
13
|
"types": "./dist/types/src/index.d.ts",
|
|
@@ -47,12 +48,12 @@
|
|
|
47
48
|
"@radix-ui/react-slot": "1.1.2",
|
|
48
49
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
49
50
|
"react-resize-detector": "^11.0.1",
|
|
50
|
-
"@dxos/echo-schema": "0.7.5-labs.
|
|
51
|
-
"@dxos/keyboard": "0.7.5-labs.
|
|
52
|
-
"@dxos/live-object": "0.7.5-labs.
|
|
53
|
-
"@dxos/react-ui-attention": "0.7.5-labs.
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
51
|
+
"@dxos/echo-schema": "0.7.5-labs.f400bbc",
|
|
52
|
+
"@dxos/keyboard": "0.7.5-labs.f400bbc",
|
|
53
|
+
"@dxos/live-object": "0.7.5-labs.f400bbc",
|
|
54
|
+
"@dxos/react-ui-attention": "0.7.5-labs.f400bbc",
|
|
55
|
+
"@dxos/react-ui-dnd": "0.7.5-labs.f400bbc",
|
|
56
|
+
"@dxos/util": "0.7.5-labs.f400bbc"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -61,24 +62,24 @@
|
|
|
61
62
|
"react": "~18.2.0",
|
|
62
63
|
"react-dom": "~18.2.0",
|
|
63
64
|
"vite": "5.4.7",
|
|
64
|
-
"@dxos/app-graph": "0.7.5-labs.
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/react-ui": "0.7.5-labs.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
65
|
+
"@dxos/app-graph": "0.7.5-labs.f400bbc",
|
|
66
|
+
"@dxos/echo-schema": "0.7.5-labs.f400bbc",
|
|
67
|
+
"@dxos/client": "0.7.5-labs.f400bbc",
|
|
68
|
+
"@dxos/react-ui": "0.7.5-labs.f400bbc",
|
|
69
|
+
"@dxos/random": "0.7.5-labs.f400bbc",
|
|
70
|
+
"@dxos/react-ui-editor": "0.7.5-labs.f400bbc",
|
|
71
|
+
"@dxos/react-ui-theme": "0.7.5-labs.f400bbc",
|
|
72
|
+
"@dxos/storybook-utils": "0.7.5-labs.f400bbc",
|
|
73
|
+
"@dxos/test-utils": "0.7.5-labs.f400bbc"
|
|
73
74
|
},
|
|
74
75
|
"peerDependencies": {
|
|
75
76
|
"@phosphor-icons/react": "^2.1.5",
|
|
76
77
|
"react": "~18.2.0",
|
|
77
78
|
"react-dom": "~18.2.0",
|
|
78
|
-
"@dxos/client": "0.7.5-labs.
|
|
79
|
-
"@dxos/random": "0.7.5-labs.
|
|
80
|
-
"@dxos/react-ui": "0.7.5-labs.
|
|
81
|
-
"@dxos/react-ui-theme": "0.7.5-labs.
|
|
79
|
+
"@dxos/client": "0.7.5-labs.f400bbc",
|
|
80
|
+
"@dxos/random": "0.7.5-labs.f400bbc",
|
|
81
|
+
"@dxos/react-ui": "0.7.5-labs.f400bbc",
|
|
82
|
+
"@dxos/react-ui-theme": "0.7.5-labs.f400bbc"
|
|
82
83
|
},
|
|
83
84
|
"publishConfig": {
|
|
84
85
|
"access": "public"
|
|
@@ -126,7 +126,7 @@ export const Default: Story = {
|
|
|
126
126
|
};
|
|
127
127
|
|
|
128
128
|
const meta: Meta<typeof StorybookStack> = {
|
|
129
|
-
title: 'ui/react-ui-stack
|
|
129
|
+
title: 'ui/react-ui-stack/Stack',
|
|
130
130
|
component: StorybookStack,
|
|
131
131
|
decorators: [withTheme],
|
|
132
132
|
argTypes: { orientation: { control: 'radio', options: ['horizontal', 'vertical'] } },
|
package/src/components/Stack.tsx
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
|
-
|
|
5
|
-
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
6
|
-
import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
|
|
7
|
-
import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
4
|
+
|
|
8
5
|
import { useArrowNavigationGroup } from '@fluentui/react-tabster';
|
|
9
6
|
import { composeRefs } from '@radix-ui/react-compose-refs';
|
|
10
|
-
import React, {
|
|
11
|
-
Children,
|
|
12
|
-
type CSSProperties,
|
|
13
|
-
type ComponentPropsWithRef,
|
|
14
|
-
forwardRef,
|
|
15
|
-
useLayoutEffect,
|
|
16
|
-
useState,
|
|
17
|
-
} from 'react';
|
|
7
|
+
import React, { Children, type CSSProperties, type ComponentPropsWithRef, forwardRef, useState, useMemo } from 'react';
|
|
18
8
|
|
|
19
9
|
import { type ThemedClassName, ListItem } from '@dxos/react-ui';
|
|
20
10
|
import { mx } from '@dxos/react-ui-theme';
|
|
21
11
|
|
|
22
|
-
import { type StackContextValue, StackContext
|
|
12
|
+
import { type StackContextValue, StackContext } from './StackContext';
|
|
13
|
+
import { useStackDropForElements } from '../hooks';
|
|
23
14
|
|
|
24
15
|
export type Orientation = 'horizontal' | 'vertical';
|
|
25
|
-
export type Size = 'intrinsic' | 'contain';
|
|
16
|
+
export type Size = 'intrinsic' | 'contain' | 'contain-fit-content';
|
|
26
17
|
|
|
27
18
|
export type StackProps = Omit<ThemedClassName<ComponentPropsWithRef<'div'>>, 'aria-orientation'> &
|
|
28
19
|
Partial<StackContextValue> & { itemsCount?: number };
|
|
29
20
|
|
|
30
21
|
export const railGridHorizontal = 'grid-rows-[[rail-start]_var(--rail-size)_[content-start]_1fr_[content-end]]';
|
|
31
|
-
|
|
32
22
|
export const railGridVertical = 'grid-cols-[[rail-start]_var(--rail-size)_[content-start]_1fr_[content-end]]';
|
|
33
23
|
|
|
24
|
+
// TODO(ZaymonFC): Magic 2px to stop overflow (tabster dummies... ask @thure).
|
|
25
|
+
export const railGridHorizontalContainFitContent =
|
|
26
|
+
'grid-rows-[[rail-start]_var(--rail-size)_[content-start]_fit-content(calc(100%-var(--rail-size)*2+2px))_[content-end]]';
|
|
27
|
+
export const railGridVerticalContainFitContent =
|
|
28
|
+
'grid-cols-[[rail-start]_var(--rail-size)_[content-start]_fit-content(calc(100%-var(--rail-size)*2+2px))_[content-end]]';
|
|
29
|
+
|
|
34
30
|
export const autoScrollRootAttributes = { 'data-drag-autoscroll': 'idle' };
|
|
35
31
|
|
|
36
32
|
export const Stack = forwardRef<HTMLDivElement, StackProps>(
|
|
@@ -50,52 +46,34 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
|
|
|
50
46
|
) => {
|
|
51
47
|
const [stackElement, stackRef] = useState<HTMLDivElement | null>(null);
|
|
52
48
|
const composedItemRef = composeRefs<HTMLDivElement>(stackRef, forwardedRef);
|
|
53
|
-
const [dropping, setDropping] = useState(false);
|
|
54
|
-
|
|
55
49
|
const arrowNavigationGroup = useArrowNavigationGroup({ axis: orientation });
|
|
56
50
|
|
|
57
51
|
const styles: CSSProperties = {
|
|
58
|
-
[orientation === 'horizontal' ? 'gridTemplateColumns' : 'gridTemplateRows']:
|
|
52
|
+
[orientation === 'horizontal' ? 'gridTemplateColumns' : 'gridTemplateRows']:
|
|
53
|
+
`repeat(${itemsCount}, min-content) [tabster-dummies] 0`,
|
|
59
54
|
...style,
|
|
60
55
|
};
|
|
61
56
|
|
|
62
57
|
const selfDroppable = !!(itemsCount < 1 && onRearrange && props.id);
|
|
63
58
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
const { dropping } = useStackDropForElements({
|
|
60
|
+
id: props.id,
|
|
61
|
+
element: stackElement,
|
|
62
|
+
selfDroppable,
|
|
63
|
+
orientation,
|
|
64
|
+
onRearrange,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const gridClasses = useMemo(() => {
|
|
68
|
+
if (!rail) {
|
|
69
|
+
return orientation === 'horizontal' ? 'grid-rows-1 pli-1' : 'grid-cols-1 plb-1';
|
|
70
|
+
}
|
|
71
|
+
if (orientation === 'horizontal') {
|
|
72
|
+
return size === 'contain-fit-content' ? railGridHorizontalContainFitContent : railGridHorizontal;
|
|
73
|
+
} else {
|
|
74
|
+
return size === 'contain-fit-content' ? railGridVerticalContainFitContent : railGridVertical;
|
|
67
75
|
}
|
|
68
|
-
|
|
69
|
-
return combine(
|
|
70
|
-
dropTargetForElements({
|
|
71
|
-
element: stackElement,
|
|
72
|
-
getData: ({ input, element }) => {
|
|
73
|
-
return attachClosestEdge(
|
|
74
|
-
{ id: props.id, type: orientation === 'horizontal' ? 'card' : 'column' },
|
|
75
|
-
{ input, element, allowedEdges: [orientation === 'horizontal' ? 'left' : 'top'] },
|
|
76
|
-
);
|
|
77
|
-
},
|
|
78
|
-
onDragEnter: ({ source }) => {
|
|
79
|
-
if (source.data.type === acceptSourceType) {
|
|
80
|
-
setDropping(true);
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
onDrag: ({ source }) => {
|
|
84
|
-
if (source.data.type === acceptSourceType) {
|
|
85
|
-
setDropping(true);
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
onDragLeave: () => setDropping(false),
|
|
89
|
-
onDrop: ({ self, source }) => {
|
|
90
|
-
setDropping(false);
|
|
91
|
-
if (source.data.type === acceptSourceType && selfDroppable) {
|
|
92
|
-
onRearrange(source.data as StackItemData, self.data as StackItemData, extractClosestEdge(self.data));
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
}),
|
|
96
|
-
autoScrollForElements({ element: stackElement, getAllowedAxis: () => orientation }),
|
|
97
|
-
);
|
|
98
|
-
}, [stackElement, selfDroppable, orientation]);
|
|
76
|
+
}, [rail, orientation, size]);
|
|
99
77
|
|
|
100
78
|
return (
|
|
101
79
|
<StackContext.Provider value={{ orientation, rail, size, onRearrange }}>
|
|
@@ -104,14 +82,8 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(
|
|
|
104
82
|
{...arrowNavigationGroup}
|
|
105
83
|
className={mx(
|
|
106
84
|
'grid relative',
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
? railGridHorizontal
|
|
110
|
-
: railGridVertical
|
|
111
|
-
: orientation === 'horizontal'
|
|
112
|
-
? 'grid-rows-1 pli-1'
|
|
113
|
-
: 'grid-cols-1 plb-1',
|
|
114
|
-
size === 'contain' &&
|
|
85
|
+
gridClasses,
|
|
86
|
+
(size === 'contain' || size === 'contain-fit-content') &&
|
|
115
87
|
(orientation === 'horizontal'
|
|
116
88
|
? 'overflow-x-auto min-bs-0 bs-full max-bs-full'
|
|
117
89
|
: 'overflow-y-auto min-is-0 is-full max-is-full'),
|
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
6
6
|
import { createContext, useContext } from 'react';
|
|
7
7
|
|
|
8
|
+
import { type Size as DndSize } from '@dxos/react-ui-dnd';
|
|
9
|
+
|
|
8
10
|
import { type Orientation, type Size } from './Stack';
|
|
9
11
|
|
|
10
|
-
export type StackItemSize =
|
|
12
|
+
export type StackItemSize = DndSize;
|
|
11
13
|
|
|
12
14
|
export type StackItemData = { id: string; type: 'column' | 'card' };
|
|
13
15
|
|
|
14
|
-
export type StackItemRearrangeHandler = (
|
|
15
|
-
source:
|
|
16
|
-
target:
|
|
16
|
+
export type StackItemRearrangeHandler<Data extends { id: string } = StackItemData> = (
|
|
17
|
+
source: Data,
|
|
18
|
+
target: Data,
|
|
17
19
|
closestEdge: Edge | null,
|
|
18
20
|
) => void;
|
|
19
21
|
|
|
@@ -16,6 +16,7 @@ import { composeRefs } from '@radix-ui/react-compose-refs';
|
|
|
16
16
|
import React, { forwardRef, useLayoutEffect, useState, type ComponentPropsWithRef, useCallback } from 'react';
|
|
17
17
|
|
|
18
18
|
import { type ThemedClassName, ListItem } from '@dxos/react-ui';
|
|
19
|
+
import { resizeAttributes, sizeStyle } from '@dxos/react-ui-dnd';
|
|
19
20
|
import { mx } from '@dxos/react-ui-theme';
|
|
20
21
|
|
|
21
22
|
import { useStack, StackItemContext, type StackItemSize, type StackItemData } from './StackContext';
|
|
@@ -36,7 +37,8 @@ import {
|
|
|
36
37
|
StackItemSigilButton,
|
|
37
38
|
} from './StackItemSigil';
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
// NOTE: 48rem fills the screen on a MacbookPro with the sidebars closed.
|
|
41
|
+
export const DEFAULT_HORIZONTAL_SIZE = 48 satisfies StackItemSize;
|
|
40
42
|
export const DEFAULT_VERTICAL_SIZE = 'min-content' satisfies StackItemSize;
|
|
41
43
|
export const DEFAULT_EXTRINSIC_SIZE = DEFAULT_HORIZONTAL_SIZE satisfies StackItemSize;
|
|
42
44
|
|
|
@@ -159,16 +161,14 @@ const StackItemRoot = forwardRef<HTMLDivElement, StackItemRootProps>(
|
|
|
159
161
|
: orientation === 'horizontal'
|
|
160
162
|
? 'dx-focus-ring-group-x'
|
|
161
163
|
: 'dx-focus-ring-group-y',
|
|
162
|
-
size === 'min-content' && (orientation === 'horizontal' ? 'is-min' : 'bs-min'),
|
|
163
164
|
orientation === 'horizontal' ? 'grid-rows-subgrid' : 'grid-cols-subgrid',
|
|
164
165
|
rail && (orientation === 'horizontal' ? 'row-span-2' : 'col-span-2'),
|
|
165
166
|
classNames,
|
|
166
167
|
)}
|
|
167
168
|
data-dx-stack-item
|
|
169
|
+
{...resizeAttributes}
|
|
168
170
|
style={{
|
|
169
|
-
...(size
|
|
170
|
-
[orientation === 'horizontal' ? 'inlineSize' : 'blockSize']: `${size}rem`,
|
|
171
|
-
}),
|
|
171
|
+
...sizeStyle(size, orientation),
|
|
172
172
|
...(Number.isFinite(order) && {
|
|
173
173
|
[orientation === 'horizontal' ? 'gridColumn' : 'gridRow']: `${order}`,
|
|
174
174
|
}),
|
|
@@ -2,126 +2,29 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';
|
|
7
|
-
import { preventUnhandled } from '@atlaskit/pragmatic-drag-and-drop/prevent-unhandled';
|
|
8
|
-
import { type DragLocationHistory } from '@atlaskit/pragmatic-drag-and-drop/types';
|
|
9
|
-
import React, { useLayoutEffect, useRef } from 'react';
|
|
5
|
+
import React from 'react';
|
|
10
6
|
|
|
11
|
-
import {
|
|
7
|
+
import { ResizeHandle } from '@dxos/react-ui-dnd';
|
|
12
8
|
|
|
13
|
-
import { useStack, useStackItem
|
|
9
|
+
import { useStack, useStackItem } from './StackContext';
|
|
14
10
|
import { DEFAULT_EXTRINSIC_SIZE } from './StackItem';
|
|
15
11
|
|
|
16
|
-
const REM = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
17
|
-
|
|
18
12
|
const MIN_WIDTH = 20;
|
|
19
13
|
const MIN_HEIGHT = 3;
|
|
20
14
|
|
|
21
|
-
const measureStackItem = (element: HTMLButtonElement): { width: number; height: number } => {
|
|
22
|
-
const stackItemElement = element.closest('[data-dx-stack-item]');
|
|
23
|
-
return stackItemElement?.getBoundingClientRect() ?? { width: DEFAULT_EXTRINSIC_SIZE, height: DEFAULT_EXTRINSIC_SIZE };
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const getNextSize = (startSize: number, location: DragLocationHistory, client: 'clientX' | 'clientY') => {
|
|
27
|
-
return Math.max(
|
|
28
|
-
client === 'clientX' ? MIN_WIDTH : MIN_HEIGHT,
|
|
29
|
-
startSize + (location.current.input[client] - location.initial.input[client]) / REM,
|
|
30
|
-
);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
15
|
export type StackItemResizeHandleProps = {};
|
|
34
16
|
|
|
35
17
|
export const StackItemResizeHandle = () => {
|
|
36
18
|
const { orientation } = useStack();
|
|
37
19
|
const { setSize, size } = useStackItem();
|
|
38
|
-
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
39
|
-
const dragStartSize = useRef<StackItemSize>(size);
|
|
40
|
-
const client = orientation === 'horizontal' ? 'clientX' : 'clientY';
|
|
41
|
-
|
|
42
|
-
useLayoutEffect(
|
|
43
|
-
() => {
|
|
44
|
-
if (!buttonRef.current || buttonRef.current.hasAttribute('draggable')) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// TODO(thure): This should handle StackItem state vs local state better.
|
|
48
|
-
draggable({
|
|
49
|
-
element: buttonRef.current,
|
|
50
|
-
onGenerateDragPreview: ({ nativeSetDragImage }) => {
|
|
51
|
-
// We will be moving the line to indicate a drag; we can disable the native drag preview.
|
|
52
|
-
disableNativeDragPreview({ nativeSetDragImage });
|
|
53
|
-
// We don't want any native drop animation for when the user does not drop on a drop target.
|
|
54
|
-
// We want the drag to finish immediately.
|
|
55
|
-
preventUnhandled.start();
|
|
56
|
-
},
|
|
57
|
-
onDragStart: () => {
|
|
58
|
-
dragStartSize.current =
|
|
59
|
-
dragStartSize.current === 'min-content'
|
|
60
|
-
? measureStackItem(buttonRef.current!)[orientation === 'horizontal' ? 'width' : 'height'] / REM
|
|
61
|
-
: dragStartSize.current;
|
|
62
|
-
},
|
|
63
|
-
onDrag: ({ location }) => {
|
|
64
|
-
if (typeof dragStartSize.current !== 'number') {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
setSize(getNextSize(dragStartSize.current, location, client));
|
|
68
|
-
},
|
|
69
|
-
onDrop: ({ location }) => {
|
|
70
|
-
if (typeof dragStartSize.current !== 'number') {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const nextSize = getNextSize(dragStartSize.current, location, client);
|
|
74
|
-
setSize(nextSize, true);
|
|
75
|
-
dragStartSize.current = nextSize;
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
},
|
|
79
|
-
[
|
|
80
|
-
// Note that `size` should not be a dependency here since dragging this adjusts the size.
|
|
81
|
-
],
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<button
|
|
86
|
-
ref={buttonRef}
|
|
87
|
-
className={mx(
|
|
88
|
-
'group absolute',
|
|
89
|
-
orientation === 'horizontal'
|
|
90
|
-
? 'cursor-col-resize is-3 bs-full inline-end-[-1px] !border-lb-0 before:inset-block-0 before:inline-end-0 before:is-1'
|
|
91
|
-
: 'cursor-row-resize bs-3 is-full block-end-[-1px] !border-li-0 before:inset-inline-0 before:block-end-0 before:bs-1',
|
|
92
|
-
'before:transition-opacity before:duration-100 before:ease-in-out before:opacity-0 hover:before:opacity-100 focus-visible:before:opacity-100 active:before:opacity-100',
|
|
93
|
-
'before:absolute before:block before:bg-accentFocusIndicator',
|
|
94
|
-
)}
|
|
95
|
-
>
|
|
96
|
-
<div
|
|
97
|
-
role='none'
|
|
98
|
-
className={mx(
|
|
99
|
-
'absolute flex items-center group-hover:opacity-0 group-focus-visible:opacity-0 group-active:opacity-0',
|
|
100
|
-
orientation === 'horizontal'
|
|
101
|
-
? 'block-start-0 inline-end-px bs-[--rail-size]'
|
|
102
|
-
: 'inline-start-0 block-end-px is-[--rail-size] flex justify-center',
|
|
103
|
-
)}
|
|
104
|
-
>
|
|
105
|
-
<DragHandleSignifier orientation={orientation} />
|
|
106
|
-
</div>
|
|
107
|
-
</button>
|
|
108
|
-
);
|
|
109
|
-
};
|
|
110
20
|
|
|
111
|
-
const DragHandleSignifier = ({ orientation }: { orientation: 'horizontal' | 'vertical' }) => {
|
|
112
21
|
return (
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<path d='M256,232c-8.8,0-16-7.2-16-16v-56c0-8.8,7.2-16,16-16v88Z' /> */}
|
|
121
|
-
<path d='M256,64c-8.8,0-16-7.2-16-16s7.2-16,16-16v32Z' />
|
|
122
|
-
<path d='M256,120c-8.8,0-16-7.2-16-16s7.2-16,16-16v32Z' />
|
|
123
|
-
<path d='M256,176c-8.8,0-16-7.2-16-16s7.2-16,16-16v32Z' />
|
|
124
|
-
<path d='M256,232c-8.8,0-16-7.2-16-16s7.2-16,16-16v32Z' />
|
|
125
|
-
</svg>
|
|
22
|
+
<ResizeHandle
|
|
23
|
+
side={orientation === 'horizontal' ? 'inline-end' : 'block-end'}
|
|
24
|
+
fallbackSize={DEFAULT_EXTRINSIC_SIZE}
|
|
25
|
+
minSize={orientation === 'horizontal' ? MIN_WIDTH : MIN_HEIGHT}
|
|
26
|
+
size={size}
|
|
27
|
+
onSizeChange={setSize}
|
|
28
|
+
/>
|
|
126
29
|
);
|
|
127
30
|
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
6
|
+
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
7
|
+
import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
|
|
8
|
+
import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
9
|
+
import { useLayoutEffect, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import { type Orientation } from '../components/Stack';
|
|
12
|
+
import { type StackItemRearrangeHandler, type StackItemData } from '../components/StackContext';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Hook to handle drag and drop functionality for Stack components.
|
|
16
|
+
*/
|
|
17
|
+
export const useStackDropForElements = ({
|
|
18
|
+
element,
|
|
19
|
+
selfDroppable,
|
|
20
|
+
orientation,
|
|
21
|
+
id,
|
|
22
|
+
onRearrange,
|
|
23
|
+
}: {
|
|
24
|
+
element: HTMLDivElement | null;
|
|
25
|
+
selfDroppable: boolean;
|
|
26
|
+
orientation: Orientation;
|
|
27
|
+
id?: string;
|
|
28
|
+
onRearrange?: StackItemRearrangeHandler;
|
|
29
|
+
}) => {
|
|
30
|
+
const [dropping, setDropping] = useState(false);
|
|
31
|
+
|
|
32
|
+
useLayoutEffect(() => {
|
|
33
|
+
if (!element || !selfDroppable) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const acceptSourceType = orientation === 'horizontal' ? 'column' : 'card';
|
|
38
|
+
|
|
39
|
+
return combine(
|
|
40
|
+
dropTargetForElements({
|
|
41
|
+
element,
|
|
42
|
+
getData: ({ input, element }) => {
|
|
43
|
+
return attachClosestEdge(
|
|
44
|
+
{ id, type: orientation === 'horizontal' ? 'card' : 'column' },
|
|
45
|
+
{ input, element, allowedEdges: [orientation === 'horizontal' ? 'left' : 'top'] },
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
|
+
onDragEnter: ({ source }) => {
|
|
49
|
+
if (source.data.type === acceptSourceType) {
|
|
50
|
+
setDropping(true);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
onDrag: ({ source }) => {
|
|
54
|
+
if (source.data.type === acceptSourceType) {
|
|
55
|
+
setDropping(true);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
onDragLeave: () => {
|
|
59
|
+
return setDropping(false);
|
|
60
|
+
},
|
|
61
|
+
onDrop: ({ self, source }) => {
|
|
62
|
+
setDropping(false);
|
|
63
|
+
if (source.data.type === acceptSourceType && selfDroppable && onRearrange) {
|
|
64
|
+
onRearrange(source.data as StackItemData, self.data as StackItemData, extractClosestEdge(self.data));
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
autoScrollForElements({ element, getAllowedAxis: () => orientation }),
|
|
69
|
+
);
|
|
70
|
+
}, [element, selfDroppable, orientation, id, onRearrange]);
|
|
71
|
+
|
|
72
|
+
return { dropping };
|
|
73
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"playwright.config.d.ts","sourceRoot":"","sources":["../../../../src/playwright/playwright.config.ts"],"names":[],"mappings":";AASA,wBAQG"}
|
|
File without changes
|