@dxos/react-ui-list 0.7.4 → 0.7.5-labs.071a3e2

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 (37) hide show
  1. package/dist/lib/browser/index.mjs +147 -217
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +156 -222
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +147 -217
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/List/List.d.ts +1 -1
  11. package/dist/types/src/components/List/List.d.ts.map +1 -1
  12. package/dist/types/src/components/List/ListItem.d.ts +6 -9
  13. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  14. package/dist/types/src/components/List/ListRoot.d.ts +3 -6
  15. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  16. package/dist/types/src/components/Tree/Tree.d.ts +4 -2
  17. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  18. package/dist/types/src/components/Tree/TreeItem.d.ts +3 -1
  19. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  20. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  21. package/dist/types/src/components/Tree/TreeItemToggle.d.ts +1 -0
  22. package/dist/types/src/components/Tree/TreeItemToggle.d.ts.map +1 -1
  23. package/dist/types/src/components/Tree/helpers.d.ts +1 -1
  24. package/dist/types/tsconfig.tsbuildinfo +1 -0
  25. package/package.json +20 -20
  26. package/src/components/List/ListItem.tsx +15 -7
  27. package/src/components/Tree/Tree.tsx +9 -5
  28. package/src/components/Tree/TreeItem.tsx +23 -21
  29. package/src/components/Tree/TreeItemHeading.tsx +2 -3
  30. package/src/components/Tree/TreeItemToggle.tsx +3 -2
  31. package/src/components/Tree/helpers.ts +1 -1
  32. package/dist/types/src/components/List/DropIndicator.d.ts +0 -11
  33. package/dist/types/src/components/List/DropIndicator.d.ts.map +0 -1
  34. package/dist/types/src/components/Tree/DropIndicator.d.ts +0 -8
  35. package/dist/types/src/components/Tree/DropIndicator.d.ts.map +0 -1
  36. package/src/components/List/DropIndicator.tsx +0 -69
  37. package/src/components/Tree/DropIndicator.tsx +0 -78
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-list",
3
- "version": "0.7.4",
3
+ "version": "0.7.5-labs.071a3e2",
4
4
  "description": "A list component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -25,38 +25,38 @@
25
25
  "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
26
26
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
27
27
  "@preact/signals-core": "^1.6.0",
28
- "@radix-ui/react-context": "^1.0.0",
29
- "effect": "^3.9.2",
30
- "@dxos/debug": "0.7.4",
31
- "@dxos/echo-schema": "0.7.4",
32
- "@dxos/invariant": "0.7.4",
33
- "@dxos/live-object": "0.7.4",
34
- "@dxos/react-ui-attention": "0.7.4",
35
- "@dxos/log": "0.7.4",
36
- "@dxos/react-ui-mosaic": "0.7.4",
37
- "@dxos/react-ui-text-tooltip": "0.7.4",
38
- "@dxos/react-ui-types": "0.7.4",
39
- "@dxos/util": "0.7.4"
28
+ "@radix-ui/react-context": "1.1.1",
29
+ "@dxos/debug": "0.7.5-labs.071a3e2",
30
+ "@dxos/live-object": "0.7.5-labs.071a3e2",
31
+ "@dxos/echo-schema": "0.7.5-labs.071a3e2",
32
+ "@dxos/invariant": "0.7.5-labs.071a3e2",
33
+ "@dxos/react-ui-attention": "0.7.5-labs.071a3e2",
34
+ "@dxos/log": "0.7.5-labs.071a3e2",
35
+ "@dxos/react-ui-mosaic": "0.7.5-labs.071a3e2",
36
+ "@dxos/react-ui-text-tooltip": "0.7.5-labs.071a3e2",
37
+ "@dxos/react-ui-types": "0.7.5-labs.071a3e2",
38
+ "@dxos/util": "0.7.5-labs.071a3e2"
40
39
  },
41
40
  "devDependencies": {
42
41
  "@phosphor-icons/react": "^2.1.5",
43
42
  "@types/react": "~18.2.0",
44
43
  "@types/react-dom": "~18.2.0",
44
+ "effect": "^3.12.3",
45
45
  "react": "~18.2.0",
46
46
  "react-dom": "~18.2.0",
47
47
  "vite": "5.4.7",
48
- "@dxos/random": "0.7.4",
49
- "@dxos/react-ui": "0.7.4",
50
- "@dxos/storybook-utils": "0.7.4",
51
- "@dxos/react-ui-theme": "0.7.4"
48
+ "@dxos/random": "0.7.5-labs.071a3e2",
49
+ "@dxos/react-ui-theme": "0.7.5-labs.071a3e2",
50
+ "@dxos/react-ui": "0.7.5-labs.071a3e2",
51
+ "@dxos/storybook-utils": "0.7.5-labs.071a3e2"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@phosphor-icons/react": "^2.1.5",
55
- "effect": "^3.9.2",
55
+ "effect": "^3.12.3",
56
56
  "react": "~18.2.0",
57
57
  "react-dom": "~18.2.0",
58
- "@dxos/react-ui": "0.7.4",
59
- "@dxos/react-ui-theme": "0.7.4"
58
+ "@dxos/react-ui": "0.7.5-labs.071a3e2",
59
+ "@dxos/react-ui-theme": "0.7.5-labs.071a3e2"
60
60
  },
61
61
  "publishConfig": {
62
62
  "access": "public"
@@ -25,10 +25,9 @@ import React, {
25
25
  import { createPortal } from 'react-dom';
26
26
 
27
27
  import { invariant } from '@dxos/invariant';
28
- import { Icon, type ThemedClassName } from '@dxos/react-ui';
28
+ import { Icon, type ThemedClassName, ListItem as NaturalListItem } from '@dxos/react-ui';
29
29
  import { mx } from '@dxos/react-ui-theme';
30
30
 
31
- import { DropIndicator } from './DropIndicator';
32
31
  import { useListContext } from './ListRoot';
33
32
 
34
33
  export type ListItemRecord = {};
@@ -75,13 +74,14 @@ export const [ListItemProvider, useListItemContext] = createContext<ListItemCont
75
74
  export type ListItemProps<T extends ListItemRecord> = ThemedClassName<
76
75
  PropsWithChildren<{
77
76
  item: T;
78
- }>
77
+ }> &
78
+ HTMLAttributes<HTMLDivElement>
79
79
  >;
80
80
 
81
81
  /**
82
82
  * Draggable list item.
83
83
  */
84
- export const ListItem = <T extends ListItemRecord>({ children, classNames, item }: ListItemProps<T>) => {
84
+ export const ListItem = <T extends ListItemRecord>({ children, classNames, item, ...props }: ListItemProps<T>) => {
85
85
  const { isItem, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
86
86
  const ref = useRef<HTMLDivElement | null>(null);
87
87
  const dragHandleRef = useRef<HTMLElement | null>(null);
@@ -113,6 +113,7 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item
113
113
  container.style.width = rect.width + 'px';
114
114
  setState({ type: 'preview', container });
115
115
  setRootState({ type: 'preview', container, item });
116
+ return () => {}; // TODO(burdon): Cleanup.
116
117
  },
117
118
  });
118
119
  }
@@ -164,11 +165,18 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item
164
165
 
165
166
  return (
166
167
  <ListItemProvider item={item} dragHandleRef={dragHandleRef}>
167
- <div className='relative'>
168
- <div ref={ref} role='listitem' className={mx('flex overflow-hidden', classNames, stateStyles[state.type])}>
168
+ <div role='none' className='relative'>
169
+ <div
170
+ ref={ref}
171
+ role='listitem'
172
+ className={mx('flex overflow-hidden', classNames, stateStyles[state.type])}
173
+ {...props}
174
+ >
169
175
  {children}
170
176
  </div>
171
- {state.type === 'is-dragging-over' && state.closestEdge && <DropIndicator edge={state.closestEdge} />}
177
+ {state.type === 'is-dragging-over' && state.closestEdge && (
178
+ <NaturalListItem.DropIndicator edge={state.closestEdge} />
179
+ )}
172
180
  </div>
173
181
  </ListItemProvider>
174
182
  );
@@ -9,11 +9,13 @@ import { Treegrid, type TreegridRootProps } from '@dxos/react-ui';
9
9
  import { type TreeContextType, TreeProvider } from './TreeContext';
10
10
  import { TreeItem, type TreeItemProps } from './TreeItem';
11
11
 
12
- export type TreeProps<T = any> = { id: string } & TreeContextType &
12
+ export type TreeProps<T = any> = { root?: T; path?: string[]; id: string } & TreeContextType &
13
13
  Partial<Pick<TreegridRootProps, 'gridTemplateColumns' | 'classNames'>> &
14
- Pick<TreeItemProps<T>, 'draggable' | 'renderColumns' | 'canDrop' | 'onOpenChange' | 'onSelect'>;
14
+ Pick<TreeItemProps<T>, 'draggable' | 'renderColumns' | 'canDrop' | 'onOpenChange' | 'onSelect' | 'levelOffset'>;
15
15
 
16
16
  export const Tree = <T = any,>({
17
+ root,
18
+ path,
17
19
  id,
18
20
  getItems,
19
21
  getProps,
@@ -26,6 +28,7 @@ export const Tree = <T = any,>({
26
28
  canDrop,
27
29
  onOpenChange,
28
30
  onSelect,
31
+ levelOffset,
29
32
  }: TreeProps<T>) => {
30
33
  const context = useMemo(
31
34
  () => ({
@@ -36,8 +39,8 @@ export const Tree = <T = any,>({
36
39
  }),
37
40
  [getItems, getProps, isOpen, isCurrent],
38
41
  );
39
- const items = getItems();
40
- const path = useMemo(() => [id], [id]);
42
+ const items = getItems(root);
43
+ const treePath = useMemo(() => (path ? [...path, id] : [id]), [id, path]);
41
44
 
42
45
  return (
43
46
  <Treegrid.Root gridTemplateColumns={gridTemplateColumns} classNames={classNames}>
@@ -47,7 +50,8 @@ export const Tree = <T = any,>({
47
50
  key={item.id}
48
51
  item={item}
49
52
  last={index === items.length - 1}
50
- path={path}
53
+ path={treePath}
54
+ levelOffset={levelOffset}
51
55
  draggable={draggable}
52
56
  renderColumns={renderColumns}
53
57
  canDrop={canDrop}
@@ -3,11 +3,7 @@
3
3
  //
4
4
 
5
5
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import {
7
- draggable as pragmaticDraggable,
8
- dropTargetForElements,
9
- } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
10
- // https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx
6
+ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
11
7
  import {
12
8
  attachInstruction,
13
9
  extractInstruction,
@@ -18,9 +14,8 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState, type FC
18
14
 
19
15
  import { S } from '@dxos/echo-schema';
20
16
  import { invariant } from '@dxos/invariant';
21
- import { Treegrid } from '@dxos/react-ui';
17
+ import { Treegrid, TreeItem as NaturalTreeItem } from '@dxos/react-ui';
22
18
  import {
23
- focusRing,
24
19
  ghostHover,
25
20
  hoverableControls,
26
21
  hoverableFocusedKeyboardControls,
@@ -28,11 +23,10 @@ import {
28
23
  mx,
29
24
  } from '@dxos/react-ui-theme';
30
25
 
31
- import { DropIndicator } from './DropIndicator';
32
26
  import { useTree } from './TreeContext';
33
27
  import { TreeItemHeading } from './TreeItemHeading';
34
28
  import { TreeItemToggle } from './TreeItemToggle';
35
- import { DEFAULT_INDENTATION, paddingIndendation } from './helpers';
29
+ import { DEFAULT_INDENTATION, paddingIndentation } from './helpers';
36
30
 
37
31
  type TreeItemState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
38
32
 
@@ -52,9 +46,16 @@ export const isTreeData = (data: unknown): data is TreeData => S.is(TreeDataSche
52
46
  export type TreeItemProps<T = any> = {
53
47
  item: T;
54
48
  path: string[];
49
+ levelOffset?: number;
55
50
  last: boolean;
56
51
  draggable?: boolean;
57
- renderColumns?: FC<{ item: T; path: string[]; menuOpen: boolean; setMenuOpen: (open: boolean) => void }>;
52
+ renderColumns?: FC<{
53
+ item: T;
54
+ path: string[];
55
+ open: boolean;
56
+ menuOpen: boolean;
57
+ setMenuOpen: (open: boolean) => void;
58
+ }>;
58
59
  canDrop?: (source: TreeData, target: TreeData) => boolean;
59
60
  onOpenChange?: (params: { item: T; path: string[]; open: boolean }) => void;
60
61
  onSelect?: (params: { item: T; path: string[]; current: boolean; option: boolean }) => void;
@@ -64,11 +65,12 @@ export const RawTreeItem = <T = any,>({
64
65
  item,
65
66
  path: _path,
66
67
  last,
67
- draggable,
68
+ draggable: _draggable,
68
69
  renderColumns: Columns,
69
70
  canDrop,
70
71
  onOpenChange,
71
72
  onSelect,
73
+ levelOffset = 2,
72
74
  }: TreeItemProps<T>) => {
73
75
  const { getItems, getProps, isOpen, isCurrent } = useTree();
74
76
  const items = getItems(item);
@@ -76,7 +78,7 @@ export const RawTreeItem = <T = any,>({
76
78
  const path = useMemo(() => [..._path, id], [_path, id]);
77
79
  const open = isOpen(path, item);
78
80
  const current = isCurrent(path, item);
79
- const level = path.length - 2;
81
+ const level = path.length - levelOffset;
80
82
  const isBranch = !!parentOf;
81
83
  const mode: ItemMode = last ? 'last-in-group' : open ? 'expanded' : 'standard';
82
84
  const data = useMemo(() => ({ id, path, item }) satisfies TreeData, [id, path, item]);
@@ -97,7 +99,7 @@ export const RawTreeItem = <T = any,>({
97
99
  }, []);
98
100
 
99
101
  useEffect(() => {
100
- if (!draggable) {
102
+ if (!_draggable) {
101
103
  return;
102
104
  }
103
105
 
@@ -105,7 +107,7 @@ export const RawTreeItem = <T = any,>({
105
107
 
106
108
  // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about
107
109
  return combine(
108
- pragmaticDraggable({
110
+ draggable({
109
111
  element: buttonRef.current,
110
112
  getInitialData: () => data,
111
113
  onDragStart: () => {
@@ -122,6 +124,7 @@ export const RawTreeItem = <T = any,>({
122
124
  }
123
125
  },
124
126
  }),
127
+ // https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx
125
128
  dropTargetForElements({
126
129
  element: buttonRef.current,
127
130
  getData: ({ input, element }) => {
@@ -171,7 +174,7 @@ export const RawTreeItem = <T = any,>({
171
174
  },
172
175
  }),
173
176
  );
174
- }, [draggable, item, id, mode, path, open, canDrop]);
177
+ }, [_draggable, item, id, mode, path, open, canDrop]);
175
178
 
176
179
  // Cancel expand on unmount.
177
180
  useEffect(() => () => cancelExpand(), [cancelExpand]);
@@ -215,13 +218,12 @@ export const RawTreeItem = <T = any,>({
215
218
  aria-labelledby={`${id}__label`}
216
219
  parentOf={parentOf?.join(Treegrid.PARENT_OF_SEPARATOR)}
217
220
  classNames={mx(
218
- 'grid grid-cols-subgrid col-[tree-row] mt-[2px] aria-[current]:bg-input',
221
+ 'grid grid-cols-subgrid col-[tree-row] mbs-0.5 aria-[current]:bg-input',
219
222
  hoverableControls,
220
223
  hoverableFocusedKeyboardControls,
221
224
  hoverableFocusedWithinControls,
222
225
  hoverableDescriptionIcons,
223
226
  ghostHover,
224
- focusRing,
225
227
  className,
226
228
  )}
227
229
  data-itemid={id}
@@ -239,7 +241,7 @@ export const RawTreeItem = <T = any,>({
239
241
  <Treegrid.Cell
240
242
  indent
241
243
  classNames='relative grid grid-cols-subgrid col-[tree-row]'
242
- style={paddingIndendation(level)}
244
+ style={paddingIndentation(level)}
243
245
  >
244
246
  <div role='none' className='flex items-center'>
245
247
  <TreeItemToggle open={open} isBranch={isBranch} onToggle={handleOpenChange} />
@@ -253,8 +255,8 @@ export const RawTreeItem = <T = any,>({
253
255
  onSelect={handleSelect}
254
256
  />
255
257
  </div>
256
- {Columns && <Columns item={item} path={path} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />}
257
- {instruction && <DropIndicator instruction={instruction} gap={2} />}
258
+ {Columns && <Columns item={item} path={path} open={open} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />}
259
+ {instruction && <NaturalTreeItem.DropIndicator instruction={instruction} gap={2} />}
258
260
  </Treegrid.Cell>
259
261
  </Treegrid.Row>
260
262
  {open &&
@@ -264,7 +266,7 @@ export const RawTreeItem = <T = any,>({
264
266
  item={item}
265
267
  path={path}
266
268
  last={index === items.length - 1}
267
- draggable={draggable}
269
+ draggable={_draggable}
268
270
  renderColumns={Columns}
269
271
  canDrop={canDrop}
270
272
  onOpenChange={onOpenChange}
@@ -51,14 +51,13 @@ export const TreeItemHeading = memo(
51
51
  asChild
52
52
  ref={forwardedRef}
53
53
  >
54
- {/* TODO(wittjosiah): Class precedence. See #8149. */}
55
54
  <Button
56
55
  data-testid='treeItem.heading'
57
56
  variant='ghost'
58
57
  density='fine'
59
58
  classNames={mx(
60
- 'grow gap-2 !pis-0.5 hover:!bg-transparent dark:hover:!bg-transparent',
61
- 'disabled:!cursor-default disabled:!opacity-100',
59
+ 'grow gap-2 pis-0.5 hover:bg-transparent dark:hover:bg-transparent',
60
+ 'disabled:cursor-default disabled:opacity-100',
62
61
  className,
63
62
  )}
64
63
  disabled={disabled}
@@ -11,10 +11,11 @@ export type TreeItemToggleProps = {
11
11
  open?: boolean;
12
12
  isBranch?: boolean;
13
13
  onToggle?: () => void;
14
+ hidden?: boolean;
14
15
  };
15
16
 
16
17
  export const TreeItemToggle = memo(
17
- forwardRef<HTMLButtonElement, TreeItemToggleProps>(({ open, isBranch, onToggle }, forwardedRef) => {
18
+ forwardRef<HTMLButtonElement, TreeItemToggleProps>(({ open, isBranch, hidden, onToggle }, forwardedRef) => {
18
19
  return (
19
20
  <Button
20
21
  ref={forwardedRef}
@@ -22,7 +23,7 @@ export const TreeItemToggle = memo(
22
23
  aria-expanded={open}
23
24
  variant='ghost'
24
25
  density='fine'
25
- classNames={mx('is-6 !pli-1', !isBranch && 'invisible')}
26
+ classNames={mx('is-4 dx-focus-ring-inset pli-0', hidden ? 'hidden' : !isBranch && 'invisible')}
26
27
  onClick={onToggle}
27
28
  >
28
29
  <Icon
@@ -4,6 +4,6 @@
4
4
 
5
5
  export const DEFAULT_INDENTATION = 8;
6
6
 
7
- export const paddingIndendation = (level: number, indentation = DEFAULT_INDENTATION) => ({
7
+ export const paddingIndentation = (level: number, indentation = DEFAULT_INDENTATION) => ({
8
8
  paddingInlineStart: `${(level - 1) * indentation}px`,
9
9
  });
@@ -1,11 +0,0 @@
1
- import { type Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
2
- import React from 'react';
3
- export type DropIndicatorProps = {
4
- edge: Edge;
5
- gap?: number;
6
- };
7
- /**
8
- * This is a tailwind port of `@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box`
9
- */
10
- export declare const DropIndicator: ({ edge, gap }: DropIndicatorProps) => React.JSX.Element;
11
- //# sourceMappingURL=DropIndicator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DropIndicator.d.ts","sourceRoot":"","sources":["../../../../../src/components/List/DropIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,gDAAgD,CAAC;AAC3E,OAAO,KAAkD,MAAM,OAAO,CAAC;AA6BvE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,kBAAuB,kBAAkB,sBA0BlE,CAAC"}
@@ -1,8 +0,0 @@
1
- import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
2
- import React from 'react';
3
- export type DropIndicatorProps = {
4
- instruction: Instruction;
5
- gap?: number;
6
- };
7
- export declare const DropIndicator: ({ instruction, gap }: DropIndicatorProps) => React.JSX.Element | null;
8
- //# sourceMappingURL=DropIndicator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DropIndicator.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/DropIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,oDAAoD,CAAC;AACtF,OAAO,KAAkD,MAAM,OAAO,CAAC;AAoCvE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,aAAa,yBAA8B,kBAAkB,6BA+BzE,CAAC"}
@@ -1,69 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { type Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
6
- import React, { type CSSProperties, type HTMLAttributes } from 'react';
7
-
8
- import { mx } from '@dxos/react-ui-theme';
9
-
10
- type Orientation = 'horizontal' | 'vertical';
11
-
12
- const edgeToOrientationMap: Record<Edge, Orientation> = {
13
- top: 'horizontal',
14
- bottom: 'horizontal',
15
- left: 'vertical',
16
- right: 'vertical',
17
- };
18
-
19
- const orientationStyles: Record<Orientation, HTMLAttributes<HTMLElement>['className']> = {
20
- horizontal: 'h-[--line-thickness] left-[--terminal-radius] right-0 before:left-[--negative-terminal-size]',
21
- vertical: 'w-[--line-thickness] top-[--terminal-radius] bottom-0 before:top-[--negative-terminal-size]',
22
- };
23
-
24
- const edgeStyles: Record<Edge, HTMLAttributes<HTMLElement>['className']> = {
25
- top: 'top-[--line-offset] before:top-[--offset-terminal]',
26
- right: 'right-[--line-offset] before:right-[--offset-terminal]',
27
- bottom: 'bottom-[--line-offset] before:bottom-[--offset-terminal]',
28
- left: 'left-[--line-offset] before:left-[--offset-terminal]',
29
- };
30
-
31
- const strokeSize = 2;
32
- const terminalSize = 8;
33
- const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
34
-
35
- export type DropIndicatorProps = {
36
- edge: Edge;
37
- gap?: number;
38
- };
39
-
40
- /**
41
- * This is a tailwind port of `@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box`
42
- */
43
- export const DropIndicator = ({ edge, gap = 0 }: DropIndicatorProps) => {
44
- const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
45
-
46
- const orientation = edgeToOrientationMap[edge];
47
-
48
- return (
49
- <div
50
- style={
51
- {
52
- '--line-thickness': `${strokeSize}px`,
53
- '--line-offset': `${lineOffset}`,
54
- '--terminal-size': `${terminalSize}px`,
55
- '--terminal-radius': `${terminalSize / 2}px`,
56
- '--negative-terminal-size': `-${terminalSize}px`,
57
- '--offset-terminal': `${offsetToAlignTerminalWithLine}px`,
58
- } as CSSProperties
59
- }
60
- className={mx(
61
- 'absolute z-10 pointer-events-none bg-blue-700',
62
- "before:content-[''] before:w-[--terminal-size] before:h-[--terminal-size] box-border before:absolute",
63
- 'before:border-[length:--line-thickness] before:border-solid before:border-blue-700 before:rounded-full',
64
- orientationStyles[orientation],
65
- edgeStyles[edge],
66
- )}
67
- ></div>
68
- );
69
- };
@@ -1,78 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
6
- import React, { type HTMLAttributes, type CSSProperties } from 'react';
7
-
8
- import { mx } from '@dxos/react-ui-theme';
9
-
10
- // Tree item hitbox
11
- // https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx#tree-item
12
-
13
- type InstructionType = Exclude<Instruction, { type: 'instruction-blocked' }>['type'];
14
- type Orientation = 'sibling' | 'child';
15
-
16
- const edgeToOrientationMap: Record<InstructionType, Orientation> = {
17
- 'reorder-above': 'sibling',
18
- 'reorder-below': 'sibling',
19
- 'make-child': 'child',
20
- reparent: 'child',
21
- };
22
-
23
- const orientationStyles: Record<Orientation, HTMLAttributes<HTMLElement>['className']> = {
24
- // TODO(wittjosiah): Stop using left/right here.
25
- sibling:
26
- 'bs-[--line-thickness] left-[--horizontal-indent] right-0 bg-accentSurface before:left-[--negative-terminal-size]',
27
- child: 'is-full block-start-0 block-end-0 border-[length:--line-thickness] before:invisible',
28
- };
29
-
30
- const instructionStyles: Record<InstructionType, HTMLAttributes<HTMLElement>['className']> = {
31
- 'reorder-above': 'block-start-[--line-offset] before:block-start-[--offset-terminal]',
32
- 'reorder-below': 'block-end-[--line-offset] before:block-end-[--offset-terminal]',
33
- 'make-child': 'border-accentSurface',
34
- // TODO(wittjosiah): This is not occurring in the current implementation.
35
- reparent: '',
36
- };
37
-
38
- const strokeSize = 2;
39
- const terminalSize = 8;
40
- const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
41
-
42
- export type DropIndicatorProps = {
43
- instruction: Instruction;
44
- gap?: number;
45
- };
46
-
47
- export const DropIndicator = ({ instruction, gap = 0 }: DropIndicatorProps) => {
48
- const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
49
- const isBlocked = instruction.type === 'instruction-blocked';
50
- const desiredInstruction = isBlocked ? instruction.desired : instruction;
51
- const orientation = edgeToOrientationMap[desiredInstruction.type];
52
- if (isBlocked) {
53
- return null;
54
- }
55
-
56
- return (
57
- <div
58
- style={
59
- {
60
- '--line-thickness': `${strokeSize}px`,
61
- '--line-offset': `${lineOffset}`,
62
- '--terminal-size': `${terminalSize}px`,
63
- '--terminal-radius': `${terminalSize / 2}px`,
64
- '--negative-terminal-size': `-${terminalSize}px`,
65
- '--offset-terminal': `${offsetToAlignTerminalWithLine}px`,
66
- '--horizontal-indent': `${desiredInstruction.currentLevel * desiredInstruction.indentPerLevel + 4}px`,
67
- } as CSSProperties
68
- }
69
- className={mx(
70
- 'absolute z-10 pointer-events-none',
71
- 'before:is-[--terminal-size] before:bs-[--terminal-size] box-border before:absolute',
72
- 'before:border-[length:--line-thickness] before:border-solid before:border-accentSurface before:rounded-full',
73
- orientationStyles[orientation],
74
- instructionStyles[desiredInstruction.type],
75
- )}
76
- ></div>
77
- );
78
- };