@dxos/react-ui-menu 0.8.4-main.c1de068 → 0.8.4-main.c85a9c8dae

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 (59) hide show
  1. package/dist/lib/browser/index.mjs +556 -390
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +556 -390
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/builder.d.ts +9 -3
  8. package/dist/types/src/builder.d.ts.map +1 -1
  9. package/dist/types/src/components/ActionLabel.d.ts +3 -3
  10. package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
  11. package/dist/types/src/components/DropdownMenu.d.ts +1 -1
  12. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  13. package/dist/types/src/components/Menu.d.ts +46 -0
  14. package/dist/types/src/components/Menu.d.ts.map +1 -0
  15. package/dist/types/src/components/Menu.test.d.ts +2 -0
  16. package/dist/types/src/components/Menu.test.d.ts.map +1 -0
  17. package/dist/types/src/components/MenuItems.stories.d.ts +21 -0
  18. package/dist/types/src/components/MenuItems.stories.d.ts.map +1 -0
  19. package/dist/types/src/components/ToolbarMenu.d.ts +4 -3
  20. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
  21. package/dist/types/src/components/ToolbarMenu.stories.d.ts +20 -0
  22. package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -0
  23. package/dist/types/src/components/index.d.ts +1 -3
  24. package/dist/types/src/components/index.d.ts.map +1 -1
  25. package/dist/types/src/hooks/useMenuActions.d.ts +8 -7
  26. package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
  27. package/dist/types/src/index.d.ts +0 -1
  28. package/dist/types/src/index.d.ts.map +1 -1
  29. package/dist/types/src/testing/generator.d.ts +14 -12
  30. package/dist/types/src/testing/generator.d.ts.map +1 -1
  31. package/dist/types/src/translations.d.ts +2 -2
  32. package/dist/types/src/translations.d.ts.map +1 -1
  33. package/dist/types/src/types.d.ts +36 -26
  34. package/dist/types/src/types.d.ts.map +1 -1
  35. package/dist/types/src/util.d.ts +14 -5
  36. package/dist/types/src/util.d.ts.map +1 -1
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +36 -29
  39. package/src/builder.ts +45 -18
  40. package/src/components/ActionLabel.tsx +6 -6
  41. package/src/components/DropdownMenu.tsx +15 -7
  42. package/src/components/Menu.test.tsx +448 -0
  43. package/src/components/Menu.tsx +349 -0
  44. package/src/components/MenuItems.stories.tsx +265 -0
  45. package/src/components/ToolbarMenu.stories.tsx +80 -0
  46. package/src/components/ToolbarMenu.tsx +72 -37
  47. package/src/components/index.ts +1 -3
  48. package/src/hooks/useMenuActions.ts +31 -53
  49. package/src/index.ts +0 -2
  50. package/src/testing/generator.ts +67 -62
  51. package/src/translations.ts +1 -1
  52. package/src/types.ts +38 -27
  53. package/src/util.ts +34 -15
  54. package/dist/types/src/components/MenuContext.d.ts +0 -13
  55. package/dist/types/src/components/MenuContext.d.ts.map +0 -1
  56. package/dist/types/src/components/Menus.stories.d.ts +0 -25
  57. package/dist/types/src/components/Menus.stories.d.ts.map +0 -1
  58. package/src/components/MenuContext.tsx +0 -50
  59. package/src/components/Menus.stories.tsx +0 -69
@@ -1,48 +1,39 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
 
3
- // src/index.ts
4
- import { rxFromSignal } from "@dxos/app-graph";
5
-
6
- // src/components/DropdownMenu.tsx
7
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
8
- import { useControllableState } from "@radix-ui/react-use-controllable-state";
9
- import React3, { useCallback } from "react";
10
- import { DropdownMenu as NaturalDropdownMenu, Icon } from "@dxos/react-ui";
11
-
12
- // src/components/ActionLabel.tsx
13
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
14
- import React from "react";
15
- import { keySymbols } from "@dxos/keyboard";
16
- import { toLocalizedString, useTranslation } from "@dxos/react-ui";
17
- import { mx, descriptionText } from "@dxos/react-ui-theme";
18
-
19
- // src/translations.ts
20
- var translationKey = "react-ui-menu";
21
- var translations = [
22
- {
23
- "en-US": {
24
- [translationKey]: {}
25
- }
26
- }
27
- ];
3
+ // src/components/Menu.tsx
4
+ import { Atom, RegistryContext, useAtomValue } from "@effect-atom/atom-react";
5
+ import { createContextScope } from "@radix-ui/react-context";
6
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
7
+ import React4, { useCallback as useCallback3, useContext, useMemo } from "react";
8
+ import { log } from "@dxos/log";
9
+ import { Icon as Icon3, DropdownMenu as NaturalDropdownMenu2 } from "@dxos/react-ui";
28
10
 
29
11
  // src/util.ts
30
- import { ACTION_GROUP_TYPE, ACTION_TYPE, actionGroupSymbol } from "@dxos/app-graph";
12
+ import * as Effect from "effect/Effect";
13
+ import { Node } from "@dxos/app-graph";
14
+ import { runAndForwardErrors } from "@dxos/effect";
31
15
  import { getHostPlatform } from "@dxos/util";
16
+ var executeMenuAction = async (action, params = {}) => {
17
+ let effect = action.data(params);
18
+ if (action._actionContext) {
19
+ effect = effect.pipe(Effect.provide(action._actionContext));
20
+ }
21
+ await runAndForwardErrors(effect);
22
+ };
32
23
  var getShortcut = (action) => {
33
24
  return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
34
25
  };
35
26
  var createMenuAction = (id, invoke, properties) => ({
36
27
  id,
37
- type: ACTION_TYPE,
28
+ type: Node.ActionType,
38
29
  properties,
39
- data: invoke
30
+ data: () => Effect.sync(invoke)
40
31
  });
41
32
  var createMenuItemGroup = (id, properties) => ({
42
33
  id,
43
- type: ACTION_GROUP_TYPE,
34
+ type: Node.ActionGroupType,
44
35
  properties,
45
- data: actionGroupSymbol
36
+ data: Node.actionGroupSymbol
46
37
  });
47
38
  var createGapSeparator = (id = "gap", source = "root") => ({
48
39
  nodes: [
@@ -58,7 +49,8 @@ var createGapSeparator = (id = "gap", source = "root") => ({
58
49
  edges: [
59
50
  {
60
51
  source,
61
- target: id
52
+ target: id,
53
+ relation: "child"
62
54
  }
63
55
  ]
64
56
  });
@@ -76,128 +68,119 @@ var createLineSeparator = (id = "line", source = "root") => ({
76
68
  edges: [
77
69
  {
78
70
  source,
79
- target: id
71
+ target: id,
72
+ relation: "child"
80
73
  }
81
74
  ]
82
75
  });
83
76
 
84
77
  // src/components/ActionLabel.tsx
85
- var ActionLabel = ({ action }) => {
86
- var _effect = _useSignals();
87
- try {
88
- const { t } = useTranslation(translationKey);
89
- const shortcut = getShortcut(action);
90
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
91
- className: "grow truncate"
92
- }, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
93
- className: mx("shrink-0", descriptionText)
94
- }, keySymbols(shortcut).join("")));
95
- } finally {
96
- _effect.f();
78
+ import React from "react";
79
+ import { keySymbols } from "@dxos/keyboard";
80
+ import { toLocalizedString, useTranslation } from "@dxos/react-ui";
81
+ import { mx } from "@dxos/ui-theme";
82
+
83
+ // src/translations.ts
84
+ var translationKey = "@dxos/react-ui-menu";
85
+ var translations = [
86
+ {
87
+ "en-US": {
88
+ [translationKey]: {}
89
+ }
97
90
  }
91
+ ];
92
+
93
+ // src/components/ActionLabel.tsx
94
+ var ActionLabel = ({ action }) => {
95
+ const { t } = useTranslation(translationKey);
96
+ const shortcut = getShortcut(action);
97
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
98
+ className: "grow truncate"
99
+ }, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
100
+ className: mx("shrink-0", "text-description")
101
+ }, keySymbols(shortcut).join("")));
98
102
  };
99
103
  var actionLabel = (action, t) => {
100
104
  const shortcut = getShortcut(action);
101
105
  return `${toLocalizedString(action.properties.label, t)}${shortcut ? ` (${keySymbols(shortcut).join("")})` : ""}`;
102
106
  };
103
107
 
104
- // src/components/MenuContext.tsx
105
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
106
- import { createContextScope } from "@radix-ui/react-context";
107
- import React2, { useMemo } from "react";
108
- var MENU_NAME = "GraphMenu";
109
- var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
110
- var [MenuContextProvider, useMenu] = createMenuContext(MENU_NAME);
111
- var menuContextDefaults = {
112
- iconSize: 5,
113
- useGroupItems: () => null
114
- };
115
- var useMenuScope = createMenuScope();
116
- var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
117
- var _effect = _useSignals2();
118
- try {
119
- const { scope } = useMenuScope(void 0);
120
- return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
121
- useGroupItems,
122
- iconSize,
123
- attendableId,
124
- scope
125
- }, children);
126
- } finally {
127
- _effect.f();
128
- }
129
- };
130
- var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
131
- const { useGroupItems } = useMenu(consumerName, __menuScope);
132
- const groupItems = useGroupItems(group);
133
- return useMemo(() => propsItems ?? groupItems ?? void 0, [
134
- propsItems,
135
- groupItems
136
- ]);
137
- };
108
+ // src/components/ToolbarMenu.tsx
109
+ import React3, { Fragment, useCallback as useCallback2 } from "react";
110
+ import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
111
+ import { useAttention } from "@dxos/react-ui-attention";
112
+ import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/ui-theme";
113
+
114
+ // src/types.ts
115
+ import { Node as Node2 } from "@dxos/app-graph";
116
+ var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
117
+ var isSeparator = (node) => node.type === MenuSeparatorType;
118
+ var isMenuGroup = (node) => node.type === Node2.ActionGroupType;
138
119
 
139
120
  // src/components/DropdownMenu.tsx
121
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
122
+ import React2, { useCallback } from "react";
123
+ import { Icon, DropdownMenu as NaturalDropdownMenu } from "@dxos/react-ui";
140
124
  var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
141
- var _effect = _useSignals3();
142
- try {
143
- const action = item;
144
- const handleClick = useCallback((event) => onClick(action, event), [
145
- action,
146
- onClick
147
- ]);
148
- const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
149
- return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Item, {
150
- onClick: handleClick,
151
- classNames: "gap-2",
152
- disabled: action.properties?.disabled,
153
- ...action.properties?.testId && {
154
- "data-testid": action.properties.testId
155
- }
156
- }, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon, {
157
- icon: action.properties.icon,
158
- size: iconSize
159
- }), /* @__PURE__ */ React3.createElement(ActionLabel, {
160
- action
161
- }));
162
- } finally {
163
- _effect.f();
164
- }
125
+ const action = item;
126
+ const handleClick = useCallback((event) => onClick(action, event), [
127
+ action,
128
+ onClick
129
+ ]);
130
+ const { iconSize } = useMenuScoped("DropdownMenuItem", __menuScope);
131
+ return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Item, {
132
+ onClick: handleClick,
133
+ classNames: "gap-2",
134
+ disabled: action.properties?.disabled,
135
+ ...action.properties?.testId && {
136
+ "data-testid": action.properties.testId
137
+ }
138
+ }, action.properties?.icon && /* @__PURE__ */ React2.createElement(Icon, {
139
+ icon: action.properties.icon,
140
+ size: iconSize
141
+ }), /* @__PURE__ */ React2.createElement(ActionLabel, {
142
+ action
143
+ }));
165
144
  };
166
145
  var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, caller, children, __menuScope, ...naturalProps }) => {
167
- var _effect = _useSignals3();
168
- try {
169
- const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
170
- prop: open,
171
- defaultProp: defaultOpen,
172
- onChange: onOpenChange
173
- });
174
- const handleActionClick = useCallback((action, event) => {
175
- if (action.properties?.disabled) {
176
- return;
177
- }
178
- event.stopPropagation();
179
- setOptionsMenuOpen(false);
180
- void action.data?.({
146
+ const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
147
+ prop: open,
148
+ defaultProp: defaultOpen,
149
+ onChange: onOpenChange
150
+ });
151
+ const { onAction } = useMenuScoped("DropdownMenuRoot", __menuScope);
152
+ const handleActionClick = useCallback((action, event) => {
153
+ if (action.properties?.disabled) {
154
+ return;
155
+ }
156
+ event.stopPropagation();
157
+ setOptionsMenuOpen(false);
158
+ if (onAction) {
159
+ onAction(action, {
181
160
  parent: group,
182
161
  caller
183
162
  });
184
- }, [
185
- group,
186
- caller
187
- ]);
188
- const items = useMenuItems(group, propsItems);
189
- return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
190
- open: optionsMenuOpen,
191
- onOpenChange: setOptionsMenuOpen,
192
- ...naturalProps
193
- }, children, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React3.createElement(DropdownMenuItem, {
194
- key: item.id,
195
- item,
196
- onClick: handleActionClick
197
- }))), /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Arrow, null))));
198
- } finally {
199
- _effect.f();
200
- }
163
+ } else {
164
+ void executeMenuAction(action, {
165
+ parent: group,
166
+ caller
167
+ });
168
+ }
169
+ }, [
170
+ group,
171
+ caller,
172
+ onAction
173
+ ]);
174
+ const items = useMenuItems(group, propsItems);
175
+ return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Root, {
176
+ open: optionsMenuOpen,
177
+ onOpenChange: setOptionsMenuOpen,
178
+ ...naturalProps
179
+ }, children, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React2.createElement(DropdownMenuItem, {
180
+ key: item.id,
181
+ item,
182
+ onClick: handleActionClick
183
+ }))), /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Arrow, null))));
201
184
  };
202
185
  var DropdownMenu = {
203
186
  Root: DropdownMenuRoot,
@@ -205,289 +188,437 @@ var DropdownMenu = {
205
188
  VirtualTrigger: NaturalDropdownMenu.VirtualTrigger
206
189
  };
207
190
 
208
- // src/components/ToolbarMenu.tsx
209
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
210
- import React4, { Fragment, useCallback as useCallback2 } from "react";
211
- import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
212
- import { useAttention } from "@dxos/react-ui-attention";
213
- import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/react-ui-theme";
214
-
215
- // src/types.ts
216
- import { ACTION_GROUP_TYPE as ACTION_GROUP_TYPE2 } from "@dxos/app-graph";
217
- var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
218
- var isSeparator = (node) => node.type === MenuSeparatorType;
219
- var isMenuGroup = (node) => node.type === ACTION_GROUP_TYPE2;
220
-
221
191
  // src/components/ToolbarMenu.tsx
222
192
  var ActionToolbarItem = ({ action, __menuScope }) => {
223
- var _effect = _useSignals4();
224
- try {
225
- const { iconSize } = useMenu("ActionToolbarItem", __menuScope);
226
- const { t } = useTranslation2(translationKey);
227
- const handleClick = useCallback2(() => action.data?.(), [
193
+ const { iconSize, onAction } = useMenuScoped("ActionToolbarItem", __menuScope);
194
+ const { t } = useTranslation2(translationKey);
195
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
196
+ const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
197
+ const rootProps = icon ? {
198
+ icon,
199
+ size: iconSize,
200
+ iconOnly,
201
+ label: actionLabel(action, t)
202
+ } : {
203
+ children: /* @__PURE__ */ React3.createElement(ActionLabel, {
228
204
  action
229
- ]);
230
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
231
- const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
232
- const rootProps = icon ? {
233
- icon,
234
- size: iconSize,
235
- iconOnly,
236
- label: actionLabel(action, t)
237
- } : {
238
- children: /* @__PURE__ */ React4.createElement(ActionLabel, {
239
- action
240
- })
241
- };
242
- return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
243
- key: action.id,
244
- disabled,
245
- onClick: handleClick,
246
- variant: "ghost",
247
- ...testId && {
248
- "data-testid": testId
249
- },
250
- ...rootProps,
251
- classNames
252
- });
253
- } finally {
254
- _effect.f();
255
- }
205
+ })
206
+ };
207
+ const handleClick = useCallback2(() => {
208
+ if (onAction) {
209
+ onAction(action, {});
210
+ } else {
211
+ void executeMenuAction(action);
212
+ }
213
+ }, [
214
+ action,
215
+ onAction
216
+ ]);
217
+ return hidden ? null : /* @__PURE__ */ React3.createElement(Root, {
218
+ key: action.id,
219
+ disabled,
220
+ onClick: handleClick,
221
+ variant: "ghost",
222
+ ...testId && {
223
+ "data-testid": testId
224
+ },
225
+ ...rootProps,
226
+ classNames
227
+ });
256
228
  };
257
229
  var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
258
- var _effect = _useSignals4();
259
- try {
260
- const { iconOnly, disabled, testId } = group.properties;
261
- const { t } = useTranslation2(translationKey);
262
- const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
263
- const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
264
- const activeItem = items?.find((item) => !!item.properties.checked);
265
- const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
266
- activeItem?.properties.icon || group.properties.icon;
267
- const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
268
- const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
269
- const rootProps = icon ? {
270
- icon,
271
- size: iconSize,
272
- iconOnly,
273
- label: actionLabel(labelAction, t),
274
- caretDown: true
275
- } : {
276
- children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(ActionLabel, {
277
- action: labelAction
278
- }), /* @__PURE__ */ React4.createElement(Icon2, {
279
- size: 3,
280
- icon: "ph--caret-down--bold",
281
- classNames: "mis-1"
282
- }))
283
- };
284
- return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
285
- group,
286
- items
287
- }, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
288
- asChild: true
289
- }, /* @__PURE__ */ React4.createElement(Root, {
290
- variant: "ghost",
291
- disabled,
292
- ...rootProps,
293
- ...testId && {
294
- "data-testid": testId
295
- }
296
- })));
297
- } finally {
298
- _effect.f();
299
- }
230
+ const { iconOnly, disabled, testId } = group.properties;
231
+ const { t } = useTranslation2(translationKey);
232
+ const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
233
+ const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
234
+ const activeItem = items?.find((item) => !!item.properties.checked);
235
+ const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
236
+ activeItem?.properties.icon || group.properties.icon;
237
+ const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
238
+ const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
239
+ const rootProps = icon ? {
240
+ icon,
241
+ size: iconSize,
242
+ iconOnly,
243
+ label: actionLabel(labelAction, t),
244
+ caretDown: true
245
+ } : {
246
+ children: /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ActionLabel, {
247
+ action: labelAction
248
+ }), /* @__PURE__ */ React3.createElement(Icon2, {
249
+ size: 3,
250
+ icon: "ph--caret-down--bold",
251
+ classNames: "ms-1"
252
+ }))
253
+ };
254
+ return /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
255
+ group,
256
+ items
257
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
258
+ asChild: true
259
+ }, /* @__PURE__ */ React3.createElement(Root, {
260
+ variant: "ghost",
261
+ disabled,
262
+ ...rootProps,
263
+ ...testId && {
264
+ "data-testid": testId
265
+ }
266
+ })));
300
267
  };
301
268
  var ToggleGroupItem = ({ group, action, __menuScope }) => {
302
- var _effect = _useSignals4();
303
- try {
304
- const { iconSize } = useMenu("ToggleGroupItem", __menuScope);
305
- const { t } = useTranslation2(translationKey);
306
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
307
- const handleClick = useCallback2(() => action.data?.({
308
- parent: group
309
- }), [
310
- action,
311
- group
312
- ]);
313
- const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
314
- const rootProps = icon ? {
315
- icon,
316
- size: iconSize,
317
- iconOnly,
318
- label: actionLabel(action, t)
319
- } : {
320
- children: /* @__PURE__ */ React4.createElement(ActionLabel, {
321
- action
322
- })
323
- };
324
- return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
325
- key: action.id,
326
- value: action.id,
327
- disabled,
328
- onClick: handleClick,
329
- variant: "ghost",
330
- ...testId && {
331
- "data-testid": testId
269
+ const { iconSize, onAction } = useMenuScoped("ToggleGroupItem", __menuScope);
270
+ const { t } = useTranslation2(translationKey);
271
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
272
+ const handleClick = useCallback2(() => {
273
+ if (onAction) {
274
+ onAction(action, {
275
+ parent: group
276
+ });
277
+ } else {
278
+ void executeMenuAction(action, {
279
+ parent: group
280
+ });
281
+ }
282
+ }, [
283
+ action,
284
+ group,
285
+ onAction
286
+ ]);
287
+ const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
288
+ const rootProps = icon ? {
289
+ icon,
290
+ size: iconSize,
291
+ iconOnly,
292
+ label: actionLabel(action, t)
293
+ } : {
294
+ children: /* @__PURE__ */ React3.createElement(ActionLabel, {
295
+ action
296
+ })
297
+ };
298
+ return hidden ? null : /* @__PURE__ */ React3.createElement(Root, {
299
+ key: action.id,
300
+ value: action.id,
301
+ disabled,
302
+ onClick: handleClick,
303
+ variant: "ghost",
304
+ ...testId && {
305
+ "data-testid": testId
306
+ },
307
+ ...rootProps,
308
+ classNames
309
+ });
310
+ };
311
+ var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
312
+ const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
313
+ const { selectCardinality, value } = group.properties;
314
+ return (
315
+ // TODO(thure): Fix.
316
+ // @ts-ignore
317
+ /* @__PURE__ */ React3.createElement(
318
+ NaturalToolbar.ToggleGroup,
319
+ {
320
+ type: selectCardinality,
321
+ value
332
322
  },
333
- ...rootProps,
323
+ // TODO(thure): Handle other menu item types.
324
+ items.map((action) => /* @__PURE__ */ React3.createElement(ToggleGroupItem, {
325
+ key: action.id,
326
+ group,
327
+ action
328
+ }))
329
+ )
330
+ );
331
+ };
332
+ var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp, ...props }) => {
333
+ const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
334
+ const { attendableId, alwaysActive } = useMenuScoped("ToolbarMenu", __menuScope);
335
+ const { hasAttention } = useAttention(attendableId);
336
+ const InnerRoot = textBlockWidthProp ? "div" : Fragment;
337
+ const innerRootProps = textBlockWidthProp ? {
338
+ role: "none",
339
+ className: mx2(textBlockWidth, toolbarLayout, "h-full")
340
+ } : {};
341
+ return /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
342
+ ...props,
343
+ classNames: [
344
+ attendableId,
334
345
  classNames
346
+ ],
347
+ disabled: !alwaysActive && !hasAttention,
348
+ layoutManaged: textBlockWidthProp
349
+ }, /* @__PURE__ */ React3.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React3.createElement(ToolbarMenuItem, {
350
+ key: item.id ?? i,
351
+ item
352
+ }))));
353
+ };
354
+ var ToolbarMenuItem = ({ item }) => {
355
+ if (isSeparator(item)) {
356
+ return /* @__PURE__ */ React3.createElement(NaturalToolbar.Separator, {
357
+ variant: item.properties.variant
335
358
  });
336
- } finally {
337
- _effect.f();
338
359
  }
360
+ if (isMenuGroup(item)) {
361
+ if (item.properties.variant === "dropdownMenu") {
362
+ return /* @__PURE__ */ React3.createElement(DropdownMenuToolbarItem, {
363
+ group: item
364
+ });
365
+ } else {
366
+ return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
367
+ group: item
368
+ });
369
+ }
370
+ }
371
+ return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
372
+ action: item
373
+ });
339
374
  };
340
- var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
341
- var _effect = _useSignals4();
342
- try {
343
- const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
344
- const { selectCardinality, value } = group.properties;
345
- return (
346
- // TODO(thure): The type here is difficult to manage, what do?
347
- // @ts-ignore
348
- /* @__PURE__ */ React4.createElement(
349
- NaturalToolbar.ToggleGroup,
350
- {
351
- type: selectCardinality,
352
- value
353
- },
354
- // TODO(thure): Handle other menu item types.
355
- items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
356
- key: action.id,
357
- group,
358
- action
359
- }))
360
- )
361
- );
362
- } finally {
363
- _effect.f();
375
+
376
+ // src/components/Menu.tsx
377
+ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/components/Menu.tsx";
378
+ var MENU_NAME = "Menu";
379
+ var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
380
+ var nullItemsAtom = Atom.make(null);
381
+ var defaultItemsAccessor = () => nullItemsAtom;
382
+ var menuContextDefaults = {
383
+ iconSize: 5,
384
+ items: defaultItemsAccessor,
385
+ onAction: void 0,
386
+ menuItemsAtom: Atom.make(/* @__PURE__ */ new Map()),
387
+ addMenuItems: () => {
388
+ },
389
+ removeMenuItems: () => {
364
390
  }
365
391
  };
366
- var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: wrapContents, ...props }) => {
367
- var _effect = _useSignals4();
368
- try {
369
- const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
370
- const { attendableId } = useMenu("ToolbarMenu", __menuScope);
371
- const { hasAttention } = useAttention(attendableId);
372
- const InnerRoot = wrapContents ? "div" : Fragment;
373
- const innerRootProps = wrapContents ? {
374
- role: "none",
375
- className: mx2(textBlockWidth, toolbarLayout, "bs-full")
376
- } : {};
377
- return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
392
+ var [MenuContextProvider, useMenuScoped] = createMenuContext(MENU_NAME, menuContextDefaults);
393
+ var useMenuScope = createMenuScope();
394
+ var MenuDropdownContext = /* @__PURE__ */ React4.createContext({
395
+ closeMenu: () => {
396
+ }
397
+ });
398
+ var DEFAULT_PRIORITY = 100;
399
+ var sortMenuItems = (items) => [
400
+ ...items
401
+ ].sort((a, b) => {
402
+ if (a.priority !== b.priority) {
403
+ return a.priority - b.priority;
404
+ }
405
+ return a.id.localeCompare(b.id);
406
+ });
407
+ var MenuProvider = ({ children, items = menuContextDefaults.items, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
408
+ const { scope } = useMenuScope(void 0);
409
+ const registry = useContext(RegistryContext);
410
+ const menuItemsAtom = useMemo(() => Atom.make(/* @__PURE__ */ new Map()).pipe(Atom.keepAlive), []);
411
+ const addMenuItems = useCallback3((props) => {
412
+ const priority = props.priority ?? DEFAULT_PRIORITY;
413
+ const prev = registry.get(menuItemsAtom);
414
+ const next = new Map(prev);
415
+ next.set(props.id, {
378
416
  ...props,
379
- layoutManaged: wrapContents,
380
- classNames: [
381
- attendableId && !hasAttention && "*:opacity-20 !bg-transparent",
382
- classNames
383
- ]
384
- }, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => isSeparator(item) ? /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
385
- key: i,
386
- variant: item.properties.variant
387
- }) : isMenuGroup(item) ? item.properties.variant === "dropdownMenu" ? (
388
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
389
- /* @__PURE__ */ React4.createElement(DropdownMenuToolbarItem, {
390
- key: item.id,
391
- group: item
392
- })
393
- ) : (
394
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
395
- /* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
396
- key: item.id,
397
- group: item
398
- })
399
- ) : (
400
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
401
- /* @__PURE__ */ React4.createElement(ActionToolbarItem, {
402
- key: item.id,
403
- action: item
404
- })
405
- ))));
406
- } finally {
407
- _effect.f();
417
+ priority
418
+ });
419
+ registry.set(menuItemsAtom, next);
420
+ }, [
421
+ registry,
422
+ menuItemsAtom
423
+ ]);
424
+ const removeMenuItems = useCallback3((id) => {
425
+ const prev = registry.get(menuItemsAtom);
426
+ const next = new Map(prev);
427
+ next.delete(id);
428
+ registry.set(menuItemsAtom, next);
429
+ }, [
430
+ registry,
431
+ menuItemsAtom
432
+ ]);
433
+ return /* @__PURE__ */ React4.createElement(MenuContextProvider, {
434
+ items,
435
+ iconSize,
436
+ attendableId,
437
+ alwaysActive,
438
+ menuItemsAtom,
439
+ addMenuItems,
440
+ removeMenuItems,
441
+ onAction,
442
+ scope
443
+ }, children);
444
+ };
445
+ var resolveItems = (baseItems, group, entries) => {
446
+ const applicable = [
447
+ ...entries.values()
448
+ ].filter((entry) => !entry.groupFilter || entry.groupFilter(group));
449
+ if (applicable.length === 0) {
450
+ return baseItems;
451
+ }
452
+ const sorted = sortMenuItems(applicable);
453
+ const replacements = sorted.filter((entry) => entry.mode === "replacement");
454
+ if (replacements.length > 0) {
455
+ if (replacements.length > 1) {
456
+ log.warn("multiple replacement entries found", {
457
+ ids: replacements.map((r) => r.id).join(", "),
458
+ using: replacements[0].id
459
+ }, {
460
+ F: __dxlog_file,
461
+ L: 152,
462
+ S: void 0,
463
+ C: (f, a) => f(...a)
464
+ });
465
+ }
466
+ return replacements[0].items;
408
467
  }
468
+ const additive = sorted.filter((entry) => entry.mode === "additive");
469
+ const additiveItems = additive.flatMap((entry) => entry.items);
470
+ if (!baseItems || baseItems.length === 0) {
471
+ return additiveItems.length > 0 ? additiveItems : null;
472
+ }
473
+ return [
474
+ ...baseItems,
475
+ ...additiveItems
476
+ ];
409
477
  };
410
-
411
- // src/hooks/useMenuActions.ts
412
- import { RegistryContext, useRxValue } from "@effect-rx/rx-react";
413
- import { useCallback as useCallback3, useContext, useEffect, useState } from "react";
414
- import { Graph, ROOT_ID } from "@dxos/app-graph";
415
- var edgesArrayToRecord = (edges) => {
416
- return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
417
- if (!acc[source]) {
418
- acc[source] = {
419
- inbound: [],
420
- outbound: []
421
- };
478
+ var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
479
+ const { items, menuItemsAtom } = useMenuScoped(consumerName, __menuScope);
480
+ const groupItems = useAtomValue(items(group));
481
+ const entries = useAtomValue(menuItemsAtom) ?? /* @__PURE__ */ new Map();
482
+ const baseItems = useMemo(() => propsItems ?? groupItems ?? null, [
483
+ propsItems,
484
+ groupItems
485
+ ]);
486
+ const resolved = useMemo(() => resolveItems(baseItems, group, entries), [
487
+ baseItems,
488
+ group,
489
+ entries
490
+ ]);
491
+ return resolved ?? void 0;
492
+ };
493
+ var useMenu = (consumerName) => {
494
+ return useMenuScoped(consumerName, void 0);
495
+ };
496
+ var MenuRoot = ({ children, open, defaultOpen, onOpenChange, caller, ...props }) => {
497
+ const [menuOpen, setMenuOpen] = useControllableState2({
498
+ prop: open,
499
+ defaultProp: defaultOpen,
500
+ onChange: onOpenChange
501
+ });
502
+ const closeMenu = useCallback3(() => setMenuOpen(false), [
503
+ setMenuOpen
504
+ ]);
505
+ return /* @__PURE__ */ React4.createElement(MenuProvider, props, /* @__PURE__ */ React4.createElement(MenuDropdownContext.Provider, {
506
+ value: {
507
+ closeMenu,
508
+ caller
422
509
  }
423
- if (!acc[target]) {
424
- acc[target] = {
425
- inbound: [],
426
- outbound: []
427
- };
510
+ }, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Root, {
511
+ open: menuOpen,
512
+ onOpenChange: setMenuOpen
513
+ }, children)));
514
+ };
515
+ var MenuContentItem = ({ item, onClick, __menuScope }) => {
516
+ const action = item;
517
+ const handleClick = useCallback3((event) => onClick(action, event), [
518
+ action,
519
+ onClick
520
+ ]);
521
+ const { iconSize } = useMenuScoped("MenuContentItem", __menuScope);
522
+ return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Item, {
523
+ onClick: handleClick,
524
+ classNames: "gap-2",
525
+ disabled: action.properties?.disabled,
526
+ ...action.properties?.testId && {
527
+ "data-testid": action.properties.testId
428
528
  }
429
- const sourceEdges = acc[source];
430
- if (!sourceEdges.outbound.includes(target)) {
431
- sourceEdges.outbound.push(target);
529
+ }, action.properties?.icon && /* @__PURE__ */ React4.createElement(Icon3, {
530
+ icon: action.properties.icon,
531
+ size: iconSize
532
+ }), /* @__PURE__ */ React4.createElement(ActionLabel, {
533
+ action
534
+ }));
535
+ };
536
+ var MenuContent = ({ group, items: propsItems, caller: callerOverride, __menuScope }) => {
537
+ const { closeMenu, caller: contextCaller } = useContext(MenuDropdownContext);
538
+ const caller = callerOverride ?? contextCaller;
539
+ const { onAction } = useMenuScoped("MenuContent", __menuScope);
540
+ const resolvedItems = useMenuItems(group, propsItems, "MenuContent", __menuScope);
541
+ const handleActionClick = useCallback3((action, event) => {
542
+ if (action.properties?.disabled) {
543
+ return;
432
544
  }
433
- const targetEdges = acc[target];
434
- if (!targetEdges.inbound.includes(source)) {
435
- targetEdges.inbound.push(source);
545
+ event.stopPropagation();
546
+ closeMenu();
547
+ if (onAction) {
548
+ onAction(action, {
549
+ parent: group,
550
+ caller
551
+ });
552
+ } else {
553
+ void executeMenuAction(action, {
554
+ parent: group,
555
+ caller
556
+ });
436
557
  }
437
- return acc;
438
- }, {})));
439
- };
440
- var useMenuActions = (props) => {
441
- const registry = useContext(RegistryContext);
442
- const menuGraphProps = useRxValue(props);
443
- const [graph] = useState(new Graph({
444
- registry,
445
- nodes: menuGraphProps.nodes,
446
- edges: edgesArrayToRecord(menuGraphProps.edges)
447
- }));
448
- useEffect(() => {
449
- graph.addNodes(menuGraphProps.nodes);
450
- graph.addEdges(menuGraphProps.edges);
451
558
  }, [
452
- menuGraphProps
559
+ group,
560
+ caller,
561
+ onAction,
562
+ closeMenu
453
563
  ]);
454
- const useGroupItems = useCallback3((sourceNode) => {
455
- const items = useRxValue(graph.connections(sourceNode?.id || ROOT_ID));
456
- return items;
564
+ return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Portal, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Viewport, null, resolvedItems?.map((item) => /* @__PURE__ */ React4.createElement(MenuContentItem, {
565
+ key: item.id,
566
+ item,
567
+ onClick: handleActionClick
568
+ }))), /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Arrow, null)));
569
+ };
570
+ var Menu = {
571
+ Root: MenuRoot,
572
+ Trigger: NaturalDropdownMenu2.Trigger,
573
+ Content: MenuContent,
574
+ VirtualTrigger: NaturalDropdownMenu2.VirtualTrigger,
575
+ Toolbar: ToolbarMenu
576
+ };
577
+
578
+ // src/hooks/useMenuActions.ts
579
+ import { RegistryContext as RegistryContext2, useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
580
+ import { useCallback as useCallback4, useContext as useContext2, useRef } from "react";
581
+ import { Graph, Node as Node3 } from "@dxos/app-graph";
582
+ var useMenuActions = (props) => {
583
+ const registry = useContext2(RegistryContext2);
584
+ const menuGraphProps = useAtomValue2(props);
585
+ const graphRef = useRef(null);
586
+ if (!graphRef.current || graphRef.current.props !== menuGraphProps) {
587
+ const newGraph = Graph.make({
588
+ registry
589
+ });
590
+ newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
591
+ graphRef.current = {
592
+ graph: newGraph,
593
+ props: menuGraphProps
594
+ };
595
+ }
596
+ const graph = graphRef.current.graph;
597
+ const items = useCallback4((group) => {
598
+ return graph.connections(group?.id || Node3.RootId, "child");
457
599
  }, [
458
600
  graph
459
601
  ]);
460
602
  return {
461
- useGroupItems
603
+ items
462
604
  };
463
605
  };
464
606
 
465
607
  // src/builder.ts
466
608
  import { invariant } from "@dxos/invariant";
467
- var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/builder.ts";
468
- var MenuBuilder = Object.freeze({
469
- make: () => new MenuBuilderImpl({
470
- nodes: [],
471
- edges: []
472
- }, "root")
473
- });
609
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/builder.ts";
474
610
  var MenuBuilderImpl = class _MenuBuilderImpl {
611
+ _data;
612
+ _rootId;
613
+ _separatorCount = 0;
475
614
  constructor(_data, _rootId) {
476
615
  this._data = _data;
477
616
  this._rootId = _rootId;
478
617
  }
479
- action(id, invoke, properties) {
480
- this._data.nodes.push(createMenuAction(id, invoke, properties));
481
- this._data.edges.push({
482
- source: this._rootId,
483
- target: id
484
- });
485
- return this;
486
- }
487
618
  root(props) {
488
619
  invariant(this._rootId === "root", "Root group can only be at the top level", {
489
- F: __dxlog_file,
490
- L: 42,
620
+ F: __dxlog_file2,
621
+ L: 41,
491
622
  S: this,
492
623
  A: [
493
624
  "this._rootId === 'root'",
@@ -495,8 +626,8 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
495
626
  ]
496
627
  });
497
628
  invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
498
- F: __dxlog_file,
499
- L: 43,
629
+ F: __dxlog_file2,
630
+ L: 42,
500
631
  S: this,
501
632
  A: [
502
633
  "this._data.nodes.find((node) => node.id === 'root') === undefined",
@@ -506,36 +637,71 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
506
637
  this._data.nodes.push(createMenuItemGroup("root", props));
507
638
  return this;
508
639
  }
509
- group(id, properties, cb) {
510
- this._data.nodes.push(createMenuItemGroup(id, properties));
640
+ build() {
641
+ return this._data;
642
+ }
643
+ action(id, props, invoke) {
644
+ this._data.nodes.push(createMenuAction(id, invoke, props));
645
+ this._data.edges.push({
646
+ source: this._rootId,
647
+ target: id,
648
+ relation: "child"
649
+ });
650
+ return this;
651
+ }
652
+ group(id, props, cb) {
653
+ this._data.nodes.push(createMenuItemGroup(id, props));
511
654
  this._data.edges.push({
512
655
  source: this._rootId,
513
- target: id
656
+ target: id,
657
+ relation: "child"
514
658
  });
515
659
  cb(new _MenuBuilderImpl(this._data, id));
516
660
  return this;
517
661
  }
518
- build() {
519
- return this._data;
662
+ subgraph(subgraph) {
663
+ this._data.nodes.push(...subgraph.nodes);
664
+ this._data.edges.push(...subgraph.edges);
665
+ return this;
666
+ }
667
+ separator(id, variant = "gap") {
668
+ id ??= `separator-${++this._separatorCount}`;
669
+ this._data.nodes.push({
670
+ id,
671
+ type: MenuSeparatorType,
672
+ properties: {
673
+ variant
674
+ },
675
+ data: void 0
676
+ });
677
+ this._data.edges.push({
678
+ source: this._rootId,
679
+ target: id,
680
+ relation: "child"
681
+ });
682
+ return this;
520
683
  }
521
684
  };
685
+ var MenuBuilder = Object.freeze({
686
+ make: () => new MenuBuilderImpl({
687
+ nodes: [],
688
+ edges: []
689
+ }, "root")
690
+ });
522
691
  export {
523
- DropdownMenu,
692
+ Menu,
524
693
  MenuBuilder,
525
- MenuProvider,
526
694
  MenuSeparatorType,
527
- ToolbarMenu,
528
695
  createGapSeparator,
529
696
  createLineSeparator,
530
697
  createMenuAction,
531
698
  createMenuItemGroup,
532
- createMenuScope,
533
699
  isMenuGroup,
534
700
  isSeparator,
535
701
  menuContextDefaults,
536
- rxFromSignal,
537
702
  useMenu,
538
703
  useMenuActions,
539
- useMenuItems
704
+ useMenuItems,
705
+ useMenuScoped
540
706
  };
541
707
  //# sourceMappingURL=index.mjs.map