@dxos/react-ui-list 0.8.4-main.406dc2a → 0.8.4-main.40e3dcdf1b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +667 -711
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +667 -711
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Accordion/Accordion.stories.d.ts +0 -3
- package/dist/types/src/components/Accordion/Accordion.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts +6 -6
- package/dist/types/src/components/List/List.d.ts.map +1 -1
- package/dist/types/src/components/List/List.stories.d.ts +2 -2
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/ListItem.d.ts +8 -6
- package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
- package/dist/types/src/components/List/ListRoot.d.ts +2 -2
- package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.d.ts +10 -6
- package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +9 -28
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeContext.d.ts +22 -9
- package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItem.d.ts +20 -3
- package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItemHeading.d.ts +1 -1
- package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +2 -0
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/testing.d.ts +2 -2
- package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -28
- package/src/components/Accordion/Accordion.stories.tsx +2 -5
- package/src/components/Accordion/AccordionItem.tsx +3 -3
- package/src/components/Accordion/AccordionRoot.tsx +1 -1
- package/src/components/List/List.stories.tsx +31 -19
- package/src/components/List/List.tsx +2 -2
- package/src/components/List/ListItem.tsx +53 -35
- package/src/components/List/ListRoot.tsx +2 -2
- package/src/components/List/testing.ts +2 -2
- package/src/components/Tree/Tree.stories.tsx +150 -60
- package/src/components/Tree/Tree.tsx +39 -41
- package/src/components/Tree/TreeContext.tsx +19 -8
- package/src/components/Tree/TreeItem.tsx +173 -103
- package/src/components/Tree/TreeItemHeading.tsx +9 -5
- package/src/components/Tree/TreeItemToggle.tsx +1 -1
- package/src/components/Tree/index.ts +2 -0
- package/src/components/Tree/testing.ts +4 -3
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-list",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.40e3dcdf1b",
|
|
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",
|
|
@@ -24,39 +28,38 @@
|
|
|
24
28
|
"src"
|
|
25
29
|
],
|
|
26
30
|
"dependencies": {
|
|
27
|
-
"@atlaskit/pragmatic-drag-and-drop": "
|
|
28
|
-
"@atlaskit/pragmatic-drag-and-drop-hitbox": "
|
|
29
|
-
"@
|
|
30
|
-
"@preact/signals-core": "^1.12.1",
|
|
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",
|
|
31
34
|
"@radix-ui/react-accordion": "1.2.3",
|
|
32
35
|
"@radix-ui/react-context": "1.1.1",
|
|
33
|
-
"@
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/echo": "0.8.4-main.
|
|
36
|
-
"@dxos/
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/react-ui
|
|
40
|
-
"@dxos/react-ui-
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/util": "0.8.4-main.
|
|
36
|
+
"@radix-ui/react-slot": "1.1.2",
|
|
37
|
+
"@dxos/debug": "0.8.4-main.40e3dcdf1b",
|
|
38
|
+
"@dxos/echo": "0.8.4-main.40e3dcdf1b",
|
|
39
|
+
"@dxos/invariant": "0.8.4-main.40e3dcdf1b",
|
|
40
|
+
"@dxos/log": "0.8.4-main.40e3dcdf1b",
|
|
41
|
+
"@dxos/ui-theme": "0.8.4-main.40e3dcdf1b",
|
|
42
|
+
"@dxos/react-ui": "0.8.4-main.40e3dcdf1b",
|
|
43
|
+
"@dxos/react-ui-text-tooltip": "0.8.4-main.40e3dcdf1b",
|
|
44
|
+
"@dxos/ui-types": "0.8.4-main.40e3dcdf1b",
|
|
45
|
+
"@dxos/util": "0.8.4-main.40e3dcdf1b"
|
|
43
46
|
},
|
|
44
47
|
"devDependencies": {
|
|
45
|
-
"@types/react": "~19.2.
|
|
46
|
-
"@types/react-dom": "~19.2.
|
|
47
|
-
"effect": "3.
|
|
48
|
-
"react": "~19.2.
|
|
49
|
-
"react-dom": "~19.2.
|
|
50
|
-
"vite": "7.1.
|
|
51
|
-
"@dxos/random": "0.8.4-main.
|
|
52
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
48
|
+
"@types/react": "~19.2.7",
|
|
49
|
+
"@types/react-dom": "~19.2.3",
|
|
50
|
+
"effect": "3.19.16",
|
|
51
|
+
"react": "~19.2.3",
|
|
52
|
+
"react-dom": "~19.2.3",
|
|
53
|
+
"vite": "^7.1.11",
|
|
54
|
+
"@dxos/random": "0.8.4-main.40e3dcdf1b",
|
|
55
|
+
"@dxos/storybook-utils": "0.8.4-main.40e3dcdf1b"
|
|
53
56
|
},
|
|
54
57
|
"peerDependencies": {
|
|
55
|
-
"effect": "
|
|
56
|
-
"react": "
|
|
57
|
-
"react-dom": "
|
|
58
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
59
|
-
"@dxos/
|
|
58
|
+
"effect": "3.19.16",
|
|
59
|
+
"react": "~19.2.3",
|
|
60
|
+
"react-dom": "~19.2.3",
|
|
61
|
+
"@dxos/react-ui": "0.8.4-main.40e3dcdf1b",
|
|
62
|
+
"@dxos/ui-theme": "0.8.4-main.40e3dcdf1b"
|
|
60
63
|
},
|
|
61
64
|
"publishConfig": {
|
|
62
65
|
"access": "public"
|
|
@@ -6,7 +6,7 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
8
|
import { faker } from '@dxos/random';
|
|
9
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
10
|
|
|
11
11
|
import { Accordion } from './Accordion';
|
|
12
12
|
|
|
@@ -42,10 +42,7 @@ const DefaultStory = () => {
|
|
|
42
42
|
const meta = {
|
|
43
43
|
title: 'ui/react-ui-list/Accordion',
|
|
44
44
|
render: DefaultStory,
|
|
45
|
-
decorators: [withTheme],
|
|
46
|
-
parameters: {
|
|
47
|
-
layout: 'column',
|
|
48
|
-
},
|
|
45
|
+
decorators: [withTheme(), withLayout({ layout: 'column' })],
|
|
49
46
|
} satisfies Meta<typeof Accordion>;
|
|
50
47
|
|
|
51
48
|
export default meta;
|
|
@@ -7,7 +7,7 @@ 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/
|
|
10
|
+
import { mx } from '@dxos/ui-theme';
|
|
11
11
|
|
|
12
12
|
import { type ListItemRecord } from '../List';
|
|
13
13
|
|
|
@@ -43,7 +43,7 @@ export type AccordionItemHeaderProps = ThemedClassName<AccordionPrimitive.Accord
|
|
|
43
43
|
export const AccordionItemHeader = ({ classNames, children, ...props }: AccordionItemHeaderProps) => {
|
|
44
44
|
return (
|
|
45
45
|
<AccordionPrimitive.Header {...props} className={mx(classNames)}>
|
|
46
|
-
<AccordionPrimitive.Trigger className='group flex items-center p-2 dx-focus-ring-inset
|
|
46
|
+
<AccordionPrimitive.Trigger className='group flex items-center p-2 dx-focus-ring-inset w-full text-start'>
|
|
47
47
|
{children}
|
|
48
48
|
<Icon
|
|
49
49
|
icon='ph--caret-right--regular'
|
|
@@ -59,7 +59,7 @@ export type AccordionItemBodyProps = ThemedClassName<PropsWithChildren>;
|
|
|
59
59
|
|
|
60
60
|
export const AccordionItemBody = ({ children, classNames }: AccordionItemBodyProps) => {
|
|
61
61
|
return (
|
|
62
|
-
<AccordionPrimitive.Content className='overflow-hidden data-[state=closed]:animate-
|
|
62
|
+
<AccordionPrimitive.Content className='overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down'>
|
|
63
63
|
<div role='none' className={mx('p-2', classNames)}>
|
|
64
64
|
{children}
|
|
65
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/
|
|
10
|
+
import { mx } from '@dxos/ui-theme';
|
|
11
11
|
|
|
12
12
|
import { type ListItemRecord } from '../List';
|
|
13
13
|
|
|
@@ -2,31 +2,43 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
5
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
7
|
import * as Schema from 'effect/Schema';
|
|
7
|
-
import React from 'react';
|
|
8
|
+
import React, { useContext, useMemo } from 'react';
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { ghostHover, mx } from '@dxos/
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
12
|
+
import { ghostHover, mx } from '@dxos/ui-theme';
|
|
12
13
|
import { arrayMove } from '@dxos/util';
|
|
13
14
|
|
|
14
15
|
import { List, type ListRootProps } from './List';
|
|
15
|
-
import { TestItemSchema, type TestItemType, createList } from './testing';
|
|
16
|
+
import { TestItemSchema, type TestItemType, type TestList, createList } from './testing';
|
|
16
17
|
|
|
17
18
|
// TODO(burdon): var-icon-size.
|
|
18
|
-
const grid = 'grid grid-cols-[32px_1fr_32px] min-
|
|
19
|
+
const grid = 'grid grid-cols-[32px_1fr_32px] min-h-[2rem] rounded-sm';
|
|
20
|
+
|
|
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;
|
|
19
26
|
|
|
20
|
-
const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) => {
|
|
21
27
|
const handleSelect = (item: TestItemType) => {
|
|
22
28
|
console.log('select', item);
|
|
23
29
|
};
|
|
24
30
|
const handleDelete = (item: TestItemType) => {
|
|
25
|
-
const
|
|
26
|
-
|
|
31
|
+
const prev = registry.get(listAtom);
|
|
32
|
+
registry.set(listAtom, {
|
|
33
|
+
...prev,
|
|
34
|
+
items: prev.items.filter((i) => i.id !== item.id),
|
|
35
|
+
});
|
|
27
36
|
};
|
|
28
37
|
const handleMove = (from: number, to: number) => {
|
|
29
|
-
|
|
38
|
+
const prev = registry.get(listAtom);
|
|
39
|
+
const newItems = [...prev.items];
|
|
40
|
+
arrayMove(newItems, from, to);
|
|
41
|
+
registry.set(listAtom, { ...prev, items: newItems });
|
|
30
42
|
};
|
|
31
43
|
|
|
32
44
|
return (
|
|
@@ -41,7 +53,7 @@ const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) =>
|
|
|
41
53
|
|
|
42
54
|
<div role='list' className='w-full h-full overflow-auto'>
|
|
43
55
|
{items?.map((item) => (
|
|
44
|
-
<List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid
|
|
56
|
+
<List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid)}>
|
|
45
57
|
<List.ItemDragHandle />
|
|
46
58
|
<List.ItemTitle onClick={() => handleSelect(item)}>{item.name}</List.ItemTitle>
|
|
47
59
|
<List.ItemDeleteButton onClick={() => handleDelete(item)} />
|
|
@@ -57,7 +69,7 @@ const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) =>
|
|
|
57
69
|
|
|
58
70
|
<List.ItemDragPreview<TestItemType>>
|
|
59
71
|
{({ item }) => (
|
|
60
|
-
<List.ItemWrapper classNames={mx(grid, 'bg-
|
|
72
|
+
<List.ItemWrapper classNames={mx(grid, 'bg-modal-surface border border-separator')}>
|
|
61
73
|
<List.ItemDragHandle />
|
|
62
74
|
<div className='flex items-center'>{item.name}</div>
|
|
63
75
|
</List.ItemWrapper>
|
|
@@ -69,13 +81,17 @@ const DefaultStory = ({ items = [], ...props }: ListRootProps<TestItemType>) =>
|
|
|
69
81
|
);
|
|
70
82
|
};
|
|
71
83
|
|
|
72
|
-
const SimpleStory = (
|
|
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
|
+
|
|
73
89
|
return (
|
|
74
90
|
<List.Root<TestItemType> dragPreview items={items} {...props}>
|
|
75
91
|
{({ items }) => (
|
|
76
92
|
<div role='list' className='w-full h-full overflow-auto'>
|
|
77
93
|
{items?.map((item) => (
|
|
78
|
-
<List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid
|
|
94
|
+
<List.Item<TestItemType> key={item.id} item={item} classNames={mx(grid)}>
|
|
79
95
|
<List.ItemDragHandle />
|
|
80
96
|
<List.ItemTitle>{item.name}</List.ItemTitle>
|
|
81
97
|
<List.ItemDeleteButton />
|
|
@@ -87,12 +103,10 @@ const SimpleStory = ({ items = [], ...props }: ListRootProps<TestItemType>) => {
|
|
|
87
103
|
);
|
|
88
104
|
};
|
|
89
105
|
|
|
90
|
-
const list = live(createList(100));
|
|
91
|
-
|
|
92
106
|
const meta = {
|
|
93
107
|
title: 'ui/react-ui-list/List',
|
|
94
108
|
component: List.Root,
|
|
95
|
-
decorators: [withTheme],
|
|
109
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withRegistry],
|
|
96
110
|
parameters: {
|
|
97
111
|
layout: 'fullscreen',
|
|
98
112
|
},
|
|
@@ -103,7 +117,6 @@ export default meta;
|
|
|
103
117
|
export const Default: StoryObj<typeof DefaultStory> = {
|
|
104
118
|
render: DefaultStory,
|
|
105
119
|
args: {
|
|
106
|
-
items: list.items,
|
|
107
120
|
isItem: Schema.is(TestItemSchema),
|
|
108
121
|
},
|
|
109
122
|
};
|
|
@@ -111,7 +124,6 @@ export const Default: StoryObj<typeof DefaultStory> = {
|
|
|
111
124
|
export const Simple: StoryObj<typeof SimpleStory> = {
|
|
112
125
|
render: SimpleStory,
|
|
113
126
|
args: {
|
|
114
|
-
items: list.items,
|
|
115
127
|
isItem: Schema.is(TestItemSchema),
|
|
116
128
|
},
|
|
117
129
|
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
ListItem,
|
|
7
|
-
|
|
7
|
+
ListItemIconButton,
|
|
8
8
|
ListItemDeleteButton,
|
|
9
9
|
ListItemDragHandle,
|
|
10
10
|
ListItemDragPreview,
|
|
@@ -33,8 +33,8 @@ export const List = {
|
|
|
33
33
|
ItemDragPreview: ListItemDragPreview,
|
|
34
34
|
ItemWrapper: ListItemWrapper,
|
|
35
35
|
ItemDragHandle: ListItemDragHandle,
|
|
36
|
+
ItemIconButton: ListItemIconButton,
|
|
36
37
|
ItemDeleteButton: ListItemDeleteButton,
|
|
37
|
-
ItemButton: ListItemButton,
|
|
38
38
|
ItemTitle: ListItemTitle,
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
extractClosestEdge,
|
|
12
12
|
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
13
13
|
import { createContext } from '@radix-ui/react-context';
|
|
14
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
14
15
|
import React, {
|
|
15
16
|
type ComponentProps,
|
|
16
17
|
type HTMLAttributes,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
type ThemedClassName,
|
|
32
33
|
useTranslation,
|
|
33
34
|
} from '@dxos/react-ui';
|
|
34
|
-
import { mx } from '@dxos/
|
|
35
|
+
import { mx, osTranslations } from '@dxos/ui-theme';
|
|
35
36
|
|
|
36
37
|
import { useListContext } from './ListRoot';
|
|
37
38
|
|
|
@@ -46,17 +47,17 @@ export type ItemDragState =
|
|
|
46
47
|
container: HTMLElement;
|
|
47
48
|
}
|
|
48
49
|
| {
|
|
49
|
-
type: '
|
|
50
|
+
type: 'w-dragging';
|
|
50
51
|
}
|
|
51
52
|
| {
|
|
52
|
-
type: '
|
|
53
|
+
type: 'w-dragging-over';
|
|
53
54
|
closestEdge: Edge | null;
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
export const idle: ItemDragState = { type: 'idle' };
|
|
57
58
|
|
|
58
59
|
const stateStyles: { [Key in ItemDragState['type']]?: HTMLAttributes<HTMLDivElement>['className'] } = {
|
|
59
|
-
'
|
|
60
|
+
'w-dragging': 'opacity-50',
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
type ListItemContext<T extends ListItemRecord> = {
|
|
@@ -80,6 +81,8 @@ export type ListItemProps<T extends ListItemRecord> = ThemedClassName<
|
|
|
80
81
|
PropsWithChildren<
|
|
81
82
|
{
|
|
82
83
|
item: T;
|
|
84
|
+
asChild?: boolean;
|
|
85
|
+
selected?: boolean;
|
|
83
86
|
} & HTMLAttributes<HTMLDivElement>
|
|
84
87
|
>
|
|
85
88
|
>;
|
|
@@ -87,7 +90,15 @@ export type ListItemProps<T extends ListItemRecord> = ThemedClassName<
|
|
|
87
90
|
/**
|
|
88
91
|
* Draggable list item.
|
|
89
92
|
*/
|
|
90
|
-
export const ListItem = <T extends ListItemRecord>({
|
|
93
|
+
export const ListItem = <T extends ListItemRecord>({
|
|
94
|
+
children,
|
|
95
|
+
classNames,
|
|
96
|
+
item,
|
|
97
|
+
asChild,
|
|
98
|
+
selected,
|
|
99
|
+
...props
|
|
100
|
+
}: ListItemProps<T>) => {
|
|
101
|
+
const Comp = asChild ? Slot : 'div';
|
|
91
102
|
const { isItem, readonly, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
|
|
92
103
|
const ref = useRef<HTMLDivElement | null>(null);
|
|
93
104
|
const dragHandleRef = useRef<HTMLElement | null>(null);
|
|
@@ -124,8 +135,8 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
|
|
|
124
135
|
}
|
|
125
136
|
: undefined,
|
|
126
137
|
onDragStart: () => {
|
|
127
|
-
setState({ type: '
|
|
128
|
-
setRootState({ type: '
|
|
138
|
+
setState({ type: 'w-dragging' });
|
|
139
|
+
setRootState({ type: 'w-dragging', item });
|
|
129
140
|
},
|
|
130
141
|
onDrop: () => {
|
|
131
142
|
setState(idle);
|
|
@@ -147,7 +158,7 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
|
|
|
147
158
|
getIsSticky: () => true,
|
|
148
159
|
onDragEnter: ({ self }) => {
|
|
149
160
|
const closestEdge = extractClosestEdge(self.data);
|
|
150
|
-
setState({ type: '
|
|
161
|
+
setState({ type: 'w-dragging-over', closestEdge });
|
|
151
162
|
},
|
|
152
163
|
onDragLeave: () => {
|
|
153
164
|
setState(idle);
|
|
@@ -155,10 +166,10 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
|
|
|
155
166
|
onDrag: ({ self }) => {
|
|
156
167
|
const closestEdge = extractClosestEdge(self.data);
|
|
157
168
|
setState((current) => {
|
|
158
|
-
if (current.type === '
|
|
169
|
+
if (current.type === 'w-dragging-over' && current.closestEdge === closestEdge) {
|
|
159
170
|
return current;
|
|
160
171
|
}
|
|
161
|
-
return { type: '
|
|
172
|
+
return { type: 'w-dragging-over', closestEdge };
|
|
162
173
|
});
|
|
163
174
|
},
|
|
164
175
|
onDrop: () => {
|
|
@@ -170,12 +181,18 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
|
|
|
170
181
|
|
|
171
182
|
return (
|
|
172
183
|
<ListItemProvider item={item} dragHandleRef={dragHandleRef}>
|
|
173
|
-
<
|
|
184
|
+
<Comp
|
|
185
|
+
ref={ref}
|
|
186
|
+
role='listitem'
|
|
187
|
+
aria-selected={selected}
|
|
188
|
+
className={mx('relative dx-selected', classNames, stateStyles[state.type])}
|
|
189
|
+
{...props}
|
|
190
|
+
>
|
|
174
191
|
{children}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
192
|
+
</Comp>
|
|
193
|
+
{state.type === 'w-dragging-over' && state.closestEdge && (
|
|
194
|
+
<NaturalListItem.DropIndicator edge={state.closestEdge} />
|
|
195
|
+
)}
|
|
179
196
|
</ListItemProvider>
|
|
180
197
|
);
|
|
181
198
|
};
|
|
@@ -184,47 +201,48 @@ export const ListItem = <T extends ListItemRecord>({ children, classNames, item,
|
|
|
184
201
|
// List item components
|
|
185
202
|
//
|
|
186
203
|
|
|
187
|
-
export const
|
|
204
|
+
export const ListItemIconButton = ({
|
|
188
205
|
autoHide = true,
|
|
206
|
+
iconOnly = true,
|
|
207
|
+
variant = 'ghost',
|
|
189
208
|
classNames,
|
|
190
209
|
disabled,
|
|
191
|
-
icon = 'ph--x--regular',
|
|
192
|
-
label,
|
|
193
210
|
...props
|
|
194
|
-
}:
|
|
195
|
-
|
|
196
|
-
const { state } = useListContext('DELETE_BUTTON');
|
|
211
|
+
}: IconButtonProps & { autoHide?: boolean }) => {
|
|
212
|
+
const { state } = useListContext('ITEM_BUTTON');
|
|
197
213
|
const isDisabled = state.type !== 'idle' || disabled;
|
|
198
|
-
const { t } = useTranslation('os');
|
|
199
214
|
return (
|
|
200
215
|
<IconButton
|
|
201
|
-
iconOnly
|
|
202
|
-
variant='ghost'
|
|
203
216
|
{...props}
|
|
204
|
-
icon={icon}
|
|
205
217
|
disabled={isDisabled}
|
|
206
|
-
|
|
218
|
+
iconOnly={iconOnly}
|
|
219
|
+
variant={variant}
|
|
207
220
|
classNames={[classNames, autoHide && disabled && 'hidden']}
|
|
208
221
|
/>
|
|
209
222
|
);
|
|
210
223
|
};
|
|
211
224
|
|
|
212
|
-
|
|
225
|
+
// TODO(burdon): Generalize to action button.
|
|
226
|
+
export const ListItemDeleteButton = ({
|
|
213
227
|
autoHide = true,
|
|
214
|
-
iconOnly = true,
|
|
215
|
-
variant = 'ghost',
|
|
216
228
|
classNames,
|
|
217
229
|
disabled,
|
|
230
|
+
icon = 'ph--x--regular',
|
|
231
|
+
label,
|
|
218
232
|
...props
|
|
219
|
-
}: IconButtonProps &
|
|
220
|
-
|
|
233
|
+
}: Partial<Pick<IconButtonProps, 'icon'>> &
|
|
234
|
+
Omit<IconButtonProps, 'icon' | 'label'> & { autoHide?: boolean; label?: string }) => {
|
|
235
|
+
const { state } = useListContext('DELETE_BUTTON');
|
|
221
236
|
const isDisabled = state.type !== 'idle' || disabled;
|
|
237
|
+
const { t } = useTranslation(osTranslations);
|
|
222
238
|
return (
|
|
223
239
|
<IconButton
|
|
240
|
+
iconOnly
|
|
241
|
+
variant='ghost'
|
|
224
242
|
{...props}
|
|
243
|
+
icon={icon}
|
|
225
244
|
disabled={isDisabled}
|
|
226
|
-
|
|
227
|
-
variant={variant}
|
|
245
|
+
label={label ?? t('delete label')}
|
|
228
246
|
classNames={[classNames, autoHide && disabled && 'hidden']}
|
|
229
247
|
/>
|
|
230
248
|
);
|
|
@@ -232,7 +250,7 @@ export const ListItemButton = ({
|
|
|
232
250
|
|
|
233
251
|
export const ListItemDragHandle = ({ disabled }: Pick<IconButtonProps, 'disabled'>) => {
|
|
234
252
|
const { dragHandleRef } = useListItemContext('DRAG_HANDLE');
|
|
235
|
-
const { t } = useTranslation(
|
|
253
|
+
const { t } = useTranslation(osTranslations);
|
|
236
254
|
return (
|
|
237
255
|
<IconButton
|
|
238
256
|
iconOnly
|
|
@@ -255,7 +273,7 @@ export const ListItemDragPreview = <T extends ListItemRecord>({
|
|
|
255
273
|
};
|
|
256
274
|
|
|
257
275
|
export const ListItemWrapper = ({ classNames, children }: ThemedClassName<PropsWithChildren>) => (
|
|
258
|
-
<div className={mx('flex
|
|
276
|
+
<div className={mx('flex w-full gap-2', classNames)}>{children}</div>
|
|
259
277
|
);
|
|
260
278
|
|
|
261
279
|
export const ListItemTitle = ({
|
|
@@ -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
|
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Obj } from '@dxos/echo';
|
|
8
8
|
import { faker } from '@dxos/random';
|
|
9
9
|
|
|
10
10
|
export const TestItemSchema = Schema.Struct({
|
|
11
|
-
id:
|
|
11
|
+
id: Obj.ID,
|
|
12
12
|
name: Schema.String,
|
|
13
13
|
});
|
|
14
14
|
|