@dxos/plugin-navtree 0.6.14-main.7bd9c89 → 0.6.14-main.f49f251

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 (46) hide show
  1. package/dist/lib/browser/index.mjs +576 -386
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  5. package/dist/types/src/components/NavTree.d.ts +20 -0
  6. package/dist/types/src/components/NavTree.d.ts.map +1 -0
  7. package/dist/types/src/components/NavTree.stories.d.ts +7 -0
  8. package/dist/types/src/components/NavTree.stories.d.ts.map +1 -0
  9. package/dist/types/src/components/NavTreeContainer.d.ts +8 -8
  10. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  11. package/dist/types/src/components/NavTreeItemAction.d.ts +23 -0
  12. package/dist/types/src/components/NavTreeItemAction.d.ts.map +1 -0
  13. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +45 -0
  14. package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +1 -0
  15. package/dist/types/src/components/index.d.ts +1 -0
  16. package/dist/types/src/components/index.d.ts.map +1 -1
  17. package/dist/types/src/stories/Graph.stories.d.ts +1 -6
  18. package/dist/types/src/stories/Graph.stories.d.ts.map +1 -1
  19. package/dist/types/src/testing/generator.d.ts +86 -0
  20. package/dist/types/src/testing/generator.d.ts.map +1 -0
  21. package/dist/types/src/testing/index.d.ts +3 -0
  22. package/dist/types/src/testing/index.d.ts.map +1 -0
  23. package/dist/types/src/testing/visitor.d.ts +18 -0
  24. package/dist/types/src/testing/visitor.d.ts.map +1 -0
  25. package/dist/types/src/translations.d.ts +5 -10
  26. package/dist/types/src/translations.d.ts.map +1 -1
  27. package/dist/types/src/types.d.ts +41 -0
  28. package/dist/types/src/types.d.ts.map +1 -0
  29. package/dist/types/src/util.d.ts +8 -9
  30. package/dist/types/src/util.d.ts.map +1 -1
  31. package/package.json +36 -32
  32. package/src/NavTreePlugin.tsx +88 -33
  33. package/src/components/NavTree.stories.tsx +104 -0
  34. package/src/components/NavTree.tsx +127 -0
  35. package/src/components/NavTreeContainer.tsx +141 -325
  36. package/src/components/NavTreeItemAction.stories.tsx +57 -0
  37. package/src/components/NavTreeItemAction.tsx +367 -0
  38. package/src/components/index.ts +1 -0
  39. package/src/experimental/Tree.stories.tsx +1 -1
  40. package/src/stories/Graph.stories.tsx +104 -98
  41. package/src/testing/generator.ts +199 -0
  42. package/src/testing/index.ts +6 -0
  43. package/src/testing/visitor.ts +152 -0
  44. package/src/translations.ts +3 -3
  45. package/src/types.ts +50 -0
  46. package/src/util.ts +52 -63
@@ -5,13 +5,14 @@ import {
5
5
  } from "./chunk-PSVCPL4T.mjs";
6
6
 
7
7
  // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
8
- import React8 from "react";
8
+ import React10 from "react";
9
9
  import { resolvePlugin, parseIntentPlugin, LayoutAction as LayoutAction3, parseGraphPlugin, NavigationAction as NavigationAction2 } from "@dxos/app-framework";
10
- import { createExtension, isAction as isAction4, isGraphNode } from "@dxos/app-graph";
10
+ import { createExtension, isAction as isAction5, isGraphNode } from "@dxos/app-graph";
11
+ import { invariant } from "@dxos/invariant";
11
12
  import { Keyboard as Keyboard2 } from "@dxos/keyboard";
12
13
  import { LocalStorageStore } from "@dxos/local-storage";
13
- import { Path as Path3 } from "@dxos/react-ui-mosaic";
14
- import { getHostPlatform as getHostPlatform2 } from "@dxos/util";
14
+ import { Path as Path2 } from "@dxos/react-ui-mosaic";
15
+ import { getHostPlatform as getHostPlatform3 } from "@dxos/util";
15
16
 
16
17
  // packages/plugins/plugin-navtree/src/components/CommandsDialog.tsx
17
18
  import React, { useMemo, useState } from "react";
@@ -146,96 +147,412 @@ var NavBarStart = ({ activeNode, popoverAnchorId }) => {
146
147
  }, label));
147
148
  };
148
149
 
150
+ // packages/plugins/plugin-navtree/src/components/NavTree.tsx
151
+ import React4, { Fragment as Fragment2, useCallback, useEffect } from "react";
152
+ import { isAction as isAction2 } from "@dxos/app-graph";
153
+ import { Popover as Popover2, toLocalizedString as toLocalizedString4, Treegrid, useTranslation as useTranslation4 } from "@dxos/react-ui";
154
+ import { Tree } from "@dxos/react-ui-list";
155
+
156
+ // packages/plugins/plugin-navtree/src/components/NavTreeItemAction.tsx
157
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
158
+ import React3, { useRef, useState as useState2 } from "react";
159
+ import { keySymbols as keySymbols2 } from "@dxos/keyboard";
160
+ import { Button as Button2, Dialog as Dialog2, DropdownMenu, ContextMenu, Tooltip, useTranslation as useTranslation3, toLocalizedString as toLocalizedString3, Icon as Icon2 } from "@dxos/react-ui";
161
+ import { SearchList as SearchList2 } from "@dxos/react-ui-searchlist";
162
+ import { descriptionText as descriptionText2, hoverableControlItem, hoverableOpenControlItem, mx as mx2 } from "@dxos/react-ui-theme";
163
+ import { getHostPlatform as getHostPlatform2 } from "@dxos/util";
164
+ var getShortcut = (action) => {
165
+ return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform2()];
166
+ };
167
+ var fallbackIcon = "ph--placeholder--regular";
168
+ var NavTreeItemActionDropdownMenu = ({ label, icon, testId, defaultMenuOpen, menuActions, menuOpen, suppressNextTooltip, onChangeMenuOpen, onAction }) => {
169
+ const { t } = useTranslation3(NAVTREE_PLUGIN);
170
+ const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
171
+ prop: menuOpen,
172
+ defaultProp: defaultMenuOpen,
173
+ onChange: onChangeMenuOpen
174
+ });
175
+ return /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
176
+ open: optionsMenuOpen,
177
+ onOpenChange: (nextOpen) => {
178
+ if (!nextOpen && suppressNextTooltip) {
179
+ suppressNextTooltip.current = true;
180
+ }
181
+ return setOptionsMenuOpen(nextOpen);
182
+ }
183
+ }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
184
+ asChild: true
185
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
186
+ asChild: true
187
+ }, /* @__PURE__ */ React3.createElement(Button2, {
188
+ variant: "ghost",
189
+ density: "fine",
190
+ classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
191
+ "data-testid": testId,
192
+ "aria-label": t("tree item actions label")
193
+ }, /* @__PURE__ */ React3.createElement("span", {
194
+ className: "sr-only"
195
+ }, toLocalizedString3(label, t)), /* @__PURE__ */ React3.createElement(Icon2, {
196
+ icon: icon ?? fallbackIcon,
197
+ size: 4
198
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
199
+ classNames: "z-[31]"
200
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, menuActions?.map((action) => {
201
+ const shortcut = getShortcut(action);
202
+ return /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
203
+ key: action.id,
204
+ onClick: (event) => {
205
+ if (action.properties?.disabled) {
206
+ return;
207
+ }
208
+ event.stopPropagation();
209
+ if (suppressNextTooltip) {
210
+ suppressNextTooltip.current = true;
211
+ }
212
+ setOptionsMenuOpen(false);
213
+ onAction?.(action);
214
+ },
215
+ classNames: "gap-2",
216
+ disabled: action.properties?.disabled,
217
+ ...action.properties?.testId && {
218
+ "data-testid": action.properties.testId
219
+ }
220
+ }, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon2, {
221
+ icon: action.properties.icon,
222
+ size: 4
223
+ }), /* @__PURE__ */ React3.createElement("span", {
224
+ className: "grow truncate"
225
+ }, toLocalizedString3(action.properties.label, t)), shortcut && /* @__PURE__ */ React3.createElement("span", {
226
+ className: mx2("shrink-0", descriptionText2)
227
+ }, keySymbols2(shortcut).join("")));
228
+ })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null))));
229
+ };
230
+ var NavTreeItemActionSearchList = ({ menuActions, icon, label, testId, suppressNextTooltip, onAction }) => {
231
+ const { t } = useTranslation3(NAVTREE_PLUGIN);
232
+ const [optionsMenuOpen, setOptionsMenuOpen] = useState2(false);
233
+ const button = useRef(null);
234
+ const sortedActions = menuActions?.sort(({ properties: p1 }, { properties: p2 }) => {
235
+ const t1 = toLocalizedString3(p1.label, t).toLowerCase();
236
+ const t2 = toLocalizedString3(p2.label, t).toLowerCase();
237
+ return t1.localeCompare(t2);
238
+ });
239
+ return /* @__PURE__ */ React3.createElement(Dialog2.Root, {
240
+ open: optionsMenuOpen,
241
+ onOpenChange: (nextOpen) => {
242
+ if (!nextOpen && suppressNextTooltip) {
243
+ suppressNextTooltip.current = true;
244
+ }
245
+ return setOptionsMenuOpen(nextOpen);
246
+ }
247
+ }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
248
+ asChild: true
249
+ }, /* @__PURE__ */ React3.createElement(Dialog2.Trigger, {
250
+ asChild: true
251
+ }, /* @__PURE__ */ React3.createElement(Button2, {
252
+ variant: "ghost",
253
+ density: "fine",
254
+ classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
255
+ "data-testid": testId,
256
+ onKeyDownCapture: (event) => {
257
+ if (button.current && button.current === event.target) {
258
+ switch (event.key) {
259
+ case "Enter":
260
+ case " ":
261
+ event.stopPropagation();
262
+ setOptionsMenuOpen(true);
263
+ break;
264
+ default:
265
+ }
266
+ }
267
+ },
268
+ ref: button
269
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
270
+ icon: icon ?? fallbackIcon,
271
+ size: 4
272
+ })))), /* @__PURE__ */ React3.createElement(Dialog2.Portal, null, /* @__PURE__ */ React3.createElement(Dialog2.Overlay, null, /* @__PURE__ */ React3.createElement(Dialog2.Content, {
273
+ classNames: "z-[31] is-full max-is-[24rem] pli-2 plb-1"
274
+ }, /* @__PURE__ */ React3.createElement(SearchList2.Root, {
275
+ label: t("tree item searchlist input placeholder")
276
+ }, /* @__PURE__ */ React3.createElement(SearchList2.Input, {
277
+ placeholder: t("tree item searchlist input placeholder"),
278
+ classNames: "pli-3"
279
+ }), /* @__PURE__ */ React3.createElement(SearchList2.Content, {
280
+ classNames: "min-bs-[12rem] bs-[50dvh] max-bs-[30rem] overflow-auto"
281
+ }, sortedActions?.map((action) => {
282
+ const label2 = toLocalizedString3(action.properties.label, t);
283
+ const shortcut = getShortcut(action);
284
+ return /* @__PURE__ */ React3.createElement(SearchList2.Item, {
285
+ // TODO(burdon): Value should be id since label is not unique.
286
+ value: label2,
287
+ key: action.id,
288
+ onSelect: () => {
289
+ if (action.properties?.disabled) {
290
+ return;
291
+ }
292
+ if (suppressNextTooltip) {
293
+ suppressNextTooltip.current = true;
294
+ }
295
+ setOptionsMenuOpen(false);
296
+ onAction?.(action);
297
+ },
298
+ classNames: "flex items-center gap-2 pli-2",
299
+ disabled: action.properties?.disabled,
300
+ ...action.properties?.testId && {
301
+ "data-testid": action.properties.testId
302
+ }
303
+ }, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon2, {
304
+ icon: action.properties?.icon,
305
+ size: 4
306
+ }), /* @__PURE__ */ React3.createElement("span", {
307
+ className: "grow truncate"
308
+ }, label2), shortcut && /* @__PURE__ */ React3.createElement("span", {
309
+ className: mx2("shrink-0", descriptionText2)
310
+ }, keySymbols2(shortcut).join("")));
311
+ })), /* @__PURE__ */ React3.createElement("div", {
312
+ role: "none",
313
+ className: "flex items-center plb-2 pli-3"
314
+ }, /* @__PURE__ */ React3.createElement("span", {
315
+ className: descriptionText2
316
+ }, toLocalizedString3(label, t))))))));
317
+ };
318
+ var NavTreeItemMonolithicAction = ({ parent, properties: { disabled, caller, testId, label, icon } = {
319
+ label: "never"
320
+ }, data: invoke }) => {
321
+ const { t } = useTranslation3(NAVTREE_PLUGIN);
322
+ return /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
323
+ asChild: true
324
+ }, /* @__PURE__ */ React3.createElement(Button2, {
325
+ variant: "ghost",
326
+ density: "fine",
327
+ classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
328
+ disabled,
329
+ onClick: (event) => {
330
+ if (disabled) {
331
+ return;
332
+ }
333
+ event.stopPropagation();
334
+ void invoke?.(caller ? {
335
+ node: parent,
336
+ caller
337
+ } : {
338
+ node: parent
339
+ });
340
+ },
341
+ "data-testid": testId
342
+ }, /* @__PURE__ */ React3.createElement("span", {
343
+ className: "sr-only"
344
+ }, toLocalizedString3(label, t)), /* @__PURE__ */ React3.createElement(Icon2, {
345
+ icon: icon ?? fallbackIcon,
346
+ size: 4
347
+ })));
348
+ };
349
+ var NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...props }) => {
350
+ const { t } = useTranslation3(NAVTREE_PLUGIN);
351
+ const suppressNextTooltip = useRef(false);
352
+ const [triggerTooltipOpen, setTriggerTooltipOpen] = useState2(false);
353
+ const monolithicAction = menuActions?.length === 1 && menuActions[0];
354
+ const baseLabel = toLocalizedString3(monolithicAction ? monolithicAction.properties.label : props.label, t);
355
+ return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
356
+ open: triggerTooltipOpen,
357
+ onOpenChange: (nextOpen) => {
358
+ if (suppressNextTooltip.current) {
359
+ setTriggerTooltipOpen(false);
360
+ suppressNextTooltip.current = false;
361
+ } else {
362
+ setTriggerTooltipOpen(nextOpen);
363
+ }
364
+ }
365
+ }, baseLabel && /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, {
366
+ classNames: "z-[31]",
367
+ side: "bottom"
368
+ }, baseLabel, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))), monolithic && menuActions?.length === 1 ? /* @__PURE__ */ React3.createElement(NavTreeItemMonolithicAction, {
369
+ parent: node,
370
+ ...menuActions[0]
371
+ }) : props.menuType === "searchList" ? /* @__PURE__ */ React3.createElement(NavTreeItemActionSearchList, {
372
+ ...props,
373
+ menuActions,
374
+ suppressNextTooltip,
375
+ onAction: (action) => action.data?.(props.caller ? {
376
+ node,
377
+ caller: props.caller
378
+ } : {
379
+ node
380
+ })
381
+ }) : /* @__PURE__ */ React3.createElement(NavTreeItemActionDropdownMenu, {
382
+ ...props,
383
+ parent: node,
384
+ menuActions,
385
+ suppressNextTooltip,
386
+ onAction: (action) => action.data?.(props.caller ? {
387
+ node,
388
+ caller: props.caller
389
+ } : {
390
+ node
391
+ })
392
+ }));
393
+ };
394
+
395
+ // packages/plugins/plugin-navtree/src/components/NavTree.tsx
396
+ var NAV_TREE_ITEM = "NavTreeItem";
397
+ var NavTree = ({ loadDescendents, renderPresence: renderPresence2, popoverAnchorId, ...props }) => {
398
+ const renderColumns = useCallback(({ item, menuOpen, setMenuOpen }) => {
399
+ return /* @__PURE__ */ React4.createElement(NavTreeColumns, {
400
+ item,
401
+ menuOpen,
402
+ setMenuOpen,
403
+ loadDescendents,
404
+ renderPresence: renderPresence2,
405
+ popoverAnchorId
406
+ });
407
+ }, [
408
+ renderPresence2,
409
+ popoverAnchorId,
410
+ loadDescendents
411
+ ]);
412
+ return /* @__PURE__ */ React4.createElement(Tree, {
413
+ ...props,
414
+ draggable: true,
415
+ gridTemplateColumns: "[tree-row-start] 1fr min-content min-content min-content [tree-row-end]",
416
+ classNames: "pbs-1",
417
+ renderColumns
418
+ });
419
+ };
420
+ var NavTreeColumns = ({ item, menuOpen, setMenuOpen, loadDescendents, renderPresence: Presence, popoverAnchorId }) => {
421
+ const { t } = useTranslation4(NAVTREE_PLUGIN);
422
+ const level = item.path.length - 2;
423
+ const [primaryAction, ...secondaryActions] = item.actions.toSorted((a, b) => a.properties?.disposition === "toolbar" ? -1 : 1);
424
+ const actions = (primaryAction?.properties?.disposition === "toolbar" ? secondaryActions : item.actions).flatMap((action) => isAction2(action) ? [
425
+ action
426
+ ] : []).filter((action) => !action.properties?.hidden);
427
+ const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover2.Anchor : Fragment2;
428
+ useEffect(() => {
429
+ const frame = requestAnimationFrame(() => {
430
+ void loadDescendents?.(item.node);
431
+ if (primaryAction && !isAction2(primaryAction)) {
432
+ void loadDescendents?.(primaryAction);
433
+ }
434
+ });
435
+ return () => cancelAnimationFrame(frame);
436
+ }, [
437
+ primaryAction
438
+ ]);
439
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, primaryAction?.properties?.disposition === "toolbar" ? /* @__PURE__ */ React4.createElement(NavTreeItemAction, {
440
+ testId: primaryAction.properties?.testId,
441
+ label: toLocalizedString4(primaryAction.properties?.label, t),
442
+ icon: primaryAction.properties?.icon ?? "ph--placeholder--regular",
443
+ parent: item.node,
444
+ monolithic: isAction2(primaryAction),
445
+ menuActions: isAction2(primaryAction) ? [
446
+ primaryAction
447
+ ] : item.groupedActions[primaryAction.id],
448
+ menuType: primaryAction.properties?.menuType,
449
+ caller: NAV_TREE_ITEM
450
+ }) : /* @__PURE__ */ React4.createElement(Treegrid.Cell, null), /* @__PURE__ */ React4.createElement(ActionRoot, null, actions.length > 0 ? /* @__PURE__ */ React4.createElement(NavTreeItemAction, {
451
+ testId: `navtree.treeItem.actionsLevel${level}`,
452
+ label: t("tree item actions label"),
453
+ icon: "ph--dots-three-vertical--regular",
454
+ parent: item.node,
455
+ menuActions: actions,
456
+ menuType: "dropdown",
457
+ caller: NAV_TREE_ITEM,
458
+ menuOpen,
459
+ onChangeMenuOpen: setMenuOpen
460
+ }) : /* @__PURE__ */ React4.createElement(Treegrid.Cell, null)), Presence && /* @__PURE__ */ React4.createElement(Presence, {
461
+ item
462
+ }));
463
+ };
464
+
149
465
  // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
150
- import React4, { useCallback, useMemo as useMemo2 } from "react";
466
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
467
+ import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
468
+ import React6, { useCallback as useCallback2, useEffect as useEffect2 } from "react";
151
469
  import { NavigationAction, Surface, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
152
- import { getGraph as getGraph2, isAction as isAction3, isActionLike } from "@dxos/app-graph";
470
+ import { isAction as isAction4, isActionLike } from "@dxos/app-graph";
471
+ import { useGraph as useGraph2 } from "@dxos/plugin-graph";
472
+ import { isEchoObject, isSpace } from "@dxos/react-client/echo";
153
473
  import { ElevationProvider, useMediaQuery, useSidebars as useSidebars2 } from "@dxos/react-ui";
154
- import { List } from "@dxos/react-ui-list";
155
- import { Mosaic, Path as Path2 } from "@dxos/react-ui-mosaic";
156
- import { getLevel, NavTree } from "@dxos/react-ui-navtree";
157
- import { ghostHover, mx as mx3 } from "@dxos/react-ui-theme";
474
+ import { isItem } from "@dxos/react-ui-list";
158
475
  import { arrayMove } from "@dxos/util";
159
476
 
160
477
  // packages/plugins/plugin-navtree/src/components/NavTreeFooter.tsx
161
478
  import { ArrowSquareOut, GearSix, Warning } from "@phosphor-icons/react";
162
479
  import { formatDistance } from "date-fns/formatDistance";
163
- import React3 from "react";
480
+ import React5 from "react";
164
481
  import { SettingsAction, useResolvePlugin, parseNavigationPlugin, useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
165
482
  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";
483
+ import { Button as Button3, Tooltip as Tooltip2, Popover as Popover3, useSidebars, useTranslation as useTranslation5, Link, Message, Trans, useDefaultValue } from "@dxos/react-ui";
167
484
  import { PlankHeading as PlankHeading2 } from "@dxos/react-ui-deck";
168
- import { getSize, mx as mx2 } from "@dxos/react-ui-theme";
485
+ import { getSize, mx as mx3 } from "@dxos/react-ui-theme";
169
486
  var buttonStyles = "pli-1.5 text-xs font-normal";
170
487
  var repo = "https://github.com/dxos/dxos";
171
488
  var NavTreeFooter = (props) => {
172
489
  const layoutPart = useDefaultValue(props.layoutPart, () => "sidebar");
173
490
  const config = useConfig();
174
- const { t } = useTranslation3(NAVTREE_PLUGIN);
491
+ const { t } = useTranslation5(NAVTREE_PLUGIN);
175
492
  const { navigationSidebarOpen } = useSidebars(NAVTREE_PLUGIN);
176
493
  const dispatch = useIntentDispatcher2();
177
494
  const { version, timestamp, commitHash } = config.values.runtime?.app?.build ?? {};
178
495
  const navigationPlugin = useResolvePlugin(parseNavigationPlugin);
179
496
  const releaseUrl = config.values.runtime?.app?.env?.DX_ENVIRONMENT === "production" ? `${repo}/releases/tag/v${version}` : `${repo}/commit/${commitHash}`;
180
497
  const previewUrl = "https://docs.dxos.org/composer#technology-preview";
181
- return /* @__PURE__ */ React3.createElement("div", {
498
+ return /* @__PURE__ */ React5.createElement("div", {
182
499
  role: "none",
183
- className: mx2("bs-[--rail-size] pbe-[env(safe-area-inset-bottom)] box-content border-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, {
500
+ className: mx3("bs-[--rail-size] pbe-[env(safe-area-inset-bottom)] box-content border-separator border-bs pli-1 flex justify-end", layoutPart === "complementary" && "md:justify-end flex-row-reverse")
501
+ }, /* @__PURE__ */ React5.createElement(Popover3.Root, null, /* @__PURE__ */ React5.createElement(Popover3.Trigger, {
185
502
  asChild: true
186
- }, /* @__PURE__ */ React3.createElement(Button2, {
503
+ }, /* @__PURE__ */ React5.createElement(Button3, {
187
504
  variant: "ghost",
188
505
  classNames: buttonStyles,
189
506
  ...!navigationSidebarOpen && {
190
507
  tabIndex: -1
191
508
  }
192
- }, "v", version)), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
509
+ }, "v", version)), /* @__PURE__ */ React5.createElement(Popover3.Portal, null, /* @__PURE__ */ React5.createElement(Popover3.Content, {
193
510
  side: "top",
194
511
  role: "message",
195
512
  classNames: "z-[12] bg-warning-500 max-is-[min(calc(100vw-16px),40ch)]"
196
- }, /* @__PURE__ */ React3.createElement(Message.Root, {
513
+ }, /* @__PURE__ */ React5.createElement(Message.Root, {
197
514
  valence: "warning",
198
515
  className: "rounded-be-none p-5"
199
- }, /* @__PURE__ */ React3.createElement(Message.Title, null, /* @__PURE__ */ React3.createElement(Warning, {
516
+ }, /* @__PURE__ */ React5.createElement(Message.Title, null, /* @__PURE__ */ React5.createElement(Warning, {
200
517
  weight: "duotone",
201
518
  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, {
519
+ }), /* @__PURE__ */ React5.createElement("span", null, t("warning title"))), /* @__PURE__ */ React5.createElement(Message.Body, null, t("technology preview message"), /* @__PURE__ */ React5.createElement("br", null), /* @__PURE__ */ React5.createElement(Link, {
203
520
  href: previewUrl,
204
521
  target: "_blank",
205
522
  rel: "noreferrer",
206
523
  variant: "neutral"
207
- }, t("learn more label"), /* @__PURE__ */ React3.createElement(ArrowSquareOut, {
524
+ }, t("learn more label"), /* @__PURE__ */ React5.createElement(ArrowSquareOut, {
208
525
  className: "inline mis-1",
209
526
  weight: "bold"
210
- })))), /* @__PURE__ */ React3.createElement("div", {
527
+ })))), /* @__PURE__ */ React5.createElement("div", {
211
528
  role: "none",
212
529
  className: "plb-4 pli-5 space-b-2 text-baseText"
213
- }, timestamp && /* @__PURE__ */ React3.createElement("p", null, t("released message", {
530
+ }, timestamp && /* @__PURE__ */ React5.createElement("p", null, t("released message", {
214
531
  released: formatDistance(new Date(timestamp), /* @__PURE__ */ new Date(), {
215
532
  addSuffix: true
216
533
  })
217
- }), /* @__PURE__ */ React3.createElement("br", null), /* @__PURE__ */ React3.createElement(Link, {
534
+ }), /* @__PURE__ */ React5.createElement("br", null), /* @__PURE__ */ React5.createElement(Link, {
218
535
  href: releaseUrl,
219
536
  target: "_blank",
220
537
  rel: "noreferrer",
221
538
  variant: "neutral"
222
- }, t("see release label"), /* @__PURE__ */ React3.createElement(ArrowSquareOut, {
539
+ }, t("see release label"), /* @__PURE__ */ React5.createElement(ArrowSquareOut, {
223
540
  className: "inline mis-1",
224
541
  weight: "bold"
225
- }))), /* @__PURE__ */ React3.createElement("p", null, /* @__PURE__ */ React3.createElement(Trans, {
542
+ }))), /* @__PURE__ */ React5.createElement("p", null, /* @__PURE__ */ React5.createElement(Trans, {
226
543
  t,
227
544
  i18nKey: "powered by dxos message",
228
545
  components: {
229
- dxos: /* @__PURE__ */ React3.createElement(Link, {
546
+ dxos: /* @__PURE__ */ React5.createElement(Link, {
230
547
  href: "https://dxos.org",
231
548
  target: "_blank",
232
549
  rel: "noreferrer",
233
550
  variant: "neutral"
234
551
  })
235
552
  }
236
- }))), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
553
+ }))), /* @__PURE__ */ React5.createElement(Popover3.Arrow, null)))), /* @__PURE__ */ React5.createElement(Tooltip2.Root, null, /* @__PURE__ */ React5.createElement(Tooltip2.Trigger, {
237
554
  asChild: true
238
- }, /* @__PURE__ */ React3.createElement(Button2, {
555
+ }, /* @__PURE__ */ React5.createElement(Button3, {
239
556
  variant: "ghost",
240
557
  classNames: buttonStyles,
241
558
  "data-testid": "treeView.openSettings",
@@ -246,13 +563,13 @@ var NavTreeFooter = (props) => {
246
563
  onClick: () => dispatch({
247
564
  action: SettingsAction.OPEN
248
565
  })
249
- }, /* @__PURE__ */ React3.createElement("span", {
566
+ }, /* @__PURE__ */ React5.createElement("span", {
250
567
  className: "sr-only"
251
- }, t("open settings label")), /* @__PURE__ */ React3.createElement(GearSix, {
252
- className: mx2(getSize(4), "rotate-90")
253
- }))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, {
568
+ }, t("open settings label")), /* @__PURE__ */ React5.createElement(GearSix, {
569
+ className: mx3(getSize(4), "rotate-90")
570
+ }))), /* @__PURE__ */ React5.createElement(Tooltip2.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip2.Content, {
254
571
  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, {
572
+ }, t("open settings label"), /* @__PURE__ */ React5.createElement(Tooltip2.Arrow, null)))), navigationPlugin?.meta.id === "dxos.org/plugin/deck" && /* @__PURE__ */ React5.createElement(PlankHeading2.Controls, {
256
573
  variant: "hide-disabled",
257
574
  capabilities: {
258
575
  incrementStart: false,
@@ -264,7 +581,7 @@ var NavTreeFooter = (props) => {
264
581
  };
265
582
 
266
583
  // packages/plugins/plugin-navtree/src/util.ts
267
- import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction2 } from "@dxos/app-graph";
584
+ import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction3 } from "@dxos/app-graph";
268
585
  import { Path } from "@dxos/react-ui-mosaic";
269
586
  import { nonNullable } from "@dxos/util";
270
587
  var getParent = (graph, node, path) => {
@@ -288,7 +605,7 @@ var resolveMigrationOperation = (graph, activeNode, destinationPath, destination
288
605
  if (persistenceParent) {
289
606
  const activeKey = activeNode.properties.persistenceKey;
290
607
  if (activeKey && persistenceParent?.properties.acceptPersistenceKey) {
291
- return persistenceParent.properties.acceptPersistenceKey.has(activeKey) && destinationRelatedNode.properties.onTransferStart ? "transfer" : destinationRelatedNode.properties.onCopy ? "copy" : "reject";
608
+ return persistenceParent.properties.acceptPersistenceKey.has(activeKey) && persistenceParent.properties.onTransferStart ? "transfer" : persistenceParent.properties.onCopy ? "copy" : "reject";
292
609
  } else {
293
610
  return "reject";
294
611
  }
@@ -330,8 +647,11 @@ var getChildren = (graph, node, filter, path = []) => {
330
647
  };
331
648
  var getActions = (graph, node) => {
332
649
  return graph.actions(node).reduce((acc, arg) => {
650
+ if (arg.properties.disposition === "item") {
651
+ return acc;
652
+ }
333
653
  acc.actions.push(arg);
334
- if (!isAction2(arg)) {
654
+ if (!isAction3(arg)) {
335
655
  const actionGroup = graph.actions(arg);
336
656
  acc.groupedActions[arg.id] = actionGroup;
337
657
  }
@@ -356,80 +676,65 @@ var expandActions = (graph, node) => {
356
676
  graph.expand(node, "outbound", ACTION_GROUP_TYPE)
357
677
  ]);
358
678
  };
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);
679
+ function* navTreeItemVisitor({ graph, node, open, getItem, path = [], filter }) {
362
680
  const stack = [
363
- {
364
- id: node.id,
365
- node,
366
- path: [],
367
- parentOf: (l0Children ?? []).map(({ id }) => id),
368
- actions: l0Actions,
369
- groupedActions: l0GroupedActions
370
- }
681
+ getItem(node, path, filter)
371
682
  ];
372
683
  while (stack.length > 0) {
373
684
  const nextItem = stack.pop();
374
- if ((nextItem.path?.length ?? 0) > 0) {
685
+ if (nextItem.path.length > 1) {
375
686
  yield nextItem;
376
687
  }
377
- const { id, node: node2, path: path2 } = nextItem;
688
+ const { node: node2, path: path2 } = nextItem;
378
689
  const children = getChildren(graph, node2, filter, path2);
379
- if (path2?.length === 0 || (id ?? "never") in openItemIds) {
690
+ const actions = graph.actions(node2);
691
+ if (path2.length === 1 || open.includes(Path.create(...path2))) {
692
+ for (let i = actions.length - 1; i >= 0; i--) {
693
+ if (actions[i].properties.disposition === "item") {
694
+ stack.push(getItem(actions[i], path2, filter));
695
+ }
696
+ }
380
697
  for (let i = children.length - 1; i >= 0; i--) {
381
698
  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
- });
699
+ stack.push(getItem(child, path2, filter));
400
700
  }
401
701
  }
402
702
  }
403
703
  }
404
- var treeItemsFromRootNode = (graph, rootNode, openItemIds, path = [], filter) => {
405
- return Array.from(navTreeItemVisitor(graph, rootNode, openItemIds, path, filter));
704
+ var treeItemsFromRootNode = (graph, rootNode, open, getItem, path, filter) => {
705
+ return Array.from(navTreeItemVisitor({
706
+ graph,
707
+ node: rootNode,
708
+ open,
709
+ getItem,
710
+ path,
711
+ filter
712
+ }));
406
713
  };
407
- var expandOpenGraphNodes = (graph, openItemIds) => {
408
- return Promise.all(Object.keys(openItemIds).map((openItemId) => {
409
- const node = graph.findNode(Path.last(openItemId));
714
+ var expandOpenGraphNodes = (graph, open) => {
715
+ return Promise.all(open.map((id) => {
716
+ const node = graph.findNode(Path.last(id));
410
717
  return node && expandChildrenAndActions(graph, node);
411
718
  }).filter(nonNullable));
412
719
  };
413
720
 
414
721
  // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
415
722
  var NODE_TYPE = "dxos/app-graph/node";
416
- var renderPresence = (node) => /* @__PURE__ */ React4.createElement(Surface, {
723
+ var renderPresence = ({ item }) => /* @__PURE__ */ React6.createElement(Surface, {
417
724
  role: "presence--glyph",
418
725
  data: {
419
- object: node.data
726
+ object: item.node.data,
727
+ id: item.node.id
420
728
  }
421
729
  });
422
- var NavTreeContainer = ({ root, activeIds, openItemIds, onOpenItemIdsChange, attended, popoverAnchorId }) => {
730
+ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) => {
423
731
  const { closeNavigationSidebar } = useSidebars2(NAVTREE_PLUGIN);
424
732
  const [isLg] = useMediaQuery("lg", {
425
733
  ssr: false
426
734
  });
427
735
  const dispatch = useIntentDispatcher3();
428
- const graph = useMemo2(() => getGraph2(root), [
429
- root
430
- ]);
431
- const items = treeItemsFromRootNode(graph, root, openItemIds);
432
- const loadDescendents = useCallback((node) => {
736
+ const { graph } = useGraph2();
737
+ const loadDescendents = useCallback2((node) => {
433
738
  void expandActions(graph, node);
434
739
  if (!isActionLike(node)) {
435
740
  void expandChildren(graph, node).then(() => (
@@ -443,11 +748,29 @@ var NavTreeContainer = ({ root, activeIds, openItemIds, onOpenItemIdsChange, att
443
748
  }, [
444
749
  graph
445
750
  ]);
446
- const handleNavigate = async ({ node, actions }) => {
751
+ const canDrop = useCallback2((source, target) => {
752
+ if (isSpace(target.node.data)) {
753
+ return isEchoObject(source.node.data) || isSpace(source.node.data);
754
+ } else if (isEchoObject(target.node.data)) {
755
+ return isEchoObject(source.node.data);
756
+ } else {
757
+ return false;
758
+ }
759
+ }, []);
760
+ const handleSelect = useCallback2(({ node, actions, path }) => {
447
761
  if (!node.data) {
448
762
  return;
449
763
  }
450
- await dispatch({
764
+ if (isAction4(node)) {
765
+ const [parentId] = path.slice(1);
766
+ const parent = items.find(({ id }) => id === parentId)?.node;
767
+ void (parent && node.data({
768
+ node: parent,
769
+ caller: NAV_TREE_ITEM
770
+ }));
771
+ return;
772
+ }
773
+ void dispatch({
451
774
  action: NavigationAction.OPEN,
452
775
  data: {
453
776
  activeParts: {
@@ -458,279 +781,97 @@ var NavTreeContainer = ({ root, activeIds, openItemIds, onOpenItemIdsChange, att
458
781
  }
459
782
  });
460
783
  const defaultAction = actions?.find((action) => action.properties?.disposition === "default");
461
- if (isAction3(defaultAction)) {
784
+ if (isAction4(defaultAction)) {
462
785
  void defaultAction.data();
463
786
  }
464
787
  if (!isLg) {
465
788
  closeNavigationSidebar();
466
789
  }
467
- };
468
- const handleItemOpenChange = ({ id, actions, path }, nextOpen) => {
469
- if (path) {
470
- if (nextOpen) {
471
- onOpenItemIdsChange({
472
- ...openItemIds,
473
- [id]: true
474
- });
475
- } else {
476
- const { [id]: _, ...nextOpenItemIds } = openItemIds;
477
- onOpenItemIdsChange(nextOpenItemIds);
478
- }
479
- }
480
- const defaultAction = actions?.find((action) => action.properties?.disposition === "default");
481
- if (isAction3(defaultAction)) {
482
- void defaultAction.data();
483
- }
484
- };
485
- const resolveItemLevel = useCallback((overPosition, activeId, levelOffset) => {
486
- if (!(typeof overPosition === "number" && activeId)) {
487
- return 1;
488
- } else {
489
- const nextItems = arrayMove(items, items.findIndex(({ id }) => id === activeId), overPosition);
490
- const previousItem = nextItems[overPosition - 1];
491
- const nextItem = nextItems[overPosition + 1];
492
- return Math.min(previousItem ? getLevel(previousItem?.path) + 1 : 1, Math.max(nextItem ? getLevel(nextItem?.path) : 1, getLevel(nextItems[overPosition].path) + levelOffset));
493
- }
494
790
  }, [
495
- items
791
+ items,
792
+ dispatch,
793
+ isLg,
794
+ closeNavigationSidebar
496
795
  ]);
497
- const handleMove = useCallback(({ active, over, details }) => {
498
- const levelOffset = Math.floor((details?.delta?.x ?? 0) / 16);
499
- const overPosition = over.position ?? 0;
500
- const nextItems = arrayMove(items, items.findIndex(({ id }) => id === active.item.id), overPosition);
501
- const previousItem = nextItems[overPosition - 1];
502
- const nextItem = nextItems[overPosition + 1];
503
- const activeNode = "node" in active.item ? active.item.node : void 0;
504
- if (!activeNode || !previousItem || !previousItem.path) {
505
- return {
506
- operation: "reject",
507
- details: {
508
- levelOffset
796
+ useEffect2(() => {
797
+ return monitorForElements({
798
+ canMonitor: ({ source }) => isItem(source.data),
799
+ onDrop: ({ location, source }) => {
800
+ if (!location.current.dropTargets.length) {
801
+ return;
509
802
  }
510
- };
511
- }
512
- const overLevel = resolveItemLevel(overPosition, active.item.id, levelOffset);
513
- const previousLevel = getLevel(previousItem.path);
514
- if (previousLevel === overLevel - 1) {
515
- if (Path2.hasChild(previousItem.id, active.item.id)) {
516
- const operation = previousItem.node.properties.onRearrangeChildren ? "rearrange" : "reject";
517
- return {
518
- operation,
519
- details: {
520
- levelOffset
521
- }
522
- };
523
- } else {
524
- const operation = resolveMigrationOperation(graph, activeNode, previousItem.path, previousItem.node);
525
- return {
526
- operation,
527
- details: {
528
- levelOffset
529
- }
530
- };
531
- }
532
- } else if (previousLevel === overLevel) {
533
- const parent = getParent(graph, previousItem.node, previousItem.path);
534
- const parentPath = previousItem.path.slice(0, previousItem.path.length - 1);
535
- if (Path2.siblings(previousItem.id, active.item.id)) {
536
- const operation = parent?.properties.onRearrangeChildren ? "rearrange" : "reject";
537
- return {
538
- operation,
539
- details: {
540
- levelOffset
541
- }
542
- };
543
- } else {
544
- const operation = resolveMigrationOperation(graph, activeNode, parentPath, parent);
545
- return {
546
- operation,
547
- details: {
548
- levelOffset
549
- }
550
- };
551
- }
552
- } else if (nextItem && nextItem.path) {
553
- const nextLevel = getLevel(nextItem.path);
554
- if (nextLevel === overLevel) {
555
- const parent = getParent(graph, nextItem.node, nextItem.path);
556
- const parentPath = nextItem.path.slice(0, nextItem.path.length - 1);
557
- if (Path2.siblings(nextItem.id, active.item.id)) {
558
- const operation = parent?.properties.onRearrangeChildren ? "rearrange" : "reject";
559
- return {
560
- operation,
561
- details: {
562
- levelOffset
803
+ const target = location.current.dropTargets[0];
804
+ const instruction = extractInstruction(target.data);
805
+ if (instruction !== null && instruction.type !== "instruction-blocked") {
806
+ const sourceNode = source.data.node;
807
+ const targetNode = target.data.node;
808
+ const sourcePath = source.data.path;
809
+ const targetPath = target.data.path;
810
+ const nextItems = instruction.type.startsWith("reorder") ? items.filter((item) => item.path.slice(0, -1).join() === targetPath.slice(0, -1).join()) : items.filter((item) => item.path.slice(0, -1).join() === targetPath.join());
811
+ const operation = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== "make-child" ? "rearrange" : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
812
+ const sourceParent = getParent(graph, sourceNode, sourcePath);
813
+ const targetParent = getParent(graph, targetNode, targetPath);
814
+ const sourceIndex = nextItems.findIndex(({ id }) => id === sourceNode.id);
815
+ const targetIndex = nextItems.findIndex(({ id }) => id === targetNode.id);
816
+ const migrationIndex = instruction.type === "make-child" ? nextItems.length > 0 ? nextItems.length - 1 : 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
817
+ switch (operation) {
818
+ case "rearrange": {
819
+ arrayMove(nextItems, sourceIndex, targetIndex);
820
+ void sourceParent?.properties.onRearrangeChildren?.(nextItems.map((item) => item.node.data));
821
+ break;
563
822
  }
564
- };
565
- } else {
566
- const operation = resolveMigrationOperation(graph, activeNode, parentPath, parent);
567
- return {
568
- operation,
569
- details: {
570
- levelOffset
823
+ case "copy": {
824
+ const target2 = instruction.type === "make-child" ? targetNode : targetParent;
825
+ void target2?.properties.onCopy?.(sourceNode, migrationIndex);
826
+ break;
827
+ }
828
+ case "transfer": {
829
+ const target2 = instruction.type === "make-child" ? targetNode : targetParent;
830
+ if (!target2?.properties.onTransferStart || !sourceParent?.properties.onTransferEnd) {
831
+ break;
832
+ }
833
+ void target2?.properties.onTransferStart(sourceNode, migrationIndex);
834
+ void sourceParent?.properties.onTransferEnd?.(sourceNode, target2);
835
+ break;
571
836
  }
572
- };
573
- }
574
- } else {
575
- return {
576
- operation: "reject",
577
- details: {
578
- levelOffset
579
- }
580
- };
581
- }
582
- } else {
583
- return {
584
- operation: "reject",
585
- details: {
586
- levelOffset
587
- }
588
- };
589
- }
590
- }, [
591
- root,
592
- items
593
- ]);
594
- const handleDrop = useCallback(({ operation, active, over, details = {} }) => {
595
- if (Path2.first(over.path) !== root.id) {
596
- return void 0;
597
- }
598
- const { levelOffset = 0 } = details;
599
- const overPosition = over.position ?? 0;
600
- const nextItems = arrayMove(items, items.findIndex(({ id }) => id === active.item.id), overPosition);
601
- const activeNode = "node" in active.item ? active.item.node : void 0;
602
- const activeParentId = Path2.parent(active.item.id);
603
- if (!activeNode) {
604
- return void 0;
605
- }
606
- const activeParent = getParent(graph, activeNode, active.item.path ?? []);
607
- if (operation === "rearrange") {
608
- void activeParent?.properties.onRearrangeChildren?.(nextItems.filter(({ id }) => Path2.hasChild(activeParentId, id)).map(({ node }) => node.data));
609
- return null;
610
- } else {
611
- const previousItem = nextItems[overPosition - 1];
612
- const nextItem = nextItems[overPosition + 1];
613
- const overLevel = resolveItemLevel(overPosition, active.item.id, levelOffset);
614
- const previousLevel = getLevel(previousItem.path);
615
- if (operation === "copy") {
616
- if (previousLevel === overLevel - 1) {
617
- void previousItem.node.properties.onCopy?.(activeNode, 0);
618
- return null;
619
- } else if (previousLevel === overLevel) {
620
- const parent = getParent(graph, previousItem.node, previousItem.path ?? []);
621
- void parent?.properties.onCopy?.(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === previousItem.node.id) + 1);
622
- return null;
623
- } else if (nextItem && nextItem.path) {
624
- const parent = getParent(graph, nextItem.node, nextItem.path ?? []);
625
- void parent?.properties.onCopy?.(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === nextItem.node.id));
626
- return null;
627
- }
628
- } else if (operation === "transfer") {
629
- const onTransferEnd = activeParent?.properties.onTransferEnd;
630
- if (!onTransferEnd) {
631
- return void 0;
632
- } else if (previousLevel === overLevel - 1) {
633
- const onTransferStart = previousItem.node.properties.onTransferStart;
634
- if (onTransferStart) {
635
- void onTransferEnd(activeNode, previousItem.node);
636
- void onTransferStart(activeNode, 0);
637
- return null;
638
- }
639
- } else if (previousLevel === overLevel && previousItem.path) {
640
- const parent = getParent(graph, previousItem.node, previousItem.path);
641
- if (parent?.properties.onTransferStart) {
642
- void onTransferEnd(activeNode, previousItem.node);
643
- void parent.properties.onTransferStart(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === previousItem.node.id) + 1);
644
- return null;
645
- }
646
- } else if (nextItem && nextItem.path) {
647
- const parent = getParent(graph, nextItem.node, nextItem.path);
648
- if (parent?.properties.onTransferStart) {
649
- void onTransferEnd(activeNode, previousItem.node);
650
- void parent.properties.onTransferStart(activeNode, getChildren(graph, parent).findIndex(({ id }) => id === nextItem.node.id));
651
- return null;
652
837
  }
653
838
  }
654
839
  }
655
- }
656
- return void 0;
657
- }, [
658
- root,
659
- items
660
- ]);
661
- const handleDragEnd = useCallback(() => {
662
- onOpenItemIdsChange({
663
- ...openItemIds
664
840
  });
665
841
  }, [
666
- onOpenItemIdsChange,
667
- openItemIds
842
+ items
668
843
  ]);
669
- const debug = false;
670
- if (debug) {
671
- const getLabel = (item) => {
672
- const label = item.node?.properties?.label;
673
- return typeof label === "string" ? label : item.id;
674
- };
675
- return /* @__PURE__ */ React4.createElement("div", {
676
- className: "bs-full overflow-hidden row-span-3 grid grid-cols-1 grid-rows-[min-content_1fr_min-content]"
677
- }, /* @__PURE__ */ React4.createElement("div", {
678
- className: "flex items-center p-2"
679
- }, "Items: ", items.length), /* @__PURE__ */ React4.createElement("div", {
680
- role: "none",
681
- className: "!overflow-y-auto"
682
- }, /* @__PURE__ */ React4.createElement(List.Root, {
683
- items,
684
- isItem: () => true
685
- }, ({ items: items2 }) => items2.map((item) => /* @__PURE__ */ React4.createElement(List.Item, {
686
- key: item.id,
687
- item,
688
- classNames: mx3("p-2", ghostHover)
689
- }, /* @__PURE__ */ React4.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React4.createElement(List.ItemTitle, {
690
- classNames: "p-2 text-sm",
691
- onClick: () => handleNavigate(item)
692
- }, getLabel(item)), /* @__PURE__ */ React4.createElement(List.IconButton, {
693
- icon: "ph--caret-down--regular",
694
- onClick: () => handleItemOpenChange(item, true)
695
- }))))), /* @__PURE__ */ React4.createElement(NavTreeFooter, null));
696
- }
697
- return /* @__PURE__ */ React4.createElement(Mosaic.Root, null, /* @__PURE__ */ React4.createElement(Mosaic.DragOverlay, null), /* @__PURE__ */ React4.createElement(ElevationProvider, {
844
+ return /* @__PURE__ */ React6.createElement(ElevationProvider, {
698
845
  elevation: "chrome"
699
- }, /* @__PURE__ */ React4.createElement("div", {
846
+ }, /* @__PURE__ */ React6.createElement("div", {
700
847
  role: "none",
701
848
  className: "bs-full overflow-hidden row-span-3 grid grid-cols-1 grid-rows-[min-content_1fr_min-content]"
702
- }, /* @__PURE__ */ React4.createElement(Surface, {
849
+ }, /* @__PURE__ */ React6.createElement(Surface, {
703
850
  role: "search-input",
704
851
  limit: 1
705
- }), /* @__PURE__ */ React4.createElement("div", {
852
+ }), /* @__PURE__ */ React6.createElement("div", {
706
853
  role: "none",
707
854
  className: "!overflow-y-auto"
708
- }, /* @__PURE__ */ React4.createElement(NavTree, {
709
- id: root.id,
855
+ }, /* @__PURE__ */ React6.createElement(NavTree, {
710
856
  items,
711
- current: activeIds,
712
- attended,
713
- type: NODE_TYPE,
857
+ open,
858
+ current,
714
859
  loadDescendents,
715
- popoverAnchorId,
716
860
  renderPresence,
717
- resolveItemLevel,
718
- open: openItemIds,
719
- onNavigate: handleNavigate,
720
- onItemOpenChange: handleItemOpenChange,
721
- onMove: handleMove,
722
- onDrop: handleDrop,
723
- onDragEnd: handleDragEnd
724
- })), /* @__PURE__ */ React4.createElement(NavTreeFooter, null))));
861
+ popoverAnchorId,
862
+ canDrop,
863
+ onSelect: handleSelect,
864
+ ...props
865
+ })), /* @__PURE__ */ React6.createElement(NavTreeFooter, null)));
725
866
  };
726
867
 
727
868
  // packages/plugins/plugin-navtree/src/components/NavTreeDocumentTitle.tsx
728
- import { useEffect } from "react";
729
- import { toLocalizedString as toLocalizedString3, useTranslation as useTranslation4 } from "@dxos/react-ui";
869
+ import { useEffect as useEffect3 } from "react";
870
+ import { toLocalizedString as toLocalizedString5, useTranslation as useTranslation6 } from "@dxos/react-ui";
730
871
  var NavTreeDocumentTitle = ({ node }) => {
731
- const { t } = useTranslation4(NAVTREE_PLUGIN);
732
- useEffect(() => {
733
- document.title = node ? toLocalizedString3(node.properties.label, t) : t("current app name", {
872
+ const { t } = useTranslation6(NAVTREE_PLUGIN);
873
+ useEffect3(() => {
874
+ document.title = node ? toLocalizedString5(node.properties.label, t) : t("current app name", {
734
875
  ns: "appkit"
735
876
  });
736
877
  }, [
@@ -740,14 +881,14 @@ var NavTreeDocumentTitle = ({ node }) => {
740
881
  };
741
882
 
742
883
  // packages/plugins/plugin-navtree/src/components/NotchStart.tsx
743
- import React6 from "react";
884
+ import React8 from "react";
744
885
  import { useIntentDispatcher as useIntentDispatcher4, useResolvePlugin as useResolvePlugin2 } from "@dxos/app-framework";
745
886
  import { ClientAction } from "@dxos/plugin-client/meta";
746
887
  import { parseObservabilityPlugin } from "@dxos/plugin-observability";
747
888
  import { useIdentity } from "@dxos/react-client/halo";
748
889
 
749
890
  // packages/plugins/plugin-navtree/src/components/HaloButton.tsx
750
- import React5 from "react";
891
+ import React7 from "react";
751
892
  import { ConnectionState, useNetworkStatus } from "@dxos/react-client/mesh";
752
893
  import { Avatar } from "@dxos/react-ui";
753
894
  import { focusRing, mx as mx4 } from "@dxos/react-ui-theme";
@@ -757,20 +898,20 @@ var HaloButton = (props) => {
757
898
  const { onClick, identityKey, internal, size = 8 } = props;
758
899
  const fallbackValue = hexToFallback(identityKey ?? "0");
759
900
  const { swarm: connectionState } = useNetworkStatus();
760
- return /* @__PURE__ */ React5.createElement("button", {
901
+ return /* @__PURE__ */ React7.createElement("button", {
761
902
  className: mx4(focusRing, "rounded grid place-items-center"),
762
903
  onClick
763
- }, /* @__PURE__ */ React5.createElement(Avatar.Root, {
904
+ }, /* @__PURE__ */ React7.createElement(Avatar.Root, {
764
905
  size,
765
906
  variant: "circle",
766
907
  status: connectionState === ConnectionState.OFFLINE ? "error" : internal ? "internal" : "active",
767
908
  hue: props.hue || fallbackValue.hue
768
- }, /* @__PURE__ */ React5.createElement(Avatar.Frame, {
909
+ }, /* @__PURE__ */ React7.createElement(Avatar.Frame, {
769
910
  "data-testid": "treeView.haloButton",
770
911
  "data-joyride": "welcome/halo"
771
- }, internal ? /* @__PURE__ */ React5.createElement(Avatar.Image, {
912
+ }, internal ? /* @__PURE__ */ React7.createElement(Avatar.Image, {
772
913
  href: INTERNAL
773
- }) : /* @__PURE__ */ React5.createElement(Avatar.Fallback, {
914
+ }) : /* @__PURE__ */ React7.createElement(Avatar.Fallback, {
774
915
  text: props.emoji || fallbackValue.emoji
775
916
  }))));
776
917
  };
@@ -780,7 +921,7 @@ var NotchStart = () => {
780
921
  const identity = useIdentity();
781
922
  const observabilityPlugin = useResolvePlugin2(parseObservabilityPlugin);
782
923
  const dispatch = useIntentDispatcher4();
783
- return /* @__PURE__ */ React6.createElement(HaloButton, {
924
+ return /* @__PURE__ */ React8.createElement(HaloButton, {
784
925
  size: 8,
785
926
  identityKey: identity?.identityKey.toHex(),
786
927
  hue: identity?.profile?.data?.hue,
@@ -794,14 +935,14 @@ var NotchStart = () => {
794
935
 
795
936
  // packages/plugins/plugin-navtree/src/components/CommandsTrigger.tsx
796
937
  import { MagnifyingGlass } from "@phosphor-icons/react";
797
- import React7 from "react";
938
+ import React9 from "react";
798
939
  import { LayoutAction as LayoutAction2, useIntent } from "@dxos/app-framework";
799
- import { Button as Button3, useTranslation as useTranslation5 } from "@dxos/react-ui";
940
+ import { Button as Button4, useTranslation as useTranslation7 } from "@dxos/react-ui";
800
941
  import { getSize as getSize2 } from "@dxos/react-ui-theme";
801
942
  var CommandsTrigger = () => {
802
943
  const { dispatch } = useIntent();
803
- const { t } = useTranslation5(NAVTREE_PLUGIN);
804
- return /* @__PURE__ */ React7.createElement(Button3, {
944
+ const { t } = useTranslation7(NAVTREE_PLUGIN);
945
+ return /* @__PURE__ */ React9.createElement(Button4, {
805
946
  classNames: "pis-3 pie-2 gap-2 mli-1 mbs-1 min-bs-0 bs-[--rail-action] justify-start",
806
947
  onClick: () => dispatch({
807
948
  action: LayoutAction2.SET_LAYOUT,
@@ -811,15 +952,14 @@ var CommandsTrigger = () => {
811
952
  dialogBlockAlign: "start"
812
953
  }
813
954
  })
814
- }, /* @__PURE__ */ React7.createElement("span", {
955
+ }, /* @__PURE__ */ React9.createElement("span", {
815
956
  className: "text-description font-normal grow text-start"
816
- }, t("command list input placeholder")), /* @__PURE__ */ React7.createElement(MagnifyingGlass, {
957
+ }, t("command list input placeholder")), /* @__PURE__ */ React9.createElement(MagnifyingGlass, {
817
958
  className: getSize2(5)
818
959
  }));
819
960
  };
820
961
 
821
962
  // packages/plugins/plugin-navtree/src/translations.ts
822
- import { translations as navtreeTranslations } from "@dxos/react-ui-navtree";
823
963
  var translations_default = [
824
964
  {
825
965
  "en-US": {
@@ -834,29 +974,87 @@ var translations_default = [
834
974
  "learn more label": "Learn more",
835
975
  "released message": "This version released {{released}}.",
836
976
  "see release label": "See release on GitHub",
837
- "powered by dxos message": "Powered by <dxos>DXOS</dxos>"
977
+ "powered by dxos message": "Powered by <dxos>DXOS</dxos>",
978
+ "tree item actions label": "More actions",
979
+ "tree item searchlist input placeholder": "Search for actions\u2026",
980
+ "empty branch message": "\xA0"
838
981
  }
839
982
  }
840
- },
841
- ...navtreeTranslations
983
+ }
842
984
  ];
843
985
 
844
986
  // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
987
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-navtree/src/NavTreePlugin.tsx";
845
988
  var NavTreePlugin = () => {
989
+ let graphPlugin;
990
+ let graph;
991
+ const itemCache = /* @__PURE__ */ new Map();
846
992
  const state = new LocalStorageStore("dxos.org/settings/navtree", {
993
+ root: void 0,
994
+ get flatTree() {
995
+ if (!this.root || !graph) {
996
+ return [];
997
+ }
998
+ return treeItemsFromRootNode(graph, this.root, this.open, getItem);
999
+ },
847
1000
  // TODO(thure): Do this dynamically.
848
- openItemIds: {
849
- root: true,
850
- "dxos.org/plugin/space-spaces": true,
851
- "dxos.org/plugin/files": true
852
- }
1001
+ open: [
1002
+ "root",
1003
+ "root~dxos.org/plugin/space-spaces",
1004
+ "root~dxos.org/plugin/files"
1005
+ ]
853
1006
  });
854
- let graphPlugin;
855
- let graph;
856
- const handleOpenItemIdsChange = (nextOpenItemIds) => {
857
- state.values.openItemIds = nextOpenItemIds;
1007
+ const getItem = (node, parent, filter) => {
1008
+ invariant(graph, void 0, {
1009
+ F: __dxlog_file,
1010
+ L: 80,
1011
+ S: void 0,
1012
+ A: [
1013
+ "graph",
1014
+ ""
1015
+ ]
1016
+ });
1017
+ const path = [
1018
+ ...parent,
1019
+ node.id
1020
+ ];
1021
+ const { actions, groupedActions } = getActions(graph, node);
1022
+ const children = getChildren(graph, node, filter, path);
1023
+ const parentOf = children.length > 0 ? children.map(({ id }) => id) : node.properties.role === "branch" ? [] : void 0;
1024
+ const item = {
1025
+ id: node.id,
1026
+ label: node.properties.label ?? node.id,
1027
+ icon: node.properties.icon,
1028
+ disabled: node.properties.disabled,
1029
+ testId: node.properties.testId,
1030
+ className: node.properties.className,
1031
+ headingClassName: node.properties.headingClassName,
1032
+ path,
1033
+ parentOf,
1034
+ node,
1035
+ actions,
1036
+ groupedActions
1037
+ };
1038
+ const cachedItem = itemCache.get(node.id);
1039
+ if (cachedItem && JSON.stringify(item) === JSON.stringify(cachedItem)) {
1040
+ return cachedItem;
1041
+ } else {
1042
+ itemCache.set(node.id, item);
1043
+ return item;
1044
+ }
1045
+ };
1046
+ const handleOpenChange = (item, open) => {
1047
+ const path = Path2.create(...item.path);
1048
+ if (open) {
1049
+ state.values.open.push(path);
1050
+ } else {
1051
+ const index = state.values.open.indexOf(path);
1052
+ if (index > -1) {
1053
+ state.values.open.splice(index, 1);
1054
+ }
1055
+ }
858
1056
  if (graph) {
859
- void expandOpenGraphNodes(graph, nextOpenItemIds);
1057
+ void expandOpenGraphNodes(graph, state.values.open);
860
1058
  }
861
1059
  };
862
1060
  return {
@@ -871,22 +1069,21 @@ var NavTreePlugin = () => {
871
1069
  getChildren(graph, state.values.root);
872
1070
  getActions(graph, state.values.root);
873
1071
  state.prop({
874
- key: "openItemIds",
875
- storageKey: "openItemIds",
1072
+ key: "open",
876
1073
  type: LocalStorageStore.json()
877
1074
  });
878
- void expandOpenGraphNodes(graph, state.values.openItemIds);
1075
+ void expandOpenGraphNodes(graph, state.values.open);
879
1076
  graph.subscribeTraverse({
880
1077
  visitor: (node, path) => {
881
1078
  let shortcut;
882
1079
  if (typeof node.properties.keyBinding === "object") {
883
1080
  const availablePlatforms = Object.keys(node.properties.keyBinding);
884
- const platform = getHostPlatform2();
1081
+ const platform = getHostPlatform3();
885
1082
  shortcut = availablePlatforms.includes(platform) ? node.properties.keyBinding[platform] : platform === "ios" ? node.properties.keyBinding.macos : platform === "linux" || platform === "unknown" ? node.properties.keyBinding.windows : void 0;
886
1083
  } else {
887
1084
  shortcut = node.properties.keyBinding;
888
1085
  }
889
- if (shortcut && isAction4(node)) {
1086
+ if (shortcut && isAction5(node)) {
890
1087
  Keyboard2.singleton.getContext(path.slice(0, -1).join("/")).bind({
891
1088
  shortcut,
892
1089
  handler: () => {
@@ -931,33 +1128,29 @@ var NavTreePlugin = () => {
931
1128
  switch (data.component) {
932
1129
  case `${NAVTREE_PLUGIN}/Commands`: {
933
1130
  const selected = typeof data.subject === "string" ? data.subject : void 0;
934
- return /* @__PURE__ */ React8.createElement(CommandsDialogContent, {
1131
+ return /* @__PURE__ */ React10.createElement(CommandsDialogContent, {
935
1132
  selected
936
1133
  });
937
1134
  }
938
1135
  }
939
1136
  switch (role) {
940
1137
  case "navigation":
941
- if (state.values.root && state.values.openItemIds) {
942
- return /* @__PURE__ */ React8.createElement(NavTreeContainer, {
943
- root: state.values.root,
944
- activeIds: data.activeIds,
945
- openItemIds: state.values.openItemIds,
946
- onOpenItemIdsChange: handleOpenItemIdsChange,
947
- attended: data.attended,
948
- popoverAnchorId: data.popoverAnchorId
949
- });
950
- }
951
- break;
1138
+ return /* @__PURE__ */ React10.createElement(NavTreeContainer, {
1139
+ items: state.values.flatTree,
1140
+ current: data.activeIds,
1141
+ open: state.values.open,
1142
+ onOpenChange: handleOpenChange,
1143
+ popoverAnchorId: data.popoverAnchorId
1144
+ });
952
1145
  case "document-title": {
953
- return /* @__PURE__ */ React8.createElement(NavTreeDocumentTitle, {
1146
+ return /* @__PURE__ */ React10.createElement(NavTreeDocumentTitle, {
954
1147
  node: isGraphNode(data.activeNode) ? data.activeNode : void 0
955
1148
  });
956
1149
  }
957
1150
  case "navbar-start": {
958
1151
  if (state.values.root && data.activeNode) {
959
1152
  return {
960
- node: /* @__PURE__ */ React8.createElement(NavBarStart, {
1153
+ node: /* @__PURE__ */ React10.createElement(NavBarStart, {
961
1154
  activeNode: data.activeNode,
962
1155
  popoverAnchorId: data.popoverAnchorId
963
1156
  }),
@@ -967,10 +1160,10 @@ var NavTreePlugin = () => {
967
1160
  break;
968
1161
  }
969
1162
  case "notch-start":
970
- return /* @__PURE__ */ React8.createElement(NotchStart, null);
1163
+ return /* @__PURE__ */ React10.createElement(NotchStart, null);
971
1164
  case "search-input":
972
1165
  return {
973
- node: /* @__PURE__ */ React8.createElement(CommandsTrigger, null),
1166
+ node: /* @__PURE__ */ React10.createElement(CommandsTrigger, null),
974
1167
  disposition: "fallback"
975
1168
  };
976
1169
  }
@@ -987,18 +1180,15 @@ var NavTreePlugin = () => {
987
1180
  });
988
1181
  if (Array.isArray(path)) {
989
1182
  const additionalOpenItems = [
990
- ...Array(path.length - 1)
1183
+ ...Array(path.length)
991
1184
  ].reduce((acc, _, index) => {
992
- const itemId = Path3.create(...path.slice(1, index + 1));
1185
+ const itemId = Path2.create(...path.slice(0, index));
993
1186
  if (itemId.length > 0) {
994
- acc[itemId] = true;
1187
+ acc.push(itemId);
995
1188
  }
996
1189
  return acc;
997
- }, {});
998
- state.values.openItemIds = {
999
- ...additionalOpenItems,
1000
- ...state.values.openItemIds
1001
- };
1190
+ }, []);
1191
+ state.values.open.push(...additionalOpenItems);
1002
1192
  }
1003
1193
  }
1004
1194
  break;