@dxos/plugin-navtree 0.8.4-main.f9ba587 → 0.8.4-main.fcc0d83b33

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 (223) hide show
  1. package/dist/lib/browser/index.mjs +157 -124
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/translations.mjs +21 -0
  5. package/dist/lib/browser/translations.mjs.map +7 -0
  6. package/dist/types/src/NavTreePlugin.d.ts +2 -1
  7. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  8. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  9. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  10. package/dist/types/src/capabilities/index.d.ts +7 -105
  11. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  12. package/dist/types/src/capabilities/keyboard.d.ts +3 -2
  13. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
  14. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  15. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  16. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  17. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  18. package/dist/types/src/capabilities/state.d.ts +4 -18
  19. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  20. package/dist/types/src/components/NavTree/NavTree.d.ts +12 -5
  21. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  22. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +25 -5
  23. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  25. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  26. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  27. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  28. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +13 -9
  29. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  30. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +33 -4
  31. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
  33. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  34. package/dist/types/src/components/Sidebar/L0Menu.d.ts +10 -5
  35. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  36. package/dist/types/src/components/Sidebar/L1Panel.d.ts +4 -8
  37. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  38. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +13 -0
  39. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
  40. package/dist/types/src/components/Sidebar/index.d.ts +1 -0
  41. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
  42. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  43. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
  44. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/index.d.ts +1 -4
  46. package/dist/types/src/components/index.d.ts.map +1 -1
  47. package/dist/types/src/components/types.d.ts +8 -17
  48. package/dist/types/src/components/types.d.ts.map +1 -1
  49. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts +6 -0
  50. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  51. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  52. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  53. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  54. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  55. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  56. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  57. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  58. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  59. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  60. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  61. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  62. package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +1 -1
  63. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  64. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  65. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  66. package/dist/types/src/containers/index.d.ts +7 -0
  67. package/dist/types/src/containers/index.d.ts.map +1 -0
  68. package/dist/types/src/experimental/Tree.d.ts +5 -6
  69. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  70. package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
  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 +1 -2
  83. package/dist/types/src/index.d.ts.map +1 -1
  84. package/dist/types/src/meta.d.ts +3 -4
  85. package/dist/types/src/meta.d.ts.map +1 -1
  86. package/dist/types/src/operations/expose.d.ts +5 -0
  87. package/dist/types/src/operations/expose.d.ts.map +1 -0
  88. package/dist/types/src/operations/index.d.ts +3 -0
  89. package/dist/types/src/operations/index.d.ts.map +1 -0
  90. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  91. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  92. package/dist/types/src/testing/generator.d.ts +5 -6
  93. package/dist/types/src/testing/generator.d.ts.map +1 -1
  94. package/dist/types/src/testing/update-state.d.ts +2 -2
  95. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  96. package/dist/types/src/translations.d.ts +8 -10
  97. package/dist/types/src/translations.d.ts.map +1 -1
  98. package/dist/types/src/types/capabilities.d.ts +15 -0
  99. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  100. package/dist/types/src/types/events.d.ts +5 -0
  101. package/dist/types/src/types/events.d.ts.map +1 -0
  102. package/dist/types/src/types/index.d.ts +4 -0
  103. package/dist/types/src/types/index.d.ts.map +1 -0
  104. package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
  105. package/dist/types/src/types/schema.d.ts.map +1 -0
  106. package/dist/types/src/util.d.ts +12 -9
  107. package/dist/types/src/util.d.ts.map +1 -1
  108. package/dist/types/tsconfig.tsbuildinfo +1 -1
  109. package/package.json +74 -59
  110. package/src/NavTreePlugin.tsx +66 -86
  111. package/src/capabilities/app-graph-builder.ts +34 -44
  112. package/src/capabilities/index.ts +10 -8
  113. package/src/capabilities/keyboard.ts +58 -51
  114. package/src/capabilities/operation-handler.ts +16 -0
  115. package/src/capabilities/react-surface.tsx +46 -38
  116. package/src/capabilities/state.ts +129 -84
  117. package/src/components/NavTree/NavTree.stories.tsx +111 -103
  118. package/src/components/NavTree/NavTree.tsx +71 -35
  119. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  120. package/src/components/NavTreeContext/index.ts +5 -0
  121. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +25 -19
  122. package/src/components/NavTreeItem/NavTreeItemAction.tsx +73 -50
  123. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +70 -38
  124. package/src/components/Sidebar/L0Menu.tsx +176 -210
  125. package/src/components/Sidebar/L1Panel.tsx +212 -135
  126. package/src/components/Sidebar/L1Tabs.tsx +42 -0
  127. package/src/components/Sidebar/index.ts +1 -0
  128. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -9
  129. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  130. package/src/components/index.ts +2 -4
  131. package/src/components/types.ts +14 -19
  132. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  133. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +127 -0
  134. package/src/containers/CommandsDialogContent/index.ts +5 -0
  135. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  136. package/src/containers/CommandsTrigger/index.ts +5 -0
  137. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +271 -0
  138. package/src/containers/NavTreeContainer/index.ts +6 -0
  139. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +5 -4
  140. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  141. package/src/containers/index.ts +12 -0
  142. package/src/experimental/Tree.stories.tsx +110 -115
  143. package/src/experimental/Tree.tsx +16 -34
  144. package/src/hooks/index.ts +8 -0
  145. package/src/hooks/useActions.ts +34 -0
  146. package/src/hooks/useLoadDescendents.ts +23 -0
  147. package/src/hooks/useNavTreeModel.ts +118 -0
  148. package/src/hooks/useNavTreeState.ts +35 -0
  149. package/src/index.ts +1 -2
  150. package/src/meta.ts +11 -8
  151. package/src/operations/expose.ts +42 -0
  152. package/src/operations/index.ts +7 -0
  153. package/src/testing/app-graph-builder.ts +167 -238
  154. package/src/testing/generator.ts +41 -39
  155. package/src/testing/update-state.ts +6 -6
  156. package/src/translations.ts +8 -9
  157. package/src/types/capabilities.ts +21 -0
  158. package/src/types/events.ts +12 -0
  159. package/src/types/index.ts +7 -0
  160. package/src/{types.ts → types/schema.ts} +9 -8
  161. package/src/util.ts +26 -33
  162. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs +0 -45
  163. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
  164. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  165. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  166. package/dist/lib/browser/chunk-TZA65AKW.mjs +0 -1428
  167. package/dist/lib/browser/chunk-TZA65AKW.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
  169. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  170. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs +0 -47
  171. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
  172. package/dist/lib/browser/keyboard-QRS6WOQH.mjs +0 -51
  173. package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
  174. package/dist/lib/browser/react-surface-N2HPMYCU.mjs +0 -51
  175. package/dist/lib/browser/react-surface-N2HPMYCU.mjs.map +0 -7
  176. package/dist/lib/browser/state-54DY3DOY.mjs +0 -117
  177. package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
  178. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs +0 -46
  179. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs.map +0 -7
  180. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs +0 -1429
  181. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs.map +0 -7
  182. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs +0 -18
  183. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs.map +0 -7
  184. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs +0 -16
  185. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs.map +0 -7
  186. package/dist/lib/node-esm/index.mjs +0 -150
  187. package/dist/lib/node-esm/index.mjs.map +0 -7
  188. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs +0 -48
  189. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs.map +0 -7
  190. package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs +0 -52
  191. package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs.map +0 -7
  192. package/dist/lib/node-esm/meta.json +0 -1
  193. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs +0 -52
  194. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs.map +0 -7
  195. package/dist/lib/node-esm/state-Z3OTRC2I.mjs +0 -118
  196. package/dist/lib/node-esm/state-Z3OTRC2I.mjs.map +0 -7
  197. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  198. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  199. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  200. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  201. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  202. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  203. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  204. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  205. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  206. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  207. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  208. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  209. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  210. package/dist/types/src/events.d.ts +0 -4
  211. package/dist/types/src/events.d.ts.map +0 -1
  212. package/dist/types/src/hooks.d.ts +0 -3
  213. package/dist/types/src/hooks.d.ts.map +0 -1
  214. package/dist/types/src/types.d.ts.map +0 -1
  215. package/src/capabilities/capabilities.ts +0 -20
  216. package/src/capabilities/intent-resolver.ts +0 -37
  217. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -118
  218. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -37
  219. package/src/components/CommandsDialog/index.ts +0 -6
  220. package/src/components/NavTreeContainer.tsx +0 -314
  221. package/src/events.ts +0 -11
  222. package/src/hooks.ts +0 -21
  223. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -0,0 +1,127 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { forwardRef, useMemo, useState } from 'react';
6
+
7
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
10
+ import { Keyboard, keySymbols } from '@dxos/keyboard';
11
+ import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
12
+ import { useActions } from '@dxos/plugin-graph';
13
+ import { Button, Dialog, toLocalizedString, useTranslation } from '@dxos/react-ui';
14
+ import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
15
+ import { osTranslations } from '@dxos/ui-theme';
16
+ import { getHostPlatform } from '@dxos/util';
17
+
18
+ import { KEY_BINDING, meta } from '#meta';
19
+
20
+ export type CommandsDialogContentProps = {
21
+ selected?: string;
22
+ };
23
+
24
+ // TODO(wittjosiah): This probably deserves its own plugin but for now it lives here w/ other navigation UI.
25
+ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogContentProps>(
26
+ ({ selected: initial }, forwardedRef) => {
27
+ const { t } = useTranslation(meta.id);
28
+ const { invokePromise } = useOperationInvoker();
29
+ const runAction = useActionRunner();
30
+ const { graph } = useAppGraph();
31
+ const [selected, setSelected] = useState<string | undefined>(initial);
32
+
33
+ // Traverse graph.
34
+ // TODO(burdon): Factor out commonality with shortcut dialog.
35
+ const allActions = useMemo(() => {
36
+ // TODO(burdon): Get from navtree (not keyboard).
37
+ const current = Keyboard.singleton.getCurrentContext();
38
+ const actionMap = new Set<string>();
39
+ const actions: Node.ActionLike[] = [];
40
+ Graph.traverse(graph, {
41
+ relation: ['child', 'action'],
42
+ visitor: (node, path) => {
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
+ actionMap.add(node.id);
48
+ actions.push(node);
49
+ }
50
+ },
51
+ });
52
+
53
+ actions.sort((a, b) => {
54
+ return toLocalizedString(a.properties.label, t)
55
+ ?.toLowerCase()
56
+ .localeCompare(toLocalizedString(b.properties.label, t)?.toLowerCase());
57
+ });
58
+
59
+ return actions;
60
+ }, [graph]);
61
+
62
+ const group = allActions.find(({ id }) => id === selected);
63
+ const groupActions = useActions(graph, group?.id);
64
+ const actions = Node.isActionGroup(group) ? groupActions : allActions;
65
+
66
+ const { results, handleSearch } = useSearchListResults({
67
+ items: actions,
68
+ extract: (action) => toLocalizedString(action.properties.label, t),
69
+ });
70
+
71
+ return (
72
+ <Dialog.Content ref={forwardedRef}>
73
+ <Dialog.Title srOnly>{t('commands-dialog.title', { ns: meta.id })}</Dialog.Title>
74
+ <SearchList.Root onSearch={handleSearch}>
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()];
82
+
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
+ }
94
+
95
+ if (Node.isActionGroup(action)) {
96
+ setSelected(action.id);
97
+ return;
98
+ }
99
+
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>
118
+ </SearchList.Root>
119
+ <Dialog.ActionBar>
120
+ <Dialog.Close asChild>
121
+ <Button classNames='w-full'>{t('close.label', { ns: osTranslations })}</Button>
122
+ </Dialog.Close>
123
+ </Dialog.ActionBar>
124
+ </Dialog.Content>
125
+ );
126
+ },
127
+ );
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export { CommandsDialogContent as default } from './CommandsDialogContent';
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { Button, Icon, useTranslation } from '@dxos/react-ui';
10
+
11
+ import { COMMANDS_DIALOG, meta } from '#meta';
12
+
13
+ // TODO(thure): Refactor to be handled by a more appropriate plugin.
14
+ export const CommandsTrigger = () => {
15
+ const { invokePromise } = useOperationInvoker();
16
+ const { t } = useTranslation(meta.id);
17
+ return (
18
+ <Button
19
+ classNames='m-1 px-1 lg:px-2'
20
+ onClick={() =>
21
+ void invokePromise(LayoutOperation.UpdateDialog, { subject: COMMANDS_DIALOG, blockAlign: 'start' })
22
+ }
23
+ >
24
+ <span className='text-description font-normal grow text-start'>{t('command-list-input.placeholder')}</span>
25
+ <Icon icon='ph--magnifying-glass--regular' />
26
+ </Button>
27
+ );
28
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export { CommandsTrigger as default } from './CommandsTrigger';
@@ -0,0 +1,271 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
6
+ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
+ import React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from 'react';
8
+
9
+ import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
10
+ import { LayoutOperation } from '@dxos/app-toolkit';
11
+ import { useAppGraph, useLayout } from '@dxos/app-toolkit/ui';
12
+ import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
13
+ import { useMediaQuery, useSidebars } from '@dxos/react-ui';
14
+ import { type TreeData, isTreeData } from '@dxos/react-ui-list';
15
+ import { arrayMove } from '@dxos/util';
16
+
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';
21
+
22
+ import { filterItems, getParent, resolveMigrationOperation } from '../../util';
23
+
24
+ // TODO(thure): Is NavTree truly authoritative in this regard?
25
+ export const NODE_TYPE = 'dxos/app-graph/node';
26
+
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} />;
31
+ };
32
+
33
+ const getItems = (graph: Graph.ReadableGraph, node?: Node.Node, disposition?: string) => {
34
+ return Graph.getConnections(graph, node?.id ?? Node.RootId, 'child').filter((node) => filterItems(node, disposition));
35
+ };
36
+
37
+ export type NavTreeContainerProps = {
38
+ popoverAnchorId?: string;
39
+ tab: string;
40
+ };
41
+
42
+ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProps>(
43
+ ({ tab, popoverAnchorId }, forwardedRef) => {
44
+ const [isLg] = useMediaQuery('lg');
45
+ const { invokePromise } = useOperationInvoker();
46
+ const runAction = useActionRunner();
47
+ const { graph } = useAppGraph();
48
+ const { getItem, setItem } = useNavTreeState();
49
+ const layout = useLayout();
50
+ const model = useNavTreeModel(Node.RootId);
51
+ const { navigationSidebarState } = useSidebars(meta.id);
52
+ const latestRef = useRef({
53
+ tab,
54
+ activeItems: layout.active,
55
+ navigationSidebarState,
56
+ isLg,
57
+ });
58
+
59
+ useEffect(() => {
60
+ latestRef.current = {
61
+ tab,
62
+ activeItems: layout.active,
63
+ navigationSidebarState,
64
+ isLg,
65
+ };
66
+ }, [tab, layout.active, navigationSidebarState, isLg]);
67
+
68
+ const handleOpenChange = useCallback(
69
+ ({ item: { id }, path, open }: { item: Node.Node; path: string[]; open: boolean }) => {
70
+ // TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.
71
+ setItem(path, 'open', open);
72
+ Graph.expand(graph, id, 'child');
73
+ },
74
+ [graph, setItem],
75
+ );
76
+
77
+ const handleTabChange = useCallback(
78
+ (node: NavTreeItemGraphNode) => {
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, {
88
+ state:
89
+ node.id === activeTab
90
+ ? currentSidebarState === 'expanded'
91
+ ? latestIsLg
92
+ ? 'collapsed'
93
+ : 'closed'
94
+ : 'expanded'
95
+ : 'expanded',
96
+ });
97
+
98
+ void invokePromise(LayoutOperation.SwitchWorkspace, { subject: node.id });
99
+
100
+ // Open the first item if the workspace is empty.
101
+ if (activeItems.length === 0) {
102
+ const [item] = getItems(graph, node).filter((node) => !Node.isActionLike(node));
103
+ if (item && item.data) {
104
+ if (layout.mode === 'multi') {
105
+ void invokePromise(LayoutOperation.Set, { subject: [item.id] });
106
+ } else {
107
+ void invokePromise(LayoutOperation.Open, { subject: [item.id] });
108
+ }
109
+ }
110
+ }
111
+ },
112
+ [invokePromise, graph, layout.mode],
113
+ );
114
+
115
+ const blockInstruction = useCallback(
116
+ ({ instruction, source, target }: { instruction: Instruction; source: TreeData; target: TreeData }) => {
117
+ return target.item.properties.blockInstruction?.(source, instruction) ?? false;
118
+ },
119
+ [],
120
+ );
121
+
122
+ const canDrop = useCallback(({ source, target }: { source: TreeData; target: TreeData }) => {
123
+ return target.item.properties.canDrop?.(source) ?? false;
124
+ }, []);
125
+
126
+ const canSelect = useCallback(({ item }: { item: Node.Node }) => {
127
+ return item.properties.selectable ?? true;
128
+ }, []);
129
+
130
+ const handleSelect = useCallback(
131
+ ({ item: node, path, option }: { item: Node.Node; path: string[]; option: boolean }) => {
132
+ if (!node.data) {
133
+ return;
134
+ }
135
+
136
+ if (Node.isAction(node)) {
137
+ const [parent] = Graph.getConnections(graph, node.id, Node.childRelation('inbound'));
138
+ if (parent) {
139
+ void runAction(node, { parent, path, caller: NAV_TREE_ITEM });
140
+ }
141
+ return;
142
+ }
143
+
144
+ const current = getItem(path).current;
145
+ if (!current) {
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
+ }
151
+ } else if (option) {
152
+ void invokePromise(LayoutOperation.Close, { subject: [node.id] });
153
+ } else {
154
+ void invokePromise(LayoutOperation.ScrollIntoView, { subject: node.id });
155
+ }
156
+
157
+ const defaultAction = Graph.getActions(graph, node.id).find(
158
+ (action) => action.properties?.disposition === 'default',
159
+ );
160
+ if (Node.isAction(defaultAction)) {
161
+ void runAction(defaultAction);
162
+ }
163
+
164
+ if (!isLg) {
165
+ void invokePromise(LayoutOperation.UpdateSidebar, { state: 'closed' });
166
+ }
167
+ },
168
+ [graph, invokePromise, getItem, runAction, isLg, layout.mode],
169
+ );
170
+
171
+ const handleBack = useCallback(() => void invokePromise(LayoutOperation.RevertWorkspace), [invokePromise]);
172
+
173
+ // TODO(wittjosiah): Factor out hook.
174
+ useEffect(() => {
175
+ return monitorForElements({
176
+ canMonitor: ({ source }) => isTreeData(source.data),
177
+ onDrop: ({ location, source }) => {
178
+ // Didn't drop on anything.
179
+ if (!location.current.dropTargets.length) {
180
+ return;
181
+ }
182
+ const target = location.current.dropTargets[0];
183
+ const instruction: Instruction | null = extractInstruction(target.data);
184
+ if (instruction !== null && instruction.type !== 'instruction-blocked') {
185
+ const sourceNode = source.data.item as NavTreeItemGraphNode;
186
+ const targetNode = target.data.item as NavTreeItemGraphNode;
187
+ const sourcePath = source.data.path as string[];
188
+ const targetPath = target.data.path as string[];
189
+ const sameParent = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join();
190
+ const operation =
191
+ sameParent && instruction.type !== 'make-child'
192
+ ? 'rearrange'
193
+ : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
194
+ const sourceParent = getParent(graph, sourceNode, sourcePath);
195
+ const targetParent = getParent(graph, targetNode, targetPath);
196
+ const sourceItems = getItems(graph, sourceParent);
197
+ const targetItems = getItems(graph, targetParent);
198
+ const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
199
+ const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
200
+ const migrationIndex =
201
+ instruction.type === 'make-child'
202
+ ? undefined
203
+ : instruction.type === 'reorder-below'
204
+ ? targetIndex + 1
205
+ : targetIndex;
206
+ switch (operation) {
207
+ case 'rearrange': {
208
+ const nextItems = sourceItems.map(({ data }) => data);
209
+ arrayMove(nextItems, sourceIndex, targetIndex);
210
+ void sourceNode.properties.onRearrange?.(nextItems);
211
+ break;
212
+ }
213
+ case 'copy': {
214
+ const target = instruction.type === 'make-child' ? targetNode : targetParent;
215
+ void target?.properties.onCopy?.(sourceNode, migrationIndex);
216
+ break;
217
+ }
218
+ case 'transfer': {
219
+ const target = instruction.type === 'make-child' ? targetNode : targetParent;
220
+ if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) {
221
+ break;
222
+ }
223
+ void target?.properties.onTransferStart(sourceNode, migrationIndex);
224
+ void sourceParent?.properties.onTransferEnd?.(sourceNode, target);
225
+ break;
226
+ }
227
+ }
228
+ }
229
+ },
230
+ });
231
+ }, [graph]);
232
+
233
+ const onItemHover = useCallback(({ item }: { item: Node.Node }) => Graph.expand(graph, item.id, 'child'), [graph]);
234
+
235
+ const navTreeContextValue = useMemo(
236
+ () => ({
237
+ model,
238
+ popoverAnchorId,
239
+ renderItemEnd: NavTreeItemEnd,
240
+ blockInstruction,
241
+ canDrop,
242
+ canSelect,
243
+ onBack: handleBack,
244
+ onOpenChange: handleOpenChange,
245
+ onSelect: handleSelect,
246
+ onTabChange: handleTabChange,
247
+ onItemHover,
248
+ }),
249
+ [
250
+ model,
251
+ popoverAnchorId,
252
+ blockInstruction,
253
+ canDrop,
254
+ canSelect,
255
+ handleBack,
256
+ handleOpenChange,
257
+ handleSelect,
258
+ handleTabChange,
259
+ onItemHover,
260
+ ],
261
+ );
262
+
263
+ return (
264
+ <NavTreeContext.Provider value={navTreeContextValue}>
265
+ <NavTree id={Node.RootId} root={Graph.getRoot(graph)} tab={tab} open={layout.sidebarOpen} ref={forwardedRef} />
266
+ </NavTreeContext.Provider>
267
+ );
268
+ },
269
+ );
270
+
271
+ export const NavTreeContainer = memo(NavTreeContainer$);
@@ -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';
@@ -5,13 +5,14 @@ import { useEffect } from 'react';
5
5
 
6
6
  import { type Node } from '@dxos/app-graph';
7
7
  import { toLocalizedString, useTranslation } from '@dxos/react-ui';
8
+ import { osTranslations } from '@dxos/ui-theme';
8
9
 
9
- import { NAVTREE_PLUGIN } from '../meta';
10
+ import { meta } from '#meta';
10
11
 
11
- export const NavTreeDocumentTitle = ({ node }: { node?: Node }) => {
12
- const { t } = useTranslation(NAVTREE_PLUGIN);
12
+ export const NavTreeDocumentTitle = ({ node }: { node?: Node.Node }) => {
13
+ const { t } = useTranslation(meta.id);
13
14
  useEffect(() => {
14
- document.title = node ? toLocalizedString(node.properties.label, t) : t('current app name', { ns: 'appkit' });
15
+ document.title = node ? toLocalizedString(node.properties.label, t) : t('current-app.name', { ns: osTranslations });
15
16
  }, [node?.properties?.label]);
16
17
  return null;
17
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'));