@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.
- package/dist/lib/browser/index.mjs +676 -729
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +676 -729
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Accordion/Accordion.stories.d.ts +7 -4
- package/dist/types/src/components/Accordion/Accordion.stories.d.ts.map +1 -1
- package/dist/types/src/components/Accordion/AccordionItem.d.ts +1 -1
- package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts +8 -8
- package/dist/types/src/components/List/List.d.ts.map +1 -1
- package/dist/types/src/components/List/List.stories.d.ts +14 -5
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/ListItem.d.ts +6 -9
- 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/List/testing.d.ts +1 -1
- package/dist/types/src/components/List/testing.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 +18 -7
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeContext.d.ts +20 -10
- package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItem.d.ts +32 -10
- package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItemHeading.d.ts +4 -3
- package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItemToggle.d.ts +3 -3
- package/dist/types/src/components/Tree/TreeItemToggle.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 +3 -3
- 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 +5 -7
- package/src/components/Accordion/Accordion.tsx +1 -1
- package/src/components/Accordion/AccordionItem.tsx +8 -5
- package/src/components/Accordion/AccordionRoot.tsx +1 -1
- package/src/components/List/List.stories.tsx +40 -26
- package/src/components/List/List.tsx +2 -5
- package/src/components/List/ListItem.tsx +50 -38
- package/src/components/List/ListRoot.tsx +3 -3
- package/src/components/List/testing.ts +3 -3
- package/src/components/Tree/Tree.stories.tsx +172 -79
- package/src/components/Tree/Tree.tsx +43 -40
- package/src/components/Tree/TreeContext.tsx +17 -9
- package/src/components/Tree/TreeItem.tsx +141 -83
- package/src/components/Tree/TreeItemHeading.tsx +13 -8
- package/src/components/Tree/TreeItemToggle.tsx +29 -18
- package/src/components/Tree/index.ts +2 -0
- 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.
|
|
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": "
|
|
27
|
-
"@atlaskit/pragmatic-drag-and-drop-hitbox": "
|
|
28
|
-
"@
|
|
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.
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/
|
|
37
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
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": "~
|
|
45
|
-
"@types/react-dom": "~
|
|
46
|
-
"effect": "3.
|
|
47
|
-
"react": "~
|
|
48
|
-
"react-dom": "~
|
|
49
|
-
"vite": "
|
|
50
|
-
"@dxos/random": "0.8.4-main.
|
|
51
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
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": "
|
|
55
|
-
"react": "~
|
|
56
|
-
"react-dom": "~
|
|
57
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
58
|
-
"@dxos/
|
|
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 '@
|
|
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/
|
|
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
|
|
42
|
+
const meta = {
|
|
45
43
|
title: 'ui/react-ui-list/Accordion',
|
|
46
44
|
render: DefaultStory,
|
|
47
|
-
decorators: [withTheme, withLayout({
|
|
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,
|
|
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/
|
|
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
|
-
|
|
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
|
|
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-
|
|
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/
|
|
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 '@
|
|
6
|
-
|
|
5
|
+
import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
7
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
9
|
-
import React from 'react';
|
|
7
|
+
import * as Schema from 'effect/Schema';
|
|
8
|
+
import React, { useContext, useMemo } from 'react';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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 {
|
|
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-
|
|
19
|
+
const grid = 'grid grid-cols-[32px_1fr_32px] min-h-[2rem] rounded-sm';
|
|
21
20
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
35
|
-
|
|
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
|
-
|
|
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-
|
|
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 = (
|
|
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
|
|
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<
|
|
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<
|
|
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,
|
|
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 {
|
|
29
|
-
|
|
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: '
|
|
49
|
+
type: 'w-dragging';
|
|
45
50
|
}
|
|
46
51
|
| {
|
|
47
|
-
type: '
|
|
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
|
-
'
|
|
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: '
|
|
123
|
-
setRootState({ type: '
|
|
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: '
|
|
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 === '
|
|
158
|
+
if (current.type === 'w-dragging-over' && current.closestEdge === closestEdge) {
|
|
154
159
|
return current;
|
|
155
160
|
}
|
|
156
|
-
return { type: '
|
|
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='
|
|
169
|
-
|
|
170
|
-
|
|
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'>> &
|
|
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
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|