@dxos/react-ui-list 0.8.4-main.b97322e → 0.8.4-main.c4373fc
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 +91 -89
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +91 -89
- 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 +10 -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 +6 -6
- 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 +4 -7
- package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
- 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 +3 -3
- package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +36 -6
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeContext.d.ts +3 -2
- package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeItem.d.ts +14 -9
- 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/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 +25 -24
- package/src/components/Accordion/Accordion.stories.tsx +8 -7
- package/src/components/Accordion/Accordion.tsx +1 -1
- package/src/components/Accordion/AccordionItem.tsx +5 -2
- package/src/components/List/List.stories.tsx +16 -14
- package/src/components/List/List.tsx +2 -5
- package/src/components/List/ListItem.tsx +39 -27
- package/src/components/List/ListRoot.tsx +1 -1
- package/src/components/List/testing.ts +2 -2
- package/src/components/Tree/Tree.stories.tsx +51 -48
- package/src/components/Tree/Tree.tsx +7 -2
- package/src/components/Tree/TreeContext.tsx +3 -2
- package/src/components/Tree/TreeItem.tsx +52 -42
- package/src/components/Tree/TreeItemHeading.tsx +7 -6
- package/src/components/Tree/TreeItemToggle.tsx +29 -18
- package/src/components/Tree/testing.ts +2 -2
|
@@ -5,34 +5,35 @@
|
|
|
5
5
|
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
6
6
|
import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
7
7
|
import {
|
|
8
|
-
attachInstruction,
|
|
9
|
-
extractInstruction,
|
|
10
8
|
type Instruction,
|
|
11
9
|
type ItemMode,
|
|
10
|
+
attachInstruction,
|
|
11
|
+
extractInstruction,
|
|
12
12
|
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
13
|
-
import
|
|
14
|
-
import React, { memo, useCallback, useEffect, useMemo, useRef, useState
|
|
13
|
+
import * as Schema from 'effect/Schema';
|
|
14
|
+
import React, { type FC, type KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
15
15
|
|
|
16
|
-
import { type HasId } from '@dxos/echo
|
|
16
|
+
import { type HasId } from '@dxos/echo/internal';
|
|
17
17
|
import { invariant } from '@dxos/invariant';
|
|
18
|
-
import {
|
|
18
|
+
import { TreeItem as NaturalTreeItem, Treegrid } from '@dxos/react-ui';
|
|
19
19
|
import {
|
|
20
|
+
ghostFocusWithin,
|
|
20
21
|
ghostHover,
|
|
21
22
|
hoverableControls,
|
|
22
23
|
hoverableFocusedKeyboardControls,
|
|
23
24
|
hoverableFocusedWithinControls,
|
|
24
25
|
} from '@dxos/react-ui-theme';
|
|
25
26
|
|
|
27
|
+
import { DEFAULT_INDENTATION, paddingIndentation } from './helpers';
|
|
26
28
|
import { useTree } from './TreeContext';
|
|
27
29
|
import { TreeItemHeading } from './TreeItemHeading';
|
|
28
30
|
import { TreeItemToggle } from './TreeItemToggle';
|
|
29
|
-
import { DEFAULT_INDENTATION, paddingIndentation } from './helpers';
|
|
30
|
-
|
|
31
|
-
type TreeItemState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
|
|
32
31
|
|
|
33
32
|
const hoverableDescriptionIcons =
|
|
34
33
|
'[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]';
|
|
35
34
|
|
|
35
|
+
type TreeItemState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
|
|
36
|
+
|
|
36
37
|
export const TreeDataSchema = Schema.Struct({
|
|
37
38
|
id: Schema.String,
|
|
38
39
|
path: Schema.Array(Schema.String),
|
|
@@ -40,23 +41,25 @@ export const TreeDataSchema = Schema.Struct({
|
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
export type TreeData = Schema.Schema.Type<typeof TreeDataSchema>;
|
|
43
|
-
|
|
44
44
|
export const isTreeData = (data: unknown): data is TreeData => Schema.is(TreeDataSchema)(data);
|
|
45
45
|
|
|
46
|
+
export type ColumnRenderer<T extends HasId = any> = FC<{
|
|
47
|
+
item: T;
|
|
48
|
+
path: string[];
|
|
49
|
+
open: boolean;
|
|
50
|
+
menuOpen: boolean;
|
|
51
|
+
setMenuOpen: (open: boolean) => void;
|
|
52
|
+
}>;
|
|
53
|
+
|
|
46
54
|
export type TreeItemProps<T extends HasId = any> = {
|
|
47
55
|
item: T;
|
|
48
56
|
path: string[];
|
|
49
57
|
levelOffset?: number;
|
|
50
58
|
last: boolean;
|
|
51
59
|
draggable?: boolean;
|
|
52
|
-
renderColumns?:
|
|
53
|
-
item: T;
|
|
54
|
-
path: string[];
|
|
55
|
-
open: boolean;
|
|
56
|
-
menuOpen: boolean;
|
|
57
|
-
setMenuOpen: (open: boolean) => void;
|
|
58
|
-
}>;
|
|
60
|
+
renderColumns?: ColumnRenderer<T>;
|
|
59
61
|
canDrop?: (params: { source: TreeData; target: TreeData }) => boolean;
|
|
62
|
+
canSelect?: (params: { item: T; path: string[] }) => boolean;
|
|
60
63
|
onOpenChange?: (params: { item: T; path: string[]; open: boolean }) => void;
|
|
61
64
|
onSelect?: (params: { item: T; path: string[]; current: boolean; option: boolean }) => void;
|
|
62
65
|
};
|
|
@@ -64,13 +67,14 @@ export type TreeItemProps<T extends HasId = any> = {
|
|
|
64
67
|
const RawTreeItem = <T extends HasId = any>({
|
|
65
68
|
item,
|
|
66
69
|
path: _path,
|
|
70
|
+
levelOffset = 2,
|
|
67
71
|
last,
|
|
68
72
|
draggable: _draggable,
|
|
69
73
|
renderColumns: Columns,
|
|
70
74
|
canDrop,
|
|
75
|
+
canSelect,
|
|
71
76
|
onOpenChange,
|
|
72
77
|
onSelect,
|
|
73
|
-
levelOffset = 2,
|
|
74
78
|
}: TreeItemProps<T>) => {
|
|
75
79
|
const rowRef = useRef<HTMLDivElement | null>(null);
|
|
76
80
|
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
|
@@ -82,13 +86,17 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
82
86
|
|
|
83
87
|
const { useItems, getProps, isOpen, isCurrent } = useTree();
|
|
84
88
|
const items = useItems(item);
|
|
85
|
-
const { id, label,
|
|
89
|
+
const { id, parentOf, label, className, headingClassName, icon, iconClassName, disabled, testId } = getProps(
|
|
90
|
+
item,
|
|
91
|
+
_path,
|
|
92
|
+
);
|
|
86
93
|
const path = useMemo(() => [..._path, id], [_path, id]);
|
|
87
94
|
const open = isOpen(path, item);
|
|
88
95
|
const current = isCurrent(path, item);
|
|
89
96
|
const level = path.length - levelOffset;
|
|
90
97
|
const isBranch = !!parentOf;
|
|
91
98
|
const mode: ItemMode = last ? 'last-in-group' : open ? 'expanded' : 'standard';
|
|
99
|
+
const canSelectItem = canSelect?.({ item, path }) ?? true;
|
|
92
100
|
|
|
93
101
|
const cancelExpand = useCallback(() => {
|
|
94
102
|
if (cancelExpandRef.current) {
|
|
@@ -180,38 +188,37 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
180
188
|
// Cancel expand on unmount.
|
|
181
189
|
useEffect(() => () => cancelExpand(), [cancelExpand]);
|
|
182
190
|
|
|
183
|
-
const
|
|
191
|
+
const handleOpenToggle = useCallback(
|
|
184
192
|
() => onOpenChange?.({ item, path, open: !open }),
|
|
185
193
|
[onOpenChange, item, path, open],
|
|
186
194
|
);
|
|
187
195
|
|
|
188
196
|
const handleSelect = useCallback(
|
|
189
197
|
(option = false) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
// If the item is a branch, toggle it if:
|
|
199
|
+
// - also holding down the option key
|
|
200
|
+
// - or the item is currently selected
|
|
201
|
+
if (isBranch && (option || current)) {
|
|
202
|
+
handleOpenToggle();
|
|
203
|
+
} else if (canSelectItem) {
|
|
204
|
+
canSelect?.({ item, path });
|
|
193
205
|
rowRef.current?.focus();
|
|
194
206
|
onSelect?.({ item, path, current: !current, option });
|
|
195
207
|
}
|
|
196
208
|
},
|
|
197
|
-
[item, path, current, isBranch,
|
|
209
|
+
[item, path, current, isBranch, canSelectItem, handleOpenToggle, onSelect],
|
|
198
210
|
);
|
|
199
211
|
|
|
200
212
|
const handleKeyDown = useCallback(
|
|
201
213
|
(event: KeyboardEvent) => {
|
|
202
214
|
switch (event.key) {
|
|
203
215
|
case 'ArrowRight':
|
|
204
|
-
isBranch && !open && handleOpenChange();
|
|
205
|
-
break;
|
|
206
216
|
case 'ArrowLeft':
|
|
207
|
-
isBranch &&
|
|
208
|
-
break;
|
|
209
|
-
case ' ':
|
|
210
|
-
handleSelect(event.altKey);
|
|
217
|
+
isBranch && handleOpenToggle();
|
|
211
218
|
break;
|
|
212
219
|
}
|
|
213
220
|
},
|
|
214
|
-
[isBranch, open,
|
|
221
|
+
[isBranch, open, handleOpenToggle, handleSelect],
|
|
215
222
|
);
|
|
216
223
|
|
|
217
224
|
return (
|
|
@@ -229,6 +236,7 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
229
236
|
hoverableFocusedWithinControls,
|
|
230
237
|
hoverableDescriptionIcons,
|
|
231
238
|
ghostHover,
|
|
239
|
+
ghostFocusWithin,
|
|
232
240
|
className,
|
|
233
241
|
]}
|
|
234
242
|
data-itemid={id}
|
|
@@ -243,26 +251,27 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
243
251
|
setMenuOpen(true);
|
|
244
252
|
}}
|
|
245
253
|
>
|
|
246
|
-
<
|
|
247
|
-
|
|
248
|
-
|
|
254
|
+
<div
|
|
255
|
+
role='none'
|
|
256
|
+
className='indent relative grid grid-cols-subgrid col-[tree-row]'
|
|
249
257
|
style={paddingIndentation(level)}
|
|
250
258
|
>
|
|
251
|
-
<
|
|
252
|
-
<TreeItemToggle isBranch={isBranch} open={open}
|
|
259
|
+
<Treegrid.Cell classNames='flex items-center'>
|
|
260
|
+
<TreeItemToggle isBranch={isBranch} open={open} onClick={handleOpenToggle} />
|
|
253
261
|
<TreeItemHeading
|
|
254
|
-
ref={buttonRef}
|
|
255
|
-
label={label}
|
|
256
|
-
icon={icon}
|
|
257
|
-
className={headingClassName}
|
|
258
262
|
disabled={disabled}
|
|
259
263
|
current={current}
|
|
264
|
+
label={label}
|
|
265
|
+
className={headingClassName}
|
|
266
|
+
icon={icon}
|
|
267
|
+
iconClassName={iconClassName}
|
|
260
268
|
onSelect={handleSelect}
|
|
269
|
+
ref={buttonRef}
|
|
261
270
|
/>
|
|
262
|
-
</
|
|
271
|
+
</Treegrid.Cell>
|
|
263
272
|
{Columns && <Columns item={item} path={path} open={open} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />}
|
|
264
273
|
{instruction && <NaturalTreeItem.DropIndicator instruction={instruction} gap={2} />}
|
|
265
|
-
</
|
|
274
|
+
</div>
|
|
266
275
|
</Treegrid.Row>
|
|
267
276
|
{open &&
|
|
268
277
|
items.map((item, index) => (
|
|
@@ -274,6 +283,7 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
274
283
|
draggable={_draggable}
|
|
275
284
|
renderColumns={Columns}
|
|
276
285
|
canDrop={canDrop}
|
|
286
|
+
canSelect={canSelect}
|
|
277
287
|
onOpenChange={onOpenChange}
|
|
278
288
|
onSelect={onSelect}
|
|
279
289
|
/>
|
|
@@ -4,23 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { type KeyboardEvent, type MouseEvent, forwardRef, memo, useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
import { Button, Icon, toLocalizedString, useTranslation
|
|
7
|
+
import { Button, Icon, type Label, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
import { TextTooltip } from '@dxos/react-ui-text-tooltip';
|
|
9
9
|
|
|
10
10
|
// TODO(wittjosiah): Consider whether there should be a separate disabled prop which was visually distinct
|
|
11
11
|
// rather than just making the item unselectable.
|
|
12
|
-
export type
|
|
12
|
+
export type TreeItemHeadingProps = {
|
|
13
13
|
label: Label;
|
|
14
|
-
icon?: string;
|
|
15
14
|
className?: string;
|
|
15
|
+
icon?: string;
|
|
16
|
+
iconClassName?: string;
|
|
16
17
|
disabled?: boolean;
|
|
17
18
|
current?: boolean;
|
|
18
19
|
onSelect?: (option: boolean) => void;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export const TreeItemHeading = memo(
|
|
22
|
-
forwardRef<HTMLButtonElement,
|
|
23
|
-
({ label, icon,
|
|
23
|
+
forwardRef<HTMLButtonElement, TreeItemHeadingProps>(
|
|
24
|
+
({ label, className, icon, iconClassName, disabled, current, onSelect }, forwardedRef) => {
|
|
24
25
|
const { t } = useTranslation();
|
|
25
26
|
|
|
26
27
|
const handleSelect = useCallback(
|
|
@@ -64,7 +65,7 @@ export const TreeItemHeading = memo(
|
|
|
64
65
|
onKeyDown={handleButtonKeydown}
|
|
65
66
|
{...(current && { 'aria-current': 'location' })}
|
|
66
67
|
>
|
|
67
|
-
{icon && <Icon icon={icon ?? 'ph--placeholder--regular'} size={5} classNames='mlb-1' />}
|
|
68
|
+
{icon && <Icon icon={icon ?? 'ph--placeholder--regular'} size={5} classNames={['mlb-1', iconClassName]} />}
|
|
68
69
|
<span className='flex-1 is-0 truncate text-start text-sm font-normal' data-tooltip>
|
|
69
70
|
{toLocalizedString(label, t)}
|
|
70
71
|
</span>
|
|
@@ -4,29 +4,40 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { forwardRef, memo } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { IconButton, type IconButtonProps } from '@dxos/react-ui';
|
|
8
8
|
|
|
9
|
-
export type TreeItemToggleProps = {
|
|
9
|
+
export type TreeItemToggleProps = Omit<IconButtonProps, 'icon' | 'size' | 'label'> & {
|
|
10
10
|
open?: boolean;
|
|
11
11
|
isBranch?: boolean;
|
|
12
|
-
onToggle?: () => void;
|
|
13
12
|
hidden?: boolean;
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
export const TreeItemToggle = memo(
|
|
17
|
-
forwardRef<HTMLButtonElement, TreeItemToggleProps>(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
forwardRef<HTMLButtonElement, TreeItemToggleProps>(
|
|
17
|
+
({ open, isBranch, hidden, classNames, ...props }, forwardedRef) => {
|
|
18
|
+
return (
|
|
19
|
+
<IconButton
|
|
20
|
+
ref={forwardedRef}
|
|
21
|
+
data-testid='treeItem.toggle'
|
|
22
|
+
aria-expanded={open}
|
|
23
|
+
variant='ghost'
|
|
24
|
+
density='fine'
|
|
25
|
+
classNames={[
|
|
26
|
+
'bs-full is-6 pli-0',
|
|
27
|
+
'[&_svg]:transition-[transform] [&_svg]:duration-200',
|
|
28
|
+
open && '[&_svg]:rotate-90',
|
|
29
|
+
hidden ? 'hidden' : !isBranch && 'invisible',
|
|
30
|
+
classNames,
|
|
31
|
+
]}
|
|
32
|
+
size={3}
|
|
33
|
+
icon='ph--caret-right--bold'
|
|
34
|
+
iconOnly
|
|
35
|
+
noTooltip
|
|
36
|
+
label={open ? 'Click to close' : 'Click to open'}
|
|
37
|
+
tabIndex={-1}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
),
|
|
32
43
|
);
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
6
|
-
import
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
7
|
|
|
8
|
-
import { type HasId, ObjectId } from '@dxos/echo
|
|
8
|
+
import { type HasId, ObjectId } from '@dxos/echo/internal';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { faker } from '@dxos/random';
|
|
11
11
|
|