@dxos/plugin-navtree 0.7.1-staging.8709ba7 → 0.7.2-main.f1adc9f

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 (37) hide show
  1. package/dist/lib/browser/index.mjs +226 -200
  2. package/dist/lib/browser/index.mjs.map +3 -3
  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 +7 -5
  6. package/dist/types/src/components/NavTree.d.ts.map +1 -1
  7. package/dist/types/src/components/NavTree.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/NavTreeContainer.d.ts +2 -6
  9. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  10. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +1 -0
  11. package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +1 -1
  12. package/dist/types/src/stories/Graph.stories.d.ts +2 -1
  13. package/dist/types/src/stories/Graph.stories.d.ts.map +1 -1
  14. package/dist/types/src/testing/generator.d.ts +0 -1
  15. package/dist/types/src/testing/generator.d.ts.map +1 -1
  16. package/dist/types/src/testing/index.d.ts +1 -1
  17. package/dist/types/src/testing/index.d.ts.map +1 -1
  18. package/dist/types/src/testing/update-state.d.ts +10 -0
  19. package/dist/types/src/testing/update-state.d.ts.map +1 -0
  20. package/dist/types/src/types.d.ts +12 -3
  21. package/dist/types/src/types.d.ts.map +1 -1
  22. package/dist/types/src/util.d.ts +1 -20
  23. package/dist/types/src/util.d.ts.map +1 -1
  24. package/package.json +28 -28
  25. package/src/NavTreePlugin.tsx +103 -90
  26. package/src/components/NavTree.stories.tsx +73 -69
  27. package/src/components/NavTree.tsx +30 -20
  28. package/src/components/NavTreeContainer.tsx +97 -56
  29. package/src/stories/Graph.stories.tsx +68 -96
  30. package/src/testing/generator.ts +2 -7
  31. package/src/testing/index.ts +1 -1
  32. package/src/testing/update-state.ts +70 -0
  33. package/src/types.ts +18 -3
  34. package/src/util.ts +2 -94
  35. package/dist/types/src/testing/visitor.d.ts +0 -18
  36. package/dist/types/src/testing/visitor.d.ts.map +0 -1
  37. package/src/testing/visitor.ts +0 -152
@@ -5,14 +5,13 @@ import {
5
5
  } from "./chunk-PSVCPL4T.mjs";
6
6
 
7
7
  // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
8
+ import { effect } from "@preact/signals-core";
8
9
  import React10 from "react";
9
- import { resolvePlugin, parseIntentPlugin, LayoutAction as LayoutAction3, parseGraphPlugin, NavigationAction as NavigationAction2, parseNavigationPlugin as parseNavigationPlugin2 } from "@dxos/app-framework";
10
+ import { resolvePlugin, parseIntentPlugin, LayoutAction as LayoutAction4, parseGraphPlugin, NavigationAction as NavigationAction2, parseNavigationPlugin as parseNavigationPlugin2, parseLayoutPlugin } from "@dxos/app-framework";
10
11
  import { createExtension, isAction as isAction5, isGraphNode } from "@dxos/app-graph";
11
- import { invariant } from "@dxos/invariant";
12
+ import { create } from "@dxos/echo-schema";
12
13
  import { Keyboard as Keyboard2 } from "@dxos/keyboard";
13
- import { LocalStorageStore } from "@dxos/local-storage";
14
- import { Path as Path2 } from "@dxos/react-ui-mosaic";
15
- import { mx as mx5 } from "@dxos/react-ui-theme";
14
+ import { Path } from "@dxos/react-ui-mosaic";
16
15
  import { getHostPlatform as getHostPlatform3 } from "@dxos/util";
17
16
 
18
17
  // packages/plugins/plugin-navtree/src/components/CommandsDialog.tsx
@@ -395,10 +394,12 @@ var NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...props }) =>
395
394
 
396
395
  // packages/plugins/plugin-navtree/src/components/NavTree.tsx
397
396
  var NAV_TREE_ITEM = "NavTreeItem";
398
- var NavTree = ({ loadDescendents, renderPresence: renderPresence2, popoverAnchorId, ...props }) => {
399
- const renderColumns = useCallback(({ item, menuOpen, setMenuOpen }) => {
397
+ var NavTree = ({ getActions: getActions2, loadDescendents, renderPresence: renderPresence2, popoverAnchorId, ...props }) => {
398
+ const renderColumns = useCallback(({ item, path, menuOpen, setMenuOpen }) => {
400
399
  return /* @__PURE__ */ React4.createElement(NavTreeColumns, {
401
- item,
400
+ path,
401
+ node: item,
402
+ getActions: getActions2,
402
403
  menuOpen,
403
404
  setMenuOpen,
404
405
  loadDescendents,
@@ -417,17 +418,18 @@ var NavTree = ({ loadDescendents, renderPresence: renderPresence2, popoverAnchor
417
418
  renderColumns
418
419
  });
419
420
  };
420
- var NavTreeColumns = ({ item, menuOpen, setMenuOpen, loadDescendents, renderPresence: Presence, popoverAnchorId }) => {
421
+ var NavTreeColumns = ({ path, node, getActions: getActions2, menuOpen, setMenuOpen, loadDescendents, renderPresence: Presence, popoverAnchorId }) => {
421
422
  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) ? [
423
+ const level = path.length - 2;
424
+ const { actions: _actions, groupedActions } = getActions2(node);
425
+ const [primaryAction, ...secondaryActions] = _actions.toSorted((a, b) => a.properties?.disposition === "toolbar" ? -1 : 1);
426
+ const actions = (primaryAction?.properties?.disposition === "toolbar" ? secondaryActions : _actions).flatMap((action) => isAction2(action) ? [
425
427
  action
426
428
  ] : []).filter((action) => !action.properties?.hidden);
427
- const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover2.Anchor : Fragment2;
429
+ const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${node.id}` ? Popover2.Anchor : Fragment2;
428
430
  useEffect(() => {
429
431
  const frame = requestAnimationFrame(() => {
430
- void loadDescendents?.(item.node);
432
+ void loadDescendents?.(node);
431
433
  if (primaryAction && !isAction2(primaryAction)) {
432
434
  void loadDescendents?.(primaryAction);
433
435
  }
@@ -440,38 +442,40 @@ var NavTreeColumns = ({ item, menuOpen, setMenuOpen, loadDescendents, renderPres
440
442
  testId: primaryAction.properties?.testId,
441
443
  label: toLocalizedString4(primaryAction.properties?.label, t),
442
444
  icon: primaryAction.properties?.icon ?? "ph--placeholder--regular",
443
- parent: item.node,
445
+ parent: node,
444
446
  monolithic: isAction2(primaryAction),
445
447
  menuActions: isAction2(primaryAction) ? [
446
448
  primaryAction
447
- ] : item.groupedActions[primaryAction.id],
449
+ ] : groupedActions[primaryAction.id],
448
450
  menuType: primaryAction.properties?.menuType,
449
451
  caller: NAV_TREE_ITEM
450
452
  }) : /* @__PURE__ */ React4.createElement(Treegrid.Cell, null), /* @__PURE__ */ React4.createElement(ActionRoot, null, actions.length > 0 ? /* @__PURE__ */ React4.createElement(NavTreeItemAction, {
451
453
  testId: `navtree.treeItem.actionsLevel${level}`,
452
454
  label: t("tree item actions label"),
453
455
  icon: "ph--dots-three-vertical--regular",
454
- parent: item.node,
456
+ parent: node,
455
457
  menuActions: actions,
456
458
  menuType: "dropdown",
457
459
  caller: NAV_TREE_ITEM,
458
460
  menuOpen,
459
461
  onChangeMenuOpen: setMenuOpen
460
462
  }) : /* @__PURE__ */ React4.createElement(Treegrid.Cell, null)), Presence && /* @__PURE__ */ React4.createElement(Presence, {
461
- item
463
+ node
462
464
  }));
463
465
  };
464
466
 
465
467
  // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
466
468
  import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
467
469
  import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
468
- import React6, { useCallback as useCallback2, useEffect as useEffect2 } from "react";
469
- import { NavigationAction, Surface, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
470
+ import { untracked } from "@preact/signals-core";
471
+ import React6, { memo, useCallback as useCallback2, useEffect as useEffect2 } from "react";
472
+ import { LayoutAction as LayoutAction2, NavigationAction, Surface, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
470
473
  import { isAction as isAction4, isActionLike } from "@dxos/app-graph";
471
474
  import { useGraph as useGraph2 } from "@dxos/plugin-graph";
472
475
  import { isEchoObject, isSpace } from "@dxos/react-client/echo";
473
476
  import { ElevationProvider, useMediaQuery, useSidebars as useSidebars2 } from "@dxos/react-ui";
474
- import { isItem } from "@dxos/react-ui-list";
477
+ import { isTreeData } from "@dxos/react-ui-list";
478
+ import { mx as mx4 } from "@dxos/react-ui-theme";
475
479
  import { arrayMove } from "@dxos/util";
476
480
 
477
481
  // packages/plugins/plugin-navtree/src/components/NavTreeFooter.tsx
@@ -584,7 +588,6 @@ var NavTreeFooter = (props) => {
584
588
 
585
589
  // packages/plugins/plugin-navtree/src/util.ts
586
590
  import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction3 } from "@dxos/app-graph";
587
- import { Path } from "@dxos/react-ui-mosaic";
588
591
  import { nonNullable } from "@dxos/util";
589
592
  var getParent = (graph, node, path) => {
590
593
  const parentId = path[path.length - 2];
@@ -627,14 +630,6 @@ var sortActions = (actions) => actions.sort((a, b) => {
627
630
  }
628
631
  return 1;
629
632
  });
630
- var getTreeItemNode = (treeItems, path) => {
631
- if (!path) {
632
- return void 0;
633
- }
634
- return treeItems.find((treeItem) => {
635
- return treeItem.path && !treeItem.path.find((id, index) => path[index] !== id);
636
- });
637
- };
638
633
  var getChildren = (graph, node, filter, path = []) => {
639
634
  return graph.nodes(node, {
640
635
  relation: "outbound",
@@ -678,64 +673,55 @@ var expandActions = (graph, node) => {
678
673
  graph.expand(node, "outbound", ACTION_GROUP_TYPE)
679
674
  ]);
680
675
  };
681
- function* navTreeItemVisitor({ graph, node, open, getItem, path = [], filter }) {
682
- const stack = [
683
- getItem(node, path, filter)
684
- ];
685
- while (stack.length > 0) {
686
- const nextItem = stack.pop();
687
- if (nextItem.path.length > 1) {
688
- yield nextItem;
689
- }
690
- const { node: node2, path: path2 } = nextItem;
691
- const children = getChildren(graph, node2, filter, path2);
692
- const actions = graph.actions(node2);
693
- if (path2.length === 1 || open.includes(Path.create(...path2))) {
694
- for (let i = actions.length - 1; i >= 0; i--) {
695
- if (actions[i].properties.disposition === "item") {
696
- stack.push(getItem(actions[i], path2, filter));
697
- }
698
- }
699
- for (let i = children.length - 1; i >= 0; i--) {
700
- const child = children[i];
701
- stack.push(getItem(child, path2, filter));
702
- }
703
- }
704
- }
705
- }
706
- var treeItemsFromRootNode = (graph, rootNode, open, getItem, path, filter) => {
707
- return Array.from(navTreeItemVisitor({
708
- graph,
709
- node: rootNode,
710
- open,
711
- getItem,
712
- path,
713
- filter
714
- }));
715
- };
716
- var expandOpenGraphNodes = (graph, open) => {
717
- return Promise.all(open.map((id) => {
718
- const node = graph.findNode(Path.last(id));
719
- return node && expandChildrenAndActions(graph, node);
720
- }).filter(nonNullable));
721
- };
722
676
 
723
677
  // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
724
678
  var NODE_TYPE = "dxos/app-graph/node";
725
- var renderPresence = ({ item }) => /* @__PURE__ */ React6.createElement(Surface, {
679
+ var renderPresence = ({ node }) => /* @__PURE__ */ React6.createElement(Surface, {
726
680
  role: "presence--glyph",
727
681
  data: {
728
- object: item.node.data,
729
- id: item.node.id
682
+ object: node.data,
683
+ id: node.id
730
684
  }
731
685
  });
732
- var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) => {
686
+ var NavTreeContainer = /* @__PURE__ */ memo(({ isCurrent, popoverAnchorId, ...props }) => {
733
687
  const { closeNavigationSidebar } = useSidebars2(NAVTREE_PLUGIN);
734
688
  const [isLg] = useMediaQuery("lg", {
735
689
  ssr: false
736
690
  });
737
691
  const dispatch = useIntentDispatcher3();
738
692
  const { graph } = useGraph2();
693
+ const getActions2 = useCallback2((node) => getActions(graph, node), [
694
+ graph
695
+ ]);
696
+ const getItems = useCallback2((node) => {
697
+ return graph.nodes(node ?? graph.root, {
698
+ filter: (node2) => {
699
+ return untracked(() => {
700
+ const action = isActionLike(node2);
701
+ const disposition = node2.properties.disposition;
702
+ return !action || action && disposition === "item";
703
+ });
704
+ }
705
+ });
706
+ }, [
707
+ graph
708
+ ]);
709
+ const getProps = useCallback2((node, path) => {
710
+ const children = getChildren(graph, node, void 0, path);
711
+ const parentOf = children.length > 0 ? children.map(({ id }) => id) : node.properties.role === "branch" ? [] : void 0;
712
+ return {
713
+ id: node.id,
714
+ label: node.properties.label ?? node.id,
715
+ parentOf,
716
+ icon: node.properties.icon,
717
+ disabled: node.properties.disabled,
718
+ className: mx4(node.properties.modified && "italic", node.properties.className),
719
+ headingClassName: node.properties.headingClassName,
720
+ testId: node.properties.testId
721
+ };
722
+ }, [
723
+ graph
724
+ ]);
739
725
  const loadDescendents = useCallback2((node) => {
740
726
  void expandActions(graph, node);
741
727
  if (!isActionLike(node)) {
@@ -751,38 +737,62 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
751
737
  graph
752
738
  ]);
753
739
  const canDrop = useCallback2((source, target) => {
754
- if (isSpace(target.node.data)) {
755
- return isEchoObject(source.node.data) || isSpace(source.node.data);
756
- } else if (isEchoObject(target.node.data)) {
757
- return isEchoObject(source.node.data);
740
+ const sourceNode = source.item;
741
+ const targetNode = target.item;
742
+ if (isSpace(targetNode.data)) {
743
+ return isEchoObject(sourceNode.data) || isSpace(sourceNode.data);
744
+ } else if (isEchoObject(targetNode.data)) {
745
+ return isEchoObject(sourceNode.data);
758
746
  } else {
759
747
  return false;
760
748
  }
761
749
  }, []);
762
- const handleSelect = useCallback2(({ node, actions, path }) => {
750
+ const handleSelect = useCallback2(({ item: node, path, option }) => {
763
751
  if (!node.data) {
764
752
  return;
765
753
  }
766
754
  if (isAction4(node)) {
767
- const [parentId] = path.slice(1);
768
- const parent = items.find(({ id }) => id === parentId)?.node;
755
+ const [parent] = graph.nodes(node, {
756
+ relation: "inbound"
757
+ });
769
758
  void (parent && node.data({
770
759
  node: parent,
771
760
  caller: NAV_TREE_ITEM
772
761
  }));
773
762
  return;
774
763
  }
775
- void dispatch({
776
- action: NavigationAction.OPEN,
777
- data: {
778
- activeParts: {
779
- main: [
780
- node.id
781
- ]
764
+ const current = isCurrent(path, node);
765
+ if (!current) {
766
+ void dispatch({
767
+ action: NavigationAction.OPEN,
768
+ data: {
769
+ activeParts: {
770
+ main: [
771
+ node.id
772
+ ]
773
+ }
782
774
  }
783
- }
784
- });
785
- const defaultAction = actions?.find((action) => action.properties?.disposition === "default");
775
+ });
776
+ } else if (option) {
777
+ void dispatch({
778
+ action: NavigationAction.CLOSE,
779
+ data: {
780
+ activeParts: {
781
+ main: [
782
+ node.id
783
+ ]
784
+ }
785
+ }
786
+ });
787
+ } else {
788
+ void dispatch({
789
+ action: LayoutAction2.SCROLL_INTO_VIEW,
790
+ data: {
791
+ id: node.id
792
+ }
793
+ });
794
+ }
795
+ const defaultAction = graph.actions(node).find((action) => action.properties?.disposition === "default");
786
796
  if (isAction4(defaultAction)) {
787
797
  void defaultAction.data();
788
798
  }
@@ -790,14 +800,15 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
790
800
  closeNavigationSidebar();
791
801
  }
792
802
  }, [
793
- items,
803
+ graph,
794
804
  dispatch,
805
+ isCurrent,
795
806
  isLg,
796
807
  closeNavigationSidebar
797
808
  ]);
798
809
  useEffect2(() => {
799
810
  return monitorForElements({
800
- canMonitor: ({ source }) => isItem(source.data),
811
+ canMonitor: ({ source }) => isTreeData(source.data),
801
812
  onDrop: ({ location, source }) => {
802
813
  if (!location.current.dropTargets.length) {
803
814
  return;
@@ -805,21 +816,23 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
805
816
  const target = location.current.dropTargets[0];
806
817
  const instruction = extractInstruction(target.data);
807
818
  if (instruction !== null && instruction.type !== "instruction-blocked") {
808
- const sourceNode = source.data.node;
809
- const targetNode = target.data.node;
819
+ const sourceNode = source.data.item;
820
+ const targetNode = target.data.item;
810
821
  const sourcePath = source.data.path;
811
822
  const targetPath = target.data.path;
812
- 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());
813
823
  const operation = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== "make-child" ? "rearrange" : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
814
824
  const sourceParent = getParent(graph, sourceNode, sourcePath);
815
825
  const targetParent = getParent(graph, targetNode, targetPath);
816
- const sourceIndex = nextItems.findIndex(({ id }) => id === sourceNode.id);
817
- const targetIndex = nextItems.findIndex(({ id }) => id === targetNode.id);
818
- const migrationIndex = instruction.type === "make-child" ? nextItems.length > 0 ? nextItems.length - 1 : 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
826
+ const sourceItems = getItems(sourceParent);
827
+ const targetItems = getItems(targetParent);
828
+ const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
829
+ const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
830
+ const migrationIndex = instruction.type === "make-child" ? void 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
819
831
  switch (operation) {
820
832
  case "rearrange": {
833
+ const nextItems = sourceItems.map(({ data }) => data);
821
834
  arrayMove(nextItems, sourceIndex, targetIndex);
822
- void sourceParent?.properties.onRearrangeChildren?.(nextItems.map((item) => item.node.data));
835
+ void sourceParent?.properties.onRearrangeChildren?.(nextItems);
823
836
  break;
824
837
  }
825
838
  case "copy": {
@@ -841,7 +854,7 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
841
854
  }
842
855
  });
843
856
  }, [
844
- items
857
+ graph
845
858
  ]);
846
859
  return /* @__PURE__ */ React6.createElement(ElevationProvider, {
847
860
  elevation: "chrome"
@@ -858,9 +871,11 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
858
871
  role: "none",
859
872
  className: "border-be border-separator !overflow-y-auto"
860
873
  }, /* @__PURE__ */ React6.createElement(NavTree, {
861
- items,
862
- open,
863
- current,
874
+ id: graph.root.id,
875
+ getActions: getActions2,
876
+ getItems,
877
+ getProps,
878
+ isCurrent,
864
879
  loadDescendents,
865
880
  renderPresence,
866
881
  popoverAnchorId,
@@ -868,7 +883,7 @@ var NavTreeContainer = ({ items, current, open, popoverAnchorId, ...props }) =>
868
883
  onSelect: handleSelect,
869
884
  ...props
870
885
  })), /* @__PURE__ */ React6.createElement(NavTreeFooter, null)));
871
- };
886
+ });
872
887
 
873
888
  // packages/plugins/plugin-navtree/src/components/NavTreeDocumentTitle.tsx
874
889
  import { useEffect as useEffect3 } from "react";
@@ -896,7 +911,7 @@ import { useIdentity } from "@dxos/react-client/halo";
896
911
  import React7 from "react";
897
912
  import { ConnectionState, useNetworkStatus } from "@dxos/react-client/mesh";
898
913
  import { Avatar } from "@dxos/react-ui";
899
- import { focusRing, mx as mx4 } from "@dxos/react-ui-theme";
914
+ import { focusRing, mx as mx5 } from "@dxos/react-ui-theme";
900
915
  import { hexToFallback } from "@dxos/util";
901
916
  var INTERNAL = "https://avatars.githubusercontent.com/u/57182821";
902
917
  var HaloButton = (props) => {
@@ -904,7 +919,7 @@ var HaloButton = (props) => {
904
919
  const fallbackValue = hexToFallback(identityKey ?? "0");
905
920
  const { swarm: connectionState } = useNetworkStatus();
906
921
  return /* @__PURE__ */ React7.createElement("button", {
907
- className: mx4(focusRing, "rounded grid place-items-center"),
922
+ className: mx5(focusRing, "rounded grid place-items-center"),
908
923
  onClick
909
924
  }, /* @__PURE__ */ React7.createElement(Avatar.Root, {
910
925
  size,
@@ -941,7 +956,7 @@ var NotchStart = () => {
941
956
  // packages/plugins/plugin-navtree/src/components/CommandsTrigger.tsx
942
957
  import { MagnifyingGlass } from "@phosphor-icons/react";
943
958
  import React9 from "react";
944
- import { LayoutAction as LayoutAction2, useIntent } from "@dxos/app-framework";
959
+ import { LayoutAction as LayoutAction3, useIntent } from "@dxos/app-framework";
945
960
  import { Button as Button4, useTranslation as useTranslation7 } from "@dxos/react-ui";
946
961
  import { getSize as getSize2 } from "@dxos/react-ui-theme";
947
962
  var CommandsTrigger = () => {
@@ -950,7 +965,7 @@ var CommandsTrigger = () => {
950
965
  return /* @__PURE__ */ React9.createElement(Button4, {
951
966
  classNames: "w-full h-full !rounded-none",
952
967
  onClick: () => dispatch({
953
- action: LayoutAction2.SET_LAYOUT,
968
+ action: LayoutAction3.SET_LAYOUT,
954
969
  data: {
955
970
  element: "dialog",
956
971
  component: `${NAVTREE_PLUGIN}/Commands`,
@@ -989,93 +1004,86 @@ var translations_default = [
989
1004
  ];
990
1005
 
991
1006
  // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
992
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-navtree/src/NavTreePlugin.tsx";
1007
+ var KEY = `${NAVTREE_PLUGIN}/state`;
1008
+ var getInitialState = () => {
1009
+ const stringified = localStorage.getItem(KEY);
1010
+ if (!stringified) {
1011
+ return;
1012
+ }
1013
+ try {
1014
+ const cached = JSON.parse(stringified);
1015
+ return cached.map(([key, value]) => [
1016
+ key,
1017
+ create(value)
1018
+ ]);
1019
+ } catch {
1020
+ }
1021
+ };
993
1022
  var NavTreePlugin = () => {
994
1023
  let graphPlugin;
995
1024
  let graph;
996
- const itemCache = /* @__PURE__ */ new Map();
997
- const state = new LocalStorageStore("dxos.org/settings/navtree", {
998
- root: void 0,
999
- get flatTree() {
1000
- if (!this.root || !graph) {
1001
- return [];
1002
- }
1003
- return treeItemsFromRootNode(graph, this.root, this.open, getItem);
1004
- },
1005
- // TODO(thure): Do this dynamically.
1006
- open: [
1025
+ let unsubscribe;
1026
+ const state = new Map(getInitialState() ?? [
1027
+ // TODO(thure): Initialize these dynamically.
1028
+ [
1007
1029
  "root",
1030
+ create({
1031
+ open: true,
1032
+ current: false
1033
+ })
1034
+ ],
1035
+ [
1008
1036
  "root~dxos.org/plugin/space-spaces",
1009
- "root~dxos.org/plugin/files"
1037
+ create({
1038
+ open: true,
1039
+ current: false
1040
+ })
1041
+ ],
1042
+ [
1043
+ "root~dxos.org/plugin/files",
1044
+ create({
1045
+ open: true,
1046
+ current: false
1047
+ })
1010
1048
  ]
1011
- });
1012
- const getItem = (node, parent, filter) => {
1013
- invariant(graph, void 0, {
1014
- F: __dxlog_file,
1015
- L: 82,
1016
- S: void 0,
1017
- A: [
1018
- "graph",
1019
- ""
1020
- ]
1049
+ ]);
1050
+ const getItem = (_path) => {
1051
+ const path = Path.create(..._path);
1052
+ const value = state.get(path) ?? create({
1053
+ open: false,
1054
+ current: false
1021
1055
  });
1022
- const path = [
1023
- ...parent,
1024
- node.id
1025
- ];
1026
- const { actions, groupedActions } = getActions(graph, node);
1027
- const children = getChildren(graph, node, filter, path);
1028
- const parentOf = children.length > 0 ? children.map(({ id }) => id) : node.properties.role === "branch" ? [] : void 0;
1029
- const item = {
1030
- id: node.id,
1031
- label: node.properties.label ?? node.id,
1032
- icon: node.properties.icon,
1033
- disabled: node.properties.disabled,
1034
- testId: node.properties.testId,
1035
- className: mx5(node.properties.modified && "italic", node.properties.className),
1036
- headingClassName: node.properties.headingClassName,
1037
- path,
1038
- parentOf,
1039
- node,
1040
- actions,
1041
- groupedActions
1042
- };
1043
- const cachedItem = itemCache.get(node.id);
1044
- if (cachedItem && JSON.stringify(item) === JSON.stringify(cachedItem)) {
1045
- return cachedItem;
1046
- } else {
1047
- itemCache.set(node.id, item);
1048
- return item;
1056
+ if (!state.has(path)) {
1057
+ state.set(path, value);
1049
1058
  }
1059
+ return value;
1050
1060
  };
1051
- const handleOpenChange = (item, open) => {
1052
- const path = Path2.create(...item.path);
1053
- if (open) {
1054
- state.values.open.push(path);
1055
- } else {
1056
- const index = state.values.open.indexOf(path);
1057
- if (index > -1) {
1058
- state.values.open.splice(index, 1);
1059
- }
1060
- }
1061
+ const setItem = (path, key, next) => {
1062
+ const value = getItem(path);
1063
+ value[key] = next;
1064
+ localStorage.setItem(KEY, JSON.stringify(Array.from(state.entries())));
1065
+ };
1066
+ const isOpen = (path) => getItem(path).open;
1067
+ const isCurrent = (path) => getItem(path).current;
1068
+ const handleOpenChange = ({ item: { id }, path, open }) => {
1069
+ setItem(path, "open", open);
1061
1070
  if (graph) {
1062
- void expandOpenGraphNodes(graph, state.values.open);
1071
+ const node = graph.findNode(id);
1072
+ return node && expandChildrenAndActions(graph, node);
1063
1073
  }
1064
1074
  };
1065
1075
  return {
1066
1076
  meta: meta_default,
1067
1077
  ready: async (plugins) => {
1068
- state.prop({
1069
- key: "open",
1070
- type: LocalStorageStore.json()
1071
- });
1078
+ const layout = resolvePlugin(plugins, parseLayoutPlugin)?.provides.layout;
1079
+ const location = resolvePlugin(plugins, parseNavigationPlugin2)?.provides.location;
1072
1080
  graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
1073
1081
  graph = graphPlugin?.provides.graph;
1074
- if (!graph) {
1082
+ if (!graph || !location || !layout) {
1075
1083
  return;
1076
1084
  }
1085
+ const soloPart = location?.active.solo?.[0];
1077
1086
  const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
1078
- const soloPart = resolvePlugin(plugins, parseNavigationPlugin2)?.provides.location.active.solo?.[0];
1079
1087
  if (dispatch && soloPart) {
1080
1088
  void dispatch({
1081
1089
  plugin: NAVTREE_PLUGIN,
@@ -1085,8 +1093,30 @@ var NavTreePlugin = () => {
1085
1093
  }
1086
1094
  });
1087
1095
  }
1088
- state.values.root = graph.root;
1089
- void expandOpenGraphNodes(graph, state.values.open);
1096
+ let previous = [];
1097
+ unsubscribe = effect(() => {
1098
+ const part = layout.layoutMode === "solo" ? "solo" : "main";
1099
+ const current = location.active[part]?.map(({ id }) => id) ?? [];
1100
+ const removed = previous.filter((id) => !current.includes(id));
1101
+ previous = current;
1102
+ setTimeout(() => {
1103
+ removed.forEach((id) => {
1104
+ const keys = Array.from(state.keys()).filter((key) => Path.last(key) === id);
1105
+ keys.forEach((key) => {
1106
+ setItem(Path.parts(key), "current", false);
1107
+ });
1108
+ });
1109
+ current.forEach((id) => {
1110
+ const keys = Array.from(/* @__PURE__ */ new Set([
1111
+ ...state.keys(),
1112
+ id
1113
+ ])).filter((key) => Path.last(key) === id);
1114
+ keys.forEach((key) => {
1115
+ setItem(Path.parts(key), "current", true);
1116
+ });
1117
+ });
1118
+ });
1119
+ });
1090
1120
  graph.subscribeTraverse({
1091
1121
  visitor: (node, path) => {
1092
1122
  let shortcut;
@@ -1115,22 +1145,23 @@ var NavTreePlugin = () => {
1115
1145
  Keyboard2.singleton.setCurrentContext(graphPlugin?.provides.graph.root.id);
1116
1146
  },
1117
1147
  unload: async () => {
1148
+ unsubscribe?.();
1118
1149
  Keyboard2.singleton.destroy();
1119
1150
  },
1120
1151
  provides: {
1121
1152
  metadata: {
1122
1153
  records: {
1123
1154
  [NODE_TYPE]: {
1124
- parse: (item, type) => {
1155
+ parse: ({ item }, type) => {
1125
1156
  switch (type) {
1126
1157
  case "node":
1127
- return item.node;
1158
+ return item;
1128
1159
  case "object":
1129
- return item.node.data;
1160
+ return item.data;
1130
1161
  case "view-object":
1131
1162
  return {
1132
1163
  id: `${item.id}-view`,
1133
- object: item.node.data
1164
+ object: item.data
1134
1165
  };
1135
1166
  }
1136
1167
  }
@@ -1150,9 +1181,8 @@ var NavTreePlugin = () => {
1150
1181
  switch (role) {
1151
1182
  case "navigation":
1152
1183
  return /* @__PURE__ */ React10.createElement(NavTreeContainer, {
1153
- items: state.values.flatTree,
1154
- current: data.activeIds,
1155
- open: state.values.open,
1184
+ isOpen,
1185
+ isCurrent,
1156
1186
  onOpenChange: handleOpenChange,
1157
1187
  popoverAnchorId: data.popoverAnchorId
1158
1188
  });
@@ -1162,7 +1192,7 @@ var NavTreePlugin = () => {
1162
1192
  });
1163
1193
  }
1164
1194
  case "navbar-start": {
1165
- if (state.values.root && data.activeNode) {
1195
+ if (data.activeNode) {
1166
1196
  return {
1167
1197
  node: /* @__PURE__ */ React10.createElement(NavBarStart, {
1168
1198
  activeNode: data.activeNode,
@@ -1192,16 +1222,15 @@ var NavTreePlugin = () => {
1192
1222
  const path = await graph.waitForPath({
1193
1223
  target: intent.data.id
1194
1224
  });
1195
- const additionalOpenItems = [
1225
+ [
1196
1226
  ...Array(path.length)
1197
- ].reduce((acc, _, index) => {
1198
- const itemId = Path2.create(...path.slice(0, index));
1199
- if (itemId.length > 0 && !state.values.open.includes(itemId)) {
1200
- acc.push(itemId);
1227
+ ].forEach((_, index) => {
1228
+ const subpath = path.slice(0, index);
1229
+ const value = getItem(subpath);
1230
+ if (!value.open) {
1231
+ setItem(subpath, "open", true);
1201
1232
  }
1202
- return acc;
1203
- }, []);
1204
- state.values.open.push(...additionalOpenItems);
1233
+ });
1205
1234
  }
1206
1235
  break;
1207
1236
  }
@@ -1220,7 +1249,7 @@ var NavTreePlugin = () => {
1220
1249
  id: "dxos.org/plugin/navtree/open-commands",
1221
1250
  data: async () => {
1222
1251
  await intentPlugin?.provides.intent.dispatch({
1223
- action: LayoutAction3.SET_LAYOUT,
1252
+ action: LayoutAction4.SET_LAYOUT,
1224
1253
  data: {
1225
1254
  element: "dialog",
1226
1255
  component: `${NAVTREE_PLUGIN}/Commands`,
@@ -1260,14 +1289,11 @@ export {
1260
1289
  expandActions,
1261
1290
  expandChildren,
1262
1291
  expandChildrenAndActions,
1263
- expandOpenGraphNodes,
1264
1292
  getActions,
1265
1293
  getChildren,
1266
1294
  getParent,
1267
1295
  getPersistenceParent,
1268
- getTreeItemNode,
1269
1296
  resolveMigrationOperation,
1270
- sortActions,
1271
- treeItemsFromRootNode
1297
+ sortActions
1272
1298
  };
1273
1299
  //# sourceMappingURL=index.mjs.map