@dxos/plugin-navtree 0.8.4-main.f9ba587 → 0.8.4-main.fffef41
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-5J4LRWDX.mjs → app-graph-builder-OHSCN3GX.mjs} +13 -12
- package/dist/lib/browser/app-graph-builder-OHSCN3GX.mjs.map +7 -0
- package/dist/lib/browser/{chunk-WCARAZ7J.mjs → chunk-5VLWX4PK.mjs} +4 -4
- package/dist/lib/browser/chunk-5VLWX4PK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TZA65AKW.mjs → chunk-7D2MPHXV.mjs} +317 -262
- package/dist/lib/browser/chunk-7D2MPHXV.mjs.map +7 -0
- package/dist/lib/browser/chunk-E6MZBCU5.mjs +19 -0
- package/dist/lib/browser/chunk-E6MZBCU5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +8 -11
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-3XYN2CBU.mjs → intent-resolver-YUVXVPHG.mjs} +7 -7
- package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +7 -0
- package/dist/lib/browser/{keyboard-QRS6WOQH.mjs → keyboard-YYTYJW4M.mjs} +4 -4
- package/dist/lib/{node-esm/keyboard-MOZWHFUM.mjs.map → browser/keyboard-YYTYJW4M.mjs.map} +2 -2
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-N2HPMYCU.mjs → react-surface-J7MWWAGD.mjs} +10 -10
- package/dist/lib/browser/react-surface-J7MWWAGD.mjs.map +7 -0
- package/dist/lib/browser/{state-54DY3DOY.mjs → state-EUSVT6BI.mjs} +7 -7
- package/dist/lib/browser/state-EUSVT6BI.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +1 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +18 -15
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/state.d.ts +2 -2
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- 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 +2 -2
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +26 -4
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +32 -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 +2 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +5 -6
- 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 +2 -2
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/events.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 +7 -4
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -3
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +1 -1
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +4 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +1 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +49 -50
- package/src/NavTreePlugin.tsx +75 -76
- package/src/capabilities/app-graph-builder.ts +10 -9
- package/src/capabilities/capabilities.ts +2 -2
- package/src/capabilities/intent-resolver.ts +2 -2
- package/src/capabilities/keyboard.ts +2 -2
- package/src/capabilities/react-surface.tsx +5 -5
- package/src/capabilities/state.ts +4 -3
- package/src/components/CommandsDialog/CommandsDialog.tsx +15 -7
- package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -7
- package/src/components/NavTree/NavTree.stories.tsx +67 -53
- package/src/components/NavTree/NavTree.tsx +7 -3
- package/src/components/NavTreeContainer.tsx +91 -36
- package/src/components/NavTreeDocumentTitle.tsx +2 -2
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +4 -6
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +11 -10
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +33 -27
- package/src/components/Sidebar/L0Menu.tsx +56 -55
- package/src/components/Sidebar/L1Panel.tsx +72 -97
- package/src/components/Sidebar/L1Tabs.tsx +58 -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 +1 -1
- package/src/components/types.ts +3 -2
- package/src/events.ts +2 -2
- package/src/experimental/Tree.stories.tsx +36 -38
- package/src/experimental/Tree.tsx +17 -35
- package/src/meta.ts +10 -7
- package/src/testing/app-graph-builder.ts +20 -19
- package/src/testing/generator.ts +2 -2
- package/src/translations.ts +1 -0
- package/src/types.ts +4 -3
- package/src/util.ts +2 -20
- package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
- package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
- package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
- package/dist/lib/browser/chunk-TZA65AKW.mjs.map +0 -7
- package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
- package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
- package/dist/lib/browser/react-surface-N2HPMYCU.mjs.map +0 -7
- package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs +0 -46
- package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CY7QWR4R.mjs +0 -1429
- package/dist/lib/node-esm/chunk-CY7QWR4R.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-P2JGW3WR.mjs +0 -18
- package/dist/lib/node-esm/chunk-P2JGW3WR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-V3QXFDDP.mjs +0 -16
- package/dist/lib/node-esm/chunk-V3QXFDDP.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -150
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs +0 -48
- package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs.map +0 -7
- package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs +0 -52
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs +0 -52
- package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs.map +0 -7
- package/dist/lib/node-esm/state-Z3OTRC2I.mjs +0 -118
- package/dist/lib/node-esm/state-Z3OTRC2I.mjs.map +0 -7
|
@@ -7,6 +7,8 @@ import React from 'react';
|
|
|
7
7
|
import { Avatar, type AvatarStatus, type Size } from '@dxos/react-ui';
|
|
8
8
|
import { hexToFallback } from '@dxos/util';
|
|
9
9
|
|
|
10
|
+
import { L0ItemActiveTabIndicator } from '../Sidebar';
|
|
11
|
+
|
|
10
12
|
export type UserAccountAvatarProps = {
|
|
11
13
|
size?: Size;
|
|
12
14
|
userId?: string;
|
|
@@ -19,17 +21,23 @@ export const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAcco
|
|
|
19
21
|
const fallbackValue = hexToFallback(userId ?? '0');
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
<>
|
|
25
|
+
<L0ItemActiveTabIndicator classNames='inset-block-6' />
|
|
26
|
+
<div
|
|
27
|
+
className='grid place-items-center dx-focus-ring-group-indicator rounded-full'
|
|
28
|
+
data-joyride='welcome/account'
|
|
29
|
+
>
|
|
30
|
+
<Avatar.Root>
|
|
31
|
+
<Avatar.Content
|
|
32
|
+
variant='circle'
|
|
33
|
+
size={size ?? 12}
|
|
34
|
+
status={status ?? 'active'}
|
|
35
|
+
hue={hue || fallbackValue.hue}
|
|
36
|
+
fallback={emoji || fallbackValue.emoji}
|
|
37
|
+
data-testid='treeView.userAccount'
|
|
38
|
+
/>
|
|
39
|
+
</Avatar.Root>
|
|
40
|
+
</div>
|
|
41
|
+
</>
|
|
34
42
|
);
|
|
35
43
|
};
|
package/src/components/index.ts
CHANGED
package/src/components/types.ts
CHANGED
|
@@ -9,9 +9,10 @@ import type { Density } from '@dxos/react-ui';
|
|
|
9
9
|
import type { TreeProps } from '@dxos/react-ui-list';
|
|
10
10
|
import type { MaybePromise } from '@dxos/util';
|
|
11
11
|
|
|
12
|
-
import type { L1PanelProps } from './Sidebar';
|
|
13
12
|
import type { FlattenedActions, NavTreeItemGraphNode } from '../types';
|
|
14
13
|
|
|
14
|
+
import type { L1PanelProps } from './Sidebar';
|
|
15
|
+
|
|
15
16
|
export type NavTreeContextValue = Pick<
|
|
16
17
|
TreeProps<NavTreeItemGraphNode, { disposition?: string; sort?: boolean }>,
|
|
17
18
|
'useItems' | 'getProps' | 'isCurrent' | 'isOpen' | 'canDrop' | 'onOpenChange' | 'onSelect'
|
|
@@ -21,7 +22,7 @@ export type NavTreeContextValue = Pick<
|
|
|
21
22
|
topbar?: boolean;
|
|
22
23
|
popoverAnchorId?: string;
|
|
23
24
|
renderItemEnd?: FC<{ node: Node; open: boolean }>;
|
|
24
|
-
|
|
25
|
+
useActions: (node: Node) => FlattenedActions;
|
|
25
26
|
loadDescendents?: (node: Node) => MaybePromise<void>;
|
|
26
27
|
isAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
|
|
27
28
|
setAlternateTree?: (path: string[], open: boolean) => void;
|
package/src/events.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { Events } from '@dxos/app-framework';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { meta } from './meta';
|
|
8
8
|
|
|
9
9
|
export namespace NavTreeEvents {
|
|
10
|
-
export const StateReady = Events.createStateEvent(
|
|
10
|
+
export const StateReady = Events.createStateEvent(meta.id);
|
|
11
11
|
}
|
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
|
-
import { House, List, Planet, PlusCircle, Sailboat } from '@phosphor-icons/react';
|
|
8
5
|
import { type Meta } from '@storybook/react-vite';
|
|
9
6
|
import React, { type JSX, type PropsWithChildren, 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 } from '@dxos/react-ui';
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
14
12
|
|
|
15
13
|
import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visitor } from './Tree';
|
|
16
14
|
|
|
@@ -32,7 +30,7 @@ const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Eleme
|
|
|
32
30
|
<div className='flex'>
|
|
33
31
|
{/* TODO(burdon): Custom thin scrollbar. */}
|
|
34
32
|
{/* TODO(burdon): Horizontal scrolling within navtree? */}
|
|
35
|
-
<div className='flex flex-col overflow-y-auto
|
|
33
|
+
<div className='flex flex-col overflow-y-auto is-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
|
|
36
34
|
<div className='flex flex-col grow overflow-hidden'>{children}</div>
|
|
37
35
|
</div>
|
|
38
36
|
);
|
|
@@ -48,7 +46,7 @@ const data: TreeNodeData[] = [
|
|
|
48
46
|
id: faker.string.uuid(),
|
|
49
47
|
title: 'plugins/Personal Space',
|
|
50
48
|
color: 'text-green-400',
|
|
51
|
-
|
|
49
|
+
iconName: 'ph--house--regular',
|
|
52
50
|
children: [
|
|
53
51
|
{
|
|
54
52
|
id: faker.string.uuid(),
|
|
@@ -83,7 +81,7 @@ const data: TreeNodeData[] = [
|
|
|
83
81
|
{
|
|
84
82
|
id: faker.string.uuid(),
|
|
85
83
|
title: faker.commerce.productName(),
|
|
86
|
-
|
|
84
|
+
iconName: 'ph--planet--regular',
|
|
87
85
|
children: [
|
|
88
86
|
{
|
|
89
87
|
id: faker.string.uuid(),
|
|
@@ -94,38 +92,17 @@ const data: TreeNodeData[] = [
|
|
|
94
92
|
{
|
|
95
93
|
id: faker.string.uuid(),
|
|
96
94
|
title: faker.commerce.productName(),
|
|
97
|
-
|
|
95
|
+
iconName: 'ph--sailboat--regular',
|
|
98
96
|
},
|
|
99
97
|
{
|
|
100
98
|
id: faker.string.uuid(),
|
|
101
99
|
title: faker.commerce.productName(),
|
|
102
|
-
|
|
100
|
+
iconName: 'ph--planet--regular',
|
|
103
101
|
},
|
|
104
102
|
],
|
|
105
103
|
},
|
|
106
104
|
];
|
|
107
105
|
|
|
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
106
|
const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
130
107
|
const [items, setItems] = useState(data);
|
|
131
108
|
const root = items[0];
|
|
@@ -181,7 +158,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
181
158
|
setItems((items) => {
|
|
182
159
|
items[0].children?.push({
|
|
183
160
|
id: faker.string.uuid(),
|
|
184
|
-
|
|
161
|
+
iconName: 'ph--planet--regular',
|
|
185
162
|
title: faker.commerce.productName(),
|
|
186
163
|
});
|
|
187
164
|
|
|
@@ -212,21 +189,42 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
212
189
|
/>
|
|
213
190
|
</div>
|
|
214
191
|
|
|
215
|
-
<div className='flex items-center my-2
|
|
216
|
-
<
|
|
192
|
+
<div className='flex items-center my-2 pli-2 gap-2'>
|
|
193
|
+
<IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
|
|
217
194
|
<span className='grow text-sm' onClick={handleCreateSpace}>
|
|
218
195
|
New space
|
|
219
196
|
</span>
|
|
220
|
-
<
|
|
197
|
+
<Icon icon='ph--list--regular' />
|
|
221
198
|
</div>
|
|
222
199
|
</div>
|
|
223
200
|
);
|
|
224
201
|
};
|
|
225
202
|
|
|
226
|
-
const meta
|
|
203
|
+
const meta = {
|
|
227
204
|
title: 'plugins/plugin-navtree/experimental/Tree',
|
|
228
205
|
component: Tree,
|
|
229
|
-
decorators: [withTheme, withLayout({
|
|
230
|
-
}
|
|
206
|
+
decorators: [withTheme, withLayout({ container: 'column' })],
|
|
207
|
+
} satisfies Meta<typeof Tree>;
|
|
231
208
|
|
|
232
209
|
export default meta;
|
|
210
|
+
|
|
211
|
+
export const Default = () => {
|
|
212
|
+
return <Container sidebar={<Sidebar mutate />} />;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export const Visitor = () => {
|
|
216
|
+
const [items] = useState(data);
|
|
217
|
+
const root = items[0];
|
|
218
|
+
const [openItems] = useState<ItemMap>({ [root.children![0].id]: true });
|
|
219
|
+
return (
|
|
220
|
+
<div className='flex flex-col'>
|
|
221
|
+
{Array.from(visitor(root, openItems)).map(({ node: { id, title }, depth }) => (
|
|
222
|
+
<div key={id} className='grid grid-cols-[40px_400px_400px] font-mono'>
|
|
223
|
+
<div>{depth}</div>
|
|
224
|
+
<div>{id}</div>
|
|
225
|
+
<div>{title}</div>
|
|
226
|
+
</div>
|
|
227
|
+
))}
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
};
|
|
@@ -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/react-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/meta.ts
CHANGED
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type PluginMeta } from '@dxos/app-framework';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
6
7
|
|
|
7
|
-
export const
|
|
8
|
+
export const meta: PluginMeta = {
|
|
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`;
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { Atom } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Function from 'effect/Function';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
7
8
|
|
|
8
9
|
import { type PluginContext } from '@dxos/app-framework';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
10
|
-
import {
|
|
11
|
+
import { type BuilderExtensions, ROOT_ID, createExtension } from '@dxos/plugin-graph';
|
|
11
12
|
import { faker } from '@dxos/random';
|
|
12
13
|
|
|
13
14
|
export const storybookGraphBuilders = (context: PluginContext): BuilderExtensions => {
|
|
@@ -27,8 +28,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
27
28
|
createExtension({
|
|
28
29
|
id: 'app-menu',
|
|
29
30
|
actions: (node) =>
|
|
30
|
-
|
|
31
|
-
pipe(
|
|
31
|
+
Atom.make((get) =>
|
|
32
|
+
Function.pipe(
|
|
32
33
|
get(node),
|
|
33
34
|
Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
|
|
34
35
|
Option.map((node) => {
|
|
@@ -54,8 +55,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
54
55
|
createExtension({
|
|
55
56
|
id: 'user-account',
|
|
56
57
|
connector: (node) =>
|
|
57
|
-
|
|
58
|
-
pipe(
|
|
58
|
+
Atom.make((get) =>
|
|
59
|
+
Function.pipe(
|
|
59
60
|
get(node),
|
|
60
61
|
Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
|
|
61
62
|
Option.map(() => {
|
|
@@ -111,8 +112,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
111
112
|
id: 'spaces-root',
|
|
112
113
|
position: 'hoist',
|
|
113
114
|
connector: (node) =>
|
|
114
|
-
|
|
115
|
-
pipe(
|
|
115
|
+
Atom.make((get) =>
|
|
116
|
+
Function.pipe(
|
|
116
117
|
get(node),
|
|
117
118
|
Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
|
|
118
119
|
Option.map(() => {
|
|
@@ -137,7 +138,7 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
137
138
|
createExtension({
|
|
138
139
|
id: 'spaces',
|
|
139
140
|
connector: (node) => {
|
|
140
|
-
const count =
|
|
141
|
+
const count = Atom.make((get) => {
|
|
141
142
|
let value = 3;
|
|
142
143
|
const interval = setInterval(() => {
|
|
143
144
|
if (value >= 10) {
|
|
@@ -152,8 +153,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
152
153
|
return value;
|
|
153
154
|
});
|
|
154
155
|
|
|
155
|
-
return
|
|
156
|
-
pipe(
|
|
156
|
+
return Atom.make((get) =>
|
|
157
|
+
Function.pipe(
|
|
157
158
|
get(node),
|
|
158
159
|
Option.flatMap((node) => (node.id === 'spaces-root' ? Option.some(node) : Option.none())),
|
|
159
160
|
Option.map(() => {
|
|
@@ -178,8 +179,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
178
179
|
createExtension({
|
|
179
180
|
id: 'space-actions',
|
|
180
181
|
actions: (node) =>
|
|
181
|
-
|
|
182
|
-
pipe(
|
|
182
|
+
Atom.make((get) =>
|
|
183
|
+
Function.pipe(
|
|
183
184
|
get(node),
|
|
184
185
|
Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
|
|
185
186
|
Option.map((node) => {
|
|
@@ -204,7 +205,7 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
204
205
|
createExtension({
|
|
205
206
|
id: 'objects',
|
|
206
207
|
connector: (node) => {
|
|
207
|
-
const count =
|
|
208
|
+
const count = Atom.make((get) => {
|
|
208
209
|
let value = 3;
|
|
209
210
|
const interval = setInterval(() => {
|
|
210
211
|
if (value >= 20) {
|
|
@@ -219,8 +220,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
219
220
|
return value;
|
|
220
221
|
});
|
|
221
222
|
|
|
222
|
-
return
|
|
223
|
-
pipe(
|
|
223
|
+
return Atom.make((get) =>
|
|
224
|
+
Function.pipe(
|
|
224
225
|
get(node),
|
|
225
226
|
Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
|
|
226
227
|
Option.map((node) => {
|
|
@@ -244,8 +245,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
|
|
|
244
245
|
createExtension({
|
|
245
246
|
id: 'object-actions',
|
|
246
247
|
actions: (node) =>
|
|
247
|
-
|
|
248
|
-
pipe(
|
|
248
|
+
Atom.make((get) =>
|
|
249
|
+
Function.pipe(
|
|
249
250
|
get(node),
|
|
250
251
|
Option.flatMap((node) => (node.type === 'object' ? Option.some(node) : Option.none())),
|
|
251
252
|
Option.map((node) => {
|
package/src/testing/generator.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
7
|
import { type NodeArg } from '@dxos/app-graph';
|
|
8
8
|
import { type Live, Obj, Type } from '@dxos/echo';
|
|
9
|
-
import { TypedObject } from '@dxos/echo
|
|
9
|
+
import { TypedObject } from '@dxos/echo/internal';
|
|
10
10
|
import { faker } from '@dxos/random';
|
|
11
11
|
import { range } from '@dxos/util';
|
|
12
12
|
|
package/src/translations.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -28,13 +28,14 @@ export type FlattenedActions = {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
type SharedProperties = {
|
|
31
|
-
|
|
32
|
-
icon?: string;
|
|
31
|
+
testId?: string;
|
|
33
32
|
disabled?: boolean;
|
|
34
33
|
position?: Position;
|
|
35
|
-
|
|
34
|
+
label: Label;
|
|
36
35
|
className?: string;
|
|
37
36
|
headingClassName?: string;
|
|
37
|
+
icon?: string;
|
|
38
|
+
iconHue?: string;
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
export type NodeProperties = SharedProperties & {
|
package/src/util.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Action, type Node, type ReadableGraph,
|
|
5
|
+
import { type Action, type Node, type ReadableGraph, isActionLike } from '@dxos/app-graph';
|
|
6
6
|
import { isNonNullable } from '@dxos/util';
|
|
7
7
|
|
|
8
|
-
import { type
|
|
8
|
+
import { type NavTreeItemGraphNode } from './types';
|
|
9
9
|
|
|
10
10
|
export const getParent = (
|
|
11
11
|
graph: ReadableGraph,
|
|
@@ -88,24 +88,6 @@ export const getChildren = (
|
|
|
88
88
|
.filter(isNonNullable) as NavTreeItemGraphNode[];
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
-
export const getActions = (graph: ReadableGraph, node: Node): FlattenedActions => {
|
|
92
|
-
return graph.getActions(node.id).reduce(
|
|
93
|
-
(acc: FlattenedActions, arg) => {
|
|
94
|
-
if (arg.properties.disposition === 'item') {
|
|
95
|
-
return acc;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
acc.actions.push(arg);
|
|
99
|
-
if (!isAction(arg)) {
|
|
100
|
-
const actionGroup = graph.getActions(arg.id);
|
|
101
|
-
acc.groupedActions[arg.id] = actionGroup;
|
|
102
|
-
}
|
|
103
|
-
return acc;
|
|
104
|
-
},
|
|
105
|
-
{ actions: [], groupedActions: {} },
|
|
106
|
-
);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
91
|
export const l0ItemType = (item: Node<any>) => {
|
|
110
92
|
if (item.properties.disposition === 'collection') {
|
|
111
93
|
return 'collection';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/capabilities/app-graph-builder.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Rx } from '@effect-rx/rx-react';\nimport { Option, pipe } from 'effect';\n\nimport { Capabilities, contributes, type PluginContext, createIntent, LayoutAction } from '@dxos/app-framework';\nimport { createExtension, ROOT_ID } from '@dxos/plugin-graph';\n\nimport { COMMANDS_DIALOG, NAVTREE_PLUGIN } from '../meta';\n\nexport default (context: PluginContext) =>\n contributes(\n Capabilities.AppGraphBuilder,\n createExtension({\n id: NAVTREE_PLUGIN,\n actions: (node) =>\n Rx.make((get) =>\n pipe(\n get(node),\n Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),\n Option.map(() => [\n {\n id: COMMANDS_DIALOG,\n data: async () => {\n const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);\n await dispatch(\n createIntent(LayoutAction.UpdateDialog, {\n part: 'dialog',\n subject: COMMANDS_DIALOG,\n options: {\n blockAlign: 'start',\n },\n }),\n );\n },\n properties: {\n label: ['open commands label', { ns: NAVTREE_PLUGIN }],\n icon: 'ph--magnifying-glass--regular',\n keyBinding: {\n macos: 'meta+k',\n windows: 'ctrl+k',\n },\n },\n },\n ]),\n Option.getOrElse(() => []),\n ),\n ),\n }),\n );\n"],
|
|
5
|
-
"mappings": ";;;;;;AAIA,SAASA,UAAU;AACnB,SAASC,QAAQC,YAAY;AAE7B,SAASC,cAAcC,aAAiCC,cAAcC,oBAAoB;AAC1F,SAASC,iBAAiBC,eAAe;AAIzC,IAAA,4BAAe,CAACC,YACdC,YACEC,aAAaC,iBACbC,gBAAgB;EACdC,IAAIC;EACJC,SAAS,CAACC,SACRC,GAAGC,KAAK,CAACC,QACPC,KACED,IAAIH,IAAAA,GACJK,OAAOC,QAAQ,CAACN,UAAUA,MAAKH,OAAOU,UAAUF,OAAOG,KAAKR,KAAAA,IAAQK,OAAOI,KAAI,CAAA,GAC/EJ,OAAOK,IAAI,MAAM;IACf;MACEb,IAAIc;MACJC,MAAM,YAAA;AACJ,cAAM,EAAEC,iBAAiBC,SAAQ,IAAKtB,QAAQuB,cAAcrB,aAAasB,gBAAgB;AACzF,cAAMF,SACJG,aAAaC,aAAaC,cAAc;UACtCC,MAAM;UACNC,SAASV;UACTW,SAAS;YACPC,YAAY;UACd;QACF,CAAA,CAAA;MAEJ;MACAC,YAAY;QACVC,OAAO;UAAC;UAAuB;YAAEC,IAAI5B;UAAe;;QACpD6B,MAAM;QACNC,YAAY;UACVC,OAAO;UACPC,SAAS;QACX;MACF;IACF;GACD,GACDzB,OAAO0B,UAAU,MAAM,CAAA,CAAE,CAAA,CAAA;AAGjC,CAAA,CAAA;",
|
|
6
|
-
"names": ["Rx", "Option", "pipe", "Capabilities", "contributes", "createIntent", "LayoutAction", "createExtension", "ROOT_ID", "context", "contributes", "Capabilities", "AppGraphBuilder", "createExtension", "id", "NAVTREE_PLUGIN", "actions", "node", "Rx", "make", "get", "pipe", "Option", "flatMap", "ROOT_ID", "some", "none", "map", "COMMANDS_DIALOG", "data", "dispatchPromise", "dispatch", "getCapability", "IntentDispatcher", "createIntent", "LayoutAction", "UpdateDialog", "part", "subject", "options", "blockAlign", "properties", "label", "ns", "icon", "keyBinding", "macos", "windows", "getOrElse"]
|
|
7
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// src/meta.ts
|
|
2
|
-
var NAVTREE_PLUGIN = "dxos.org/plugin/navtree";
|
|
3
|
-
var KEY_BINDING = "KeyBinding";
|
|
4
|
-
var COMMANDS_DIALOG = `${NAVTREE_PLUGIN}/CommandsDialog`;
|
|
5
|
-
var meta = {
|
|
6
|
-
id: NAVTREE_PLUGIN,
|
|
7
|
-
name: "Navtree"
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
NAVTREE_PLUGIN,
|
|
12
|
-
KEY_BINDING,
|
|
13
|
-
COMMANDS_DIALOG,
|
|
14
|
-
meta
|
|
15
|
-
};
|
|
16
|
-
//# sourceMappingURL=chunk-ERDGQTH5.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/meta.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type PluginMeta } from '@dxos/app-framework';\n\nexport const NAVTREE_PLUGIN = 'dxos.org/plugin/navtree';\n\n// TODO(wittjosiah): Factor out.\nexport const KEY_BINDING = 'KeyBinding';\n// TODO(wittjosiah): Factor out.\nexport const COMMANDS_DIALOG = `${NAVTREE_PLUGIN}/CommandsDialog`;\n\nexport const meta: PluginMeta = {\n id: NAVTREE_PLUGIN,\n name: 'Navtree',\n};\n"],
|
|
5
|
-
"mappings": ";AAMO,IAAMA,iBAAiB;AAGvB,IAAMC,cAAc;AAEpB,IAAMC,kBAAkB,GAAGF,cAAAA;AAE3B,IAAMG,OAAmB;EAC9BC,IAAIJ;EACJK,MAAM;AACR;",
|
|
6
|
-
"names": ["NAVTREE_PLUGIN", "KEY_BINDING", "COMMANDS_DIALOG", "meta", "id", "name"]
|
|
7
|
-
}
|