@dxos/plugin-navtree 0.8.4-main.fd6878d → 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-6JDBQ25U.mjs → app-graph-builder-OHSCN3GX.mjs} +11 -10
- 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-SNGLGBFJ.mjs → chunk-7D2MPHXV.mjs} +128 -114
- 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 +5 -7
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-N35ZIHFD.mjs → intent-resolver-YUVXVPHG.mjs} +6 -6
- package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +7 -0
- package/dist/lib/browser/{keyboard-HMTMA33N.mjs → keyboard-YYTYJW4M.mjs} +4 -4
- package/dist/lib/browser/{keyboard-HMTMA33N.mjs.map → keyboard-YYTYJW4M.mjs.map} +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-WKWXMM2N.mjs → react-surface-J7MWWAGD.mjs} +10 -10
- package/dist/lib/browser/react-surface-J7MWWAGD.mjs.map +7 -0
- package/dist/lib/browser/{state-P5DGL7KS.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 +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts +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.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 +1 -1
- 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.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/events.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +1 -2
- 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/types.d.ts +4 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +48 -48
- package/src/NavTreePlugin.tsx +70 -71
- package/src/capabilities/app-graph-builder.ts +8 -7
- package/src/capabilities/capabilities.ts +2 -2
- package/src/capabilities/intent-resolver.ts +1 -1
- package/src/capabilities/react-surface.tsx +4 -4
- package/src/capabilities/state.ts +2 -2
- package/src/components/CommandsDialog/CommandsDialog.tsx +14 -6
- package/src/components/CommandsDialog/CommandsTrigger.tsx +4 -3
- package/src/components/NavTree/NavTree.stories.tsx +65 -51
- package/src/components/NavTree/NavTree.tsx +4 -0
- package/src/components/NavTreeContainer.tsx +54 -22
- package/src/components/NavTreeDocumentTitle.tsx +2 -2
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +4 -6
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +5 -4
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +27 -21
- package/src/components/Sidebar/L0Menu.tsx +54 -53
- package/src/components/Sidebar/L1Panel.tsx +23 -28
- package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -8
- package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
- package/src/events.ts +2 -2
- package/src/experimental/Tree.stories.tsx +28 -30
- package/src/experimental/Tree.tsx +6 -23
- package/src/meta.ts +10 -7
- package/src/testing/app-graph-builder.ts +19 -18
- package/src/testing/generator.ts +2 -2
- package/src/types.ts +4 -3
- package/dist/lib/browser/app-graph-builder-6JDBQ25U.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-SNGLGBFJ.mjs.map +0 -7
- package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-N35ZIHFD.mjs.map +0 -7
- package/dist/lib/browser/react-surface-WKWXMM2N.mjs.map +0 -7
- package/dist/lib/browser/state-P5DGL7KS.mjs.map +0 -7
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
9
|
-
import React from 'react';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
import React, { type KeyboardEvent, useCallback, useRef } from 'react';
|
|
8
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
Capabilities,
|
|
@@ -16,22 +15,20 @@ import {
|
|
|
16
15
|
contributes,
|
|
17
16
|
createResolver,
|
|
18
17
|
defineCapability,
|
|
19
|
-
useCapability,
|
|
20
18
|
} from '@dxos/app-framework';
|
|
19
|
+
import { useCapability } from '@dxos/app-framework/react';
|
|
21
20
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
22
21
|
import { live } from '@dxos/live-object';
|
|
23
22
|
import { AttentionPlugin } from '@dxos/plugin-attention';
|
|
24
|
-
import { ClientPlugin } from '@dxos/plugin-client';
|
|
25
23
|
import { GraphPlugin } from '@dxos/plugin-graph';
|
|
26
|
-
import { SpacePlugin } from '@dxos/plugin-space';
|
|
27
24
|
import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
|
|
28
25
|
import { ThemePlugin } from '@dxos/plugin-theme';
|
|
29
26
|
import { faker } from '@dxos/random';
|
|
30
27
|
import { IconButton, Input, Main, Toolbar } from '@dxos/react-ui';
|
|
28
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
31
29
|
import { useAttention, useAttentionAttributes } from '@dxos/react-ui-attention';
|
|
32
30
|
import { Stack, StackItem } from '@dxos/react-ui-stack';
|
|
33
31
|
import { defaultTx, mx } from '@dxos/react-ui-theme';
|
|
34
|
-
import { withLayout } from '@dxos/storybook-utils';
|
|
35
32
|
|
|
36
33
|
import { NavTreePlugin } from '../../NavTreePlugin';
|
|
37
34
|
import { storybookGraphBuilders } from '../../testing';
|
|
@@ -68,6 +65,15 @@ const StoryPlankHeading = ({ attendableId }: { attendableId: string }) => {
|
|
|
68
65
|
|
|
69
66
|
const StoryPlank = ({ attendableId }: { attendableId: string }) => {
|
|
70
67
|
const attentionAttrs = useAttentionAttributes(attendableId);
|
|
68
|
+
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
69
|
+
|
|
70
|
+
// NOTE(thure): This is the same workaround as in Plank, but that component is out of scope for this story.
|
|
71
|
+
// TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
|
|
72
|
+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
73
|
+
if (event.target === event.currentTarget && event.key === 'Escape') {
|
|
74
|
+
rootElement.current?.closest('main')?.focus();
|
|
75
|
+
}
|
|
76
|
+
}, []);
|
|
71
77
|
|
|
72
78
|
return (
|
|
73
79
|
<StackItem.Root
|
|
@@ -75,10 +81,12 @@ const StoryPlank = ({ attendableId }: { attendableId: string }) => {
|
|
|
75
81
|
{...attentionAttrs}
|
|
76
82
|
classNames='bg-baseSurface border-ie border-separator'
|
|
77
83
|
size={30}
|
|
84
|
+
onKeyDown={handleKeyDown}
|
|
85
|
+
ref={rootElement}
|
|
78
86
|
>
|
|
79
87
|
<StoryPlankHeading attendableId={attendableId} />
|
|
80
88
|
<StackItem.Content toolbar>
|
|
81
|
-
<Toolbar.Root classNames='border-
|
|
89
|
+
<Toolbar.Root classNames='border-be border-subduedSeparator'>
|
|
82
90
|
<Toolbar.Button>Test</Toolbar.Button>
|
|
83
91
|
</Toolbar.Root>
|
|
84
92
|
|
|
@@ -116,20 +124,21 @@ const DefaultStory = () => {
|
|
|
116
124
|
);
|
|
117
125
|
};
|
|
118
126
|
|
|
119
|
-
const meta
|
|
127
|
+
const meta = {
|
|
120
128
|
title: 'plugins/plugin-navtree/NavTree',
|
|
121
129
|
component: NavTreeContainer,
|
|
122
130
|
render: DefaultStory,
|
|
123
131
|
decorators: [
|
|
132
|
+
withTheme,
|
|
124
133
|
withPluginManager({
|
|
125
134
|
plugins: [
|
|
126
135
|
ThemePlugin({ tx: defaultTx }),
|
|
127
|
-
StorybookLayoutPlugin({ initialState: { sidebarState: 'expanded' } }),
|
|
128
136
|
GraphPlugin(),
|
|
129
137
|
IntentPlugin(),
|
|
130
138
|
SettingsPlugin(),
|
|
131
139
|
AttentionPlugin(),
|
|
132
140
|
NavTreePlugin(),
|
|
141
|
+
StorybookLayoutPlugin({ initialState: { sidebarState: 'expanded' } }),
|
|
133
142
|
],
|
|
134
143
|
capabilities: (context) => [
|
|
135
144
|
contributes(StoryState, live({ tab: 'space-0' })),
|
|
@@ -147,54 +156,59 @@ const meta: Meta<typeof NavTreeContainer> = {
|
|
|
147
156
|
]),
|
|
148
157
|
],
|
|
149
158
|
}),
|
|
150
|
-
withLayout({ fullscreen: true }),
|
|
151
159
|
],
|
|
152
160
|
parameters: {
|
|
161
|
+
layout: 'fullscreen',
|
|
153
162
|
translations,
|
|
154
163
|
},
|
|
155
|
-
}
|
|
164
|
+
} satisfies Meta<typeof NavTreeContainer>;
|
|
156
165
|
|
|
157
166
|
export default meta;
|
|
158
167
|
|
|
159
168
|
type Story = StoryObj<typeof NavTreeContainer>;
|
|
160
169
|
|
|
161
|
-
export const Default: Story = {
|
|
170
|
+
export const Default: Story = {
|
|
171
|
+
play: async ({ canvasElement }) => {
|
|
172
|
+
const canvas = within(canvasElement);
|
|
162
173
|
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
174
|
+
// Find the element with treegrid role and click on its parent
|
|
175
|
+
const treegridElement = await canvas.findByRole('treegrid');
|
|
176
|
+
const treegridParent = treegridElement.parentElement;
|
|
177
|
+
if (treegridParent) {
|
|
178
|
+
await userEvent.click(treegridParent);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Press Escape
|
|
182
|
+
await userEvent.keyboard('{Escape}');
|
|
183
|
+
|
|
184
|
+
// Confirm that focus is on an element with attribute data-main-landmark="0"
|
|
185
|
+
await expect(document.activeElement).toHaveAttribute('data-main-landmark', '0');
|
|
186
|
+
|
|
187
|
+
// Press Tab
|
|
188
|
+
await userEvent.keyboard('{Tab}');
|
|
189
|
+
|
|
190
|
+
// Confirm that focus is now on an element with data-main-landmark="1"
|
|
191
|
+
await expect(document.activeElement).toHaveAttribute('data-main-landmark', '1');
|
|
192
|
+
|
|
193
|
+
// Press Tab
|
|
194
|
+
await userEvent.keyboard('{Tab}');
|
|
195
|
+
|
|
196
|
+
// Confirm that focus is now on an element with data-main-landmark="0"
|
|
197
|
+
await expect(document.activeElement).toHaveAttribute('data-main-landmark', '0');
|
|
198
|
+
|
|
199
|
+
// Press Shift-Tab
|
|
200
|
+
await userEvent.keyboard('{Shift>}{Tab}{/Shift}');
|
|
201
|
+
|
|
202
|
+
// Press Enter
|
|
203
|
+
await userEvent.keyboard('{Enter}');
|
|
204
|
+
|
|
205
|
+
// Confirm that focus is now on an element with data-attendable-id="space-0:object-0"
|
|
206
|
+
await expect(document.activeElement).toHaveAttribute('data-attendable-id', 'space-0:object-0');
|
|
207
|
+
|
|
208
|
+
// Press Escape
|
|
209
|
+
await userEvent.keyboard('{Escape}');
|
|
210
|
+
|
|
211
|
+
// Confirm that focus is now on an element with data-main-landmark="1"
|
|
212
|
+
await expect(document.activeElement).toHaveAttribute('data-main-landmark', '1');
|
|
213
|
+
},
|
|
200
214
|
};
|
|
@@ -47,6 +47,10 @@ export const NavTree = ({ id, root, ...props }: NavTreeProps) => {
|
|
|
47
47
|
const path = useMemo(() => [id], [id]);
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
|
+
// TODO(thure): `Tabs.Root` forces all items that should be able to receive focus to use `Tabs.Tab(Primitive)` since
|
|
51
|
+
// it uses RovingFocus and doesn’t support moving focus to an item that is not a tab. Assess whether this situation
|
|
52
|
+
// should change including whether it should motivate a change in the design/taxonomy, or if this means this should
|
|
53
|
+
// not use `react-ui-tabs` at all.
|
|
50
54
|
<Tabs.Root value={tab} orientation='vertical' verticalVariant='stateless' classNames='relative'>
|
|
51
55
|
<L0Menu
|
|
52
56
|
menuActions={topLevelActions}
|
|
@@ -7,15 +7,8 @@ import { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-a
|
|
|
7
7
|
import { untracked } from '@preact/signals-core';
|
|
8
8
|
import React, { memo, useCallback, useEffect, useMemo } from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
Surface,
|
|
13
|
-
createIntent,
|
|
14
|
-
useAppGraph,
|
|
15
|
-
useCapability,
|
|
16
|
-
useIntentDispatcher,
|
|
17
|
-
useLayout,
|
|
18
|
-
} from '@dxos/app-framework';
|
|
10
|
+
import { LayoutAction, createIntent } from '@dxos/app-framework';
|
|
11
|
+
import { Surface, useAppGraph, useCapability, useIntentDispatcher, useLayout } from '@dxos/app-framework/react';
|
|
19
12
|
import { type Node, ROOT_ID, type ReadableGraph, isAction, isActionLike } from '@dxos/app-graph';
|
|
20
13
|
import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
|
|
21
14
|
import { useConnections, useActions as useGraphActions } from '@dxos/plugin-graph';
|
|
@@ -25,7 +18,7 @@ import { mx } from '@dxos/react-ui-theme';
|
|
|
25
18
|
import { arrayMove, byPosition } from '@dxos/util';
|
|
26
19
|
|
|
27
20
|
import { NavTreeCapabilities } from '../capabilities';
|
|
28
|
-
import {
|
|
21
|
+
import { meta } from '../meta';
|
|
29
22
|
import { type FlattenedActions, type NavTreeItemGraphNode } from '../types';
|
|
30
23
|
import { getChildren, getParent, resolveMigrationOperation } from '../util';
|
|
31
24
|
|
|
@@ -41,7 +34,9 @@ const renderItemEnd = ({ node, open }: { node: Node; open: boolean }) => (
|
|
|
41
34
|
);
|
|
42
35
|
|
|
43
36
|
const getChildrenFilter = (node: Node): node is Node =>
|
|
44
|
-
untracked(
|
|
37
|
+
untracked(
|
|
38
|
+
() => !isActionLike(node) && node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== 'hidden',
|
|
39
|
+
);
|
|
45
40
|
|
|
46
41
|
const filterItems = (node: Node, disposition?: string) => {
|
|
47
42
|
if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
|
|
@@ -96,12 +91,12 @@ export type NavTreeContainerProps = {
|
|
|
96
91
|
} & Pick<NavTreeContextValue, 'tab'>;
|
|
97
92
|
|
|
98
93
|
export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeContainerProps) => {
|
|
99
|
-
const [isLg] = useMediaQuery('lg'
|
|
94
|
+
const [isLg] = useMediaQuery('lg');
|
|
100
95
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
101
96
|
const { graph } = useAppGraph();
|
|
102
97
|
const { isOpen, isCurrent, isAlternateTree, setItem } = useCapability(NavTreeCapabilities.State);
|
|
103
98
|
const layout = useLayout();
|
|
104
|
-
const { navigationSidebarState } = useSidebars(
|
|
99
|
+
const { navigationSidebarState } = useSidebars(meta.id);
|
|
105
100
|
|
|
106
101
|
const getProps = useCallback(
|
|
107
102
|
(node: Node, path: string[]): TreeItemDataProps => {
|
|
@@ -110,12 +105,13 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
110
105
|
children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
|
|
111
106
|
return {
|
|
112
107
|
id: node.id,
|
|
113
|
-
label: node.properties.label ?? node.id,
|
|
114
108
|
parentOf,
|
|
115
|
-
icon: node.properties.icon,
|
|
116
109
|
disabled: node.properties.disabled,
|
|
117
|
-
|
|
110
|
+
label: node.properties.label ?? node.id,
|
|
111
|
+
className: mx(node.properties.className, node.properties.modified && 'italic'), // TODO(burdon): Italic?
|
|
118
112
|
headingClassName: node.properties.headingClassName,
|
|
113
|
+
icon: node.properties.icon,
|
|
114
|
+
iconHue: node.properties.iconHue,
|
|
119
115
|
testId: node.properties.testId,
|
|
120
116
|
};
|
|
121
117
|
},
|
|
@@ -160,13 +156,23 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
160
156
|
}),
|
|
161
157
|
);
|
|
162
158
|
|
|
163
|
-
await dispatch(
|
|
159
|
+
await dispatch(
|
|
160
|
+
createIntent(LayoutAction.SwitchWorkspace, {
|
|
161
|
+
part: 'workspace',
|
|
162
|
+
subject: node.id,
|
|
163
|
+
}),
|
|
164
|
+
);
|
|
164
165
|
|
|
165
166
|
// Open the first item if the workspace is empty.
|
|
166
167
|
if (layout.active.length === 0) {
|
|
167
168
|
const [item] = getItems(graph, node).filter((node) => !isActionLike(node));
|
|
168
169
|
if (item && item.data) {
|
|
169
|
-
await dispatch(
|
|
170
|
+
await dispatch(
|
|
171
|
+
createIntent(LayoutAction.Open, {
|
|
172
|
+
part: 'main',
|
|
173
|
+
subject: [item.id],
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
170
176
|
}
|
|
171
177
|
}
|
|
172
178
|
},
|
|
@@ -177,6 +183,10 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
177
183
|
return target.item.properties.canDrop?.(source) ?? false;
|
|
178
184
|
}, []);
|
|
179
185
|
|
|
186
|
+
const canSelect = useCallback(({ item }: { item: Node }) => {
|
|
187
|
+
return item.properties.selectable ?? true;
|
|
188
|
+
}, []);
|
|
189
|
+
|
|
180
190
|
const handleSelect = useCallback(
|
|
181
191
|
({ item: node, path, option }: { item: Node; path: string[]; option: boolean }) => {
|
|
182
192
|
if (!node.data) {
|
|
@@ -200,10 +210,19 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
200
210
|
);
|
|
201
211
|
} else if (option) {
|
|
202
212
|
void dispatch(
|
|
203
|
-
createIntent(LayoutAction.Close, {
|
|
213
|
+
createIntent(LayoutAction.Close, {
|
|
214
|
+
part: 'main',
|
|
215
|
+
subject: [node.id],
|
|
216
|
+
options: { state: false },
|
|
217
|
+
}),
|
|
204
218
|
);
|
|
205
219
|
} else {
|
|
206
|
-
void dispatch(
|
|
220
|
+
void dispatch(
|
|
221
|
+
createIntent(LayoutAction.ScrollIntoView, {
|
|
222
|
+
part: 'current',
|
|
223
|
+
subject: node.id,
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
207
226
|
}
|
|
208
227
|
|
|
209
228
|
const defaultAction = graph.getActions(node.id).find((action) => action.properties?.disposition === 'default');
|
|
@@ -212,14 +231,25 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
212
231
|
}
|
|
213
232
|
|
|
214
233
|
if (!isLg) {
|
|
215
|
-
void dispatch(
|
|
234
|
+
void dispatch(
|
|
235
|
+
createIntent(LayoutAction.UpdateSidebar, {
|
|
236
|
+
part: 'sidebar',
|
|
237
|
+
options: { state: 'closed' },
|
|
238
|
+
}),
|
|
239
|
+
);
|
|
216
240
|
}
|
|
217
241
|
},
|
|
218
242
|
[graph, dispatch, isCurrent, isLg],
|
|
219
243
|
);
|
|
220
244
|
|
|
221
245
|
const handleBack = useCallback(
|
|
222
|
-
() =>
|
|
246
|
+
() =>
|
|
247
|
+
dispatch(
|
|
248
|
+
createIntent(LayoutAction.RevertWorkspace, {
|
|
249
|
+
part: 'workspace',
|
|
250
|
+
options: { revert: true },
|
|
251
|
+
}),
|
|
252
|
+
),
|
|
223
253
|
[dispatch],
|
|
224
254
|
);
|
|
225
255
|
|
|
@@ -302,6 +332,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
302
332
|
isCurrent,
|
|
303
333
|
isOpen,
|
|
304
334
|
canDrop,
|
|
335
|
+
canSelect,
|
|
305
336
|
isAlternateTree,
|
|
306
337
|
setAlternateTree,
|
|
307
338
|
onTabChange: handleTabChange,
|
|
@@ -320,6 +351,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
320
351
|
isCurrent,
|
|
321
352
|
isOpen,
|
|
322
353
|
canDrop,
|
|
354
|
+
canSelect,
|
|
323
355
|
isAlternateTree,
|
|
324
356
|
setAlternateTree,
|
|
325
357
|
handleTabChange,
|
|
@@ -6,10 +6,10 @@ import { useEffect } from 'react';
|
|
|
6
6
|
import { type Node } from '@dxos/app-graph';
|
|
7
7
|
import { toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { meta } from '../meta';
|
|
10
10
|
|
|
11
11
|
export const NavTreeDocumentTitle = ({ node }: { node?: Node }) => {
|
|
12
|
-
const { t } = useTranslation(
|
|
12
|
+
const { t } = useTranslation(meta.id);
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
document.title = node ? toLocalizedString(node.properties.label, t) : t('current app name', { ns: 'appkit' });
|
|
15
15
|
}, [node?.properties?.label]);
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
|
|
9
7
|
import { type NodeArg } from '@dxos/app-graph';
|
|
10
8
|
import { faker } from '@dxos/random';
|
|
11
|
-
import {
|
|
9
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
12
10
|
|
|
13
11
|
import { NavTreeItemAction, type NavTreeItemActionMenuProps } from './NavTreeItemAction';
|
|
14
12
|
|
|
@@ -39,20 +37,20 @@ const menuActions = faker.helpers.multiple(
|
|
|
39
37
|
{ count: 20 },
|
|
40
38
|
);
|
|
41
39
|
|
|
42
|
-
const meta
|
|
40
|
+
const meta = {
|
|
43
41
|
title: 'plugins/plugin-navtree/NavTreeItemAction',
|
|
44
42
|
component: NavTreeItemAction,
|
|
45
|
-
decorators: [withTheme, withLayout()],
|
|
46
43
|
args: {
|
|
47
44
|
icon: 'ph--list--regular',
|
|
48
45
|
parent,
|
|
49
46
|
menuActions,
|
|
50
47
|
label: 'Select action',
|
|
51
48
|
} satisfies Partial<NavTreeItemActionMenuProps>,
|
|
49
|
+
decorators: [withTheme],
|
|
52
50
|
parameters: {
|
|
53
51
|
layout: 'centered',
|
|
54
52
|
},
|
|
55
|
-
}
|
|
53
|
+
} satisfies Meta<typeof NavTreeItemAction>;
|
|
56
54
|
|
|
57
55
|
export default meta;
|
|
58
56
|
|
|
@@ -9,7 +9,7 @@ import { IconButton, toLocalizedString, useDensityContext, useTranslation } from
|
|
|
9
9
|
import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
|
|
10
10
|
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { meta } from '../../meta';
|
|
13
13
|
import { type ActionProperties } from '../../types';
|
|
14
14
|
|
|
15
15
|
export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
@@ -38,7 +38,7 @@ export const NavTreeItemActionDropdownMenu = ({
|
|
|
38
38
|
menuActions,
|
|
39
39
|
caller,
|
|
40
40
|
}: NavTreeItemActionMenuProps) => {
|
|
41
|
-
const { t } = useTranslation(
|
|
41
|
+
const { t } = useTranslation(meta.id);
|
|
42
42
|
const density = useDensityContext();
|
|
43
43
|
return (
|
|
44
44
|
<MenuProvider>
|
|
@@ -81,10 +81,11 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
81
81
|
label={baseLabel}
|
|
82
82
|
disabled={disabled}
|
|
83
83
|
onClick={(event) => {
|
|
84
|
+
event.stopPropagation();
|
|
84
85
|
if (disabled) {
|
|
85
86
|
return;
|
|
86
87
|
}
|
|
87
|
-
|
|
88
|
+
|
|
88
89
|
void invoke?.(caller ? { parent, caller } : { parent });
|
|
89
90
|
}}
|
|
90
91
|
data-testid={testId}
|
|
@@ -93,7 +94,7 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
93
94
|
};
|
|
94
95
|
|
|
95
96
|
export const NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...props }: NavTreeItemActionMenuProps) => {
|
|
96
|
-
const { t } = useTranslation(
|
|
97
|
+
const { t } = useTranslation(meta.id);
|
|
97
98
|
|
|
98
99
|
const monolithicAction = menuActions?.length === 1 && menuActions[0];
|
|
99
100
|
const baseLabel = toLocalizedString(monolithicAction ? monolithicAction.properties!.label : props.label, t);
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
import React, { Fragment, memo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { isAction } from '@dxos/app-graph';
|
|
8
|
-
import {
|
|
8
|
+
import { Popover, Treegrid, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
10
|
import { useLoadDescendents } from '../../hooks';
|
|
11
|
-
import {
|
|
11
|
+
import { meta } from '../../meta';
|
|
12
12
|
import { NAV_TREE_ITEM } from '../NavTree';
|
|
13
13
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
14
14
|
import { type NavTreeItemColumnsProps } from '../types';
|
|
15
15
|
|
|
16
16
|
import { NavTreeItemAction } from './NavTreeItemAction';
|
|
17
17
|
|
|
18
|
-
export const NavTreeItemColumns = memo(({ path, item, open
|
|
19
|
-
const { t } = useTranslation(
|
|
18
|
+
export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumnsProps) => {
|
|
19
|
+
const { t } = useTranslation(meta.id);
|
|
20
20
|
const { useActions, renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();
|
|
21
21
|
|
|
22
22
|
const level = path.length - 2;
|
|
@@ -29,15 +29,15 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
29
29
|
.flatMap((action) => (isAction(action) ? [action] : []))
|
|
30
30
|
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
31
31
|
|
|
32
|
-
const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover.Anchor : Fragment;
|
|
33
|
-
|
|
34
32
|
useLoadDescendents(item);
|
|
35
33
|
useLoadDescendents(primaryAction && !isAction(primaryAction) ? primaryAction : undefined);
|
|
36
34
|
|
|
35
|
+
const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover.Anchor : Fragment;
|
|
36
|
+
|
|
37
37
|
return (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
<div role='none' className='contents app-no-drag'>
|
|
39
|
+
{primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled ? (
|
|
40
|
+
<Treegrid.Cell classNames='contents'>
|
|
41
41
|
<NavTreeItemAction
|
|
42
42
|
testId={primaryAction.properties?.testId}
|
|
43
43
|
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
@@ -48,11 +48,13 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
48
48
|
menuType={primaryAction.properties?.menuType}
|
|
49
49
|
caller={NAV_TREE_ITEM}
|
|
50
50
|
/>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
</Treegrid.Cell>
|
|
52
|
+
) : (
|
|
53
|
+
<Treegrid.Cell role='none' />
|
|
54
|
+
)}
|
|
55
|
+
<ActionRoot>
|
|
56
|
+
{actions.length > 0 ? (
|
|
57
|
+
<Treegrid.Cell classNames='contents'>
|
|
56
58
|
<NavTreeItemAction
|
|
57
59
|
testId={`navtree.treeItem.actionsLevel${level}`}
|
|
58
60
|
label={t('tree item actions label')}
|
|
@@ -62,12 +64,16 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
62
64
|
menuType='dropdown'
|
|
63
65
|
caller={NAV_TREE_ITEM}
|
|
64
66
|
/>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
</Treegrid.Cell>
|
|
68
|
+
) : (
|
|
69
|
+
<Treegrid.Cell role='none' />
|
|
70
|
+
)}
|
|
71
|
+
</ActionRoot>
|
|
72
|
+
{ItemEnd && (
|
|
73
|
+
<Treegrid.Cell classNames='contents'>
|
|
74
|
+
<ItemEnd node={item} open={open} />
|
|
75
|
+
</Treegrid.Cell>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
72
78
|
);
|
|
73
79
|
});
|