@dxos/react-ui-menu 0.8.4-main.ead640a → 0.8.4-main.effb148878

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