@dxos/plugin-navtree 0.8.4-main.1068cf700f → 0.8.4-main.1c7ec43d41

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 (207) hide show
  1. package/dist/lib/browser/NavTreePlugin-3KLPENH6.mjs +54 -0
  2. package/dist/lib/browser/NavTreePlugin-3KLPENH6.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +98 -114
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/translations.mjs +21 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/types/src/NavTreePlugin.d.ts +1 -0
  9. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  10. package/dist/types/src/NavTreePlugin.node.d.ts +4 -0
  11. package/dist/types/src/NavTreePlugin.node.d.ts.map +1 -0
  12. package/dist/types/src/NavTreePlugin.test.d.ts +2 -0
  13. package/dist/types/src/NavTreePlugin.test.d.ts.map +1 -0
  14. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  15. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  16. package/dist/types/src/capabilities/index.d.ts +7 -5
  17. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  18. package/dist/types/src/capabilities/keyboard.d.ts +5 -0
  19. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  20. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  21. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  22. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  23. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  24. package/dist/types/src/capabilities/state.d.ts +6 -0
  25. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  26. package/dist/types/src/components/NavTree/NavTree.d.ts +10 -32
  27. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  28. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +10 -15
  29. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  31. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  32. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  33. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  34. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +7 -3
  35. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  36. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
  37. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  39. package/dist/types/src/components/Sidebar/L0Menu.d.ts +4 -1
  40. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  41. package/dist/types/src/components/Sidebar/L1Panel.d.ts +2 -5
  42. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  43. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +3 -2
  44. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  45. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  46. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/index.d.ts +0 -3
  48. package/dist/types/src/components/index.d.ts.map +1 -1
  49. package/dist/types/src/components/types.d.ts +5 -14
  50. package/dist/types/src/components/types.d.ts.map +1 -1
  51. package/dist/types/src/{components/CommandsDialog/CommandsDialog.d.ts → containers/CommandsDialogContent/CommandsDialogContent.d.ts} +1 -1
  52. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  53. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  54. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  55. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  56. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  57. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  58. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  59. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  60. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  61. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  62. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  63. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  64. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  65. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  66. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  67. package/dist/types/src/containers/index.d.ts +7 -0
  68. package/dist/types/src/containers/index.d.ts.map +1 -0
  69. package/dist/types/src/experimental/Tree.d.ts +2 -2
  70. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  71. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  72. package/dist/types/src/hooks/index.d.ts +5 -0
  73. package/dist/types/src/hooks/index.d.ts.map +1 -0
  74. package/dist/types/src/hooks/useActions.d.ts +5 -0
  75. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  76. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  77. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  78. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  79. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  80. package/dist/types/src/hooks/useNavTreeState.d.ts +18 -0
  81. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  82. package/dist/types/src/index.d.ts +3 -2
  83. package/dist/types/src/index.d.ts.map +1 -1
  84. package/dist/types/src/meta.d.ts.map +1 -1
  85. package/dist/types/src/operations/expose.d.ts +5 -0
  86. package/dist/types/src/operations/expose.d.ts.map +1 -0
  87. package/dist/types/src/operations/index.d.ts +3 -0
  88. package/dist/types/src/operations/index.d.ts.map +1 -0
  89. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  90. package/dist/types/src/testing/generator.d.ts +3 -3
  91. package/dist/types/src/testing/generator.d.ts.map +1 -1
  92. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  93. package/dist/types/src/translations.d.ts +8 -11
  94. package/dist/types/src/translations.d.ts.map +1 -1
  95. package/dist/types/src/types/capabilities.d.ts +1 -2
  96. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  97. package/dist/types/src/types/events.d.ts.map +1 -1
  98. package/dist/types/src/util.d.ts +7 -3
  99. package/dist/types/src/util.d.ts.map +1 -1
  100. package/dist/types/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +62 -43
  102. package/src/NavTreePlugin.node.ts +17 -0
  103. package/src/NavTreePlugin.test.ts +27 -0
  104. package/src/NavTreePlugin.tsx +8 -25
  105. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +7 -7
  106. package/src/capabilities/index.ts +11 -5
  107. package/src/capabilities/{keyboard/keyboard.ts → keyboard.ts} +2 -2
  108. package/src/capabilities/operation-handler.ts +16 -0
  109. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +9 -11
  110. package/src/capabilities/{state/state.ts → state.ts} +41 -14
  111. package/src/components/NavTree/NavTree.stories.tsx +26 -24
  112. package/src/components/NavTree/NavTree.tsx +64 -22
  113. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  114. package/src/components/NavTreeContext/index.ts +5 -0
  115. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +7 -9
  116. package/src/components/NavTreeItem/NavTreeItemAction.tsx +56 -40
  117. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +43 -17
  118. package/src/components/Sidebar/L0Menu.tsx +104 -110
  119. package/src/components/Sidebar/L1Panel.tsx +163 -142
  120. package/src/components/Sidebar/L1Tabs.tsx +13 -4
  121. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +1 -2
  122. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
  123. package/src/components/index.ts +0 -3
  124. package/src/components/types.ts +11 -17
  125. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  126. package/src/{components/CommandsDialog/CommandsDialog.tsx → containers/CommandsDialogContent/CommandsDialogContent.tsx} +52 -53
  127. package/src/containers/CommandsDialogContent/index.ts +5 -0
  128. package/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.tsx +8 -6
  129. package/src/containers/CommandsTrigger/index.ts +5 -0
  130. package/src/{components → containers/NavTreeContainer}/NavTreeContainer.tsx +78 -145
  131. package/src/containers/NavTreeContainer/index.ts +6 -0
  132. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +2 -2
  133. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  134. package/src/containers/index.ts +12 -0
  135. package/src/experimental/Tree.stories.tsx +64 -61
  136. package/src/experimental/Tree.tsx +3 -3
  137. package/src/hooks/index.ts +8 -0
  138. package/src/hooks/useActions.ts +34 -0
  139. package/src/hooks/useLoadDescendents.ts +23 -0
  140. package/src/hooks/useNavTreeModel.ts +118 -0
  141. package/src/hooks/useNavTreeState.ts +35 -0
  142. package/src/index.ts +8 -2
  143. package/src/meta.ts +3 -2
  144. package/src/operations/expose.ts +42 -0
  145. package/src/operations/index.ts +7 -0
  146. package/src/testing/app-graph-builder.ts +40 -36
  147. package/src/testing/generator.ts +25 -25
  148. package/src/translations.ts +8 -10
  149. package/src/types/capabilities.ts +4 -4
  150. package/src/types/events.ts +2 -2
  151. package/src/util.ts +19 -5
  152. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs +0 -44
  153. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +0 -7
  154. package/dist/lib/browser/chunk-63YLDLLE.mjs +0 -1373
  155. package/dist/lib/browser/chunk-63YLDLLE.mjs.map +0 -7
  156. package/dist/lib/browser/chunk-X2HDG62A.mjs +0 -23
  157. package/dist/lib/browser/chunk-X2HDG62A.mjs.map +0 -7
  158. package/dist/lib/browser/chunk-YKTYPINZ.mjs +0 -19
  159. package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +0 -7
  160. package/dist/lib/browser/keyboard-46XQHY2O.mjs +0 -53
  161. package/dist/lib/browser/keyboard-46XQHY2O.mjs.map +0 -7
  162. package/dist/lib/browser/operation-resolver-NNNDII45.mjs +0 -53
  163. package/dist/lib/browser/operation-resolver-NNNDII45.mjs.map +0 -7
  164. package/dist/lib/browser/react-surface-APSEG23H.mjs +0 -59
  165. package/dist/lib/browser/react-surface-APSEG23H.mjs.map +0 -7
  166. package/dist/lib/browser/state-M5YUCIQU.mjs +0 -121
  167. package/dist/lib/browser/state-M5YUCIQU.mjs.map +0 -7
  168. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
  169. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  170. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  171. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  172. package/dist/types/src/capabilities/keyboard/index.d.ts +0 -3
  173. package/dist/types/src/capabilities/keyboard/index.d.ts.map +0 -1
  174. package/dist/types/src/capabilities/keyboard/keyboard.d.ts +0 -5
  175. package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +0 -1
  176. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  177. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  178. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  179. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  180. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  181. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  182. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  183. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  184. package/dist/types/src/capabilities/state/index.d.ts +0 -3
  185. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  186. package/dist/types/src/capabilities/state/state.d.ts +0 -6
  187. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  188. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  189. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  190. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  191. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  192. package/dist/types/src/components/NavTreeContainer.d.ts +0 -16
  193. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  194. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  195. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  196. package/dist/types/src/hooks.d.ts +0 -34
  197. package/dist/types/src/hooks.d.ts.map +0 -1
  198. package/src/capabilities/app-graph-builder/index.ts +0 -7
  199. package/src/capabilities/keyboard/index.ts +0 -7
  200. package/src/capabilities/operation-resolver/index.ts +0 -7
  201. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -42
  202. package/src/capabilities/react-surface/index.ts +0 -7
  203. package/src/capabilities/state/index.ts +0 -7
  204. package/src/components/CommandsDialog/index.ts +0 -6
  205. package/src/hooks.ts +0 -73
  206. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
  207. /package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +0 -0
@@ -11,11 +11,11 @@ import { Keyboard, keySymbols } from '@dxos/keyboard';
11
11
  import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
12
12
  import { useActions } from '@dxos/plugin-graph';
13
13
  import { Button, Dialog, toLocalizedString, useTranslation } from '@dxos/react-ui';
14
- import { SearchList, useSearchListResults } from '@dxos/react-ui-searchlist';
14
+ import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
15
15
  import { osTranslations } from '@dxos/ui-theme';
16
16
  import { getHostPlatform } from '@dxos/util';
17
17
 
18
- import { KEY_BINDING, meta } from '../../meta';
18
+ import { KEY_BINDING, meta } from '#meta';
19
19
 
20
20
  export type CommandsDialogContentProps = {
21
21
  selected?: string;
@@ -25,7 +25,7 @@ export type CommandsDialogContentProps = {
25
25
  export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogContentProps>(
26
26
  ({ selected: initial }, forwardedRef) => {
27
27
  const { t } = useTranslation(meta.id);
28
- const { invokeSync } = useOperationInvoker();
28
+ const { invokePromise } = useOperationInvoker();
29
29
  const runAction = useActionRunner();
30
30
  const { graph } = useAppGraph();
31
31
  const [selected, setSelected] = useState<string | undefined>(initial);
@@ -38,12 +38,12 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
38
38
  const actionMap = new Set<string>();
39
39
  const actions: Node.ActionLike[] = [];
40
40
  Graph.traverse(graph, {
41
+ relation: ['child', 'action'],
41
42
  visitor: (node, path) => {
42
- if (
43
- (Node.isAction(node) || Node.isActionGroup(node)) &&
44
- !actionMap.has(node.id) &&
45
- current.startsWith(path.slice(0, -1).join('/'))
46
- ) {
43
+ const isActionLike = Node.isAction(node) || Node.isActionGroup(node);
44
+ const parentId = path.at(-2) ?? '';
45
+ const matches = current === parentId || current.startsWith(parentId + '/');
46
+ if (isActionLike && !actionMap.has(node.id) && matches) {
47
47
  actionMap.add(node.id);
48
48
  actions.push(node);
49
49
  }
@@ -70,58 +70,57 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
70
70
 
71
71
  return (
72
72
  <Dialog.Content ref={forwardedRef}>
73
- <Dialog.Title>{t('commands dialog title', { ns: meta.id })}</Dialog.Title>
73
+ <Dialog.Title srOnly>{t('commands-dialog.title', { ns: meta.id })}</Dialog.Title>
74
74
  <SearchList.Root onSearch={handleSearch}>
75
- <SearchList.Content>
76
- <SearchList.Input placeholder={t('command list input placeholder')} />
77
- <SearchList.Viewport>
78
- {results.map((action) => {
79
- const shortcut =
80
- typeof action.properties.keyBinding === 'string'
81
- ? action.properties.keyBinding
82
- : action.properties.keyBinding?.[getHostPlatform()];
75
+ <SearchList.Input placeholder={t('command-list-input.placeholder')} />
76
+ <SearchList.Viewport>
77
+ {results.map((action) => {
78
+ const shortcut =
79
+ typeof action.properties.keyBinding === 'string'
80
+ ? action.properties.keyBinding
81
+ : action.properties.keyBinding?.[getHostPlatform()];
83
82
 
84
- return (
85
- <SearchList.Item
86
- value={action.id}
87
- key={action.id}
88
- label={toLocalizedString(action.properties.label, t)}
89
- icon={action.properties.icon}
90
- suffix={shortcut ? keySymbols(shortcut).join('') : undefined}
91
- onSelect={() => {
92
- if (action.properties.disabled) {
93
- return;
94
- }
83
+ return (
84
+ <SearchList.Item
85
+ value={action.id}
86
+ key={action.id}
87
+ label={toLocalizedString(action.properties.label, t)}
88
+ icon={action.properties.icon}
89
+ suffix={shortcut ? keySymbols(shortcut).join('') : undefined}
90
+ onSelect={() => {
91
+ if (action.properties.disabled) {
92
+ return;
93
+ }
95
94
 
96
- if (Node.isActionGroup(action)) {
97
- setSelected(action.id);
98
- return;
99
- }
95
+ if (Node.isActionGroup(action)) {
96
+ setSelected(action.id);
97
+ return;
98
+ }
100
99
 
101
- invokeSync(LayoutOperation.UpdateDialog, { state: false });
102
- setTimeout(() => {
103
- const node = Graph.getConnections(graph, group?.id ?? action.id, 'inbound')[0];
104
- if (node && Node.isAction(action)) {
105
- void runAction(action, { parent: node, caller: KEY_BINDING });
106
- }
107
- });
108
- }}
109
- classNames='flex items-center gap-2'
110
- disabled={action.properties.disabled}
111
- {...(action.properties?.testId && {
112
- 'data-testid': action.properties.testId,
113
- })}
114
- />
115
- );
116
- })}
117
- </SearchList.Viewport>
118
- </SearchList.Content>
100
+ void invokePromise(LayoutOperation.UpdateDialog, { state: false });
101
+ setTimeout(() => {
102
+ const lookupId = group?.id ?? action.id;
103
+ const node = Graph.getConnections(graph, lookupId, Node.actionRelation('inbound'))[0];
104
+ if (node && Node.isAction(action)) {
105
+ void runAction(action, { parent: node, caller: KEY_BINDING });
106
+ }
107
+ });
108
+ }}
109
+ classNames='flex items-center gap-2'
110
+ disabled={action.properties.disabled}
111
+ {...(action.properties?.testId && {
112
+ 'data-testid': action.properties.testId,
113
+ })}
114
+ />
115
+ );
116
+ })}
117
+ </SearchList.Viewport>
119
118
  </SearchList.Root>
120
- <div role='none' className='pli-cardSpacingInline pbe-cardSpacingBlock'>
119
+ <Dialog.ActionBar>
121
120
  <Dialog.Close asChild>
122
- <Button classNames='is-full'>{t('close label', { ns: osTranslations })}</Button>
121
+ <Button classNames='w-full'>{t('close.label', { ns: osTranslations })}</Button>
123
122
  </Dialog.Close>
124
- </div>
123
+ </Dialog.ActionBar>
125
124
  </Dialog.Content>
126
125
  );
127
126
  },
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export { CommandsDialogContent as default } from './CommandsDialogContent';
@@ -8,19 +8,21 @@ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
8
  import { LayoutOperation } from '@dxos/app-toolkit';
9
9
  import { Button, Icon, useTranslation } from '@dxos/react-ui';
10
10
 
11
- import { COMMANDS_DIALOG, meta } from '../../meta';
11
+ import { COMMANDS_DIALOG, meta } from '#meta';
12
12
 
13
13
  // TODO(thure): Refactor to be handled by a more appropriate plugin.
14
14
  export const CommandsTrigger = () => {
15
- const { invokeSync } = useOperationInvoker();
15
+ const { invokePromise } = useOperationInvoker();
16
16
  const { t } = useTranslation(meta.id);
17
17
  return (
18
18
  <Button
19
- classNames='m-1 pli-1 lg:pli-2'
20
- onClick={() => invokeSync(LayoutOperation.UpdateDialog, { subject: COMMANDS_DIALOG, blockAlign: 'start' })}
19
+ classNames='m-1 px-1 lg:px-2'
20
+ onClick={() =>
21
+ void invokePromise(LayoutOperation.UpdateDialog, { subject: COMMANDS_DIALOG, blockAlign: 'start' })
22
+ }
21
23
  >
22
- <span className='text-description font-normal grow text-start'>{t('command list input placeholder')}</span>
23
- <Icon icon='ph--magnifying-glass--regular' size={5} />
24
+ <span className='text-description font-normal grow text-start'>{t('command-list-input.placeholder')}</span>
25
+ <Icon icon='ph--magnifying-glass--regular' />
24
26
  </Button>
25
27
  );
26
28
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export { CommandsTrigger as default } from './CommandsTrigger';
@@ -2,168 +2,114 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
6
5
  import { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
7
- import React, { forwardRef, memo, useCallback, useEffect, useMemo } from 'react';
6
+ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
+ import React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from 'react';
8
8
 
9
9
  import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
10
10
  import { LayoutOperation } from '@dxos/app-toolkit';
11
11
  import { useAppGraph, useLayout } from '@dxos/app-toolkit/ui';
12
- import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
13
12
  import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
14
- import { useConnections, useActions as useGraphActions } from '@dxos/plugin-graph';
15
13
  import { useMediaQuery, useSidebars } from '@dxos/react-ui';
16
- import { type TreeData, type TreeItemDataProps, isTreeData } from '@dxos/react-ui-list';
17
- import { mx } from '@dxos/ui-theme';
18
- import { arrayMove, byPosition } from '@dxos/util';
14
+ import { type TreeData, isTreeData } from '@dxos/react-ui-list';
15
+ import { arrayMove } from '@dxos/util';
19
16
 
20
- import { useIsAlternateTree, useIsCurrent, useIsOpen, useNavTreeState } from '../hooks';
21
- import { meta } from '../meta';
22
- import { type FlattenedActions, type NavTreeItemGraphNode } from '../types';
23
- import { getChildren, getParent, resolveMigrationOperation } from '../util';
17
+ import { NAV_TREE_ITEM, NavTree, NavTreeContext } from '#components';
18
+ import { useNavTreeModel, useNavTreeState } from '#hooks';
19
+ import { meta } from '#meta';
20
+ import { type NavTreeItemGraphNode } from '#types';
24
21
 
25
- import { NAV_TREE_ITEM, NavTree } from './NavTree';
26
- import { NavTreeContext } from './NavTreeContext';
27
- import { type NavTreeContextValue } from './types';
22
+ import { filterItems, getParent, resolveMigrationOperation } from '../../util';
28
23
 
29
24
  // TODO(thure): Is NavTree truly authoritative in this regard?
30
25
  export const NODE_TYPE = 'dxos/app-graph/node';
31
26
 
32
- const renderItemEnd = ({ node, open }: { node: Node.Node; open: boolean }) => (
33
- <Surface.Surface role='navtree-item-end' data={{ id: node.id, subject: node.data, open }} limit={1} />
34
- );
35
-
36
- const getChildrenFilter = (node: Node.Node): node is Node.Node =>
37
- !Node.isActionLike(node) && node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== 'hidden';
38
-
39
- const filterItems = (node: Node.Node, disposition?: string) => {
40
- if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
41
- return false;
42
- } else if (!disposition) {
43
- const action = Node.isAction(node);
44
- return !action || node.properties.disposition === 'item';
45
- } else {
46
- return node.properties.disposition === disposition;
47
- }
27
+ // TODO(wittjosiah): Avoid using Surface within the navtree, prefer declarative data flow.
28
+ const NavTreeItemEnd = ({ node, open }: { node: Node.Node; open: boolean }) => {
29
+ const data = useMemo(() => ({ id: node.id, subject: node.data, open }), [node.id, node.data, open]);
30
+ return <Surface.Surface role='navtree-item-end' data={data} limit={1} />;
48
31
  };
49
32
 
50
33
  const getItems = (graph: Graph.ReadableGraph, node?: Node.Node, disposition?: string) => {
51
- return Graph.getConnections(graph, node?.id ?? Node.RootId, 'outbound').filter((node) =>
52
- filterItems(node, disposition),
53
- );
54
- };
55
-
56
- const useItems = (node?: Node.Node, options?: { disposition?: string; sort?: boolean }) => {
57
- const { graph } = useAppGraph();
58
- const connections = useConnections(graph, node?.id ?? Node.RootId);
59
- const filtered = connections.filter((node) => filterItems(node, options?.disposition));
60
- return options?.sort ? filtered.toSorted((a, b) => byPosition(a.properties, b.properties)) : filtered;
61
- };
62
-
63
- const useActions = (node: Node.Node): FlattenedActions => {
64
- const { graph } = useAppGraph();
65
- const actions = useGraphActions(graph, node.id);
66
-
67
- return useMemo(
68
- () =>
69
- actions.reduce(
70
- (acc: FlattenedActions, arg) => {
71
- if (arg.properties.disposition === 'item') {
72
- return acc;
73
- }
74
-
75
- acc.actions.push(arg);
76
- if (!Node.isAction(arg)) {
77
- const actionGroup = Graph.getActions(graph, arg.id);
78
- acc.groupedActions[arg.id] = actionGroup;
79
- }
80
- return acc;
81
- },
82
- { actions: [], groupedActions: {} },
83
- ),
84
- [actions],
85
- );
34
+ return Graph.getConnections(graph, node?.id ?? Node.RootId, 'child').filter((node) => filterItems(node, disposition));
86
35
  };
87
36
 
88
37
  export type NavTreeContainerProps = {
89
38
  popoverAnchorId?: string;
90
- topbar?: boolean;
91
- } & Pick<NavTreeContextValue, 'tab'>;
39
+ tab: string;
40
+ };
92
41
 
93
42
  export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProps>(
94
- ({ tab, popoverAnchorId, topbar }, forwardedRef) => {
43
+ ({ tab, popoverAnchorId }, forwardedRef) => {
95
44
  const [isLg] = useMediaQuery('lg');
96
- const { invokeSync, invokePromise } = useOperationInvoker();
45
+ const { invokePromise } = useOperationInvoker();
97
46
  const runAction = useActionRunner();
98
47
  const { graph } = useAppGraph();
99
48
  const { getItem, setItem } = useNavTreeState();
100
49
  const layout = useLayout();
50
+ const model = useNavTreeModel(Node.RootId);
101
51
  const { navigationSidebarState } = useSidebars(meta.id);
52
+ const latestRef = useRef({
53
+ tab,
54
+ activeItems: layout.active,
55
+ navigationSidebarState,
56
+ isLg,
57
+ });
102
58
 
103
- const getProps = useCallback(
104
- (node: Node.Node, path: string[]): TreeItemDataProps => {
105
- const children = getChildren(graph, node, path).filter(getChildrenFilter);
106
- const parentOf =
107
- children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
108
- return {
109
- id: node.id,
110
- parentOf,
111
- disabled: node.properties.disabled,
112
- label: node.properties.label ?? node.id,
113
- className: mx(node.properties.className, node.properties.modified && 'italic'), // TODO(burdon): Italic?
114
- headingClassName: node.properties.headingClassName,
115
- icon: node.properties.icon,
116
- iconHue: node.properties.iconHue,
117
- testId: node.properties.testId,
118
- };
119
- },
120
- [graph],
121
- );
122
-
123
- const loadDescendents = useCallback(
124
- (node: Node.Node) => {
125
- Graph.expand(graph, node.id, 'outbound');
126
- // Load one level deeper, which resolves some juddering observed on open/close.
127
- Graph.getConnections(graph, node.id, 'outbound').forEach((child) => {
128
- Graph.expand(graph, child.id, 'outbound');
129
- });
130
- },
131
- [graph],
132
- );
59
+ useEffect(() => {
60
+ latestRef.current = {
61
+ tab,
62
+ activeItems: layout.active,
63
+ navigationSidebarState,
64
+ isLg,
65
+ };
66
+ }, [tab, layout.active, navigationSidebarState, isLg]);
133
67
 
134
68
  const handleOpenChange = useCallback(
135
69
  ({ item: { id }, path, open }: { item: Node.Node; path: string[]; open: boolean }) => {
136
70
  // TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.
137
71
  setItem(path, 'open', open);
138
- Graph.expand(graph, id, 'outbound');
72
+ Graph.expand(graph, id, 'child');
139
73
  },
140
- [graph],
74
+ [graph, setItem],
141
75
  );
142
76
 
143
77
  const handleTabChange = useCallback(
144
78
  (node: NavTreeItemGraphNode) => {
145
- invokeSync(LayoutOperation.UpdateSidebar, {
79
+ Graph.expand(graph, node.id, 'child');
80
+
81
+ const {
82
+ tab: activeTab,
83
+ activeItems,
84
+ navigationSidebarState: currentSidebarState,
85
+ isLg: latestIsLg,
86
+ } = latestRef.current;
87
+ void invokePromise(LayoutOperation.UpdateSidebar, {
146
88
  state:
147
- node.id === tab
148
- ? navigationSidebarState === 'expanded'
149
- ? isLg
89
+ node.id === activeTab
90
+ ? currentSidebarState === 'expanded'
91
+ ? latestIsLg
150
92
  ? 'collapsed'
151
93
  : 'closed'
152
94
  : 'expanded'
153
95
  : 'expanded',
154
96
  });
155
97
 
156
- invokeSync(LayoutOperation.SwitchWorkspace, { subject: node.id });
98
+ void invokePromise(LayoutOperation.SwitchWorkspace, { subject: node.id });
157
99
 
158
100
  // Open the first item if the workspace is empty.
159
- if (layout.active.length === 0) {
101
+ if (activeItems.length === 0) {
160
102
  const [item] = getItems(graph, node).filter((node) => !Node.isActionLike(node));
161
103
  if (item && item.data) {
162
- invokeSync(LayoutOperation.Open, { subject: [item.id] });
104
+ if (layout.mode === 'multi') {
105
+ void invokePromise(LayoutOperation.Set, { subject: [item.id] });
106
+ } else {
107
+ void invokePromise(LayoutOperation.Open, { subject: [item.id] });
108
+ }
163
109
  }
164
110
  }
165
111
  },
166
- [invokeSync, layout.active, tab, navigationSidebarState, isLg],
112
+ [invokePromise, graph, layout.mode],
167
113
  );
168
114
 
169
115
  const blockInstruction = useCallback(
@@ -188,18 +134,22 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
188
134
  }
189
135
 
190
136
  if (Node.isAction(node)) {
191
- const [parent] = Graph.getConnections(graph, node.id, 'inbound');
137
+ const [parent] = Graph.getConnections(graph, node.id, Node.childRelation('inbound'));
192
138
  if (parent) {
193
- void runAction(node, { parent, caller: NAV_TREE_ITEM });
139
+ void runAction(node, { parent, path, caller: NAV_TREE_ITEM });
194
140
  }
195
141
  return;
196
142
  }
197
143
 
198
144
  const current = getItem(path).current;
199
145
  if (!current) {
200
- invokeSync(LayoutOperation.Open, { subject: [node.id], key: node.properties.key });
146
+ if (layout.mode === 'multi') {
147
+ void invokePromise(LayoutOperation.Set, { subject: [node.id] });
148
+ } else {
149
+ void invokePromise(LayoutOperation.Open, { subject: [node.id], key: node.properties.key });
150
+ }
201
151
  } else if (option) {
202
- invokeSync(LayoutOperation.Close, { subject: [node.id] });
152
+ void invokePromise(LayoutOperation.Close, { subject: [node.id] });
203
153
  } else {
204
154
  void invokePromise(LayoutOperation.ScrollIntoView, { subject: node.id });
205
155
  }
@@ -212,13 +162,13 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
212
162
  }
213
163
 
214
164
  if (!isLg) {
215
- invokeSync(LayoutOperation.UpdateSidebar, { state: 'closed' });
165
+ void invokePromise(LayoutOperation.UpdateSidebar, { state: 'closed' });
216
166
  }
217
167
  },
218
- [graph, invokeSync, invokePromise, getItem, isLg, runAction],
168
+ [graph, invokePromise, getItem, runAction, isLg, layout.mode],
219
169
  );
220
170
 
221
- const handleBack = useCallback(() => invokeSync(LayoutOperation.RevertWorkspace), [invokeSync]);
171
+ const handleBack = useCallback(() => void invokePromise(LayoutOperation.RevertWorkspace), [invokePromise]);
222
172
 
223
173
  // TODO(wittjosiah): Factor out hook.
224
174
  useEffect(() => {
@@ -236,8 +186,9 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
236
186
  const targetNode = target.data.item as NavTreeItemGraphNode;
237
187
  const sourcePath = source.data.path as string[];
238
188
  const targetPath = target.data.path as string[];
189
+ const sameParent = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join();
239
190
  const operation =
240
- sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== 'make-child'
191
+ sameParent && instruction.type !== 'make-child'
241
192
  ? 'rearrange'
242
193
  : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
243
194
  const sourceParent = getParent(graph, sourceNode, sourcePath);
@@ -266,7 +217,7 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
266
217
  }
267
218
  case 'transfer': {
268
219
  const target = instruction.type === 'make-child' ? targetNode : targetParent;
269
- if (!target?.properties.onTransferStart || !sourceParent?.properties.onTransferEnd) {
220
+ if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) {
270
221
  break;
271
222
  }
272
223
  void target?.properties.onTransferStart(sourceNode, migrationIndex);
@@ -279,57 +230,39 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
279
230
  });
280
231
  }, [graph]);
281
232
 
282
- const setAlternateTree = useCallback(
283
- (path: string[], open: boolean) => {
284
- setItem(path, 'alternateTree', open);
285
- },
286
- [setItem],
287
- );
233
+ const onItemHover = useCallback(({ item }: { item: Node.Node }) => Graph.expand(graph, item.id, 'child'), [graph]);
288
234
 
289
235
  const navTreeContextValue = useMemo(
290
236
  () => ({
237
+ model,
238
+ popoverAnchorId,
239
+ renderItemEnd: NavTreeItemEnd,
291
240
  blockInstruction,
292
241
  canDrop,
293
242
  canSelect,
294
- getProps,
295
- useIsAlternateTree,
296
- useIsCurrent,
297
- useIsOpen,
298
- loadDescendents,
299
243
  onBack: handleBack,
300
244
  onOpenChange: handleOpenChange,
301
245
  onSelect: handleSelect,
302
246
  onTabChange: handleTabChange,
303
- popoverAnchorId,
304
- renderItemEnd,
305
- setAlternateTree,
306
- tab,
307
- topbar,
308
- useActions,
309
- useItems,
247
+ onItemHover,
310
248
  }),
311
249
  [
250
+ model,
251
+ popoverAnchorId,
312
252
  blockInstruction,
313
253
  canDrop,
314
254
  canSelect,
315
- getProps,
316
255
  handleBack,
317
256
  handleOpenChange,
318
257
  handleSelect,
319
258
  handleTabChange,
320
- loadDescendents,
321
- popoverAnchorId,
322
- renderItemEnd,
323
- setAlternateTree,
324
- tab,
325
- topbar,
326
- useActions,
259
+ onItemHover,
327
260
  ],
328
261
  );
329
262
 
330
263
  return (
331
264
  <NavTreeContext.Provider value={navTreeContextValue}>
332
- <NavTree id={Node.RootId} root={Graph.getRoot(graph)} open={layout.sidebarOpen} ref={forwardedRef} />
265
+ <NavTree id={Node.RootId} root={Graph.getRoot(graph)} tab={tab} open={layout.sidebarOpen} ref={forwardedRef} />
333
266
  </NavTreeContext.Provider>
334
267
  );
335
268
  },
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export { NavTreeContainer, NODE_TYPE } from './NavTreeContainer';
6
+ export { NavTreeContainer as default } from './NavTreeContainer';
@@ -7,12 +7,12 @@ import { type Node } from '@dxos/app-graph';
7
7
  import { toLocalizedString, useTranslation } from '@dxos/react-ui';
8
8
  import { osTranslations } from '@dxos/ui-theme';
9
9
 
10
- import { meta } from '../meta';
10
+ import { meta } from '#meta';
11
11
 
12
12
  export const NavTreeDocumentTitle = ({ node }: { node?: Node.Node }) => {
13
13
  const { t } = useTranslation(meta.id);
14
14
  useEffect(() => {
15
- document.title = node ? toLocalizedString(node.properties.label, t) : t('current app name', { ns: osTranslations });
15
+ document.title = node ? toLocalizedString(node.properties.label, t) : t('current-app.name', { ns: osTranslations });
16
16
  }, [node?.properties?.label]);
17
17
  return null;
18
18
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export { NavTreeDocumentTitle as default } from './NavTreeDocumentTitle';
@@ -0,0 +1,12 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentType, lazy } from 'react';
6
+
7
+ export { NODE_TYPE } from './NavTreeContainer';
8
+
9
+ export const CommandsDialogContent: ComponentType<any> = lazy(() => import('./CommandsDialogContent'));
10
+ export const CommandsTrigger: ComponentType<any> = lazy(() => import('./CommandsTrigger'));
11
+ export const NavTreeContainer: ComponentType<any> = lazy(() => import('./NavTreeContainer'));
12
+ export const NavTreeDocumentTitle: ComponentType<any> = lazy(() => import('./NavTreeDocumentTitle'));