@dxos/plugin-navtree 0.8.4-main.ae835ea → 0.8.4-main.bc674ce
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-RSMA6I22.mjs +43 -0
- package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs.map +7 -0
- package/dist/lib/browser/chunk-6YPQ625I.mjs +1293 -0
- package/dist/lib/browser/chunk-6YPQ625I.mjs.map +7 -0
- package/dist/lib/browser/chunk-AGQDZBPL.mjs +23 -0
- package/dist/lib/browser/chunk-AGQDZBPL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-E6MZBCU5.mjs → chunk-YKTYPINZ.mjs} +1 -1
- package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +82 -91
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/{keyboard-YYTYJW4M.mjs → keyboard-32EH3N4K.mjs} +20 -19
- package/dist/lib/browser/keyboard-32EH3N4K.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs +52 -0
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs.map +7 -0
- package/dist/lib/browser/react-surface-F6CVMS3Y.mjs +58 -0
- package/dist/lib/browser/react-surface-F6CVMS3Y.mjs.map +7 -0
- package/dist/lib/browser/state-EVYQOUI3.mjs +120 -0
- package/dist/lib/browser/state-EVYQOUI3.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +2 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +3 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +5 -108
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard/index.d.ts +3 -0
- package/dist/types/src/capabilities/keyboard/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts +5 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/index.d.ts +3 -0
- package/dist/types/src/capabilities/state/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/state.d.ts +6 -0
- package/dist/types/src/capabilities/state/state.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +3 -2
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -1
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts +30 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +4 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContainer.d.ts +8 -1
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +6 -6
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +2 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +4 -4
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts +2 -2
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +7 -7
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/hooks.d.ts +32 -1
- package/dist/types/src/hooks.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +5 -6
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.d.ts +2 -2
- package/dist/types/src/testing/update-state.d.ts.map +1 -1
- package/dist/types/src/types/capabilities.d.ts +16 -0
- package/dist/types/src/types/capabilities.d.ts.map +1 -0
- package/dist/types/src/types/events.d.ts +5 -0
- package/dist/types/src/types/events.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +4 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/{types.d.ts → types/schema.d.ts} +6 -6
- package/dist/types/src/types/schema.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +7 -7
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +53 -52
- package/src/NavTreePlugin.tsx +53 -70
- package/src/capabilities/app-graph-builder/app-graph-builder.ts +41 -0
- package/src/capabilities/app-graph-builder/index.ts +7 -0
- package/src/capabilities/index.ts +5 -9
- package/src/capabilities/keyboard/index.ts +7 -0
- package/src/capabilities/keyboard/keyboard.ts +65 -0
- package/src/capabilities/operation-resolver/index.ts +7 -0
- package/src/capabilities/operation-resolver/operation-resolver.ts +41 -0
- package/src/capabilities/react-surface/index.ts +7 -0
- package/src/capabilities/react-surface/react-surface.tsx +54 -0
- package/src/capabilities/state/index.ts +7 -0
- package/src/capabilities/state/state.ts +121 -0
- package/src/components/CommandsDialog/CommandsDialog.tsx +108 -97
- package/src/components/CommandsDialog/CommandsTrigger.tsx +4 -13
- package/src/components/NavTree/NavTree.stories.tsx +33 -42
- package/src/components/NavTree/NavTree.tsx +5 -15
- package/src/components/NavTreeContainer.tsx +253 -262
- package/src/components/NavTreeDocumentTitle.tsx +3 -2
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +17 -7
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +18 -12
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +5 -5
- package/src/components/Sidebar/L0Menu.tsx +67 -93
- package/src/components/Sidebar/L1Panel.tsx +9 -9
- package/src/components/Sidebar/L1Tabs.tsx +6 -31
- package/src/components/index.ts +1 -0
- package/src/components/types.ts +7 -7
- package/src/experimental/Tree.stories.tsx +4 -4
- package/src/experimental/Tree.tsx +3 -3
- package/src/hooks.ts +54 -2
- package/src/index.ts +1 -2
- package/src/meta.ts +2 -2
- package/src/testing/app-graph-builder.ts +159 -235
- package/src/testing/generator.ts +19 -17
- package/src/testing/update-state.ts +6 -6
- package/src/types/capabilities.ts +21 -0
- package/src/types/events.ts +11 -0
- package/src/types/index.ts +7 -0
- package/src/{types.ts → types/schema.ts} +5 -5
- package/src/util.ts +13 -16
- package/dist/lib/browser/app-graph-builder-D7NLWZLU.mjs +0 -46
- package/dist/lib/browser/app-graph-builder-D7NLWZLU.mjs.map +0 -7
- package/dist/lib/browser/chunk-5VLWX4PK.mjs +0 -15
- package/dist/lib/browser/chunk-5VLWX4PK.mjs.map +0 -7
- package/dist/lib/browser/chunk-BNGPXJB7.mjs +0 -1482
- package/dist/lib/browser/chunk-BNGPXJB7.mjs.map +0 -7
- package/dist/lib/browser/chunk-E6MZBCU5.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs +0 -47
- package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +0 -7
- package/dist/lib/browser/keyboard-YYTYJW4M.mjs.map +0 -7
- package/dist/lib/browser/react-surface-7OUBD57A.mjs +0 -51
- package/dist/lib/browser/react-surface-7OUBD57A.mjs.map +0 -7
- package/dist/lib/browser/state-EUSVT6BI.mjs +0 -117
- package/dist/lib/browser/state-EUSVT6BI.mjs.map +0 -7
- package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/capabilities.d.ts +0 -21
- package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/keyboard.d.ts +0 -4
- package/dist/types/src/capabilities/keyboard.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface.d.ts +0 -4
- package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
- package/dist/types/src/capabilities/state.d.ts +0 -20
- package/dist/types/src/capabilities/state.d.ts.map +0 -1
- package/dist/types/src/events.d.ts +0 -4
- package/dist/types/src/events.d.ts.map +0 -1
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder.ts +0 -53
- package/src/capabilities/capabilities.ts +0 -20
- package/src/capabilities/intent-resolver.ts +0 -37
- package/src/capabilities/keyboard.ts +0 -59
- package/src/capabilities/react-surface.tsx +0 -45
- package/src/capabilities/state.ts +0 -105
- package/src/events.ts +0 -11
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
|
+
import { useActionRunner } from '@dxos/plugin-graph';
|
|
8
9
|
import { IconButton, toLocalizedString, useDensityContext, useTranslation } from '@dxos/react-ui';
|
|
9
10
|
import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
|
|
10
|
-
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/
|
|
11
|
+
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
|
|
11
12
|
|
|
12
13
|
import { meta } from '../../meta';
|
|
13
14
|
import { type ActionProperties } from '../../types';
|
|
14
15
|
|
|
15
16
|
export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
16
|
-
parent: Node;
|
|
17
|
+
parent: Node.Node;
|
|
17
18
|
caller?: string;
|
|
18
19
|
monolithic?: boolean;
|
|
19
|
-
menuActions?: Action[];
|
|
20
|
+
menuActions?: Node.Action[];
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const fallbackIcon = 'ph--placeholder--regular';
|
|
@@ -40,8 +41,10 @@ export const NavTreeItemActionDropdownMenu = ({
|
|
|
40
41
|
}: NavTreeItemActionMenuProps) => {
|
|
41
42
|
const { t } = useTranslation(meta.id);
|
|
42
43
|
const density = useDensityContext();
|
|
44
|
+
const runAction = useActionRunner();
|
|
45
|
+
|
|
43
46
|
return (
|
|
44
|
-
<MenuProvider>
|
|
47
|
+
<MenuProvider onAction={runAction}>
|
|
45
48
|
<DropdownMenu.Root group={parent} items={menuActions as MenuItem[]} caller={caller}>
|
|
46
49
|
<DropdownMenu.Trigger asChild>
|
|
47
50
|
<IconButton
|
|
@@ -59,13 +62,16 @@ export const NavTreeItemActionDropdownMenu = ({
|
|
|
59
62
|
);
|
|
60
63
|
};
|
|
61
64
|
|
|
62
|
-
export const NavTreeItemMonolithicAction = (
|
|
63
|
-
parent,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
export const NavTreeItemMonolithicAction = (
|
|
66
|
+
props: Node.Action & { parent: Node.Node; onAction?: (action: Node.Action) => void; baseLabel: string },
|
|
67
|
+
) => {
|
|
68
|
+
const {
|
|
69
|
+
parent,
|
|
70
|
+
properties: { disabled, caller, testId, icon, variant = 'ghost', iconOnly = true } = { label: 'never' },
|
|
71
|
+
baseLabel,
|
|
72
|
+
} = props;
|
|
68
73
|
const density = useDensityContext();
|
|
74
|
+
const runAction = useActionRunner();
|
|
69
75
|
return (
|
|
70
76
|
<IconButton
|
|
71
77
|
{...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
|
|
@@ -86,7 +92,7 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
void
|
|
95
|
+
void runAction(props, caller ? { parent, caller } : { parent });
|
|
90
96
|
}}
|
|
91
97
|
data-testid={testId}
|
|
92
98
|
/>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { Fragment, memo } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Node } from '@dxos/app-graph';
|
|
8
8
|
import { Popover, Treegrid, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
10
|
import { useLoadDescendents } from '../../hooks';
|
|
@@ -26,11 +26,11 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
|
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
const actions = (primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : _actions)
|
|
29
|
-
.flatMap((action) => (isAction(action) ? [action] : []))
|
|
29
|
+
.flatMap((action) => (Node.isAction(action) ? [action] : []))
|
|
30
30
|
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
31
31
|
|
|
32
32
|
useLoadDescendents(item);
|
|
33
|
-
useLoadDescendents(primaryAction && !isAction(primaryAction) ? primaryAction : undefined);
|
|
33
|
+
useLoadDescendents(primaryAction && !Node.isAction(primaryAction) ? (primaryAction as Node.Node) : undefined);
|
|
34
34
|
|
|
35
35
|
const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover.Anchor : Fragment;
|
|
36
36
|
|
|
@@ -43,8 +43,8 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
|
|
|
43
43
|
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
44
44
|
icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
|
|
45
45
|
parent={item}
|
|
46
|
-
monolithic={isAction(primaryAction)}
|
|
47
|
-
menuActions={isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction
|
|
46
|
+
monolithic={Node.isAction(primaryAction)}
|
|
47
|
+
menuActions={Node.isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction?.id ?? '']}
|
|
48
48
|
menuType={primaryAction.properties?.menuType}
|
|
49
49
|
caller={NAV_TREE_ITEM}
|
|
50
50
|
/>
|
|
@@ -23,8 +23,8 @@ import React, {
|
|
|
23
23
|
} from 'react';
|
|
24
24
|
|
|
25
25
|
import { type Node } from '@dxos/app-graph';
|
|
26
|
-
import { invariant } from '@dxos/invariant';
|
|
27
26
|
import { DxAvatar } from '@dxos/lit-ui/react';
|
|
27
|
+
import { useActionRunner } from '@dxos/plugin-graph';
|
|
28
28
|
import {
|
|
29
29
|
Icon,
|
|
30
30
|
ListItem,
|
|
@@ -38,10 +38,10 @@ import {
|
|
|
38
38
|
import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
|
|
39
39
|
import type { StackItemRearrangeHandler } from '@dxos/react-ui-stack';
|
|
40
40
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
41
|
-
import { mx } from '@dxos/
|
|
41
|
+
import { mx } from '@dxos/ui-theme';
|
|
42
42
|
import { arrayMove } from '@dxos/util';
|
|
43
43
|
|
|
44
|
-
import {
|
|
44
|
+
import { useNavTreeState } from '../../hooks';
|
|
45
45
|
import { meta } from '../../meta';
|
|
46
46
|
import { l0ItemType } from '../../util';
|
|
47
47
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
@@ -57,43 +57,41 @@ type L0ItemData = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
type L0ItemRootProps = {
|
|
60
|
-
item: Node
|
|
61
|
-
parent?: Node
|
|
60
|
+
item: Node.Node;
|
|
61
|
+
parent?: Node.Node;
|
|
62
62
|
path: string[];
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
type L0ItemProps = L0ItemRootProps & {
|
|
66
|
-
item: Node
|
|
67
|
-
parent?: Node
|
|
66
|
+
item: Node.Node;
|
|
67
|
+
parent?: Node.Node;
|
|
68
68
|
path: string[];
|
|
69
69
|
pinned?: boolean;
|
|
70
70
|
onRearrange?: StackItemRearrangeHandler<L0ItemData>;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
|
|
74
|
-
const { tab,
|
|
74
|
+
const { tab, onSelect, onTabChange } = useNavTreeContext();
|
|
75
|
+
const { getItem } = useNavTreeState();
|
|
75
76
|
const [isLg] = useMediaQuery('lg');
|
|
77
|
+
const runAction = useActionRunner();
|
|
76
78
|
|
|
77
79
|
return useCallback(
|
|
78
80
|
(event: MouseEvent) => {
|
|
79
81
|
switch (type) {
|
|
80
82
|
case 'action': {
|
|
81
|
-
const {
|
|
82
|
-
|
|
83
|
-
properties: { caller },
|
|
84
|
-
} = item;
|
|
85
|
-
|
|
86
|
-
return invoke?.(caller ? { node: parent, caller } : { node: parent });
|
|
83
|
+
const { properties: { caller } = {} } = item;
|
|
84
|
+
return void runAction(item as Node.Action, caller ? { parent, caller } : { parent });
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
case 'tab':
|
|
90
88
|
return onTabChange?.(item);
|
|
91
89
|
|
|
92
90
|
case 'link':
|
|
93
|
-
return onSelect?.({ item, path, current: !
|
|
91
|
+
return onSelect?.({ item, path, current: !getItem(path).current, option: event.altKey });
|
|
94
92
|
}
|
|
95
93
|
},
|
|
96
|
-
[item, parent, type, tab,
|
|
94
|
+
[item, parent, type, tab, getItem, onSelect, onTabChange, isLg, runAction],
|
|
97
95
|
);
|
|
98
96
|
};
|
|
99
97
|
|
|
@@ -102,7 +100,7 @@ const l0Breakpoints: Record<string, string> = {
|
|
|
102
100
|
};
|
|
103
101
|
|
|
104
102
|
const l0ItemRoot =
|
|
105
|
-
'group/l0item flex
|
|
103
|
+
'group/l0item flex is-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
|
|
106
104
|
|
|
107
105
|
const l0ItemContent = 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm';
|
|
108
106
|
|
|
@@ -119,10 +117,8 @@ const L0ItemRoot = forwardRef<HTMLElement, PropsWithChildren<L0ItemRootProps>>(
|
|
|
119
117
|
const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
|
|
120
118
|
const rootProps =
|
|
121
119
|
type === 'tab'
|
|
122
|
-
? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-
|
|
123
|
-
:
|
|
124
|
-
? { onClick: handleClick, 'data-testid': testId, 'data-itemid': id }
|
|
125
|
-
: { onClick: handleClick, role: 'button' };
|
|
120
|
+
? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-object-id': id }
|
|
121
|
+
: { onClick: handleClick, 'data-testid': testId, 'data-object-id': id };
|
|
126
122
|
|
|
127
123
|
return (
|
|
128
124
|
<Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
|
|
@@ -256,68 +252,50 @@ const ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
|
|
|
256
252
|
};
|
|
257
253
|
|
|
258
254
|
//
|
|
259
|
-
//
|
|
255
|
+
// L0Menu
|
|
260
256
|
//
|
|
261
257
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
258
|
+
export type L0MenuProps = {
|
|
259
|
+
menuActions: MenuItem[];
|
|
260
|
+
topLevelItems: Node.Node[];
|
|
261
|
+
pinnedItems: Node.Node[];
|
|
262
|
+
userAccountItem?: Node.Node;
|
|
263
|
+
parent?: Node.Node;
|
|
264
|
+
path: string[];
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
|
|
268
|
+
const { t } = useTranslation(meta.id);
|
|
269
|
+
const runAction = useActionRunner();
|
|
270
|
+
const handleAction = useCallback(
|
|
271
|
+
(action: Node.Action, params: Node.InvokeProps) => {
|
|
272
|
+
void runAction(action, params);
|
|
273
|
+
},
|
|
274
|
+
[runAction],
|
|
275
|
+
);
|
|
268
276
|
|
|
269
277
|
const handleRearrange = useCallback<StackItemRearrangeHandler<L0ItemData>>(
|
|
270
278
|
(source, target, closestEdge) => {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
279
|
+
const sourceItem = topLevelItems.find((i) => i.id === source.id);
|
|
280
|
+
if (!sourceItem?.properties.onRearrange) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const sourceIndex = topLevelItems.findIndex((i) => i.id === source.id);
|
|
285
|
+
const targetIndex = topLevelItems.findIndex((i) => i.id === target.id);
|
|
274
286
|
const insertIndex =
|
|
275
287
|
source.id === target.id
|
|
276
288
|
? sourceIndex
|
|
277
289
|
: targetIndex +
|
|
278
290
|
(sourceIndex < targetIndex ? (closestEdge === 'top' ? -1 : 0) : closestEdge === 'bottom' ? 1 : 0);
|
|
279
|
-
const nextOrder = arrayMove([...
|
|
280
|
-
return
|
|
291
|
+
const nextOrder = arrayMove([...topLevelItems], sourceIndex, insertIndex);
|
|
292
|
+
return sourceItem.properties.onRearrange(nextOrder.map((item) => item.data));
|
|
281
293
|
},
|
|
282
|
-
[
|
|
294
|
+
[topLevelItems],
|
|
283
295
|
);
|
|
284
296
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
role='group'
|
|
288
|
-
className='contents group/l0c'
|
|
289
|
-
aria-labelledby={`${item.id}__label`}
|
|
290
|
-
data-itemid={id}
|
|
291
|
-
data-testid={testId}
|
|
292
|
-
>
|
|
293
|
-
{collectionItems.map((collectionItem) => (
|
|
294
|
-
<L0Item
|
|
295
|
-
key={collectionItem.id}
|
|
296
|
-
item={collectionItem}
|
|
297
|
-
parent={item}
|
|
298
|
-
path={groupPath}
|
|
299
|
-
{...(item.properties.onRearrangeChildren && { onRearrange: handleRearrange })}
|
|
300
|
-
/>
|
|
301
|
-
))}
|
|
302
|
-
</div>
|
|
303
|
-
);
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
//
|
|
307
|
-
// L0Menu
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
export type L0MenuProps = {
|
|
311
|
-
menuActions: MenuItem[];
|
|
312
|
-
topLevelItems: Node<any>[];
|
|
313
|
-
pinnedItems: Node<any>[];
|
|
314
|
-
userAccountItem?: Node<any>;
|
|
315
|
-
parent?: Node<any>;
|
|
316
|
-
path: string[];
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
|
|
320
|
-
const { t } = useTranslation(meta.id);
|
|
297
|
+
// Check if any items have onRearrange to enable drag-and-drop.
|
|
298
|
+
const hasRearrangeableItems = topLevelItems.some((item) => item.properties.onRearrange);
|
|
321
299
|
|
|
322
300
|
return (
|
|
323
301
|
<Tabs.Tablist
|
|
@@ -328,13 +306,17 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
328
306
|
]}
|
|
329
307
|
>
|
|
330
308
|
{/* TODO(wittjosiah): Use L0Item trigger. */}
|
|
331
|
-
<MenuProvider>
|
|
309
|
+
<MenuProvider onAction={handleAction}>
|
|
332
310
|
<DropdownMenu.Root group={parent} items={menuActions}>
|
|
333
311
|
<Tooltip.Trigger content={t('app menu label')} side='right' asChild>
|
|
334
312
|
<Tabs.TabPrimitive value='options' asChild role='button'>
|
|
335
313
|
<DropdownMenu.Trigger
|
|
336
314
|
data-testid='spacePlugin.addSpace'
|
|
337
|
-
className={mx(
|
|
315
|
+
className={mx(
|
|
316
|
+
l0ItemRoot,
|
|
317
|
+
'grid place-items-center dx-focus-ring-group',
|
|
318
|
+
'[body[data-platform="macos"]_&]:mt-[30px]',
|
|
319
|
+
)}
|
|
338
320
|
>
|
|
339
321
|
<div
|
|
340
322
|
role='none'
|
|
@@ -358,17 +340,19 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
358
340
|
role='none'
|
|
359
341
|
className={mx([
|
|
360
342
|
'flex flex-col gap-1 pbs-1',
|
|
361
|
-
'[body[data-platform="
|
|
343
|
+
'[body[data-platform="macos"]_&]:pbs-[30px]',
|
|
362
344
|
'[body[data-platform="ios"]_&]:pbs-[max(env(safe-area-inset-top),0.25rem)]',
|
|
363
345
|
])}
|
|
364
346
|
>
|
|
365
|
-
{topLevelItems.map((item) =>
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
347
|
+
{topLevelItems.map((item) => (
|
|
348
|
+
<L0Item
|
|
349
|
+
key={item.id}
|
|
350
|
+
item={item}
|
|
351
|
+
parent={parent}
|
|
352
|
+
path={path}
|
|
353
|
+
{...(hasRearrangeableItems && { onRearrange: handleRearrange })}
|
|
354
|
+
/>
|
|
355
|
+
))}
|
|
372
356
|
</div>
|
|
373
357
|
<ScrollArea.Scrollbar orientation='vertical'>
|
|
374
358
|
<ScrollArea.Thumb />
|
|
@@ -378,11 +362,9 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
378
362
|
|
|
379
363
|
{/* Actions. */}
|
|
380
364
|
<div role='none' className='grid grid-cols-1 auto-rows-[--rail-action] pbs-2'>
|
|
381
|
-
{pinnedItems
|
|
382
|
-
.
|
|
383
|
-
|
|
384
|
-
<L0Item key={item.id} item={item} parent={parent} path={path} pinned />
|
|
385
|
-
))}
|
|
365
|
+
{pinnedItems.map((item) => (
|
|
366
|
+
<L0Item key={item.id} item={item} parent={parent} path={path} pinned />
|
|
367
|
+
))}
|
|
386
368
|
</div>
|
|
387
369
|
|
|
388
370
|
{userAccountItem && (
|
|
@@ -398,14 +380,6 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
398
380
|
</L0ItemRoot>
|
|
399
381
|
</div>
|
|
400
382
|
)}
|
|
401
|
-
<div
|
|
402
|
-
role='none'
|
|
403
|
-
className='hidden [body[data-platform="darwin"]_&]:block absolute block-start-0 is-[calc(var(--l0-size)-1px)] bs-[calc(40px+0.25rem)]'
|
|
404
|
-
style={{
|
|
405
|
-
background:
|
|
406
|
-
'linear-gradient(to bottom, var(--dx-sidebarSurface) 0%, var(--dx-sidebarSurface) 70%, transparent 100%)',
|
|
407
|
-
}}
|
|
408
|
-
/>
|
|
409
383
|
</Tabs.Tablist>
|
|
410
384
|
);
|
|
411
385
|
};
|
|
@@ -8,8 +8,9 @@ import { type Node } from '@dxos/app-graph';
|
|
|
8
8
|
import { DensityProvider, IconButton, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
import { Tree } from '@dxos/react-ui-list';
|
|
10
10
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
11
|
-
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/
|
|
11
|
+
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
|
|
12
12
|
|
|
13
|
+
import { useIsAlternateTree } from '../../hooks';
|
|
13
14
|
import { meta } from '../../meta';
|
|
14
15
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
15
16
|
import { NavTreeItemColumns } from '../NavTreeItem';
|
|
@@ -17,7 +18,7 @@ import { NavTreeItemColumns } from '../NavTreeItem';
|
|
|
17
18
|
export type L1PanelProps = {
|
|
18
19
|
open?: boolean;
|
|
19
20
|
path: string[];
|
|
20
|
-
item: Node
|
|
21
|
+
item: Node.Node;
|
|
21
22
|
currentItemId: string;
|
|
22
23
|
onBack?: () => void;
|
|
23
24
|
};
|
|
@@ -27,16 +28,16 @@ export type L1PanelProps = {
|
|
|
27
28
|
*/
|
|
28
29
|
export const L1Panel = ({ open, path, item, currentItemId, onBack }: L1PanelProps) => {
|
|
29
30
|
const { t } = useTranslation(meta.id);
|
|
30
|
-
const
|
|
31
|
+
const navTreeContext = useNavTreeContext();
|
|
31
32
|
const title = toLocalizedString(item.properties.label, t);
|
|
32
33
|
|
|
33
34
|
// TODO(wittjosiah): Support multiple alternate trees.
|
|
34
35
|
const { useItems } = navTreeContext;
|
|
35
36
|
const alternateTree = useItems(item, { disposition: 'alternate-tree' })[0];
|
|
36
37
|
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
37
|
-
const isAlternate =
|
|
38
|
+
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
38
39
|
const useAlternateItems = useCallback(
|
|
39
|
-
(node?: Node, { disposition }: { disposition?: string } = {}) => {
|
|
40
|
+
(node?: Node.Node, { disposition }: { disposition?: string } = {}) => {
|
|
40
41
|
// TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
|
|
41
42
|
return useItems(node, { disposition, sort: node?.id === alternateTree.id });
|
|
42
43
|
},
|
|
@@ -96,13 +97,13 @@ export const L1Panel = ({ open, path, item, currentItemId, onBack }: L1PanelProp
|
|
|
96
97
|
*/
|
|
97
98
|
const L1PanelHeader = ({ item, path, onBack }: L1PanelProps) => {
|
|
98
99
|
const { t } = useTranslation(meta.id);
|
|
99
|
-
const {
|
|
100
|
+
const { setAlternateTree, ...navTreeContext } = useNavTreeContext();
|
|
100
101
|
const title = toLocalizedString(item.properties.label, t);
|
|
101
102
|
|
|
102
103
|
// TODO(wittjosiah): Support multiple alternate trees.
|
|
103
104
|
const alternateTree = navTreeContext.useItems(item, { disposition: 'alternate-tree' })[0];
|
|
104
105
|
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
105
|
-
const isAlternate =
|
|
106
|
+
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
106
107
|
const backCapable = item.id.startsWith('!') || isAlternate;
|
|
107
108
|
|
|
108
109
|
const handleOpen = useCallback(() => {
|
|
@@ -124,10 +125,10 @@ const L1PanelHeader = ({ item, path, onBack }: L1PanelProps) => {
|
|
|
124
125
|
<h2 className='flex-1 truncate min-is-0'>{title}</h2>
|
|
125
126
|
{(backCapable && (
|
|
126
127
|
<IconButton
|
|
128
|
+
data-testid='treeView.primaryTreeButton'
|
|
127
129
|
variant='ghost'
|
|
128
130
|
icon='ph--arrow-u-down-left--regular'
|
|
129
131
|
iconOnly
|
|
130
|
-
size={5}
|
|
131
132
|
label={t('button back')}
|
|
132
133
|
classNames={[hoverableControlItem, hoverableOpenControlItem, 'pointer-fine:pli-1']}
|
|
133
134
|
onClick={handleBack}
|
|
@@ -139,7 +140,6 @@ const L1PanelHeader = ({ item, path, onBack }: L1PanelProps) => {
|
|
|
139
140
|
variant='ghost'
|
|
140
141
|
icon={alternateTree.properties.icon ?? 'ph--placeholder--regular'}
|
|
141
142
|
iconOnly
|
|
142
|
-
size={5}
|
|
143
143
|
label={toLocalizedString(alternateTree.properties.label ?? alternateTree.id, t)}
|
|
144
144
|
classNames={[hoverableControlItem, hoverableOpenControlItem, 'pointer-fine:pli-1']}
|
|
145
145
|
onClick={handleOpen}
|
|
@@ -2,57 +2,32 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React
|
|
5
|
+
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import { type Node } from '@dxos/app-graph';
|
|
8
8
|
|
|
9
|
-
import { useLoadDescendents } from '../../hooks';
|
|
10
9
|
import { l0ItemType } from '../../util';
|
|
11
|
-
import { useNavTreeContext } from '../NavTreeContext';
|
|
12
10
|
|
|
13
11
|
import { L1Panel, type L1PanelProps } from './L1Panel';
|
|
14
12
|
|
|
15
13
|
export type L1TabsProps = Pick<L1PanelProps, 'open' | 'currentItemId' | 'onBack'> & {
|
|
16
14
|
path: string[];
|
|
17
|
-
topLevelItems: Node
|
|
15
|
+
topLevelItems: Node.Node[];
|
|
18
16
|
};
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
|
-
* Each
|
|
19
|
+
* Each workspace is an L1 tab.
|
|
22
20
|
*/
|
|
23
21
|
export const L1Tabs = ({ topLevelItems, onBack, ...props }: L1TabsProps) => {
|
|
24
22
|
return (
|
|
25
23
|
<>
|
|
26
24
|
{topLevelItems.map((item) => {
|
|
27
25
|
const type = l0ItemType(item);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
|
|
31
|
-
case 'collection':
|
|
32
|
-
return <L1PanelCollection key={item.id} item={item} {...props} />;
|
|
33
|
-
default:
|
|
34
|
-
return null;
|
|
26
|
+
if (type === 'tab') {
|
|
27
|
+
return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
|
|
35
28
|
}
|
|
29
|
+
return null;
|
|
36
30
|
})}
|
|
37
31
|
</>
|
|
38
32
|
);
|
|
39
33
|
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*/
|
|
44
|
-
const L1PanelCollection = ({ item, path, ...props }: L1PanelProps) => {
|
|
45
|
-
const { useItems } = useNavTreeContext();
|
|
46
|
-
useLoadDescendents(item);
|
|
47
|
-
const collectionItems = useItems(item);
|
|
48
|
-
const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
49
|
-
return (
|
|
50
|
-
<>
|
|
51
|
-
{collectionItems
|
|
52
|
-
.filter((item) => l0ItemType(item) === 'tab')
|
|
53
|
-
.map((item) => (
|
|
54
|
-
<L1Panel key={item.id} item={item} path={groupPath} {...props} />
|
|
55
|
-
))}
|
|
56
|
-
</>
|
|
57
|
-
);
|
|
58
|
-
};
|
package/src/components/index.ts
CHANGED
package/src/components/types.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { FC } from 'react';
|
|
6
6
|
|
|
7
|
-
import type
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
8
|
import type { Density } from '@dxos/react-ui';
|
|
9
9
|
import type { TreeProps } from '@dxos/react-ui-list';
|
|
10
10
|
import type { MaybePromise } from '@dxos/util';
|
|
@@ -15,23 +15,23 @@ import type { L1PanelProps } from './Sidebar';
|
|
|
15
15
|
|
|
16
16
|
export type NavTreeContextValue = Pick<
|
|
17
17
|
TreeProps<NavTreeItemGraphNode, { disposition?: string; sort?: boolean }>,
|
|
18
|
-
'useItems' | 'getProps' | '
|
|
18
|
+
'useItems' | 'getProps' | 'useIsCurrent' | 'useIsOpen' | 'blockInstruction' | 'canDrop' | 'onOpenChange' | 'onSelect'
|
|
19
19
|
> &
|
|
20
20
|
Pick<L1PanelProps, 'onBack'> & {
|
|
21
21
|
tab: string;
|
|
22
22
|
topbar?: boolean;
|
|
23
23
|
popoverAnchorId?: string;
|
|
24
|
-
renderItemEnd?: FC<{ node: Node; open: boolean }>;
|
|
25
|
-
useActions: (node: Node) => FlattenedActions;
|
|
26
|
-
loadDescendents?: (node: Node) => MaybePromise<void>;
|
|
27
|
-
|
|
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
28
|
setAlternateTree?: (path: string[], open: boolean) => void;
|
|
29
29
|
onTabChange?: (node: NavTreeItemGraphNode) => void;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export type NavTreeItemColumnsProps = {
|
|
33
33
|
path: string[];
|
|
34
|
-
item: Node;
|
|
34
|
+
item: Node.Node;
|
|
35
35
|
open: boolean;
|
|
36
36
|
density?: Density;
|
|
37
37
|
};
|
|
@@ -8,7 +8,7 @@ import React, { type JSX, type PropsWithChildren, useEffect, useState } from 're
|
|
|
8
8
|
import { faker } from '@dxos/random';
|
|
9
9
|
import { Icon, IconButton } from '@dxos/react-ui';
|
|
10
10
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
-
import { mx } from '@dxos/
|
|
11
|
+
import { mx } from '@dxos/ui-theme';
|
|
12
12
|
|
|
13
13
|
import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visitor } from './Tree';
|
|
14
14
|
|
|
@@ -30,7 +30,7 @@ const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Eleme
|
|
|
30
30
|
<div className='flex'>
|
|
31
31
|
{/* TODO(burdon): Custom thin scrollbar. */}
|
|
32
32
|
{/* TODO(burdon): Horizontal scrolling within navtree? */}
|
|
33
|
-
<div className='flex flex-col overflow-y-auto
|
|
33
|
+
<div className='flex flex-col overflow-y-auto is-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
|
|
34
34
|
<div className='flex flex-col grow overflow-hidden'>{children}</div>
|
|
35
35
|
</div>
|
|
36
36
|
);
|
|
@@ -189,7 +189,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
189
189
|
/>
|
|
190
190
|
</div>
|
|
191
191
|
|
|
192
|
-
<div className='flex items-center my-2
|
|
192
|
+
<div className='flex items-center my-2 pli-2 gap-2'>
|
|
193
193
|
<IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
|
|
194
194
|
<span className='grow text-sm' onClick={handleCreateSpace}>
|
|
195
195
|
New space
|
|
@@ -203,7 +203,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
203
203
|
const meta = {
|
|
204
204
|
title: 'plugins/plugin-navtree/experimental/Tree',
|
|
205
205
|
component: Tree,
|
|
206
|
-
decorators: [withTheme, withLayout({
|
|
206
|
+
decorators: [withTheme, withLayout({ layout: 'column' })],
|
|
207
207
|
} satisfies Meta<typeof Tree>;
|
|
208
208
|
|
|
209
209
|
export default meta;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React, { type HTMLAttributes, type PropsWithChildren } from 'react';
|
|
6
6
|
|
|
7
7
|
import { type ClassNameValue, Icon, type Size } from '@dxos/react-ui';
|
|
8
|
-
import { mx } from '@dxos/
|
|
8
|
+
import { mx } from '@dxos/ui-theme';
|
|
9
9
|
|
|
10
10
|
export const IconButton = ({
|
|
11
11
|
iconName,
|
|
@@ -19,7 +19,7 @@ export const IconButton = ({
|
|
|
19
19
|
} & Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
|
|
20
20
|
// TODO(burdon): Density aware.
|
|
21
21
|
return (
|
|
22
|
-
<div className={mx('flex
|
|
22
|
+
<div className={mx('flex is-6 bs-6 items-center justify-center select-none', classNames)} onClick={onClick}>
|
|
23
23
|
<Icon icon={iconName} classNames='cursor-pointer' size={size} />
|
|
24
24
|
</div>
|
|
25
25
|
);
|
|
@@ -193,7 +193,7 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
|
|
|
193
193
|
<Grid
|
|
194
194
|
style={{ paddingLeft: `${(depth - 1) * 24}px` }}
|
|
195
195
|
className={mx(
|
|
196
|
-
'group
|
|
196
|
+
'group is-full items-center cursor-pointer bg-hoverSurface',
|
|
197
197
|
// TODO(burdon): Use data-active.
|
|
198
198
|
selected?.[id] && 'bg-activeSurface',
|
|
199
199
|
className,
|