@dxos/plugin-navtree 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b

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 (116) hide show
  1. package/dist/lib/browser/app-graph-builder-BL7LRXCM.mjs +44 -0
  2. package/dist/lib/browser/app-graph-builder-BL7LRXCM.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-AOAGODQB.mjs +15 -0
  4. package/dist/lib/browser/chunk-AOAGODQB.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-EO6JEADO.mjs +1113 -0
  6. package/dist/lib/browser/chunk-EO6JEADO.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-VAXG4OAG.mjs → chunk-KOXMEAOS.mjs} +3 -3
  8. package/dist/lib/browser/{chunk-VAXG4OAG.mjs.map → chunk-KOXMEAOS.mjs.map} +3 -3
  9. package/dist/lib/browser/index.mjs +108 -1199
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/intent-resolver-U25VBFH3.mjs +47 -0
  12. package/dist/lib/browser/intent-resolver-U25VBFH3.mjs.map +7 -0
  13. package/dist/lib/browser/keyboard-MUBRTPI5.mjs +46 -0
  14. package/dist/lib/browser/keyboard-MUBRTPI5.mjs.map +7 -0
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/react-surface-6ZP5XUTS.mjs +57 -0
  17. package/dist/lib/browser/react-surface-6ZP5XUTS.mjs.map +7 -0
  18. package/dist/lib/browser/state-65TQKYX7.mjs +108 -0
  19. package/dist/lib/browser/state-65TQKYX7.mjs.map +7 -0
  20. package/dist/types/src/NavTreePlugin.d.ts +1 -3
  21. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
  23. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  24. package/dist/types/src/capabilities/capabilities.d.ts +18 -0
  25. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  26. package/dist/types/src/capabilities/index.d.ts +251 -0
  27. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  28. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  29. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  30. package/dist/types/src/capabilities/keyboard.d.ts +4 -0
  31. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  32. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  33. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  34. package/dist/types/src/capabilities/state.d.ts +17 -0
  35. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  36. package/dist/types/src/components/CommandsDialog.d.ts.map +1 -1
  37. package/dist/types/src/components/CommandsTrigger.d.ts.map +1 -1
  38. package/dist/types/src/components/L0Menu.d.ts +9 -0
  39. package/dist/types/src/components/L0Menu.d.ts.map +1 -0
  40. package/dist/types/src/components/L1Panels.d.ts +8 -0
  41. package/dist/types/src/components/L1Panels.d.ts.map +1 -0
  42. package/dist/types/src/components/NavTree.d.ts +3 -22
  43. package/dist/types/src/components/NavTree.d.ts.map +1 -1
  44. package/dist/types/src/components/NavTree.stories.d.ts +2 -2
  45. package/dist/types/src/components/NavTree.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/NavTreeContainer.d.ts +4 -3
  47. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  48. package/dist/types/src/components/NavTreeContext.d.ts +4 -0
  49. package/dist/types/src/components/NavTreeContext.d.ts.map +1 -0
  50. package/dist/types/src/components/NavTreeItemAction.d.ts +4 -8
  51. package/dist/types/src/components/NavTreeItemAction.d.ts.map +1 -1
  52. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +0 -5
  53. package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +1 -1
  54. package/dist/types/src/components/NavTreeItemColumns.d.ts +4 -0
  55. package/dist/types/src/components/NavTreeItemColumns.d.ts.map +1 -0
  56. package/dist/types/src/components/NotchStart.d.ts.map +1 -1
  57. package/dist/types/src/components/index.d.ts +3 -0
  58. package/dist/types/src/components/index.d.ts.map +1 -1
  59. package/dist/types/src/components/types.d.ts +25 -0
  60. package/dist/types/src/components/types.d.ts.map +1 -0
  61. package/dist/types/src/events.d.ts +4 -0
  62. package/dist/types/src/events.d.ts.map +1 -0
  63. package/dist/types/src/hooks.d.ts +3 -0
  64. package/dist/types/src/hooks.d.ts.map +1 -0
  65. package/dist/types/src/index.d.ts +3 -2
  66. package/dist/types/src/index.d.ts.map +1 -1
  67. package/dist/types/src/meta.d.ts +1 -2
  68. package/dist/types/src/meta.d.ts.map +1 -1
  69. package/dist/types/src/stories/Graph.stories.d.ts +2 -2
  70. package/dist/types/src/stories/Graph.stories.d.ts.map +1 -1
  71. package/dist/types/src/stories/StorybookNavTree.d.ts +4 -0
  72. package/dist/types/src/stories/StorybookNavTree.d.ts.map +1 -0
  73. package/dist/types/src/translations.d.ts +0 -7
  74. package/dist/types/src/translations.d.ts.map +1 -1
  75. package/dist/types/src/types.d.ts +3 -2
  76. package/dist/types/src/types.d.ts.map +1 -1
  77. package/dist/types/src/util.d.ts +9 -0
  78. package/dist/types/src/util.d.ts.map +1 -1
  79. package/dist/types/tsconfig.tsbuildinfo +1 -1
  80. package/package.json +34 -39
  81. package/src/NavTreePlugin.tsx +67 -291
  82. package/src/capabilities/app-graph-builder.ts +42 -0
  83. package/src/capabilities/capabilities.ts +19 -0
  84. package/src/capabilities/index.ts +13 -0
  85. package/src/capabilities/intent-resolver.ts +36 -0
  86. package/src/capabilities/keyboard.ts +54 -0
  87. package/src/capabilities/react-surface.tsx +56 -0
  88. package/src/capabilities/state.ts +97 -0
  89. package/src/components/CommandsDialog.tsx +3 -4
  90. package/src/components/CommandsTrigger.tsx +7 -5
  91. package/src/components/L0Menu.tsx +208 -0
  92. package/src/components/L1Panels.tsx +100 -0
  93. package/src/components/NavTree.stories.tsx +5 -5
  94. package/src/components/NavTree.tsx +26 -124
  95. package/src/components/NavTreeContainer.tsx +106 -44
  96. package/src/components/NavTreeContext.tsx +13 -0
  97. package/src/components/NavTreeItemAction.stories.tsx +0 -2
  98. package/src/components/NavTreeItemAction.tsx +58 -316
  99. package/src/components/NavTreeItemColumns.tsx +71 -0
  100. package/src/components/NotchStart.tsx +6 -5
  101. package/src/components/index.ts +3 -0
  102. package/src/components/types.ts +33 -0
  103. package/src/events.ts +11 -0
  104. package/src/hooks.ts +21 -0
  105. package/src/index.ts +3 -4
  106. package/src/meta.ts +1 -1
  107. package/src/stories/Graph.stories.tsx +5 -4
  108. package/src/stories/StorybookNavTree.tsx +63 -0
  109. package/src/translations.ts +0 -7
  110. package/src/types.ts +3 -2
  111. package/src/util.ts +54 -0
  112. package/dist/lib/browser/meta.mjs +0 -13
  113. package/dist/lib/browser/meta.mjs.map +0 -7
  114. package/dist/types/src/components/NavTreeFooter.d.ts +0 -6
  115. package/dist/types/src/components/NavTreeFooter.d.ts.map +0 -1
  116. package/src/components/NavTreeFooter.tsx +0 -159
@@ -1,936 +1,41 @@
1
+ import {
2
+ AppGraphBuilder,
3
+ IntentResolver,
4
+ Keyboard,
5
+ NODE_TYPE,
6
+ ReactSurface,
7
+ State,
8
+ expandActions,
9
+ expandChildren,
10
+ expandChildrenAndActions,
11
+ getActions,
12
+ getChildren,
13
+ getFirstTwoRenderableChars,
14
+ getParent,
15
+ getPersistenceParent,
16
+ l0ItemType,
17
+ resolveMigrationOperation,
18
+ sortActions
19
+ } from "./chunk-EO6JEADO.mjs";
20
+ import {
21
+ NavTreeCapabilities
22
+ } from "./chunk-AOAGODQB.mjs";
1
23
  import {
2
24
  COMMANDS_DIALOG,
3
25
  KEY_BINDING,
4
26
  NAVTREE_PLUGIN,
5
- meta_default
6
- } from "./chunk-VAXG4OAG.mjs";
27
+ meta
28
+ } from "./chunk-KOXMEAOS.mjs";
7
29
 
8
- // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
9
- import { effect } from "@preact/signals-core";
10
- import React9 from "react";
11
- import { createIntent as createIntent6, createResolver, createSurface, LayoutAction as LayoutAction4, NavigationAction as NavigationAction2, parseGraphPlugin, parseIntentPlugin, parseLayoutPlugin, parseNavigationPlugin as parseNavigationPlugin2, resolvePlugin } from "@dxos/app-framework";
12
- import { createExtension, isAction as isAction5, isGraphNode } from "@dxos/app-graph";
13
- import { Keyboard as Keyboard2 } from "@dxos/keyboard";
14
- import { create } from "@dxos/live-object";
15
- import { Path } from "@dxos/react-ui-mosaic";
16
- import { getHostPlatform as getHostPlatform3 } from "@dxos/util";
30
+ // packages/plugins/plugin-navtree/src/events.ts
31
+ import { Events } from "@dxos/app-framework";
32
+ var NavTreeEvents;
33
+ (function(NavTreeEvents2) {
34
+ NavTreeEvents2.StateReady = Events.createStateEvent(NAVTREE_PLUGIN);
35
+ })(NavTreeEvents || (NavTreeEvents = {}));
17
36
 
18
- // packages/plugins/plugin-navtree/src/components/CommandsDialog.tsx
19
- import React, { useMemo, useState } from "react";
20
- import { useIntentDispatcher, LayoutAction, createIntent } from "@dxos/app-framework";
21
- import { isActionGroup, isAction } from "@dxos/app-graph";
22
- import { Keyboard, keySymbols } from "@dxos/keyboard";
23
- import { useGraph } from "@dxos/plugin-graph";
24
- import { Button, Dialog, Icon, useTranslation, toLocalizedString } from "@dxos/react-ui";
25
- import { SearchList } from "@dxos/react-ui-searchlist";
26
- import { descriptionText, mx } from "@dxos/react-ui-theme";
27
- import { getHostPlatform } from "@dxos/util";
28
- var CommandsDialogContent = ({ selected: initial }) => {
29
- const { t } = useTranslation(NAVTREE_PLUGIN);
30
- const [selected, setSelected] = useState(initial);
31
- const { dispatchPromise: dispatch } = useIntentDispatcher();
32
- const { graph } = useGraph();
33
- const allActions = useMemo(() => {
34
- const current = Keyboard.singleton.getCurrentContext();
35
- const actionMap = /* @__PURE__ */ new Set();
36
- const actions2 = [];
37
- graph?.traverse({
38
- visitor: (node, path) => {
39
- if ((isAction(node) || isActionGroup(node)) && !actionMap.has(node.id) && current.startsWith(path.slice(0, -1).join("/"))) {
40
- actionMap.add(node.id);
41
- actions2.push(node);
42
- }
43
- }
44
- });
45
- actions2.sort((a, b) => {
46
- return toLocalizedString(a.properties.label, t)?.toLowerCase().localeCompare(toLocalizedString(b.properties.label, t)?.toLowerCase());
47
- });
48
- return actions2;
49
- }, [
50
- graph
51
- ]);
52
- const group = allActions.find(({ id }) => id === selected);
53
- const actions = isActionGroup(group) ? graph.actions(group) : allActions;
54
- return /* @__PURE__ */ React.createElement(Dialog.Content, {
55
- classNames: [
56
- "md:max-is-[30rem] overflow-hidden mbs-12"
57
- ]
58
- }, /* @__PURE__ */ React.createElement(Dialog.Title, null, t("commands dialog title", {
59
- ns: NAVTREE_PLUGIN
60
- })), /* @__PURE__ */ React.createElement(SearchList.Root, {
61
- label: t("command list input placeholder"),
62
- classNames: "flex flex-col grow overflow-hidden my-2"
63
- }, /* @__PURE__ */ React.createElement(SearchList.Input, {
64
- placeholder: t("command list input placeholder"),
65
- classNames: "px-1 my-2"
66
- }), /* @__PURE__ */ React.createElement(SearchList.Content, {
67
- classNames: "max-bs-[24rem] overflow-auto"
68
- }, actions?.map((action) => {
69
- const label = toLocalizedString(action.properties.label, t);
70
- const shortcut = typeof action.properties.keyBinding === "string" ? action.properties.keyBinding : action.properties.keyBinding?.[getHostPlatform()];
71
- return /* @__PURE__ */ React.createElement(SearchList.Item, {
72
- value: label,
73
- key: action.id,
74
- onSelect: () => {
75
- if (action.properties.disabled) {
76
- return;
77
- }
78
- if (isActionGroup(action)) {
79
- setSelected(action.id);
80
- return;
81
- }
82
- void dispatch(createIntent(LayoutAction.SetLayout, {
83
- element: "dialog",
84
- state: false
85
- }));
86
- setTimeout(() => {
87
- const node = graph.nodes(group ?? action, {
88
- relation: "inbound"
89
- })[0];
90
- void (node && isAction(action) && action.data({
91
- node,
92
- caller: KEY_BINDING
93
- }));
94
- });
95
- },
96
- classNames: "flex items-center gap-2",
97
- disabled: action.properties.disabled,
98
- ...action.properties?.testId && {
99
- "data-testid": action.properties.testId
100
- }
101
- }, /* @__PURE__ */ React.createElement(Icon, {
102
- icon: action.properties.icon,
103
- size: 4
104
- }), /* @__PURE__ */ React.createElement("span", {
105
- className: "grow truncate"
106
- }, label), shortcut && /* @__PURE__ */ React.createElement("span", {
107
- className: mx("shrink-0", descriptionText)
108
- }, keySymbols(shortcut).join("")));
109
- }))), /* @__PURE__ */ React.createElement(Dialog.Close, {
110
- asChild: true
111
- }, /* @__PURE__ */ React.createElement(Button, {
112
- variant: "primary",
113
- classNames: "mbs-2"
114
- }, t("close label", {
115
- ns: "os"
116
- }))));
117
- };
118
-
119
- // packages/plugins/plugin-navtree/src/components/NavTree.tsx
120
- import React3, { Fragment, useCallback, useEffect } from "react";
121
- import { isAction as isAction2 } from "@dxos/app-graph";
122
- import { Popover, toLocalizedString as toLocalizedString3, Treegrid, useTranslation as useTranslation3 } from "@dxos/react-ui";
123
- import { Tree } from "@dxos/react-ui-list";
124
-
125
- // packages/plugins/plugin-navtree/src/components/NavTreeItemAction.tsx
126
- import { useControllableState } from "@radix-ui/react-use-controllable-state";
127
- import React2, { useRef, useState as useState2 } from "react";
128
- import { keySymbols as keySymbols2 } from "@dxos/keyboard";
129
- import { Button as Button2, Dialog as Dialog2, DropdownMenu, ContextMenu, Tooltip, useTranslation as useTranslation2, toLocalizedString as toLocalizedString2, Icon as Icon2 } from "@dxos/react-ui";
130
- import { SearchList as SearchList2 } from "@dxos/react-ui-searchlist";
131
- import { descriptionText as descriptionText2, hoverableControlItem, hoverableOpenControlItem, mx as mx2 } from "@dxos/react-ui-theme";
132
- import { getHostPlatform as getHostPlatform2 } from "@dxos/util";
133
- var getShortcut = (action) => {
134
- return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform2()];
135
- };
136
- var fallbackIcon = "ph--placeholder--regular";
137
- var NavTreeItemActionDropdownMenu = ({ label, icon, testId, defaultMenuOpen, menuActions, menuOpen, suppressNextTooltip, onChangeMenuOpen, onAction }) => {
138
- const { t } = useTranslation2(NAVTREE_PLUGIN);
139
- const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
140
- prop: menuOpen,
141
- defaultProp: defaultMenuOpen,
142
- onChange: onChangeMenuOpen
143
- });
144
- return /* @__PURE__ */ React2.createElement(DropdownMenu.Root, {
145
- open: optionsMenuOpen,
146
- onOpenChange: (nextOpen) => {
147
- if (!nextOpen && suppressNextTooltip) {
148
- suppressNextTooltip.current = true;
149
- }
150
- return setOptionsMenuOpen(nextOpen);
151
- }
152
- }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
153
- asChild: true
154
- }, /* @__PURE__ */ React2.createElement(DropdownMenu.Trigger, {
155
- asChild: true
156
- }, /* @__PURE__ */ React2.createElement(Button2, {
157
- variant: "ghost",
158
- density: "fine",
159
- classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
160
- "data-testid": testId,
161
- "aria-label": t("tree item actions label")
162
- }, /* @__PURE__ */ React2.createElement("span", {
163
- className: "sr-only"
164
- }, toLocalizedString2(label, t)), /* @__PURE__ */ React2.createElement(Icon2, {
165
- icon: icon ?? fallbackIcon,
166
- size: 4
167
- })))), /* @__PURE__ */ React2.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React2.createElement(DropdownMenu.Viewport, null, menuActions?.map((action) => {
168
- const shortcut = getShortcut(action);
169
- return /* @__PURE__ */ React2.createElement(DropdownMenu.Item, {
170
- key: action.id,
171
- onClick: (event) => {
172
- if (action.properties?.disabled) {
173
- return;
174
- }
175
- event.stopPropagation();
176
- if (suppressNextTooltip) {
177
- suppressNextTooltip.current = true;
178
- }
179
- setOptionsMenuOpen(false);
180
- onAction?.(action);
181
- },
182
- classNames: "gap-2",
183
- disabled: action.properties?.disabled,
184
- ...action.properties?.testId && {
185
- "data-testid": action.properties.testId
186
- }
187
- }, action.properties?.icon && /* @__PURE__ */ React2.createElement(Icon2, {
188
- icon: action.properties.icon,
189
- size: 4
190
- }), /* @__PURE__ */ React2.createElement("span", {
191
- className: "grow truncate"
192
- }, toLocalizedString2(action.properties.label, t)), shortcut && /* @__PURE__ */ React2.createElement("span", {
193
- className: mx2("shrink-0", descriptionText2)
194
- }, keySymbols2(shortcut).join("")));
195
- })), /* @__PURE__ */ React2.createElement(DropdownMenu.Arrow, null))));
196
- };
197
- var NavTreeItemActionSearchList = ({ menuActions, icon, label, testId, suppressNextTooltip, onAction }) => {
198
- const { t } = useTranslation2(NAVTREE_PLUGIN);
199
- const [optionsMenuOpen, setOptionsMenuOpen] = useState2(false);
200
- const button = useRef(null);
201
- const sortedActions = menuActions?.sort(({ properties: p1 }, { properties: p2 }) => {
202
- const t1 = toLocalizedString2(p1.label, t).toLowerCase();
203
- const t2 = toLocalizedString2(p2.label, t).toLowerCase();
204
- return t1.localeCompare(t2);
205
- });
206
- return /* @__PURE__ */ React2.createElement(Dialog2.Root, {
207
- open: optionsMenuOpen,
208
- onOpenChange: (nextOpen) => {
209
- if (!nextOpen && suppressNextTooltip) {
210
- suppressNextTooltip.current = true;
211
- }
212
- return setOptionsMenuOpen(nextOpen);
213
- }
214
- }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
215
- asChild: true
216
- }, /* @__PURE__ */ React2.createElement(Dialog2.Trigger, {
217
- asChild: true
218
- }, /* @__PURE__ */ React2.createElement(Button2, {
219
- variant: "ghost",
220
- density: "fine",
221
- classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
222
- "data-testid": testId,
223
- onKeyDownCapture: (event) => {
224
- if (button.current && button.current === event.target) {
225
- switch (event.key) {
226
- case "Enter":
227
- case " ":
228
- event.stopPropagation();
229
- setOptionsMenuOpen(true);
230
- break;
231
- default:
232
- }
233
- }
234
- },
235
- ref: button
236
- }, /* @__PURE__ */ React2.createElement(Icon2, {
237
- icon: icon ?? fallbackIcon,
238
- size: 4
239
- })))), /* @__PURE__ */ React2.createElement(Dialog2.Portal, null, /* @__PURE__ */ React2.createElement(Dialog2.Overlay, null, /* @__PURE__ */ React2.createElement(Dialog2.Content, {
240
- classNames: "is-full max-is-[24rem] pli-2 plb-1"
241
- }, /* @__PURE__ */ React2.createElement(SearchList2.Root, {
242
- label: t("tree item searchlist input placeholder")
243
- }, /* @__PURE__ */ React2.createElement(SearchList2.Input, {
244
- placeholder: t("tree item searchlist input placeholder"),
245
- classNames: "pli-3"
246
- }), /* @__PURE__ */ React2.createElement(SearchList2.Content, {
247
- classNames: "min-bs-[12rem] bs-[50dvh] max-bs-[30rem] overflow-auto"
248
- }, sortedActions?.map((action) => {
249
- const label2 = toLocalizedString2(action.properties.label, t);
250
- const shortcut = getShortcut(action);
251
- return /* @__PURE__ */ React2.createElement(SearchList2.Item, {
252
- // TODO(burdon): Value should be id since label is not unique.
253
- value: label2,
254
- key: action.id,
255
- onSelect: () => {
256
- if (action.properties?.disabled) {
257
- return;
258
- }
259
- if (suppressNextTooltip) {
260
- suppressNextTooltip.current = true;
261
- }
262
- setOptionsMenuOpen(false);
263
- onAction?.(action);
264
- },
265
- classNames: "flex items-center gap-2 pli-2",
266
- disabled: action.properties?.disabled,
267
- ...action.properties?.testId && {
268
- "data-testid": action.properties.testId
269
- }
270
- }, action.properties?.icon && /* @__PURE__ */ React2.createElement(Icon2, {
271
- icon: action.properties?.icon,
272
- size: 4
273
- }), /* @__PURE__ */ React2.createElement("span", {
274
- className: "grow truncate"
275
- }, label2), shortcut && /* @__PURE__ */ React2.createElement("span", {
276
- className: mx2("shrink-0", descriptionText2)
277
- }, keySymbols2(shortcut).join("")));
278
- })), /* @__PURE__ */ React2.createElement("div", {
279
- role: "none",
280
- className: "flex items-center plb-2 pli-3"
281
- }, /* @__PURE__ */ React2.createElement("span", {
282
- className: descriptionText2
283
- }, toLocalizedString2(label, t))))))));
284
- };
285
- var NavTreeItemMonolithicAction = ({ parent, properties: { disabled, caller, testId, label, icon } = {
286
- label: "never"
287
- }, data: invoke }) => {
288
- const { t } = useTranslation2(NAVTREE_PLUGIN);
289
- return /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
290
- asChild: true
291
- }, /* @__PURE__ */ React2.createElement(Button2, {
292
- variant: "ghost",
293
- density: "fine",
294
- classNames: mx2("shrink-0 !pli-2 pointer-fine:!pli-1", hoverableControlItem, hoverableOpenControlItem),
295
- disabled,
296
- onClick: (event) => {
297
- if (disabled) {
298
- return;
299
- }
300
- event.stopPropagation();
301
- void invoke?.(caller ? {
302
- node: parent,
303
- caller
304
- } : {
305
- node: parent
306
- });
307
- },
308
- "data-testid": testId
309
- }, /* @__PURE__ */ React2.createElement("span", {
310
- className: "sr-only"
311
- }, toLocalizedString2(label, t)), /* @__PURE__ */ React2.createElement(Icon2, {
312
- icon: icon ?? fallbackIcon,
313
- size: 4
314
- })));
315
- };
316
- var NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...props }) => {
317
- const { t } = useTranslation2(NAVTREE_PLUGIN);
318
- const suppressNextTooltip = useRef(false);
319
- const [triggerTooltipOpen, setTriggerTooltipOpen] = useState2(false);
320
- const monolithicAction = menuActions?.length === 1 && menuActions[0];
321
- const baseLabel = toLocalizedString2(monolithicAction ? monolithicAction.properties.label : props.label, t);
322
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
323
- open: triggerTooltipOpen,
324
- onOpenChange: (nextOpen) => {
325
- if (suppressNextTooltip.current) {
326
- setTriggerTooltipOpen(false);
327
- suppressNextTooltip.current = false;
328
- } else {
329
- setTriggerTooltipOpen(nextOpen);
330
- }
331
- }
332
- }, baseLabel && /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, {
333
- classNames: "z-[31]",
334
- side: "bottom"
335
- }, baseLabel, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))), monolithic && menuActions?.length === 1 ? /* @__PURE__ */ React2.createElement(NavTreeItemMonolithicAction, {
336
- parent: node,
337
- ...menuActions[0]
338
- }) : props.menuType === "searchList" ? /* @__PURE__ */ React2.createElement(NavTreeItemActionSearchList, {
339
- ...props,
340
- menuActions,
341
- suppressNextTooltip,
342
- onAction: (action) => action.data?.(props.caller ? {
343
- node,
344
- caller: props.caller
345
- } : {
346
- node
347
- })
348
- }) : /* @__PURE__ */ React2.createElement(NavTreeItemActionDropdownMenu, {
349
- ...props,
350
- parent: node,
351
- menuActions,
352
- suppressNextTooltip,
353
- onAction: (action) => action.data?.(props.caller ? {
354
- node,
355
- caller: props.caller
356
- } : {
357
- node
358
- })
359
- }));
360
- };
361
-
362
- // packages/plugins/plugin-navtree/src/components/NavTree.tsx
363
- var NAV_TREE_ITEM = "NavTreeItem";
364
- var NavTree = ({ getActions: getActions2, loadDescendents, renderItemEnd: renderItemEnd2, popoverAnchorId, ...props }) => {
365
- const renderColumns = useCallback(({ item, path, open, menuOpen, setMenuOpen }) => {
366
- return /* @__PURE__ */ React3.createElement(NavTreeColumns, {
367
- path,
368
- node: item,
369
- getActions: getActions2,
370
- open,
371
- menuOpen,
372
- setMenuOpen,
373
- loadDescendents,
374
- renderItemEnd: renderItemEnd2,
375
- popoverAnchorId
376
- });
377
- }, [
378
- renderItemEnd2,
379
- popoverAnchorId,
380
- loadDescendents
381
- ]);
382
- return /* @__PURE__ */ React3.createElement(Tree, {
383
- ...props,
384
- draggable: true,
385
- gridTemplateColumns: "[tree-row-start] 1fr min-content min-content min-content [tree-row-end]",
386
- renderColumns
387
- });
388
- };
389
- var NavTreeColumns = ({ path, node, getActions: getActions2, open, menuOpen, setMenuOpen, loadDescendents, renderItemEnd: ItemEnd, popoverAnchorId }) => {
390
- const { t } = useTranslation3(NAVTREE_PLUGIN);
391
- const level = path.length - 2;
392
- const { actions: _actions, groupedActions } = getActions2(node);
393
- const [primaryAction, ...secondaryActions] = _actions.toSorted((a, b) => a.properties?.disposition === "toolbar" ? -1 : 1);
394
- const actions = (primaryAction?.properties?.disposition === "toolbar" ? secondaryActions : _actions).flatMap((action) => isAction2(action) ? [
395
- action
396
- ] : []).filter((action) => !action.properties?.hidden);
397
- const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${node.id}` ? Popover.Anchor : Fragment;
398
- useEffect(() => {
399
- const frame = requestAnimationFrame(() => {
400
- void loadDescendents?.(node);
401
- if (primaryAction && !isAction2(primaryAction)) {
402
- void loadDescendents?.(primaryAction);
403
- }
404
- });
405
- return () => cancelAnimationFrame(frame);
406
- }, [
407
- primaryAction
408
- ]);
409
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, primaryAction?.properties?.disposition === "toolbar" ? /* @__PURE__ */ React3.createElement(NavTreeItemAction, {
410
- testId: primaryAction.properties?.testId,
411
- label: toLocalizedString3(primaryAction.properties?.label, t),
412
- icon: primaryAction.properties?.icon ?? "ph--placeholder--regular",
413
- parent: node,
414
- monolithic: isAction2(primaryAction),
415
- menuActions: isAction2(primaryAction) ? [
416
- primaryAction
417
- ] : groupedActions[primaryAction.id],
418
- menuType: primaryAction.properties?.menuType,
419
- caller: NAV_TREE_ITEM
420
- }) : /* @__PURE__ */ React3.createElement(Treegrid.Cell, null), /* @__PURE__ */ React3.createElement(ActionRoot, null, actions.length > 0 ? /* @__PURE__ */ React3.createElement(NavTreeItemAction, {
421
- testId: `navtree.treeItem.actionsLevel${level}`,
422
- label: t("tree item actions label"),
423
- icon: "ph--dots-three-vertical--regular",
424
- parent: node,
425
- menuActions: actions,
426
- menuType: "dropdown",
427
- caller: NAV_TREE_ITEM,
428
- menuOpen,
429
- onChangeMenuOpen: setMenuOpen
430
- }) : /* @__PURE__ */ React3.createElement(Treegrid.Cell, null)), ItemEnd && /* @__PURE__ */ React3.createElement(ItemEnd, {
431
- node,
432
- open
433
- }));
434
- };
435
-
436
- // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
437
- import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
438
- import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
439
- import { untracked } from "@preact/signals-core";
440
- import React5, { memo, useCallback as useCallback2, useEffect as useEffect2 } from "react";
441
- import { createIntent as createIntent3, LayoutAction as LayoutAction2, NavigationAction, Surface, useIntentDispatcher as useIntentDispatcher3 } from "@dxos/app-framework";
442
- import { isAction as isAction4, isActionLike } from "@dxos/app-graph";
443
- import { useGraph as useGraph2 } from "@dxos/plugin-graph";
444
- import { isEchoObject, isSpace } from "@dxos/react-client/echo";
445
- import { useMediaQuery, useSidebars as useSidebars2 } from "@dxos/react-ui";
446
- import { isTreeData } from "@dxos/react-ui-list";
447
- import { mx as mx4 } from "@dxos/react-ui-theme";
448
- import { arrayMove } from "@dxos/util";
449
-
450
- // packages/plugins/plugin-navtree/src/components/NavTreeFooter.tsx
451
- import { ArrowSquareOut, GearSix, Warning } from "@phosphor-icons/react";
452
- import { formatDistance } from "date-fns/formatDistance";
453
- import React4 from "react";
454
- import { SettingsAction, parseNavigationPlugin, useResolvePlugin, useIntentDispatcher as useIntentDispatcher2, createIntent as createIntent2 } from "@dxos/app-framework";
455
- import { useConfig } from "@dxos/react-client";
456
- import { Button as Button3, Link, Message, Popover as Popover2, Tooltip as Tooltip2, Trans, useDefaultValue, useSidebars, useTranslation as useTranslation4 } from "@dxos/react-ui";
457
- import { LayoutControls } from "@dxos/react-ui-stack";
458
- import { getSize, mx as mx3 } from "@dxos/react-ui-theme";
459
- var buttonStyles = "pli-1.5 text-xs font-normal";
460
- var repo = "https://github.com/dxos/dxos";
461
- var VERSION_REGEX = /([\d.]+)/;
462
- var NavTreeFooter = (props) => {
463
- const layoutPart = useDefaultValue(props.layoutPart, () => "sidebar");
464
- const config = useConfig();
465
- const { t } = useTranslation4(NAVTREE_PLUGIN);
466
- const { navigationSidebarOpen } = useSidebars(NAVTREE_PLUGIN);
467
- const { dispatchPromise: dispatch } = useIntentDispatcher2();
468
- const { version, timestamp, commitHash } = config.values.runtime?.app?.build ?? {};
469
- const navigationPlugin = useResolvePlugin(parseNavigationPlugin);
470
- const [_, v] = version?.match(VERSION_REGEX) ?? [];
471
- const releaseUrl = config.values.runtime?.app?.env?.DX_ENVIRONMENT === "production" ? `${repo}/releases/tag/v${version}` : `${repo}/commit/${commitHash}`;
472
- const previewUrl = "https://docs.dxos.org/composer#technology-preview";
473
- return /* @__PURE__ */ React4.createElement("div", {
474
- role: "none",
475
- className: mx3("flex bs-[--rail-size] pbe-[env(safe-area-inset-bottom)] box-content justify-end", layoutPart === "complementary" && "md:justify-end flex-row-reverse")
476
- }, /* @__PURE__ */ React4.createElement(Popover2.Root, null, /* @__PURE__ */ React4.createElement(Popover2.Trigger, {
477
- asChild: true
478
- }, /* @__PURE__ */ React4.createElement(Button3, {
479
- variant: "ghost",
480
- classNames: buttonStyles,
481
- ...!navigationSidebarOpen && {
482
- tabIndex: -1
483
- }
484
- }, "v", v)), /* @__PURE__ */ React4.createElement(Popover2.Portal, null, /* @__PURE__ */ React4.createElement(Popover2.Content, {
485
- side: "top",
486
- role: "message",
487
- classNames: "z-[12] bg-warning-500 max-is-[min(calc(100vw-16px),40ch)]"
488
- }, /* @__PURE__ */ React4.createElement(Message.Root, {
489
- valence: "warning",
490
- className: "rounded-be-none p-5"
491
- }, /* @__PURE__ */ React4.createElement(Message.Title, null, /* @__PURE__ */ React4.createElement(Warning, {
492
- weight: "duotone",
493
- className: "inline mie-2 is-6 bs-6"
494
- }), /* @__PURE__ */ React4.createElement("span", null, t("warning title"))), /* @__PURE__ */ React4.createElement(Message.Body, null, t("technology preview message"), /* @__PURE__ */ React4.createElement("br", null), /* @__PURE__ */ React4.createElement(Link, {
495
- href: previewUrl,
496
- target: "_blank",
497
- rel: "noreferrer",
498
- variant: "neutral"
499
- }, t("learn more label"), /* @__PURE__ */ React4.createElement(ArrowSquareOut, {
500
- className: "inline mis-1",
501
- weight: "bold"
502
- })))), /* @__PURE__ */ React4.createElement("div", {
503
- role: "none",
504
- className: "plb-4 pli-5 space-b-2 text-baseText"
505
- }, timestamp && /* @__PURE__ */ React4.createElement("p", null, t("released message", {
506
- released: formatDistance(new Date(timestamp), /* @__PURE__ */ new Date(), {
507
- addSuffix: true
508
- })
509
- }), /* @__PURE__ */ React4.createElement("br", null), /* @__PURE__ */ React4.createElement(Link, {
510
- href: releaseUrl,
511
- target: "_blank",
512
- rel: "noreferrer",
513
- variant: "neutral"
514
- }, t("see release label"), /* @__PURE__ */ React4.createElement(ArrowSquareOut, {
515
- className: "inline mis-1",
516
- weight: "bold"
517
- }))), /* @__PURE__ */ React4.createElement("p", null, /* @__PURE__ */ React4.createElement(Trans, {
518
- t,
519
- i18nKey: "powered by dxos message",
520
- components: {
521
- dxos: /* @__PURE__ */ React4.createElement(Link, {
522
- href: "https://dxos.org",
523
- target: "_blank",
524
- rel: "noreferrer",
525
- variant: "neutral"
526
- })
527
- }
528
- }))), /* @__PURE__ */ React4.createElement(Popover2.Arrow, null)))), /* @__PURE__ */ React4.createElement(Tooltip2.Root, null, /* @__PURE__ */ React4.createElement(Tooltip2.Trigger, {
529
- asChild: true
530
- }, /* @__PURE__ */ React4.createElement(Button3, {
531
- variant: "ghost",
532
- classNames: buttonStyles,
533
- "data-testid": "treeView.openSettings",
534
- "data-joyride": "welcome/settings",
535
- ...!navigationSidebarOpen && {
536
- tabIndex: -1
537
- },
538
- onClick: () => dispatch(createIntent2(SettingsAction.Open))
539
- }, /* @__PURE__ */ React4.createElement("span", {
540
- className: "sr-only"
541
- }, t("open settings label")), /* @__PURE__ */ React4.createElement(GearSix, {
542
- className: mx3(getSize(5), "rotate-90")
543
- }))), /* @__PURE__ */ React4.createElement(Tooltip2.Portal, null, /* @__PURE__ */ React4.createElement(Tooltip2.Content, {
544
- classNames: "z-[12]"
545
- }, t("open settings label"), /* @__PURE__ */ React4.createElement(Tooltip2.Arrow, null)))), navigationPlugin?.meta.id === "dxos.org/plugin/deck" && /* @__PURE__ */ React4.createElement(LayoutControls, {
546
- variant: "hide-disabled",
547
- capabilities: {
548
- incrementStart: false,
549
- incrementEnd: false
550
- },
551
- onClick: (_type) => {
552
- }
553
- }));
554
- };
555
-
556
- // packages/plugins/plugin-navtree/src/util.ts
557
- import { ACTION_TYPE, ACTION_GROUP_TYPE, isAction as isAction3 } from "@dxos/app-graph";
558
- import { nonNullable } from "@dxos/util";
559
- var getParent = (graph, node, path) => {
560
- const parentId = path[path.length - 2];
561
- return graph.nodes(node, {
562
- relation: "inbound"
563
- }).find((n) => n.id === parentId);
564
- };
565
- var getPersistenceParent = (graph, node, path, persistenceClass) => {
566
- if (node.properties.acceptPersistenceClass?.has(persistenceClass)) {
567
- return node;
568
- } else {
569
- const parent = getParent(graph, node, path);
570
- return parent ? getPersistenceParent(graph, parent, path.slice(0, path.length - 1), persistenceClass) : null;
571
- }
572
- };
573
- var resolveMigrationOperation = (graph, activeNode, destinationPath, destinationRelatedNode) => {
574
- const activeClass = activeNode.properties.persistenceClass;
575
- if (destinationRelatedNode && activeClass) {
576
- const persistenceParent = getPersistenceParent(graph, destinationRelatedNode, destinationPath, activeClass);
577
- if (persistenceParent) {
578
- const activeKey = activeNode.properties.persistenceKey;
579
- if (activeKey && persistenceParent?.properties.acceptPersistenceKey) {
580
- return persistenceParent.properties.acceptPersistenceKey.has(activeKey) && persistenceParent.properties.onTransferStart ? "transfer" : persistenceParent.properties.onCopy ? "copy" : "reject";
581
- } else {
582
- return "reject";
583
- }
584
- } else {
585
- return "reject";
586
- }
587
- } else {
588
- return "reject";
589
- }
590
- };
591
- var sortActions = (actions) => actions.sort((a, b) => {
592
- if (a.properties.disposition === b.properties.disposition) {
593
- return 0;
594
- }
595
- if (a.properties.disposition === "toolbar") {
596
- return -1;
597
- }
598
- return 1;
599
- });
600
- var getChildren = (graph, node, filter, path = []) => {
601
- return graph.nodes(node, {
602
- relation: "outbound",
603
- filter
604
- }).map((n) => {
605
- const nextPath = [
606
- ...path,
607
- node.id
608
- ];
609
- return nextPath.includes(n.id) ? void 0 : n;
610
- }).filter(nonNullable);
611
- };
612
- var getActions = (graph, node) => {
613
- return graph.actions(node).reduce((acc, arg) => {
614
- if (arg.properties.disposition === "item") {
615
- return acc;
616
- }
617
- acc.actions.push(arg);
618
- if (!isAction3(arg)) {
619
- const actionGroup = graph.actions(arg);
620
- acc.groupedActions[arg.id] = actionGroup;
621
- }
622
- return acc;
623
- }, {
624
- actions: [],
625
- groupedActions: {}
626
- });
627
- };
628
- var expandChildrenAndActions = (graph, node) => {
629
- return Promise.all([
630
- expandChildren(graph, node),
631
- expandActions(graph, node)
632
- ]);
633
- };
634
- var expandChildren = (graph, node) => {
635
- return graph.expand(node, "outbound");
636
- };
637
- var expandActions = (graph, node) => {
638
- return Promise.all([
639
- graph.expand(node, "outbound", ACTION_TYPE),
640
- graph.expand(node, "outbound", ACTION_GROUP_TYPE)
641
- ]);
642
- };
643
-
644
- // packages/plugins/plugin-navtree/src/components/NavTreeContainer.tsx
645
- var NODE_TYPE = "dxos/app-graph/node";
646
- var renderItemEnd = ({ node, open }) => /* @__PURE__ */ React5.createElement(Surface, {
647
- role: "navtree-item-end",
648
- data: {
649
- id: node.id,
650
- subject: node.data,
651
- open
652
- },
653
- limit: 1
654
- });
655
- var NavTreeContainer = /* @__PURE__ */ memo(({ isCurrent, popoverAnchorId, ...props }) => {
656
- const { closeNavigationSidebar } = useSidebars2(NAVTREE_PLUGIN);
657
- const [isLg] = useMediaQuery("lg", {
658
- ssr: false
659
- });
660
- const { dispatchPromise: dispatch } = useIntentDispatcher3();
661
- const { graph } = useGraph2();
662
- const getActions2 = useCallback2((node) => getActions(graph, node), [
663
- graph
664
- ]);
665
- const getItems = useCallback2((node) => {
666
- return graph.nodes(node ?? graph.root, {
667
- filter: (node2) => {
668
- return untracked(() => {
669
- const action = isActionLike(node2);
670
- const disposition = node2.properties.disposition;
671
- return !action || action && disposition === "item";
672
- });
673
- }
674
- });
675
- }, [
676
- graph
677
- ]);
678
- const getProps = useCallback2((node, path) => {
679
- const children = getChildren(graph, node, void 0, path);
680
- const parentOf = children.length > 0 ? children.map(({ id }) => id) : node.properties.role === "branch" ? [] : void 0;
681
- return {
682
- id: node.id,
683
- label: node.properties.label ?? node.id,
684
- parentOf,
685
- icon: node.properties.icon,
686
- disabled: node.properties.disabled,
687
- className: mx4(node.properties.modified && "italic", node.properties.className),
688
- headingClassName: node.properties.headingClassName,
689
- testId: node.properties.testId
690
- };
691
- }, [
692
- graph
693
- ]);
694
- const loadDescendents = useCallback2((node) => {
695
- void expandActions(graph, node);
696
- if (!isActionLike(node)) {
697
- void expandChildren(graph, node).then(() => (
698
- // Load one level deeper, which resolves some juddering observed on open/close.
699
- Promise.all(getChildren(graph, node).flatMap((child) => [
700
- expandActions(graph, child),
701
- expandChildren(graph, child)
702
- ]))
703
- ));
704
- }
705
- }, [
706
- graph
707
- ]);
708
- const canDrop = useCallback2((source, target) => {
709
- const sourceNode = source.item;
710
- const targetNode = target.item;
711
- if (isSpace(targetNode.data)) {
712
- return isEchoObject(sourceNode.data) || isSpace(sourceNode.data);
713
- } else if (isEchoObject(targetNode.data)) {
714
- return isEchoObject(sourceNode.data);
715
- } else {
716
- return false;
717
- }
718
- }, []);
719
- const handleSelect = useCallback2(({ item: node, path, option }) => {
720
- if (!node.data) {
721
- return;
722
- }
723
- if (isAction4(node)) {
724
- const [parent] = graph.nodes(node, {
725
- relation: "inbound"
726
- });
727
- void (parent && node.data({
728
- node: parent,
729
- caller: NAV_TREE_ITEM
730
- }));
731
- return;
732
- }
733
- const current = isCurrent(path, node);
734
- if (!current) {
735
- void dispatch(createIntent3(NavigationAction.Open, {
736
- activeParts: {
737
- main: [
738
- node.id
739
- ]
740
- }
741
- }));
742
- } else if (option) {
743
- void dispatch(createIntent3(NavigationAction.Close, {
744
- activeParts: {
745
- main: [
746
- node.id
747
- ]
748
- }
749
- }));
750
- } else {
751
- void dispatch(createIntent3(LayoutAction2.ScrollIntoView, {
752
- id: node.id
753
- }));
754
- }
755
- const defaultAction = graph.actions(node).find((action) => action.properties?.disposition === "default");
756
- if (isAction4(defaultAction)) {
757
- void defaultAction.data();
758
- }
759
- if (!isLg) {
760
- closeNavigationSidebar();
761
- }
762
- }, [
763
- graph,
764
- dispatch,
765
- isCurrent,
766
- isLg,
767
- closeNavigationSidebar
768
- ]);
769
- useEffect2(() => {
770
- return monitorForElements({
771
- canMonitor: ({ source }) => isTreeData(source.data),
772
- onDrop: ({ location, source }) => {
773
- if (!location.current.dropTargets.length) {
774
- return;
775
- }
776
- const target = location.current.dropTargets[0];
777
- const instruction = extractInstruction(target.data);
778
- if (instruction !== null && instruction.type !== "instruction-blocked") {
779
- const sourceNode = source.data.item;
780
- const targetNode = target.data.item;
781
- const sourcePath = source.data.path;
782
- const targetPath = target.data.path;
783
- const operation = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== "make-child" ? "rearrange" : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
784
- const sourceParent = getParent(graph, sourceNode, sourcePath);
785
- const targetParent = getParent(graph, targetNode, targetPath);
786
- const sourceItems = getItems(sourceParent);
787
- const targetItems = getItems(targetParent);
788
- const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
789
- const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
790
- const migrationIndex = instruction.type === "make-child" ? void 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
791
- switch (operation) {
792
- case "rearrange": {
793
- const nextItems = sourceItems.map(({ data }) => data);
794
- arrayMove(nextItems, sourceIndex, targetIndex);
795
- void sourceParent?.properties.onRearrangeChildren?.(nextItems);
796
- break;
797
- }
798
- case "copy": {
799
- const target2 = instruction.type === "make-child" ? targetNode : targetParent;
800
- void target2?.properties.onCopy?.(sourceNode, migrationIndex);
801
- break;
802
- }
803
- case "transfer": {
804
- const target2 = instruction.type === "make-child" ? targetNode : targetParent;
805
- if (!target2?.properties.onTransferStart || !sourceParent?.properties.onTransferEnd) {
806
- break;
807
- }
808
- void target2?.properties.onTransferStart(sourceNode, migrationIndex);
809
- void sourceParent?.properties.onTransferEnd?.(sourceNode, target2);
810
- break;
811
- }
812
- }
813
- }
814
- }
815
- });
816
- }, [
817
- graph
818
- ]);
819
- return /* @__PURE__ */ React5.createElement("div", {
820
- role: "none",
821
- className: "grid grid-cols-1 grid-rows-[var(--rail-size)_1fr_min-content] bs-full overflow-hidden"
822
- }, /* @__PURE__ */ React5.createElement("div", {
823
- role: "none",
824
- className: "border-be border-separator"
825
- }, /* @__PURE__ */ React5.createElement(Surface, {
826
- role: "search-input",
827
- limit: 1
828
- })), /* @__PURE__ */ React5.createElement("div", {
829
- role: "none",
830
- className: "border-be border-separator !overflow-y-auto"
831
- }, /* @__PURE__ */ React5.createElement(NavTree, {
832
- id: graph.root.id,
833
- getActions: getActions2,
834
- getItems,
835
- getProps,
836
- isCurrent,
837
- loadDescendents,
838
- renderItemEnd,
839
- popoverAnchorId,
840
- canDrop,
841
- onSelect: handleSelect,
842
- ...props
843
- })), /* @__PURE__ */ React5.createElement(NavTreeFooter, null));
844
- });
845
-
846
- // packages/plugins/plugin-navtree/src/components/NavTreeDocumentTitle.tsx
847
- import { useEffect as useEffect3 } from "react";
848
- import { toLocalizedString as toLocalizedString4, useTranslation as useTranslation5 } from "@dxos/react-ui";
849
- var NavTreeDocumentTitle = ({ node }) => {
850
- const { t } = useTranslation5(NAVTREE_PLUGIN);
851
- useEffect3(() => {
852
- document.title = node ? toLocalizedString4(node.properties.label, t) : t("current app name", {
853
- ns: "appkit"
854
- });
855
- }, [
856
- node?.properties?.label
857
- ]);
858
- return null;
859
- };
860
-
861
- // packages/plugins/plugin-navtree/src/components/NotchStart.tsx
862
- import React7 from "react";
863
- import { createIntent as createIntent4, useIntentDispatcher as useIntentDispatcher4, useResolvePlugin as useResolvePlugin2 } from "@dxos/app-framework";
864
- import { ClientAction } from "@dxos/plugin-client/types";
865
- import { parseObservabilityPlugin } from "@dxos/plugin-observability";
866
- import { useIdentity } from "@dxos/react-client/halo";
867
-
868
- // packages/plugins/plugin-navtree/src/components/HaloButton.tsx
869
- import React6 from "react";
870
- import { ConnectionState, useNetworkStatus } from "@dxos/react-client/mesh";
871
- import { Avatar } from "@dxos/react-ui";
872
- import { focusRing, mx as mx5 } from "@dxos/react-ui-theme";
873
- import { hexToFallback } from "@dxos/util";
874
- var INTERNAL = "https://avatars.githubusercontent.com/u/57182821";
875
- var HaloButton = (props) => {
876
- const { onClick, identityKey, internal, size = 8 } = props;
877
- const fallbackValue = hexToFallback(identityKey ?? "0");
878
- const { swarm: connectionState } = useNetworkStatus();
879
- return /* @__PURE__ */ React6.createElement("button", {
880
- className: mx5(focusRing, "rounded grid place-items-center"),
881
- onClick
882
- }, /* @__PURE__ */ React6.createElement(Avatar.Root, {
883
- size,
884
- variant: "circle",
885
- status: connectionState === ConnectionState.OFFLINE ? "error" : internal ? "internal" : "active",
886
- hue: props.hue || fallbackValue.hue
887
- }, /* @__PURE__ */ React6.createElement(Avatar.Frame, {
888
- "data-testid": "treeView.haloButton",
889
- "data-joyride": "welcome/halo"
890
- }, internal ? /* @__PURE__ */ React6.createElement(Avatar.Image, {
891
- href: INTERNAL
892
- }) : /* @__PURE__ */ React6.createElement(Avatar.Fallback, {
893
- text: props.emoji || fallbackValue.emoji
894
- }))));
895
- };
896
-
897
- // packages/plugins/plugin-navtree/src/components/NotchStart.tsx
898
- var NotchStart = () => {
899
- const identity = useIdentity();
900
- const observabilityPlugin = useResolvePlugin2(parseObservabilityPlugin);
901
- const { dispatchPromise: dispatch } = useIntentDispatcher4();
902
- return /* @__PURE__ */ React7.createElement(HaloButton, {
903
- size: 8,
904
- identityKey: identity?.identityKey.toHex(),
905
- hue: identity?.profile?.data?.hue,
906
- emoji: identity?.profile?.data?.emoji,
907
- internal: observabilityPlugin?.provides?.observability?.group === "dxos",
908
- onClick: () => dispatch(createIntent4(ClientAction.ShareIdentity))
909
- });
910
- };
911
-
912
- // packages/plugins/plugin-navtree/src/components/CommandsTrigger.tsx
913
- import { MagnifyingGlass } from "@phosphor-icons/react";
914
- import React8 from "react";
915
- import { createIntent as createIntent5, LayoutAction as LayoutAction3, useIntentDispatcher as useIntentDispatcher5 } from "@dxos/app-framework";
916
- import { Button as Button4, useTranslation as useTranslation6 } from "@dxos/react-ui";
917
- import { getSize as getSize2 } from "@dxos/react-ui-theme";
918
- var CommandsTrigger = () => {
919
- const { dispatchPromise: dispatch } = useIntentDispatcher5();
920
- const { t } = useTranslation6(NAVTREE_PLUGIN);
921
- return /* @__PURE__ */ React8.createElement(Button4, {
922
- classNames: "w-full h-full !rounded-none",
923
- onClick: () => dispatch(createIntent5(LayoutAction3.SetLayout, {
924
- element: "dialog",
925
- component: COMMANDS_DIALOG,
926
- dialogBlockAlign: "start"
927
- }))
928
- }, /* @__PURE__ */ React8.createElement("span", {
929
- className: "text-description font-normal grow text-start"
930
- }, t("command list input placeholder")), /* @__PURE__ */ React8.createElement(MagnifyingGlass, {
931
- className: getSize2(5)
932
- }));
933
- };
37
+ // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
38
+ import { definePlugin, defineModule, Events as Events2, contributes, Capabilities, allOf, createIntent, LayoutAction } from "@dxos/app-framework";
934
39
 
935
40
  // packages/plugins/plugin-navtree/src/translations.ts
936
41
  var translations_default = [
@@ -942,14 +47,7 @@ var translations_default = [
942
47
  "commands dialog title": "Commands",
943
48
  "command list input placeholder": "Search for commands\u2026",
944
49
  "node actions menu invoker label": "More options",
945
- "warning title": "WARNING",
946
- "technology preview message": "Composer is still in technology preview.",
947
- "learn more label": "Learn more",
948
- "released message": "This version released {{released}}.",
949
- "see release label": "See release on GitHub",
950
- "powered by dxos message": "Powered by <dxos>DXOS</dxos>",
951
50
  "tree item actions label": "More actions",
952
- "tree item searchlist input placeholder": "Search for actions\u2026",
953
51
  "empty branch message": "\xA0"
954
52
  }
955
53
  }
@@ -957,284 +55,95 @@ var translations_default = [
957
55
  ];
958
56
 
959
57
  // packages/plugins/plugin-navtree/src/NavTreePlugin.tsx
960
- var KEY = `${NAVTREE_PLUGIN}/state`;
961
- var getInitialState = () => {
962
- const stringified = localStorage.getItem(KEY);
963
- if (!stringified) {
964
- return;
965
- }
966
- try {
967
- const cached = JSON.parse(stringified);
968
- return cached.map(([key, value]) => [
969
- key,
970
- create({
971
- open: value.open,
972
- current: false
973
- })
974
- ]);
975
- } catch {
976
- }
977
- };
978
- var NavTreePlugin = () => {
979
- let graphPlugin;
980
- let graph;
981
- let unsubscribe;
982
- const state = new Map(getInitialState() ?? [
983
- // TODO(thure): Initialize these dynamically.
984
- [
985
- "root",
986
- create({
987
- open: true,
988
- current: false
989
- })
58
+ var NavTreePlugin = () => definePlugin(meta, [
59
+ defineModule({
60
+ id: `${meta.id}/module/state`,
61
+ activatesOn: Events2.LayoutReady,
62
+ activatesAfter: [
63
+ NavTreeEvents.StateReady
990
64
  ],
991
- [
992
- "root~dxos.org/plugin/space-spaces",
993
- create({
994
- open: true,
995
- current: false
996
- })
997
- ],
998
- [
999
- "root~dxos.org/plugin/files",
1000
- create({
1001
- open: true,
1002
- current: false
1003
- })
1004
- ]
1005
- ]);
1006
- const getItem = (_path) => {
1007
- const path = Path.create(..._path);
1008
- const value = state.get(path) ?? create({
1009
- open: false,
1010
- current: false
1011
- });
1012
- if (!state.has(path)) {
1013
- state.set(path, value);
1014
- }
1015
- return value;
1016
- };
1017
- const setItem = (path, key, next) => {
1018
- const value = getItem(path);
1019
- value[key] = next;
1020
- localStorage.setItem(KEY, JSON.stringify(Array.from(state.entries())));
1021
- };
1022
- const isOpen = (path) => getItem(path).open;
1023
- const isCurrent = (path) => getItem(path).current;
1024
- const handleOpenChange = ({ item: { id }, path, open }) => {
1025
- setItem(path, "open", open);
1026
- if (graph) {
1027
- const node = graph.findNode(id);
1028
- return node && expandChildrenAndActions(graph, node);
1029
- }
1030
- };
1031
- return {
1032
- meta: meta_default,
1033
- ready: async ({ plugins }) => {
1034
- const layout = resolvePlugin(plugins, parseLayoutPlugin)?.provides.layout;
1035
- const location = resolvePlugin(plugins, parseNavigationPlugin2)?.provides.location;
1036
- graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
1037
- graph = graphPlugin?.provides.graph;
1038
- if (!graph || !location || !layout) {
1039
- return;
1040
- }
1041
- const soloPart = location?.active.solo?.[0];
1042
- const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatchPromise;
1043
- if (dispatch && soloPart) {
1044
- void dispatch(createIntent6(NavigationAction2.Expose, {
1045
- id: soloPart.id
1046
- }));
1047
- }
1048
- let previous = [];
1049
- unsubscribe = effect(() => {
1050
- const part = layout.layoutMode === "solo" ? "solo" : "main";
1051
- const current = location.active[part]?.map(({ id }) => id) ?? [];
1052
- const removed = previous.filter((id) => !current.includes(id));
1053
- previous = current;
1054
- setTimeout(() => {
1055
- removed.forEach((id) => {
1056
- const keys = Array.from(state.keys()).filter((key) => Path.last(key) === id);
1057
- keys.forEach((key) => {
1058
- setItem(Path.parts(key), "current", false);
1059
- });
1060
- });
1061
- current.forEach((id) => {
1062
- const keys = Array.from(/* @__PURE__ */ new Set([
1063
- ...state.keys(),
1064
- id
1065
- ])).filter((key) => Path.last(key) === id);
1066
- keys.forEach((key) => {
1067
- setItem(Path.parts(key), "current", true);
1068
- });
1069
- });
1070
- });
1071
- });
1072
- graph.subscribeTraverse({
1073
- visitor: (node, path) => {
1074
- let shortcut;
1075
- if (typeof node.properties.keyBinding === "object") {
1076
- const availablePlatforms = Object.keys(node.properties.keyBinding);
1077
- const platform = getHostPlatform3();
1078
- shortcut = availablePlatforms.includes(platform) ? node.properties.keyBinding[platform] : platform === "ios" ? node.properties.keyBinding.macos : platform === "linux" || platform === "unknown" ? node.properties.keyBinding.windows : void 0;
1079
- } else {
1080
- shortcut = node.properties.keyBinding;
1081
- }
1082
- if (shortcut && isAction5(node)) {
1083
- Keyboard2.singleton.getContext(path.slice(0, -1).join("/")).bind({
1084
- shortcut,
1085
- handler: () => {
1086
- void node.data({
1087
- node,
1088
- caller: KEY_BINDING
1089
- });
1090
- },
1091
- data: node.properties.label
1092
- });
1093
- }
1094
- }
1095
- });
1096
- Keyboard2.singleton.initialize();
1097
- Keyboard2.singleton.setCurrentContext(graphPlugin?.provides.graph.root.id);
1098
- },
1099
- unload: async () => {
1100
- unsubscribe?.();
1101
- Keyboard2.singleton.destroy();
1102
- },
1103
- provides: {
65
+ activate: State
66
+ }),
67
+ defineModule({
68
+ id: `${meta.id}/module/translations`,
69
+ activatesOn: Events2.SetupTranslations,
70
+ activate: () => contributes(Capabilities.Translations, translations_default)
71
+ }),
72
+ defineModule({
73
+ id: `${meta.id}/module/metadata`,
74
+ activatesOn: Events2.SetupMetadata,
75
+ activate: () => contributes(Capabilities.Metadata, {
76
+ id: NODE_TYPE,
1104
77
  metadata: {
1105
- records: {
1106
- [NODE_TYPE]: {
1107
- parse: ({ item }, type) => {
1108
- switch (type) {
1109
- case "node":
1110
- return item;
1111
- case "object":
1112
- return item.data;
1113
- case "view-object":
1114
- return {
1115
- id: `${item.id}-view`,
1116
- object: item.data
1117
- };
1118
- }
1119
- }
1120
- }
1121
- }
1122
- },
1123
- surface: {
1124
- definitions: () => [
1125
- createSurface({
1126
- id: COMMANDS_DIALOG,
1127
- role: "dialog",
1128
- filter: (data) => data.component === COMMANDS_DIALOG,
1129
- component: ({ data }) => /* @__PURE__ */ React9.createElement(CommandsDialogContent, {
1130
- selected: data.subject
1131
- })
1132
- }),
1133
- createSurface({
1134
- id: `${NAVTREE_PLUGIN}/navigation`,
1135
- role: "navigation",
1136
- component: ({ data }) => /* @__PURE__ */ React9.createElement(NavTreeContainer, {
1137
- isOpen,
1138
- isCurrent,
1139
- onOpenChange: handleOpenChange,
1140
- popoverAnchorId: data.popoverAnchorId
1141
- })
1142
- }),
1143
- createSurface({
1144
- id: `${NAVTREE_PLUGIN}/document-title`,
1145
- role: "document-title",
1146
- component: ({ data }) => /* @__PURE__ */ React9.createElement(NavTreeDocumentTitle, {
1147
- node: isGraphNode(data.subject) ? data.subject : void 0
1148
- })
1149
- }),
1150
- createSurface({
1151
- id: `${NAVTREE_PLUGIN}/notch-start`,
1152
- role: "notch-start",
1153
- component: () => /* @__PURE__ */ React9.createElement(NotchStart, null)
1154
- }),
1155
- createSurface({
1156
- id: `${NAVTREE_PLUGIN}/search-input`,
1157
- role: "search-input",
1158
- disposition: "fallback",
1159
- component: () => /* @__PURE__ */ React9.createElement(CommandsTrigger, null)
1160
- })
1161
- ]
1162
- },
1163
- intent: {
1164
- resolvers: ({ plugins }) => {
1165
- const graph2 = resolvePlugin(plugins, parseGraphPlugin)?.provides.graph;
1166
- if (!graph2) {
1167
- return [];
78
+ parse: ({ item }, type) => {
79
+ switch (type) {
80
+ case "node":
81
+ return item;
82
+ case "object":
83
+ return item.data;
84
+ case "view-object":
85
+ return {
86
+ id: `${item.id}-view`,
87
+ object: item.data
88
+ };
1168
89
  }
1169
- return createResolver(NavigationAction2.Expose, async ({ id }) => {
1170
- const path = await graph2.waitForPath({
1171
- target: id
1172
- });
1173
- [
1174
- ...Array(path.length)
1175
- ].forEach((_, index) => {
1176
- const subpath = path.slice(0, index);
1177
- const value = getItem(subpath);
1178
- if (!value.open) {
1179
- setItem(subpath, "open", true);
1180
- }
1181
- });
1182
- });
1183
90
  }
1184
- },
1185
- graph: {
1186
- builder: (plugins) => {
1187
- const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatchPromise;
1188
- return [
1189
- createExtension({
1190
- id: NAVTREE_PLUGIN,
1191
- filter: (node) => node.id === "root",
1192
- actions: () => [
1193
- {
1194
- id: COMMANDS_DIALOG,
1195
- data: async () => {
1196
- await dispatch?.(createIntent6(LayoutAction4.SetLayout, {
1197
- element: "dialog",
1198
- component: COMMANDS_DIALOG,
1199
- dialogBlockAlign: "start"
1200
- }));
1201
- },
1202
- properties: {
1203
- label: [
1204
- "open commands label",
1205
- {
1206
- ns: NAVTREE_PLUGIN
1207
- }
1208
- ],
1209
- icon: "ph--magnifying-glass--regular",
1210
- keyBinding: {
1211
- macos: "meta+k",
1212
- windows: "ctrl+k"
1213
- }
1214
- }
1215
- }
1216
- ]
1217
- })
1218
- ];
1219
- }
1220
- },
1221
- translations: translations_default
1222
- }
1223
- };
1224
- };
1225
-
1226
- // packages/plugins/plugin-navtree/src/index.ts
1227
- var src_default = NavTreePlugin;
91
+ }
92
+ })
93
+ }),
94
+ defineModule({
95
+ id: `${meta.id}/module/expose`,
96
+ activatesOn: allOf(Events2.DispatcherReady, Events2.LayoutReady, NavTreeEvents.StateReady),
97
+ activate: async (context) => {
98
+ const layout = context.requestCapability(Capabilities.Layout);
99
+ const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
100
+ if (dispatch && layout.active.length === 1) {
101
+ await dispatch(createIntent(LayoutAction.Expose, {
102
+ part: "navigation",
103
+ subject: layout.active[0]
104
+ }));
105
+ }
106
+ return [];
107
+ }
108
+ }),
109
+ defineModule({
110
+ id: `${meta.id}/module/keyboard`,
111
+ activatesOn: Events2.AppGraphReady,
112
+ activate: Keyboard
113
+ }),
114
+ defineModule({
115
+ id: `${meta.id}/module/react-surface`,
116
+ activatesOn: Events2.SetupSurfaces,
117
+ activate: ReactSurface
118
+ }),
119
+ defineModule({
120
+ id: `${meta.id}/module/intent-resolver`,
121
+ activatesOn: Events2.SetupIntents,
122
+ activate: IntentResolver
123
+ }),
124
+ defineModule({
125
+ id: `${meta.id}/module/app-graph-builder`,
126
+ activatesOn: Events2.SetupAppGraph,
127
+ activate: AppGraphBuilder
128
+ })
129
+ ]);
1228
130
  export {
131
+ COMMANDS_DIALOG,
132
+ KEY_BINDING,
133
+ NAVTREE_PLUGIN,
134
+ NavTreeCapabilities,
135
+ NavTreeEvents,
1229
136
  NavTreePlugin,
1230
- src_default as default,
1231
137
  expandActions,
1232
138
  expandChildren,
1233
139
  expandChildrenAndActions,
1234
140
  getActions,
1235
141
  getChildren,
142
+ getFirstTwoRenderableChars,
1236
143
  getParent,
1237
144
  getPersistenceParent,
145
+ l0ItemType,
146
+ meta,
1238
147
  resolveMigrationOperation,
1239
148
  sortActions
1240
149
  };