@dxos/react-ui-menu 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8

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