@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
|
@@ -10,10 +10,20 @@ import {
|
|
|
10
10
|
attachInstruction,
|
|
11
11
|
extractInstruction,
|
|
12
12
|
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
13
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
13
14
|
import * as Schema from 'effect/Schema';
|
|
14
|
-
import React, {
|
|
15
|
+
import React, {
|
|
16
|
+
type FC,
|
|
17
|
+
type KeyboardEvent,
|
|
18
|
+
type MouseEvent,
|
|
19
|
+
memo,
|
|
20
|
+
useCallback,
|
|
21
|
+
useEffect,
|
|
22
|
+
useMemo,
|
|
23
|
+
useRef,
|
|
24
|
+
useState,
|
|
25
|
+
} from 'react';
|
|
15
26
|
|
|
16
|
-
import { type HasId } from '@dxos/echo/internal';
|
|
17
27
|
import { invariant } from '@dxos/invariant';
|
|
18
28
|
import { TreeItem as NaturalTreeItem, Treegrid } from '@dxos/react-ui';
|
|
19
29
|
import {
|
|
@@ -22,7 +32,8 @@ import {
|
|
|
22
32
|
hoverableControls,
|
|
23
33
|
hoverableFocusedKeyboardControls,
|
|
24
34
|
hoverableFocusedWithinControls,
|
|
25
|
-
|
|
35
|
+
mx,
|
|
36
|
+
} from '@dxos/ui-theme';
|
|
26
37
|
|
|
27
38
|
import { DEFAULT_INDENTATION, paddingIndentation } from './helpers';
|
|
28
39
|
import { useTree } from './TreeContext';
|
|
@@ -32,7 +43,7 @@ import { TreeItemToggle } from './TreeItemToggle';
|
|
|
32
43
|
const hoverableDescriptionIcons =
|
|
33
44
|
'[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]';
|
|
34
45
|
|
|
35
|
-
type
|
|
46
|
+
type TreeItemDragState = 'idle' | 'dragging' | 'preview' | 'parent-of-instruction';
|
|
36
47
|
|
|
37
48
|
export const TreeDataSchema = Schema.Struct({
|
|
38
49
|
id: Schema.String,
|
|
@@ -43,7 +54,7 @@ export const TreeDataSchema = Schema.Struct({
|
|
|
43
54
|
export type TreeData = Schema.Schema.Type<typeof TreeDataSchema>;
|
|
44
55
|
export const isTreeData = (data: unknown): data is TreeData => Schema.is(TreeDataSchema)(data);
|
|
45
56
|
|
|
46
|
-
export type ColumnRenderer<T extends
|
|
57
|
+
export type ColumnRenderer<T extends { id: string } = any> = FC<{
|
|
47
58
|
item: T;
|
|
48
59
|
path: string[];
|
|
49
60
|
open: boolean;
|
|
@@ -51,52 +62,73 @@ export type ColumnRenderer<T extends HasId = any> = FC<{
|
|
|
51
62
|
setMenuOpen: (open: boolean) => void;
|
|
52
63
|
}>;
|
|
53
64
|
|
|
54
|
-
export type TreeItemProps<T extends
|
|
65
|
+
export type TreeItemProps<T extends { id: string } = any> = {
|
|
55
66
|
item: T;
|
|
56
67
|
path: string[];
|
|
57
68
|
levelOffset?: number;
|
|
58
69
|
last: boolean;
|
|
59
70
|
draggable?: boolean;
|
|
60
71
|
renderColumns?: ColumnRenderer<T>;
|
|
72
|
+
blockInstruction?: (params: { instruction: Instruction; source: TreeData; target: TreeData }) => boolean;
|
|
61
73
|
canDrop?: (params: { source: TreeData; target: TreeData }) => boolean;
|
|
62
74
|
canSelect?: (params: { item: T; path: string[] }) => boolean;
|
|
63
75
|
onOpenChange?: (params: { item: T; path: string[]; open: boolean }) => void;
|
|
64
76
|
onSelect?: (params: { item: T; path: string[]; current: boolean; option: boolean }) => void;
|
|
77
|
+
onItemHover?: (params: { item: T }) => void;
|
|
65
78
|
};
|
|
66
79
|
|
|
67
|
-
const RawTreeItem = <T extends
|
|
80
|
+
const RawTreeItem = <T extends { id: string } = any>({
|
|
68
81
|
item,
|
|
69
|
-
path:
|
|
82
|
+
path: pathProp,
|
|
70
83
|
levelOffset = 2,
|
|
71
84
|
last,
|
|
72
|
-
draggable:
|
|
85
|
+
draggable: draggableProp,
|
|
73
86
|
renderColumns: Columns,
|
|
87
|
+
blockInstruction,
|
|
74
88
|
canDrop,
|
|
75
89
|
canSelect,
|
|
76
90
|
onOpenChange,
|
|
77
91
|
onSelect,
|
|
92
|
+
onItemHover,
|
|
78
93
|
}: TreeItemProps<T>) => {
|
|
79
94
|
const rowRef = useRef<HTMLDivElement | null>(null);
|
|
80
95
|
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
|
81
96
|
const openRef = useRef(false);
|
|
82
97
|
const cancelExpandRef = useRef<NodeJS.Timeout | null>(null);
|
|
83
|
-
const [_state, setState] = useState<
|
|
98
|
+
const [_state, setState] = useState<TreeItemDragState>('idle');
|
|
84
99
|
const [instruction, setInstruction] = useState<Instruction | null>(null);
|
|
85
100
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
86
101
|
|
|
87
|
-
const {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
);
|
|
93
|
-
const path = useMemo(() => [...
|
|
94
|
-
|
|
95
|
-
const
|
|
102
|
+
const {
|
|
103
|
+
itemProps: itemPropsAtom,
|
|
104
|
+
childIds: childIdsAtom,
|
|
105
|
+
itemOpen: itemOpenAtom,
|
|
106
|
+
itemCurrent: itemCurrentAtom,
|
|
107
|
+
} = useTree();
|
|
108
|
+
const path = useMemo(() => [...pathProp, item.id], [pathProp, item.id]);
|
|
109
|
+
|
|
110
|
+
const {
|
|
111
|
+
id,
|
|
112
|
+
parentOf,
|
|
113
|
+
draggable: itemDraggable,
|
|
114
|
+
droppable: itemDroppable,
|
|
115
|
+
label,
|
|
116
|
+
className,
|
|
117
|
+
headingClassName,
|
|
118
|
+
icon,
|
|
119
|
+
iconHue,
|
|
120
|
+
disabled,
|
|
121
|
+
testId,
|
|
122
|
+
} = useAtomValue(itemPropsAtom(path));
|
|
123
|
+
const childIds = useAtomValue(childIdsAtom(item.id));
|
|
124
|
+
const open = useAtomValue(itemOpenAtom(path));
|
|
125
|
+
const current = useAtomValue(itemCurrentAtom(path));
|
|
126
|
+
|
|
96
127
|
const level = path.length - levelOffset;
|
|
97
128
|
const isBranch = !!parentOf;
|
|
98
129
|
const mode: ItemMode = last ? 'last-in-group' : open ? 'expanded' : 'standard';
|
|
99
130
|
const canSelectItem = canSelect?.({ item, path }) ?? true;
|
|
131
|
+
const data = { id, path, item } satisfies TreeData;
|
|
100
132
|
|
|
101
133
|
const cancelExpand = useCallback(() => {
|
|
102
134
|
if (cancelExpandRef.current) {
|
|
@@ -105,19 +137,19 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
105
137
|
}
|
|
106
138
|
}, []);
|
|
107
139
|
|
|
140
|
+
const isItemDraggable = draggableProp && itemDraggable !== false;
|
|
141
|
+
const isItemDroppable = itemDroppable !== false;
|
|
142
|
+
|
|
108
143
|
useEffect(() => {
|
|
109
|
-
if (!
|
|
144
|
+
if (!draggableProp) {
|
|
110
145
|
return;
|
|
111
146
|
}
|
|
112
147
|
|
|
113
148
|
invariant(buttonRef.current);
|
|
114
149
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
// https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about
|
|
118
|
-
return combine(
|
|
150
|
+
const makeDraggable = () =>
|
|
119
151
|
draggable({
|
|
120
|
-
element: buttonRef.current
|
|
152
|
+
element: buttonRef.current!,
|
|
121
153
|
getInitialData: () => data,
|
|
122
154
|
onDragStart: () => {
|
|
123
155
|
setState('dragging');
|
|
@@ -132,58 +164,72 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
132
164
|
onOpenChange?.({ item, path, open: true });
|
|
133
165
|
}
|
|
134
166
|
},
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// TODO(wittjosiah): This is not occurring in the current implementation.
|
|
171
|
-
setInstruction(instruction);
|
|
172
|
-
} else {
|
|
173
|
-
setInstruction(null);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (!isItemDroppable) {
|
|
170
|
+
return isItemDraggable ? makeDraggable() : undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const dropTarget = dropTargetForElements({
|
|
174
|
+
element: buttonRef.current,
|
|
175
|
+
getData: ({ input, element }) => {
|
|
176
|
+
return attachInstruction(data, {
|
|
177
|
+
input,
|
|
178
|
+
element,
|
|
179
|
+
indentPerLevel: DEFAULT_INDENTATION,
|
|
180
|
+
currentLevel: level,
|
|
181
|
+
mode,
|
|
182
|
+
block: isBranch ? [] : ['make-child'],
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
canDrop: ({ source }) => {
|
|
186
|
+
const _canDrop = canDrop ?? (() => true);
|
|
187
|
+
return source.element !== buttonRef.current && _canDrop({ source: source.data as TreeData, target: data });
|
|
188
|
+
},
|
|
189
|
+
getIsSticky: () => true,
|
|
190
|
+
onDrag: ({ self, source }) => {
|
|
191
|
+
const desired = extractInstruction(self.data);
|
|
192
|
+
const block =
|
|
193
|
+
desired && blockInstruction?.({ instruction: desired, source: source.data as TreeData, target: data });
|
|
194
|
+
const instruction: Instruction | null =
|
|
195
|
+
block && desired.type !== 'instruction-blocked' ? { type: 'instruction-blocked', desired } : desired;
|
|
196
|
+
|
|
197
|
+
if (source.data.id !== id) {
|
|
198
|
+
if (instruction?.type === 'make-child' && isBranch && !open && !cancelExpandRef.current) {
|
|
199
|
+
cancelExpandRef.current = setTimeout(() => {
|
|
200
|
+
onOpenChange?.({ item, path, open: true });
|
|
201
|
+
}, 500);
|
|
174
202
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
203
|
+
|
|
204
|
+
if (instruction?.type !== 'make-child') {
|
|
205
|
+
cancelExpand();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
setInstruction(instruction);
|
|
209
|
+
} else if (instruction?.type === 'reparent') {
|
|
210
|
+
// TODO(wittjosiah): This is not occurring in the current implementation.
|
|
211
|
+
setInstruction(instruction);
|
|
212
|
+
} else {
|
|
182
213
|
setInstruction(null);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
onDragLeave: () => {
|
|
217
|
+
cancelExpand();
|
|
218
|
+
setInstruction(null);
|
|
219
|
+
},
|
|
220
|
+
onDrop: () => {
|
|
221
|
+
cancelExpand();
|
|
222
|
+
setInstruction(null);
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (!isItemDraggable) {
|
|
227
|
+
return dropTarget;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about
|
|
231
|
+
return combine(makeDraggable(), dropTarget);
|
|
232
|
+
}, [draggableProp, isItemDraggable, isItemDroppable, item, id, mode, path, open, blockInstruction, canDrop]);
|
|
187
233
|
|
|
188
234
|
// Cancel expand on unmount.
|
|
189
235
|
useEffect(() => () => cancelExpand(), [cancelExpand]);
|
|
@@ -221,6 +267,29 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
221
267
|
[isBranch, open, handleOpenToggle, handleSelect],
|
|
222
268
|
);
|
|
223
269
|
|
|
270
|
+
const handleItemHover = useCallback(() => {
|
|
271
|
+
onItemHover?.({ item });
|
|
272
|
+
}, [onItemHover, item]);
|
|
273
|
+
|
|
274
|
+
const handleContextMenu = useCallback(
|
|
275
|
+
(event: MouseEvent) => {
|
|
276
|
+
event.preventDefault();
|
|
277
|
+
setMenuOpen(true);
|
|
278
|
+
},
|
|
279
|
+
[setMenuOpen],
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const childProps = {
|
|
283
|
+
draggable: draggableProp,
|
|
284
|
+
renderColumns: Columns,
|
|
285
|
+
blockInstruction,
|
|
286
|
+
canDrop,
|
|
287
|
+
canSelect,
|
|
288
|
+
onItemHover,
|
|
289
|
+
onOpenChange,
|
|
290
|
+
onSelect,
|
|
291
|
+
};
|
|
292
|
+
|
|
224
293
|
return (
|
|
225
294
|
<>
|
|
226
295
|
<Treegrid.Row
|
|
@@ -229,27 +298,25 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
229
298
|
id={id}
|
|
230
299
|
aria-labelledby={`${id}__label`}
|
|
231
300
|
parentOf={parentOf?.join(Treegrid.PARENT_OF_SEPARATOR)}
|
|
232
|
-
|
|
233
|
-
|
|
301
|
+
data-object-id={id}
|
|
302
|
+
data-testid={testId}
|
|
303
|
+
// NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
|
|
304
|
+
// without alerting the user (except for in the correct link element). See also:
|
|
305
|
+
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
|
|
306
|
+
aria-current={current ? ('' as 'page') : undefined}
|
|
307
|
+
classNames={mx(
|
|
308
|
+
'grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-active-surface',
|
|
234
309
|
hoverableControls,
|
|
235
310
|
hoverableFocusedKeyboardControls,
|
|
236
311
|
hoverableFocusedWithinControls,
|
|
237
312
|
hoverableDescriptionIcons,
|
|
238
|
-
ghostHover,
|
|
239
313
|
ghostFocusWithin,
|
|
314
|
+
ghostHover,
|
|
240
315
|
className,
|
|
241
|
-
|
|
242
|
-
data-itemid={id}
|
|
243
|
-
data-testid={testId}
|
|
244
|
-
// NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
|
|
245
|
-
// without alerting the user (except for in the correct link element). See also:
|
|
246
|
-
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
|
|
247
|
-
aria-current={current ? ('' as 'page') : undefined}
|
|
316
|
+
)}
|
|
248
317
|
onKeyDown={handleKeyDown}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
setMenuOpen(true);
|
|
252
|
-
}}
|
|
318
|
+
onMouseEnter={handleItemHover}
|
|
319
|
+
onContextMenu={handleContextMenu}
|
|
253
320
|
>
|
|
254
321
|
<div
|
|
255
322
|
role='none'
|
|
@@ -264,7 +331,7 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
264
331
|
label={label}
|
|
265
332
|
className={headingClassName}
|
|
266
333
|
icon={icon}
|
|
267
|
-
|
|
334
|
+
iconHue={iconHue}
|
|
268
335
|
onSelect={handleSelect}
|
|
269
336
|
ref={buttonRef}
|
|
270
337
|
/>
|
|
@@ -274,22 +341,25 @@ const RawTreeItem = <T extends HasId = any>({
|
|
|
274
341
|
</div>
|
|
275
342
|
</Treegrid.Row>
|
|
276
343
|
{open &&
|
|
277
|
-
|
|
278
|
-
<
|
|
279
|
-
key={item.id}
|
|
280
|
-
item={item}
|
|
281
|
-
path={path}
|
|
282
|
-
last={index === items.length - 1}
|
|
283
|
-
draggable={_draggable}
|
|
284
|
-
renderColumns={Columns}
|
|
285
|
-
canDrop={canDrop}
|
|
286
|
-
canSelect={canSelect}
|
|
287
|
-
onOpenChange={onOpenChange}
|
|
288
|
-
onSelect={onSelect}
|
|
289
|
-
/>
|
|
344
|
+
childIds.map((childId, index) => (
|
|
345
|
+
<TreeItemById key={childId} id={childId} path={path} last={index === childIds.length - 1} {...childProps} />
|
|
290
346
|
))}
|
|
291
347
|
</>
|
|
292
348
|
);
|
|
293
349
|
};
|
|
294
350
|
|
|
295
351
|
export const TreeItem = memo(RawTreeItem) as FC<TreeItemProps>;
|
|
352
|
+
|
|
353
|
+
/** Resolves a child ID to an item via the `item` atom and renders a TreeItem. */
|
|
354
|
+
export type TreeItemByIdProps = Omit<TreeItemProps, 'item'> & { id: string };
|
|
355
|
+
|
|
356
|
+
const RawTreeItemById = <T extends { id: string } = any>({ id, ...props }: TreeItemByIdProps) => {
|
|
357
|
+
const { item: itemAtom } = useTree();
|
|
358
|
+
const item = useAtomValue(itemAtom(id)) as T | undefined;
|
|
359
|
+
if (!item) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
return <TreeItem item={item} {...props} />;
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
export const TreeItemById = memo(RawTreeItemById) as FC<TreeItemByIdProps>;
|
|
@@ -6,6 +6,7 @@ import React, { type KeyboardEvent, type MouseEvent, forwardRef, memo, useCallba
|
|
|
6
6
|
|
|
7
7
|
import { Button, Icon, type Label, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
import { TextTooltip } from '@dxos/react-ui-text-tooltip';
|
|
9
|
+
import { getStyles } from '@dxos/ui-theme';
|
|
9
10
|
|
|
10
11
|
// TODO(wittjosiah): Consider whether there should be a separate disabled prop which was visually distinct
|
|
11
12
|
// rather than just making the item unselectable.
|
|
@@ -13,7 +14,7 @@ export type TreeItemHeadingProps = {
|
|
|
13
14
|
label: Label;
|
|
14
15
|
className?: string;
|
|
15
16
|
icon?: string;
|
|
16
|
-
|
|
17
|
+
iconHue?: string;
|
|
17
18
|
disabled?: boolean;
|
|
18
19
|
current?: boolean;
|
|
19
20
|
onSelect?: (option: boolean) => void;
|
|
@@ -21,8 +22,9 @@ export type TreeItemHeadingProps = {
|
|
|
21
22
|
|
|
22
23
|
export const TreeItemHeading = memo(
|
|
23
24
|
forwardRef<HTMLButtonElement, TreeItemHeadingProps>(
|
|
24
|
-
({ label, className, icon,
|
|
25
|
+
({ label, className, icon, iconHue, disabled, current, onSelect }, forwardedRef) => {
|
|
25
26
|
const { t } = useTranslation();
|
|
27
|
+
const styles = iconHue ? getStyles(iconHue) : undefined;
|
|
26
28
|
|
|
27
29
|
const handleSelect = useCallback(
|
|
28
30
|
(event: MouseEvent) => {
|
|
@@ -56,7 +58,7 @@ export const TreeItemHeading = memo(
|
|
|
56
58
|
variant='ghost'
|
|
57
59
|
density='fine'
|
|
58
60
|
classNames={[
|
|
59
|
-
'grow gap-2
|
|
61
|
+
'grow gap-2 ps-0.5 hover:bg-transparent dark:hover:bg-transparent',
|
|
60
62
|
'disabled:cursor-default disabled:opacity-100',
|
|
61
63
|
className,
|
|
62
64
|
]}
|
|
@@ -65,8 +67,10 @@ export const TreeItemHeading = memo(
|
|
|
65
67
|
onKeyDown={handleButtonKeydown}
|
|
66
68
|
{...(current && { 'aria-current': 'location' })}
|
|
67
69
|
>
|
|
68
|
-
{icon &&
|
|
69
|
-
|
|
70
|
+
{icon && (
|
|
71
|
+
<Icon icon={icon ?? 'ph--placeholder--regular'} size={5} classNames={['my-1', styles?.surfaceText]} />
|
|
72
|
+
)}
|
|
73
|
+
<span className='flex-1 w-0 truncate text-start font-normal' data-tooltip>
|
|
70
74
|
{toLocalizedString(label, t)}
|
|
71
75
|
</span>
|
|
72
76
|
</Button>
|
|
@@ -23,7 +23,7 @@ export const TreeItemToggle = memo(
|
|
|
23
23
|
variant='ghost'
|
|
24
24
|
density='fine'
|
|
25
25
|
classNames={[
|
|
26
|
-
'
|
|
26
|
+
'h-full w-6 px-0',
|
|
27
27
|
'[&_svg]:transition-[transform] [&_svg]:duration-200',
|
|
28
28
|
open && '[&_svg]:rotate-90',
|
|
29
29
|
hidden ? 'hidden' : !isBranch && 'invisible',
|
|
@@ -5,20 +5,21 @@
|
|
|
5
5
|
import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
6
6
|
import * as Schema from 'effect/Schema';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { Obj } from '@dxos/echo';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { faker } from '@dxos/random';
|
|
11
11
|
|
|
12
12
|
import { type TreeData } from './TreeItem';
|
|
13
13
|
|
|
14
|
-
export type TestItem =
|
|
14
|
+
export type TestItem = {
|
|
15
|
+
id: string;
|
|
15
16
|
name: string;
|
|
16
17
|
icon?: string;
|
|
17
18
|
items: TestItem[];
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
export const TestItemSchema = Schema.Struct({
|
|
21
|
-
id:
|
|
22
|
+
id: Obj.ID,
|
|
22
23
|
name: Schema.String,
|
|
23
24
|
icon: Schema.optional(Schema.String),
|
|
24
25
|
items: Schema.mutable(Schema.Array(Schema.suspend((): Schema.Schema<TestItem> => TestItemSchema))),
|