@dxos/plugin-navtree 0.8.3-staging.0fa589b → 0.8.4-main.1068cf700f
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/app-graph-builder-XGA4GPGL.mjs +44 -0
- package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +7 -0
- package/dist/lib/browser/chunk-63YLDLLE.mjs +1373 -0
- package/dist/lib/browser/chunk-63YLDLLE.mjs.map +7 -0
- package/dist/lib/browser/chunk-X2HDG62A.mjs +23 -0
- package/dist/lib/browser/chunk-X2HDG62A.mjs.map +7 -0
- package/dist/lib/browser/chunk-YKTYPINZ.mjs +19 -0
- package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +89 -100
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/{keyboard-DDFATRUG.mjs → keyboard-46XQHY2O.mjs} +21 -19
- package/dist/lib/browser/keyboard-46XQHY2O.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/operation-resolver-NNNDII45.mjs +53 -0
- package/dist/lib/browser/operation-resolver-NNNDII45.mjs.map +7 -0
- package/dist/lib/browser/react-surface-APSEG23H.mjs +59 -0
- package/dist/lib/browser/react-surface-APSEG23H.mjs.map +7 -0
- package/dist/lib/browser/state-M5YUCIQU.mjs +121 -0
- package/dist/lib/browser/state-M5YUCIQU.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +2 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +3 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +5 -105
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard/index.d.ts +3 -0
- package/dist/types/src/capabilities/keyboard/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts +5 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/index.d.ts +3 -0
- package/dist/types/src/capabilities/state/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/state.d.ts +6 -0
- package/dist/types/src/capabilities/state/state.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +3 -2
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -1
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts +32 -3
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +29 -4
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContainer.d.ts +8 -1
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +6 -6
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +33 -4
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +6 -4
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +6 -7
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts +12 -0
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +8 -8
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +4 -5
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/hooks.d.ts +32 -1
- package/dist/types/src/hooks.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +3 -4
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +5 -6
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.d.ts +2 -2
- package/dist/types/src/testing/update-state.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +14 -13
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/capabilities.d.ts +16 -0
- package/dist/types/src/types/capabilities.d.ts.map +1 -0
- package/dist/types/src/types/events.d.ts +5 -0
- package/dist/types/src/types/events.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +4 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
- package/dist/types/src/types/schema.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +8 -9
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +56 -55
- package/src/NavTreePlugin.tsx +64 -84
- package/src/capabilities/app-graph-builder/app-graph-builder.ts +42 -0
- package/src/capabilities/app-graph-builder/index.ts +7 -0
- package/src/capabilities/index.ts +5 -9
- package/src/capabilities/keyboard/index.ts +7 -0
- package/src/capabilities/keyboard/keyboard.ts +66 -0
- package/src/capabilities/operation-resolver/index.ts +7 -0
- package/src/capabilities/operation-resolver/operation-resolver.ts +42 -0
- package/src/capabilities/react-surface/index.ts +7 -0
- package/src/capabilities/react-surface/react-surface.tsx +55 -0
- package/src/capabilities/state/index.ts +7 -0
- package/src/capabilities/state/state.ts +122 -0
- package/src/components/CommandsDialog/CommandsDialog.tsx +108 -98
- package/src/components/CommandsDialog/CommandsTrigger.tsx +8 -19
- package/src/components/NavTree/NavTree.stories.tsx +100 -94
- package/src/components/NavTree/NavTree.tsx +12 -18
- package/src/components/NavTreeContainer.tsx +283 -259
- package/src/components/NavTreeDocumentTitle.tsx +5 -4
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +21 -13
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +28 -21
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +38 -32
- package/src/components/Sidebar/L0Menu.tsx +115 -143
- package/src/components/Sidebar/L1Panel.tsx +177 -122
- package/src/components/Sidebar/L1Tabs.tsx +33 -0
- package/src/components/Sidebar/index.ts +1 -0
- package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -8
- package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
- package/src/components/index.ts +2 -1
- package/src/components/types.ts +9 -8
- package/src/experimental/Tree.stories.tsx +77 -85
- package/src/experimental/Tree.tsx +17 -35
- package/src/hooks.ts +54 -2
- package/src/index.ts +1 -2
- package/src/meta.ts +11 -8
- package/src/testing/app-graph-builder.ts +159 -234
- package/src/testing/generator.ts +20 -18
- package/src/testing/update-state.ts +6 -6
- package/src/translations.ts +7 -4
- package/src/types/capabilities.ts +21 -0
- package/src/types/events.ts +12 -0
- package/src/types/index.ts +7 -0
- package/src/{types.ts → types/schema.ts} +9 -8
- package/src/util.ts +14 -35
- package/dist/lib/browser/app-graph-builder-P7AY3K72.mjs +0 -45
- package/dist/lib/browser/app-graph-builder-P7AY3K72.mjs.map +0 -7
- package/dist/lib/browser/chunk-33VLL4IJ.mjs +0 -15
- package/dist/lib/browser/chunk-33VLL4IJ.mjs.map +0 -7
- package/dist/lib/browser/chunk-IEW3JD5C.mjs +0 -16
- package/dist/lib/browser/chunk-IEW3JD5C.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZJPL4XJD.mjs +0 -1429
- package/dist/lib/browser/chunk-ZJPL4XJD.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-NAYKKAOP.mjs +0 -47
- package/dist/lib/browser/intent-resolver-NAYKKAOP.mjs.map +0 -7
- package/dist/lib/browser/keyboard-DDFATRUG.mjs.map +0 -7
- package/dist/lib/browser/react-surface-H3JRTVNU.mjs +0 -51
- package/dist/lib/browser/react-surface-H3JRTVNU.mjs.map +0 -7
- package/dist/lib/browser/state-J6AKZRB4.mjs +0 -117
- package/dist/lib/browser/state-J6AKZRB4.mjs.map +0 -7
- package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/capabilities.d.ts +0 -21
- package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/keyboard.d.ts +0 -4
- package/dist/types/src/capabilities/keyboard.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface.d.ts +0 -4
- package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
- package/dist/types/src/capabilities/state.d.ts +0 -20
- package/dist/types/src/capabilities/state.d.ts.map +0 -1
- package/dist/types/src/events.d.ts +0 -4
- package/dist/types/src/events.d.ts.map +0 -1
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder.ts +0 -52
- package/src/capabilities/capabilities.ts +0 -20
- package/src/capabilities/intent-resolver.ts +0 -37
- package/src/capabilities/keyboard.ts +0 -59
- package/src/capabilities/react-surface.tsx +0 -45
- package/src/capabilities/state.ts +0 -104
- package/src/events.ts +0 -11
|
@@ -2,42 +2,18 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import { House, List, Planet, PlusCircle, Sailboat } from '@phosphor-icons/react';
|
|
8
|
-
import { type Meta } from '@storybook/react';
|
|
9
|
-
import React, { type JSX, type PropsWithChildren, useEffect, useState } from 'react';
|
|
5
|
+
import { type Meta } from '@storybook/react-vite';
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
10
7
|
|
|
11
8
|
import { faker } from '@dxos/random';
|
|
12
|
-
import {
|
|
13
|
-
import { withLayout, withTheme } from '@dxos/
|
|
9
|
+
import { Icon, IconButton, Layout, ScrollArea } from '@dxos/react-ui';
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
import { mx } from '@dxos/ui-theme';
|
|
14
12
|
|
|
15
13
|
import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visitor } from './Tree';
|
|
16
14
|
|
|
17
15
|
faker.seed(1234);
|
|
18
16
|
|
|
19
|
-
/**
|
|
20
|
-
* Space:
|
|
21
|
-
* - Space panels are separated from each other to give them more weight than folders.
|
|
22
|
-
* - Private space isn't different (just first, different icon).
|
|
23
|
-
* - Edit titles in place.
|
|
24
|
-
*
|
|
25
|
-
* Navigation:
|
|
26
|
-
* - up/down across spaces/folder peers
|
|
27
|
-
* - right to enter space/folder children
|
|
28
|
-
* - left to parent
|
|
29
|
-
*/
|
|
30
|
-
const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Element }>) => {
|
|
31
|
-
return (
|
|
32
|
-
<div className='flex'>
|
|
33
|
-
{/* TODO(burdon): Custom thin scrollbar. */}
|
|
34
|
-
{/* TODO(burdon): Horizontal scrolling within navtree? */}
|
|
35
|
-
<div className='flex flex-col overflow-y-auto w-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
|
|
36
|
-
<div className='flex flex-col grow overflow-hidden'>{children}</div>
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
17
|
// TODO(burdon): Generate.
|
|
42
18
|
const data: TreeNodeData[] = [
|
|
43
19
|
{
|
|
@@ -48,7 +24,7 @@ const data: TreeNodeData[] = [
|
|
|
48
24
|
id: faker.string.uuid(),
|
|
49
25
|
title: 'plugins/Personal Space',
|
|
50
26
|
color: 'text-green-400',
|
|
51
|
-
|
|
27
|
+
iconName: 'ph--house--regular',
|
|
52
28
|
children: [
|
|
53
29
|
{
|
|
54
30
|
id: faker.string.uuid(),
|
|
@@ -83,7 +59,7 @@ const data: TreeNodeData[] = [
|
|
|
83
59
|
{
|
|
84
60
|
id: faker.string.uuid(),
|
|
85
61
|
title: faker.commerce.productName(),
|
|
86
|
-
|
|
62
|
+
iconName: 'ph--planet--regular',
|
|
87
63
|
children: [
|
|
88
64
|
{
|
|
89
65
|
id: faker.string.uuid(),
|
|
@@ -94,38 +70,17 @@ const data: TreeNodeData[] = [
|
|
|
94
70
|
{
|
|
95
71
|
id: faker.string.uuid(),
|
|
96
72
|
title: faker.commerce.productName(),
|
|
97
|
-
|
|
73
|
+
iconName: 'ph--sailboat--regular',
|
|
98
74
|
},
|
|
99
75
|
{
|
|
100
76
|
id: faker.string.uuid(),
|
|
101
77
|
title: faker.commerce.productName(),
|
|
102
|
-
|
|
78
|
+
iconName: 'ph--planet--regular',
|
|
103
79
|
},
|
|
104
80
|
],
|
|
105
81
|
},
|
|
106
82
|
];
|
|
107
83
|
|
|
108
|
-
export const Default = () => {
|
|
109
|
-
return <Container sidebar={<Sidebar mutate />} />;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export const Visitor = () => {
|
|
113
|
-
const [items] = useState(data);
|
|
114
|
-
const root = items[0];
|
|
115
|
-
const [openItems] = useState<ItemMap>({ [root.children![0].id]: true });
|
|
116
|
-
return (
|
|
117
|
-
<div className='flex flex-col'>
|
|
118
|
-
{Array.from(visitor(root, openItems)).map(({ node: { id, title }, depth }) => (
|
|
119
|
-
<div key={id} className='grid grid-cols-[40px_400px_400px] font-mono'>
|
|
120
|
-
<div>{depth}</div>
|
|
121
|
-
<div>{id}</div>
|
|
122
|
-
<div>{title}</div>
|
|
123
|
-
</div>
|
|
124
|
-
))}
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
84
|
const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
130
85
|
const [items, setItems] = useState(data);
|
|
131
86
|
const root = items[0];
|
|
@@ -157,7 +112,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
157
112
|
}
|
|
158
113
|
}, []);
|
|
159
114
|
|
|
160
|
-
const handleCreateItem: TreeProps['onMenuAction'] = (id
|
|
115
|
+
const handleCreateItem: TreeProps['onMenuAction'] = (id) => {
|
|
161
116
|
setItems((items) => {
|
|
162
117
|
let parent: TreeNodeData | undefined;
|
|
163
118
|
visitNodes(root, (node) => {
|
|
@@ -181,7 +136,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
181
136
|
setItems((items) => {
|
|
182
137
|
items[0].children?.push({
|
|
183
138
|
id: faker.string.uuid(),
|
|
184
|
-
|
|
139
|
+
iconName: 'ph--planet--regular',
|
|
185
140
|
title: faker.commerce.productName(),
|
|
186
141
|
});
|
|
187
142
|
|
|
@@ -190,43 +145,80 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
190
145
|
};
|
|
191
146
|
|
|
192
147
|
return (
|
|
193
|
-
<
|
|
194
|
-
<
|
|
195
|
-
<
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
148
|
+
<Layout.Main>
|
|
149
|
+
<ScrollArea.Root orientation='vertical' thin>
|
|
150
|
+
<ScrollArea.Viewport>
|
|
151
|
+
<Tree
|
|
152
|
+
className='p-0.5 gap-1'
|
|
153
|
+
node={root}
|
|
154
|
+
open={openItems}
|
|
155
|
+
selected={selectedItems}
|
|
156
|
+
active={activeItems}
|
|
157
|
+
onChangeOpen={(id, open) => setOpenItems((items) => ({ ...items, [id]: open }))}
|
|
158
|
+
onChangeSelected={(id, open) => setSelectedItems((items) => ({ ...items, [id]: open }))}
|
|
159
|
+
onMenuAction={handleCreateItem}
|
|
160
|
+
getSlots={(node, open, depth) => {
|
|
161
|
+
if (depth === 1) {
|
|
162
|
+
return {
|
|
163
|
+
root: 'rounded bg-white dark:bg-neutral-850',
|
|
164
|
+
header: mx('rounded-t bg-neutral-50 dark:bg-neutral-900', !open && 'rounded-b'),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
</ScrollArea.Viewport>
|
|
170
|
+
</ScrollArea.Root>
|
|
171
|
+
|
|
172
|
+
<div className='flex items-center my-2 pli-2 gap-2'>
|
|
173
|
+
<IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
|
|
217
174
|
<span className='grow text-sm' onClick={handleCreateSpace}>
|
|
218
175
|
New space
|
|
219
176
|
</span>
|
|
220
|
-
<
|
|
177
|
+
<Icon icon='ph--list--regular' />
|
|
221
178
|
</div>
|
|
222
|
-
</
|
|
179
|
+
</Layout.Main>
|
|
223
180
|
);
|
|
224
181
|
};
|
|
225
182
|
|
|
226
|
-
const meta
|
|
183
|
+
const meta = {
|
|
227
184
|
title: 'plugins/plugin-navtree/experimental/Tree',
|
|
228
185
|
component: Tree,
|
|
229
|
-
decorators: [withTheme, withLayout({
|
|
230
|
-
|
|
186
|
+
decorators: [withTheme(), withLayout({ layout: 'column', classNames: 'is-[20rem]' })],
|
|
187
|
+
parameters: {
|
|
188
|
+
layout: 'fullscreen',
|
|
189
|
+
},
|
|
190
|
+
} satisfies Meta<typeof Tree>;
|
|
231
191
|
|
|
232
192
|
export default meta;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Space:
|
|
196
|
+
* - Space panels are separated from each other to give them more weight than folders.
|
|
197
|
+
* - Private space isn't different (just first, different icon).
|
|
198
|
+
* - Edit titles in place.
|
|
199
|
+
*
|
|
200
|
+
* Navigation:
|
|
201
|
+
* - up/down across spaces/folder peers
|
|
202
|
+
* - right to enter space/folder children
|
|
203
|
+
* - left to parent
|
|
204
|
+
*/
|
|
205
|
+
export const Default = () => {
|
|
206
|
+
return <Sidebar mutate />;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const Visitor = () => {
|
|
210
|
+
const [items] = useState(data);
|
|
211
|
+
const root = items[0];
|
|
212
|
+
const [openItems] = useState<ItemMap>({ [root.children![0].id]: true });
|
|
213
|
+
return (
|
|
214
|
+
<div className='flex flex-col'>
|
|
215
|
+
{Array.from(visitor(root, openItems)).map(({ node: { id, title }, depth }) => (
|
|
216
|
+
<div key={id} className='grid grid-cols-[40px_400px_400px] font-mono'>
|
|
217
|
+
<div>{depth}</div>
|
|
218
|
+
<div>{id}</div>
|
|
219
|
+
<div>{title}</div>
|
|
220
|
+
</div>
|
|
221
|
+
))}
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
@@ -2,34 +2,25 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { CaretRight, Circle, File, Folder, type Icon, type IconProps, Plus, UserCircle } from '@phosphor-icons/react';
|
|
6
5
|
import React, { type HTMLAttributes, type PropsWithChildren } from 'react';
|
|
7
6
|
|
|
8
|
-
import { type ClassNameValue, type Size } from '@dxos/react-ui';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
// TODO(burdon): Rounded border if first/last.
|
|
12
|
-
const styles = {
|
|
13
|
-
hover: 'hover:bg-slate-400 dark:hover:bg-slate-800',
|
|
14
|
-
selected: '!bg-slate-300 dark:!bg-slate-700',
|
|
15
|
-
};
|
|
7
|
+
import { type ClassNameValue, Icon, type Size } from '@dxos/react-ui';
|
|
8
|
+
import { mx } from '@dxos/ui-theme';
|
|
16
9
|
|
|
17
10
|
export const IconButton = ({
|
|
18
|
-
|
|
11
|
+
iconName,
|
|
19
12
|
classNames,
|
|
20
13
|
size = 4,
|
|
21
14
|
onClick,
|
|
22
|
-
...props
|
|
23
15
|
}: {
|
|
24
|
-
|
|
16
|
+
iconName: string;
|
|
25
17
|
classNames?: ClassNameValue;
|
|
26
18
|
size?: Size;
|
|
27
|
-
} & Pick<
|
|
28
|
-
Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
|
|
19
|
+
} & Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
|
|
29
20
|
// TODO(burdon): Density aware.
|
|
30
21
|
return (
|
|
31
|
-
<div className={mx('flex
|
|
32
|
-
<Icon
|
|
22
|
+
<div className={mx('flex is-6 bs-6 items-center justify-center select-none', classNames)} onClick={onClick}>
|
|
23
|
+
<Icon icon={iconName} classNames='cursor-pointer' size={size} />
|
|
33
24
|
</div>
|
|
34
25
|
);
|
|
35
26
|
};
|
|
@@ -37,7 +28,7 @@ export const IconButton = ({
|
|
|
37
28
|
export type TreeNodeData = {
|
|
38
29
|
id: string;
|
|
39
30
|
title: string;
|
|
40
|
-
|
|
31
|
+
iconName?: string;
|
|
41
32
|
color?: string;
|
|
42
33
|
children?: TreeNodeData[];
|
|
43
34
|
};
|
|
@@ -123,9 +114,8 @@ const StateIcon = ({ node, open, selected, active }: TreeNodeProps) => {
|
|
|
123
114
|
// TODO(burdon): No animation if opening/closing folder.
|
|
124
115
|
return (
|
|
125
116
|
<IconButton
|
|
126
|
-
|
|
117
|
+
iconName={isActive ? 'ph--user-circle--regular' : 'ph--circle--regular'}
|
|
127
118
|
size={4}
|
|
128
|
-
weight={selected?.[id] ? 'fill' : 'duotone'}
|
|
129
119
|
classNames={mx(
|
|
130
120
|
'text-slate-500',
|
|
131
121
|
!isChildActive && 'opacity-0 transition duration-500',
|
|
@@ -143,7 +133,7 @@ const OpenIcon = ({
|
|
|
143
133
|
return (
|
|
144
134
|
(children?.length && open && (
|
|
145
135
|
<IconButton
|
|
146
|
-
|
|
136
|
+
iconName='ph--caret-right--regular'
|
|
147
137
|
size={3}
|
|
148
138
|
classNames={mx('transition duration-200', open?.[id] ? 'rotate-90' : 'transform-none')}
|
|
149
139
|
onClick={(ev) => {
|
|
@@ -157,23 +147,15 @@ const OpenIcon = ({
|
|
|
157
147
|
|
|
158
148
|
// TODO(burdon): Drag handle,
|
|
159
149
|
const ItemIcon = ({
|
|
160
|
-
node: { children,
|
|
150
|
+
node: { children, iconName = children?.length ? 'ph--folder--regular' : 'ph--file--regular', color },
|
|
161
151
|
}: Pick<TreeNodeProps, 'node'>) => {
|
|
162
|
-
return (
|
|
163
|
-
(Icon && (
|
|
164
|
-
<IconButton
|
|
165
|
-
Icon={Icon}
|
|
166
|
-
classNames={color ?? 'text-neutral-700 dark:text-neutral-300'}
|
|
167
|
-
weight={color ? 'duotone' : 'regular'}
|
|
168
|
-
/>
|
|
169
|
-
)) || <div />
|
|
170
|
-
);
|
|
152
|
+
return (iconName && <IconButton iconName={iconName} classNames={color ?? 'text-subdued'} />) || <div />;
|
|
171
153
|
};
|
|
172
154
|
|
|
173
155
|
const MenuItem = ({ node: { id }, onMenuAction }: Pick<TreeNodeProps, 'node' | 'onMenuAction'>) => {
|
|
174
156
|
return (
|
|
175
157
|
<IconButton
|
|
176
|
-
|
|
158
|
+
iconName='ph--plus--regular'
|
|
177
159
|
classNames='invisible group-hover:visible'
|
|
178
160
|
onClick={(ev) => {
|
|
179
161
|
ev.stopPropagation();
|
|
@@ -211,9 +193,9 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
|
|
|
211
193
|
<Grid
|
|
212
194
|
style={{ paddingLeft: `${(depth - 1) * 24}px` }}
|
|
213
195
|
className={mx(
|
|
214
|
-
'group
|
|
215
|
-
|
|
216
|
-
selected?.[id] &&
|
|
196
|
+
'group is-full items-center cursor-pointer bg-hoverSurface',
|
|
197
|
+
// TODO(burdon): Use data-active.
|
|
198
|
+
selected?.[id] && 'bg-activeSurface',
|
|
217
199
|
className,
|
|
218
200
|
)}
|
|
219
201
|
onClick={() => selected && onChangeSelected?.(id, !selected[id])}
|
|
@@ -256,7 +238,7 @@ export const TreeChildNodes = ({
|
|
|
256
238
|
} = props;
|
|
257
239
|
return (
|
|
258
240
|
<div className={mx('flex flex-col mt-0.5 gap-0.5', className)}>
|
|
259
|
-
{children?.map((child
|
|
241
|
+
{children?.map((child) => (
|
|
260
242
|
<TreeNode key={child.id} {...props} depth={depth + 1} node={child} ancestors={[...ancestors, props.node]} />
|
|
261
243
|
))}
|
|
262
244
|
</div>
|
package/src/hooks.ts
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type Atom, useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import { useEffect, useMemo } from 'react';
|
|
6
7
|
|
|
8
|
+
import { useCapability } from '@dxos/app-framework/ui';
|
|
7
9
|
import { type Node } from '@dxos/app-graph';
|
|
8
10
|
|
|
9
11
|
import { useNavTreeContext } from './components';
|
|
12
|
+
import { NavTreeCapabilities } from './types';
|
|
10
13
|
|
|
11
|
-
export const useLoadDescendents = (root?: Node) => {
|
|
14
|
+
export const useLoadDescendents = (root?: Node.Node) => {
|
|
12
15
|
const { loadDescendents } = useNavTreeContext();
|
|
13
16
|
useEffect(() => {
|
|
14
17
|
const frame = requestAnimationFrame(() => {
|
|
@@ -19,3 +22,52 @@ export const useLoadDescendents = (root?: Node) => {
|
|
|
19
22
|
return () => cancelAnimationFrame(frame);
|
|
20
23
|
}, [root]);
|
|
21
24
|
};
|
|
25
|
+
|
|
26
|
+
export type UseNavTreeStateResult = {
|
|
27
|
+
getItem: (path: string[]) => NavTreeCapabilities.NavTreeItemState;
|
|
28
|
+
getItemAtom: (path: string[]) => Atom.Atom<NavTreeCapabilities.NavTreeItemState>;
|
|
29
|
+
setItem: (path: string[], key: 'open' | 'current' | 'alternateTree', next: boolean) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hook that provides access to navtree state functions.
|
|
34
|
+
* For reactive subscriptions, use `useNavTreeItemState` or `useAtomValue(getItemAtom(path))`.
|
|
35
|
+
*/
|
|
36
|
+
export const useNavTreeState = (): UseNavTreeStateResult => {
|
|
37
|
+
return useCapability(NavTreeCapabilities.State);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Hook that subscribes to a single navtree item's state.
|
|
42
|
+
* Use this for fine-grained reactivity.
|
|
43
|
+
*/
|
|
44
|
+
export const useNavTreeItemState = (path: string[]): NavTreeCapabilities.NavTreeItemState => {
|
|
45
|
+
const { getItemAtom } = useCapability(NavTreeCapabilities.State);
|
|
46
|
+
// Memoize the path to avoid creating new atoms on every render.
|
|
47
|
+
const pathKey = useMemo(() => path.join('~'), [path]);
|
|
48
|
+
const atom = useMemo(() => getItemAtom(path), [getItemAtom, pathKey]);
|
|
49
|
+
return useAtomValue(atom);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Hook that subscribes to the open state for a tree item.
|
|
54
|
+
* Designed to be passed to Tree component as useIsOpen prop.
|
|
55
|
+
*/
|
|
56
|
+
export const useIsOpen = (path: string[], _item?: any): boolean => {
|
|
57
|
+
return useNavTreeItemState(path).open;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Hook that subscribes to the current state for a tree item.
|
|
62
|
+
* Designed to be passed to Tree component as useIsCurrent prop.
|
|
63
|
+
*/
|
|
64
|
+
export const useIsCurrent = (path: string[], _item?: any): boolean => {
|
|
65
|
+
return useNavTreeItemState(path).current;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Hook that subscribes to the alternateTree state for a tree item.
|
|
70
|
+
*/
|
|
71
|
+
export const useIsAlternateTree = (path: string[], _item?: any): boolean => {
|
|
72
|
+
return useNavTreeItemState(path).alternateTree ?? false;
|
|
73
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export { NavTreeCapabilities } from './
|
|
6
|
-
export { NavTreeEvents } from './events';
|
|
5
|
+
export { NavTreeCapabilities, NavTreeEvents } from './types';
|
|
7
6
|
export * from './NavTreePlugin';
|
|
8
7
|
export * from './meta';
|
|
9
8
|
export * from './util';
|
package/src/meta.ts
CHANGED
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Plugin } from '@dxos/app-framework';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
6
7
|
|
|
7
|
-
export const
|
|
8
|
+
export const meta: Plugin.Meta = {
|
|
9
|
+
id: 'dxos.org/plugin/navtree',
|
|
10
|
+
name: 'Navtree',
|
|
11
|
+
description: trim`
|
|
12
|
+
Hierarchical navigation tree for browsing spaces, folders, and objects.
|
|
13
|
+
Provides sidebar navigation with collapsible sections and quick access to workspace content.
|
|
14
|
+
`,
|
|
15
|
+
};
|
|
8
16
|
|
|
9
17
|
// TODO(wittjosiah): Factor out.
|
|
10
18
|
export const KEY_BINDING = 'KeyBinding';
|
|
11
19
|
// TODO(wittjosiah): Factor out.
|
|
12
|
-
export const COMMANDS_DIALOG = `${
|
|
13
|
-
|
|
14
|
-
export const meta: PluginMeta = {
|
|
15
|
-
id: NAVTREE_PLUGIN,
|
|
16
|
-
name: 'Navtree',
|
|
17
|
-
};
|
|
20
|
+
export const COMMANDS_DIALOG = `${meta.id}/CommandsDialog`;
|