@dxos/plugin-navtree 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +137 -72
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +7 -5
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts +5 -0
- package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +6 -0
- package/dist/types/src/capabilities/state.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/NavTree.d.ts +10 -32
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +10 -14
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
- package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +11 -3
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +4 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +3 -6
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts +3 -2
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +5 -13
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/{components/CommandsDialog/CommandsDialog.d.ts → containers/CommandsDialogContent/CommandsDialogContent.d.ts} +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +29 -0
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsDialogContent/index.d.ts +3 -0
- package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsTrigger/index.d.ts +3 -0
- package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
- package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +3 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +7 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/experimental/Tree.stories.d.ts +18 -4
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +5 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useActions.d.ts +5 -0
- package/dist/types/src/hooks/useActions.d.ts.map +1 -0
- package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
- package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
- package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
- package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
- package/dist/types/src/{hooks.d.ts → hooks/useNavTreeState.d.ts} +2 -14
- package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/expose.d.ts +5 -0
- package/dist/types/src/operations/expose.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +3 -3
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +9 -10
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/events.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +6 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -43
- package/src/NavTreePlugin.tsx +26 -27
- package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +6 -5
- package/src/capabilities/index.ts +11 -5
- package/src/capabilities/{keyboard/keyboard.ts → keyboard.ts} +7 -6
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +13 -14
- package/src/capabilities/{state/state.ts → state.ts} +43 -15
- package/src/components/NavTree/NavTree.stories.tsx +26 -24
- package/src/components/NavTree/NavTree.tsx +63 -22
- package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
- package/src/components/NavTreeContext/index.ts +5 -0
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +1 -3
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +56 -39
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +42 -16
- package/src/components/Sidebar/L0Menu.tsx +99 -109
- package/src/components/Sidebar/L1Panel.tsx +252 -94
- package/src/components/Sidebar/L1Tabs.tsx +13 -3
- package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +2 -3
- package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
- package/src/components/index.ts +0 -3
- package/src/components/types.ts +12 -17
- package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
- package/src/{components/CommandsDialog/CommandsDialog.tsx → containers/CommandsDialogContent/CommandsDialogContent.tsx} +23 -21
- package/src/containers/CommandsDialogContent/index.ts +7 -0
- package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
- package/src/containers/CommandsTrigger/index.ts +7 -0
- package/src/{components → containers/NavTreeContainer}/NavTreeContainer.tsx +76 -142
- package/src/containers/NavTreeContainer/index.ts +6 -0
- package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +2 -2
- package/src/containers/NavTreeDocumentTitle/index.ts +7 -0
- package/src/containers/index.ts +12 -0
- package/src/experimental/Tree.stories.tsx +54 -57
- package/src/experimental/Tree.tsx +3 -3
- package/src/hooks/index.ts +8 -0
- package/src/hooks/useActions.ts +34 -0
- package/src/hooks/useLoadDescendents.ts +23 -0
- package/src/hooks/useNavTreeModel.ts +118 -0
- package/src/{hooks.ts → hooks/useNavTreeState.ts} +3 -34
- package/src/meta.ts +2 -2
- package/src/operations/expose.ts +42 -0
- package/src/operations/index.ts +7 -0
- package/src/testing/app-graph-builder.ts +34 -30
- package/src/testing/generator.ts +4 -4
- package/src/translations.ts +9 -10
- package/src/types/capabilities.ts +2 -2
- package/src/types/events.ts +4 -3
- package/src/util.ts +19 -5
- package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs +0 -43
- package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs.map +0 -7
- package/dist/lib/browser/chunk-6YPQ625I.mjs +0 -1293
- package/dist/lib/browser/chunk-6YPQ625I.mjs.map +0 -7
- package/dist/lib/browser/chunk-AGQDZBPL.mjs +0 -23
- package/dist/lib/browser/chunk-AGQDZBPL.mjs.map +0 -7
- package/dist/lib/browser/chunk-YKTYPINZ.mjs +0 -19
- package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +0 -7
- package/dist/lib/browser/keyboard-32EH3N4K.mjs +0 -52
- package/dist/lib/browser/keyboard-32EH3N4K.mjs.map +0 -7
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs +0 -52
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs.map +0 -7
- package/dist/lib/browser/react-surface-F6CVMS3Y.mjs +0 -58
- package/dist/lib/browser/react-surface-F6CVMS3Y.mjs.map +0 -7
- package/dist/lib/browser/state-EVYQOUI3.mjs +0 -120
- package/dist/lib/browser/state-EVYQOUI3.mjs.map +0 -7
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/keyboard/index.d.ts +0 -3
- package/dist/types/src/capabilities/keyboard/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts +0 -5
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
- package/dist/types/src/capabilities/state/index.d.ts +0 -3
- package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/state/state.d.ts +0 -6
- package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
- package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
- package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeContainer.d.ts +0 -16
- package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
- package/dist/types/src/hooks.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder/index.ts +0 -7
- package/src/capabilities/keyboard/index.ts +0 -7
- package/src/capabilities/operation-resolver/index.ts +0 -7
- package/src/capabilities/operation-resolver/operation-resolver.ts +0 -41
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/capabilities/state/index.ts +0 -7
- package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -26
- package/src/components/CommandsDialog/index.ts +0 -6
- /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
- /package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +0 -0
|
@@ -2,150 +2,308 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Option from 'effect/Option';
|
|
7
|
+
import React, { memo, useCallback, useMemo } from 'react';
|
|
6
8
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
+
import { Node } from '@dxos/app-graph';
|
|
10
|
+
import { isPinnedWorkspace } from '@dxos/app-toolkit';
|
|
11
|
+
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
12
|
+
import { Graph, useActionRunner, useConnections, useEdges } from '@dxos/plugin-graph';
|
|
13
|
+
import { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
14
|
+
import { useAttended } from '@dxos/react-ui-attention';
|
|
9
15
|
import { Tree } from '@dxos/react-ui-list';
|
|
16
|
+
import { Menu, type MenuItem } from '@dxos/react-ui-menu';
|
|
10
17
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
11
18
|
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
|
|
12
19
|
|
|
13
|
-
import { useIsAlternateTree } from '
|
|
14
|
-
import { meta } from '
|
|
20
|
+
import { useActions, useIsAlternateTree, useLoadDescendents } from '#hooks';
|
|
21
|
+
import { meta } from '#meta';
|
|
22
|
+
import { NAV_TREE_ITEM } from '../NavTree';
|
|
15
23
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
16
|
-
import { NavTreeItemColumns } from '../NavTreeItem';
|
|
24
|
+
import { NavTreeItemAction, NavTreeItemColumns } from '../NavTreeItem';
|
|
17
25
|
|
|
18
26
|
export type L1PanelProps = {
|
|
19
27
|
open?: boolean;
|
|
20
28
|
path: string[];
|
|
21
29
|
item: Node.Node;
|
|
22
|
-
|
|
30
|
+
isCurrent: boolean;
|
|
23
31
|
onBack?: () => void;
|
|
24
32
|
};
|
|
25
33
|
|
|
26
34
|
/**
|
|
27
35
|
* Space or settings panel.
|
|
28
36
|
*/
|
|
29
|
-
|
|
37
|
+
const L1Panel$ = ({ open, path, item, isCurrent, onBack }: L1PanelProps) => {
|
|
30
38
|
const { t } = useTranslation(meta.id);
|
|
31
|
-
const navTreeContext = useNavTreeContext();
|
|
32
39
|
const title = toLocalizedString(item.properties.label, t);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const { useItems } = navTreeContext;
|
|
36
|
-
const alternateTree = useItems(item, { disposition: 'alternate-tree' })[0];
|
|
37
|
-
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
38
|
-
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
39
|
-
const useAlternateItems = useCallback(
|
|
40
|
-
(node?: Node.Node, { disposition }: { disposition?: string } = {}) => {
|
|
41
|
-
// TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
|
|
42
|
-
return useItems(node, { disposition, sort: node?.id === alternateTree.id });
|
|
43
|
-
},
|
|
44
|
-
[alternateTree, useItems],
|
|
45
|
-
);
|
|
40
|
+
const isActivated = useIsActivatedWorkspace(item);
|
|
41
|
+
const shouldRenderContent = isCurrent || isActivated;
|
|
46
42
|
|
|
47
43
|
return (
|
|
48
|
-
<Tabs.
|
|
44
|
+
<Tabs.Panel
|
|
49
45
|
key={item.id}
|
|
50
46
|
value={item.id}
|
|
51
47
|
classNames={[
|
|
52
|
-
'absolute inset-
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
|
|
48
|
+
'absolute inset-y-0 end-0',
|
|
49
|
+
'w-[calc(100%-var(--dx-l0-size))] lg:w-(--dx-l1-size) grid-cols-1 grid-rows-[var(--dx-rail-size)_1fr]',
|
|
50
|
+
'py-[env(safe-area-inset-top)]',
|
|
51
|
+
isCurrent && 'grid',
|
|
56
52
|
]}
|
|
57
53
|
tabIndex={-1}
|
|
58
54
|
aria-label={title}
|
|
55
|
+
{...(isCurrent && { 'data-testid': 'navtree.workspace.visible' })}
|
|
59
56
|
{...(!open && { inert: true })}
|
|
60
57
|
>
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
<L1PanelHeader path={path} item={item} currentItemId={currentItemId} onBack={onBack} />
|
|
64
|
-
<div role='none' className='overflow-y-auto'>
|
|
65
|
-
{isAlternate ? (
|
|
66
|
-
<Tree
|
|
67
|
-
{...navTreeContext}
|
|
68
|
-
id={alternateTree.id}
|
|
69
|
-
root={alternateTree}
|
|
70
|
-
path={alternatePath}
|
|
71
|
-
levelOffset={5}
|
|
72
|
-
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
73
|
-
renderColumns={NavTreeItemColumns}
|
|
74
|
-
useItems={useAlternateItems}
|
|
75
|
-
/>
|
|
76
|
-
) : (
|
|
77
|
-
<Tree
|
|
78
|
-
{...navTreeContext}
|
|
79
|
-
id={item.id}
|
|
80
|
-
root={item}
|
|
81
|
-
path={path}
|
|
82
|
-
levelOffset={5}
|
|
83
|
-
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
84
|
-
renderColumns={NavTreeItemColumns}
|
|
85
|
-
draggable
|
|
86
|
-
/>
|
|
87
|
-
)}
|
|
88
|
-
</div>
|
|
89
|
-
</DensityProvider>
|
|
90
|
-
)}
|
|
91
|
-
</Tabs.Tabpanel>
|
|
58
|
+
{shouldRenderContent && <L1PanelContent open={open} path={path} item={item} onBack={onBack} />}
|
|
59
|
+
</Tabs.Panel>
|
|
92
60
|
);
|
|
93
61
|
};
|
|
94
62
|
|
|
63
|
+
/** Determines whether a workspace tab has been populated with real child content (i.e. expanded at least once). */
|
|
64
|
+
const useIsActivatedWorkspace = (item: Node.Node): boolean => {
|
|
65
|
+
const { graph } = useAppGraph();
|
|
66
|
+
const edges = useEdges(graph, item.id);
|
|
67
|
+
|
|
68
|
+
return useMemo(() => {
|
|
69
|
+
const childIds = edges[Graph.relationKey('child')] ?? [];
|
|
70
|
+
return childIds.some((childId) => {
|
|
71
|
+
const child = Graph.getNode(graph, childId);
|
|
72
|
+
if (Option.isNone(child)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return child.value.properties.disposition === undefined;
|
|
76
|
+
});
|
|
77
|
+
}, [edges, graph]);
|
|
78
|
+
};
|
|
79
|
+
|
|
95
80
|
/**
|
|
96
|
-
*
|
|
81
|
+
* Mounted panel content for active or previously-visited tabs.
|
|
97
82
|
*/
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const { setAlternateTree, ...navTreeContext } = useNavTreeContext();
|
|
101
|
-
const title = toLocalizedString(item.properties.label, t);
|
|
83
|
+
const L1PanelContent = ({ path, item, onBack }: Pick<L1PanelProps, 'open' | 'path' | 'item' | 'onBack'>) => {
|
|
84
|
+
const navTreeContext = useNavTreeContext();
|
|
102
85
|
|
|
103
|
-
|
|
104
|
-
const alternateTree = navTreeContext.useItems(item, { disposition: 'alternate-tree' })[0];
|
|
86
|
+
const alternateTree = useAlternateTreeItem(item);
|
|
105
87
|
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
106
88
|
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
107
|
-
const backCapable = item.id.startsWith('!') || isAlternate;
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
90
|
+
return (
|
|
91
|
+
<DensityProvider density='fine'>
|
|
92
|
+
<L1PanelHeader path={path} item={item} onBack={onBack} />
|
|
93
|
+
<ScrollArea.Root thin orientation='vertical'>
|
|
94
|
+
<ScrollArea.Viewport>
|
|
95
|
+
{isAlternate && alternateTree ? (
|
|
96
|
+
<Tree
|
|
97
|
+
model={navTreeContext.model}
|
|
98
|
+
id={alternateTree.id}
|
|
99
|
+
rootId={alternateTree.id}
|
|
100
|
+
path={alternatePath}
|
|
101
|
+
levelOffset={5}
|
|
102
|
+
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
103
|
+
renderColumns={NavTreeItemColumns}
|
|
104
|
+
blockInstruction={navTreeContext.blockInstruction}
|
|
105
|
+
canDrop={navTreeContext.canDrop}
|
|
106
|
+
canSelect={navTreeContext.canSelect}
|
|
107
|
+
onOpenChange={navTreeContext.onOpenChange}
|
|
108
|
+
onSelect={navTreeContext.onSelect}
|
|
109
|
+
onItemHover={navTreeContext.onItemHover}
|
|
110
|
+
/>
|
|
111
|
+
) : (
|
|
112
|
+
<Tree
|
|
113
|
+
model={navTreeContext.model}
|
|
114
|
+
id={item.id}
|
|
115
|
+
rootId={item.id}
|
|
116
|
+
path={path}
|
|
117
|
+
levelOffset={5}
|
|
118
|
+
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
119
|
+
draggable
|
|
120
|
+
renderColumns={NavTreeItemColumns}
|
|
121
|
+
blockInstruction={navTreeContext.blockInstruction}
|
|
122
|
+
canDrop={navTreeContext.canDrop}
|
|
123
|
+
canSelect={navTreeContext.canSelect}
|
|
124
|
+
onOpenChange={navTreeContext.onOpenChange}
|
|
125
|
+
onSelect={navTreeContext.onSelect}
|
|
126
|
+
onItemHover={navTreeContext.onItemHover}
|
|
127
|
+
/>
|
|
128
|
+
)}
|
|
129
|
+
</ScrollArea.Viewport>
|
|
130
|
+
</ScrollArea.Root>
|
|
131
|
+
</DensityProvider>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
112
134
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Header row.
|
|
137
|
+
*/
|
|
138
|
+
const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path' | 'onBack'>) => {
|
|
139
|
+
const { t } = useTranslation(meta.id);
|
|
140
|
+
const { renderItemEnd: ItemEnd } = useNavTreeContext();
|
|
141
|
+
const title = toLocalizedString(item.properties.label, t);
|
|
142
|
+
const backCapableWorkspace = isPinnedWorkspace(item.id);
|
|
143
|
+
|
|
144
|
+
const { primaryAction, groupedActions, menuActions, onAction } = useL1MenuActions({ item, path });
|
|
145
|
+
useLoadDescendents(item);
|
|
146
|
+
|
|
147
|
+
// TODO(wittjosiah): Hack to only show containsAttended when attended item is within alternate tree (e.g. settings).
|
|
148
|
+
// Since every object in the space is a descendant of the space node, we'd otherwise always show containsAttended.
|
|
149
|
+
const alternateTree = useAlternateTreeItem(item);
|
|
150
|
+
const attended = useAttended();
|
|
151
|
+
const alternateTreeOpen = useMemo(() => {
|
|
152
|
+
if (!alternateTree) {
|
|
153
|
+
return true;
|
|
118
154
|
}
|
|
119
|
-
|
|
155
|
+
const hasAlternateAttended = attended.some(
|
|
156
|
+
(attendedId) => attendedId === alternateTree.id || attendedId.startsWith(alternateTree.id + '/'),
|
|
157
|
+
);
|
|
158
|
+
return !hasAlternateAttended;
|
|
159
|
+
}, [alternateTree, attended]);
|
|
120
160
|
|
|
121
|
-
// TODO(burdon): Reuse same grid as tree?
|
|
122
161
|
return (
|
|
123
|
-
<div
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
162
|
+
<div
|
|
163
|
+
data-tauri-drag-region
|
|
164
|
+
className='flex w-full items-center border-b border-subdued-separator dx-app-drag dx-density-coarse pe-1'
|
|
165
|
+
>
|
|
166
|
+
{backCapableWorkspace ? (
|
|
127
167
|
<IconButton
|
|
128
|
-
|
|
168
|
+
density='coarse'
|
|
169
|
+
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
129
170
|
variant='ghost'
|
|
130
|
-
icon='ph--
|
|
171
|
+
icon='ph--caret-left--regular'
|
|
131
172
|
iconOnly
|
|
132
|
-
label={t('button
|
|
133
|
-
|
|
134
|
-
onClick={
|
|
173
|
+
label={t('button-back.button')}
|
|
174
|
+
data-testid='treeView.primaryTreeButton'
|
|
175
|
+
onClick={() => onBack?.()}
|
|
135
176
|
/>
|
|
136
|
-
)
|
|
137
|
-
|
|
177
|
+
) : (
|
|
178
|
+
<div data-tauri-drag-region className='w-6' />
|
|
179
|
+
)}
|
|
180
|
+
<h2 data-tauri-drag-region className='flex-1 truncate min-w-0'>
|
|
181
|
+
{title}
|
|
182
|
+
</h2>
|
|
183
|
+
{/* TODO(wittjosiah): Reconcile with NavTreeItemColumns. */}
|
|
184
|
+
<div role='none' className='contents dx-app-no-drag'>
|
|
185
|
+
{primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled && (
|
|
186
|
+
<NavTreeItemAction
|
|
187
|
+
testId={primaryAction.properties?.testId}
|
|
188
|
+
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
189
|
+
icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
|
|
190
|
+
parent={item}
|
|
191
|
+
path={path}
|
|
192
|
+
monolithic={Node.isAction(primaryAction)}
|
|
193
|
+
menuActions={Node.isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction?.id ?? '']}
|
|
194
|
+
menuType={primaryAction.properties?.menuType}
|
|
195
|
+
caller={NAV_TREE_ITEM}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
{menuActions.length === 1 && (
|
|
138
199
|
<IconButton
|
|
139
|
-
|
|
200
|
+
density='coarse'
|
|
201
|
+
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
140
202
|
variant='ghost'
|
|
141
|
-
icon={
|
|
203
|
+
icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
|
|
142
204
|
iconOnly
|
|
143
|
-
label={toLocalizedString(
|
|
144
|
-
|
|
145
|
-
onClick={
|
|
205
|
+
label={toLocalizedString(menuActions[0].properties?.label, t)}
|
|
206
|
+
data-testid={menuActions[0].properties?.testId}
|
|
207
|
+
onClick={() => onAction(menuActions[0] as Node.Action)}
|
|
146
208
|
/>
|
|
147
|
-
)
|
|
148
|
-
|
|
209
|
+
)}
|
|
210
|
+
{menuActions.length > 1 && (
|
|
211
|
+
<Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>
|
|
212
|
+
<Menu.Trigger asChild>
|
|
213
|
+
<IconButton
|
|
214
|
+
density='coarse'
|
|
215
|
+
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
216
|
+
variant='ghost'
|
|
217
|
+
icon='ph--dots-three-vertical--regular'
|
|
218
|
+
iconOnly
|
|
219
|
+
label={t('tree-item-actions.label')}
|
|
220
|
+
data-testid='navtree.treeItem.actionsLevel0'
|
|
221
|
+
/>
|
|
222
|
+
</Menu.Trigger>
|
|
223
|
+
<Menu.Content group={item} items={menuActions as MenuItem[]} />
|
|
224
|
+
</Menu.Root>
|
|
225
|
+
)}
|
|
226
|
+
{ItemEnd && <ItemEnd node={item} open={alternateTreeOpen} />}
|
|
227
|
+
</div>
|
|
149
228
|
</div>
|
|
150
229
|
);
|
|
151
230
|
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Builds the menu actions for the L1 panel header, combining graph actions with a synthetic settings/back action.
|
|
234
|
+
*/
|
|
235
|
+
const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>) => {
|
|
236
|
+
const { t } = useTranslation(meta.id);
|
|
237
|
+
const { setAlternateTree } = useNavTreeContext();
|
|
238
|
+
const { graph } = useAppGraph();
|
|
239
|
+
const runAction = useActionRunner();
|
|
240
|
+
|
|
241
|
+
const alternateTree = useAlternateTreeItem(item);
|
|
242
|
+
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
243
|
+
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
244
|
+
|
|
245
|
+
// Graph actions.
|
|
246
|
+
const { actions: actionsProp, groupedActions } = useActions(item);
|
|
247
|
+
const [primaryAction, ...secondaryActions] = actionsProp.toSorted((a, _b) =>
|
|
248
|
+
a.properties?.disposition === 'list-item-primary' ? -1 : 1,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const graphMenuActions = (
|
|
252
|
+
primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : actionsProp
|
|
253
|
+
)
|
|
254
|
+
.flatMap((action) => (Node.isAction(action) ? [action] : []))
|
|
255
|
+
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
256
|
+
|
|
257
|
+
// Synthetic settings/back action.
|
|
258
|
+
const settingsActionId = `${item.id}~settings`;
|
|
259
|
+
const settingsAction = useMemo((): Node.Action | undefined => {
|
|
260
|
+
if (!alternateTree) {
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
id: settingsActionId,
|
|
265
|
+
type: Node.ActionType,
|
|
266
|
+
data: () => Effect.void,
|
|
267
|
+
properties: {
|
|
268
|
+
label: isAlternate
|
|
269
|
+
? ['button-back.button', { ns: meta.id }]
|
|
270
|
+
: (alternateTree.properties.label ?? alternateTree.id),
|
|
271
|
+
icon: isAlternate
|
|
272
|
+
? 'ph--arrow-u-down-left--regular'
|
|
273
|
+
: (alternateTree.properties.icon ?? 'ph--placeholder--regular'),
|
|
274
|
+
disposition: 'list-item',
|
|
275
|
+
testId: isAlternate ? 'navtree.backToSpace' : 'navtree.spaceSettings',
|
|
276
|
+
},
|
|
277
|
+
} as Node.Action;
|
|
278
|
+
}, [alternateTree, isAlternate, settingsActionId, t]);
|
|
279
|
+
|
|
280
|
+
const menuActions = useMemo(
|
|
281
|
+
() => [...graphMenuActions, ...(settingsAction ? [settingsAction] : [])],
|
|
282
|
+
[graphMenuActions, settingsAction],
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
const onAction = useCallback(
|
|
286
|
+
(action: Node.Action, params?: Node.InvokeProps) => {
|
|
287
|
+
if (action.id === settingsActionId) {
|
|
288
|
+
if (alternateTree && !isAlternate) {
|
|
289
|
+
Graph.expand(graph, alternateTree.id, 'child');
|
|
290
|
+
}
|
|
291
|
+
setAlternateTree?.(alternatePath, !isAlternate);
|
|
292
|
+
} else {
|
|
293
|
+
void runAction(action, { ...params, path });
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
[settingsActionId, setAlternateTree, alternatePath, isAlternate, runAction, graph, alternateTree, path],
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
return { primaryAction, groupedActions, menuActions, onAction };
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/** Finds the first child with disposition 'alternate-tree' using graph connections directly. */
|
|
303
|
+
const useAlternateTreeItem = (item: Node.Node): Node.Node | undefined => {
|
|
304
|
+
const { graph } = useAppGraph();
|
|
305
|
+
const connections = useConnections(graph, item.id, 'child');
|
|
306
|
+
return connections.find((node) => node.properties.disposition === 'alternate-tree');
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export const L1Panel = memo(L1Panel$);
|
|
@@ -10,7 +10,8 @@ import { l0ItemType } from '../../util';
|
|
|
10
10
|
|
|
11
11
|
import { L1Panel, type L1PanelProps } from './L1Panel';
|
|
12
12
|
|
|
13
|
-
export type L1TabsProps = Pick<L1PanelProps, 'open' | '
|
|
13
|
+
export type L1TabsProps = Pick<L1PanelProps, 'open' | 'onBack'> & {
|
|
14
|
+
currentItemId: string;
|
|
14
15
|
path: string[];
|
|
15
16
|
topLevelItems: Node.Node[];
|
|
16
17
|
};
|
|
@@ -18,13 +19,22 @@ export type L1TabsProps = Pick<L1PanelProps, 'open' | 'currentItemId' | 'onBack'
|
|
|
18
19
|
/**
|
|
19
20
|
* Each workspace is an L1 tab.
|
|
20
21
|
*/
|
|
21
|
-
export const L1Tabs = ({ topLevelItems, onBack,
|
|
22
|
+
export const L1Tabs = ({ topLevelItems, currentItemId, onBack, open, path }: L1TabsProps) => {
|
|
22
23
|
return (
|
|
23
24
|
<>
|
|
24
25
|
{topLevelItems.map((item) => {
|
|
25
26
|
const type = l0ItemType(item);
|
|
26
27
|
if (type === 'tab') {
|
|
27
|
-
return
|
|
28
|
+
return (
|
|
29
|
+
<L1Panel
|
|
30
|
+
key={item.id}
|
|
31
|
+
item={item}
|
|
32
|
+
path={path}
|
|
33
|
+
open={open}
|
|
34
|
+
onBack={onBack}
|
|
35
|
+
isCurrent={item.id === currentItemId}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
28
38
|
}
|
|
29
39
|
return null;
|
|
30
40
|
})}
|
|
@@ -9,9 +9,8 @@ import { withTheme } from '@dxos/react-ui/testing';
|
|
|
9
9
|
import { UserAccountAvatar } from './UserAccountAvatar';
|
|
10
10
|
|
|
11
11
|
const meta = {
|
|
12
|
-
title: 'plugins/plugin-navtree/UserAccountAvatar',
|
|
13
|
-
|
|
14
|
-
decorators: [withTheme],
|
|
12
|
+
title: 'plugins/plugin-navtree/components/UserAccountAvatar',
|
|
13
|
+
decorators: [withTheme()],
|
|
15
14
|
component: UserAccountAvatar,
|
|
16
15
|
} satisfies Meta<typeof UserAccountAvatar>;
|
|
17
16
|
|
|
@@ -22,7 +22,7 @@ export const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAcco
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<>
|
|
25
|
-
<L0ItemActiveTabIndicator classNames='inset-
|
|
25
|
+
<L0ItemActiveTabIndicator classNames='inset-y-6' />
|
|
26
26
|
<div
|
|
27
27
|
className='grid place-items-center dx-focus-ring-group-indicator rounded-full'
|
|
28
28
|
data-joyride='welcome/account'
|
package/src/components/index.ts
CHANGED
package/src/components/types.ts
CHANGED
|
@@ -6,28 +6,23 @@ import type { FC } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { type Node } from '@dxos/app-graph';
|
|
8
8
|
import type { Density } from '@dxos/react-ui';
|
|
9
|
-
import type { TreeProps } from '@dxos/react-ui-list';
|
|
10
|
-
import type { MaybePromise } from '@dxos/util';
|
|
9
|
+
import type { TreeModel, TreeProps } from '@dxos/react-ui-list';
|
|
11
10
|
|
|
12
|
-
import type {
|
|
11
|
+
import type { NavTreeItemGraphNode } from '#types';
|
|
13
12
|
|
|
14
13
|
import type { L1PanelProps } from './Sidebar';
|
|
15
14
|
|
|
16
|
-
export type NavTreeContextValue =
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
export type NavTreeContextValue = {
|
|
16
|
+
model: TreeModel<NavTreeItemGraphNode>;
|
|
17
|
+
popoverAnchorId?: string;
|
|
18
|
+
renderItemEnd?: FC<{ node: Node.Node; open: boolean }>;
|
|
19
|
+
setAlternateTree?: (path: string[], open: boolean) => void;
|
|
20
|
+
onTabChange?: (node: NavTreeItemGraphNode) => void;
|
|
21
|
+
} & Pick<
|
|
22
|
+
TreeProps<NavTreeItemGraphNode>,
|
|
23
|
+
'blockInstruction' | 'canDrop' | 'canSelect' | 'onOpenChange' | 'onSelect' | 'onItemHover'
|
|
19
24
|
> &
|
|
20
|
-
Pick<L1PanelProps, 'onBack'
|
|
21
|
-
tab: string;
|
|
22
|
-
topbar?: boolean;
|
|
23
|
-
popoverAnchorId?: string;
|
|
24
|
-
renderItemEnd?: FC<{ node: Node.Node; open: boolean }>;
|
|
25
|
-
useActions: (node: Node.Node) => FlattenedActions;
|
|
26
|
-
loadDescendents?: (node: Node.Node) => MaybePromise<void>;
|
|
27
|
-
useIsAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
|
|
28
|
-
setAlternateTree?: (path: string[], open: boolean) => void;
|
|
29
|
-
onTabChange?: (node: NavTreeItemGraphNode) => void;
|
|
30
|
-
};
|
|
25
|
+
Pick<L1PanelProps, 'onBack'>;
|
|
31
26
|
|
|
32
27
|
export type NavTreeItemColumnsProps = {
|
|
33
28
|
path: string[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
9
|
+
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
10
|
+
import { Dialog } from '@dxos/react-ui';
|
|
11
|
+
import { withLayout } from '@dxos/react-ui/testing';
|
|
12
|
+
|
|
13
|
+
import { NavTreePlugin } from '../../NavTreePlugin';
|
|
14
|
+
import { translations } from '../../translations';
|
|
15
|
+
|
|
16
|
+
import { CommandsDialogContent } from './CommandsDialogContent';
|
|
17
|
+
|
|
18
|
+
const DefaultStory = () => (
|
|
19
|
+
<Dialog.Root defaultOpen>
|
|
20
|
+
<Dialog.Overlay>
|
|
21
|
+
<CommandsDialogContent />
|
|
22
|
+
</Dialog.Overlay>
|
|
23
|
+
</Dialog.Root>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const meta = {
|
|
27
|
+
title: 'plugins/plugin-navtree/containers/CommandsDialogContent',
|
|
28
|
+
component: CommandsDialogContent,
|
|
29
|
+
render: DefaultStory,
|
|
30
|
+
decorators: [
|
|
31
|
+
withLayout({ layout: 'fullscreen' }),
|
|
32
|
+
withPluginManager({
|
|
33
|
+
plugins: [...corePlugins(), StorybookPlugin({}), NavTreePlugin()],
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
parameters: {
|
|
37
|
+
layout: 'fullscreen',
|
|
38
|
+
translations,
|
|
39
|
+
},
|
|
40
|
+
} satisfies Meta<typeof CommandsDialogContent>;
|
|
41
|
+
|
|
42
|
+
export default meta;
|
|
43
|
+
|
|
44
|
+
type Story = StoryObj<typeof meta>;
|
|
45
|
+
|
|
46
|
+
export const Default: Story = {};
|
|
@@ -4,17 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { forwardRef, useMemo, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { useOperationInvoker } from '@dxos/app-framework/ui';
|
|
8
|
+
import { LayoutOperation } from '@dxos/app-toolkit';
|
|
9
|
+
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
9
10
|
import { Keyboard, keySymbols } from '@dxos/keyboard';
|
|
10
11
|
import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
|
|
11
12
|
import { useActions } from '@dxos/plugin-graph';
|
|
12
13
|
import { Button, Dialog, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
13
|
-
import { SearchList, useSearchListResults } from '@dxos/react-ui-
|
|
14
|
+
import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
|
|
14
15
|
import { osTranslations } from '@dxos/ui-theme';
|
|
15
16
|
import { getHostPlatform } from '@dxos/util';
|
|
16
17
|
|
|
17
|
-
import { KEY_BINDING, meta } from '
|
|
18
|
+
import { KEY_BINDING, meta } from '#meta';
|
|
18
19
|
|
|
19
20
|
export type CommandsDialogContentProps = {
|
|
20
21
|
selected?: string;
|
|
@@ -24,7 +25,7 @@ export type CommandsDialogContentProps = {
|
|
|
24
25
|
export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogContentProps>(
|
|
25
26
|
({ selected: initial }, forwardedRef) => {
|
|
26
27
|
const { t } = useTranslation(meta.id);
|
|
27
|
-
const {
|
|
28
|
+
const { invokePromise } = useOperationInvoker();
|
|
28
29
|
const runAction = useActionRunner();
|
|
29
30
|
const { graph } = useAppGraph();
|
|
30
31
|
const [selected, setSelected] = useState<string | undefined>(initial);
|
|
@@ -37,12 +38,12 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
37
38
|
const actionMap = new Set<string>();
|
|
38
39
|
const actions: Node.ActionLike[] = [];
|
|
39
40
|
Graph.traverse(graph, {
|
|
41
|
+
relation: ['child', 'action'],
|
|
40
42
|
visitor: (node, path) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
) {
|
|
43
|
+
const isActionLike = Node.isAction(node) || Node.isActionGroup(node);
|
|
44
|
+
const parentId = path.at(-2) ?? '';
|
|
45
|
+
const matches = current === parentId || current.startsWith(parentId + '/');
|
|
46
|
+
if (isActionLike && !actionMap.has(node.id) && matches) {
|
|
46
47
|
actionMap.add(node.id);
|
|
47
48
|
actions.push(node);
|
|
48
49
|
}
|
|
@@ -69,11 +70,11 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
69
70
|
|
|
70
71
|
return (
|
|
71
72
|
<Dialog.Content ref={forwardedRef}>
|
|
72
|
-
<Dialog.Title>{t('commands
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
-
<SearchList.Input placeholder={t('command list input placeholder')} />
|
|
73
|
+
<Dialog.Title srOnly>{t('commands-dialog.title', { ns: meta.id })}</Dialog.Title>
|
|
74
|
+
<Dialog.Body>
|
|
75
|
+
<SearchList.Root onSearch={handleSearch}>
|
|
76
76
|
<SearchList.Content>
|
|
77
|
+
<SearchList.Input placeholder={t('command-list-input.placeholder')} />
|
|
77
78
|
<SearchList.Viewport>
|
|
78
79
|
{results.map((action) => {
|
|
79
80
|
const shortcut =
|
|
@@ -98,9 +99,10 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
void invokePromise(LayoutOperation.UpdateDialog, { state: false });
|
|
102
103
|
setTimeout(() => {
|
|
103
|
-
const
|
|
104
|
+
const lookupId = group?.id ?? action.id;
|
|
105
|
+
const node = Graph.getConnections(graph, lookupId, Node.actionRelation('inbound'))[0];
|
|
104
106
|
if (node && Node.isAction(action)) {
|
|
105
107
|
void runAction(action, { parent: node, caller: KEY_BINDING });
|
|
106
108
|
}
|
|
@@ -116,13 +118,13 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
116
118
|
})}
|
|
117
119
|
</SearchList.Viewport>
|
|
118
120
|
</SearchList.Content>
|
|
119
|
-
</
|
|
120
|
-
</
|
|
121
|
-
<
|
|
121
|
+
</SearchList.Root>
|
|
122
|
+
</Dialog.Body>
|
|
123
|
+
<Dialog.ActionBar>
|
|
122
124
|
<Dialog.Close asChild>
|
|
123
|
-
<Button classNames='
|
|
125
|
+
<Button classNames='w-full'>{t('close.label', { ns: osTranslations })}</Button>
|
|
124
126
|
</Dialog.Close>
|
|
125
|
-
</
|
|
127
|
+
</Dialog.ActionBar>
|
|
126
128
|
</Dialog.Content>
|
|
127
129
|
);
|
|
128
130
|
},
|