@dxos/react-ui-list 0.8.4-main.70d3990 → 0.8.4-main.74a063c4e0

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 (46) hide show
  1. package/dist/lib/browser/index.mjs +680 -728
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +680 -728
  5. package/dist/lib/node-esm/index.mjs.map +3 -3
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  8. package/dist/types/src/components/List/List.d.ts +8 -6
  9. package/dist/types/src/components/List/List.d.ts.map +1 -1
  10. package/dist/types/src/components/List/List.stories.d.ts +2 -2
  11. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/List/ListItem.d.ts +8 -6
  13. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  14. package/dist/types/src/components/List/ListRoot.d.ts +2 -2
  15. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  16. package/dist/types/src/components/Tree/Tree.d.ts +10 -6
  17. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  18. package/dist/types/src/components/Tree/Tree.stories.d.ts +9 -28
  19. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Tree/TreeContext.d.ts +21 -8
  21. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  22. package/dist/types/src/components/Tree/TreeItem.d.ts +14 -3
  23. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  24. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  25. package/dist/types/src/components/Tree/index.d.ts +2 -0
  26. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  27. package/dist/types/src/components/Tree/testing.d.ts +2 -2
  28. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  29. package/dist/types/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +31 -28
  31. package/src/components/Accordion/Accordion.stories.tsx +6 -6
  32. package/src/components/Accordion/AccordionItem.tsx +3 -4
  33. package/src/components/Accordion/AccordionRoot.tsx +1 -1
  34. package/src/components/List/List.stories.tsx +34 -22
  35. package/src/components/List/List.tsx +4 -9
  36. package/src/components/List/ListItem.tsx +60 -40
  37. package/src/components/List/ListRoot.tsx +3 -3
  38. package/src/components/List/testing.ts +4 -4
  39. package/src/components/Tree/Tree.stories.tsx +153 -64
  40. package/src/components/Tree/Tree.tsx +30 -41
  41. package/src/components/Tree/TreeContext.tsx +18 -7
  42. package/src/components/Tree/TreeItem.tsx +182 -108
  43. package/src/components/Tree/TreeItemHeading.tsx +4 -5
  44. package/src/components/Tree/TreeItemToggle.tsx +4 -4
  45. package/src/components/Tree/index.ts +2 -0
  46. package/src/components/Tree/testing.ts +7 -7
@@ -2,27 +2,38 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
5
  import {
8
6
  type Instruction,
9
7
  type ItemMode,
10
8
  attachInstruction,
11
9
  extractInstruction,
12
10
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
11
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
12
+ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
13
+ import { useAtomValue } from '@effect-atom/atom-react';
13
14
  import * as Schema from 'effect/Schema';
14
- import React, { type FC, type KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
15
+ import React, {
16
+ type FC,
17
+ type KeyboardEvent,
18
+ type MouseEvent,
19
+ memo,
20
+ useCallback,
21
+ useEffect,
22
+ useMemo,
23
+ useRef,
24
+ useState,
25
+ } from 'react';
15
26
 
16
- import { type HasId } from '@dxos/echo/internal';
17
27
  import { invariant } from '@dxos/invariant';
18
- import { TreeItem as NaturalTreeItem, Treegrid } from '@dxos/react-ui';
28
+ import { TreeItem as NaturalTreeItem, Treegrid, TREEGRID_PARENT_OF_SEPARATOR } from '@dxos/react-ui';
19
29
  import {
20
30
  ghostFocusWithin,
21
31
  ghostHover,
22
32
  hoverableControls,
23
33
  hoverableFocusedKeyboardControls,
24
34
  hoverableFocusedWithinControls,
25
- } from '@dxos/react-ui-theme';
35
+ mx,
36
+ } from '@dxos/ui-theme';
26
37
 
27
38
  import { DEFAULT_INDENTATION, paddingIndentation } from './helpers';
28
39
  import { useTree } from './TreeContext';
@@ -32,7 +43,7 @@ import { TreeItemToggle } from './TreeItemToggle';
32
43
  const hoverableDescriptionIcons =
33
44
  '[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]';
34
45
 
35
- type TreeItemState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
46
+ type TreeItemDragState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
36
47
 
37
48
  export const TreeDataSchema = Schema.Struct({
38
49
  id: Schema.String,
@@ -43,7 +54,7 @@ export const TreeDataSchema = Schema.Struct({
43
54
  export type TreeData = Schema.Schema.Type<typeof TreeDataSchema>;
44
55
  export const isTreeData = (data: unknown): data is TreeData => Schema.is(TreeDataSchema)(data);
45
56
 
46
- export type ColumnRenderer<T extends HasId = any> = FC<{
57
+ export type ColumnRenderer<T extends { id: string } = any> = FC<{
47
58
  item: T;
48
59
  path: string[];
49
60
  open: boolean;
@@ -51,7 +62,7 @@ export type ColumnRenderer<T extends HasId = any> = FC<{
51
62
  setMenuOpen: (open: boolean) => void;
52
63
  }>;
53
64
 
54
- export type TreeItemProps<T extends HasId = any> = {
65
+ export type TreeItemProps<T extends { id: string } = any> = {
55
66
  item: T;
56
67
  path: string[];
57
68
  levelOffset?: number;
@@ -63,39 +74,62 @@ export type TreeItemProps<T extends HasId = any> = {
63
74
  canSelect?: (params: { item: T; path: string[] }) => boolean;
64
75
  onOpenChange?: (params: { item: T; path: string[]; open: boolean }) => void;
65
76
  onSelect?: (params: { item: T; path: string[]; current: boolean; option: boolean }) => void;
77
+ onItemHover?: (params: { item: T }) => void;
66
78
  };
67
79
 
68
- const RawTreeItem = <T extends HasId = any>({
80
+ const RawTreeItem = <T extends { id: string } = any>({
69
81
  item,
70
- path: _path,
82
+ path: pathProp,
71
83
  levelOffset = 2,
72
84
  last,
73
- draggable: _draggable,
85
+ draggable: draggableProp,
74
86
  renderColumns: Columns,
75
87
  blockInstruction,
76
88
  canDrop,
77
89
  canSelect,
78
90
  onOpenChange,
79
91
  onSelect,
92
+ onItemHover,
80
93
  }: TreeItemProps<T>) => {
81
94
  const rowRef = useRef<HTMLDivElement | null>(null);
82
95
  const buttonRef = useRef<HTMLButtonElement | null>(null);
83
96
  const openRef = useRef(false);
84
97
  const cancelExpandRef = useRef<NodeJS.Timeout | null>(null);
85
- const [_state, setState] = useState<TreeItemState>('idle');
98
+ const [_state, setState] = useState<TreeItemDragState>('idle');
86
99
  const [instruction, setInstruction] = useState<Instruction | null>(null);
87
100
  const [menuOpen, setMenuOpen] = useState(false);
88
101
 
89
- const { useItems, getProps, isOpen, isCurrent } = useTree();
90
- const items = useItems(item);
91
- const { id, parentOf, label, className, headingClassName, icon, iconHue, disabled, testId } = getProps(item, _path);
92
- const path = useMemo(() => [..._path, id], [_path, id]);
93
- const open = isOpen(path, item);
94
- const current = isCurrent(path, item);
102
+ const {
103
+ itemProps: itemPropsAtom,
104
+ childIds: childIdsAtom,
105
+ itemOpen: itemOpenAtom,
106
+ itemCurrent: itemCurrentAtom,
107
+ } = useTree();
108
+ const path = useMemo(() => [...pathProp, item.id], [pathProp, item.id]);
109
+
110
+ const {
111
+ id,
112
+ parentOf,
113
+ draggable: itemDraggable,
114
+ droppable: itemDroppable,
115
+ label,
116
+ className,
117
+ headingClassName,
118
+ icon,
119
+ iconHue,
120
+ disabled,
121
+ testId,
122
+ } = useAtomValue(itemPropsAtom(path));
123
+ const childIds = useAtomValue(childIdsAtom(item.id));
124
+ const open = useAtomValue(itemOpenAtom(path));
125
+ const current = useAtomValue(itemCurrentAtom(path));
126
+
95
127
  const level = path.length - levelOffset;
96
128
  const isBranch = !!parentOf;
97
129
  const mode: ItemMode = last ? 'last-in-group' : open ? 'expanded' : 'standard';
98
130
  const canSelectItem = canSelect?.({ item, path }) ?? true;
131
+ const data = { id, path, item } satisfies TreeData;
132
+ const shouldSeedNativeDragData = typeof document !== 'undefined' && document.body.hasAttribute('data-platform');
99
133
 
100
134
  const cancelExpand = useCallback(() => {
101
135
  if (cancelExpandRef.current) {
@@ -104,20 +138,27 @@ const RawTreeItem = <T extends HasId = any>({
104
138
  }
105
139
  }, []);
106
140
 
141
+ const isItemDraggable = draggableProp && itemDraggable !== false;
142
+ const isItemDroppable = itemDroppable !== false;
143
+ const nativeDragText = id;
144
+
107
145
  useEffect(() => {
108
- if (!_draggable) {
146
+ if (!draggableProp) {
109
147
  return;
110
148
  }
111
149
 
112
150
  invariant(buttonRef.current);
113
151
 
114
- const data = { id, path, item } satisfies TreeData;
115
-
116
- // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about
117
- return combine(
152
+ const makeDraggable = () =>
118
153
  draggable({
119
- element: buttonRef.current,
154
+ element: buttonRef.current!,
120
155
  getInitialData: () => data,
156
+ getInitialDataForExternal: () => {
157
+ if (!shouldSeedNativeDragData) {
158
+ return {};
159
+ }
160
+ return { 'text/plain': nativeDragText };
161
+ },
121
162
  onDragStart: () => {
122
163
  setState('dragging');
123
164
  if (open) {
@@ -131,62 +172,72 @@ const RawTreeItem = <T extends HasId = any>({
131
172
  onOpenChange?.({ item, path, open: true });
132
173
  }
133
174
  },
134
- }),
135
- // https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx
136
- dropTargetForElements({
137
- element: buttonRef.current,
138
- getData: ({ input, element }) => {
139
- return attachInstruction(data, {
140
- input,
141
- element,
142
- indentPerLevel: DEFAULT_INDENTATION,
143
- currentLevel: level,
144
- mode,
145
- block: isBranch ? [] : ['make-child'],
146
- });
147
- },
148
- canDrop: ({ source }) => {
149
- const _canDrop = canDrop ?? (() => true);
150
- return source.element !== buttonRef.current && _canDrop({ source: source.data as TreeData, target: data });
151
- },
152
- getIsSticky: () => true,
153
- onDrag: ({ self, source }) => {
154
- const desired = extractInstruction(self.data);
155
- const block =
156
- desired && blockInstruction?.({ instruction: desired, source: source.data as TreeData, target: data });
157
- const instruction: Instruction | null =
158
- block && desired.type !== 'instruction-blocked' ? { type: 'instruction-blocked', desired } : desired;
159
-
160
- if (source.data.id !== id) {
161
- if (instruction?.type === 'make-child' && isBranch && !open && !cancelExpandRef.current) {
162
- cancelExpandRef.current = setTimeout(() => {
163
- onOpenChange?.({ item, path, open: true });
164
- }, 500);
165
- }
166
-
167
- if (instruction?.type !== 'make-child') {
168
- cancelExpand();
169
- }
170
-
171
- setInstruction(instruction);
172
- } else if (instruction?.type === 'reparent') {
173
- // TODO(wittjosiah): This is not occurring in the current implementation.
174
- setInstruction(instruction);
175
- } else {
176
- setInstruction(null);
175
+ });
176
+
177
+ if (!isItemDroppable) {
178
+ return isItemDraggable ? makeDraggable() : undefined;
179
+ }
180
+
181
+ const dropTarget = dropTargetForElements({
182
+ element: buttonRef.current,
183
+ getData: ({ input, element }) => {
184
+ return attachInstruction(data, {
185
+ input,
186
+ element,
187
+ indentPerLevel: DEFAULT_INDENTATION,
188
+ currentLevel: level,
189
+ mode,
190
+ block: isBranch ? [] : ['make-child'],
191
+ });
192
+ },
193
+ canDrop: ({ source }) => {
194
+ const _canDrop = canDrop ?? (() => true);
195
+ return source.element !== buttonRef.current && _canDrop({ source: source.data as TreeData, target: data });
196
+ },
197
+ getIsSticky: () => true,
198
+ onDrag: ({ self, source }) => {
199
+ const desired = extractInstruction(self.data);
200
+ const block =
201
+ desired && blockInstruction?.({ instruction: desired, source: source.data as TreeData, target: data });
202
+ const instruction: Instruction | null =
203
+ block && desired.type !== 'instruction-blocked' ? { type: 'instruction-blocked', desired } : desired;
204
+
205
+ if (source.data.id !== id) {
206
+ if (instruction?.type === 'make-child' && isBranch && !open && !cancelExpandRef.current) {
207
+ cancelExpandRef.current = setTimeout(() => {
208
+ onOpenChange?.({ item, path, open: true });
209
+ }, 500);
177
210
  }
178
- },
179
- onDragLeave: () => {
180
- cancelExpand();
181
- setInstruction(null);
182
- },
183
- onDrop: () => {
184
- cancelExpand();
211
+
212
+ if (instruction?.type !== 'make-child') {
213
+ cancelExpand();
214
+ }
215
+
216
+ setInstruction(instruction);
217
+ } else if (instruction?.type === 'reparent') {
218
+ // TODO(wittjosiah): This is not occurring in the current implementation.
219
+ setInstruction(instruction);
220
+ } else {
185
221
  setInstruction(null);
186
- },
187
- }),
188
- );
189
- }, [_draggable, item, id, mode, path, open, blockInstruction, canDrop]);
222
+ }
223
+ },
224
+ onDragLeave: () => {
225
+ cancelExpand();
226
+ setInstruction(null);
227
+ },
228
+ onDrop: () => {
229
+ cancelExpand();
230
+ setInstruction(null);
231
+ },
232
+ });
233
+
234
+ if (!isItemDraggable) {
235
+ return dropTarget;
236
+ }
237
+
238
+ // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about
239
+ return combine(makeDraggable(), dropTarget);
240
+ }, [draggableProp, isItemDraggable, isItemDroppable, item, id, mode, path, open, blockInstruction, canDrop]);
190
241
 
191
242
  // Cancel expand on unmount.
192
243
  useEffect(() => () => cancelExpand(), [cancelExpand]);
@@ -224,6 +275,29 @@ const RawTreeItem = <T extends HasId = any>({
224
275
  [isBranch, open, handleOpenToggle, handleSelect],
225
276
  );
226
277
 
278
+ const handleItemHover = useCallback(() => {
279
+ onItemHover?.({ item });
280
+ }, [onItemHover, item]);
281
+
282
+ const handleContextMenu = useCallback(
283
+ (event: MouseEvent) => {
284
+ event.preventDefault();
285
+ setMenuOpen(true);
286
+ },
287
+ [setMenuOpen],
288
+ );
289
+
290
+ const childProps = {
291
+ draggable: draggableProp,
292
+ renderColumns: Columns,
293
+ blockInstruction,
294
+ canDrop,
295
+ canSelect,
296
+ onItemHover,
297
+ onOpenChange,
298
+ onSelect,
299
+ };
300
+
227
301
  return (
228
302
  <>
229
303
  <Treegrid.Row
@@ -231,28 +305,26 @@ const RawTreeItem = <T extends HasId = any>({
231
305
  key={id}
232
306
  id={id}
233
307
  aria-labelledby={`${id}__label`}
234
- parentOf={parentOf?.join(Treegrid.PARENT_OF_SEPARATOR)}
235
- classNames={[
236
- 'grid grid-cols-subgrid col-[tree-row] mbs-0.5 aria-[current]:bg-activeSurface',
237
- hoverableControls,
238
- hoverableFocusedKeyboardControls,
239
- hoverableFocusedWithinControls,
240
- hoverableDescriptionIcons,
241
- ghostHover,
242
- ghostFocusWithin,
243
- className,
244
- ]}
308
+ parentOf={parentOf?.join(TREEGRID_PARENT_OF_SEPARATOR)}
245
309
  data-object-id={id}
246
310
  data-testid={testId}
247
311
  // NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
248
312
  // without alerting the user (except for in the correct link element). See also:
249
313
  // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
250
314
  aria-current={current ? ('' as 'page') : undefined}
315
+ classNames={mx(
316
+ 'grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-active-surface',
317
+ hoverableControls,
318
+ hoverableFocusedKeyboardControls,
319
+ hoverableFocusedWithinControls,
320
+ hoverableDescriptionIcons,
321
+ ghostFocusWithin,
322
+ ghostHover,
323
+ className,
324
+ )}
251
325
  onKeyDown={handleKeyDown}
252
- onContextMenu={(event) => {
253
- event.preventDefault();
254
- setMenuOpen(true);
255
- }}
326
+ onMouseEnter={handleItemHover}
327
+ onContextMenu={handleContextMenu}
256
328
  >
257
329
  <div
258
330
  role='none'
@@ -277,23 +349,25 @@ const RawTreeItem = <T extends HasId = any>({
277
349
  </div>
278
350
  </Treegrid.Row>
279
351
  {open &&
280
- items.map((item, index) => (
281
- <TreeItem
282
- key={item.id}
283
- item={item}
284
- path={path}
285
- last={index === items.length - 1}
286
- draggable={_draggable}
287
- renderColumns={Columns}
288
- blockInstruction={blockInstruction}
289
- canDrop={canDrop}
290
- canSelect={canSelect}
291
- onOpenChange={onOpenChange}
292
- onSelect={onSelect}
293
- />
352
+ childIds.map((childId, index) => (
353
+ <TreeItemById key={childId} id={childId} path={path} last={index === childIds.length - 1} {...childProps} />
294
354
  ))}
295
355
  </>
296
356
  );
297
357
  };
298
358
 
299
359
  export const TreeItem = memo(RawTreeItem) as FC<TreeItemProps>;
360
+
361
+ /** Resolves a child ID to an item via the `item` atom and renders a TreeItem. */
362
+ export type TreeItemByIdProps = Omit<TreeItemProps, 'item'> & { id: string };
363
+
364
+ const RawTreeItemById = <T extends { id: string } = any>({ id, ...props }: TreeItemByIdProps) => {
365
+ const { item: itemAtom } = useTree();
366
+ const item = useAtomValue(itemAtom(id)) as T | undefined;
367
+ if (!item) {
368
+ return null;
369
+ }
370
+ return <TreeItem item={item} {...props} />;
371
+ };
372
+
373
+ export const TreeItemById = memo(RawTreeItemById) as FC<TreeItemByIdProps>;
@@ -6,7 +6,7 @@ import React, { type KeyboardEvent, type MouseEvent, forwardRef, memo, useCallba
6
6
 
7
7
  import { Button, Icon, type Label, toLocalizedString, useTranslation } from '@dxos/react-ui';
8
8
  import { TextTooltip } from '@dxos/react-ui-text-tooltip';
9
- import { getStyles } from '@dxos/react-ui-theme';
9
+ import { getStyles } from '@dxos/ui-theme';
10
10
 
11
11
  // TODO(wittjosiah): Consider whether there should be a separate disabled prop which was visually distinct
12
12
  // rather than just making the item unselectable.
@@ -56,9 +56,8 @@ export const TreeItemHeading = memo(
56
56
  <Button
57
57
  data-testid='treeItem.heading'
58
58
  variant='ghost'
59
- density='fine'
60
59
  classNames={[
61
- 'grow gap-2 pis-0.5 hover:bg-transparent dark:hover:bg-transparent',
60
+ 'grow gap-2 ps-0.5 hover:bg-transparent dark:hover:bg-transparent',
62
61
  'disabled:cursor-default disabled:opacity-100',
63
62
  className,
64
63
  ]}
@@ -67,8 +66,8 @@ export const TreeItemHeading = memo(
67
66
  onKeyDown={handleButtonKeydown}
68
67
  {...(current && { 'aria-current': 'location' })}
69
68
  >
70
- {icon && <Icon icon={icon ?? 'ph--placeholder--regular'} size={5} classNames={['mlb-1', styles?.icon]} />}
71
- <span className='flex-1 is-0 truncate text-start text-sm font-normal' data-tooltip>
69
+ {icon && <Icon icon={icon ?? 'ph--placeholder--regular'} classNames={['my-1', styles?.surfaceText]} />}
70
+ <span className='flex-1 w-0 truncate text-start font-normal' data-tooltip>
72
71
  {toLocalizedString(label, t)}
73
72
  </span>
74
73
  </Button>
@@ -14,7 +14,7 @@ export type TreeItemToggleProps = Omit<IconButtonProps, 'icon' | 'size' | 'label
14
14
 
15
15
  export const TreeItemToggle = memo(
16
16
  forwardRef<HTMLButtonElement, TreeItemToggleProps>(
17
- ({ open, isBranch, hidden, classNames, ...props }, forwardedRef) => {
17
+ ({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
18
18
  return (
19
19
  <IconButton
20
20
  ref={forwardedRef}
@@ -23,9 +23,9 @@ export const TreeItemToggle = memo(
23
23
  variant='ghost'
24
24
  density='fine'
25
25
  classNames={[
26
- 'bs-full is-6 pli-0',
27
- '[&_svg]:transition-[transform] [&_svg]:duration-200',
28
- open && '[&_svg]:rotate-90',
26
+ 'h-full w-6 px-0',
27
+ '[&_svg]:transition-transform [&_svg]:duration-200',
28
+ open ? '[&_svg]:rotate-90' : '[&_svg]:rotate-0',
29
29
  hidden ? 'hidden' : !isBranch && 'invisible',
30
30
  classNames,
31
31
  ]}
@@ -5,3 +5,5 @@
5
5
  export * from './Tree';
6
6
  export * from './TreeContext';
7
7
  export * from './TreeItem';
8
+ export * from './TreeItemToggle';
9
+ export * from './helpers';
@@ -6,13 +6,13 @@ import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-
6
6
  import * as Schema from 'effect/Schema';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
- import { type HasId } from '@dxos/echo/internal';
10
9
  import { log } from '@dxos/log';
11
- import { faker } from '@dxos/random';
10
+ import { random } from '@dxos/random';
12
11
 
13
12
  import { type TreeData } from './TreeItem';
14
13
 
15
- export type TestItem = HasId & {
14
+ export type TestItem = {
15
+ id: string;
16
16
  name: string;
17
17
  icon?: string;
18
18
  items: TestItem[];
@@ -26,18 +26,18 @@ export const TestItemSchema = Schema.Struct({
26
26
  });
27
27
 
28
28
  export const createTree = (n = 4, d = 4): TestItem => ({
29
- id: faker.string.uuid(),
30
- name: faker.commerce.productName(),
29
+ id: random.string.uuid(),
30
+ name: random.commerce.productName(),
31
31
  icon:
32
32
  d === 3
33
33
  ? undefined
34
- : faker.helpers.arrayElement([
34
+ : random.helpers.arrayElement([
35
35
  'ph--planet--regular',
36
36
  'ph--sailboat--regular',
37
37
  'ph--house--regular',
38
38
  'ph--gear--regular',
39
39
  ]),
40
- items: d > 0 ? faker.helpers.multiple(() => createTree(n, d - 1), { count: n }) : [],
40
+ items: d > 0 ? random.helpers.multiple(() => createTree(n, d - 1), { count: n }) : [],
41
41
  });
42
42
 
43
43
  const removeItem = (tree: TestItem, source: TreeData) => {