@dxos/plugin-navtree 0.7.5-main.9d2a38b → 0.7.5-main.b19bfc8

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.
Files changed (110) hide show
  1. package/dist/lib/browser/{app-graph-builder-OF4MMBLH.mjs → app-graph-builder-BL7LRXCM.mjs} +7 -5
  2. package/dist/lib/browser/{app-graph-builder-OF4MMBLH.mjs.map → app-graph-builder-BL7LRXCM.mjs.map} +3 -3
  3. package/dist/lib/browser/chunk-7OKF4GP3.mjs +1156 -0
  4. package/dist/lib/browser/chunk-7OKF4GP3.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-OI7AAA6Q.mjs → chunk-AOAGODQB.mjs} +1 -1
  6. package/dist/lib/browser/chunk-AOAGODQB.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +22 -27
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/intent-resolver-U25VBFH3.mjs +47 -0
  10. package/dist/lib/browser/intent-resolver-U25VBFH3.mjs.map +7 -0
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/react-surface-SIEGT4YS.mjs +57 -0
  13. package/dist/lib/browser/react-surface-SIEGT4YS.mjs.map +7 -0
  14. package/dist/lib/browser/{state-HT65TAYL.mjs → state-IEFQTUPG.mjs} +7 -10
  15. package/dist/lib/browser/state-IEFQTUPG.mjs.map +7 -0
  16. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  17. package/dist/types/src/capabilities/app-graph-builder.d.ts +110 -110
  18. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  19. package/dist/types/src/capabilities/capabilities.d.ts +3 -2
  20. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  21. package/dist/types/src/capabilities/index.d.ts +178 -122
  22. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  23. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/state.d.ts +3 -3
  26. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  27. package/dist/types/src/components/CommandsDialog.d.ts +1 -2
  28. package/dist/types/src/components/CommandsDialog.d.ts.map +1 -1
  29. package/dist/types/src/components/CommandsTrigger.d.ts +1 -2
  30. package/dist/types/src/components/CommandsTrigger.d.ts.map +1 -1
  31. package/dist/types/src/components/HaloButton.d.ts +1 -2
  32. package/dist/types/src/components/HaloButton.d.ts.map +1 -1
  33. package/dist/types/src/components/HaloButton.stories.d.ts +1 -2
  34. package/dist/types/src/components/HaloButton.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/L0Menu.d.ts +8 -0
  36. package/dist/types/src/components/L0Menu.d.ts.map +1 -0
  37. package/dist/types/src/components/L1Panels.d.ts +13 -0
  38. package/dist/types/src/components/L1Panels.d.ts.map +1 -0
  39. package/dist/types/src/components/NavTree.d.ts +2 -20
  40. package/dist/types/src/components/NavTree.d.ts.map +1 -1
  41. package/dist/types/src/components/NavTree.stories.d.ts +2 -2
  42. package/dist/types/src/components/NavTree.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/NavTreeContainer.d.ts +4 -3
  44. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  45. package/dist/types/src/components/NavTreeContext.d.ts +4 -0
  46. package/dist/types/src/components/NavTreeContext.d.ts.map +1 -0
  47. package/dist/types/src/components/NavTreeItemAction.d.ts +5 -5
  48. package/dist/types/src/components/NavTreeItemAction.d.ts.map +1 -1
  49. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +2 -2
  50. package/dist/types/src/components/NavTreeItemColumns.d.ts +4 -0
  51. package/dist/types/src/components/NavTreeItemColumns.d.ts.map +1 -0
  52. package/dist/types/src/components/NotchStart.d.ts +1 -2
  53. package/dist/types/src/components/NotchStart.d.ts.map +1 -1
  54. package/dist/types/src/components/index.d.ts +2 -0
  55. package/dist/types/src/components/index.d.ts.map +1 -1
  56. package/dist/types/src/components/types.d.ts +26 -0
  57. package/dist/types/src/components/types.d.ts.map +1 -0
  58. package/dist/types/src/experimental/Tree.d.ts +8 -8
  59. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  60. package/dist/types/src/experimental/Tree.stories.d.ts +2 -3
  61. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  62. package/dist/types/src/hooks.d.ts +3 -0
  63. package/dist/types/src/hooks.d.ts.map +1 -0
  64. package/dist/types/src/stories/Graph.stories.d.ts +2 -2
  65. package/dist/types/src/stories/Graph.stories.d.ts.map +1 -1
  66. package/dist/types/src/stories/StorybookNavTree.d.ts +3 -0
  67. package/dist/types/src/stories/StorybookNavTree.d.ts.map +1 -0
  68. package/dist/types/src/translations.d.ts +0 -6
  69. package/dist/types/src/translations.d.ts.map +1 -1
  70. package/dist/types/src/types.d.ts +2 -1
  71. package/dist/types/src/types.d.ts.map +1 -1
  72. package/dist/types/src/util.d.ts +9 -0
  73. package/dist/types/src/util.d.ts.map +1 -1
  74. package/package.json +33 -31
  75. package/src/NavTreePlugin.tsx +9 -11
  76. package/src/capabilities/app-graph-builder.ts +6 -4
  77. package/src/capabilities/capabilities.ts +3 -2
  78. package/src/capabilities/intent-resolver.ts +22 -16
  79. package/src/capabilities/react-surface.tsx +15 -41
  80. package/src/capabilities/state.ts +6 -9
  81. package/src/components/CommandsDialog.tsx +3 -4
  82. package/src/components/CommandsTrigger.tsx +7 -5
  83. package/src/components/L0Menu.tsx +238 -0
  84. package/src/components/L1Panels.tsx +119 -0
  85. package/src/components/NavTree.stories.tsx +6 -6
  86. package/src/components/NavTree.tsx +26 -116
  87. package/src/components/NavTreeContainer.tsx +114 -33
  88. package/src/components/NavTreeContext.tsx +13 -0
  89. package/src/components/NavTreeItemAction.tsx +12 -4
  90. package/src/components/NavTreeItemColumns.tsx +71 -0
  91. package/src/components/NotchStart.tsx +2 -2
  92. package/src/components/index.ts +2 -0
  93. package/src/components/types.ts +35 -0
  94. package/src/hooks.ts +21 -0
  95. package/src/stories/Graph.stories.tsx +6 -5
  96. package/src/stories/StorybookNavTree.tsx +63 -0
  97. package/src/translations.ts +0 -6
  98. package/src/types.ts +2 -1
  99. package/src/util.ts +56 -2
  100. package/dist/lib/browser/chunk-IMGT2LAL.mjs +0 -658
  101. package/dist/lib/browser/chunk-IMGT2LAL.mjs.map +0 -7
  102. package/dist/lib/browser/chunk-OI7AAA6Q.mjs.map +0 -7
  103. package/dist/lib/browser/intent-resolver-74JPWYBP.mjs +0 -42
  104. package/dist/lib/browser/intent-resolver-74JPWYBP.mjs.map +0 -7
  105. package/dist/lib/browser/react-surface-6QWXI53A.mjs +0 -189
  106. package/dist/lib/browser/react-surface-6QWXI53A.mjs.map +0 -7
  107. package/dist/lib/browser/state-HT65TAYL.mjs.map +0 -7
  108. package/dist/types/src/components/NavTreeFooter.d.ts +0 -6
  109. package/dist/types/src/components/NavTreeFooter.d.ts.map +0 -1
  110. package/src/components/NavTreeFooter.tsx +0 -161
@@ -0,0 +1,1156 @@
1
+ import {
2
+ NavTreeCapabilities
3
+ } from "./chunk-AOAGODQB.mjs";
4
+ import {
5
+ COMMANDS_DIALOG,
6
+ KEY_BINDING,
7
+ NAVTREE_PLUGIN
8
+ } from "./chunk-KOXMEAOS.mjs";
9
+
10
+ // packages/plugins/plugin-navtree/src/components/CommandsDialog.tsx
11
+ import React, { useMemo, useState } from "react";
12
+ import { createIntent, LayoutAction, useAppGraph, useIntentDispatcher } from "@dxos/app-framework";
13
+ import { isActionGroup, isAction } from "@dxos/app-graph";
14
+ import { Keyboard, keySymbols } from "@dxos/keyboard";
15
+ import { Button, Dialog, Icon, useTranslation, toLocalizedString } from "@dxos/react-ui";
16
+ import { SearchList } from "@dxos/react-ui-searchlist";
17
+ import { descriptionText, mx } from "@dxos/react-ui-theme";
18
+ import { getHostPlatform } from "@dxos/util";
19
+ var CommandsDialogContent = ({ selected: initial }) => {
20
+ const { t } = useTranslation(NAVTREE_PLUGIN);
21
+ const [selected, setSelected] = useState(initial);
22
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
23
+ const { graph } = useAppGraph();
24
+ const allActions = useMemo(() => {
25
+ const current = Keyboard.singleton.getCurrentContext();
26
+ const actionMap = /* @__PURE__ */ new Set();
27
+ const actions2 = [];
28
+ graph?.traverse({
29
+ visitor: (node, path) => {
30
+ if ((isAction(node) || isActionGroup(node)) && !actionMap.has(node.id) && current.startsWith(path.slice(0, -1).join("/"))) {
31
+ actionMap.add(node.id);
32
+ actions2.push(node);
33
+ }
34
+ }
35
+ });
36
+ actions2.sort((a, b) => {
37
+ return toLocalizedString(a.properties.label, t)?.toLowerCase().localeCompare(toLocalizedString(b.properties.label, t)?.toLowerCase());
38
+ });
39
+ return actions2;
40
+ }, [
41
+ graph
42
+ ]);
43
+ const group = allActions.find(({ id }) => id === selected);
44
+ const actions = isActionGroup(group) ? graph.actions(group) : allActions;
45
+ return /* @__PURE__ */ React.createElement(Dialog.Content, {
46
+ classNames: [
47
+ "md:max-is-[30rem] overflow-hidden mbs-12"
48
+ ]
49
+ }, /* @__PURE__ */ React.createElement(Dialog.Title, null, t("commands dialog title", {
50
+ ns: NAVTREE_PLUGIN
51
+ })), /* @__PURE__ */ React.createElement(SearchList.Root, {
52
+ label: t("command list input placeholder"),
53
+ classNames: "flex flex-col grow overflow-hidden my-2"
54
+ }, /* @__PURE__ */ React.createElement(SearchList.Input, {
55
+ placeholder: t("command list input placeholder"),
56
+ classNames: "px-1 my-2"
57
+ }), /* @__PURE__ */ React.createElement(SearchList.Content, {
58
+ classNames: "max-bs-[24rem] overflow-auto"
59
+ }, actions?.map((action) => {
60
+ const label = toLocalizedString(action.properties.label, t);
61
+ const shortcut = typeof action.properties.keyBinding === "string" ? action.properties.keyBinding : action.properties.keyBinding?.[getHostPlatform()];
62
+ return /* @__PURE__ */ React.createElement(SearchList.Item, {
63
+ value: label,
64
+ key: action.id,
65
+ onSelect: () => {
66
+ if (action.properties.disabled) {
67
+ return;
68
+ }
69
+ if (isActionGroup(action)) {
70
+ setSelected(action.id);
71
+ return;
72
+ }
73
+ void dispatch(createIntent(LayoutAction.UpdateDialog, {
74
+ part: "dialog",
75
+ options: {
76
+ state: false
77
+ }
78
+ }));
79
+ setTimeout(() => {
80
+ const node = graph.nodes(group ?? action, {
81
+ relation: "inbound"
82
+ })[0];
83
+ void (node && isAction(action) && action.data({
84
+ node,
85
+ caller: KEY_BINDING
86
+ }));
87
+ });
88
+ },
89
+ classNames: "flex items-center gap-2",
90
+ disabled: action.properties.disabled,
91
+ ...action.properties?.testId && {
92
+ "data-testid": action.properties.testId
93
+ }
94
+ }, /* @__PURE__ */ React.createElement(Icon, {
95
+ icon: action.properties.icon,
96
+ size: 4
97
+ }), /* @__PURE__ */ React.createElement("span", {
98
+ className: "grow truncate"
99
+ }, label), shortcut && /* @__PURE__ */ React.createElement("span", {
100
+ className: mx("shrink-0", descriptionText)
101
+ }, keySymbols(shortcut).join("")));
102
+ }))), /* @__PURE__ */ React.createElement(Dialog.Close, {
103
+ asChild: true
104
+ }, /* @__PURE__ */ React.createElement(Button, {
105
+ variant: "primary",
106
+ classNames: "mbs-2"
107
+ }, t("close label", {
108
+ ns: "os"
109
+ }))));
110
+ };
111
+
112
+ // packages/plugins/plugin-navtree/src/components/CommandsTrigger.tsx
113
+ import { MagnifyingGlass } from "@phosphor-icons/react";
114
+ import React2 from "react";
115
+ import { createIntent as createIntent2, LayoutAction as LayoutAction2, useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
116
+ import { Button as Button2, useTranslation as useTranslation2 } from "@dxos/react-ui";
117
+ import { getSize } from "@dxos/react-ui-theme";
118
+ var CommandsTrigger = () => {
119
+ const { dispatchPromise: dispatch } = useIntentDispatcher2();
120
+ const { t } = useTranslation2(NAVTREE_PLUGIN);
121
+ return /* @__PURE__ */ React2.createElement(Button2, {
122
+ classNames: "m-1 pli-1 lg:pli-2",
123
+ onClick: () => dispatch(createIntent2(LayoutAction2.UpdateDialog, {
124
+ part: "dialog",
125
+ subject: COMMANDS_DIALOG,
126
+ options: {
127
+ blockAlign: "start"
128
+ }
129
+ }))
130
+ }, /* @__PURE__ */ React2.createElement("span", {
131
+ className: "text-description font-normal grow text-start"
132
+ }, t("command list input placeholder")), /* @__PURE__ */ React2.createElement(MagnifyingGlass, {
133
+ className: getSize(5)
134
+ }));
135
+ };
136
+
137
+ // packages/plugins/plugin-navtree/src/components/NotchStart.tsx
138
+ import React4 from "react";
139
+ import { createIntent as createIntent3, useCapabilities, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
140
+ import { ClientAction } from "@dxos/plugin-client/types";
141
+ import { ObservabilityCapabilities } from "@dxos/plugin-observability";
142
+ import { useIdentity } from "@dxos/react-client/halo";
143
+
144
+ // packages/plugins/plugin-navtree/src/components/HaloButton.tsx
145
+ import React3 from "react";
146
+ import { ConnectionState, useNetworkStatus } from "@dxos/react-client/mesh";
147
+ import { Avatar } from "@dxos/react-ui";
148
+ import { focusRing, mx as mx2 } from "@dxos/react-ui-theme";
149
+ import { hexToFallback } from "@dxos/util";
150
+ var INTERNAL = "https://avatars.githubusercontent.com/u/57182821";
151
+ var HaloButton = (props) => {
152
+ const { onClick, identityKey, internal, size = 8 } = props;
153
+ const fallbackValue = hexToFallback(identityKey ?? "0");
154
+ const { swarm: connectionState } = useNetworkStatus();
155
+ return /* @__PURE__ */ React3.createElement("button", {
156
+ className: mx2(focusRing, "rounded grid place-items-center"),
157
+ onClick
158
+ }, /* @__PURE__ */ React3.createElement(Avatar.Root, {
159
+ size,
160
+ variant: "circle",
161
+ status: connectionState === ConnectionState.OFFLINE ? "error" : internal ? "internal" : "active",
162
+ hue: props.hue || fallbackValue.hue
163
+ }, /* @__PURE__ */ React3.createElement(Avatar.Frame, {
164
+ "data-testid": "treeView.haloButton",
165
+ "data-joyride": "welcome/halo"
166
+ }, internal ? /* @__PURE__ */ React3.createElement(Avatar.Image, {
167
+ href: INTERNAL
168
+ }) : /* @__PURE__ */ React3.createElement(Avatar.Fallback, {
169
+ text: props.emoji || fallbackValue.emoji
170
+ }))));
171
+ };
172
+
173
+ // packages/plugins/plugin-navtree/src/components/NotchStart.tsx
174
+ var NotchStart = () => {
175
+ const identity = useIdentity();
176
+ const [observability] = useCapabilities(ObservabilityCapabilities.Observability);
177
+ const { dispatchPromise: dispatch } = useIntentDispatcher3();
178
+ return /* @__PURE__ */ React4.createElement(HaloButton, {
179
+ size: 12,
180
+ identityKey: identity?.identityKey.toHex(),
181
+ hue: identity?.profile?.data?.hue,
182
+ emoji: identity?.profile?.data?.emoji,
183
+ internal: observability?.group === "dxos",
184
+ onClick: () => dispatch(createIntent3(ClientAction.ShareIdentity))
185
+ });
186
+ };
187
+
188
+ // packages/plugins/plugin-navtree/src/util.ts
189
+ import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction2, isActionLike } from "@dxos/app-graph";
190
+ import { isNonNullable } from "@dxos/util";
191
+ var getParent = (graph, node, path) => {
192
+ const parentId = path[path.length - 2];
193
+ return graph.nodes(node, {
194
+ relation: "inbound"
195
+ }).find((n) => n.id === parentId);
196
+ };
197
+ var getPersistenceParent = (graph, node, path, persistenceClass) => {
198
+ if (node.properties.acceptPersistenceClass?.has(persistenceClass)) {
199
+ return node;
200
+ } else {
201
+ const parent = getParent(graph, node, path);
202
+ return parent ? getPersistenceParent(graph, parent, path.slice(0, path.length - 1), persistenceClass) : null;
203
+ }
204
+ };
205
+ var resolveMigrationOperation = (graph, activeNode, destinationPath, destinationRelatedNode) => {
206
+ const activeClass = activeNode.properties.persistenceClass;
207
+ if (destinationRelatedNode && activeClass) {
208
+ const persistenceParent = getPersistenceParent(graph, destinationRelatedNode, destinationPath, activeClass);
209
+ if (persistenceParent) {
210
+ const activeKey = activeNode.properties.persistenceKey;
211
+ if (activeKey && persistenceParent?.properties.acceptPersistenceKey) {
212
+ return persistenceParent.properties.acceptPersistenceKey.has(activeKey) && persistenceParent.properties.onTransferStart ? "transfer" : persistenceParent.properties.onCopy ? "copy" : "reject";
213
+ } else {
214
+ return "reject";
215
+ }
216
+ } else {
217
+ return "reject";
218
+ }
219
+ } else {
220
+ return "reject";
221
+ }
222
+ };
223
+ var sortActions = (actions) => actions.sort((a, b) => {
224
+ if (a.properties.disposition === b.properties.disposition) {
225
+ return 0;
226
+ }
227
+ if (a.properties.disposition === "toolbar") {
228
+ return -1;
229
+ }
230
+ return 1;
231
+ });
232
+ var getChildren = (graph, node, filter, path = []) => {
233
+ return graph.nodes(node, {
234
+ relation: "outbound",
235
+ filter
236
+ }).map((n) => {
237
+ const nextPath = [
238
+ ...path,
239
+ node.id
240
+ ];
241
+ return nextPath.includes(n.id) ? void 0 : n;
242
+ }).filter(isNonNullable);
243
+ };
244
+ var getActions = (graph, node) => {
245
+ return graph.actions(node).reduce((acc, arg) => {
246
+ if (arg.properties.disposition === "item") {
247
+ return acc;
248
+ }
249
+ acc.actions.push(arg);
250
+ if (!isAction2(arg)) {
251
+ const actionGroup = graph.actions(arg);
252
+ acc.groupedActions[arg.id] = actionGroup;
253
+ }
254
+ return acc;
255
+ }, {
256
+ actions: [],
257
+ groupedActions: {}
258
+ });
259
+ };
260
+ var expandChildrenAndActions = (graph, node) => {
261
+ return Promise.all([
262
+ expandChildren(graph, node),
263
+ expandActions(graph, node)
264
+ ]);
265
+ };
266
+ var expandChildren = (graph, node) => {
267
+ return graph.expand(node, "outbound");
268
+ };
269
+ var expandActions = (graph, node) => {
270
+ return Promise.all([
271
+ graph.expand(node, "outbound", ACTION_TYPE),
272
+ graph.expand(node, "outbound", ACTION_GROUP_TYPE)
273
+ ]);
274
+ };
275
+ var l0ItemType = (item) => {
276
+ if (item.properties.disposition === "collection") {
277
+ return "collection";
278
+ } else if (isActionLike(item)) {
279
+ return "action";
280
+ } else if (item.properties.disposition === "navigation") {
281
+ return "link";
282
+ } else {
283
+ return "tab";
284
+ }
285
+ };
286
+ var renderableCharRegex = /^(?![\p{Control}\p{Mark}\p{Separator}\p{Surrogate}\p{Unassigned}])[\p{L}\p{N}\p{P}\p{S}\p{Emoji}]$/u;
287
+ var getFirstTwoRenderableChars = (label) => {
288
+ const characters = Array.from(label);
289
+ const result = [
290
+ "",
291
+ ""
292
+ ];
293
+ let foundFirst = false;
294
+ for (let i = 0; i < characters.length; i++) {
295
+ const char = characters[i];
296
+ if (renderableCharRegex.test(char)) {
297
+ if (!foundFirst) {
298
+ result[0] = char;
299
+ foundFirst = true;
300
+ } else {
301
+ const textBetween = characters.slice(result[0].length, i).join("");
302
+ if (/[^\p{L}\p{N}_]/u.test(textBetween)) {
303
+ result[1] = char;
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ }
309
+ return result;
310
+ };
311
+
312
+ // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
313
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
314
+ import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
315
+ import { untracked } from "@preact/signals-core";
316
+ import React10, { memo as memo2, useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo5 } from "react";
317
+ import { createIntent as createIntent5, LayoutAction as LayoutAction4, Surface, useAppGraph as useAppGraph2, useCapability, useIntentDispatcher as useIntentDispatcher5, useLayout as useLayout2 } from "@dxos/app-framework";
318
+ import { isAction as isAction4, isActionLike as isActionLike2 } from "@dxos/app-graph";
319
+ import { isEchoObject, isSpace } from "@dxos/react-client/echo";
320
+ import { useMediaQuery as useMediaQuery2 } from "@dxos/react-ui";
321
+ import { isTreeData } from "@dxos/react-ui-list";
322
+ import { mx as mx6 } from "@dxos/react-ui-theme";
323
+ import { arrayMove } from "@dxos/util";
324
+
325
+ // packages/plugins/plugin-navtree/src/components/NavTree.tsx
326
+ import React9, { useMemo as useMemo4 } from "react";
327
+ import { Tabs as Tabs3 } from "@dxos/react-ui-tabs";
328
+ import { byPosition } from "@dxos/util";
329
+
330
+ // packages/plugins/plugin-navtree/src/components/L0Menu.tsx
331
+ import React5, { useCallback, useMemo as useMemo2 } from "react";
332
+ import { createIntent as createIntent4, LayoutAction as LayoutAction3, useIntentDispatcher as useIntentDispatcher4 } from "@dxos/app-framework";
333
+ import { Icon as Icon2, Popover, ScrollArea, toLocalizedString as toLocalizedString3, Tooltip, useMediaQuery, useSidebars, useTranslation as useTranslation4 } from "@dxos/react-ui";
334
+ import { Tabs } from "@dxos/react-ui-tabs";
335
+ import { mx as mx3 } from "@dxos/react-ui-theme";
336
+
337
+ // packages/plugins/plugin-navtree/src/components/NavTreeContext.tsx
338
+ import { createContext, useContext } from "react";
339
+ import { raise } from "@dxos/debug";
340
+ var NavTreeContext = /* @__PURE__ */ createContext(null);
341
+ var useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error("NavTreeContext not found"));
342
+
343
+ // packages/plugins/plugin-navtree/src/hooks.ts
344
+ import { useEffect as useEffect2 } from "react";
345
+
346
+ // packages/plugins/plugin-navtree/src/components/NavTreeDocumentTitle.tsx
347
+ import { useEffect } from "react";
348
+ import { toLocalizedString as toLocalizedString2, useTranslation as useTranslation3 } from "@dxos/react-ui";
349
+ var NavTreeDocumentTitle = ({ node }) => {
350
+ const { t } = useTranslation3(NAVTREE_PLUGIN);
351
+ useEffect(() => {
352
+ document.title = node ? toLocalizedString2(node.properties.label, t) : t("current app name", {
353
+ ns: "appkit"
354
+ });
355
+ }, [
356
+ node?.properties?.label
357
+ ]);
358
+ return null;
359
+ };
360
+
361
+ // packages/plugins/plugin-navtree/src/hooks.ts
362
+ var useLoadDescendents = (root) => {
363
+ const { loadDescendents } = useNavTreeContext();
364
+ useEffect2(() => {
365
+ const frame = requestAnimationFrame(() => {
366
+ if (root) {
367
+ void loadDescendents?.(root);
368
+ }
369
+ });
370
+ return () => cancelAnimationFrame(frame);
371
+ }, [
372
+ root
373
+ ]);
374
+ };
375
+
376
+ // packages/plugins/plugin-navtree/src/components/L0Menu.tsx
377
+ var useL0ItemClick = ({ item, parent, path }, type) => {
378
+ const { tab, onTabChange, onSelect, isCurrent } = useNavTreeContext();
379
+ const { dispatchPromise: dispatch } = useIntentDispatcher4();
380
+ const { navigationSidebarState } = useSidebars(NAVTREE_PLUGIN);
381
+ const [isLg] = useMediaQuery("lg", {
382
+ ssr: false
383
+ });
384
+ return useCallback((event) => {
385
+ switch (type) {
386
+ case "tab":
387
+ void dispatch(createIntent4(LayoutAction3.UpdateSidebar, {
388
+ part: "sidebar",
389
+ options: {
390
+ state: item.id === tab ? navigationSidebarState === "expanded" ? isLg ? "collapsed" : "closed" : "expanded" : "expanded"
391
+ }
392
+ }));
393
+ return onTabChange?.(item);
394
+ case "link":
395
+ return onSelect?.({
396
+ item,
397
+ path,
398
+ current: !isCurrent(path, item),
399
+ option: event.altKey
400
+ });
401
+ case "action": {
402
+ const { data: invoke, properties: { caller } } = item;
403
+ return invoke?.(caller ? {
404
+ node: parent,
405
+ caller
406
+ } : {
407
+ node: parent
408
+ });
409
+ }
410
+ }
411
+ }, [
412
+ item,
413
+ type,
414
+ onSelect,
415
+ isCurrent,
416
+ parent,
417
+ tab,
418
+ navigationSidebarState,
419
+ isLg,
420
+ dispatch
421
+ ]);
422
+ };
423
+ var l0Breakpoints = {
424
+ lg: "hidden lg:grid"
425
+ };
426
+ var L0Item = ({ item, parent, path, pinned }) => {
427
+ const { t } = useTranslation4(NAVTREE_PLUGIN);
428
+ const type = l0ItemType(item);
429
+ const itemPath = useMemo2(() => [
430
+ ...path,
431
+ item.id
432
+ ], [
433
+ item.id,
434
+ path
435
+ ]);
436
+ const { getProps, popoverAnchorId } = useNavTreeContext();
437
+ const { id, testId } = getProps?.(item, path) ?? {};
438
+ const Root = type === "collection" ? "h2" : type === "tab" ? Tabs.TabPrimitive : "button";
439
+ const handleClick = useL0ItemClick({
440
+ item,
441
+ path: itemPath,
442
+ parent
443
+ }, type);
444
+ const rootProps = type === "tab" ? {
445
+ value: item.id,
446
+ tabIndex: 0,
447
+ onClick: handleClick,
448
+ "data-testid": testId,
449
+ "data-itemid": id
450
+ } : type !== "collection" ? {
451
+ onClick: handleClick,
452
+ "data-testid": testId,
453
+ "data-itemid": id
454
+ } : {
455
+ onClick: handleClick
456
+ };
457
+ const localizedString = toLocalizedString3(item.properties.label, t);
458
+ const hue = item.properties.hue ?? null;
459
+ const avatarValue = useMemo2(() => type === "tab" ? getFirstTwoRenderableChars(localizedString).join("").toUpperCase() : [], [
460
+ type,
461
+ item.properties.label,
462
+ t
463
+ ]);
464
+ const hueFgStyle = hue && {
465
+ style: {
466
+ color: `var(--dx-${hue}SurfaceText)`
467
+ }
468
+ };
469
+ const l0ItemTrigger = /* @__PURE__ */ React5.createElement(Root, {
470
+ ...rootProps,
471
+ "data-type": type,
472
+ className: mx3('group/l0i dx-focus-ring-group grid overflow-hidden relative data[type!="collection"]:cursor-pointer app-no-drag', l0Breakpoints[item.properties.l0Breakpoint])
473
+ }, type !== "collection" && /* @__PURE__ */ React5.createElement("div", {
474
+ role: "none",
475
+ className: mx3("absolute -z-[1] dx-focus-ring-group-indicator transition-colors", type === "tab" || pinned ? "rounded" : "rounded-full", pinned ? "bg-transparent group-hover/l0i:bg-groupSurface inset-inline-3 inset-block-0.5" : "bg-groupSurface inset-inline-3 inset-block-2"),
476
+ ...hue && {
477
+ style: {
478
+ background: `var(--dx-${hue}Surface)`
479
+ }
480
+ }
481
+ }), /* @__PURE__ */ React5.createElement("div", {
482
+ role: "none",
483
+ className: "hidden group-aria-selected/l0i:block absolute inline-start-0 inset-block-4 is-1 bg-accentSurface rounded-ie"
484
+ }), item.properties.icon && /* @__PURE__ */ React5.createElement(Icon2, {
485
+ icon: item.properties.icon,
486
+ size: pinned ? 5 : 7,
487
+ classNames: "place-self-center",
488
+ ...hueFgStyle
489
+ }) || (type === "tab" && item.properties.disposition !== "pin-end" ? /* @__PURE__ */ React5.createElement("span", {
490
+ role: "img",
491
+ className: "place-self-center text-3xl font-light",
492
+ ...hueFgStyle
493
+ }, avatarValue) : item.properties.icon && /* @__PURE__ */ React5.createElement(Icon2, {
494
+ icon: "ph--planet--regular",
495
+ size: pinned ? 5 : 7,
496
+ classNames: "place-self-center",
497
+ ...hueFgStyle
498
+ })), /* @__PURE__ */ React5.createElement("span", {
499
+ id: `${item.id}__label`,
500
+ className: "sr-only"
501
+ }, localizedString));
502
+ return popoverAnchorId === id ? /* @__PURE__ */ React5.createElement(Popover.Anchor, {
503
+ asChild: true
504
+ }, l0ItemTrigger) : /* @__PURE__ */ React5.createElement(Tooltip.Root, {
505
+ delayDuration: 0
506
+ }, /* @__PURE__ */ React5.createElement(Tooltip.Trigger, {
507
+ asChild: true
508
+ }, l0ItemTrigger), /* @__PURE__ */ React5.createElement(Tooltip.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip.Content, {
509
+ side: "right"
510
+ }, localizedString, /* @__PURE__ */ React5.createElement(Tooltip.Arrow, null))));
511
+ };
512
+ var L0Collection = ({ item, path, parent }) => {
513
+ const navTreeContext = useNavTreeContext();
514
+ useLoadDescendents(item);
515
+ const collectionItems = navTreeContext.getItems(item);
516
+ const groupPath = useMemo2(() => [
517
+ ...path,
518
+ item.id
519
+ ], [
520
+ item.id,
521
+ path
522
+ ]);
523
+ const { id, testId } = navTreeContext.getProps?.(item, path) ?? {};
524
+ return /* @__PURE__ */ React5.createElement("div", {
525
+ role: "group",
526
+ className: "contents group/l0c",
527
+ "aria-labelledby": `${item.id}__label`,
528
+ "data-itemid": id,
529
+ "data-testid": testId
530
+ }, collectionItems.map((collectionItem) => /* @__PURE__ */ React5.createElement(L0Item, {
531
+ key: collectionItem.id,
532
+ item: collectionItem,
533
+ parent: item,
534
+ path: groupPath
535
+ })));
536
+ };
537
+ var L0Menu = ({ topLevelItems, pinnedItems, parent, path }) => {
538
+ return /* @__PURE__ */ React5.createElement(Tabs.Tablist, {
539
+ classNames: "group/l0 absolute z-[1] inset-block-0 inline-start-0 rounded-is-lg grid grid-cols-[var(--l0-size)] grid-rows-[1fr_min-content_var(--l0-size)] contain-layout !is-[--l0-size] bg-baseSurface border-ie border-separator app-drag pbe-[env(safe-area-inset-bottom)]"
540
+ }, /* @__PURE__ */ React5.createElement(ScrollArea.Root, null, /* @__PURE__ */ React5.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React5.createElement("div", {
541
+ role: "none",
542
+ className: 'grid auto-rows-[calc(var(--l0-size)-.5rem)] plb-1 [body[data-platform="darwin"]_&]:pbs-[calc(30px+0.25rem)] [body[data-platform="ios"]_&]:pbs-[max(env(safe-area-inset-top),0.25rem)]'
543
+ }, topLevelItems.map((item) => {
544
+ if (l0ItemType(item) === "collection") {
545
+ return /* @__PURE__ */ React5.createElement(L0Collection, {
546
+ key: item.id,
547
+ item,
548
+ parent,
549
+ path
550
+ });
551
+ } else {
552
+ return /* @__PURE__ */ React5.createElement(L0Item, {
553
+ key: item.id,
554
+ item,
555
+ parent,
556
+ path
557
+ });
558
+ }
559
+ })), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, {
560
+ orientation: "vertical"
561
+ }, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))), /* @__PURE__ */ React5.createElement("div", {
562
+ role: "none",
563
+ className: "grid grid-cols-1 auto-rows-[--rail-action] pbs-2"
564
+ }, pinnedItems.filter((item) => l0ItemType(item) !== "collection").map((item) => /* @__PURE__ */ React5.createElement(L0Item, {
565
+ key: item.id,
566
+ item,
567
+ parent,
568
+ path,
569
+ pinned: true
570
+ }))), /* @__PURE__ */ React5.createElement("div", {
571
+ role: "none",
572
+ className: "grid p-2 app-no-drag"
573
+ }, /* @__PURE__ */ React5.createElement(NotchStart, null)), /* @__PURE__ */ React5.createElement("div", {
574
+ role: "none",
575
+ className: 'hidden [body[data-platform="darwin"]_&]:block absolute block-start-0 is-[calc(var(--l0-size)-1px)] bs-[calc(40px+0.25rem)]',
576
+ style: {
577
+ background: "linear-gradient(to bottom, var(--dx-baseSurface) 0%, var(--dx-baseSurface) 70%, transparent 100%)"
578
+ }
579
+ }));
580
+ };
581
+
582
+ // packages/plugins/plugin-navtree/src/components/L1Panels.tsx
583
+ import React8, { useMemo as useMemo3 } from "react";
584
+ import { useLayout } from "@dxos/app-framework";
585
+ import { IconButton as IconButton2, toLocalizedString as toLocalizedString6, useTranslation as useTranslation7 } from "@dxos/react-ui";
586
+ import { Tree } from "@dxos/react-ui-list";
587
+ import { Tabs as Tabs2 } from "@dxos/react-ui-tabs";
588
+ import { hoverableControlItem as hoverableControlItem2, hoverableOpenControlItem as hoverableOpenControlItem2, mx as mx5 } from "@dxos/react-ui-theme";
589
+
590
+ // packages/plugins/plugin-navtree/src/components/NavTreeItemColumns.tsx
591
+ import React7, { Fragment, memo } from "react";
592
+ import { isAction as isAction3 } from "@dxos/app-graph";
593
+ import { Popover as Popover2, toLocalizedString as toLocalizedString5, Treegrid, useTranslation as useTranslation6 } from "@dxos/react-ui";
594
+
595
+ // packages/plugins/plugin-navtree/src/components/NavTreeItemAction.tsx
596
+ import React6, { useRef } from "react";
597
+ import { useTranslation as useTranslation5, toLocalizedString as toLocalizedString4, IconButton } from "@dxos/react-ui";
598
+ import { DropdownMenu, MenuProvider } from "@dxos/react-ui-menu";
599
+ import { hoverableControlItem, hoverableOpenControlItem, mx as mx4 } from "@dxos/react-ui-theme";
600
+ var fallbackIcon = "ph--placeholder--regular";
601
+ var actionButtonProps = {
602
+ size: 4,
603
+ density: "fine"
604
+ };
605
+ var NavTreeItemActionDropdownMenu = ({ label, icon, testId, menuActions, onAction }) => {
606
+ const { t } = useTranslation5(NAVTREE_PLUGIN);
607
+ const suppressNextTooltip = useRef(false);
608
+ return /* @__PURE__ */ React6.createElement(MenuProvider, {
609
+ onAction
610
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Root, {
611
+ items: menuActions,
612
+ suppressNextTooltip
613
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Trigger, {
614
+ asChild: true
615
+ }, /* @__PURE__ */ React6.createElement(IconButton, {
616
+ ...actionButtonProps,
617
+ classNames: mx4("shrink-0 pli-2 pointer-fine:pli-1", hoverableControlItem, hoverableOpenControlItem),
618
+ variant: "ghost",
619
+ icon: icon ?? fallbackIcon,
620
+ iconOnly: true,
621
+ label: toLocalizedString4(label, t),
622
+ "data-testid": testId,
623
+ suppressNextTooltip
624
+ }))));
625
+ };
626
+ var NavTreeItemMonolithicAction = ({ parent, properties: { disabled, caller, testId, icon, variant = "ghost", iconOnly = true } = {
627
+ label: "never"
628
+ }, data: invoke, baseLabel }) => {
629
+ return /* @__PURE__ */ React6.createElement(IconButton, {
630
+ ...actionButtonProps,
631
+ variant,
632
+ classNames: mx4("shrink-0", hoverableControlItem, hoverableOpenControlItem, iconOnly ? "pli-2 pointer-fine:pli-1" : "p-2 pointer-fine:p-2 mie-1"),
633
+ icon: icon ?? fallbackIcon,
634
+ iconOnly,
635
+ label: baseLabel,
636
+ disabled,
637
+ onClick: (event) => {
638
+ if (disabled) {
639
+ return;
640
+ }
641
+ event.stopPropagation();
642
+ void invoke?.(caller ? {
643
+ node: parent,
644
+ caller
645
+ } : {
646
+ node: parent
647
+ });
648
+ },
649
+ "data-testid": testId
650
+ });
651
+ };
652
+ var NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...props }) => {
653
+ const { t } = useTranslation5(NAVTREE_PLUGIN);
654
+ const monolithicAction = menuActions?.length === 1 && menuActions[0];
655
+ const baseLabel = toLocalizedString4(monolithicAction ? monolithicAction.properties.label : props.label, t);
656
+ return monolithic && menuActions?.length === 1 ? /* @__PURE__ */ React6.createElement(NavTreeItemMonolithicAction, {
657
+ baseLabel,
658
+ parent: node,
659
+ ...menuActions[0]
660
+ }) : /* @__PURE__ */ React6.createElement(NavTreeItemActionDropdownMenu, {
661
+ ...props,
662
+ label: baseLabel,
663
+ parent: node,
664
+ menuActions,
665
+ onAction: (action) => action.data?.(props.caller ? {
666
+ node,
667
+ caller: props.caller
668
+ } : {
669
+ node
670
+ })
671
+ });
672
+ };
673
+
674
+ // packages/plugins/plugin-navtree/src/components/NavTreeItemColumns.tsx
675
+ var NavTreeItemColumns = /* @__PURE__ */ memo(({ path, item, open }) => {
676
+ const { t } = useTranslation6(NAVTREE_PLUGIN);
677
+ const { getActions: getActions2, renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();
678
+ const level = path.length - 2;
679
+ const { actions: _actions, groupedActions } = getActions2(item);
680
+ const [primaryAction, ...secondaryActions] = _actions.toSorted((a, b) => a.properties?.disposition === "toolbar" ? -1 : 1);
681
+ const actions = (primaryAction?.properties?.disposition === "toolbar" ? secondaryActions : _actions).flatMap((action) => isAction3(action) ? [
682
+ action
683
+ ] : []).filter((action) => !action.properties?.hidden);
684
+ const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover2.Anchor : Fragment;
685
+ useLoadDescendents(item);
686
+ useLoadDescendents(primaryAction && !isAction3(primaryAction) ? primaryAction : void 0);
687
+ return /* @__PURE__ */ React7.createElement("div", {
688
+ role: "none",
689
+ className: "contents app-no-drag"
690
+ }, primaryAction?.properties?.disposition === "toolbar" && !primaryAction?.properties?.disabled ? /* @__PURE__ */ React7.createElement(NavTreeItemAction, {
691
+ testId: primaryAction.properties?.testId,
692
+ label: toLocalizedString5(primaryAction.properties?.label, t),
693
+ icon: primaryAction.properties?.icon ?? "ph--placeholder--regular",
694
+ parent: item,
695
+ monolithic: isAction3(primaryAction),
696
+ menuActions: isAction3(primaryAction) ? [
697
+ primaryAction
698
+ ] : groupedActions[primaryAction.id],
699
+ menuType: primaryAction.properties?.menuType,
700
+ caller: NAV_TREE_ITEM
701
+ }) : /* @__PURE__ */ React7.createElement(Treegrid.Cell, null), /* @__PURE__ */ React7.createElement(ActionRoot, null, actions.length > 0 ? /* @__PURE__ */ React7.createElement(NavTreeItemAction, {
702
+ testId: `navtree.treeItem.actionsLevel${level}`,
703
+ label: t("tree item actions label"),
704
+ icon: "ph--dots-three-vertical--regular",
705
+ parent: item,
706
+ menuActions: actions,
707
+ menuType: "dropdown",
708
+ caller: NAV_TREE_ITEM
709
+ }) : /* @__PURE__ */ React7.createElement(Treegrid.Cell, null)), ItemEnd && /* @__PURE__ */ React7.createElement(ItemEnd, {
710
+ node: item,
711
+ open
712
+ }));
713
+ });
714
+
715
+ // packages/plugins/plugin-navtree/src/components/L1Panels.tsx
716
+ var L1Panel = ({ item, path, currentItemId, onBack }) => {
717
+ const layout = useLayout();
718
+ const navTreeContext = useNavTreeContext();
719
+ const { t } = useTranslation7(NAVTREE_PLUGIN);
720
+ return /* @__PURE__ */ React8.createElement(Tabs2.Tabpanel, {
721
+ key: item.id,
722
+ value: item.id,
723
+ classNames: [
724
+ "absolute inset-block-0 inline-end-0 is-[calc(100%-var(--l0-size))] lg:is-[--l1-size] grid-cols-1 grid-rows-[var(--rail-size)_1fr] pbs-[env(safe-area-inset-top)]",
725
+ item.id === currentItemId && "grid"
726
+ ],
727
+ tabIndex: -1,
728
+ ...!layout.sidebarOpen && {
729
+ inert: "true"
730
+ }
731
+ }, item.id === currentItemId && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement("h2", {
732
+ className: "flex items-center border-be border-separator pis-4 app-drag"
733
+ }, item.properties.disposition === "pin-end" && /* @__PURE__ */ React8.createElement(IconButton2, {
734
+ label: t("back label"),
735
+ iconOnly: true,
736
+ icon: "ph--caret-left--regular",
737
+ size: 5,
738
+ density: "fine",
739
+ variant: "ghost",
740
+ classNames: mx5("shrink-0 mie-2", "pli-2 pointer-fine:pli-1", hoverableControlItem2, hoverableOpenControlItem2),
741
+ onClick: onBack
742
+ }), /* @__PURE__ */ React8.createElement("span", {
743
+ className: "flex-1 truncate cursor-default"
744
+ }, toLocalizedString6(item.properties.label, t)), /* @__PURE__ */ React8.createElement(NavTreeItemColumns, {
745
+ path,
746
+ item,
747
+ open: true
748
+ })), /* @__PURE__ */ React8.createElement("div", {
749
+ role: "none",
750
+ className: "overflow-y-auto"
751
+ }, /* @__PURE__ */ React8.createElement(Tree, {
752
+ ...navTreeContext,
753
+ id: item.id,
754
+ root: item,
755
+ path,
756
+ levelOffset: 5,
757
+ draggable: true,
758
+ gridTemplateColumns: "[tree-row-start] 1fr min-content min-content min-content [tree-row-end]",
759
+ renderColumns: NavTreeItemColumns
760
+ }))));
761
+ };
762
+ var L1PanelCollection = ({ item, path, currentItemId }) => {
763
+ const { getItems } = useNavTreeContext();
764
+ useLoadDescendents(item);
765
+ const collectionItems = getItems(item);
766
+ const groupPath = useMemo3(() => [
767
+ ...path,
768
+ item.id
769
+ ], [
770
+ item.id,
771
+ path
772
+ ]);
773
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, collectionItems.filter((item2) => l0ItemType(item2) === "tab").map((item2) => /* @__PURE__ */ React8.createElement(L1Panel, {
774
+ key: item2.id,
775
+ item: item2,
776
+ path: groupPath,
777
+ currentItemId
778
+ })));
779
+ };
780
+ var L1Panels = ({ topLevelItems, path, currentItemId, onBack }) => {
781
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, topLevelItems.map((item) => {
782
+ const type = l0ItemType(item);
783
+ switch (type) {
784
+ case "collection":
785
+ return /* @__PURE__ */ React8.createElement(L1PanelCollection, {
786
+ key: item.id,
787
+ item,
788
+ path,
789
+ currentItemId
790
+ });
791
+ case "tab":
792
+ return /* @__PURE__ */ React8.createElement(L1Panel, {
793
+ key: item.id,
794
+ item,
795
+ path,
796
+ currentItemId,
797
+ onBack
798
+ });
799
+ default:
800
+ return null;
801
+ }
802
+ }));
803
+ };
804
+
805
+ // packages/plugins/plugin-navtree/src/components/NavTree.tsx
806
+ var NAV_TREE_ITEM = "NavTreeItem";
807
+ var NavTree = ({ id, root }) => {
808
+ const { tab, getItems, onBack } = useNavTreeContext();
809
+ const topLevelActions = getItems(root, "item").toSorted((a, b) => byPosition(a.properties, b.properties));
810
+ const topLevelCollections = getItems(root, "collection");
811
+ const topLevelWorkspaces = getItems(root, "workspace");
812
+ const topLevelNavigation = getItems(root, "navigation");
813
+ const l0Items = useMemo4(() => [
814
+ ...topLevelActions,
815
+ ...topLevelCollections,
816
+ ...topLevelWorkspaces,
817
+ ...topLevelNavigation
818
+ ], [
819
+ topLevelActions,
820
+ topLevelCollections,
821
+ topLevelWorkspaces,
822
+ topLevelNavigation
823
+ ]);
824
+ const pinnedItems = getItems(root, "pin-end").toSorted((a, b) => byPosition(a.properties, b.properties));
825
+ const topLevelItems = useMemo4(() => [
826
+ ...l0Items,
827
+ ...pinnedItems
828
+ ], [
829
+ l0Items,
830
+ pinnedItems
831
+ ]);
832
+ useLoadDescendents(root);
833
+ const path = useMemo4(() => [
834
+ id
835
+ ], [
836
+ id
837
+ ]);
838
+ return (
839
+ // NOTE(thure): 74px (rather than rem) is intentional in order to match the size of macOS windowing controls
840
+ /* @__PURE__ */ React9.createElement(Tabs3.Root, {
841
+ value: tab,
842
+ orientation: "vertical",
843
+ verticalVariant: "stateless",
844
+ classNames: "relative"
845
+ }, /* @__PURE__ */ React9.createElement(L0Menu, {
846
+ topLevelItems: l0Items,
847
+ pinnedItems,
848
+ path,
849
+ parent: root
850
+ }), /* @__PURE__ */ React9.createElement(L1Panels, {
851
+ topLevelItems,
852
+ path,
853
+ currentItemId: tab,
854
+ onBack
855
+ }))
856
+ );
857
+ };
858
+
859
+ // packages/plugins/plugin-navtree/src/capabilities/index.ts
860
+ import { lazy } from "@dxos/app-framework";
861
+ var AppGraphBuilder = lazy(() => import("./app-graph-builder-BL7LRXCM.mjs"));
862
+ var IntentResolver = lazy(() => import("./intent-resolver-U25VBFH3.mjs"));
863
+ var Keyboard2 = lazy(() => import("./keyboard-MUBRTPI5.mjs"));
864
+ var ReactSurface = lazy(() => import("./react-surface-SIEGT4YS.mjs"));
865
+ var State = lazy(() => import("./state-IEFQTUPG.mjs"));
866
+
867
+ // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
868
+ var NODE_TYPE = "dxos/app-graph/node";
869
+ var renderItemEnd = ({ node, open }) => /* @__PURE__ */ React10.createElement(Surface, {
870
+ role: "navtree-item-end",
871
+ data: {
872
+ id: node.id,
873
+ subject: node.data,
874
+ open
875
+ },
876
+ limit: 1
877
+ });
878
+ var NavTreeContainer = /* @__PURE__ */ memo2(({ tab, popoverAnchorId, topbar }) => {
879
+ const [isLg] = useMediaQuery2("lg", {
880
+ ssr: false
881
+ });
882
+ const { dispatchPromise: dispatch } = useIntentDispatcher5();
883
+ const { graph } = useAppGraph2();
884
+ const layout = useLayout2();
885
+ const { isOpen, isCurrent, setItem } = useCapability(NavTreeCapabilities.State);
886
+ const getActions2 = useCallback2((node) => getActions(graph, node), [
887
+ graph
888
+ ]);
889
+ const getItems = useCallback2((node, disposition) => {
890
+ return graph.nodes(node ?? graph.root, {
891
+ filter: (node2) => {
892
+ return untracked(() => {
893
+ const action = isAction4(node2);
894
+ if (!disposition) {
895
+ return !action || node2.properties.disposition === "item";
896
+ }
897
+ return node2.properties.disposition === disposition;
898
+ });
899
+ }
900
+ });
901
+ }, [
902
+ graph
903
+ ]);
904
+ const getProps = useCallback2((node, path) => {
905
+ const children = getChildren(graph, node, void 0, path);
906
+ const parentOf = children.length > 0 ? children.map(({ id }) => id) : node.properties.role === "branch" ? [] : void 0;
907
+ return {
908
+ id: node.id,
909
+ label: node.properties.label ?? node.id,
910
+ parentOf,
911
+ icon: node.properties.icon,
912
+ disabled: node.properties.disabled,
913
+ className: mx6(node.properties.modified && "italic", node.properties.className),
914
+ headingClassName: node.properties.headingClassName,
915
+ testId: node.properties.testId
916
+ };
917
+ }, [
918
+ graph
919
+ ]);
920
+ const loadDescendents = useCallback2((node) => {
921
+ void expandActions(graph, node);
922
+ if (!isActionLike2(node)) {
923
+ void expandChildren(graph, node).then(() => (
924
+ // Load one level deeper, which resolves some juddering observed on open/close.
925
+ Promise.all(getChildren(graph, node).flatMap((child) => [
926
+ expandActions(graph, child),
927
+ expandChildren(graph, child)
928
+ ]))
929
+ ));
930
+ }
931
+ }, [
932
+ graph
933
+ ]);
934
+ const onOpenChange = useCallback2(({ item: { id }, path, open }) => {
935
+ setItem(path, "open", open);
936
+ if (graph) {
937
+ const node = graph.findNode(id);
938
+ return node && expandChildrenAndActions(graph, node);
939
+ }
940
+ }, [
941
+ graph
942
+ ]);
943
+ const onTabChange = useCallback2(async (node) => {
944
+ await dispatch(createIntent5(LayoutAction4.SwitchWorkspace, {
945
+ part: "workspace",
946
+ subject: node.id
947
+ }));
948
+ if (layout.active.length === 0) {
949
+ const [item] = getItems(node).filter((node2) => !isActionLike2(node2));
950
+ if (item && item.data) {
951
+ await dispatch(createIntent5(LayoutAction4.Open, {
952
+ part: "main",
953
+ subject: [
954
+ item.id
955
+ ]
956
+ }));
957
+ }
958
+ }
959
+ }, [
960
+ dispatch,
961
+ layout
962
+ ]);
963
+ const canDrop = useCallback2((source, target) => {
964
+ const sourceNode = source.item;
965
+ const targetNode = target.item;
966
+ if (isSpace(targetNode.data)) {
967
+ return isEchoObject(sourceNode.data) || isSpace(sourceNode.data);
968
+ } else if (isEchoObject(targetNode.data)) {
969
+ return isEchoObject(sourceNode.data);
970
+ } else {
971
+ return false;
972
+ }
973
+ }, []);
974
+ const handleSelect = useCallback2(({ item: node, path, option }) => {
975
+ if (!node.data) {
976
+ return;
977
+ }
978
+ if (isAction4(node)) {
979
+ const [parent] = graph.nodes(node, {
980
+ relation: "inbound"
981
+ });
982
+ void (parent && node.data({
983
+ node: parent,
984
+ caller: NAV_TREE_ITEM
985
+ }));
986
+ return;
987
+ }
988
+ const current = isCurrent(path, node);
989
+ if (!current) {
990
+ void dispatch(createIntent5(LayoutAction4.Open, {
991
+ part: "main",
992
+ subject: [
993
+ node.id
994
+ ],
995
+ options: {
996
+ key: node.properties.key
997
+ }
998
+ }));
999
+ } else if (option) {
1000
+ void dispatch(createIntent5(LayoutAction4.Close, {
1001
+ part: "main",
1002
+ subject: [
1003
+ node.id
1004
+ ],
1005
+ options: {
1006
+ state: false
1007
+ }
1008
+ }));
1009
+ } else {
1010
+ void dispatch(createIntent5(LayoutAction4.ScrollIntoView, {
1011
+ part: "current",
1012
+ subject: node.id
1013
+ }));
1014
+ }
1015
+ const defaultAction = graph.actions(node).find((action) => action.properties?.disposition === "default");
1016
+ if (isAction4(defaultAction)) {
1017
+ void defaultAction.data();
1018
+ }
1019
+ if (!isLg) {
1020
+ void dispatch(createIntent5(LayoutAction4.UpdateSidebar, {
1021
+ part: "sidebar",
1022
+ options: {
1023
+ state: "closed"
1024
+ }
1025
+ }));
1026
+ }
1027
+ }, [
1028
+ graph,
1029
+ dispatch,
1030
+ isCurrent,
1031
+ isLg
1032
+ ]);
1033
+ const onBack = useCallback2(() => dispatch(createIntent5(LayoutAction4.RevertWorkspace, {
1034
+ part: "workspace",
1035
+ options: {
1036
+ revert: true
1037
+ }
1038
+ })), [
1039
+ dispatch
1040
+ ]);
1041
+ useEffect3(() => {
1042
+ return monitorForElements({
1043
+ canMonitor: ({ source }) => isTreeData(source.data),
1044
+ onDrop: ({ location, source }) => {
1045
+ if (!location.current.dropTargets.length) {
1046
+ return;
1047
+ }
1048
+ const target = location.current.dropTargets[0];
1049
+ const instruction = extractInstruction(target.data);
1050
+ if (instruction !== null && instruction.type !== "instruction-blocked") {
1051
+ const sourceNode = source.data.item;
1052
+ const targetNode = target.data.item;
1053
+ const sourcePath = source.data.path;
1054
+ const targetPath = target.data.path;
1055
+ const operation = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== "make-child" ? "rearrange" : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
1056
+ const sourceParent = getParent(graph, sourceNode, sourcePath);
1057
+ const targetParent = getParent(graph, targetNode, targetPath);
1058
+ const sourceItems = getItems(sourceParent);
1059
+ const targetItems = getItems(targetParent);
1060
+ const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
1061
+ const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
1062
+ const migrationIndex = instruction.type === "make-child" ? void 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
1063
+ switch (operation) {
1064
+ case "rearrange": {
1065
+ const nextItems = sourceItems.map(({ data }) => data);
1066
+ arrayMove(nextItems, sourceIndex, targetIndex);
1067
+ void sourceParent?.properties.onRearrangeChildren?.(nextItems);
1068
+ break;
1069
+ }
1070
+ case "copy": {
1071
+ const target2 = instruction.type === "make-child" ? targetNode : targetParent;
1072
+ void target2?.properties.onCopy?.(sourceNode, migrationIndex);
1073
+ break;
1074
+ }
1075
+ case "transfer": {
1076
+ const target2 = instruction.type === "make-child" ? targetNode : targetParent;
1077
+ if (!target2?.properties.onTransferStart || !sourceParent?.properties.onTransferEnd) {
1078
+ break;
1079
+ }
1080
+ void target2?.properties.onTransferStart(sourceNode, migrationIndex);
1081
+ void sourceParent?.properties.onTransferEnd?.(sourceNode, target2);
1082
+ break;
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+ });
1088
+ }, [
1089
+ graph
1090
+ ]);
1091
+ const navTreeContextValue = useMemo5(() => ({
1092
+ tab,
1093
+ onTabChange,
1094
+ onBack,
1095
+ getActions: getActions2,
1096
+ loadDescendents,
1097
+ renderItemEnd,
1098
+ popoverAnchorId,
1099
+ topbar,
1100
+ getItems,
1101
+ getProps,
1102
+ isCurrent,
1103
+ isOpen,
1104
+ onOpenChange,
1105
+ canDrop,
1106
+ onSelect: handleSelect
1107
+ }), [
1108
+ tab,
1109
+ onTabChange,
1110
+ onBack,
1111
+ getActions2,
1112
+ loadDescendents,
1113
+ renderItemEnd,
1114
+ popoverAnchorId,
1115
+ topbar,
1116
+ getItems,
1117
+ getProps,
1118
+ isCurrent,
1119
+ isOpen,
1120
+ onOpenChange,
1121
+ canDrop,
1122
+ handleSelect
1123
+ ]);
1124
+ return /* @__PURE__ */ React10.createElement(NavTreeContext.Provider, {
1125
+ value: navTreeContextValue
1126
+ }, /* @__PURE__ */ React10.createElement(NavTree, {
1127
+ root: graph.root,
1128
+ id: graph.root.id
1129
+ }));
1130
+ });
1131
+
1132
+ export {
1133
+ CommandsDialogContent,
1134
+ CommandsTrigger,
1135
+ NotchStart,
1136
+ getParent,
1137
+ getPersistenceParent,
1138
+ resolveMigrationOperation,
1139
+ sortActions,
1140
+ getChildren,
1141
+ getActions,
1142
+ expandChildrenAndActions,
1143
+ expandChildren,
1144
+ expandActions,
1145
+ l0ItemType,
1146
+ getFirstTwoRenderableChars,
1147
+ NODE_TYPE,
1148
+ NavTreeContainer,
1149
+ NavTreeDocumentTitle,
1150
+ AppGraphBuilder,
1151
+ IntentResolver,
1152
+ Keyboard2 as Keyboard,
1153
+ ReactSurface,
1154
+ State
1155
+ };
1156
+ //# sourceMappingURL=chunk-7OKF4GP3.mjs.map