@dxos/react-ui-list 0.8.3 → 0.8.4-main.1068cf700f

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 +675 -730
  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 +675 -730
  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 +5 -8
  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 +7 -4
  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 +7 -4
  26. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  27. package/dist/types/src/components/Tree/TreeItem.d.ts +24 -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/testing.d.ts +3 -3
  34. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  35. package/dist/types/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +31 -30
  37. package/src/components/Accordion/Accordion.stories.tsx +7 -9
  38. package/src/components/Accordion/Accordion.tsx +1 -1
  39. package/src/components/Accordion/AccordionItem.tsx +7 -4
  40. package/src/components/Accordion/AccordionRoot.tsx +1 -1
  41. package/src/components/List/List.stories.tsx +43 -29
  42. package/src/components/List/List.tsx +2 -5
  43. package/src/components/List/ListItem.tsx +49 -35
  44. package/src/components/List/ListRoot.tsx +3 -3
  45. package/src/components/List/testing.ts +3 -3
  46. package/src/components/Tree/Tree.stories.tsx +102 -85
  47. package/src/components/Tree/Tree.tsx +22 -9
  48. package/src/components/Tree/TreeContext.tsx +7 -4
  49. package/src/components/Tree/TreeItem.tsx +66 -54
  50. package/src/components/Tree/TreeItemHeading.tsx +11 -9
  51. package/src/components/Tree/TreeItemToggle.tsx +29 -19
  52. package/src/components/Tree/testing.ts +5 -4
  53. package/dist/lib/node/index.cjs +0 -886
  54. package/dist/lib/node/index.cjs.map +0 -7
  55. package/dist/lib/node/meta.json +0 -1
package/package.json CHANGED
@@ -1,14 +1,19 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-list",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.1068cf700f",
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,41 +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.3",
33
- "@dxos/invariant": "0.8.3",
34
- "@dxos/echo-schema": "0.8.3",
35
- "@dxos/live-object": "0.8.3",
36
- "@dxos/log": "0.8.3",
37
- "@dxos/react-ui-text-tooltip": "0.8.3",
38
- "@dxos/react-ui-types": "0.8.3",
39
- "@dxos/util": "0.8.3"
36
+ "@dxos/debug": "0.8.4-main.1068cf700f",
37
+ "@dxos/echo": "0.8.4-main.1068cf700f",
38
+ "@dxos/log": "0.8.4-main.1068cf700f",
39
+ "@dxos/invariant": "0.8.4-main.1068cf700f",
40
+ "@dxos/react-ui-text-tooltip": "0.8.4-main.1068cf700f",
41
+ "@dxos/react-ui": "0.8.4-main.1068cf700f",
42
+ "@dxos/ui-types": "0.8.4-main.1068cf700f",
43
+ "@dxos/ui-theme": "0.8.4-main.1068cf700f",
44
+ "@dxos/util": "0.8.4-main.1068cf700f"
40
45
  },
41
46
  "devDependencies": {
42
- "@phosphor-icons/react": "^2.1.5",
43
- "@types/react": "~18.2.0",
44
- "@types/react-dom": "~18.2.0",
45
- "effect": "3.14.21",
46
- "react": "~18.2.0",
47
- "react-dom": "~18.2.0",
48
- "vite": "5.4.7",
49
- "@dxos/random": "0.8.3",
50
- "@dxos/react-ui-theme": "0.8.3",
51
- "@dxos/react-ui": "0.8.3",
52
- "@dxos/storybook-utils": "0.8.3"
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.9",
53
+ "@dxos/random": "0.8.4-main.1068cf700f",
54
+ "@dxos/storybook-utils": "0.8.4-main.1068cf700f"
53
55
  },
54
56
  "peerDependencies": {
55
- "@phosphor-icons/react": "^2.1.5",
56
- "effect": "3.13.3",
57
- "react": "~18.2.0",
58
- "react-dom": "~18.2.0",
59
- "@dxos/react-ui-theme": "0.8.3",
60
- "@dxos/react-ui": "0.8.3"
57
+ "effect": "3.19.16",
58
+ "react": "~19.2.3",
59
+ "react-dom": "~19.2.3",
60
+ "@dxos/react-ui": "0.8.4-main.1068cf700f",
61
+ "@dxos/ui-theme": "0.8.4-main.1068cf700f"
61
62
  },
62
63
  "publishConfig": {
63
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';
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
 
@@ -24,9 +22,9 @@ const items: TestItem[] = Array.from({ length: 10 }, (_, i) => ({
24
22
 
25
23
  const DefaultStory = () => {
26
24
  return (
27
- <Accordion.Root<TestItem> items={items} classNames='w-[40rem]'>
25
+ <Accordion.Root<TestItem> items={items} classNames='is-[40rem]'>
28
26
  {({ items }) => (
29
- <div className='flex flex-col w-full border-y border-separator divide-y divide-separator'>
27
+ <div className='flex flex-col is-full border-y border-separator divide-y divide-separator'>
30
28
  {items.map((item) => (
31
29
  <Accordion.Item key={item.id} item={item} classNames='border-x border-separator'>
32
30
  <Accordion.ItemHeader>{item.name}</Accordion.ItemHeader>
@@ -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 }>>;
@@ -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,53 +2,56 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type Meta, type StoryObj } from '@storybook/react';
8
- import { Schema } from 'effect';
9
- import React from 'react';
10
-
11
- import { live } from '@dxos/live-object';
12
- import { ghostHover, mx } from '@dxos/react-ui-theme';
13
- import { withLayout, withTheme } from '@dxos/storybook-utils';
5
+ import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import * as Schema from 'effect/Schema';
8
+ import React, { useContext, useMemo } from 'react';
9
+
10
+ import { 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
19
  const grid = 'grid grid-cols-[32px_1fr_32px] min-bs-[2rem] rounded';
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 (
42
45
  <List.Root<TestItemType> dragPreview items={items} getId={(item) => item.id} onMove={handleMove} {...props}>
43
46
  {({ items }) => (
44
47
  <>
45
- <div className='flex flex-col w-full'>
48
+ <div className='flex flex-col is-full'>
46
49
  <div role='none' className={grid}>
47
50
  <div />
48
51
  <div className='flex items-center text-sm'>Items</div>
49
52
  </div>
50
53
 
51
- <div role='list' className='w-full h-full overflow-auto'>
54
+ <div role='list' className='is-full bs-full overflow-auto'>
52
55
  {items?.map((item) => (
53
56
  <List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid, ghostHover)}>
54
57
  <List.ItemDragHandle />
@@ -78,11 +81,15 @@ 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 }) => (
85
- <div role='list' className='w-full h-full overflow-auto'>
92
+ <div role='list' className='is-full bs-full overflow-auto'>
86
93
  {items?.map((item) => (
87
94
  <List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid, ghostHover)}>
88
95
  <List.ItemDragHandle />
@@ -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(), 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
 
@@ -72,10 +77,11 @@ export const [ListItemProvider, useListItemContext] = createContext<ListItemCont
72
77
  );
73
78
 
74
79
  export type ListItemProps<T extends ListItemRecord> = ThemedClassName<
75
- PropsWithChildren<{
76
- item: T;
77
- }> &
78
- HTMLAttributes<HTMLDivElement>
80
+ PropsWithChildren<
81
+ {
82
+ item: T;
83
+ } & HTMLAttributes<HTMLDivElement>
84
+ >
79
85
  >;
80
86
 
81
87
  /**
@@ -86,6 +92,7 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
86
92
  const ref = useRef<HTMLDivElement | null>(null);
87
93
  const dragHandleRef = useRef<HTMLElement | null>(null);
88
94
  const [state, setState] = useState<ItemDragState>(idle);
95
+
89
96
  useEffect(() => {
90
97
  const element = ref.current;
91
98
  invariant(element);
@@ -142,6 +149,9 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
142
149
  const closestEdge = extractClosestEdge(self.data);
143
150
  setState({ type: 'is-dragging-over', closestEdge });
144
151
  },
152
+ onDragLeave: () => {
153
+ setState(idle);
154
+ },
145
155
  onDrag: ({ self }) => {
146
156
  const closestEdge = extractClosestEdge(self.data);
147
157
  setState((current) => {
@@ -151,9 +161,6 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
151
161
  return { type: 'is-dragging-over', closestEdge };
152
162
  });
153
163
  },
154
- onDragLeave: () => {
155
- setState(idle);
156
- },
157
164
  onDrop: () => {
158
165
  setState(idle);
159
166
  },
@@ -163,15 +170,8 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
163
170
 
164
171
  return (
165
172
  <ListItemProvider item={item} dragHandleRef={dragHandleRef}>
166
- <div role='none' className='relative'>
167
- <div
168
- ref={ref}
169
- role='listitem'
170
- className={mx('flex overflow-hidden', classNames, stateStyles[state.type])}
171
- {...props}
172
- >
173
- {children}
174
- </div>
173
+ <div ref={ref} role='listitem' className={mx('flex relative', classNames, stateStyles[state.type])} {...props}>
174
+ {children}
175
175
  {state.type === 'is-dragging-over' && state.closestEdge && (
176
176
  <NaturalListItem.DropIndicator edge={state.closestEdge} />
177
177
  )}
@@ -184,51 +184,65 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
184
184
  // List item components
185
185
  //
186
186
 
187
- export type IconButtonProps = ThemedClassName<ComponentProps<'button'>> & { icon: string };
188
-
189
- export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
190
- ({ classNames, icon, ...props }, forwardedRef) => {
191
- return (
192
- <button ref={forwardedRef} className={mx('flex items-center justify-center', classNames)} {...props}>
193
- <Icon icon={icon} classNames='cursor-pointer' size={4} />
194
- </button>
195
- );
196
- },
197
- );
198
-
199
187
  export const ListItemDeleteButton = ({
200
188
  autoHide = true,
201
189
  classNames,
202
190
  disabled,
203
191
  icon = 'ph--x--regular',
192
+ label,
204
193
  ...props
205
- }: Partial<Pick<IconButtonProps, 'icon'>> & Omit<IconButtonProps, 'icon'> & { autoHide?: boolean }) => {
194
+ }: Partial<Pick<IconButtonProps, 'icon'>> &
195
+ Omit<IconButtonProps, 'icon' | 'label'> & { autoHide?: boolean; label?: string }) => {
206
196
  const { state } = useListContext('DELETE_BUTTON');
207
197
  const isDisabled = state.type !== 'idle' || disabled;
198
+ const { t } = useTranslation(osTranslations);
208
199
  return (
209
200
  <IconButton
201
+ iconOnly
202
+ variant='ghost'
203
+ {...props}
210
204
  icon={icon}
211
205
  disabled={isDisabled}
206
+ label={label ?? t('delete label')}
212
207
  classNames={[classNames, autoHide && disabled && 'hidden']}
213
- {...props}
214
208
  />
215
209
  );
216
210
  };
217
211
 
218
212
  export const ListItemButton = ({
219
213
  autoHide = true,
214
+ iconOnly = true,
215
+ variant = 'ghost',
220
216
  classNames,
221
217
  disabled,
222
218
  ...props
223
219
  }: IconButtonProps & { autoHide?: boolean }) => {
224
220
  const { state } = useListContext('ITEM_BUTTON');
225
221
  const isDisabled = state.type !== 'idle' || disabled;
226
- 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
+ );
227
231
  };
228
232
 
229
233
  export const ListItemDragHandle = ({ disabled }: Pick<IconButtonProps, 'disabled'>) => {
230
234
  const { dragHandleRef } = useListItemContext('DRAG_HANDLE');
231
- 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
+ );
232
246
  };
233
247
 
234
248
  export const ListItemDragPreview = <T extends ListItemRecord>({
@@ -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