@dxos/plugin-navtree 0.8.1 → 0.8.2-main.12df754

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/{chunk-DN43QXSX.mjs → chunk-FHOAKMRS.mjs} +134 -47
  2. package/dist/lib/browser/chunk-FHOAKMRS.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-4RQJXI4D.mjs → chunk-TLQLMZXU.mjs} +1 -1
  4. package/dist/lib/browser/chunk-TLQLMZXU.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +3 -2
  6. package/dist/lib/browser/index.mjs.map +2 -2
  7. package/dist/lib/browser/{intent-resolver-BZMUS24C.mjs → intent-resolver-OBGGMBVJ.mjs} +2 -2
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs → react-surface-DWMOF2TM.mjs} +3 -3
  10. package/dist/lib/browser/{state-M5UJ3MHL.mjs → state-EW62QYEN.mjs} +17 -11
  11. package/dist/lib/browser/state-EW62QYEN.mjs.map +7 -0
  12. package/dist/types/src/capabilities/capabilities.d.ts +7 -4
  13. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  14. package/dist/types/src/capabilities/index.d.ts +34 -3
  15. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  16. package/dist/types/src/capabilities/state.d.ts +7 -4
  17. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  18. package/dist/types/src/components/L1Panels.d.ts.map +1 -1
  19. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  20. package/dist/types/src/components/NavTreeItemAction.d.ts.map +1 -1
  21. package/dist/types/src/components/NavTreeItemColumns.d.ts +1 -1
  22. package/dist/types/src/components/NavTreeItemColumns.d.ts.map +1 -1
  23. package/dist/types/src/components/types.d.ts +4 -0
  24. package/dist/types/src/components/types.d.ts.map +1 -1
  25. package/dist/types/src/testing/generator.d.ts +2 -2
  26. package/dist/types/src/testing/generator.d.ts.map +1 -1
  27. package/dist/types/src/translations.d.ts +1 -0
  28. package/dist/types/src/translations.d.ts.map +1 -1
  29. package/package.json +31 -31
  30. package/src/capabilities/capabilities.ts +5 -4
  31. package/src/capabilities/state.ts +20 -14
  32. package/src/components/L1Panels.tsx +115 -30
  33. package/src/components/NavTree.stories.tsx +5 -5
  34. package/src/components/NavTreeContainer.tsx +16 -2
  35. package/src/components/NavTreeItemAction.tsx +10 -4
  36. package/src/components/NavTreeItemColumns.tsx +29 -27
  37. package/src/components/UserAccountAvatar.tsx +1 -1
  38. package/src/components/types.ts +4 -0
  39. package/src/stories/Graph.stories.tsx +4 -4
  40. package/src/testing/generator.ts +3 -3
  41. package/src/translations.ts +1 -0
  42. package/dist/lib/browser/chunk-4RQJXI4D.mjs.map +0 -7
  43. package/dist/lib/browser/chunk-DN43QXSX.mjs.map +0 -7
  44. package/dist/lib/browser/state-M5UJ3MHL.mjs.map +0 -7
  45. /package/dist/lib/browser/{intent-resolver-BZMUS24C.mjs.map → intent-resolver-OBGGMBVJ.mjs.map} +0 -0
  46. /package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs.map → react-surface-DWMOF2TM.mjs.map} +0 -0
@@ -2,14 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useMemo } from 'react';
5
+ import React, { useCallback, useMemo } from 'react';
6
6
 
7
7
  import { useLayout } from '@dxos/app-framework';
8
8
  import { type Node } from '@dxos/app-graph';
9
- import { Button, Icon, toLocalizedString, useTranslation } from '@dxos/react-ui';
9
+ import { Button, type ButtonProps, Icon, IconButton, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
10
  import { Tree } from '@dxos/react-ui-list';
11
11
  import { Tabs } from '@dxos/react-ui-tabs';
12
12
  import { hoverableControlItem, hoverableOpenControlItem, mx } from '@dxos/react-ui-theme';
13
+ import { byPosition } from '@dxos/util';
13
14
 
14
15
  import { useNavTreeContext } from './NavTreeContext';
15
16
  import { NavTreeItemColumns } from './NavTreeItemColumns';
@@ -17,12 +18,78 @@ import { useLoadDescendents } from '../hooks';
17
18
  import { NAVTREE_PLUGIN } from '../meta';
18
19
  import { l0ItemType } from '../util';
19
20
 
20
- export type L1PanelProps = { item: Node<any>; path: string[]; currentItemId: string; onBack?: () => void };
21
+ export type L1PanelProps = {
22
+ item: Node<any>;
23
+ path: string[];
24
+ currentItemId: string;
25
+ onBack?: () => void;
26
+ };
27
+
28
+ const headingBackButtonLabel =
29
+ 'absolute inset-0 min-is-0 truncate flex items-center pis-6 transition-[transform,opacity] ease-in-out duration-200';
30
+
31
+ const HeadingBackButton = ({ title, onClick }: { title: string } & Pick<ButtonProps, 'onClick'>) => {
32
+ const { t } = useTranslation(NAVTREE_PLUGIN);
33
+ return (
34
+ <Button
35
+ variant='ghost'
36
+ classNames='pli-1 flex-1 relative group text-start justify-start bs-[--rail-action] font-normal'
37
+ onClick={onClick}
38
+ >
39
+ <Icon icon='ph--caret-left--bold' size={3} />
40
+ <span
41
+ className={mx(
42
+ headingBackButtonLabel,
43
+ 'translate-y-2 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 group-focus:translate-y-0 group-focus:opacity-100',
44
+ )}
45
+ >
46
+ {t('back label')}
47
+ </span>
48
+ <span
49
+ className={mx(
50
+ headingBackButtonLabel,
51
+ 'translate-y-0 opacity-100 group-hover:-translate-y-2 group-hover:opacity-0 group-focus:-translate-y-2 group-focus:opacity-0',
52
+ )}
53
+ >
54
+ {title}
55
+ </span>
56
+ </Button>
57
+ );
58
+ };
21
59
 
22
60
  const L1Panel = ({ item, path, currentItemId, onBack }: L1PanelProps) => {
23
61
  const layout = useLayout();
24
- const navTreeContext = useNavTreeContext();
62
+ const { isAlternateTree, setAlternateTree, ...navTreeContext } = useNavTreeContext();
25
63
  const { t } = useTranslation(NAVTREE_PLUGIN);
64
+
65
+ // TODO(wittjosiah): Support multiple alternate trees.
66
+ const alternateTree = navTreeContext.getItems(item, 'alternate-tree')[0];
67
+ const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
68
+ const handleOpen = useCallback(() => setAlternateTree?.(alternatePath, true), [alternatePath, setAlternateTree]);
69
+ const isAlternate = isAlternateTree?.(alternatePath, item) ?? false;
70
+ const alternateGetItems = useCallback(
71
+ (node?: Node, disposition?: string) => {
72
+ const items = navTreeContext.getItems(node, disposition);
73
+ if (node === alternateTree) {
74
+ // TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
75
+ return items.toSorted((a, b) => byPosition(a.properties, b.properties));
76
+ }
77
+ return items;
78
+ },
79
+ [navTreeContext, alternateTree],
80
+ );
81
+
82
+ const handleBack = useCallback(() => {
83
+ if (isAlternate) {
84
+ setAlternateTree?.(alternatePath, false);
85
+ } else {
86
+ onBack?.();
87
+ }
88
+ }, [isAlternate, onBack, alternatePath, setAlternateTree]);
89
+
90
+ const title = toLocalizedString(item.properties.label, t);
91
+ const backCapable = item.id.startsWith('!') || isAlternate;
92
+
26
93
  return (
27
94
  <Tabs.Tabpanel
28
95
  key={item.id}
@@ -32,38 +99,56 @@ const L1Panel = ({ item, path, currentItemId, onBack }: L1PanelProps) => {
32
99
  item.id === currentItemId && 'grid',
33
100
  ]}
34
101
  tabIndex={-1}
102
+ aria-label={title}
35
103
  {...(!layout.sidebarOpen && { inert: 'true' })}
36
104
  >
37
105
  {item.id === currentItemId && (
38
106
  <>
39
- <h2 className='flex items-center border-be border-separator app-drag'>
40
- <Button
41
- variant='ghost'
42
- density='fine'
43
- classNames={mx(
44
- 'is-6 pli-0 dx-focus-ring-inset',
45
- !item.id.startsWith('!') && 'invisible',
46
- hoverableControlItem,
47
- hoverableOpenControlItem,
48
- )}
49
- onClick={onBack}
50
- >
51
- <Icon icon='ph--caret-left--regular' size={3} />
52
- </Button>
53
- <span className='flex-1 truncate cursor-default'>{toLocalizedString(item.properties.label, t)}</span>
54
- <NavTreeItemColumns path={path} item={item} open />
107
+ <h2 className='flex items-center border-be border-separator app-drag pis-1'>
108
+ {backCapable ? (
109
+ <HeadingBackButton title={title} onClick={handleBack} />
110
+ ) : (
111
+ <span className='flex-1 truncate min-is-0 pis-6'>{title}</span>
112
+ )}
113
+ {alternateTree && !isAlternate && (
114
+ <IconButton
115
+ variant='ghost'
116
+ classNames={mx('shrink-0', hoverableControlItem, hoverableOpenControlItem, 'pli-2 pointer-fine:pli-1')}
117
+ iconOnly
118
+ size={5}
119
+ density='coarse'
120
+ icon={alternateTree.properties.icon ?? 'ph--placeholder--regular'}
121
+ label={toLocalizedString(alternateTree.properties.label ?? alternateTree.id, t)}
122
+ data-testid='treeView.alternateTreeButton'
123
+ onClick={handleOpen}
124
+ />
125
+ )}
126
+ <NavTreeItemColumns path={path} item={item} open density='coarse' />
55
127
  </h2>
56
128
  <div role='none' className='overflow-y-auto'>
57
- <Tree
58
- {...navTreeContext}
59
- id={item.id}
60
- root={item}
61
- path={path}
62
- levelOffset={5}
63
- draggable
64
- gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
65
- renderColumns={NavTreeItemColumns}
66
- />
129
+ {isAlternate ? (
130
+ <Tree
131
+ {...navTreeContext}
132
+ getItems={alternateGetItems}
133
+ id={alternateTree.id}
134
+ root={alternateTree}
135
+ path={alternatePath}
136
+ levelOffset={5}
137
+ gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
138
+ renderColumns={NavTreeItemColumns}
139
+ />
140
+ ) : (
141
+ <Tree
142
+ {...navTreeContext}
143
+ id={item.id}
144
+ root={item}
145
+ path={path}
146
+ levelOffset={5}
147
+ draggable
148
+ gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
149
+ renderColumns={NavTreeItemColumns}
150
+ />
151
+ )}
67
152
  </div>
68
153
  </>
69
154
  )}
@@ -10,7 +10,7 @@ import { type Meta } from '@storybook/react';
10
10
  import React, { useEffect } from 'react';
11
11
 
12
12
  import { isActionLike, type NodeArg } from '@dxos/app-graph';
13
- import { create, type ReactiveObject } from '@dxos/live-object';
13
+ import { live, type Live } from '@dxos/live-object';
14
14
  import { faker } from '@dxos/random';
15
15
  import { isTreeData, type TreeData } from '@dxos/react-ui-list';
16
16
  import { Path } from '@dxos/react-ui-list';
@@ -21,8 +21,8 @@ import { createTree, updateState } from '../testing';
21
21
 
22
22
  faker.seed(1234);
23
23
 
24
- const tree = create<NodeArg<any>>(createTree());
25
- const state = new Map<string, ReactiveObject<{ open: boolean; current: boolean }>>();
24
+ const tree = live<NodeArg<any>>(createTree());
25
+ const state = new Map<string, Live<{ open: boolean; current: boolean }>>();
26
26
 
27
27
  const meta: Meta<typeof StorybookNavTree> = {
28
28
  title: 'plugins/plugin-navtree/NavTree',
@@ -73,7 +73,7 @@ const meta: Meta<typeof StorybookNavTree> = {
73
73
  }),
74
74
  isOpen: (_path: string[]) => {
75
75
  const path = Path.create(..._path);
76
- const value = state.get(path) ?? create({ open: false, current: false });
76
+ const value = state.get(path) ?? live({ open: false, current: false });
77
77
  if (!state.has(path)) {
78
78
  state.set(path, value);
79
79
  }
@@ -82,7 +82,7 @@ const meta: Meta<typeof StorybookNavTree> = {
82
82
  },
83
83
  isCurrent: (_path: string[]) => {
84
84
  const path = Path.create(..._path);
85
- const value = state.get(path) ?? create({ open: false, current: false });
85
+ const value = state.get(path) ?? live({ open: false, current: false });
86
86
  if (!state.has(path)) {
87
87
  state.set(path, value);
88
88
  }
@@ -59,7 +59,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
59
59
  const { dispatchPromise: dispatch } = useIntentDispatcher();
60
60
  const { graph } = useAppGraph();
61
61
  const layout = useLayout();
62
- const { isOpen, isCurrent, setItem } = useCapability(NavTreeCapabilities.State);
62
+ const { isOpen, isCurrent, isAlternateTree, setItem } = useCapability(NavTreeCapabilities.State);
63
63
 
64
64
  const getActions = useCallback((node: Node) => naturalGetActions(graph, node), [graph]);
65
65
 
@@ -68,7 +68,10 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
68
68
  return graph.nodes(node ?? graph.root, {
69
69
  filter: (node): node is Node => {
70
70
  return untracked(() => {
71
- if (node.properties.disposition === 'hidden') {
71
+ if (
72
+ !disposition &&
73
+ (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')
74
+ ) {
72
75
  return false;
73
76
  } else if (!disposition) {
74
77
  const action = isAction(node);
@@ -262,6 +265,13 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
262
265
  });
263
266
  }, [graph]);
264
267
 
268
+ const setAlternateTree = useCallback(
269
+ (path: string[], open: boolean) => {
270
+ setItem(path, 'alternateTree', open);
271
+ },
272
+ [setItem],
273
+ );
274
+
265
275
  const navTreeContextValue = useMemo(
266
276
  () => ({
267
277
  tab,
@@ -279,6 +289,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
279
289
  onOpenChange,
280
290
  canDrop,
281
291
  onSelect: handleSelect,
292
+ isAlternateTree,
293
+ setAlternateTree,
282
294
  }),
283
295
  [
284
296
  tab,
@@ -296,6 +308,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
296
308
  onOpenChange,
297
309
  canDrop,
298
310
  handleSelect,
311
+ isAlternateTree,
312
+ setAlternateTree,
299
313
  ],
300
314
  );
301
315
 
@@ -5,7 +5,7 @@
5
5
  import React, { type MutableRefObject, useRef } from 'react';
6
6
 
7
7
  import { type Action, type Node } from '@dxos/app-graph';
8
- import { useTranslation, toLocalizedString, IconButton } from '@dxos/react-ui';
8
+ import { useTranslation, toLocalizedString, IconButton, useDensityContext } from '@dxos/react-ui';
9
9
  import { DropdownMenu, MenuProvider, type MenuItem } from '@dxos/react-ui-menu';
10
10
  import { hoverableControlItem, hoverableOpenControlItem, mx } from '@dxos/react-ui-theme';
11
11
 
@@ -23,10 +23,14 @@ export type NavTreeItemActionMenuProps = ActionProperties & {
23
23
 
24
24
  const fallbackIcon = 'ph--placeholder--regular';
25
25
 
26
- const actionButtonProps = {
26
+ const fineActionButtonProps = {
27
27
  size: 4 as const,
28
28
  density: 'fine' as const,
29
29
  };
30
+ const coarseActionButtonProps = {
31
+ size: 5 as const,
32
+ density: 'coarse' as const,
33
+ };
30
34
 
31
35
  export const NavTreeItemActionDropdownMenu = ({
32
36
  label,
@@ -37,12 +41,13 @@ export const NavTreeItemActionDropdownMenu = ({
37
41
  }: NavTreeItemActionMenuProps) => {
38
42
  const { t } = useTranslation(NAVTREE_PLUGIN);
39
43
  const suppressNextTooltip = useRef<boolean>(false);
44
+ const density = useDensityContext();
40
45
  return (
41
46
  <MenuProvider onAction={onAction}>
42
47
  <DropdownMenu.Root items={menuActions as MenuItem[]} suppressNextTooltip={suppressNextTooltip}>
43
48
  <DropdownMenu.Trigger asChild>
44
49
  <IconButton
45
- {...actionButtonProps}
50
+ {...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
46
51
  classNames={mx('shrink-0 pli-2 pointer-fine:pli-1', hoverableControlItem, hoverableOpenControlItem)}
47
52
  variant='ghost'
48
53
  icon={icon ?? fallbackIcon}
@@ -63,9 +68,10 @@ export const NavTreeItemMonolithicAction = ({
63
68
  data: invoke,
64
69
  baseLabel,
65
70
  }: Action & { parent: Node; onAction?: (action: Action) => void; baseLabel: string }) => {
71
+ const density = useDensityContext();
66
72
  return (
67
73
  <IconButton
68
- {...actionButtonProps}
74
+ {...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
69
75
  variant={variant}
70
76
  classNames={mx(
71
77
  'shrink-0',
@@ -5,7 +5,7 @@
5
5
  import React, { Fragment, memo } from 'react';
6
6
 
7
7
  import { isAction } from '@dxos/app-graph';
8
- import { Popover, toLocalizedString, Treegrid, useTranslation } from '@dxos/react-ui';
8
+ import { DensityProvider, Popover, toLocalizedString, Treegrid, useTranslation } from '@dxos/react-ui';
9
9
 
10
10
  import { NAV_TREE_ITEM } from './NavTree';
11
11
  import { useNavTreeContext } from './NavTreeContext';
@@ -14,7 +14,7 @@ import type { NavTreeItemColumnsProps } from './types';
14
14
  import { useLoadDescendents } from '../hooks';
15
15
  import { NAVTREE_PLUGIN } from '../meta';
16
16
 
17
- export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumnsProps) => {
17
+ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }: NavTreeItemColumnsProps) => {
18
18
  const { t } = useTranslation(NAVTREE_PLUGIN);
19
19
  const { getActions, renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();
20
20
 
@@ -35,37 +35,39 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
35
35
  useLoadDescendents(primaryAction && !isAction(primaryAction) ? primaryAction : undefined);
36
36
 
37
37
  return (
38
- <div role='none' className='contents app-no-drag'>
39
- {primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled ? (
40
- <NavTreeItemAction
41
- testId={primaryAction.properties?.testId}
42
- label={toLocalizedString(primaryAction.properties?.label, t)}
43
- icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
44
- parent={item}
45
- monolithic={isAction(primaryAction)}
46
- menuActions={isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction.id]}
47
- menuType={primaryAction.properties?.menuType}
48
- caller={NAV_TREE_ITEM}
49
- />
50
- ) : (
51
- <Treegrid.Cell />
52
- )}
53
- <ActionRoot>
54
- {actions.length > 0 ? (
38
+ <DensityProvider density={density}>
39
+ <div role='none' className='contents app-no-drag'>
40
+ {primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled ? (
55
41
  <NavTreeItemAction
56
- testId={`navtree.treeItem.actionsLevel${level}`}
57
- label={t('tree item actions label')}
58
- icon='ph--dots-three-vertical--regular'
42
+ testId={primaryAction.properties?.testId}
43
+ label={toLocalizedString(primaryAction.properties?.label, t)}
44
+ icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
59
45
  parent={item}
60
- menuActions={actions}
61
- menuType='dropdown'
46
+ monolithic={isAction(primaryAction)}
47
+ menuActions={isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction.id]}
48
+ menuType={primaryAction.properties?.menuType}
62
49
  caller={NAV_TREE_ITEM}
63
50
  />
64
51
  ) : (
65
52
  <Treegrid.Cell />
66
53
  )}
67
- </ActionRoot>
68
- {ItemEnd && <ItemEnd node={item} open={open} />}
69
- </div>
54
+ <ActionRoot>
55
+ {actions.length > 0 ? (
56
+ <NavTreeItemAction
57
+ testId={`navtree.treeItem.actionsLevel${level}`}
58
+ label={t('tree item actions label')}
59
+ icon='ph--dots-three-vertical--regular'
60
+ parent={item}
61
+ menuActions={actions}
62
+ menuType='dropdown'
63
+ caller={NAV_TREE_ITEM}
64
+ />
65
+ ) : (
66
+ <Treegrid.Cell />
67
+ )}
68
+ </ActionRoot>
69
+ {ItemEnd && <ItemEnd node={item} open={open} />}
70
+ </div>
71
+ </DensityProvider>
70
72
  );
71
73
  });
@@ -27,7 +27,7 @@ export const UserAccountAvatar = (props: UserAccountAvatarProps) => {
27
27
  status={props.status ?? 'active'}
28
28
  hue={props.hue || fallbackValue.hue}
29
29
  fallback={props.emoji || fallbackValue.emoji}
30
- data-testid='treeview.userAccount'
30
+ data-testid='treeView.userAccount'
31
31
  />
32
32
  </Avatar.Root>
33
33
  </div>
@@ -5,6 +5,7 @@
5
5
  import type { FC } from 'react';
6
6
 
7
7
  import type { Node } from '@dxos/app-graph';
8
+ import type { Density } from '@dxos/react-ui';
8
9
  import type { TreeProps } from '@dxos/react-ui-list';
9
10
  import type { MaybePromise } from '@dxos/util';
10
11
 
@@ -15,6 +16,7 @@ export type NavTreeItemColumnsProps = {
15
16
  path: string[];
16
17
  item: Node;
17
18
  open: boolean;
19
+ density?: Density;
18
20
  };
19
21
 
20
22
  export type NavTreeProps = Pick<TreeProps<NavTreeItemGraphNode>, 'id' | 'root'>;
@@ -32,4 +34,6 @@ export type NavTreeContextValue = Pick<
32
34
  renderItemEnd?: FC<{ node: Node; open: boolean }>;
33
35
  popoverAnchorId?: string;
34
36
  topbar?: boolean;
37
+ isAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
38
+ setAlternateTree?: (path: string[], open: boolean) => void;
35
39
  };
@@ -12,7 +12,7 @@ import React, { useEffect } from 'react';
12
12
 
13
13
  import { Graph, ROOT_ID, type Node } from '@dxos/app-graph';
14
14
  import { registerSignalsRuntime } from '@dxos/echo-signals/react';
15
- import { create, type ReactiveObject } from '@dxos/live-object';
15
+ import { live, type Live } from '@dxos/live-object';
16
16
  import { faker } from '@dxos/random';
17
17
  import { isTreeData, type PropsFromTreeItem } from '@dxos/react-ui-list';
18
18
  import { Path } from '@dxos/react-ui-list';
@@ -49,7 +49,7 @@ const createGraph = () => {
49
49
  };
50
50
 
51
51
  const graph = createGraph();
52
- const state = new Map<string, ReactiveObject<{ open: boolean; current: boolean }>>();
52
+ const state = new Map<string, Live<{ open: boolean; current: boolean }>>();
53
53
 
54
54
  export const Default = {};
55
55
 
@@ -98,7 +98,7 @@ const meta: Meta<typeof StorybookNavTree> = {
98
98
  },
99
99
  isOpen: (_path: string[]) => {
100
100
  const path = Path.create(..._path);
101
- const value = state.get(path) ?? create({ open: false, current: false });
101
+ const value = state.get(path) ?? live({ open: false, current: false });
102
102
  if (!state.has(path)) {
103
103
  state.set(path, value);
104
104
  }
@@ -107,7 +107,7 @@ const meta: Meta<typeof StorybookNavTree> = {
107
107
  },
108
108
  isCurrent: (_path: string[]) => {
109
109
  const path = Path.create(..._path);
110
- const value = state.get(path) ?? create({ open: false, current: false });
110
+ const value = state.get(path) ?? live({ open: false, current: false });
111
111
  if (!state.has(path)) {
112
112
  state.set(path, value);
113
113
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { type NodeArg } from '@dxos/app-graph';
6
6
  import { S, TypedObject } from '@dxos/echo-schema';
7
- import { create, type ReactiveObject } from '@dxos/live-object';
7
+ import { live, type Live } from '@dxos/live-object';
8
8
  import { faker } from '@dxos/random';
9
9
  import { range } from '@dxos/util';
10
10
 
@@ -19,7 +19,7 @@ type ObjectDataGenerator = {
19
19
  createData: () => any;
20
20
  };
21
21
 
22
- type ObjectFactory<T extends ReactiveObject<any>> = {
22
+ type ObjectFactory<T extends Live<any>> = {
23
23
  schema?: S.Schema.AnyNoContext; // TODO(burdon): Support both typed and expando schema.
24
24
  createObject: () => T;
25
25
  };
@@ -30,7 +30,7 @@ const createFactory = ({ createSchema, createData }: ObjectDataGenerator) => {
30
30
  const schema = createSchema?.();
31
31
  return {
32
32
  schema,
33
- createObject: () => (schema ? create(schema, createData()) : create(createData())),
33
+ createObject: () => (schema ? live(schema, createData()) : live(createData())),
34
34
  };
35
35
  };
36
36
 
@@ -8,6 +8,7 @@ export default [
8
8
  {
9
9
  'en-US': {
10
10
  [NAVTREE_PLUGIN]: {
11
+ 'back label': 'Back',
11
12
  'open settings label': 'Settings',
12
13
  'open commands label': 'Search commands',
13
14
  'commands dialog title': 'Commands',
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/capabilities.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { defineCapability } from '@dxos/app-framework';\nimport { type ReactiveObject } from '@dxos/live-object';\n\nimport { NAVTREE_PLUGIN } from '../meta';\nimport { type NavTreeItemGraphNode } from '../types';\n\nexport namespace NavTreeCapabilities {\n export const State = defineCapability<{\n state: Map<string, ReactiveObject<{ open: boolean; current: boolean }>>;\n getItem: (path: string[]) => ReactiveObject<{ open: boolean; current: boolean }>;\n setItem: (path: string[], key: 'open' | 'current', next: boolean) => void;\n isOpen: (path: string[], item: NavTreeItemGraphNode) => boolean;\n isCurrent: (path: string[], item: NavTreeItemGraphNode) => boolean;\n }>(`${NAVTREE_PLUGIN}/capability/state`);\n}\n"],
5
- "mappings": ";;;;;AAIA,SAASA,wBAAwB;;UAMhBC,sBAAAA;uBACFC,QAAQC,iBAMlB,GAAGC,cAAAA,mBAAiC;AACzC,GARiBH,wBAAAA,sBAAAA,CAAAA,EAAAA;",
6
- "names": ["defineCapability", "NavTreeCapabilities", "State", "defineCapability", "NAVTREE_PLUGIN"]
7
- }