@dxos/plugin-navtree 0.6.8-main.046e6cf
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/LICENSE +8 -0
- package/README.md +15 -0
- package/dist/lib/browser/chunk-U7MTKDFQ.mjs +13 -0
- package/dist/lib/browser/chunk-U7MTKDFQ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1055 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/browser/meta.mjs +11 -0
- package/dist/lib/browser/meta.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +4 -0
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog.d.ts +5 -0
- package/dist/types/src/components/CommandsDialog.d.ts.map +1 -0
- package/dist/types/src/components/CommandsTrigger.d.ts +3 -0
- package/dist/types/src/components/CommandsTrigger.d.ts.map +1 -0
- package/dist/types/src/components/HaloButton.d.ts +12 -0
- package/dist/types/src/components/HaloButton.d.ts.map +1 -0
- package/dist/types/src/components/HaloButton.stories.d.ts +12 -0
- package/dist/types/src/components/HaloButton.stories.d.ts.map +1 -0
- package/dist/types/src/components/NavBarStart.d.ts +7 -0
- package/dist/types/src/components/NavBarStart.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContainer.d.ts +12 -0
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts +5 -0
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeFooter.d.ts +6 -0
- package/dist/types/src/components/NavTreeFooter.d.ts.map +1 -0
- package/dist/types/src/components/NotchStart.d.ts +3 -0
- package/dist/types/src/components/NotchStart.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +6 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/experimental/Tree.d.ts +56 -0
- package/dist/types/src/experimental/Tree.d.ts.map +1 -0
- package/dist/types/src/experimental/Tree.stories.d.ts +12 -0
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +7 -0
- package/dist/types/src/meta.d.ts.map +1 -0
- package/dist/types/src/stories/Graph.stories.d.ts +17 -0
- package/dist/types/src/stories/Graph.stories.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +27 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +32 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +77 -0
- package/src/NavTreePlugin.tsx +262 -0
- package/src/components/CommandsDialog.tsx +114 -0
- package/src/components/CommandsTrigger.tsx +34 -0
- package/src/components/HaloButton.stories.tsx +19 -0
- package/src/components/HaloButton.tsx +41 -0
- package/src/components/NavBarStart.tsx +48 -0
- package/src/components/NavTreeContainer.tsx +375 -0
- package/src/components/NavTreeDocumentTitle.tsx +17 -0
- package/src/components/NavTreeFooter.tsx +155 -0
- package/src/components/NotchStart.tsx +29 -0
- package/src/components/index.ts +9 -0
- package/src/experimental/Tree.stories.tsx +229 -0
- package/src/experimental/Tree.tsx +282 -0
- package/src/index.ts +10 -0
- package/src/meta.ts +12 -0
- package/src/stories/Graph.stories.tsx +162 -0
- package/src/translations.ts +28 -0
- package/src/util.ts +231 -0
|
@@ -0,0 +1,1055 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KEY_BINDING,
|
|
3
|
+
NAVTREE_PLUGIN,
|
|
4
|
+
meta_default
|
|
5
|
+
} from "./chunk-U7MTKDFQ.mjs";
|
|
6
|
+
|
|
7
|
+
// packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
|
|
8
|
+
import { MagnifyingGlass as MagnifyingGlass2 } from "@phosphor-icons/react";
|
|
9
|
+
import React8 from "react";
|
|
10
|
+
import { resolvePlugin, parseIntentPlugin, LayoutAction as LayoutAction4, parseGraphPlugin, NavigationAction as NavigationAction2 } from "@dxos/app-framework";
|
|
11
|
+
import { createExtension, isAction as isAction4, isGraphNode } from "@dxos/app-graph";
|
|
12
|
+
import { Keyboard as Keyboard2 } from "@dxos/keyboard";
|
|
13
|
+
import { LocalStorageStore } from "@dxos/local-storage";
|
|
14
|
+
import { Path as Path3 } from "@dxos/react-ui-mosaic";
|
|
15
|
+
import { getHostPlatform as getHostPlatform2 } from "@dxos/util";
|
|
16
|
+
|
|
17
|
+
// packages/plugins/plugin-navtree/src/components/CommandsDialog.tsx
|
|
18
|
+
import { DotOutline } from "@phosphor-icons/react";
|
|
19
|
+
import React, { useMemo, useState } from "react";
|
|
20
|
+
import { useIntentDispatcher, LayoutAction } from "@dxos/app-framework";
|
|
21
|
+
import { isActionGroup, isAction } from "@dxos/app-graph";
|
|
22
|
+
import { Keyboard, keySymbols } from "@dxos/keyboard";
|
|
23
|
+
import { useGraph } from "@dxos/plugin-graph";
|
|
24
|
+
import { Button, Dialog, useTranslation, toLocalizedString } from "@dxos/react-ui";
|
|
25
|
+
import { SearchList } from "@dxos/react-ui-searchlist";
|
|
26
|
+
import { descriptionText, getSize, mx } from "@dxos/react-ui-theme";
|
|
27
|
+
import { getHostPlatform } from "@dxos/util";
|
|
28
|
+
var CommandsDialogContent = ({ selected: initial }) => {
|
|
29
|
+
const { t } = useTranslation(NAVTREE_PLUGIN);
|
|
30
|
+
const [selected, setSelected] = useState(initial);
|
|
31
|
+
const dispatch = useIntentDispatcher();
|
|
32
|
+
const { graph } = useGraph();
|
|
33
|
+
const allActions = useMemo(() => {
|
|
34
|
+
const current = Keyboard.singleton.getCurrentContext();
|
|
35
|
+
const actionMap = /* @__PURE__ */ new Set();
|
|
36
|
+
const actions2 = [];
|
|
37
|
+
graph?.traverse({
|
|
38
|
+
visitor: (node, path) => {
|
|
39
|
+
if ((isAction(node) || isActionGroup(node)) && !actionMap.has(node.id) && current.startsWith(path.slice(0, -1).join("/"))) {
|
|
40
|
+
actionMap.add(node.id);
|
|
41
|
+
actions2.push(node);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
actions2.sort((a, b) => {
|
|
46
|
+
return toLocalizedString(a.properties.label, t)?.toLowerCase().localeCompare(toLocalizedString(b.properties.label, t)?.toLowerCase());
|
|
47
|
+
});
|
|
48
|
+
return actions2;
|
|
49
|
+
}, [
|
|
50
|
+
graph
|
|
51
|
+
]);
|
|
52
|
+
const group = allActions.find(({ id }) => id === selected);
|
|
53
|
+
const actions = isActionGroup(group) ? graph.actions(group) : allActions;
|
|
54
|
+
return /* @__PURE__ */ React.createElement(Dialog.Content, {
|
|
55
|
+
classNames: [
|
|
56
|
+
"md:max-is-[30rem] overflow-hidden mbs-12"
|
|
57
|
+
]
|
|
58
|
+
}, /* @__PURE__ */ React.createElement(Dialog.Title, null, t("commands dialog title", {
|
|
59
|
+
ns: NAVTREE_PLUGIN
|
|
60
|
+
})), /* @__PURE__ */ React.createElement(SearchList.Root, {
|
|
61
|
+
label: t("command list input placeholder"),
|
|
62
|
+
classNames: "flex flex-col grow overflow-hidden my-2"
|
|
63
|
+
}, /* @__PURE__ */ React.createElement(SearchList.Input, {
|
|
64
|
+
placeholder: t("command list input placeholder"),
|
|
65
|
+
classNames: "px-1 my-2"
|
|
66
|
+
}), /* @__PURE__ */ React.createElement(SearchList.Content, {
|
|
67
|
+
classNames: "max-bs-[24rem] overflow-auto"
|
|
68
|
+
}, actions?.map((action) => {
|
|
69
|
+
const label = toLocalizedString(action.properties.label, t);
|
|
70
|
+
const shortcut = typeof action.properties.keyBinding === "string" ? action.properties.keyBinding : action.properties.keyBinding?.[getHostPlatform()];
|
|
71
|
+
const Icon = action.properties.icon ?? DotOutline;
|
|
72
|
+
return /* @__PURE__ */ React.createElement(SearchList.Item, {
|
|
73
|
+
value: label,
|
|
74
|
+
key: action.id,
|
|
75
|
+
onSelect: () => {
|
|
76
|
+
if (action.properties.disabled) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (isActionGroup(action)) {
|
|
80
|
+
setSelected(action.id);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
void dispatch({
|
|
84
|
+
action: LayoutAction.SET_LAYOUT,
|
|
85
|
+
data: {
|
|
86
|
+
element: "dialog",
|
|
87
|
+
state: false
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
const node = graph.nodes(group ?? action, {
|
|
92
|
+
relation: "inbound"
|
|
93
|
+
})[0];
|
|
94
|
+
void (node && isAction(action) && action.data({
|
|
95
|
+
node,
|
|
96
|
+
caller: KEY_BINDING
|
|
97
|
+
}));
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
classNames: "flex items-center gap-2",
|
|
101
|
+
disabled: action.properties.disabled,
|
|
102
|
+
...action.properties?.testId && {
|
|
103
|
+
"data-testid": action.properties.testId
|
|
104
|
+
}
|
|
105
|
+
}, /* @__PURE__ */ React.createElement(Icon, {
|
|
106
|
+
className: mx(getSize(4), "shrink-0", !action.properties.icon && "invisible")
|
|
107
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
108
|
+
className: "grow truncate"
|
|
109
|
+
}, label), shortcut && /* @__PURE__ */ React.createElement("span", {
|
|
110
|
+
className: mx("shrink-0", descriptionText)
|
|
111
|
+
}, keySymbols(shortcut).join("")));
|
|
112
|
+
}))), /* @__PURE__ */ React.createElement(Dialog.Close, {
|
|
113
|
+
asChild: true
|
|
114
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
115
|
+
variant: "primary",
|
|
116
|
+
classNames: "mbs-2"
|
|
117
|
+
}, t("close label", {
|
|
118
|
+
ns: "os"
|
|
119
|
+
}))));
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// packages/plugins/plugin-navtree/src/components/NavBarStart.tsx
|
|
123
|
+
import { DotsThreeVertical } from "@phosphor-icons/react";
|
|
124
|
+
import React2, { Fragment } from "react";
|
|
125
|
+
import { getGraph } from "@dxos/app-graph";
|
|
126
|
+
import { Popover, toLocalizedString as toLocalizedString2, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
127
|
+
import { PlankHeading } from "@dxos/react-ui-deck";
|
|
128
|
+
var TREE_ITEM_MAIN_HEADING = "TreeItemMainHeading";
|
|
129
|
+
var NavBarStart = ({ activeNode, popoverAnchorId }) => {
|
|
130
|
+
const { t } = useTranslation2(NAVTREE_PLUGIN);
|
|
131
|
+
const ActionRoot = popoverAnchorId === `dxos.org/ui/${TREE_ITEM_MAIN_HEADING}/${activeNode.id}` || popoverAnchorId === `dxos.org/ui/${KEY_BINDING}/${activeNode.id}` ? Popover.Anchor : Fragment;
|
|
132
|
+
const Icon = activeNode.properties?.icon ?? DotsThreeVertical;
|
|
133
|
+
const graph = getGraph(activeNode);
|
|
134
|
+
const actions = graph.actions(activeNode);
|
|
135
|
+
const label = toLocalizedString2(activeNode.properties?.label, t);
|
|
136
|
+
const menuTriggerLabel = t("node actions menu invoker label");
|
|
137
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ActionRoot, null, /* @__PURE__ */ React2.createElement(PlankHeading.ActionsMenu, {
|
|
138
|
+
Icon,
|
|
139
|
+
attendableId: activeNode.id,
|
|
140
|
+
triggerLabel: menuTriggerLabel,
|
|
141
|
+
actions,
|
|
142
|
+
onAction: (action) => typeof action.data === "function" && action.data({
|
|
143
|
+
node: action,
|
|
144
|
+
caller: TREE_ITEM_MAIN_HEADING
|
|
145
|
+
})
|
|
146
|
+
})), /* @__PURE__ */ React2.createElement(PlankHeading.Label, {
|
|
147
|
+
attendableId: activeNode.id
|
|
148
|
+
}, label));
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
|
|
152
|
+
import React4, { useCallback, useMemo as useMemo2 } from "react";
|
|
153
|
+
import { NavigationAction, LayoutAction as LayoutAction2, Surface, SLUG_PATH_SEPARATOR, SLUG_COLLECTION_INDICATOR, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
|
|
154
|
+
import { getGraph as getGraph2, isAction as isAction3, isActionLike } from "@dxos/app-graph";
|
|
155
|
+
import { ElevationProvider, useMediaQuery, useSidebars as useSidebars2 } from "@dxos/react-ui";
|
|
156
|
+
import { Path as Path2 } from "@dxos/react-ui-mosaic";
|
|
157
|
+
import { NavTree, getLevel } from "@dxos/react-ui-navtree";
|
|
158
|
+
import { arrayMove } from "@dxos/util";
|
|
159
|
+
|
|
160
|
+
// packages/plugins/plugin-navtree/src/components/NavTreeFooter.tsx
|
|
161
|
+
import { ArrowSquareOut, GearSix, Warning } from "@phosphor-icons/react";
|
|
162
|
+
import { formatDistance } from "date-fns/formatDistance";
|
|
163
|
+
import React3 from "react";
|
|
164
|
+
import { SettingsAction, useResolvePlugin, parseNavigationPlugin, useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
|
|
165
|
+
import { useConfig } from "@dxos/react-client";
|
|
166
|
+
import { Button as Button2, Tooltip, Popover as Popover2, useSidebars, useTranslation as useTranslation3, Link, Message, Trans, useDefaultValue } from "@dxos/react-ui";
|
|
167
|
+
import { PlankHeading as PlankHeading2 } from "@dxos/react-ui-deck";
|
|
168
|
+
import { getSize as getSize2, mx as mx2 } from "@dxos/react-ui-theme";
|
|
169
|
+
var buttonStyles = "pli-1.5 text-xs font-normal";
|
|
170
|
+
var repo = "https://github.com/dxos/dxos";
|
|
171
|
+
var NavTreeFooter = (props) => {
|
|
172
|
+
const layoutPart = useDefaultValue(props.layoutPart, "sidebar");
|
|
173
|
+
const config = useConfig();
|
|
174
|
+
const { t } = useTranslation3(NAVTREE_PLUGIN);
|
|
175
|
+
const { navigationSidebarOpen } = useSidebars(NAVTREE_PLUGIN);
|
|
176
|
+
const dispatch = useIntentDispatcher2();
|
|
177
|
+
const { version, timestamp, commitHash } = config.values.runtime?.app?.build ?? {};
|
|
178
|
+
const navigationPlugin = useResolvePlugin(parseNavigationPlugin);
|
|
179
|
+
const releaseUrl = config.values.runtime?.app?.env?.DX_ENVIRONMENT === "production" ? `${repo}/releases/tag/v${version}` : `${repo}/commit/${commitHash}`;
|
|
180
|
+
const previewUrl = "https://docs.dxos.org/composer#technology-preview";
|
|
181
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
182
|
+
role: "none",
|
|
183
|
+
className: mx2("bs-[--rail-size] pbe-[env(safe-area-inset-bottom)] box-content separator-separator border-bs pli-1 flex justify-end", layoutPart === "complementary" && "md:justify-end flex-row-reverse")
|
|
184
|
+
}, /* @__PURE__ */ React3.createElement(Popover2.Root, null, /* @__PURE__ */ React3.createElement(Popover2.Trigger, {
|
|
185
|
+
asChild: true
|
|
186
|
+
}, /* @__PURE__ */ React3.createElement(Button2, {
|
|
187
|
+
variant: "ghost",
|
|
188
|
+
classNames: buttonStyles,
|
|
189
|
+
...!navigationSidebarOpen && {
|
|
190
|
+
tabIndex: -1
|
|
191
|
+
}
|
|
192
|
+
}, "v", version)), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
|
|
193
|
+
side: "top",
|
|
194
|
+
role: "message",
|
|
195
|
+
classNames: "z-[12] bg-warning-500 max-is-[min(calc(100vw-16px),40ch)]"
|
|
196
|
+
}, /* @__PURE__ */ React3.createElement(Message.Root, {
|
|
197
|
+
valence: "warning",
|
|
198
|
+
className: "rounded-be-none p-5"
|
|
199
|
+
}, /* @__PURE__ */ React3.createElement(Message.Title, null, /* @__PURE__ */ React3.createElement(Warning, {
|
|
200
|
+
weight: "duotone",
|
|
201
|
+
className: "inline mie-2 is-6 bs-6"
|
|
202
|
+
}), /* @__PURE__ */ React3.createElement("span", null, t("warning title"))), /* @__PURE__ */ React3.createElement(Message.Body, null, t("technology preview message"), /* @__PURE__ */ React3.createElement("br", null), /* @__PURE__ */ React3.createElement(Link, {
|
|
203
|
+
href: previewUrl,
|
|
204
|
+
target: "_blank",
|
|
205
|
+
rel: "noreferrer",
|
|
206
|
+
variant: "neutral"
|
|
207
|
+
}, t("learn more label"), /* @__PURE__ */ React3.createElement(ArrowSquareOut, {
|
|
208
|
+
className: "inline mis-1",
|
|
209
|
+
weight: "bold"
|
|
210
|
+
})))), /* @__PURE__ */ React3.createElement("div", {
|
|
211
|
+
role: "none",
|
|
212
|
+
className: "plb-4 pli-5 space-b-2 text-base"
|
|
213
|
+
}, timestamp && /* @__PURE__ */ React3.createElement("p", null, t("released message", {
|
|
214
|
+
released: formatDistance(new Date(timestamp), /* @__PURE__ */ new Date(), {
|
|
215
|
+
addSuffix: true
|
|
216
|
+
})
|
|
217
|
+
}), /* @__PURE__ */ React3.createElement("br", null), /* @__PURE__ */ React3.createElement(Link, {
|
|
218
|
+
href: releaseUrl,
|
|
219
|
+
target: "_blank",
|
|
220
|
+
rel: "noreferrer",
|
|
221
|
+
variant: "neutral"
|
|
222
|
+
}, t("see release label"), /* @__PURE__ */ React3.createElement(ArrowSquareOut, {
|
|
223
|
+
className: "inline mis-1",
|
|
224
|
+
weight: "bold"
|
|
225
|
+
}))), /* @__PURE__ */ React3.createElement("p", null, /* @__PURE__ */ React3.createElement(Trans, {
|
|
226
|
+
t,
|
|
227
|
+
i18nKey: "powered by dxos message",
|
|
228
|
+
components: {
|
|
229
|
+
dxos: /* @__PURE__ */ React3.createElement(Link, {
|
|
230
|
+
href: "https://dxos.org",
|
|
231
|
+
target: "_blank",
|
|
232
|
+
rel: "noreferrer",
|
|
233
|
+
variant: "neutral"
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
}))), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
237
|
+
asChild: true
|
|
238
|
+
}, /* @__PURE__ */ React3.createElement(Button2, {
|
|
239
|
+
variant: "ghost",
|
|
240
|
+
classNames: buttonStyles,
|
|
241
|
+
"data-testid": "treeView.openSettings",
|
|
242
|
+
"data-joyride": "welcome/settings",
|
|
243
|
+
...!navigationSidebarOpen && {
|
|
244
|
+
tabIndex: -1
|
|
245
|
+
},
|
|
246
|
+
onClick: () => dispatch({
|
|
247
|
+
action: SettingsAction.OPEN
|
|
248
|
+
})
|
|
249
|
+
}, /* @__PURE__ */ React3.createElement("span", {
|
|
250
|
+
className: "sr-only"
|
|
251
|
+
}, t("open settings label")), /* @__PURE__ */ React3.createElement(GearSix, {
|
|
252
|
+
className: mx2(getSize2(4), "rotate-90")
|
|
253
|
+
}))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, {
|
|
254
|
+
classNames: "z-[12]"
|
|
255
|
+
}, t("open settings label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null)))), navigationPlugin?.meta.id === "dxos.org/plugin/deck" && /* @__PURE__ */ React3.createElement(PlankHeading2.Controls, {
|
|
256
|
+
variant: "hide-disabled",
|
|
257
|
+
capabilities: {
|
|
258
|
+
incrementStart: false,
|
|
259
|
+
incrementEnd: false
|
|
260
|
+
},
|
|
261
|
+
onClick: (_type) => {
|
|
262
|
+
}
|
|
263
|
+
}));
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// packages/plugins/plugin-navtree/src/util.ts
|
|
267
|
+
import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction2 } from "@dxos/app-graph";
|
|
268
|
+
import { Path } from "@dxos/react-ui-mosaic";
|
|
269
|
+
import { nonNullable } from "@dxos/util";
|
|
270
|
+
var getParent = (graph, node, path) => {
|
|
271
|
+
const parentId = path[path.length - 2];
|
|
272
|
+
return graph.nodes(node, {
|
|
273
|
+
relation: "inbound"
|
|
274
|
+
}).find((n) => n.id === parentId);
|
|
275
|
+
};
|
|
276
|
+
var getPersistenceParent = (graph, node, path, persistenceClass) => {
|
|
277
|
+
if (node.properties.acceptPersistenceClass?.has(persistenceClass)) {
|
|
278
|
+
return node;
|
|
279
|
+
} else {
|
|
280
|
+
const parent = getParent(graph, node, path);
|
|
281
|
+
return parent ? getPersistenceParent(graph, parent, path.slice(0, path.length - 1), persistenceClass) : null;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
var resolveMigrationOperation = (graph, activeNode, destinationPath, destinationRelatedNode) => {
|
|
285
|
+
const activeClass = activeNode.properties.persistenceClass;
|
|
286
|
+
if (destinationRelatedNode && activeClass) {
|
|
287
|
+
const persistenceParent = getPersistenceParent(graph, destinationRelatedNode, destinationPath, activeClass);
|
|
288
|
+
if (persistenceParent) {
|
|
289
|
+
const activeKey = activeNode.properties.persistenceKey;
|
|
290
|
+
if (activeKey && persistenceParent?.properties.acceptPersistenceKey) {
|
|
291
|
+
return persistenceParent.properties.acceptPersistenceKey.has(activeKey) && destinationRelatedNode.properties.onTransferStart ? "transfer" : destinationRelatedNode.properties.onCopy ? "copy" : "reject";
|
|
292
|
+
} else {
|
|
293
|
+
return "reject";
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
return "reject";
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
return "reject";
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
var sortActions = (actions) => actions.sort((a, b) => {
|
|
303
|
+
if (a.properties.disposition === b.properties.disposition) {
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
if (a.properties.disposition === "toolbar") {
|
|
307
|
+
return -1;
|
|
308
|
+
}
|
|
309
|
+
return 1;
|
|
310
|
+
});
|
|
311
|
+
var getTreeItemNode = (treeItems, path) => {
|
|
312
|
+
if (!path) {
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
return treeItems.find((treeItem) => {
|
|
316
|
+
return treeItem.path && !treeItem.path.find((id, index) => path[index] !== id);
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
var getChildren = (graph, node, filter, path = []) => {
|
|
320
|
+
return graph.nodes(node, {
|
|
321
|
+
relation: "outbound",
|
|
322
|
+
filter
|
|
323
|
+
}).map((n) => {
|
|
324
|
+
const nextPath = [
|
|
325
|
+
...path,
|
|
326
|
+
node.id
|
|
327
|
+
];
|
|
328
|
+
return nextPath.includes(n.id) ? void 0 : n;
|
|
329
|
+
}).filter(nonNullable);
|
|
330
|
+
};
|
|
331
|
+
var getActions = (graph, node) => {
|
|
332
|
+
return graph.actions(node).reduce((acc, arg) => {
|
|
333
|
+
acc.actions.push(arg);
|
|
334
|
+
if (!isAction2(arg)) {
|
|
335
|
+
const actionGroup = graph.actions(arg);
|
|
336
|
+
acc.groupedActions[arg.id] = actionGroup;
|
|
337
|
+
}
|
|
338
|
+
return acc;
|
|
339
|
+
}, {
|
|
340
|
+
actions: [],
|
|
341
|
+
groupedActions: {}
|
|
342
|
+
});
|
|
343
|
+
};
|
|
344
|
+
var expandChildrenAndActions = (graph, node) => {
|
|
345
|
+
return Promise.all([
|
|
346
|
+
expandChildren(graph, node),
|
|
347
|
+
expandActions(graph, node)
|
|
348
|
+
]);
|
|
349
|
+
};
|
|
350
|
+
var expandChildren = (graph, node) => {
|
|
351
|
+
return graph.expand(node, "outbound");
|
|
352
|
+
};
|
|
353
|
+
var expandActions = (graph, node) => {
|
|
354
|
+
return Promise.all([
|
|
355
|
+
graph.expand(node, "outbound", ACTION_TYPE),
|
|
356
|
+
graph.expand(node, "outbound", ACTION_GROUP_TYPE)
|
|
357
|
+
]);
|
|
358
|
+
};
|
|
359
|
+
function* navTreeItemVisitor(graph, node, openItemIds, path = [], filter) {
|
|
360
|
+
const l0Children = getChildren(graph, node, filter, path);
|
|
361
|
+
const { actions: l0Actions, groupedActions: l0GroupedActions } = getActions(graph, node);
|
|
362
|
+
const stack = [
|
|
363
|
+
{
|
|
364
|
+
id: node.id,
|
|
365
|
+
node,
|
|
366
|
+
path: [],
|
|
367
|
+
parentOf: (l0Children ?? []).map(({ id }) => id),
|
|
368
|
+
actions: l0Actions,
|
|
369
|
+
groupedActions: l0GroupedActions
|
|
370
|
+
}
|
|
371
|
+
];
|
|
372
|
+
while (stack.length > 0) {
|
|
373
|
+
const nextItem = stack.pop();
|
|
374
|
+
if ((nextItem.path?.length ?? 0) > 0) {
|
|
375
|
+
yield nextItem;
|
|
376
|
+
}
|
|
377
|
+
const { id, node: node2, path: path2 } = nextItem;
|
|
378
|
+
const children = getChildren(graph, node2, filter, path2);
|
|
379
|
+
if (path2?.length === 0 || (id ?? "never") in openItemIds) {
|
|
380
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
381
|
+
const child = children[i];
|
|
382
|
+
const childPath = path2 ? [
|
|
383
|
+
...path2,
|
|
384
|
+
child.id
|
|
385
|
+
] : [
|
|
386
|
+
child.id
|
|
387
|
+
];
|
|
388
|
+
const childChildren = getChildren(graph, child, filter, childPath);
|
|
389
|
+
const { actions: childActions, groupedActions: childGroupedActions } = getActions(graph, child);
|
|
390
|
+
stack.push({
|
|
391
|
+
id: Path.create(...childPath),
|
|
392
|
+
node: child,
|
|
393
|
+
path: childPath,
|
|
394
|
+
...(childChildren?.length ?? 0) > 0 && {
|
|
395
|
+
parentOf: childChildren.map(({ id: id2 }) => Path.create(...childPath, id2))
|
|
396
|
+
},
|
|
397
|
+
actions: childActions,
|
|
398
|
+
groupedActions: childGroupedActions
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
var treeItemsFromRootNode = (graph, rootNode, openItemIds, path = [], filter) => {
|
|
405
|
+
return Array.from(navTreeItemVisitor(graph, rootNode, openItemIds, path, filter));
|
|
406
|
+
};
|
|
407
|
+
var expandOpenGraphNodes = (graph, openItemIds) => {
|
|
408
|
+
return Promise.all(Object.keys(openItemIds).map((openItemId) => {
|
|
409
|
+
const node = graph.findNode(Path.last(openItemId));
|
|
410
|
+
return node && expandChildrenAndActions(graph, node);
|
|
411
|
+
}).filter(nonNullable));
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
|
|
415
|
+
var NODE_TYPE = "dxos/app-graph/node";
|
|
416
|
+
var renderPresence = (node) => /* @__PURE__ */ React4.createElement(Surface, {
|
|
417
|
+
role: "presence--glyph",
|
|
418
|
+
data: {
|
|
419
|
+
object: node.data
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
var NavTreeContainer = ({ root, activeIds, openItemIds, onOpenItemIdsChange, attended, popoverAnchorId }) => {
|
|
423
|
+
const { closeNavigationSidebar } = useSidebars2(NAVTREE_PLUGIN);
|
|
424
|
+
const [isLg] = useMediaQuery("lg", {
|
|
425
|
+
ssr: false
|
|
426
|
+
});
|
|
427
|
+
const dispatch = useIntentDispatcher3();
|
|
428
|
+
const graph = useMemo2(() => getGraph2(root), [
|
|
429
|
+
root
|
|
430
|
+
]);
|
|
431
|
+
const items = treeItemsFromRootNode(graph, root, openItemIds);
|
|
432
|
+
const loadDescendents = useCallback((node) => {
|
|
433
|
+
void expandActions(graph, node);
|
|
434
|
+
if (!isActionLike(node)) {
|
|
435
|
+
void expandChildren(graph, node).then(() => (
|
|
436
|
+
// Load one level deeper, which resolves some juddering observed on open/close.
|
|
437
|
+
Promise.all(getChildren(graph, node).flatMap((child) => [
|
|
438
|
+
expandActions(graph, child),
|
|
439
|
+
expandChildren(graph, child)
|
|
440
|
+
]))
|
|
441
|
+
));
|
|
442
|
+
}
|
|
443
|
+
}, [
|
|
444
|
+
graph
|
|
445
|
+
]);
|
|
446
|
+
const handleNavigate = async ({ node, actions }) => {
|
|
447
|
+
if (!node.data) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
await dispatch({
|
|
451
|
+
action: NavigationAction.OPEN,
|
|
452
|
+
data: {
|
|
453
|
+
activeParts: node.data?.comments ? {
|
|
454
|
+
main: [
|
|
455
|
+
node.id
|
|
456
|
+
],
|
|
457
|
+
complementary: [
|
|
458
|
+
`${node.id}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
|
|
459
|
+
]
|
|
460
|
+
} : {
|
|
461
|
+
main: [
|
|
462
|
+
node.id
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
await dispatch({
|
|
468
|
+
action: LayoutAction2.SCROLL_INTO_VIEW,
|
|
469
|
+
data: {
|
|
470
|
+
id: node.id
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
const defaultAction = actions?.find((action) => action.properties?.disposition === "default");
|
|
474
|
+
if (isAction3(defaultAction)) {
|
|
475
|
+
void defaultAction.data();
|
|
476
|
+
}
|
|
477
|
+
!isLg && closeNavigationSidebar();
|
|
478
|
+
};
|
|
479
|
+
const handleItemOpenChange = ({ id, actions, path }, nextOpen) => {
|
|
480
|
+
if (path) {
|
|
481
|
+
if (nextOpen) {
|
|
482
|
+
onOpenItemIdsChange({
|
|
483
|
+
...openItemIds,
|
|
484
|
+
[id]: true
|
|
485
|
+
});
|
|
486
|
+
} else {
|
|
487
|
+
const { [id]: _, ...nextOpenItemIds } = openItemIds;
|
|
488
|
+
onOpenItemIdsChange(nextOpenItemIds);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const defaultAction = actions?.find((action) => action.properties?.disposition === "default");
|
|
492
|
+
if (isAction3(defaultAction)) {
|
|
493
|
+
void defaultAction.data();
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
const resolveItemLevel = useCallback((overPosition, activeId, levelOffset) => {
|
|
497
|
+
if (!(typeof overPosition === "number" && activeId)) {
|
|
498
|
+
return 1;
|
|
499
|
+
} else {
|
|
500
|
+
const nextItems = arrayMove(items, items.findIndex(({ id }) => id === activeId), overPosition);
|
|
501
|
+
const previousItem = nextItems[overPosition - 1];
|
|
502
|
+
const nextItem = nextItems[overPosition + 1];
|
|
503
|
+
return Math.min(previousItem ? getLevel(previousItem?.path) + 1 : 1, Math.max(nextItem ? getLevel(nextItem?.path) : 1, getLevel(nextItems[overPosition].path) + levelOffset));
|
|
504
|
+
}
|
|
505
|
+
}, [
|
|
506
|
+
items
|
|
507
|
+
]);
|
|
508
|
+
const handleMove = useCallback(({ active, over, details }) => {
|
|
509
|
+
const levelOffset = Math.floor((details?.delta?.x ?? 0) / 16);
|
|
510
|
+
const overPosition = over.position ?? 0;
|
|
511
|
+
const nextItems = arrayMove(items, items.findIndex(({ id }) => id === active.item.id), overPosition);
|
|
512
|
+
const previousItem = nextItems[overPosition - 1];
|
|
513
|
+
const nextItem = nextItems[overPosition + 1];
|
|
514
|
+
const activeNode = "node" in active.item ? active.item.node : void 0;
|
|
515
|
+
if (!activeNode || !previousItem || !previousItem.path) {
|
|
516
|
+
return {
|
|
517
|
+
operation: "reject",
|
|
518
|
+
details: {
|
|
519
|
+
levelOffset
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const overLevel = resolveItemLevel(overPosition, active.item.id, levelOffset);
|
|
524
|
+
const previousLevel = getLevel(previousItem.path);
|
|
525
|
+
if (previousLevel === overLevel - 1) {
|
|
526
|
+
if (Path2.hasChild(previousItem.id, active.item.id)) {
|
|
527
|
+
const operation = previousItem.node.properties.onRearrangeChildren ? "rearrange" : "reject";
|
|
528
|
+
return {
|
|
529
|
+
operation,
|
|
530
|
+
details: {
|
|
531
|
+
levelOffset
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
} else {
|
|
535
|
+
const operation = resolveMigrationOperation(graph, activeNode, previousItem.path, previousItem.node);
|
|
536
|
+
return {
|
|
537
|
+
operation,
|
|
538
|
+
details: {
|
|
539
|
+
levelOffset
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
} else if (previousLevel === overLevel) {
|
|
544
|
+
const parent = getParent(graph, previousItem.node, previousItem.path);
|
|
545
|
+
const parentPath = previousItem.path.slice(0, previousItem.path.length - 1);
|
|
546
|
+
if (Path2.siblings(previousItem.id, active.item.id)) {
|
|
547
|
+
const operation = parent?.properties.onRearrangeChildren ? "rearrange" : "reject";
|
|
548
|
+
return {
|
|
549
|
+
operation,
|
|
550
|
+
details: {
|
|
551
|
+
levelOffset
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
} else {
|
|
555
|
+
const operation = resolveMigrationOperation(graph, activeNode, parentPath, parent);
|
|
556
|
+
return {
|
|
557
|
+
operation,
|
|
558
|
+
details: {
|
|
559
|
+
levelOffset
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
} else if (nextItem && nextItem.path) {
|
|
564
|
+
const nextLevel = getLevel(nextItem.path);
|
|
565
|
+
if (nextLevel === overLevel) {
|
|
566
|
+
const parent = getParent(graph, nextItem.node, nextItem.path);
|
|
567
|
+
const parentPath = nextItem.path.slice(0, nextItem.path.length - 1);
|
|
568
|
+
if (Path2.siblings(nextItem.id, active.item.id)) {
|
|
569
|
+
const operation = parent?.properties.onRearrangeChildren ? "rearrange" : "reject";
|
|
570
|
+
return {
|
|
571
|
+
operation,
|
|
572
|
+
details: {
|
|
573
|
+
levelOffset
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
} else {
|
|
577
|
+
const operation = resolveMigrationOperation(graph, activeNode, parentPath, parent);
|
|
578
|
+
return {
|
|
579
|
+
operation,
|
|
580
|
+
details: {
|
|
581
|
+
levelOffset
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
return {
|
|
587
|
+
operation: "reject",
|
|
588
|
+
details: {
|
|
589
|
+
levelOffset
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
return {
|
|
595
|
+
operation: "reject",
|
|
596
|
+
details: {
|
|
597
|
+
levelOffset
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}, [
|
|
602
|
+
root,
|
|
603
|
+
items
|
|
604
|
+
]);
|
|
605
|
+
const handleDrop = useCallback(({ operation, active, over, details = {} }) => {
|
|
606
|
+
if (Path2.first(over.path) !== root.id) {
|
|
607
|
+
return void 0;
|
|
608
|
+
}
|
|
609
|
+
const { levelOffset = 0 } = details;
|
|
610
|
+
const overPosition = over.position ?? 0;
|
|
611
|
+
const nextItems = arrayMove(items, items.findIndex(({ id }) => id === active.item.id), overPosition);
|
|
612
|
+
const activeNode = "node" in active.item ? active.item.node : void 0;
|
|
613
|
+
const activeParentId = Path2.parent(active.item.id);
|
|
614
|
+
if (!activeNode) {
|
|
615
|
+
return void 0;
|
|
616
|
+
}
|
|
617
|
+
const activeParent = getParent(graph, activeNode, active.item.path ?? []);
|
|
618
|
+
if (operation === "rearrange") {
|
|
619
|
+
void activeParent?.properties.onRearrangeChildren?.(nextItems.filter(({ id }) => Path2.hasChild(activeParentId, id)).map(({ node }) => node.data));
|
|
620
|
+
return null;
|
|
621
|
+
} else {
|
|
622
|
+
const previousItem = nextItems[overPosition - 1];
|
|
623
|
+
const nextItem = nextItems[overPosition + 1];
|
|
624
|
+
const overLevel = resolveItemLevel(overPosition, active.item.id, levelOffset);
|
|
625
|
+
const previousLevel = getLevel(previousItem.path);
|
|
626
|
+
if (operation === "copy") {
|
|
627
|
+
if (previousLevel === overLevel - 1) {
|
|
628
|
+
void previousItem.node.properties.onCopy?.(activeNode, 0);
|
|
629
|
+
return null;
|
|
630
|
+
} else if (previousLevel === overLevel) {
|
|
631
|
+
const parent = getParent(graph, previousItem.node, previousItem.path ?? []);
|
|
632
|
+
void parent?.properties.onCopy?.(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === previousItem.node.id) + 1);
|
|
633
|
+
return null;
|
|
634
|
+
} else if (nextItem && nextItem.path) {
|
|
635
|
+
const parent = getParent(graph, nextItem.node, nextItem.path ?? []);
|
|
636
|
+
void parent?.properties.onCopy?.(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === nextItem.node.id));
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
} else if (operation === "transfer") {
|
|
640
|
+
const onTransferEnd = activeParent?.properties.onTransferEnd;
|
|
641
|
+
if (!onTransferEnd) {
|
|
642
|
+
return void 0;
|
|
643
|
+
} else if (previousLevel === overLevel - 1) {
|
|
644
|
+
const onTransferStart = previousItem.node.properties.onTransferStart;
|
|
645
|
+
if (onTransferStart) {
|
|
646
|
+
void onTransferEnd(activeNode, previousItem.node);
|
|
647
|
+
void onTransferStart(activeNode, 0);
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
} else if (previousLevel === overLevel && previousItem.path) {
|
|
651
|
+
const parent = getParent(graph, previousItem.node, previousItem.path);
|
|
652
|
+
if (parent?.properties.onTransferStart) {
|
|
653
|
+
void onTransferEnd(activeNode, previousItem.node);
|
|
654
|
+
void parent.properties.onTransferStart(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === previousItem.node.id) + 1);
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
} else if (nextItem && nextItem.path) {
|
|
658
|
+
const parent = getParent(graph, nextItem.node, nextItem.path);
|
|
659
|
+
if (parent?.properties.onTransferStart) {
|
|
660
|
+
void onTransferEnd(activeNode, previousItem.node);
|
|
661
|
+
void parent.properties.onTransferStart(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === nextItem.node.id));
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return void 0;
|
|
668
|
+
}, [
|
|
669
|
+
root,
|
|
670
|
+
items
|
|
671
|
+
]);
|
|
672
|
+
const handleDragEnd = useCallback(() => {
|
|
673
|
+
onOpenItemIdsChange({
|
|
674
|
+
...openItemIds
|
|
675
|
+
});
|
|
676
|
+
}, [
|
|
677
|
+
onOpenItemIdsChange,
|
|
678
|
+
openItemIds
|
|
679
|
+
]);
|
|
680
|
+
return /* @__PURE__ */ React4.createElement(ElevationProvider, {
|
|
681
|
+
elevation: "chrome"
|
|
682
|
+
}, /* @__PURE__ */ React4.createElement("div", {
|
|
683
|
+
role: "none",
|
|
684
|
+
className: "bs-full overflow-hidden row-span-3 grid grid-cols-1 grid-rows-[min-content_1fr_min-content]"
|
|
685
|
+
}, /* @__PURE__ */ React4.createElement(Surface, {
|
|
686
|
+
role: "search-input",
|
|
687
|
+
limit: 1
|
|
688
|
+
}), /* @__PURE__ */ React4.createElement("div", {
|
|
689
|
+
role: "none",
|
|
690
|
+
className: "!overflow-y-auto"
|
|
691
|
+
}, /* @__PURE__ */ React4.createElement(NavTree, {
|
|
692
|
+
id: root.id,
|
|
693
|
+
items,
|
|
694
|
+
current: activeIds,
|
|
695
|
+
attended,
|
|
696
|
+
type: NODE_TYPE,
|
|
697
|
+
onNavigate: handleNavigate,
|
|
698
|
+
onItemOpenChange: handleItemOpenChange,
|
|
699
|
+
open: openItemIds,
|
|
700
|
+
onMove: handleMove,
|
|
701
|
+
onDrop: handleDrop,
|
|
702
|
+
onDragEnd: handleDragEnd,
|
|
703
|
+
popoverAnchorId,
|
|
704
|
+
renderPresence,
|
|
705
|
+
resolveItemLevel,
|
|
706
|
+
loadDescendents
|
|
707
|
+
})), /* @__PURE__ */ React4.createElement(NavTreeFooter, null)));
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// packages/plugins/plugin-navtree/src/components/NavTreeDocumentTitle.tsx
|
|
711
|
+
import { useEffect } from "react";
|
|
712
|
+
import { toLocalizedString as toLocalizedString3, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
713
|
+
var NavTreeDocumentTitle = ({ node }) => {
|
|
714
|
+
const { t } = useTranslation4(NAVTREE_PLUGIN);
|
|
715
|
+
useEffect(() => {
|
|
716
|
+
document.title = node ? toLocalizedString3(node.properties.label, t) : t("current app name", {
|
|
717
|
+
ns: "appkit"
|
|
718
|
+
});
|
|
719
|
+
}, [
|
|
720
|
+
node?.properties?.label
|
|
721
|
+
]);
|
|
722
|
+
return null;
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
// packages/plugins/plugin-navtree/src/components/NotchStart.tsx
|
|
726
|
+
import React6 from "react";
|
|
727
|
+
import { useIntentDispatcher as useIntentDispatcher4, useResolvePlugin as useResolvePlugin2 } from "@dxos/app-framework";
|
|
728
|
+
import { ClientAction } from "@dxos/plugin-client/meta";
|
|
729
|
+
import { parseObservabilityPlugin } from "@dxos/plugin-observability";
|
|
730
|
+
import { useIdentity } from "@dxos/react-client/halo";
|
|
731
|
+
|
|
732
|
+
// packages/plugins/plugin-navtree/src/components/HaloButton.tsx
|
|
733
|
+
import React5 from "react";
|
|
734
|
+
import { ConnectionState, useNetworkStatus } from "@dxos/react-client/mesh";
|
|
735
|
+
import { Avatar } from "@dxos/react-ui";
|
|
736
|
+
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
737
|
+
import { hexToFallback } from "@dxos/util";
|
|
738
|
+
var INTERNAL = "https://avatars.githubusercontent.com/u/57182821";
|
|
739
|
+
var HaloButton = (props) => {
|
|
740
|
+
const { onClick, identityKey, internal, size = 8 } = props;
|
|
741
|
+
const fallbackValue = hexToFallback(identityKey ?? "0");
|
|
742
|
+
const { swarm: connectionState } = useNetworkStatus();
|
|
743
|
+
return /* @__PURE__ */ React5.createElement("button", {
|
|
744
|
+
className: mx3(focusRing, "rounded grid place-items-center"),
|
|
745
|
+
onClick
|
|
746
|
+
}, /* @__PURE__ */ React5.createElement(Avatar.Root, {
|
|
747
|
+
size,
|
|
748
|
+
variant: "circle",
|
|
749
|
+
status: connectionState === ConnectionState.OFFLINE ? "error" : internal ? "internal" : "active",
|
|
750
|
+
hue: props.hue || fallbackValue.hue
|
|
751
|
+
}, /* @__PURE__ */ React5.createElement(Avatar.Frame, {
|
|
752
|
+
"data-testid": "treeView.haloButton",
|
|
753
|
+
"data-joyride": "welcome/halo"
|
|
754
|
+
}, internal ? /* @__PURE__ */ React5.createElement(Avatar.Image, {
|
|
755
|
+
href: INTERNAL
|
|
756
|
+
}) : /* @__PURE__ */ React5.createElement(Avatar.Fallback, {
|
|
757
|
+
text: props.emoji || fallbackValue.emoji
|
|
758
|
+
}))));
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
// packages/plugins/plugin-navtree/src/components/NotchStart.tsx
|
|
762
|
+
var NotchStart = () => {
|
|
763
|
+
const identity = useIdentity();
|
|
764
|
+
const observabilityPlugin = useResolvePlugin2(parseObservabilityPlugin);
|
|
765
|
+
const dispatch = useIntentDispatcher4();
|
|
766
|
+
return /* @__PURE__ */ React6.createElement(HaloButton, {
|
|
767
|
+
size: 8,
|
|
768
|
+
identityKey: identity?.identityKey.toHex(),
|
|
769
|
+
hue: identity?.profile?.data?.hue,
|
|
770
|
+
emoji: identity?.profile?.data?.emoji,
|
|
771
|
+
internal: observabilityPlugin?.provides?.observability?.group === "dxos",
|
|
772
|
+
onClick: () => dispatch({
|
|
773
|
+
action: ClientAction.SHARE_IDENTITY
|
|
774
|
+
})
|
|
775
|
+
});
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
// packages/plugins/plugin-navtree/src/components/CommandsTrigger.tsx
|
|
779
|
+
import { MagnifyingGlass } from "@phosphor-icons/react";
|
|
780
|
+
import React7 from "react";
|
|
781
|
+
import { LayoutAction as LayoutAction3, useIntent } from "@dxos/app-framework";
|
|
782
|
+
import { Button as Button3, useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
783
|
+
import { getSize as getSize3 } from "@dxos/react-ui-theme";
|
|
784
|
+
var CommandsTrigger = () => {
|
|
785
|
+
const { dispatch } = useIntent();
|
|
786
|
+
const { t } = useTranslation5(NAVTREE_PLUGIN);
|
|
787
|
+
return /* @__PURE__ */ React7.createElement(Button3, {
|
|
788
|
+
classNames: "pis-3 pie-2 gap-2 mli-1 mbs-1 min-bs-0 bs-[--rail-action] justify-start",
|
|
789
|
+
onClick: () => dispatch({
|
|
790
|
+
action: LayoutAction3.SET_LAYOUT,
|
|
791
|
+
data: {
|
|
792
|
+
element: "dialog",
|
|
793
|
+
component: `${NAVTREE_PLUGIN}/Commands`,
|
|
794
|
+
dialogBlockAlign: "start"
|
|
795
|
+
}
|
|
796
|
+
})
|
|
797
|
+
}, /* @__PURE__ */ React7.createElement("span", {
|
|
798
|
+
className: "fg-description text-base font-normal grow text-start"
|
|
799
|
+
}, t("command list input placeholder")), /* @__PURE__ */ React7.createElement(MagnifyingGlass, {
|
|
800
|
+
className: getSize3(5)
|
|
801
|
+
}));
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
// packages/plugins/plugin-navtree/src/translations.ts
|
|
805
|
+
import { translations as navtreeTranslations } from "@dxos/react-ui-navtree";
|
|
806
|
+
var translations_default = [
|
|
807
|
+
{
|
|
808
|
+
"en-US": {
|
|
809
|
+
[NAVTREE_PLUGIN]: {
|
|
810
|
+
"open settings label": "Settings",
|
|
811
|
+
"open commands label": "Search commands",
|
|
812
|
+
"commands dialog title": "Commands",
|
|
813
|
+
"command list input placeholder": "Search for commands\u2026",
|
|
814
|
+
"node actions menu invoker label": "More options",
|
|
815
|
+
"warning title": "WARNING",
|
|
816
|
+
"technology preview message": "Composer is still in technology preview.",
|
|
817
|
+
"learn more label": "Learn more",
|
|
818
|
+
"released message": "This version released {{released}}.",
|
|
819
|
+
"see release label": "See release on GitHub",
|
|
820
|
+
"powered by dxos message": "Powered by <dxos>DXOS</dxos>"
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
...navtreeTranslations
|
|
825
|
+
];
|
|
826
|
+
|
|
827
|
+
// packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
|
|
828
|
+
var NavTreePlugin = () => {
|
|
829
|
+
const state = new LocalStorageStore("dxos.org/settings/navtree", {
|
|
830
|
+
// TODO(thure): Do this dynamically.
|
|
831
|
+
openItemIds: {
|
|
832
|
+
root: true,
|
|
833
|
+
"dxos.org/plugin/space-spaces": true,
|
|
834
|
+
"dxos.org/plugin/files": true
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
let graphPlugin;
|
|
838
|
+
let graph;
|
|
839
|
+
const handleOpenItemIdsChange = (nextOpenItemIds) => {
|
|
840
|
+
state.values.openItemIds = nextOpenItemIds;
|
|
841
|
+
if (graph) {
|
|
842
|
+
void expandOpenGraphNodes(graph, nextOpenItemIds);
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
return {
|
|
846
|
+
meta: meta_default,
|
|
847
|
+
ready: async (plugins) => {
|
|
848
|
+
graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
|
|
849
|
+
graph = graphPlugin?.provides.graph;
|
|
850
|
+
if (!graph) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
state.values.root = graph.root;
|
|
854
|
+
getChildren(graph, state.values.root);
|
|
855
|
+
getActions(graph, state.values.root);
|
|
856
|
+
state.prop({
|
|
857
|
+
key: "openItemIds",
|
|
858
|
+
storageKey: "openItemIds",
|
|
859
|
+
type: LocalStorageStore.json()
|
|
860
|
+
});
|
|
861
|
+
void expandOpenGraphNodes(graph, state.values.openItemIds);
|
|
862
|
+
graph.subscribeTraverse({
|
|
863
|
+
visitor: (node, path) => {
|
|
864
|
+
let shortcut;
|
|
865
|
+
if (typeof node.properties.keyBinding === "object") {
|
|
866
|
+
const availablePlatforms = Object.keys(node.properties.keyBinding);
|
|
867
|
+
const platform = getHostPlatform2();
|
|
868
|
+
shortcut = availablePlatforms.includes(platform) ? node.properties.keyBinding[platform] : platform === "ios" ? node.properties.keyBinding.macos : platform === "linux" || platform === "unknown" ? node.properties.keyBinding.windows : void 0;
|
|
869
|
+
} else {
|
|
870
|
+
shortcut = node.properties.keyBinding;
|
|
871
|
+
}
|
|
872
|
+
if (shortcut && isAction4(node)) {
|
|
873
|
+
Keyboard2.singleton.getContext(path.slice(0, -1).join("/")).bind({
|
|
874
|
+
shortcut,
|
|
875
|
+
handler: () => {
|
|
876
|
+
void node.data({
|
|
877
|
+
node,
|
|
878
|
+
caller: KEY_BINDING
|
|
879
|
+
});
|
|
880
|
+
},
|
|
881
|
+
data: node.properties.label
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
Keyboard2.singleton.initialize();
|
|
887
|
+
Keyboard2.singleton.setCurrentContext(graphPlugin?.provides.graph.root.id);
|
|
888
|
+
},
|
|
889
|
+
unload: async () => {
|
|
890
|
+
Keyboard2.singleton.destroy();
|
|
891
|
+
},
|
|
892
|
+
provides: {
|
|
893
|
+
metadata: {
|
|
894
|
+
records: {
|
|
895
|
+
[NODE_TYPE]: {
|
|
896
|
+
parse: (item, type) => {
|
|
897
|
+
switch (type) {
|
|
898
|
+
case "node":
|
|
899
|
+
return item.node;
|
|
900
|
+
case "object":
|
|
901
|
+
return item.node.data;
|
|
902
|
+
case "view-object":
|
|
903
|
+
return {
|
|
904
|
+
id: `${item.id}-view`,
|
|
905
|
+
object: item.node.data
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
surface: {
|
|
913
|
+
component: ({ data, role }) => {
|
|
914
|
+
switch (data.component) {
|
|
915
|
+
case `${NAVTREE_PLUGIN}/Commands`: {
|
|
916
|
+
const selected = typeof data.subject === "string" ? data.subject : void 0;
|
|
917
|
+
return /* @__PURE__ */ React8.createElement(CommandsDialogContent, {
|
|
918
|
+
selected
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
switch (role) {
|
|
923
|
+
case "navigation":
|
|
924
|
+
if (state.values.root && state.values.openItemIds) {
|
|
925
|
+
return /* @__PURE__ */ React8.createElement(NavTreeContainer, {
|
|
926
|
+
root: state.values.root,
|
|
927
|
+
activeIds: data.activeIds,
|
|
928
|
+
openItemIds: state.values.openItemIds,
|
|
929
|
+
onOpenItemIdsChange: handleOpenItemIdsChange,
|
|
930
|
+
attended: data.attended,
|
|
931
|
+
popoverAnchorId: data.popoverAnchorId
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
break;
|
|
935
|
+
case "document-title": {
|
|
936
|
+
return /* @__PURE__ */ React8.createElement(NavTreeDocumentTitle, {
|
|
937
|
+
node: isGraphNode(data.activeNode) ? data.activeNode : void 0
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
case "navbar-start": {
|
|
941
|
+
if (state.values.root && data.activeNode) {
|
|
942
|
+
return {
|
|
943
|
+
node: /* @__PURE__ */ React8.createElement(NavBarStart, {
|
|
944
|
+
activeNode: data.activeNode,
|
|
945
|
+
popoverAnchorId: data.popoverAnchorId
|
|
946
|
+
}),
|
|
947
|
+
disposition: "hoist"
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
case "notch-start":
|
|
953
|
+
return /* @__PURE__ */ React8.createElement(NotchStart, null);
|
|
954
|
+
case "search-input":
|
|
955
|
+
return {
|
|
956
|
+
node: /* @__PURE__ */ React8.createElement(CommandsTrigger, null),
|
|
957
|
+
disposition: "fallback"
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
},
|
|
963
|
+
intent: {
|
|
964
|
+
resolver: (intent) => {
|
|
965
|
+
switch (intent.action) {
|
|
966
|
+
case NavigationAction2.EXPOSE: {
|
|
967
|
+
if (graph && intent.data?.id) {
|
|
968
|
+
const path = graph.getPath({
|
|
969
|
+
target: intent.data.id
|
|
970
|
+
});
|
|
971
|
+
if (Array.isArray(path)) {
|
|
972
|
+
const additionalOpenItems = [
|
|
973
|
+
...Array(path.length - 1)
|
|
974
|
+
].reduce((acc, _, index) => {
|
|
975
|
+
const itemId = Path3.create(...path.slice(1, index + 1));
|
|
976
|
+
if (itemId.length > 0) {
|
|
977
|
+
acc[itemId] = true;
|
|
978
|
+
}
|
|
979
|
+
return acc;
|
|
980
|
+
}, {});
|
|
981
|
+
state.values.openItemIds = {
|
|
982
|
+
...additionalOpenItems,
|
|
983
|
+
...state.values.openItemIds
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
graph: {
|
|
993
|
+
builder: (plugins) => {
|
|
994
|
+
const intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
|
|
995
|
+
return [
|
|
996
|
+
createExtension({
|
|
997
|
+
id: NAVTREE_PLUGIN,
|
|
998
|
+
filter: (node) => node.id === "root",
|
|
999
|
+
actions: () => [
|
|
1000
|
+
{
|
|
1001
|
+
id: "dxos.org/plugin/navtree/open-commands",
|
|
1002
|
+
data: async () => {
|
|
1003
|
+
await intentPlugin?.provides.intent.dispatch({
|
|
1004
|
+
action: LayoutAction4.SET_LAYOUT,
|
|
1005
|
+
data: {
|
|
1006
|
+
element: "dialog",
|
|
1007
|
+
component: `${NAVTREE_PLUGIN}/Commands`,
|
|
1008
|
+
dialogBlockAlign: "start"
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
},
|
|
1012
|
+
properties: {
|
|
1013
|
+
label: [
|
|
1014
|
+
"open commands label",
|
|
1015
|
+
{
|
|
1016
|
+
ns: NAVTREE_PLUGIN
|
|
1017
|
+
}
|
|
1018
|
+
],
|
|
1019
|
+
icon: (props) => /* @__PURE__ */ React8.createElement(MagnifyingGlass2, props),
|
|
1020
|
+
iconSymbol: "ph--magnifying-glass--regular",
|
|
1021
|
+
keyBinding: {
|
|
1022
|
+
macos: "meta+k",
|
|
1023
|
+
windows: "ctrl+k"
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
]
|
|
1028
|
+
})
|
|
1029
|
+
];
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
translations: translations_default
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
// packages/plugins/plugin-navtree/src/index.ts
|
|
1038
|
+
var src_default = NavTreePlugin;
|
|
1039
|
+
export {
|
|
1040
|
+
NavTreePlugin,
|
|
1041
|
+
src_default as default,
|
|
1042
|
+
expandActions,
|
|
1043
|
+
expandChildren,
|
|
1044
|
+
expandChildrenAndActions,
|
|
1045
|
+
expandOpenGraphNodes,
|
|
1046
|
+
getActions,
|
|
1047
|
+
getChildren,
|
|
1048
|
+
getParent,
|
|
1049
|
+
getPersistenceParent,
|
|
1050
|
+
getTreeItemNode,
|
|
1051
|
+
resolveMigrationOperation,
|
|
1052
|
+
sortActions,
|
|
1053
|
+
treeItemsFromRootNode
|
|
1054
|
+
};
|
|
1055
|
+
//# sourceMappingURL=index.mjs.map
|