@dxos/plugin-navtree 0.8.2-staging.7ac8446 → 0.8.2
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-26D3MUCA.mjs → app-graph-builder-P7AY3K72.mjs} +7 -6
- package/dist/lib/browser/app-graph-builder-P7AY3K72.mjs.map +7 -0
- package/dist/lib/browser/{chunk-4RQJXI4D.mjs → chunk-33VLL4IJ.mjs} +2 -2
- package/dist/lib/browser/chunk-33VLL4IJ.mjs.map +7 -0
- package/dist/lib/browser/chunk-MFAWMFJC.mjs +1418 -0
- package/dist/lib/browser/chunk-MFAWMFJC.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +6 -11
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-BZMUS24C.mjs → intent-resolver-NAYKKAOP.mjs} +7 -7
- package/dist/lib/browser/intent-resolver-NAYKKAOP.mjs.map +7 -0
- package/dist/lib/browser/keyboard-DDFATRUG.mjs +51 -0
- package/dist/lib/browser/keyboard-DDFATRUG.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs → react-surface-HGA3TAQU.mjs} +3 -3
- package/dist/lib/browser/{state-M5UJ3MHL.mjs → state-R2UMYAHN.mjs} +18 -12
- package/dist/lib/browser/state-R2UMYAHN.mjs.map +7 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +7 -4
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +38 -183
- 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 +2 -2
- package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts +9 -6
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/index.d.ts +3 -0
- package/dist/types/src/components/CommandsDialog/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/NavTree.d.ts +8 -0
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +8 -0
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/index.d.ts +2 -0
- package/dist/types/src/components/NavTree/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContext.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/components/{NavTreeItemAction.d.ts → NavTreeItem/NavTreeItemAction.d.ts} +3 -5
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +8 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +4 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/index.d.ts +3 -0
- package/dist/types/src/components/NavTreeItem/index.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +13 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +15 -0
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts +3 -0
- package/dist/types/src/components/Sidebar/index.d.ts.map +1 -0
- package/dist/types/src/components/{UserAccountAvatar.d.ts → UserAccountAvatar/UserAccountAvatar.d.ts} +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -0
- package/dist/types/src/components/{UserAccountAvatar.stories.d.ts → UserAccountAvatar/UserAccountAvatar.stories.d.ts} +1 -2
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -0
- package/dist/types/src/components/UserAccountAvatar/index.d.ts +2 -0
- package/dist/types/src/components/UserAccountAvatar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +20 -14
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/hooks.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts +3 -0
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/testing/generator.d.ts +7 -6
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.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/util.d.ts +7 -10
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +42 -32
- package/src/NavTreePlugin.tsx +2 -2
- package/src/capabilities/app-graph-builder.ts +38 -28
- package/src/capabilities/capabilities.ts +5 -4
- package/src/capabilities/intent-resolver.ts +8 -7
- package/src/capabilities/keyboard.ts +37 -32
- package/src/capabilities/state.ts +23 -17
- package/src/components/{CommandsDialog.tsx → CommandsDialog/CommandsDialog.tsx} +8 -7
- package/src/components/{CommandsTrigger.tsx → CommandsDialog/CommandsTrigger.tsx} +1 -1
- package/src/components/CommandsDialog/index.ts +6 -0
- package/src/components/NavTree/NavTree.stories.tsx +159 -0
- package/src/components/NavTree/NavTree.tsx +62 -0
- package/src/components/NavTree/index.ts +5 -0
- package/src/components/NavTreeContainer.tsx +85 -67
- package/src/components/NavTreeContext.tsx +1 -1
- package/src/components/{NavTreeItemAction.stories.tsx → NavTreeItem/NavTreeItemAction.stories.tsx} +12 -6
- package/src/components/{NavTreeItemAction.tsx → NavTreeItem/NavTreeItemAction.tsx} +19 -22
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +73 -0
- package/src/components/NavTreeItem/index.ts +6 -0
- package/src/components/{L0Menu.tsx → Sidebar/L0Menu.tsx} +186 -131
- package/src/components/Sidebar/L1Panel.tsx +175 -0
- package/src/components/Sidebar/index.ts +6 -0
- package/src/components/{UserAccountAvatar.stories.tsx → UserAccountAvatar/UserAccountAvatar.stories.tsx} +5 -5
- package/src/components/{UserAccountAvatar.tsx → UserAccountAvatar/UserAccountAvatar.tsx} +7 -7
- package/src/components/UserAccountAvatar/index.ts +5 -0
- package/src/components/index.ts +0 -1
- package/src/components/types.ts +20 -15
- package/src/testing/app-graph-builder.ts +224 -0
- package/src/testing/generator.ts +15 -12
- package/src/testing/index.ts +1 -0
- package/src/translations.ts +1 -0
- package/src/util.ts +10 -32
- package/dist/lib/browser/app-graph-builder-26D3MUCA.mjs.map +0 -7
- package/dist/lib/browser/chunk-4RQJXI4D.mjs.map +0 -7
- package/dist/lib/browser/chunk-DN43QXSX.mjs +0 -1222
- package/dist/lib/browser/chunk-DN43QXSX.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-BZMUS24C.mjs.map +0 -7
- package/dist/lib/browser/keyboard-IQXHKUWM.mjs +0 -46
- package/dist/lib/browser/keyboard-IQXHKUWM.mjs.map +0 -7
- package/dist/lib/browser/state-M5UJ3MHL.mjs.map +0 -7
- package/dist/types/src/components/CommandsDialog.d.ts.map +0 -1
- package/dist/types/src/components/CommandsTrigger.d.ts.map +0 -1
- package/dist/types/src/components/L0Menu.d.ts +0 -10
- package/dist/types/src/components/L0Menu.d.ts.map +0 -1
- package/dist/types/src/components/L1Panels.d.ts +0 -14
- package/dist/types/src/components/L1Panels.d.ts.map +0 -1
- package/dist/types/src/components/NavTree.d.ts +0 -5
- package/dist/types/src/components/NavTree.d.ts.map +0 -1
- package/dist/types/src/components/NavTree.stories.d.ts +0 -7
- package/dist/types/src/components/NavTree.stories.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemAction.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemAction.stories.d.ts +0 -41
- package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemColumns.d.ts +0 -4
- package/dist/types/src/components/NavTreeItemColumns.d.ts.map +0 -1
- package/dist/types/src/components/UserAccountAvatar.d.ts.map +0 -1
- package/dist/types/src/components/UserAccountAvatar.stories.d.ts.map +0 -1
- package/dist/types/src/stories/Graph.stories.d.ts +0 -7
- package/dist/types/src/stories/Graph.stories.d.ts.map +0 -1
- package/dist/types/src/stories/StorybookNavTree.d.ts +0 -4
- package/dist/types/src/stories/StorybookNavTree.d.ts.map +0 -1
- package/src/components/L1Panels.tsx +0 -115
- package/src/components/NavTree.stories.tsx +0 -107
- package/src/components/NavTree.tsx +0 -51
- package/src/components/NavTreeItemColumns.tsx +0 -71
- package/src/stories/Graph.stories.tsx +0 -130
- package/src/stories/StorybookNavTree.tsx +0 -63
- /package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs.map → react-surface-HGA3TAQU.mjs.map} +0 -0
- /package/dist/types/src/components/{CommandsDialog.d.ts → CommandsDialog/CommandsDialog.d.ts} +0 -0
- /package/dist/types/src/components/{CommandsTrigger.d.ts → CommandsDialog/CommandsTrigger.d.ts} +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
+
import { Schema } from 'effect';
|
|
9
|
+
import React from 'react';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
Capabilities,
|
|
13
|
+
IntentPlugin,
|
|
14
|
+
LayoutAction,
|
|
15
|
+
SettingsPlugin,
|
|
16
|
+
contributes,
|
|
17
|
+
createResolver,
|
|
18
|
+
defineCapability,
|
|
19
|
+
useCapability,
|
|
20
|
+
} from '@dxos/app-framework';
|
|
21
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
22
|
+
import { live } from '@dxos/live-object';
|
|
23
|
+
import { AttentionPlugin } from '@dxos/plugin-attention';
|
|
24
|
+
import { GraphPlugin } from '@dxos/plugin-graph';
|
|
25
|
+
import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
|
|
26
|
+
import { ThemePlugin } from '@dxos/plugin-theme';
|
|
27
|
+
import { faker } from '@dxos/random';
|
|
28
|
+
import { IconButton, Input, Main, Toolbar } from '@dxos/react-ui';
|
|
29
|
+
import { useAttendableAttributes, useAttention } from '@dxos/react-ui-attention';
|
|
30
|
+
import { Stack, StackItem } from '@dxos/react-ui-stack';
|
|
31
|
+
import { defaultTx, mx } from '@dxos/react-ui-theme';
|
|
32
|
+
import { withLayout } from '@dxos/storybook-utils';
|
|
33
|
+
|
|
34
|
+
import { NavTreePlugin } from '../../NavTreePlugin';
|
|
35
|
+
import { storybookGraphBuilders } from '../../testing';
|
|
36
|
+
import translations from '../../translations';
|
|
37
|
+
import { NavTreeContainer } from '../NavTreeContainer';
|
|
38
|
+
|
|
39
|
+
faker.seed(1234);
|
|
40
|
+
|
|
41
|
+
const StoryState = defineCapability<{ tab: string }>('story-state');
|
|
42
|
+
|
|
43
|
+
// TODO(burdon): Fix outline (e.g., button in sidebar nav is clipped when focused).
|
|
44
|
+
// TODO(burdon): Consider similar containment of: Table, Sheet, Kanban Column, Form, etc.
|
|
45
|
+
|
|
46
|
+
const container = 'flex flex-col grow gap-2 p-4 rounded-md';
|
|
47
|
+
|
|
48
|
+
// TODO(burdon): Factor out PlankHeader.
|
|
49
|
+
const StoryPlankHeading = ({ attendableId }: { attendableId: string }) => {
|
|
50
|
+
const { hasAttention } = useAttention(attendableId);
|
|
51
|
+
console.log('hasAttention', hasAttention);
|
|
52
|
+
return (
|
|
53
|
+
<div className='flex p-1 items-center border-b border-separator'>
|
|
54
|
+
<IconButton
|
|
55
|
+
density='coarse'
|
|
56
|
+
icon='ph--atom--regular'
|
|
57
|
+
label='Test'
|
|
58
|
+
iconOnly
|
|
59
|
+
variant={hasAttention ? 'primary' : 'ghost'}
|
|
60
|
+
classNames='is-[--rail-action] bs-[--rail-action]'
|
|
61
|
+
/>
|
|
62
|
+
<StackItem.ResizeHandle />
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const StoryPlank = ({ attendableId }: { attendableId: string }) => {
|
|
68
|
+
const attentionAttrs = useAttendableAttributes(attendableId);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<StackItem.Root
|
|
72
|
+
item={{ id: attendableId }}
|
|
73
|
+
{...attentionAttrs}
|
|
74
|
+
classNames='bg-baseSurface border-ie border-separator'
|
|
75
|
+
size={30}
|
|
76
|
+
>
|
|
77
|
+
<StoryPlankHeading attendableId={attendableId} />
|
|
78
|
+
<StackItem.Content toolbar>
|
|
79
|
+
<Toolbar.Root classNames='border-b border-separator'>
|
|
80
|
+
<Toolbar.Button>Test</Toolbar.Button>
|
|
81
|
+
</Toolbar.Root>
|
|
82
|
+
|
|
83
|
+
<div className={mx(container, 'm-2 bg-activeSurface')}>
|
|
84
|
+
<Input.Root>
|
|
85
|
+
<Input.Label>Level 1 (group)</Input.Label>
|
|
86
|
+
</Input.Root>
|
|
87
|
+
<div className={mx(container, 'bg-baseSurface')}>
|
|
88
|
+
<Input.Root>
|
|
89
|
+
<Input.Label>Level 2 (base)</Input.Label>
|
|
90
|
+
<Input.TextArea placeholder='Enter text' />
|
|
91
|
+
</Input.Root>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</StackItem.Content>
|
|
95
|
+
</StackItem.Root>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const DefaultStory = () => {
|
|
100
|
+
const state = useCapability(StoryState);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Main.Root complementarySidebarState='closed'>
|
|
104
|
+
<Main.NavigationSidebar label='Navigation' classNames='grid'>
|
|
105
|
+
<NavTreeContainer tab={state.tab} />
|
|
106
|
+
</Main.NavigationSidebar>
|
|
107
|
+
<Main.Content bounce handlesFocus>
|
|
108
|
+
<Stack orientation='horizontal' size='contain'>
|
|
109
|
+
<StoryPlank attendableId='space-0:object-0' />
|
|
110
|
+
<StoryPlank attendableId='space-0:object-1' />
|
|
111
|
+
</Stack>
|
|
112
|
+
</Main.Content>
|
|
113
|
+
</Main.Root>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const meta: Meta<typeof NavTreeContainer> = {
|
|
118
|
+
title: 'plugins/plugin-navtree/NavTree',
|
|
119
|
+
component: NavTreeContainer,
|
|
120
|
+
render: DefaultStory,
|
|
121
|
+
decorators: [
|
|
122
|
+
withPluginManager({
|
|
123
|
+
plugins: [
|
|
124
|
+
ThemePlugin({ tx: defaultTx }),
|
|
125
|
+
StorybookLayoutPlugin({ initialState: { sidebarState: 'expanded' } }),
|
|
126
|
+
GraphPlugin(),
|
|
127
|
+
IntentPlugin(),
|
|
128
|
+
SettingsPlugin(),
|
|
129
|
+
AttentionPlugin(),
|
|
130
|
+
NavTreePlugin(),
|
|
131
|
+
],
|
|
132
|
+
capabilities: (context) => [
|
|
133
|
+
contributes(StoryState, live({ tab: 'space-0' })),
|
|
134
|
+
contributes(Capabilities.AppGraphBuilder, storybookGraphBuilders),
|
|
135
|
+
contributes(Capabilities.IntentResolver, [
|
|
136
|
+
createResolver({
|
|
137
|
+
intent: LayoutAction.UpdateLayout,
|
|
138
|
+
filter: (data): data is Schema.Schema.Type<typeof LayoutAction.SwitchWorkspace.fields.input> =>
|
|
139
|
+
Schema.is(LayoutAction.SwitchWorkspace.fields.input)(data),
|
|
140
|
+
resolve: ({ subject }) => {
|
|
141
|
+
const state = context.getCapability(StoryState);
|
|
142
|
+
state.tab = subject;
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
]),
|
|
146
|
+
],
|
|
147
|
+
}),
|
|
148
|
+
withLayout({ fullscreen: true }),
|
|
149
|
+
],
|
|
150
|
+
parameters: {
|
|
151
|
+
translations,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export default meta;
|
|
156
|
+
|
|
157
|
+
type Story = StoryObj<typeof NavTreeContainer>;
|
|
158
|
+
|
|
159
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type TreeProps } from '@dxos/react-ui-list';
|
|
8
|
+
import { Tabs } from '@dxos/react-ui-tabs';
|
|
9
|
+
|
|
10
|
+
import { useLoadDescendents } from '../../hooks';
|
|
11
|
+
import { type NavTreeItemGraphNode } from '../../types';
|
|
12
|
+
import { useNavTreeContext } from '../NavTreeContext';
|
|
13
|
+
import { L0Menu, L1Panels, type L1PanelsProps } from '../Sidebar';
|
|
14
|
+
|
|
15
|
+
export const NAV_TREE_ITEM = 'NavTreeItem';
|
|
16
|
+
|
|
17
|
+
export type NavTreeProps = Pick<TreeProps<NavTreeItemGraphNode>, 'id' | 'root'> & Pick<L1PanelsProps, 'open'>;
|
|
18
|
+
|
|
19
|
+
export const NavTree = ({ id, root, ...props }: NavTreeProps) => {
|
|
20
|
+
const { tab, useItems, onBack } = useNavTreeContext();
|
|
21
|
+
const topLevelActions = useItems(root, { disposition: 'menu', sort: true });
|
|
22
|
+
const topLevelCollections = useItems(root, { disposition: 'collection' });
|
|
23
|
+
const topLevelWorkspaces = useItems(root, { disposition: 'workspace' });
|
|
24
|
+
const topLevelNavigation = useItems(root, { disposition: 'navigation' });
|
|
25
|
+
const l0Items = useMemo(
|
|
26
|
+
() => [
|
|
27
|
+
// prettier-ignore
|
|
28
|
+
...topLevelCollections,
|
|
29
|
+
...topLevelWorkspaces,
|
|
30
|
+
...topLevelNavigation,
|
|
31
|
+
],
|
|
32
|
+
[topLevelCollections, topLevelWorkspaces, topLevelNavigation],
|
|
33
|
+
);
|
|
34
|
+
const pinnedItems = useItems(root, { disposition: 'pin-end', sort: true });
|
|
35
|
+
const userAccountItem = useItems(root, { disposition: 'user-account' })[0];
|
|
36
|
+
const topLevelItems = useMemo(
|
|
37
|
+
() => [
|
|
38
|
+
// prettier-ignore
|
|
39
|
+
...l0Items,
|
|
40
|
+
...pinnedItems,
|
|
41
|
+
...(userAccountItem ? [userAccountItem] : []),
|
|
42
|
+
],
|
|
43
|
+
[l0Items, pinnedItems, userAccountItem],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
useLoadDescendents(root);
|
|
47
|
+
const path = useMemo(() => [id], [id]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Tabs.Root value={tab} orientation='vertical' verticalVariant='stateless' classNames='relative'>
|
|
51
|
+
<L0Menu
|
|
52
|
+
menuActions={topLevelActions}
|
|
53
|
+
topLevelItems={l0Items}
|
|
54
|
+
pinnedItems={pinnedItems}
|
|
55
|
+
userAccountItem={userAccountItem}
|
|
56
|
+
path={path}
|
|
57
|
+
parent={root}
|
|
58
|
+
/>
|
|
59
|
+
<L1Panels topLevelItems={topLevelItems} path={path} currentItemId={tab} onBack={onBack} {...props} />
|
|
60
|
+
</Tabs.Root>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -16,28 +16,22 @@ import {
|
|
|
16
16
|
useIntentDispatcher,
|
|
17
17
|
useLayout,
|
|
18
18
|
} from '@dxos/app-framework';
|
|
19
|
-
import { isAction, isActionLike, type Node } from '@dxos/app-graph';
|
|
19
|
+
import { isAction, isActionLike, type ReadableGraph, ROOT_ID, type Node } from '@dxos/app-graph';
|
|
20
20
|
import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
|
|
21
|
+
import { useConnections } from '@dxos/plugin-graph';
|
|
21
22
|
import { isEchoObject, isSpace } from '@dxos/react-client/echo';
|
|
22
|
-
import { useMediaQuery } from '@dxos/react-ui';
|
|
23
|
+
import { useMediaQuery, useSidebars } from '@dxos/react-ui';
|
|
23
24
|
import { isTreeData, type TreeData, type PropsFromTreeItem } from '@dxos/react-ui-list';
|
|
24
25
|
import { mx } from '@dxos/react-ui-theme';
|
|
25
|
-
import { arrayMove } from '@dxos/util';
|
|
26
|
+
import { arrayMove, byPosition } from '@dxos/util';
|
|
26
27
|
|
|
27
28
|
import { NAV_TREE_ITEM, NavTree } from './NavTree';
|
|
28
29
|
import { NavTreeContext } from './NavTreeContext';
|
|
29
30
|
import { type NavTreeContextValue } from './types';
|
|
30
31
|
import { NavTreeCapabilities } from '../capabilities';
|
|
32
|
+
import { NAVTREE_PLUGIN } from '../meta';
|
|
31
33
|
import { type NavTreeItemGraphNode } from '../types';
|
|
32
|
-
import {
|
|
33
|
-
expandActions,
|
|
34
|
-
expandChildren,
|
|
35
|
-
getActions as naturalGetActions,
|
|
36
|
-
getChildren,
|
|
37
|
-
getParent,
|
|
38
|
-
resolveMigrationOperation,
|
|
39
|
-
expandChildrenAndActions,
|
|
40
|
-
} from '../util';
|
|
34
|
+
import { getActions as naturalGetActions, getChildren, getParent, resolveMigrationOperation } from '../util';
|
|
41
35
|
|
|
42
36
|
// TODO(thure): Is NavTree truly authoritative in this regard?
|
|
43
37
|
export const NODE_TYPE = 'dxos/app-graph/node';
|
|
@@ -49,6 +43,29 @@ const renderItemEnd = ({ node, open }: { node: Node; open: boolean }) => (
|
|
|
49
43
|
const getChildrenFilter = (node: Node): node is Node =>
|
|
50
44
|
untracked(() => !isActionLike(node) && node.type !== PLANK_COMPANION_TYPE);
|
|
51
45
|
|
|
46
|
+
const filterItems = (node: Node, disposition?: string) => {
|
|
47
|
+
if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
|
|
48
|
+
return false;
|
|
49
|
+
} else if (!disposition) {
|
|
50
|
+
const action = isAction(node);
|
|
51
|
+
return !action || node.properties.disposition === 'item';
|
|
52
|
+
} else {
|
|
53
|
+
return node.properties.disposition === disposition;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const getItems = (graph: ReadableGraph, node?: Node, disposition?: string) => {
|
|
58
|
+
return graph.getConnections(node?.id ?? ROOT_ID, 'outbound').filter((node) => filterItems(node, disposition));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const useItems = (node?: Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
62
|
+
const { graph } = useAppGraph();
|
|
63
|
+
const connections = useConnections(graph, node?.id ?? ROOT_ID).filter((node) =>
|
|
64
|
+
filterItems(node, options?.disposition),
|
|
65
|
+
);
|
|
66
|
+
return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
|
|
67
|
+
};
|
|
68
|
+
|
|
52
69
|
export type NavTreeContainerProps = {
|
|
53
70
|
popoverAnchorId?: string;
|
|
54
71
|
topbar?: boolean;
|
|
@@ -58,34 +75,15 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
58
75
|
const [isLg] = useMediaQuery('lg', { ssr: false });
|
|
59
76
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
60
77
|
const { graph } = useAppGraph();
|
|
78
|
+
const { isOpen, isCurrent, isAlternateTree, setItem } = useCapability(NavTreeCapabilities.State);
|
|
61
79
|
const layout = useLayout();
|
|
62
|
-
const {
|
|
80
|
+
const { navigationSidebarState } = useSidebars(NAVTREE_PLUGIN);
|
|
63
81
|
|
|
64
82
|
const getActions = useCallback((node: Node) => naturalGetActions(graph, node), [graph]);
|
|
65
83
|
|
|
66
|
-
const getItems = useCallback(
|
|
67
|
-
(node?: Node, disposition?: string) => {
|
|
68
|
-
return graph.nodes(node ?? graph.root, {
|
|
69
|
-
filter: (node): node is Node => {
|
|
70
|
-
return untracked(() => {
|
|
71
|
-
if (node.properties.disposition === 'hidden') {
|
|
72
|
-
return false;
|
|
73
|
-
} else if (!disposition) {
|
|
74
|
-
const action = isAction(node);
|
|
75
|
-
return !action || node.properties.disposition === 'item';
|
|
76
|
-
} else {
|
|
77
|
-
return node.properties.disposition === disposition;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
},
|
|
83
|
-
[graph],
|
|
84
|
-
);
|
|
85
|
-
|
|
86
84
|
const getProps = useCallback(
|
|
87
85
|
(node: Node, path: string[]): PropsFromTreeItem => {
|
|
88
|
-
const children = getChildren(graph, node,
|
|
86
|
+
const children = getChildren(graph, node, path).filter(getChildrenFilter);
|
|
89
87
|
const parentOf =
|
|
90
88
|
children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
|
|
91
89
|
return {
|
|
@@ -104,49 +102,59 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
104
102
|
|
|
105
103
|
const loadDescendents = useCallback(
|
|
106
104
|
(node: Node) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
getChildren(graph, node).flatMap((child) => [expandActions(graph, child), expandChildren(graph, child)]),
|
|
113
|
-
),
|
|
114
|
-
);
|
|
115
|
-
}
|
|
105
|
+
graph.expand(node.id, 'outbound');
|
|
106
|
+
// Load one level deeper, which resolves some juddering observed on open/close.
|
|
107
|
+
graph.getConnections(node.id, 'outbound').forEach((child) => {
|
|
108
|
+
graph.expand(child.id, 'outbound');
|
|
109
|
+
});
|
|
116
110
|
},
|
|
117
111
|
[graph],
|
|
118
112
|
);
|
|
119
113
|
|
|
120
|
-
const
|
|
114
|
+
const handleOpenChange = useCallback(
|
|
121
115
|
({ item: { id }, path, open }: { item: Node; path: string[]; open: boolean }) => {
|
|
122
116
|
// TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.
|
|
123
117
|
setItem(path, 'open', open);
|
|
124
|
-
|
|
125
|
-
if (graph) {
|
|
126
|
-
const node = graph.findNode(id);
|
|
127
|
-
return node && expandChildrenAndActions(graph, node as NavTreeItemGraphNode);
|
|
128
|
-
}
|
|
118
|
+
graph.expand(id, 'outbound');
|
|
129
119
|
},
|
|
130
120
|
[graph],
|
|
131
121
|
);
|
|
132
122
|
|
|
133
|
-
const
|
|
123
|
+
const handleTabChange = useCallback(
|
|
134
124
|
async (node: NavTreeItemGraphNode) => {
|
|
125
|
+
await dispatch(
|
|
126
|
+
createIntent(LayoutAction.UpdateSidebar, {
|
|
127
|
+
part: 'sidebar',
|
|
128
|
+
options: {
|
|
129
|
+
state:
|
|
130
|
+
node.id === tab
|
|
131
|
+
? navigationSidebarState === 'expanded'
|
|
132
|
+
? isLg
|
|
133
|
+
? 'collapsed'
|
|
134
|
+
: 'closed'
|
|
135
|
+
: 'expanded'
|
|
136
|
+
: 'expanded',
|
|
137
|
+
},
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
|
|
135
141
|
await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: node.id }));
|
|
142
|
+
|
|
136
143
|
// Open the first item if the workspace is empty.
|
|
137
144
|
if (layout.active.length === 0) {
|
|
138
|
-
const [item] = getItems(node).filter((node) => !isActionLike(node));
|
|
145
|
+
const [item] = getItems(graph, node).filter((node) => !isActionLike(node));
|
|
139
146
|
if (item && item.data) {
|
|
140
147
|
await dispatch(createIntent(LayoutAction.Open, { part: 'main', subject: [item.id] }));
|
|
141
148
|
}
|
|
142
149
|
}
|
|
143
150
|
},
|
|
144
|
-
[dispatch, layout],
|
|
151
|
+
[dispatch, layout.active, tab, navigationSidebarState, isLg],
|
|
145
152
|
);
|
|
146
153
|
|
|
147
154
|
const canDrop = useCallback((source: TreeData, target: TreeData) => {
|
|
148
155
|
const sourceNode = source.item as Node;
|
|
149
156
|
const targetNode = target.item as Node;
|
|
157
|
+
// TODO(wittjosiah): This shouldn't depend directly on client, there should be a graph-level abstraction.
|
|
150
158
|
if (isSpace(targetNode.data)) {
|
|
151
159
|
// TODO(wittjosiah): Find a way to only allow space as source for rearranging.
|
|
152
160
|
return isEchoObject(sourceNode.data) || isSpace(sourceNode.data);
|
|
@@ -164,8 +172,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
164
172
|
}
|
|
165
173
|
|
|
166
174
|
if (isAction(node)) {
|
|
167
|
-
const [parent] = graph.
|
|
168
|
-
void (parent && node.data({
|
|
175
|
+
const [parent] = graph.getConnections(node.id, 'inbound');
|
|
176
|
+
void (parent && node.data({ parent, caller: NAV_TREE_ITEM }));
|
|
169
177
|
return;
|
|
170
178
|
}
|
|
171
179
|
|
|
@@ -186,7 +194,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
186
194
|
void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: node.id }));
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
const defaultAction = graph.
|
|
197
|
+
const defaultAction = graph.getActions(node.id).find((action) => action.properties?.disposition === 'default');
|
|
190
198
|
if (isAction(defaultAction)) {
|
|
191
199
|
void (defaultAction.data as () => void)();
|
|
192
200
|
}
|
|
@@ -198,7 +206,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
198
206
|
[graph, dispatch, isCurrent, isLg],
|
|
199
207
|
);
|
|
200
208
|
|
|
201
|
-
const
|
|
209
|
+
const handleBack = useCallback(
|
|
202
210
|
() => dispatch(createIntent(LayoutAction.RevertWorkspace, { part: 'workspace', options: { revert: true } })),
|
|
203
211
|
[dispatch],
|
|
204
212
|
);
|
|
@@ -225,8 +233,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
225
233
|
: resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
|
|
226
234
|
const sourceParent = getParent(graph, sourceNode, sourcePath);
|
|
227
235
|
const targetParent = getParent(graph, targetNode, targetPath);
|
|
228
|
-
const sourceItems = getItems(sourceParent);
|
|
229
|
-
const targetItems = getItems(targetParent);
|
|
236
|
+
const sourceItems = getItems(graph, sourceParent);
|
|
237
|
+
const targetItems = getItems(graph, targetParent);
|
|
230
238
|
const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
|
|
231
239
|
const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
|
|
232
240
|
const migrationIndex =
|
|
@@ -262,46 +270,56 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
262
270
|
});
|
|
263
271
|
}, [graph]);
|
|
264
272
|
|
|
273
|
+
const setAlternateTree = useCallback(
|
|
274
|
+
(path: string[], open: boolean) => {
|
|
275
|
+
setItem(path, 'alternateTree', open);
|
|
276
|
+
},
|
|
277
|
+
[setItem],
|
|
278
|
+
);
|
|
279
|
+
|
|
265
280
|
const navTreeContextValue = useMemo(
|
|
266
281
|
() => ({
|
|
282
|
+
useItems,
|
|
267
283
|
tab,
|
|
268
|
-
onTabChange,
|
|
269
|
-
onBack,
|
|
270
284
|
getActions,
|
|
271
285
|
loadDescendents,
|
|
272
286
|
renderItemEnd,
|
|
273
287
|
popoverAnchorId,
|
|
274
288
|
topbar,
|
|
275
|
-
getItems,
|
|
276
289
|
getProps,
|
|
277
290
|
isCurrent,
|
|
278
291
|
isOpen,
|
|
279
|
-
onOpenChange,
|
|
280
292
|
canDrop,
|
|
293
|
+
isAlternateTree,
|
|
294
|
+
setAlternateTree,
|
|
295
|
+
onTabChange: handleTabChange,
|
|
296
|
+
onOpenChange: handleOpenChange,
|
|
281
297
|
onSelect: handleSelect,
|
|
298
|
+
onBack: handleBack,
|
|
282
299
|
}),
|
|
283
300
|
[
|
|
284
301
|
tab,
|
|
285
|
-
onTabChange,
|
|
286
|
-
onBack,
|
|
287
302
|
getActions,
|
|
288
303
|
loadDescendents,
|
|
289
304
|
renderItemEnd,
|
|
290
305
|
popoverAnchorId,
|
|
291
306
|
topbar,
|
|
292
|
-
getItems,
|
|
293
307
|
getProps,
|
|
294
308
|
isCurrent,
|
|
295
309
|
isOpen,
|
|
296
|
-
onOpenChange,
|
|
297
310
|
canDrop,
|
|
311
|
+
isAlternateTree,
|
|
312
|
+
setAlternateTree,
|
|
313
|
+
handleTabChange,
|
|
314
|
+
handleOpenChange,
|
|
298
315
|
handleSelect,
|
|
316
|
+
handleBack,
|
|
299
317
|
],
|
|
300
318
|
);
|
|
301
319
|
|
|
302
320
|
return (
|
|
303
321
|
<NavTreeContext.Provider value={navTreeContextValue}>
|
|
304
|
-
<NavTree root={graph.root}
|
|
322
|
+
<NavTree id={ROOT_ID} root={graph.root} open={layout.sidebarOpen} />
|
|
305
323
|
</NavTreeContext.Provider>
|
|
306
324
|
);
|
|
307
325
|
});
|
|
@@ -10,4 +10,4 @@ import { type NavTreeContextValue } from './types';
|
|
|
10
10
|
|
|
11
11
|
export const NavTreeContext = createContext<NavTreeContextValue | null>(null);
|
|
12
12
|
|
|
13
|
-
export const useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error('NavTreeContext
|
|
13
|
+
export const useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error('Missing NavTreeContext'));
|
package/src/components/{NavTreeItemAction.stories.tsx → NavTreeItem/NavTreeItemAction.stories.tsx}
RENAMED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
|
+
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
|
+
|
|
7
9
|
import { type NodeArg } from '@dxos/app-graph';
|
|
8
10
|
import { faker } from '@dxos/random';
|
|
9
11
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
@@ -37,19 +39,23 @@ const menuActions = faker.helpers.multiple(
|
|
|
37
39
|
{ count: 20 },
|
|
38
40
|
);
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const meta: Meta<typeof NavTreeItemAction> = {
|
|
41
43
|
title: 'plugins/plugin-navtree/NavTreeItemAction',
|
|
42
44
|
component: NavTreeItemAction,
|
|
43
|
-
decorators: [withTheme, withLayout(
|
|
45
|
+
decorators: [withTheme, withLayout()],
|
|
44
46
|
args: {
|
|
45
47
|
icon: 'ph--list--regular',
|
|
46
48
|
parent,
|
|
47
49
|
menuActions,
|
|
48
50
|
label: 'Select action',
|
|
49
|
-
onAction: (action) => {
|
|
50
|
-
console.log(action);
|
|
51
|
-
},
|
|
52
51
|
} satisfies Partial<NavTreeItemActionMenuProps>,
|
|
52
|
+
parameters: {
|
|
53
|
+
layout: 'centered',
|
|
54
|
+
},
|
|
53
55
|
};
|
|
54
56
|
|
|
55
|
-
export
|
|
57
|
+
export default meta;
|
|
58
|
+
|
|
59
|
+
type Story = StoryObj<typeof meta>;
|
|
60
|
+
|
|
61
|
+
export const Default: Story = {};
|
|
@@ -2,54 +2,56 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React
|
|
5
|
+
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import { type Action, type Node } from '@dxos/app-graph';
|
|
8
|
-
import { useTranslation, toLocalizedString, IconButton } from '@dxos/react-ui';
|
|
8
|
+
import { useTranslation, toLocalizedString, IconButton, useDensityContext } from '@dxos/react-ui';
|
|
9
9
|
import { DropdownMenu, MenuProvider, type MenuItem } from '@dxos/react-ui-menu';
|
|
10
10
|
import { hoverableControlItem, hoverableOpenControlItem, mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import { NAVTREE_PLUGIN } from '
|
|
13
|
-
import { type ActionProperties } from '
|
|
12
|
+
import { NAVTREE_PLUGIN } from '../../meta';
|
|
13
|
+
import { type ActionProperties } from '../../types';
|
|
14
14
|
|
|
15
15
|
export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
16
16
|
parent: Node;
|
|
17
17
|
caller?: string;
|
|
18
18
|
monolithic?: boolean;
|
|
19
19
|
menuActions?: Action[];
|
|
20
|
-
suppressNextTooltip?: MutableRefObject<boolean>;
|
|
21
|
-
onAction?: (action: Action) => void;
|
|
22
20
|
};
|
|
23
21
|
|
|
24
22
|
const fallbackIcon = 'ph--placeholder--regular';
|
|
25
23
|
|
|
26
|
-
const
|
|
24
|
+
const fineActionButtonProps = {
|
|
27
25
|
size: 4 as const,
|
|
28
26
|
density: 'fine' as const,
|
|
29
27
|
};
|
|
28
|
+
const coarseActionButtonProps = {
|
|
29
|
+
size: 5 as const,
|
|
30
|
+
density: 'coarse' as const,
|
|
31
|
+
};
|
|
30
32
|
|
|
31
33
|
export const NavTreeItemActionDropdownMenu = ({
|
|
34
|
+
parent,
|
|
32
35
|
label,
|
|
33
36
|
icon,
|
|
34
37
|
testId,
|
|
35
38
|
menuActions,
|
|
36
|
-
|
|
39
|
+
caller,
|
|
37
40
|
}: NavTreeItemActionMenuProps) => {
|
|
38
41
|
const { t } = useTranslation(NAVTREE_PLUGIN);
|
|
39
|
-
const
|
|
42
|
+
const density = useDensityContext();
|
|
40
43
|
return (
|
|
41
|
-
<MenuProvider
|
|
42
|
-
<DropdownMenu.Root items={menuActions as MenuItem[]}
|
|
44
|
+
<MenuProvider>
|
|
45
|
+
<DropdownMenu.Root group={parent} items={menuActions as MenuItem[]} caller={caller}>
|
|
43
46
|
<DropdownMenu.Trigger asChild>
|
|
44
47
|
<IconButton
|
|
45
|
-
{...
|
|
48
|
+
{...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
|
|
46
49
|
classNames={mx('shrink-0 pli-2 pointer-fine:pli-1', hoverableControlItem, hoverableOpenControlItem)}
|
|
47
50
|
variant='ghost'
|
|
48
51
|
icon={icon ?? fallbackIcon}
|
|
49
52
|
iconOnly
|
|
50
53
|
label={toLocalizedString(label, t)}
|
|
51
54
|
data-testid={testId}
|
|
52
|
-
suppressNextTooltip={suppressNextTooltip}
|
|
53
55
|
/>
|
|
54
56
|
</DropdownMenu.Trigger>
|
|
55
57
|
</DropdownMenu.Root>
|
|
@@ -63,9 +65,10 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
63
65
|
data: invoke,
|
|
64
66
|
baseLabel,
|
|
65
67
|
}: Action & { parent: Node; onAction?: (action: Action) => void; baseLabel: string }) => {
|
|
68
|
+
const density = useDensityContext();
|
|
66
69
|
return (
|
|
67
70
|
<IconButton
|
|
68
|
-
{...
|
|
71
|
+
{...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
|
|
69
72
|
variant={variant}
|
|
70
73
|
classNames={mx(
|
|
71
74
|
'shrink-0',
|
|
@@ -82,7 +85,7 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
87
|
event.stopPropagation();
|
|
85
|
-
void invoke?.(caller ? {
|
|
88
|
+
void invoke?.(caller ? { parent, caller } : { parent });
|
|
86
89
|
}}
|
|
87
90
|
data-testid={testId}
|
|
88
91
|
/>
|
|
@@ -98,12 +101,6 @@ export const NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...pr
|
|
|
98
101
|
return monolithic && menuActions?.length === 1 ? (
|
|
99
102
|
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={node} {...menuActions[0]} />
|
|
100
103
|
) : (
|
|
101
|
-
<NavTreeItemActionDropdownMenu
|
|
102
|
-
{...props}
|
|
103
|
-
label={baseLabel}
|
|
104
|
-
parent={node}
|
|
105
|
-
menuActions={menuActions}
|
|
106
|
-
onAction={(action) => action.data?.(props.caller ? { node, caller: props.caller } : { node })}
|
|
107
|
-
/>
|
|
104
|
+
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={node} menuActions={menuActions} />
|
|
108
105
|
);
|
|
109
106
|
};
|