@dxos/plugin-navtree 0.8.2-staging.7ac8446 → 0.8.3-main.672df60

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 (149) hide show
  1. package/dist/lib/browser/{app-graph-builder-26D3MUCA.mjs → app-graph-builder-P7AY3K72.mjs} +7 -6
  2. package/dist/lib/browser/app-graph-builder-P7AY3K72.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-4RQJXI4D.mjs → chunk-33VLL4IJ.mjs} +2 -2
  4. package/dist/lib/browser/chunk-33VLL4IJ.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-MFAWMFJC.mjs +1418 -0
  6. package/dist/lib/browser/chunk-MFAWMFJC.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +6 -11
  8. package/dist/lib/browser/index.mjs.map +3 -3
  9. package/dist/lib/browser/{intent-resolver-BZMUS24C.mjs → intent-resolver-NAYKKAOP.mjs} +7 -7
  10. package/dist/lib/browser/intent-resolver-NAYKKAOP.mjs.map +7 -0
  11. package/dist/lib/browser/keyboard-DDFATRUG.mjs +51 -0
  12. package/dist/lib/browser/keyboard-DDFATRUG.mjs.map +7 -0
  13. package/dist/lib/browser/meta.json +1 -1
  14. package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs → react-surface-HGA3TAQU.mjs} +3 -3
  15. package/dist/lib/browser/{state-M5UJ3MHL.mjs → state-R2UMYAHN.mjs} +18 -12
  16. package/dist/lib/browser/state-R2UMYAHN.mjs.map +7 -0
  17. package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
  18. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  19. package/dist/types/src/capabilities/capabilities.d.ts +7 -4
  20. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  21. package/dist/types/src/capabilities/index.d.ts +38 -183
  22. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  23. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  24. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/keyboard.d.ts +2 -2
  26. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
  27. package/dist/types/src/capabilities/state.d.ts +9 -6
  28. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  29. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -0
  30. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -0
  31. package/dist/types/src/components/CommandsDialog/index.d.ts +3 -0
  32. package/dist/types/src/components/CommandsDialog/index.d.ts.map +1 -0
  33. package/dist/types/src/components/NavTree/NavTree.d.ts +8 -0
  34. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -0
  35. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +8 -0
  36. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -0
  37. package/dist/types/src/components/NavTree/index.d.ts +2 -0
  38. package/dist/types/src/components/NavTree/index.d.ts.map +1 -0
  39. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  40. package/dist/types/src/components/NavTreeContext.d.ts.map +1 -1
  41. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
  42. package/dist/types/src/components/{NavTreeItemAction.d.ts → NavTreeItem/NavTreeItemAction.d.ts} +3 -5
  43. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -0
  44. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +8 -0
  45. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -0
  46. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +4 -0
  47. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -0
  48. package/dist/types/src/components/NavTreeItem/index.d.ts +3 -0
  49. package/dist/types/src/components/NavTreeItem/index.d.ts.map +1 -0
  50. package/dist/types/src/components/Sidebar/L0Menu.d.ts +13 -0
  51. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -0
  52. package/dist/types/src/components/Sidebar/L1Panel.d.ts +15 -0
  53. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -0
  54. package/dist/types/src/components/Sidebar/index.d.ts +3 -0
  55. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -0
  56. package/dist/types/src/components/{UserAccountAvatar.d.ts → UserAccountAvatar/UserAccountAvatar.d.ts} +1 -1
  57. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -0
  58. package/dist/types/src/components/{UserAccountAvatar.stories.d.ts → UserAccountAvatar/UserAccountAvatar.stories.d.ts} +1 -2
  59. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -0
  60. package/dist/types/src/components/UserAccountAvatar/index.d.ts +2 -0
  61. package/dist/types/src/components/UserAccountAvatar/index.d.ts.map +1 -0
  62. package/dist/types/src/components/index.d.ts +0 -1
  63. package/dist/types/src/components/index.d.ts.map +1 -1
  64. package/dist/types/src/components/types.d.ts +20 -14
  65. package/dist/types/src/components/types.d.ts.map +1 -1
  66. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  67. package/dist/types/src/hooks.d.ts.map +1 -1
  68. package/dist/types/src/testing/app-graph-builder.d.ts +3 -0
  69. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -0
  70. package/dist/types/src/testing/generator.d.ts +7 -6
  71. package/dist/types/src/testing/generator.d.ts.map +1 -1
  72. package/dist/types/src/testing/index.d.ts +1 -0
  73. package/dist/types/src/testing/index.d.ts.map +1 -1
  74. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  75. package/dist/types/src/translations.d.ts +1 -0
  76. package/dist/types/src/translations.d.ts.map +1 -1
  77. package/dist/types/src/util.d.ts +7 -10
  78. package/dist/types/src/util.d.ts.map +1 -1
  79. package/dist/types/tsconfig.tsbuildinfo +1 -1
  80. package/package.json +42 -32
  81. package/src/NavTreePlugin.tsx +2 -2
  82. package/src/capabilities/app-graph-builder.ts +38 -28
  83. package/src/capabilities/capabilities.ts +5 -4
  84. package/src/capabilities/intent-resolver.ts +8 -7
  85. package/src/capabilities/keyboard.ts +37 -32
  86. package/src/capabilities/state.ts +23 -17
  87. package/src/components/{CommandsDialog.tsx → CommandsDialog/CommandsDialog.tsx} +8 -7
  88. package/src/components/{CommandsTrigger.tsx → CommandsDialog/CommandsTrigger.tsx} +1 -1
  89. package/src/components/CommandsDialog/index.ts +6 -0
  90. package/src/components/NavTree/NavTree.stories.tsx +159 -0
  91. package/src/components/NavTree/NavTree.tsx +62 -0
  92. package/src/components/NavTree/index.ts +5 -0
  93. package/src/components/NavTreeContainer.tsx +85 -67
  94. package/src/components/NavTreeContext.tsx +1 -1
  95. package/src/components/{NavTreeItemAction.stories.tsx → NavTreeItem/NavTreeItemAction.stories.tsx} +12 -6
  96. package/src/components/{NavTreeItemAction.tsx → NavTreeItem/NavTreeItemAction.tsx} +19 -22
  97. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +73 -0
  98. package/src/components/NavTreeItem/index.ts +6 -0
  99. package/src/components/{L0Menu.tsx → Sidebar/L0Menu.tsx} +186 -131
  100. package/src/components/Sidebar/L1Panel.tsx +175 -0
  101. package/src/components/Sidebar/index.ts +6 -0
  102. package/src/components/{UserAccountAvatar.stories.tsx → UserAccountAvatar/UserAccountAvatar.stories.tsx} +5 -5
  103. package/src/components/{UserAccountAvatar.tsx → UserAccountAvatar/UserAccountAvatar.tsx} +7 -7
  104. package/src/components/UserAccountAvatar/index.ts +5 -0
  105. package/src/components/index.ts +0 -1
  106. package/src/components/types.ts +20 -15
  107. package/src/testing/app-graph-builder.ts +224 -0
  108. package/src/testing/generator.ts +15 -12
  109. package/src/testing/index.ts +1 -0
  110. package/src/translations.ts +1 -0
  111. package/src/util.ts +10 -32
  112. package/dist/lib/browser/app-graph-builder-26D3MUCA.mjs.map +0 -7
  113. package/dist/lib/browser/chunk-4RQJXI4D.mjs.map +0 -7
  114. package/dist/lib/browser/chunk-DN43QXSX.mjs +0 -1222
  115. package/dist/lib/browser/chunk-DN43QXSX.mjs.map +0 -7
  116. package/dist/lib/browser/intent-resolver-BZMUS24C.mjs.map +0 -7
  117. package/dist/lib/browser/keyboard-IQXHKUWM.mjs +0 -46
  118. package/dist/lib/browser/keyboard-IQXHKUWM.mjs.map +0 -7
  119. package/dist/lib/browser/state-M5UJ3MHL.mjs.map +0 -7
  120. package/dist/types/src/components/CommandsDialog.d.ts.map +0 -1
  121. package/dist/types/src/components/CommandsTrigger.d.ts.map +0 -1
  122. package/dist/types/src/components/L0Menu.d.ts +0 -10
  123. package/dist/types/src/components/L0Menu.d.ts.map +0 -1
  124. package/dist/types/src/components/L1Panels.d.ts +0 -14
  125. package/dist/types/src/components/L1Panels.d.ts.map +0 -1
  126. package/dist/types/src/components/NavTree.d.ts +0 -5
  127. package/dist/types/src/components/NavTree.d.ts.map +0 -1
  128. package/dist/types/src/components/NavTree.stories.d.ts +0 -7
  129. package/dist/types/src/components/NavTree.stories.d.ts.map +0 -1
  130. package/dist/types/src/components/NavTreeItemAction.d.ts.map +0 -1
  131. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +0 -41
  132. package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +0 -1
  133. package/dist/types/src/components/NavTreeItemColumns.d.ts +0 -4
  134. package/dist/types/src/components/NavTreeItemColumns.d.ts.map +0 -1
  135. package/dist/types/src/components/UserAccountAvatar.d.ts.map +0 -1
  136. package/dist/types/src/components/UserAccountAvatar.stories.d.ts.map +0 -1
  137. package/dist/types/src/stories/Graph.stories.d.ts +0 -7
  138. package/dist/types/src/stories/Graph.stories.d.ts.map +0 -1
  139. package/dist/types/src/stories/StorybookNavTree.d.ts +0 -4
  140. package/dist/types/src/stories/StorybookNavTree.d.ts.map +0 -1
  141. package/src/components/L1Panels.tsx +0 -115
  142. package/src/components/NavTree.stories.tsx +0 -107
  143. package/src/components/NavTree.tsx +0 -51
  144. package/src/components/NavTreeItemColumns.tsx +0 -71
  145. package/src/stories/Graph.stories.tsx +0 -130
  146. package/src/stories/StorybookNavTree.tsx +0 -63
  147. /package/dist/lib/browser/{react-surface-3HCM3SHJ.mjs.map → react-surface-HGA3TAQU.mjs.map} +0 -0
  148. /package/dist/types/src/components/{CommandsDialog.d.ts → CommandsDialog/CommandsDialog.d.ts} +0 -0
  149. /package/dist/types/src/components/{CommandsTrigger.d.ts → CommandsDialog/CommandsTrigger.d.ts} +0 -0
@@ -0,0 +1,175 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { type Node } from '@dxos/app-graph';
8
+ import { Button, type ButtonProps, Icon, IconButton, toLocalizedString, useTranslation } from '@dxos/react-ui';
9
+ import { Tree } from '@dxos/react-ui-list';
10
+ import { Tabs } from '@dxos/react-ui-tabs';
11
+ import { hoverableControlItem, hoverableOpenControlItem, mx } from '@dxos/react-ui-theme';
12
+
13
+ import { useLoadDescendents } from '../../hooks';
14
+ import { NAVTREE_PLUGIN } from '../../meta';
15
+ import { l0ItemType } from '../../util';
16
+ import { useNavTreeContext } from '../NavTreeContext';
17
+ import { NavTreeItemColumns } from '../NavTreeItem';
18
+
19
+ const headingBackButtonLabel = 'inset-0 min-is-0 truncate flex items-center pis-2';
20
+
21
+ const TitleButton = ({ title, onClick }: { title: string } & Pick<ButtonProps, 'onClick'>) => {
22
+ return (
23
+ <Button
24
+ variant='ghost'
25
+ classNames='pli-1 flex-1 group text-start justify-start bs-[--rail-action] font-normal'
26
+ onClick={onClick}
27
+ >
28
+ <Icon icon='ph--caret-left--bold' size={3} />
29
+ <span className={mx(headingBackButtonLabel)}>{title}</span>
30
+ </Button>
31
+ );
32
+ };
33
+
34
+ export type L1PanelProps = {
35
+ open?: boolean;
36
+ item: Node<any>;
37
+ path: string[];
38
+ currentItemId: string;
39
+ onBack?: () => void;
40
+ };
41
+
42
+ const L1Panel = ({ open, item, path, currentItemId, onBack }: L1PanelProps) => {
43
+ const { isAlternateTree, setAlternateTree, ...navTreeContext } = useNavTreeContext();
44
+ const { t } = useTranslation(NAVTREE_PLUGIN);
45
+
46
+ // TODO(wittjosiah): Support multiple alternate trees.
47
+ const alternateTree = navTreeContext.useItems(item, { disposition: 'alternate-tree' })[0];
48
+ const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
49
+ const handleOpen = useCallback(() => setAlternateTree?.(alternatePath, true), [alternatePath, setAlternateTree]);
50
+ const isAlternate = isAlternateTree?.(alternatePath, item) ?? false;
51
+ const useAlternateItems = useCallback(
52
+ (node?: Node, { disposition }: { disposition?: string } = {}) => {
53
+ // TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
54
+ return navTreeContext.useItems(node, { disposition, sort: node?.id === alternateTree.id });
55
+ },
56
+ [navTreeContext, alternateTree],
57
+ );
58
+
59
+ const handleBack = useCallback(() => {
60
+ if (isAlternate) {
61
+ setAlternateTree?.(alternatePath, false);
62
+ } else {
63
+ onBack?.();
64
+ }
65
+ }, [isAlternate, onBack, alternatePath, setAlternateTree]);
66
+
67
+ const title = toLocalizedString(item.properties.label, t);
68
+ const backCapable = item.id.startsWith('!') || isAlternate;
69
+
70
+ return (
71
+ <Tabs.Tabpanel
72
+ key={item.id}
73
+ value={item.id}
74
+ classNames={[
75
+ 'absolute inset-block-0 inline-end-0',
76
+ 'is-[calc(100%-var(--l0-size))] lg:is-[--l1-size] grid-cols-1 grid-rows-[var(--rail-size)_1fr]',
77
+ 'pbs-[env(safe-area-inset-top)]',
78
+ item.id === currentItemId && 'grid',
79
+ ]}
80
+ tabIndex={-1}
81
+ aria-label={title}
82
+ {...(!open && { inert: 'true' })}
83
+ >
84
+ {item.id === currentItemId && (
85
+ <>
86
+ <h2 className='flex items-center border-be border-subduedSeparator app-drag pli-1'>
87
+ {backCapable ? (
88
+ <TitleButton title={title} onClick={handleBack} />
89
+ ) : (
90
+ <span className='flex-1 truncate min-is-0 pis-6'>{title}</span>
91
+ )}
92
+ {alternateTree && !isAlternate && (
93
+ <IconButton
94
+ variant='ghost'
95
+ classNames={mx('shrink-0', hoverableControlItem, hoverableOpenControlItem, 'pli-2 pointer-fine:pli-1')}
96
+ iconOnly
97
+ size={5}
98
+ density='coarse'
99
+ icon={alternateTree.properties.icon ?? 'ph--placeholder--regular'}
100
+ label={toLocalizedString(alternateTree.properties.label ?? alternateTree.id, t)}
101
+ data-testid='treeView.alternateTreeButton'
102
+ onClick={handleOpen}
103
+ />
104
+ )}
105
+ <NavTreeItemColumns path={path} item={item} open density='coarse' />
106
+ </h2>
107
+ <div role='none' className='overflow-y-auto'>
108
+ {isAlternate ? (
109
+ <Tree
110
+ {...navTreeContext}
111
+ useItems={useAlternateItems}
112
+ id={alternateTree.id}
113
+ root={alternateTree}
114
+ path={alternatePath}
115
+ levelOffset={5}
116
+ gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
117
+ renderColumns={NavTreeItemColumns}
118
+ />
119
+ ) : (
120
+ <Tree
121
+ {...navTreeContext}
122
+ id={item.id}
123
+ root={item}
124
+ path={path}
125
+ levelOffset={5}
126
+ draggable
127
+ gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
128
+ renderColumns={NavTreeItemColumns}
129
+ />
130
+ )}
131
+ </div>
132
+ </>
133
+ )}
134
+ </Tabs.Tabpanel>
135
+ );
136
+ };
137
+
138
+ const L1PanelCollection = ({ item, path, ...props }: L1PanelProps) => {
139
+ const { useItems } = useNavTreeContext();
140
+ useLoadDescendents(item);
141
+ const collectionItems = useItems(item);
142
+ const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
143
+ return (
144
+ <>
145
+ {collectionItems
146
+ .filter((item) => l0ItemType(item) === 'tab')
147
+ .map((item) => (
148
+ <L1Panel key={item.id} item={item} path={groupPath} {...props} />
149
+ ))}
150
+ </>
151
+ );
152
+ };
153
+
154
+ export type L1PanelsProps = Pick<L1PanelProps, 'open' | 'currentItemId' | 'onBack'> & {
155
+ topLevelItems: Node<any>[];
156
+ path: string[];
157
+ };
158
+
159
+ export const L1Panels = ({ topLevelItems, onBack, ...props }: L1PanelsProps) => {
160
+ return (
161
+ <>
162
+ {topLevelItems.map((item) => {
163
+ const type = l0ItemType(item);
164
+ switch (type) {
165
+ case 'collection':
166
+ return <L1PanelCollection key={item.id} item={item} {...props} />;
167
+ case 'tab':
168
+ return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
169
+ default:
170
+ return null;
171
+ }
172
+ })}
173
+ </>
174
+ );
175
+ };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './L0Menu';
6
+ export * from './L1Panel';
@@ -5,17 +5,17 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { type Meta } from '@storybook/react';
8
- import React from 'react';
9
8
 
10
- import { UserAccountAvatar } from './UserAccountAvatar';
9
+ import { withTheme } from '@dxos/storybook-utils';
11
10
 
12
- export const Default = (props: any) => {
13
- return <UserAccountAvatar {...props} />;
14
- };
11
+ import { UserAccountAvatar } from './UserAccountAvatar';
15
12
 
16
13
  const meta: Meta<typeof UserAccountAvatar> = {
17
14
  title: 'plugins/plugin-navtree/UserAccountAvatar',
18
15
  component: UserAccountAvatar,
16
+ decorators: [withTheme],
19
17
  };
20
18
 
21
19
  export default meta;
20
+
21
+ export const Default = {};
@@ -15,19 +15,19 @@ export type UserAccountAvatarProps = {
15
15
  status?: AvatarStatus;
16
16
  };
17
17
 
18
- export const UserAccountAvatar = (props: UserAccountAvatarProps) => {
19
- const fallbackValue = hexToFallback(props.userId ?? '0');
18
+ export const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAccountAvatarProps) => {
19
+ const fallbackValue = hexToFallback(userId ?? '0');
20
20
 
21
21
  return (
22
22
  <div className='grid place-items-center' data-joyride='welcome/account'>
23
23
  <Avatar.Root>
24
24
  <Avatar.Content
25
25
  variant='circle'
26
- size={props.size ?? 12}
27
- status={props.status ?? 'active'}
28
- hue={props.hue || fallbackValue.hue}
29
- fallback={props.emoji || fallbackValue.emoji}
30
- data-testid='treeview.userAccount'
26
+ size={size ?? 12}
27
+ status={status ?? 'active'}
28
+ hue={hue || fallbackValue.hue}
29
+ fallback={emoji || fallbackValue.emoji}
30
+ data-testid='treeView.userAccount'
31
31
  />
32
32
  </Avatar.Root>
33
33
  </div>
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './UserAccountAvatar';
@@ -3,7 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './CommandsDialog';
6
- export * from './CommandsTrigger';
7
6
  export * from './NavTree';
8
7
  export * from './NavTreeContainer';
9
8
  export * from './NavTreeContext';
@@ -5,31 +5,36 @@
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
 
11
- import { type L1PanelProps } from './L1Panels';
12
+ import { type L1PanelProps } from './Sidebar';
12
13
  import type { FlattenedActions, NavTreeItemGraphNode } from '../types';
13
14
 
14
- export type NavTreeItemColumnsProps = {
15
- path: string[];
16
- item: Node;
17
- open: boolean;
18
- };
19
-
20
- export type NavTreeProps = Pick<TreeProps<NavTreeItemGraphNode>, 'id' | 'root'>;
21
-
22
15
  export type NavTreeContextValue = Pick<
23
16
  TreeProps<NavTreeItemGraphNode>,
24
- 'getProps' | 'isCurrent' | 'isOpen' | 'onOpenChange' | 'canDrop' | 'onSelect'
17
+ 'getProps' | 'isCurrent' | 'isOpen' | 'canDrop' | 'onOpenChange' | 'onSelect'
25
18
  > &
26
19
  Pick<L1PanelProps, 'onBack'> & {
27
20
  tab: string;
28
- onTabChange?: (node: NavTreeItemGraphNode) => void;
29
- getItems: (node?: NavTreeItemGraphNode, disposition?: string) => NavTreeItemGraphNode[];
21
+ topbar?: boolean;
22
+ popoverAnchorId?: string;
23
+ renderItemEnd?: FC<{ node: Node; open: boolean }>;
24
+ useItems: (
25
+ node?: NavTreeItemGraphNode,
26
+ options?: { disposition?: string; sort?: boolean },
27
+ ) => NavTreeItemGraphNode[];
30
28
  getActions: (node: Node) => FlattenedActions;
31
29
  loadDescendents?: (node: Node) => MaybePromise<void>;
32
- renderItemEnd?: FC<{ node: Node; open: boolean }>;
33
- popoverAnchorId?: string;
34
- topbar?: boolean;
30
+ isAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
31
+ setAlternateTree?: (path: string[], open: boolean) => void;
32
+ onTabChange?: (node: NavTreeItemGraphNode) => void;
35
33
  };
34
+
35
+ export type NavTreeItemColumnsProps = {
36
+ path: string[];
37
+ item: Node;
38
+ open: boolean;
39
+ density?: Density;
40
+ };
@@ -0,0 +1,224 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import { Option, pipe } from 'effect';
7
+
8
+ import { log } from '@dxos/log';
9
+ import { createExtension, ROOT_ID, type BuilderExtensions } from '@dxos/plugin-graph';
10
+ import { faker } from '@dxos/random';
11
+
12
+ export const storybookGraphBuilders: BuilderExtensions = [
13
+ // Create app menu actions.
14
+ createExtension({
15
+ id: 'app-menu',
16
+ actions: (node) =>
17
+ Rx.make((get) =>
18
+ pipe(
19
+ get(node),
20
+ Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
21
+ Option.map((node) => {
22
+ return [
23
+ ...Array.from({ length: 5 }, (_, i) => ({
24
+ id: `${node.id}/action-${i}`,
25
+ data: () => {
26
+ log.info('action', { id: node.id, index: i });
27
+ },
28
+ properties: {
29
+ label: `Action ${i}`,
30
+ icon: faker.properties.icon(),
31
+ disposition: 'menu',
32
+ },
33
+ })),
34
+ ];
35
+ }),
36
+ Option.getOrElse(() => []),
37
+ ),
38
+ ),
39
+ }),
40
+ // Create user account node.
41
+ createExtension({
42
+ id: 'user-account',
43
+ connector: (node) =>
44
+ Rx.make((get) =>
45
+ pipe(
46
+ get(node),
47
+ Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
48
+ Option.map(() => {
49
+ return [
50
+ {
51
+ id: 'user-account',
52
+ type: 'user-account',
53
+ properties: {
54
+ label: 'User Account',
55
+ icon: 'ph--user--regular',
56
+ disposition: 'user-account',
57
+ userId: '1234567890ABCDEF',
58
+ hue: faker.properties.hue(),
59
+ emoji: faker.properties.emoji(),
60
+ status: 'active',
61
+ },
62
+ nodes: [
63
+ {
64
+ id: 'profile',
65
+ type: 'profile',
66
+ properties: {
67
+ label: 'Profile',
68
+ icon: 'ph--user--regular',
69
+ },
70
+ },
71
+ {
72
+ id: 'devices',
73
+ type: 'devices',
74
+ properties: {
75
+ label: 'Devices',
76
+ icon: 'ph--devices--regular',
77
+ },
78
+ },
79
+ {
80
+ id: 'security',
81
+ type: 'security',
82
+ properties: {
83
+ label: 'Security',
84
+ icon: 'ph--key--regular',
85
+ },
86
+ },
87
+ ],
88
+ },
89
+ ];
90
+ }),
91
+ Option.getOrElse(() => []),
92
+ ),
93
+ ),
94
+ }),
95
+ // TODO(wittjosiah): This group node probably is unnecessary now with the flat L0 structure.
96
+ // Create spaces group node.
97
+ createExtension({
98
+ id: 'spaces-root',
99
+ position: 'hoist',
100
+ connector: (node) =>
101
+ Rx.make((get) =>
102
+ pipe(
103
+ get(node),
104
+ Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
105
+ Option.map(() => {
106
+ return [
107
+ {
108
+ id: 'spaces-root',
109
+ type: 'spaces-root',
110
+ properties: {
111
+ label: 'Spaces',
112
+ icon: 'ph--planet--regular',
113
+ role: 'branch',
114
+ disposition: 'collection',
115
+ },
116
+ },
117
+ ];
118
+ }),
119
+ Option.getOrElse(() => []),
120
+ ),
121
+ ),
122
+ }),
123
+ // Create space nodes.
124
+ createExtension({
125
+ id: 'spaces',
126
+ connector: (node) =>
127
+ Rx.make((get) =>
128
+ pipe(
129
+ get(node),
130
+ Option.flatMap((node) => (node.id === 'spaces-root' ? Option.some(node) : Option.none())),
131
+ Option.map(() => {
132
+ return [
133
+ ...Array.from({ length: 5 }, (_, i) => ({
134
+ id: `space-${i}`,
135
+ type: 'space',
136
+ properties: {
137
+ label: `Space ${i}`,
138
+ icon: faker.properties.icon(),
139
+ hue: faker.properties.hue(),
140
+ },
141
+ })),
142
+ ];
143
+ }),
144
+ Option.getOrElse(() => []),
145
+ ),
146
+ ),
147
+ }),
148
+ // Create space actions.
149
+ createExtension({
150
+ id: 'space-actions',
151
+ actions: (node) =>
152
+ Rx.make((get) =>
153
+ pipe(
154
+ get(node),
155
+ Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
156
+ Option.map((node) => {
157
+ return [
158
+ ...Array.from({ length: 5 }, (_, i) => ({
159
+ id: `${node.id}/action-${i}`,
160
+ data: () => {
161
+ log.info('action', { id: node.id, index: i });
162
+ },
163
+ properties: {
164
+ label: `Action ${i}`,
165
+ icon: faker.properties.icon(),
166
+ },
167
+ })),
168
+ ];
169
+ }),
170
+ Option.getOrElse(() => []),
171
+ ),
172
+ ),
173
+ }),
174
+ // Create object nodes.
175
+ createExtension({
176
+ id: 'objects',
177
+ connector: (node) =>
178
+ Rx.make((get) =>
179
+ pipe(
180
+ get(node),
181
+ Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
182
+ Option.map(() => {
183
+ return [
184
+ ...Array.from({ length: 5 }, (_, i) => ({
185
+ id: `object-${i}`,
186
+ type: 'object',
187
+ properties: {
188
+ label: `Object ${i}`,
189
+ icon: faker.properties.icon(),
190
+ },
191
+ })),
192
+ ];
193
+ }),
194
+ Option.getOrElse(() => []),
195
+ ),
196
+ ),
197
+ }),
198
+ // Create object actions.
199
+ createExtension({
200
+ id: 'object-actions',
201
+ actions: (node) =>
202
+ Rx.make((get) =>
203
+ pipe(
204
+ get(node),
205
+ Option.flatMap((node) => (node.type === 'object' ? Option.some(node) : Option.none())),
206
+ Option.map((node) => {
207
+ return [
208
+ ...Array.from({ length: 5 }, (_, i) => ({
209
+ id: `${node.id}/action-${i}`,
210
+ data: () => {
211
+ log.info('action', { id: node.id, index: i });
212
+ },
213
+ properties: {
214
+ label: `Action ${i}`,
215
+ icon: faker.properties.icon(),
216
+ },
217
+ })),
218
+ ];
219
+ }),
220
+ Option.getOrElse(() => []),
221
+ ),
222
+ ),
223
+ }),
224
+ ];
@@ -2,9 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
6
+
5
7
  import { type NodeArg } from '@dxos/app-graph';
6
- import { S, TypedObject } from '@dxos/echo-schema';
7
- import { create, type ReactiveObject } from '@dxos/live-object';
8
+ import { TypedObject } from '@dxos/echo-schema';
9
+ import { live, type Live } from '@dxos/live-object';
8
10
  import { faker } from '@dxos/random';
9
11
  import { range } from '@dxos/util';
10
12
 
@@ -15,12 +17,12 @@ import { range } from '@dxos/util';
15
17
  export type TestItem = { id: string; type: string } & Record<string, any>;
16
18
 
17
19
  type ObjectDataGenerator = {
18
- createSchema?: () => S.Schema.AnyNoContext;
20
+ createSchema?: () => Schema.Schema.AnyNoContext;
19
21
  createData: () => any;
20
22
  };
21
23
 
22
- type ObjectFactory<T extends ReactiveObject<any>> = {
23
- schema?: S.Schema.AnyNoContext; // TODO(burdon): Support both typed and expando schema.
24
+ type ObjectFactory<T extends Live<any>> = {
25
+ schema?: Schema.Schema.AnyNoContext; // TODO(burdon): Support both typed and expando schema.
24
26
  createObject: () => T;
25
27
  };
26
28
 
@@ -30,7 +32,7 @@ const createFactory = ({ createSchema, createData }: ObjectDataGenerator) => {
30
32
  const schema = createSchema?.();
31
33
  return {
32
34
  schema,
33
- createObject: () => (schema ? create(schema, createData()) : create(createData())),
35
+ createObject: () => (schema ? live(schema, createData()) : live(createData())),
34
36
  };
35
37
  };
36
38
 
@@ -57,10 +59,10 @@ export const defaultGenerators: { [type: string]: ObjectDataGenerator } = {
57
59
  project: {
58
60
  createSchema: () =>
59
61
  class ProjectType extends TypedObject({ typename: 'example.com/type/Project', version: '0.1.0' })({
60
- title: S.String,
61
- repo: S.String,
62
- status: S.String,
63
- priority: S.Number,
62
+ title: Schema.String,
63
+ repo: Schema.String,
64
+ status: Schema.String,
65
+ priority: Schema.Number,
64
66
  }) {},
65
67
 
66
68
  createData: () => ({
@@ -87,7 +89,7 @@ export class TestObjectGenerator {
87
89
  }, {});
88
90
  }
89
91
 
90
- get schema(): S.Schema.AnyNoContext[] {
92
+ get schema(): Schema.Schema.AnyNoContext[] {
91
93
  return Object.values(this.factories).map((f) => f.schema!);
92
94
  }
93
95
 
@@ -131,10 +133,11 @@ export const createTree = () => {
131
133
  return {
132
134
  id: faker.string.uuid(),
133
135
  data: null,
134
- type: 'collection',
136
+ type: 'category',
135
137
  properties: {
136
138
  label: l0.title,
137
139
  icon: 'ph--horse--regular',
140
+ disposition: 'collection',
138
141
  },
139
142
  nodes: [
140
143
  ...[...Array(4)].map(() => {
@@ -2,5 +2,6 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ export * from './app-graph-builder';
5
6
  export * from './generator';
6
7
  export * from './update-state';
@@ -8,6 +8,7 @@ export default [
8
8
  {
9
9
  'en-US': {
10
10
  [NAVTREE_PLUGIN]: {
11
+ 'app menu label': 'App menu',
11
12
  'open settings label': 'Settings',
12
13
  'open commands label': 'Search commands',
13
14
  'commands dialog title': 'Commands',