@dxos/react-ui-list 0.7.1 → 0.7.2-main.f1adc9f
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 +149 -87
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +180 -116
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +149 -87
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/List/DropIndicator.d.ts +5 -4
- package/dist/types/src/components/List/DropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/Tree/DropIndicator.d.ts +2 -1
- package/dist/types/src/components/Tree/DropIndicator.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.d.ts +4 -19
- package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/TreeContext.d.ts +20 -0
- package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -0
- package/dist/types/src/components/Tree/TreeItem.d.ts +26 -24
- 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/helpers.d.ts +0 -3
- package/dist/types/src/components/Tree/helpers.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +1 -1
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/testing.d.ts +3 -6
- package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
- package/package.json +16 -18
- package/src/components/List/DropIndicator.tsx +7 -2
- package/src/components/Tree/DropIndicator.tsx +7 -8
- package/src/components/Tree/Tree.stories.tsx +71 -70
- package/src/components/Tree/Tree.tsx +29 -24
- package/src/components/Tree/TreeContext.tsx +32 -0
- package/src/components/Tree/TreeItem.tsx +122 -83
- package/src/components/Tree/TreeItemHeading.tsx +14 -5
- package/src/components/Tree/helpers.ts +0 -16
- package/src/components/Tree/index.ts +1 -1
- package/src/components/Tree/testing.ts +4 -73
- package/dist/types/src/components/Tree/types.d.ts +0 -18
- package/dist/types/src/components/Tree/types.d.ts.map +0 -1
- package/src/components/Tree/types.ts +0 -34
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { type ItemMode } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
2
|
-
import { type ItemType } from './types';
|
|
3
1
|
export declare const DEFAULT_INDENTATION = 8;
|
|
4
2
|
export declare const paddingIndendation: (level: number, indentation?: number) => {
|
|
5
3
|
paddingInlineStart: string;
|
|
6
4
|
};
|
|
7
|
-
export declare const getMode: (items: ItemType[], index: number) => ItemMode;
|
|
8
5
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/helpers.ts"],"names":[],"mappings":"AAIA,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/helpers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,eAAO,MAAM,kBAAkB,UAAW,MAAM;;CAE9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/index.ts"],"names":[],"mappings":"AAIA,cAAc,QAAQ,CAAC;AACvB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/index.ts"],"names":[],"mappings":"AAIA,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
2
2
|
import { S } from '@dxos/echo-schema';
|
|
3
|
-
import { type
|
|
3
|
+
import { type TreeData } from './TreeItem';
|
|
4
4
|
export type TestItem = {
|
|
5
5
|
id: string;
|
|
6
6
|
name: string;
|
|
@@ -14,13 +14,10 @@ export declare const TestItemSchema: S.Struct<{
|
|
|
14
14
|
items: S.mutable<S.Array$<S.suspend<TestItem, TestItem, never>>>;
|
|
15
15
|
}>;
|
|
16
16
|
export declare const createTree: (n?: number, d?: number) => TestItem;
|
|
17
|
-
export declare const flattenTree: (tree: TestItem, open: string[], getItem: (tree: TestItem) => ItemType) => ItemType[];
|
|
18
|
-
export declare const getItem: (testItem: TestItem, parent?: string[]) => ItemType;
|
|
19
|
-
export declare const invalidateCache: (id: string) => void;
|
|
20
17
|
export declare const updateState: ({ state, instruction, source, target, }: {
|
|
21
18
|
state: TestItem;
|
|
22
19
|
instruction: Instruction;
|
|
23
|
-
source:
|
|
24
|
-
target:
|
|
20
|
+
source: TreeData;
|
|
21
|
+
target: TreeData;
|
|
25
22
|
}) => void;
|
|
26
23
|
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/testing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,oDAAoD,CAAC;AAEtF,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/testing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,oDAAoD,CAAC;AAEtF,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAItC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;EAKzB,CAAC;AAEH,eAAO,MAAM,UAAU,8BAAmB,QAaxC,CAAC;AAmBH,eAAO,MAAM,WAAW,4CAKrB;IACD,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;CAClB,SAgCA,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-list",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-main.f1adc9f",
|
|
4
4
|
"description": "A list component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -23,21 +23,19 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
|
|
26
|
-
"@atlaskit/pragmatic-drag-and-drop-flourish": "^1.1.2",
|
|
27
26
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
|
28
|
-
"@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.3",
|
|
29
27
|
"@preact/signals-core": "^1.6.0",
|
|
30
28
|
"@radix-ui/react-context": "^1.0.0",
|
|
31
29
|
"effect": "^3.9.2",
|
|
32
|
-
"@dxos/debug": "0.7.
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/react-ui-
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
30
|
+
"@dxos/debug": "0.7.2-main.f1adc9f",
|
|
31
|
+
"@dxos/echo-schema": "0.7.2-main.f1adc9f",
|
|
32
|
+
"@dxos/react-ui-attention": "0.7.2-main.f1adc9f",
|
|
33
|
+
"@dxos/log": "0.7.2-main.f1adc9f",
|
|
34
|
+
"@dxos/react-ui-mosaic": "0.7.2-main.f1adc9f",
|
|
35
|
+
"@dxos/invariant": "0.7.2-main.f1adc9f",
|
|
36
|
+
"@dxos/react-ui-types": "0.7.2-main.f1adc9f",
|
|
37
|
+
"@dxos/util": "0.7.2-main.f1adc9f",
|
|
38
|
+
"@dxos/react-ui-text-tooltip": "0.7.2-main.f1adc9f"
|
|
41
39
|
},
|
|
42
40
|
"devDependencies": {
|
|
43
41
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -46,18 +44,18 @@
|
|
|
46
44
|
"react": "~18.2.0",
|
|
47
45
|
"react-dom": "~18.2.0",
|
|
48
46
|
"vite": "5.4.7",
|
|
49
|
-
"@dxos/random": "0.7.
|
|
50
|
-
"@dxos/react-ui": "0.7.
|
|
51
|
-
"@dxos/react-ui-theme": "0.7.
|
|
52
|
-
"@dxos/storybook-utils": "0.7.
|
|
47
|
+
"@dxos/random": "0.7.2-main.f1adc9f",
|
|
48
|
+
"@dxos/react-ui": "0.7.2-main.f1adc9f",
|
|
49
|
+
"@dxos/react-ui-theme": "0.7.2-main.f1adc9f",
|
|
50
|
+
"@dxos/storybook-utils": "0.7.2-main.f1adc9f"
|
|
53
51
|
},
|
|
54
52
|
"peerDependencies": {
|
|
55
53
|
"@phosphor-icons/react": "^2.1.5",
|
|
56
54
|
"effect": "^3.9.2",
|
|
57
55
|
"react": "~18.2.0",
|
|
58
56
|
"react-dom": "~18.2.0",
|
|
59
|
-
"@dxos/react-ui
|
|
60
|
-
"@dxos/react-ui": "0.7.
|
|
57
|
+
"@dxos/react-ui": "0.7.2-main.f1adc9f",
|
|
58
|
+
"@dxos/react-ui-theme": "0.7.2-main.f1adc9f"
|
|
61
59
|
},
|
|
62
60
|
"publishConfig": {
|
|
63
61
|
"access": "public"
|
|
@@ -32,11 +32,16 @@ const strokeSize = 2;
|
|
|
32
32
|
const terminalSize = 8;
|
|
33
33
|
const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
|
|
34
34
|
|
|
35
|
+
export type DropIndicatorProps = {
|
|
36
|
+
edge: Edge;
|
|
37
|
+
gap?: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
35
40
|
/**
|
|
36
41
|
* This is a tailwind port of `@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box`
|
|
37
42
|
*/
|
|
38
|
-
export const DropIndicator = ({ edge, gap =
|
|
39
|
-
const lineOffset = `calc(-0.5 * (${gap} + ${strokeSize}px))`;
|
|
43
|
+
export const DropIndicator = ({ edge, gap = 0 }: DropIndicatorProps) => {
|
|
44
|
+
const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
|
|
40
45
|
|
|
41
46
|
const orientation = edgeToOrientationMap[edge];
|
|
42
47
|
|
|
@@ -10,10 +10,6 @@ import { mx } from '@dxos/react-ui-theme';
|
|
|
10
10
|
// Tree item hitbox
|
|
11
11
|
// https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx#tree-item
|
|
12
12
|
|
|
13
|
-
export type DropIndicatorProps = {
|
|
14
|
-
instruction: Instruction;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
13
|
type InstructionType = Exclude<Instruction, { type: 'instruction-blocked' }>['type'];
|
|
18
14
|
type Orientation = 'sibling' | 'child';
|
|
19
15
|
|
|
@@ -42,14 +38,17 @@ const instructionStyles: Record<InstructionType, HTMLAttributes<HTMLElement>['cl
|
|
|
42
38
|
const strokeSize = 2;
|
|
43
39
|
const terminalSize = 8;
|
|
44
40
|
const offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
|
|
45
|
-
const gap = '0px';
|
|
46
41
|
|
|
47
|
-
export
|
|
48
|
-
|
|
42
|
+
export type DropIndicatorProps = {
|
|
43
|
+
instruction: Instruction;
|
|
44
|
+
gap?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const DropIndicator = ({ instruction, gap = 0 }: DropIndicatorProps) => {
|
|
48
|
+
const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize}px))`;
|
|
49
49
|
const isBlocked = instruction.type === 'instruction-blocked';
|
|
50
50
|
const desiredInstruction = isBlocked ? instruction.desired : instruction;
|
|
51
51
|
const orientation = edgeToOrientationMap[desiredInstruction.type];
|
|
52
|
-
|
|
53
52
|
if (isBlocked) {
|
|
54
53
|
return null;
|
|
55
54
|
}
|
|
@@ -9,71 +9,83 @@ import { extractInstruction, type Instruction } from '@atlaskit/pragmatic-drag-a
|
|
|
9
9
|
import { type StoryObj, type Meta } from '@storybook/react';
|
|
10
10
|
import React, { useEffect } from 'react';
|
|
11
11
|
|
|
12
|
-
import { create } from '@dxos/echo-schema';
|
|
12
|
+
import { create, type ReactiveObject } from '@dxos/echo-schema';
|
|
13
13
|
import { faker } from '@dxos/random';
|
|
14
14
|
import { Icon } from '@dxos/react-ui';
|
|
15
15
|
import { Path } from '@dxos/react-ui-mosaic';
|
|
16
16
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
17
17
|
|
|
18
|
-
import { Tree
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
18
|
+
import { Tree } from './Tree';
|
|
19
|
+
import { type TreeData } from './TreeItem';
|
|
20
|
+
import { createTree, updateState, type TestItem } from './testing';
|
|
21
21
|
|
|
22
22
|
faker.seed(1234);
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
open: string[];
|
|
27
|
-
current: string[];
|
|
28
|
-
flatTree: ItemType[];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const state = create<State>({
|
|
32
|
-
tree: createTree(),
|
|
33
|
-
open: [],
|
|
34
|
-
current: [],
|
|
35
|
-
get flatTree() {
|
|
36
|
-
return flattenTree(this.tree, this.open, getItem);
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const Story = (args: Partial<TreeProps>) => {
|
|
41
|
-
// NOTE: If passed directly to args, this won't be reactive.
|
|
42
|
-
const items = state.flatTree;
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
return monitorForElements({
|
|
46
|
-
canMonitor: ({ source }) => isItem(source.data),
|
|
47
|
-
onDrop: ({ location, source }) => {
|
|
48
|
-
// Didn't drop on anything.
|
|
49
|
-
if (!location.current.dropTargets.length) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const target = location.current.dropTargets[0];
|
|
54
|
-
|
|
55
|
-
const instruction: Instruction | null = extractInstruction(target.data);
|
|
56
|
-
if (instruction !== null) {
|
|
57
|
-
updateState({
|
|
58
|
-
state: state.tree,
|
|
59
|
-
instruction,
|
|
60
|
-
source: source.data as ItemType,
|
|
61
|
-
target: target.data as ItemType,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
}, []);
|
|
67
|
-
|
|
68
|
-
return <Tree items={items} open={state.open} current={state.current} {...args} />;
|
|
69
|
-
};
|
|
24
|
+
const tree = create<TestItem>(createTree());
|
|
25
|
+
const state = new Map<string, ReactiveObject<{ open: boolean; current: boolean }>>();
|
|
70
26
|
|
|
71
27
|
const meta: Meta<typeof Tree> = {
|
|
72
28
|
title: 'ui/react-ui-list/Tree',
|
|
73
29
|
component: Tree,
|
|
74
|
-
render: Story,
|
|
75
30
|
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
31
|
+
render: (args) => {
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
return monitorForElements({
|
|
34
|
+
canMonitor: ({ source }) => typeof source.data.id === 'string' && Array.isArray(source.data.path),
|
|
35
|
+
onDrop: ({ location, source }) => {
|
|
36
|
+
// Didn't drop on anything.
|
|
37
|
+
if (!location.current.dropTargets.length) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const target = location.current.dropTargets[0];
|
|
42
|
+
|
|
43
|
+
const instruction: Instruction | null = extractInstruction(target.data);
|
|
44
|
+
if (instruction !== null) {
|
|
45
|
+
updateState({
|
|
46
|
+
state: tree,
|
|
47
|
+
instruction,
|
|
48
|
+
source: source.data as TreeData,
|
|
49
|
+
target: target.data as TreeData,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
return <Tree {...args} />;
|
|
57
|
+
},
|
|
76
58
|
args: {
|
|
59
|
+
id: tree.id,
|
|
60
|
+
getItems: (testItem?: TestItem) => {
|
|
61
|
+
return testItem?.items ?? tree.items;
|
|
62
|
+
},
|
|
63
|
+
getProps: (testItem: TestItem) => ({
|
|
64
|
+
id: testItem.id,
|
|
65
|
+
label: testItem.name,
|
|
66
|
+
icon: testItem.icon,
|
|
67
|
+
...((testItem.items?.length ?? 0) > 0 && {
|
|
68
|
+
parentOf: testItem.items!.map(({ id }) => id),
|
|
69
|
+
}),
|
|
70
|
+
}),
|
|
71
|
+
isOpen: (_path: string[]) => {
|
|
72
|
+
const path = Path.create(..._path);
|
|
73
|
+
const object = state.get(path) ?? create({ open: false, current: false });
|
|
74
|
+
if (!state.has(path)) {
|
|
75
|
+
state.set(path, object);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return object.open;
|
|
79
|
+
},
|
|
80
|
+
isCurrent: (_path: string[]) => {
|
|
81
|
+
const path = Path.create(..._path);
|
|
82
|
+
const object = state.get(path) ?? create({ open: false, current: false });
|
|
83
|
+
if (!state.has(path)) {
|
|
84
|
+
state.set(path, object);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return object.current;
|
|
88
|
+
},
|
|
77
89
|
renderColumns: () => {
|
|
78
90
|
return (
|
|
79
91
|
<div className='flex items-center'>
|
|
@@ -81,26 +93,15 @@ const meta: Meta<typeof Tree> = {
|
|
|
81
93
|
</div>
|
|
82
94
|
);
|
|
83
95
|
},
|
|
84
|
-
onOpenChange: (
|
|
85
|
-
const path = Path.create(...
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
} else {
|
|
89
|
-
const index = state.open.indexOf(path);
|
|
90
|
-
if (index > -1) {
|
|
91
|
-
state.open.splice(index, 1);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
96
|
+
onOpenChange: ({ path: _path, open }) => {
|
|
97
|
+
const path = Path.create(..._path);
|
|
98
|
+
const object = state.get(path);
|
|
99
|
+
object!.open = open;
|
|
94
100
|
},
|
|
95
|
-
onSelect: (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const index = state.current.indexOf(item.id);
|
|
100
|
-
if (index > -1) {
|
|
101
|
-
state.current.splice(index, 1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
101
|
+
onSelect: ({ path: _path, current }) => {
|
|
102
|
+
const path = Path.create(..._path);
|
|
103
|
+
const object = state.get(path);
|
|
104
|
+
object!.current = current;
|
|
104
105
|
},
|
|
105
106
|
},
|
|
106
107
|
};
|
|
@@ -2,26 +2,23 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React from 'react';
|
|
5
|
+
import React, { useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Treegrid, type TreegridRootProps } from '@dxos/react-ui';
|
|
8
|
-
import { Path } from '@dxos/react-ui-mosaic';
|
|
9
8
|
|
|
9
|
+
import { type TreeContextType, TreeProvider } from './TreeContext';
|
|
10
10
|
import { TreeItem, type TreeItemProps } from './TreeItem';
|
|
11
|
-
import { getMode } from './helpers';
|
|
12
|
-
import { type ItemType } from './types';
|
|
13
11
|
|
|
14
|
-
export type TreeProps<T
|
|
15
|
-
|
|
16
|
-
open: string[];
|
|
17
|
-
current: string[];
|
|
18
|
-
} & Partial<Pick<TreegridRootProps, 'gridTemplateColumns' | 'classNames'>> &
|
|
12
|
+
export type TreeProps<T = any> = { id: string } & TreeContextType &
|
|
13
|
+
Partial<Pick<TreegridRootProps, 'gridTemplateColumns' | 'classNames'>> &
|
|
19
14
|
Pick<TreeItemProps<T>, 'draggable' | 'renderColumns' | 'canDrop' | 'onOpenChange' | 'onSelect'>;
|
|
20
15
|
|
|
21
|
-
export const Tree = <T
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
export const Tree = <T = any,>({
|
|
17
|
+
id,
|
|
18
|
+
getItems,
|
|
19
|
+
getProps,
|
|
20
|
+
isOpen,
|
|
21
|
+
isCurrent,
|
|
25
22
|
draggable = false,
|
|
26
23
|
gridTemplateColumns = '[tree-row-start] 1fr min-content [tree-row-end]',
|
|
27
24
|
classNames,
|
|
@@ -30,27 +27,35 @@ export const Tree = <T extends ItemType = ItemType>({
|
|
|
30
27
|
onOpenChange,
|
|
31
28
|
onSelect,
|
|
32
29
|
}: TreeProps<T>) => {
|
|
30
|
+
const context = useMemo(
|
|
31
|
+
() => ({
|
|
32
|
+
getItems,
|
|
33
|
+
getProps,
|
|
34
|
+
isOpen,
|
|
35
|
+
isCurrent,
|
|
36
|
+
}),
|
|
37
|
+
[getItems, getProps, isOpen, isCurrent],
|
|
38
|
+
);
|
|
39
|
+
const items = getItems();
|
|
40
|
+
const path = useMemo(() => [id], [id]);
|
|
41
|
+
|
|
33
42
|
return (
|
|
34
43
|
<Treegrid.Root gridTemplateColumns={gridTemplateColumns} classNames={classNames}>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<TreeItem<T>
|
|
44
|
+
<TreeProvider value={context}>
|
|
45
|
+
{items.map((item, index) => (
|
|
46
|
+
<TreeItem
|
|
40
47
|
key={item.id}
|
|
41
48
|
item={item}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// TODO(wittjosiah): This should also be path-based.
|
|
45
|
-
current={current.includes(item.id)}
|
|
49
|
+
last={index === items.length - 1}
|
|
50
|
+
path={path}
|
|
46
51
|
draggable={draggable}
|
|
47
52
|
renderColumns={renderColumns}
|
|
48
53
|
canDrop={canDrop}
|
|
49
54
|
onOpenChange={onOpenChange}
|
|
50
55
|
onSelect={onSelect}
|
|
51
56
|
/>
|
|
52
|
-
)
|
|
53
|
-
|
|
57
|
+
))}
|
|
58
|
+
</TreeProvider>
|
|
54
59
|
</Treegrid.Root>
|
|
55
60
|
);
|
|
56
61
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext, useContext } from 'react';
|
|
6
|
+
|
|
7
|
+
import { raise } from '@dxos/debug';
|
|
8
|
+
import { type Label } from '@dxos/react-ui';
|
|
9
|
+
|
|
10
|
+
export type PropsFromTreeItem = {
|
|
11
|
+
id: string;
|
|
12
|
+
label: Label;
|
|
13
|
+
parentOf?: string[];
|
|
14
|
+
icon?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
headingClassName?: string;
|
|
18
|
+
testId?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type TreeContextType<T = any> = {
|
|
22
|
+
getItems: (parent?: T) => T[];
|
|
23
|
+
getProps: (item: T, parent: string[]) => PropsFromTreeItem;
|
|
24
|
+
isOpen: (path: string[], item: T) => boolean;
|
|
25
|
+
isCurrent: (path: string[], item: T) => boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const TreeContext = createContext<null | TreeContextType>(null);
|
|
29
|
+
|
|
30
|
+
export const useTree = () => useContext(TreeContext) ?? raise(new Error('TreeContext not found'));
|
|
31
|
+
|
|
32
|
+
export const TreeProvider = TreeContext.Provider;
|