@dxos/react-ui-list 0.8.4-main.c1de068 → 0.8.4-main.c85a9c8dae

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 (55) hide show
  1. package/dist/lib/browser/index.mjs +676 -729
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +676 -729
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Accordion/Accordion.stories.d.ts +7 -4
  8. package/dist/types/src/components/Accordion/Accordion.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/Accordion/AccordionItem.d.ts +1 -1
  10. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  11. package/dist/types/src/components/List/List.d.ts +8 -8
  12. package/dist/types/src/components/List/List.d.ts.map +1 -1
  13. package/dist/types/src/components/List/List.stories.d.ts +14 -5
  14. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/List/ListItem.d.ts +6 -9
  16. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  17. package/dist/types/src/components/List/ListRoot.d.ts +2 -2
  18. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  19. package/dist/types/src/components/List/testing.d.ts +1 -1
  20. package/dist/types/src/components/List/testing.d.ts.map +1 -1
  21. package/dist/types/src/components/Tree/Tree.d.ts +10 -6
  22. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  23. package/dist/types/src/components/Tree/Tree.stories.d.ts +18 -7
  24. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/Tree/TreeContext.d.ts +20 -10
  26. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  27. package/dist/types/src/components/Tree/TreeItem.d.ts +32 -10
  28. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  29. package/dist/types/src/components/Tree/TreeItemHeading.d.ts +4 -3
  30. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  31. package/dist/types/src/components/Tree/TreeItemToggle.d.ts +3 -3
  32. package/dist/types/src/components/Tree/TreeItemToggle.d.ts.map +1 -1
  33. package/dist/types/src/components/Tree/index.d.ts +2 -0
  34. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  35. package/dist/types/src/components/Tree/testing.d.ts +3 -3
  36. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +31 -28
  39. package/src/components/Accordion/Accordion.stories.tsx +5 -7
  40. package/src/components/Accordion/Accordion.tsx +1 -1
  41. package/src/components/Accordion/AccordionItem.tsx +8 -5
  42. package/src/components/Accordion/AccordionRoot.tsx +1 -1
  43. package/src/components/List/List.stories.tsx +40 -26
  44. package/src/components/List/List.tsx +2 -5
  45. package/src/components/List/ListItem.tsx +50 -38
  46. package/src/components/List/ListRoot.tsx +3 -3
  47. package/src/components/List/testing.ts +3 -3
  48. package/src/components/Tree/Tree.stories.tsx +172 -79
  49. package/src/components/Tree/Tree.tsx +43 -40
  50. package/src/components/Tree/TreeContext.tsx +17 -9
  51. package/src/components/Tree/TreeItem.tsx +141 -83
  52. package/src/components/Tree/TreeItemHeading.tsx +13 -8
  53. package/src/components/Tree/TreeItemToggle.tsx +29 -18
  54. package/src/components/Tree/index.ts +2 -0
  55. package/src/components/Tree/testing.ts +5 -4
package/package.json CHANGED
@@ -1,14 +1,19 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-list",
3
- "version": "0.8.4-main.c1de068",
3
+ "version": "0.8.4-main.c85a9c8dae",
4
4
  "description": "A list component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
13
  "type": "module",
10
14
  "exports": {
11
15
  ".": {
16
+ "source": "./src/index.ts",
12
17
  "types": "./dist/types/src/index.d.ts",
13
18
  "browser": "./dist/lib/browser/index.mjs",
14
19
  "node": "./dist/lib/node-esm/index.mjs"
@@ -23,39 +28,37 @@
23
28
  "src"
24
29
  ],
25
30
  "dependencies": {
26
- "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
27
- "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
28
- "@preact-signals/safe-react": "^0.9.0",
29
- "@preact/signals-core": "^1.9.0",
31
+ "@atlaskit/pragmatic-drag-and-drop": "1.7.7",
32
+ "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
33
+ "@effect-atom/atom-react": "^0.5.0",
30
34
  "@radix-ui/react-accordion": "1.2.3",
31
35
  "@radix-ui/react-context": "1.1.1",
32
- "@dxos/debug": "0.8.4-main.c1de068",
33
- "@dxos/echo-schema": "0.8.4-main.c1de068",
34
- "@dxos/invariant": "0.8.4-main.c1de068",
35
- "@dxos/live-object": "0.8.4-main.c1de068",
36
- "@dxos/log": "0.8.4-main.c1de068",
37
- "@dxos/react-ui": "0.8.4-main.c1de068",
38
- "@dxos/react-ui-text-tooltip": "0.8.4-main.c1de068",
39
- "@dxos/react-ui-theme": "0.8.4-main.c1de068",
40
- "@dxos/react-ui-types": "0.8.4-main.c1de068",
41
- "@dxos/util": "0.8.4-main.c1de068"
36
+ "@dxos/debug": "0.8.4-main.c85a9c8dae",
37
+ "@dxos/invariant": "0.8.4-main.c85a9c8dae",
38
+ "@dxos/echo": "0.8.4-main.c85a9c8dae",
39
+ "@dxos/log": "0.8.4-main.c85a9c8dae",
40
+ "@dxos/react-ui": "0.8.4-main.c85a9c8dae",
41
+ "@dxos/react-ui-text-tooltip": "0.8.4-main.c85a9c8dae",
42
+ "@dxos/ui-theme": "0.8.4-main.c85a9c8dae",
43
+ "@dxos/ui-types": "0.8.4-main.c85a9c8dae",
44
+ "@dxos/util": "0.8.4-main.c85a9c8dae"
42
45
  },
43
46
  "devDependencies": {
44
- "@types/react": "~18.2.0",
45
- "@types/react-dom": "~18.2.0",
46
- "effect": "3.17.0",
47
- "react": "~18.2.0",
48
- "react-dom": "~18.2.0",
49
- "vite": "5.4.7",
50
- "@dxos/random": "0.8.4-main.c1de068",
51
- "@dxos/storybook-utils": "0.8.4-main.c1de068"
47
+ "@types/react": "~19.2.7",
48
+ "@types/react-dom": "~19.2.3",
49
+ "effect": "3.19.16",
50
+ "react": "~19.2.3",
51
+ "react-dom": "~19.2.3",
52
+ "vite": "^7.1.11",
53
+ "@dxos/random": "0.8.4-main.c85a9c8dae",
54
+ "@dxos/storybook-utils": "0.8.4-main.c85a9c8dae"
52
55
  },
53
56
  "peerDependencies": {
54
- "effect": "^3.13.3",
55
- "react": "~18.2.0",
56
- "react-dom": "~18.2.0",
57
- "@dxos/react-ui": "0.8.4-main.c1de068",
58
- "@dxos/react-ui-theme": "0.8.4-main.c1de068"
57
+ "effect": "3.19.16",
58
+ "react": "~19.2.3",
59
+ "react-dom": "~19.2.3",
60
+ "@dxos/react-ui": "0.8.4-main.c85a9c8dae",
61
+ "@dxos/ui-theme": "0.8.4-main.c85a9c8dae"
59
62
  },
60
63
  "publishConfig": {
61
64
  "access": "public"
@@ -2,13 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
6
  import React from 'react';
9
7
 
10
8
  import { faker } from '@dxos/random';
11
- import { withLayout, withTheme } from '@dxos/storybook-utils';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
10
 
13
11
  import { Accordion } from './Accordion';
14
12
 
@@ -41,11 +39,11 @@ const DefaultStory = () => {
41
39
  );
42
40
  };
43
41
 
44
- const meta: Meta<typeof Accordion> = {
42
+ const meta = {
45
43
  title: 'ui/react-ui-list/Accordion',
46
44
  render: DefaultStory,
47
- decorators: [withTheme, withLayout({ fullscreen: true, classNames: 'flex justify-center' })],
48
- };
45
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
46
+ } satisfies Meta<typeof Accordion>;
49
47
 
50
48
  export default meta;
51
49
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { AccordionItem, AccordionItemHeader, AccordionItemBody } from './AccordionItem';
5
+ import { AccordionItem, AccordionItemBody, AccordionItemHeader } from './AccordionItem';
6
6
  import { AccordionRoot } from './AccordionRoot';
7
7
 
8
8
  // TODO(burdon): Next iteration should be based on Radix UI Accordion:
@@ -7,18 +7,21 @@ import { createContext } from '@radix-ui/react-context';
7
7
  import React, { type PropsWithChildren } from 'react';
8
8
 
9
9
  import { Icon, type ThemedClassName } from '@dxos/react-ui';
10
- import { mx } from '@dxos/react-ui-theme';
10
+ import { mx } from '@dxos/ui-theme';
11
11
 
12
- import { useAccordionContext } from './AccordionRoot';
13
12
  import { type ListItemRecord } from '../List';
14
13
 
14
+ import { useAccordionContext } from './AccordionRoot';
15
+
15
16
  const ACCORDION_ITEM_NAME = 'AccordionItem';
16
17
 
17
18
  type AccordionItemContext<T extends ListItemRecord> = {
18
19
  item: T;
19
20
  };
20
21
 
21
- export const [AccordionItemProvider, useAccordionItemContext] =
22
+ // TODO(wittjosiah): This seems to be conflicting with something in the bundle.
23
+ // Perhaps @radix-ui/react-accordion?
24
+ export const [AccordionItemProvider, useDxAccordionItemContext] =
22
25
  createContext<AccordionItemContext<any>>(ACCORDION_ITEM_NAME);
23
26
 
24
27
  export type AccordionItemProps<T extends ListItemRecord> = ThemedClassName<PropsWithChildren<{ item: T }>>;
@@ -40,7 +43,7 @@ export type AccordionItemHeaderProps = ThemedClassName<AccordionPrimitive.Accord
40
43
  export const AccordionItemHeader = ({ classNames, children, ...props }: AccordionItemHeaderProps) => {
41
44
  return (
42
45
  <AccordionPrimitive.Header {...props} className={mx(classNames)}>
43
- <AccordionPrimitive.Trigger className='group flex items-center p-2 dx-focus-ring-inset is-full text-start'>
46
+ <AccordionPrimitive.Trigger className='group flex items-center p-2 dx-focus-ring-inset w-full text-start'>
44
47
  {children}
45
48
  <Icon
46
49
  icon='ph--caret-right--regular'
@@ -56,7 +59,7 @@ export type AccordionItemBodyProps = ThemedClassName<PropsWithChildren>;
56
59
 
57
60
  export const AccordionItemBody = ({ children, classNames }: AccordionItemBodyProps) => {
58
61
  return (
59
- <AccordionPrimitive.Content className='overflow-hidden data-[state=closed]:animate-slideUp data-[state=open]:animate-slideDown'>
62
+ <AccordionPrimitive.Content className='overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down'>
60
63
  <div role='none' className={mx('p-2', classNames)}>
61
64
  {children}
62
65
  </div>
@@ -7,7 +7,7 @@ import { createContext } from '@radix-ui/react-context';
7
7
  import React, { type ReactNode } from 'react';
8
8
 
9
9
  import { type ThemedClassName } from '@dxos/react-ui';
10
- import { mx } from '@dxos/react-ui-theme';
10
+ import { mx } from '@dxos/ui-theme';
11
11
 
12
12
  import { type ListItemRecord } from '../List';
13
13
 
@@ -2,40 +2,43 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
5
+ import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
7
6
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import { Schema } from 'effect';
9
- import React from 'react';
7
+ import * as Schema from 'effect/Schema';
8
+ import React, { useContext, useMemo } from 'react';
10
9
 
11
- import { live } from '@dxos/live-object';
12
- import { ghostHover, mx } from '@dxos/react-ui-theme';
13
- import { withLayout, withTheme } from '@dxos/storybook-utils';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+ import { withRegistry } from '@dxos/storybook-utils';
12
+ import { ghostHover, mx } from '@dxos/ui-theme';
14
13
  import { arrayMove } from '@dxos/util';
15
14
 
16
15
  import { List, type ListRootProps } from './List';
17
- import { createList, TestItemSchema, type TestItemType } from './testing';
16
+ import { TestItemSchema, type TestItemType, type TestList, createList } from './testing';
18
17
 
19
18
  // TODO(burdon): var-icon-size.
20
- const grid = 'grid grid-cols-[32px_1fr_32px] min-bs-[2rem] rounded';
19
+ const grid = 'grid grid-cols-[32px_1fr_32px] min-h-[2rem] rounded-sm';
21
20
 
22
- const meta: Meta = {
23
- title: 'ui/react-ui-list/List',
24
- decorators: [withTheme, withLayout({ fullscreen: true })],
25
- };
26
-
27
- export default meta;
21
+ const DefaultStory = (props: Omit<ListRootProps<TestItemType>, 'items'>) => {
22
+ const registry = useContext(RegistryContext);
23
+ const listAtom = useMemo(() => Atom.make<TestList>(createList(100)).pipe(Atom.keepAlive), []);
24
+ const list = useAtomValue(listAtom);
25
+ const items = list.items;
28
26
 
29
- const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) => {
30
27
  const handleSelect = (item: TestItemType) => {
31
28
  console.log('select', item);
32
29
  };
33
30
  const handleDelete = (item: TestItemType) => {
34
- const idx = items.findIndex((i) => i.id === item.id);
35
- items.splice(idx, 1);
31
+ const prev = registry.get(listAtom);
32
+ registry.set(listAtom, {
33
+ ...prev,
34
+ items: prev.items.filter((i) => i.id !== item.id),
35
+ });
36
36
  };
37
37
  const handleMove = (from: number, to: number) => {
38
- arrayMove(items, from, to);
38
+ const prev = registry.get(listAtom);
39
+ const newItems = [...prev.items];
40
+ arrayMove(newItems, from, to);
41
+ registry.set(listAtom, { ...prev, items: newItems });
39
42
  };
40
43
 
41
44
  return (
@@ -66,7 +69,7 @@ const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) =>
66
69
 
67
70
  <List.ItemDragPreview<TestItemType>>
68
71
  {({ item }) => (
69
- <List.ItemWrapper classNames={mx(grid, 'bg-modalSurface border border-separator')}>
72
+ <List.ItemWrapper classNames={mx(grid, 'bg-modal-surface border border-separator')}>
70
73
  <List.ItemDragHandle />
71
74
  <div className='flex items-center'>{item.name}</div>
72
75
  </List.ItemWrapper>
@@ -78,7 +81,11 @@ const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) =>
78
81
  );
79
82
  };
80
83
 
81
- const SimpleStory = ({ items = [], ...props }: ListRootProps<TestItemType>) => {
84
+ const SimpleStory = (props: Omit<ListRootProps<TestItemType>, 'items'>) => {
85
+ const listAtom = useMemo(() => Atom.make<TestList>(createList(100)).pipe(Atom.keepAlive), []);
86
+ const list = useAtomValue(listAtom);
87
+ const items = list.items;
88
+
82
89
  return (
83
90
  <List.Root<TestItemType> dragPreview items={items} {...props}>
84
91
  {({ items }) => (
@@ -96,20 +103,27 @@ const SimpleStory = ({ items = [], ...props }: ListRootProps<TestItemType>) => {
96
103
  );
97
104
  };
98
105
 
99
- const list = live(createList(100));
106
+ const meta = {
107
+ title: 'ui/react-ui-list/List',
108
+ component: List.Root,
109
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withRegistry],
110
+ parameters: {
111
+ layout: 'fullscreen',
112
+ },
113
+ } satisfies Meta<typeof List.Root>;
114
+
115
+ export default meta;
100
116
 
101
- export const Default: StoryObj<ListRootProps<TestItemType>> = {
117
+ export const Default: StoryObj<typeof DefaultStory> = {
102
118
  render: DefaultStory,
103
119
  args: {
104
- items: list.items,
105
120
  isItem: Schema.is(TestItemSchema),
106
121
  },
107
122
  };
108
123
 
109
- export const Simple: StoryObj<ListRootProps<TestItemType>> = {
124
+ export const Simple: StoryObj<typeof SimpleStory> = {
110
125
  render: SimpleStory,
111
126
  args: {
112
- items: list.items,
113
127
  isItem: Schema.is(TestItemSchema),
114
128
  },
115
129
  };
@@ -3,11 +3,9 @@
3
3
  //
4
4
 
5
5
  import {
6
- IconButton,
7
- type IconButtonProps,
8
6
  ListItem,
9
- ListItemDeleteButton,
10
7
  ListItemButton,
8
+ ListItemDeleteButton,
11
9
  ListItemDragHandle,
12
10
  ListItemDragPreview,
13
11
  type ListItemProps,
@@ -38,9 +36,8 @@ export const List = {
38
36
  ItemDeleteButton: ListItemDeleteButton,
39
37
  ItemButton: ListItemButton,
40
38
  ItemTitle: ListItemTitle,
41
- IconButton,
42
39
  };
43
40
 
44
41
  type ListItem = ListItemRecord;
45
42
 
46
- export type { ListRootProps, ListItemProps, IconButtonProps, ListItem, ListItemRecord };
43
+ export type { ListRootProps, ListItemProps, ListItem, ListItemRecord };
@@ -17,7 +17,6 @@ import React, {
17
17
  type MutableRefObject,
18
18
  type PropsWithChildren,
19
19
  type ReactNode,
20
- forwardRef,
21
20
  useEffect,
22
21
  useRef,
23
22
  useState,
@@ -25,8 +24,14 @@ import React, {
25
24
  import { createPortal } from 'react-dom';
26
25
 
27
26
  import { invariant } from '@dxos/invariant';
28
- import { Icon, type ThemedClassName, ListItem as NaturalListItem } from '@dxos/react-ui';
29
- import { mx } from '@dxos/react-ui-theme';
27
+ import {
28
+ IconButton,
29
+ type IconButtonProps,
30
+ ListItem as NaturalListItem,
31
+ type ThemedClassName,
32
+ useTranslation,
33
+ } from '@dxos/react-ui';
34
+ import { mx, osTranslations } from '@dxos/ui-theme';
30
35
 
31
36
  import { useListContext } from './ListRoot';
32
37
 
@@ -41,17 +46,17 @@ export type ItemDragState =
41
46
  container: HTMLElement;
42
47
  }
43
48
  | {
44
- type: 'is-dragging';
49
+ type: 'w-dragging';
45
50
  }
46
51
  | {
47
- type: 'is-dragging-over';
52
+ type: 'w-dragging-over';
48
53
  closestEdge: Edge | null;
49
54
  };
50
55
 
51
56
  export const idle: ItemDragState = { type: 'idle' };
52
57
 
53
58
  const stateStyles: { [Key in ItemDragState['type']]?: HTMLAttributes<HTMLDivElement>['className'] } = {
54
- 'is-dragging': 'opacity-50',
59
+ 'w-dragging': 'opacity-50',
55
60
  };
56
61
 
57
62
  type ListItemContext<T extends ListItemRecord> = {
@@ -119,8 +124,8 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
119
124
  }
120
125
  : undefined,
121
126
  onDragStart: () => {
122
- setState({ type: 'is-dragging' });
123
- setRootState({ type: 'is-dragging', item });
127
+ setState({ type: 'w-dragging' });
128
+ setRootState({ type: 'w-dragging', item });
124
129
  },
125
130
  onDrop: () => {
126
131
  setState(idle);
@@ -142,7 +147,7 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
142
147
  getIsSticky: () => true,
143
148
  onDragEnter: ({ self }) => {
144
149
  const closestEdge = extractClosestEdge(self.data);
145
- setState({ type: 'is-dragging-over', closestEdge });
150
+ setState({ type: 'w-dragging-over', closestEdge });
146
151
  },
147
152
  onDragLeave: () => {
148
153
  setState(idle);
@@ -150,10 +155,10 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
150
155
  onDrag: ({ self }) => {
151
156
  const closestEdge = extractClosestEdge(self.data);
152
157
  setState((current) => {
153
- if (current.type === 'is-dragging-over' && current.closestEdge === closestEdge) {
158
+ if (current.type === 'w-dragging-over' && current.closestEdge === closestEdge) {
154
159
  return current;
155
160
  }
156
- return { type: 'is-dragging-over', closestEdge };
161
+ return { type: 'w-dragging-over', closestEdge };
157
162
  });
158
163
  },
159
164
  onDrop: () => {
@@ -165,16 +170,9 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
165
170
 
166
171
  return (
167
172
  <ListItemProvider item={item} dragHandleRef={dragHandleRef}>
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
- >
175
- {children}
176
- </div>
177
- {state.type === 'is-dragging-over' && state.closestEdge && (
173
+ <div ref={ref} role='listitem' className={mx('flex relative', classNames, stateStyles[state.type])} {...props}>
174
+ {children}
175
+ {state.type === 'w-dragging-over' && state.closestEdge && (
178
176
  <NaturalListItem.DropIndicator edge={state.closestEdge} />
179
177
  )}
180
178
  </div>
@@ -186,51 +184,65 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
186
184
  // List item components
187
185
  //
188
186
 
189
- export type IconButtonProps = ThemedClassName<ComponentProps<'button'>> & { icon: string };
190
-
191
- export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
192
- ({ classNames, icon, ...props }, forwardedRef) => {
193
- return (
194
- <button ref={forwardedRef} className={mx('flex items-center justify-center', classNames)} {...props}>
195
- <Icon icon={icon} classNames='cursor-pointer' size={4} />
196
- </button>
197
- );
198
- },
199
- );
200
-
201
187
  export const ListItemDeleteButton = ({
202
188
  autoHide = true,
203
189
  classNames,
204
190
  disabled,
205
191
  icon = 'ph--x--regular',
192
+ label,
206
193
  ...props
207
- }: Partial<Pick<IconButtonProps, 'icon'>> & Omit<IconButtonProps, 'icon'> & { autoHide?: boolean }) => {
194
+ }: Partial<Pick<IconButtonProps, 'icon'>> &
195
+ Omit<IconButtonProps, 'icon' | 'label'> & { autoHide?: boolean; label?: string }) => {
208
196
  const { state } = useListContext('DELETE_BUTTON');
209
197
  const isDisabled = state.type !== 'idle' || disabled;
198
+ const { t } = useTranslation(osTranslations);
210
199
  return (
211
200
  <IconButton
201
+ iconOnly
202
+ variant='ghost'
203
+ {...props}
212
204
  icon={icon}
213
205
  disabled={isDisabled}
206
+ label={label ?? t('delete label')}
214
207
  classNames={[classNames, autoHide && disabled && 'hidden']}
215
- {...props}
216
208
  />
217
209
  );
218
210
  };
219
211
 
220
212
  export const ListItemButton = ({
221
213
  autoHide = true,
214
+ iconOnly = true,
215
+ variant = 'ghost',
222
216
  classNames,
223
217
  disabled,
224
218
  ...props
225
219
  }: IconButtonProps & { autoHide?: boolean }) => {
226
220
  const { state } = useListContext('ITEM_BUTTON');
227
221
  const isDisabled = state.type !== 'idle' || disabled;
228
- return <IconButton disabled={isDisabled} classNames={[classNames, autoHide && disabled && 'hidden']} {...props} />;
222
+ return (
223
+ <IconButton
224
+ {...props}
225
+ disabled={isDisabled}
226
+ iconOnly={iconOnly}
227
+ variant={variant}
228
+ classNames={[classNames, autoHide && disabled && 'hidden']}
229
+ />
230
+ );
229
231
  };
230
232
 
231
233
  export const ListItemDragHandle = ({ disabled }: Pick<IconButtonProps, 'disabled'>) => {
232
234
  const { dragHandleRef } = useListItemContext('DRAG_HANDLE');
233
- return <IconButton ref={dragHandleRef as any} icon='ph--dots-six-vertical--regular' disabled={disabled} />;
235
+ const { t } = useTranslation(osTranslations);
236
+ return (
237
+ <IconButton
238
+ iconOnly
239
+ variant='ghost'
240
+ label={t('drag handle label')}
241
+ ref={dragHandleRef as any}
242
+ icon='ph--dots-six-vertical--regular'
243
+ disabled={disabled}
244
+ />
245
+ );
234
246
  };
235
247
 
236
248
  export const ListItemDragPreview = <T extends ListItemRecord>({
@@ -243,7 +255,7 @@ export const ListItemDragPreview = <T extends ListItemRecord>({
243
255
  };
244
256
 
245
257
  export const ListItemWrapper = ({ classNames, children }: ThemedClassName<PropsWithChildren>) => (
246
- <div className={mx('flex is-full gap-2', classNames)}>{children}</div>
258
+ <div className={mx('flex w-full gap-2', classNames)}>{children}</div>
247
259
  );
248
260
 
249
261
  export const ListItemTitle = ({
@@ -8,7 +8,7 @@ import { getReorderDestinationIndex } from '@atlaskit/pragmatic-drag-and-drop-hi
8
8
  import { createContext } from '@radix-ui/react-context';
9
9
  import React, { type ReactNode, useCallback, useEffect, useState } from 'react';
10
10
 
11
- import { idle, type ItemDragState, type ListItemRecord } from './ListItem';
11
+ import { type ItemDragState, type ListItemRecord, idle } from './ListItem';
12
12
 
13
13
  type ListContext<T extends ListItemRecord> = {
14
14
  // TODO(burdon): Rename drag state.
@@ -26,14 +26,14 @@ export const [ListProvider, useListContext] = createContext<ListContext<any>>(LI
26
26
 
27
27
  export type ListRendererProps<T extends ListItemRecord> = {
28
28
  state: ListContext<T>['state'];
29
- items: T[];
29
+ items: readonly T[];
30
30
  };
31
31
 
32
32
  const defaultGetId = <T extends ListItemRecord>(item: T) => (item as any)?.id;
33
33
 
34
34
  export type ListRootProps<T extends ListItemRecord> = {
35
35
  children?: (props: ListRendererProps<T>) => ReactNode;
36
- items?: T[];
36
+ items?: readonly T[];
37
37
  onMove?: (fromIndex: number, toIndex: number) => void;
38
38
  } & Pick<ListContext<T>, 'isItem' | 'getId' | 'readonly' | 'dragPreview'>;
39
39
 
@@ -2,13 +2,13 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
- import { ObjectId } from '@dxos/echo-schema';
7
+ import { Obj } from '@dxos/echo';
8
8
  import { faker } from '@dxos/random';
9
9
 
10
10
  export const TestItemSchema = Schema.Struct({
11
- id: ObjectId,
11
+ id: Obj.ID,
12
12
  name: Schema.String,
13
13
  });
14
14