@dxos/react-ui-menu 0.8.2-main.f11618f → 0.8.2-main.fbd8ed0

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 (51) hide show
  1. package/dist/lib/browser/index.mjs +58 -63
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +53 -58
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +58 -63
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/ActionLabel.d.ts +8 -4
  11. package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
  12. package/dist/types/src/components/DropdownMenu.d.ts +3 -2
  13. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  14. package/dist/types/src/components/MenuContext.d.ts +4 -13
  15. package/dist/types/src/components/MenuContext.d.ts.map +1 -1
  16. package/dist/types/src/{testing → components}/Menus.stories.d.ts +1 -1
  17. package/dist/types/src/components/Menus.stories.d.ts.map +1 -0
  18. package/dist/types/src/components/ToolbarMenu.d.ts +5 -1
  19. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
  20. package/dist/types/src/hooks/index.d.ts +2 -0
  21. package/dist/types/src/hooks/index.d.ts.map +1 -0
  22. package/dist/types/src/hooks/useMenuActions.d.ts +12 -0
  23. package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -0
  24. package/dist/types/src/index.d.ts +1 -1
  25. package/dist/types/src/index.d.ts.map +1 -1
  26. package/dist/types/src/testing/generator.d.ts +26 -0
  27. package/dist/types/src/testing/generator.d.ts.map +1 -0
  28. package/dist/types/src/testing/index.d.ts +1 -25
  29. package/dist/types/src/testing/index.d.ts.map +1 -1
  30. package/dist/types/src/{defs.d.ts → types.d.ts} +3 -5
  31. package/dist/types/src/types.d.ts.map +1 -0
  32. package/dist/types/src/util.d.ts +2 -2
  33. package/dist/types/src/util.d.ts.map +1 -1
  34. package/dist/types/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +18 -12
  36. package/src/components/ActionLabel.tsx +11 -8
  37. package/src/components/DropdownMenu.tsx +5 -5
  38. package/src/components/MenuContext.tsx +11 -26
  39. package/src/{testing → components}/Menus.stories.tsx +13 -13
  40. package/src/components/ToolbarMenu.tsx +27 -29
  41. package/src/hooks/index.ts +5 -0
  42. package/src/{hooks.ts → hooks/useMenuActions.ts} +20 -20
  43. package/src/index.ts +1 -1
  44. package/src/testing/generator.ts +115 -0
  45. package/src/testing/index.ts +1 -107
  46. package/src/{defs.ts → types.ts} +2 -5
  47. package/src/util.ts +7 -7
  48. package/dist/types/src/defs.d.ts.map +0 -1
  49. package/dist/types/src/hooks.d.ts +0 -17
  50. package/dist/types/src/hooks.d.ts.map +0 -1
  51. package/dist/types/src/testing/Menus.stories.d.ts.map +0 -1
@@ -25,13 +25,11 @@ import { getHostPlatform } from "@dxos/util";
25
25
  var getShortcut = (action) => {
26
26
  return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
27
27
  };
28
- var noop = () => {
29
- };
30
- var createMenuAction = (id, properties) => ({
28
+ var createMenuAction = (id, invoke, properties) => ({
31
29
  id,
32
30
  type: ACTION_TYPE,
33
31
  properties,
34
- data: noop
32
+ data: invoke
35
33
  });
36
34
  var createMenuItemGroup = (id, properties) => ({
37
35
  id,
@@ -86,6 +84,10 @@ var ActionLabel = ({ action }) => {
86
84
  className: mx("shrink-0", descriptionText)
87
85
  }, keySymbols(shortcut).join("")));
88
86
  };
87
+ var actionLabel = (action, t) => {
88
+ const shortcut = getShortcut(action);
89
+ return `${toLocalizedString(action.properties.label, t)}${shortcut ? ` (${keySymbols(shortcut).join("")})` : ""}`;
90
+ };
89
91
 
90
92
  // packages/ui/react-ui-menu/src/components/MenuContext.tsx
91
93
  import { createContextScope } from "@radix-ui/react-context";
@@ -95,27 +97,24 @@ var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
95
97
  var [MenuContextProvider, useMenu] = createMenuContext(MENU_NAME);
96
98
  var menuContextDefaults = {
97
99
  iconSize: 5,
98
- onAction: () => {
99
- },
100
- resolveGroupItems: () => null
100
+ useGroupItems: () => null
101
101
  };
102
102
  var useMenuScope = createMenuScope();
103
- var MenuProvider = ({ children, resolveGroupItems = menuContextDefaults.resolveGroupItems, onAction = menuContextDefaults.onAction, iconSize = menuContextDefaults.iconSize, attendableId }) => {
103
+ var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
104
104
  const { scope } = useMenuScope(void 0);
105
105
  return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
106
- resolveGroupItems,
107
- onAction,
106
+ useGroupItems,
108
107
  iconSize,
109
108
  attendableId,
110
109
  scope
111
110
  }, children);
112
111
  };
113
112
  var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
114
- const { resolveGroupItems } = useMenu(consumerName, __menuScope);
115
- return useMemo(() => propsItems ?? resolveGroupItems?.(group) ?? void 0, [
113
+ const { useGroupItems } = useMenu(consumerName, __menuScope);
114
+ const groupItems = useGroupItems(group);
115
+ return useMemo(() => propsItems ?? groupItems ?? void 0, [
116
116
  propsItems,
117
- group,
118
- resolveGroupItems
117
+ groupItems
119
118
  ]);
120
119
  };
121
120
 
@@ -141,13 +140,12 @@ var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
141
140
  action
142
141
  }));
143
142
  };
144
- var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, suppressNextTooltip, children, __menuScope, ...naturalProps }) => {
143
+ var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, suppressNextTooltip, caller, children, __menuScope, ...naturalProps }) => {
145
144
  const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
146
145
  prop: open,
147
146
  defaultProp: defaultOpen,
148
147
  onChange: onOpenChange
149
148
  });
150
- const { onAction } = useMenu("DropdownMenuRoot", __menuScope);
151
149
  const handleActionClick = useCallback((action, event) => {
152
150
  if (action.properties?.disabled) {
153
151
  return;
@@ -157,9 +155,14 @@ var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenCha
157
155
  suppressNextTooltip.current = true;
158
156
  }
159
157
  setOptionsMenuOpen(false);
160
- onAction?.(action);
158
+ void action.data?.({
159
+ parent: group,
160
+ caller
161
+ });
161
162
  }, [
162
- onAction
163
+ suppressNextTooltip,
164
+ group,
165
+ caller
163
166
  ]);
164
167
  const items = useMenuItems(group, propsItems);
165
168
  return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
@@ -185,10 +188,10 @@ var DropdownMenu = {
185
188
 
186
189
  // packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx
187
190
  import React4, { useCallback as useCallback2, useRef } from "react";
188
- import { Icon as Icon2, Toolbar as NaturalToolbar } from "@dxos/react-ui";
191
+ import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
189
192
  import { useAttention } from "@dxos/react-ui-attention";
190
193
 
191
- // packages/ui/react-ui-menu/src/defs.ts
194
+ // packages/ui/react-ui-menu/src/types.ts
192
195
  import { ACTION_GROUP_TYPE as ACTION_GROUP_TYPE2 } from "@dxos/app-graph";
193
196
  var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
194
197
  var isSeparator = (node) => node.type === MenuSeparatorType;
@@ -196,12 +199,10 @@ var isMenuGroup = (node) => node.type === ACTION_GROUP_TYPE2;
196
199
 
197
200
  // packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx
198
201
  var ActionToolbarItem = ({ action, __menuScope }) => {
199
- const { onAction, iconSize } = useMenu("ActionToolbarItem", __menuScope);
200
- const handleClick = useCallback2(() => {
201
- onAction?.(action);
202
- }, [
203
- action,
204
- onAction
202
+ const { iconSize } = useMenu("ActionToolbarItem", __menuScope);
203
+ const { t } = useTranslation2(translationKey);
204
+ const handleClick = useCallback2(() => action.data?.(), [
205
+ action
205
206
  ]);
206
207
  const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
207
208
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
@@ -209,9 +210,7 @@ var ActionToolbarItem = ({ action, __menuScope }) => {
209
210
  icon,
210
211
  size: iconSize,
211
212
  iconOnly,
212
- label: /* @__PURE__ */ React4.createElement(ActionLabel, {
213
- action
214
- })
213
+ label: actionLabel(action, t)
215
214
  } : {
216
215
  children: /* @__PURE__ */ React4.createElement(ActionLabel, {
217
216
  action
@@ -232,24 +231,25 @@ var ActionToolbarItem = ({ action, __menuScope }) => {
232
231
  var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
233
232
  const { iconOnly, disabled, testId } = group.properties;
234
233
  const suppressNextTooltip = useRef(false);
234
+ const { t } = useTranslation2(translationKey);
235
235
  const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
236
236
  const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
237
237
  const activeItem = items?.find((item) => !!item.properties.checked);
238
238
  const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
239
239
  activeItem?.properties.icon || group.properties.icon;
240
240
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
241
- const label = /* @__PURE__ */ React4.createElement(ActionLabel, {
242
- action: group.properties.applyActive && activeItem ? activeItem : group
243
- });
241
+ const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
244
242
  const rootProps = icon ? {
245
243
  icon,
246
244
  size: iconSize,
247
245
  iconOnly,
248
- label,
246
+ label: actionLabel(labelAction, t),
249
247
  caretDown: true,
250
248
  suppressNextTooltip
251
249
  } : {
252
- children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, label, /* @__PURE__ */ React4.createElement(Icon2, {
250
+ children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(ActionLabel, {
251
+ action: labelAction
252
+ }), /* @__PURE__ */ React4.createElement(Icon2, {
253
253
  size: 3,
254
254
  icon: "ph--caret-down--bold",
255
255
  classNames: "mis-1"
@@ -270,23 +270,22 @@ var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
270
270
  }
271
271
  })));
272
272
  };
273
- var ToggleGroupItem = ({ action, __menuScope }) => {
274
- const { iconSize, onAction } = useMenu("ToggleGroupItem", __menuScope);
273
+ var ToggleGroupItem = ({ group, action, __menuScope }) => {
274
+ const { iconSize } = useMenu("ToggleGroupItem", __menuScope);
275
+ const { t } = useTranslation2(translationKey);
275
276
  const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
276
- const handleClick = useCallback2(() => {
277
- onAction?.(action);
278
- }, [
277
+ const handleClick = useCallback2(() => action.data?.({
278
+ parent: group
279
+ }), [
279
280
  action,
280
- onAction
281
+ group
281
282
  ]);
282
283
  const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
283
284
  const rootProps = icon ? {
284
285
  icon,
285
286
  size: iconSize,
286
287
  iconOnly,
287
- label: /* @__PURE__ */ React4.createElement(ActionLabel, {
288
- action
289
- })
288
+ label: actionLabel(action, t)
290
289
  } : {
291
290
  children: /* @__PURE__ */ React4.createElement(ActionLabel, {
292
291
  action
@@ -320,6 +319,7 @@ var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
320
319
  // TODO(thure): Handle other menu item types.
321
320
  items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
322
321
  key: action.id,
322
+ group,
323
323
  action
324
324
  }))
325
325
  )
@@ -332,8 +332,8 @@ var ToolbarMenu = ({ __menuScope, classNames, ...props }) => {
332
332
  return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
333
333
  ...props,
334
334
  classNames: [
335
- "p-0 pointer-fine:p-1 attention-surface",
336
- !hasAttention && "opacity-20",
335
+ "p-1",
336
+ !hasAttention && "[&>*]:opacity-20 !bg-transparent",
337
337
  classNames
338
338
  ]
339
339
  }, items?.map((item, i) => isSeparator(item) ? /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
@@ -360,10 +360,11 @@ var ToolbarMenu = ({ __menuScope, classNames, ...props }) => {
360
360
  )));
361
361
  };
362
362
 
363
- // packages/ui/react-ui-menu/src/hooks.ts
363
+ // packages/ui/react-ui-menu/src/hooks/useMenuActions.ts
364
+ import { RegistryContext, useRxValue } from "@effect-rx/rx-react";
364
365
  import { useSignalEffect } from "@preact/signals-react";
365
- import { useCallback as useCallback3, useState } from "react";
366
- import { Graph } from "@dxos/app-graph";
366
+ import { useCallback as useCallback3, useContext, useState } from "react";
367
+ import { Graph, ROOT_ID } from "@dxos/app-graph";
367
368
  var edgesArrayToRecord = (edges) => {
368
369
  return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
369
370
  if (!acc[source]) {
@@ -387,35 +388,29 @@ var edgesArrayToRecord = (edges) => {
387
388
  targetEdges.inbound.push(source);
388
389
  }
389
390
  return acc;
390
- }, {})).map(([id, { outbound }]) => [
391
- id,
392
- outbound
393
- ]));
391
+ }, {})));
394
392
  };
395
393
  var useMenuActions = (actionCreator) => {
394
+ const registry = useContext(RegistryContext);
396
395
  const initialMenuGraphProps = actionCreator();
397
396
  const [graph] = useState(new Graph({
397
+ registry,
398
398
  nodes: initialMenuGraphProps.nodes,
399
399
  edges: edgesArrayToRecord(initialMenuGraphProps.edges)
400
400
  }));
401
401
  useSignalEffect(() => {
402
402
  const menuGraphProps = actionCreator();
403
- graph._addNodes(menuGraphProps.nodes);
404
- graph._addEdges(menuGraphProps.edges);
403
+ graph.addNodes(menuGraphProps.nodes);
404
+ graph.addEdges(menuGraphProps.edges);
405
405
  });
406
- const resolveGroupItems = useCallback3((sourceNode = graph.root) => {
407
- if (graph) {
408
- return graph.nodes(sourceNode, {
409
- filter: (n) => true
410
- }) || null;
411
- } else {
412
- return null;
413
- }
406
+ const useGroupItems = useCallback3((sourceNode) => {
407
+ const items = useRxValue(graph.connections(sourceNode?.id || ROOT_ID));
408
+ return items;
414
409
  }, [
415
410
  graph
416
411
  ]);
417
412
  return {
418
- resolveGroupItems
413
+ useGroupItems
419
414
  };
420
415
  };
421
416
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/components/DropdownMenu.tsx", "../../../src/components/ActionLabel.tsx", "../../../src/translations.ts", "../../../src/util.ts", "../../../src/components/MenuContext.tsx", "../../../src/components/ToolbarMenu.tsx", "../../../src/defs.ts", "../../../src/hooks.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type MouseEvent, type MutableRefObject, useCallback } from 'react';\n\nimport { DropdownMenu as NaturalDropdownMenu, Icon, type DropdownMenuRootProps } from '@dxos/react-ui';\n\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\nimport { type MenuAction, type MenuItem, type MenuItemGroup } from '../defs';\n\nexport type DropdownMenuProps = DropdownMenuRootProps & {\n group?: MenuItemGroup;\n items?: MenuItem[];\n suppressNextTooltip?: MutableRefObject<boolean>;\n};\n\nconst DropdownMenuItem = ({\n item,\n onClick,\n __menuScope,\n}: MenuScopedProps<{\n item: MenuItem;\n onClick: (action: MenuAction, event: MouseEvent) => void;\n}>) => {\n // TODO(thure): handle other items.\n const action = item as MenuAction;\n const handleClick = useCallback((event: MouseEvent) => onClick(action, event), [action, onClick]);\n const { iconSize } = useMenu('DropdownMenuItem', __menuScope);\n return (\n <NaturalDropdownMenu.Item\n onClick={handleClick}\n classNames='gap-2'\n disabled={action.properties?.disabled}\n {...(action.properties?.testId && { 'data-testid': action.properties.testId })}\n >\n {action.properties?.icon && <Icon icon={action.properties!.icon} size={iconSize} />}\n <ActionLabel action={action} />\n </NaturalDropdownMenu.Item>\n );\n};\n\nconst DropdownMenuRoot = ({\n items: propsItems,\n group,\n open,\n defaultOpen,\n onOpenChange,\n suppressNextTooltip,\n children,\n __menuScope,\n ...naturalProps\n}: MenuScopedProps<DropdownMenuProps>) => {\n const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({\n prop: open,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n const { onAction } = useMenu('DropdownMenuRoot', __menuScope);\n\n const handleActionClick = useCallback(\n (action: MenuAction, event: MouseEvent) => {\n if (action.properties?.disabled) {\n return;\n }\n event.stopPropagation();\n // TODO(thure): Why does Dialog’s modal-ness cause issues if we don’t explicitly close the menu here?\n if (suppressNextTooltip) {\n suppressNextTooltip.current = true;\n }\n setOptionsMenuOpen(false);\n onAction?.(action);\n },\n [onAction],\n );\n\n const items = useMenuItems(group, propsItems);\n\n return (\n <NaturalDropdownMenu.Root\n {...{\n open: optionsMenuOpen,\n onOpenChange: (nextOpen: boolean) => {\n if (!nextOpen && suppressNextTooltip) {\n suppressNextTooltip.current = true;\n }\n return setOptionsMenuOpen(nextOpen);\n },\n }}\n {...naturalProps}\n >\n {children}\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {items?.map((item) => <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />)}\n </NaturalDropdownMenu.Viewport>\n <NaturalDropdownMenu.Arrow />\n </NaturalDropdownMenu.Content>\n </NaturalDropdownMenu.Portal>\n </NaturalDropdownMenu.Root>\n );\n};\n\nexport const DropdownMenu = {\n Root: DropdownMenuRoot,\n Trigger: NaturalDropdownMenu.Trigger,\n VirtualTrigger: NaturalDropdownMenu.VirtualTrigger,\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type Action, type ActionGroup } from '@dxos/app-graph';\nimport { keySymbols } from '@dxos/keyboard';\nimport { toLocalizedString, useTranslation } from '@dxos/react-ui';\nimport { mx, descriptionText } from '@dxos/react-ui-theme';\n\nimport { type MenuActionProperties } from '../defs';\nimport { translationKey } from '../translations';\nimport { getShortcut } from '../util';\n\nexport const ActionLabel = ({\n action,\n}: {\n action: Action<MenuActionProperties> | ActionGroup<Omit<MenuActionProperties, 'variant'>>;\n}) => {\n const shortcut = getShortcut(action);\n const { t } = useTranslation(translationKey);\n\n return (\n <>\n <span className='grow truncate'>{toLocalizedString(action.properties!.label, t)}</span>\n {shortcut && <span className={mx('shrink-0', descriptionText)}>{keySymbols(shortcut).join('')}</span>}\n </>\n );\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nexport const translationKey = 'menus';\n\nexport default [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const;\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, actionGroupSymbol, type ActionLike } from '@dxos/app-graph';\nimport { getHostPlatform } from '@dxos/util';\n\nimport {\n type MenuAction,\n type MenuActionProperties,\n type MenuItemGroup,\n type MenuItemGroupProperties,\n type MenuSeparator,\n} from './defs';\n\nexport const getShortcut = (action: ActionLike) => {\n return typeof action.properties?.keyBinding === 'string'\n ? action.properties.keyBinding\n : action.properties?.keyBinding?.[getHostPlatform()];\n};\n\nexport const fallbackIcon = 'ph--placeholder--regular';\n\n// TODO(thure,wittjosiah): This is probably a smell; consider the whether react-ui-menu should use action nodes if the\n// callback in `data` is never used. See https://github.com/dxos/dxos/pull/8506#discussion_r1925855118\nconst noop = () => {};\n\nexport const createMenuAction = <P extends {} = {}>(id: string, properties: P & MenuActionProperties) =>\n ({\n id,\n type: ACTION_TYPE,\n properties,\n data: noop,\n }) satisfies MenuAction;\n\nexport const createMenuItemGroup = <\n P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,\n>(\n id: string,\n properties: P,\n) =>\n ({\n id,\n type: ACTION_GROUP_TYPE,\n properties,\n data: actionGroupSymbol,\n }) satisfies MenuItemGroup;\n\nexport const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'gap' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [{ source, target: id }],\n});\n\nexport const createLineSeparator = (id: string = 'line', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'line' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [{ source, target: id }],\n});\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { createContextScope, type Scope } from '@radix-ui/react-context';\nimport React, { type PropsWithChildren, useMemo } from 'react';\n\nimport { type Node } from '@dxos/app-graph';\n\nimport {\n type MenuActionHandler,\n type MenuAction,\n type MenuContextValue,\n type MenuItem,\n type MenuItemGroup,\n} from '../defs';\n\nexport type MenuScopedProps<P> = P & { __menuScope?: Scope };\n\nconst MENU_NAME = 'GraphMenu';\n\nconst [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);\n\nconst [MenuContextProvider, useMenu] = createMenuContext<MenuContextValue<any>>(MENU_NAME);\n\nexport const menuContextDefaults: MenuContextValue<MenuAction> = {\n iconSize: 5,\n onAction: () => {},\n resolveGroupItems: () => null,\n};\n\nconst useMenuScope = createMenuScope();\n\nconst MenuProvider = <A extends Node = MenuAction>({\n children,\n resolveGroupItems = menuContextDefaults.resolveGroupItems,\n onAction = menuContextDefaults.onAction as MenuActionHandler<A>,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n}: PropsWithChildren<Partial<MenuContextValue<A>>>) => {\n const { scope } = useMenuScope(undefined);\n return (\n <MenuContextProvider\n resolveGroupItems={resolveGroupItems}\n onAction={onAction}\n iconSize={iconSize}\n attendableId={attendableId}\n scope={scope}\n >\n {children}\n </MenuContextProvider>\n );\n};\n\nexport const useMenuItems = (\n group?: MenuItemGroup,\n propsItems?: MenuItem[],\n consumerName: string = 'useMenuItemConsumer',\n __menuScope?: Scope,\n) => {\n const { resolveGroupItems } = useMenu(consumerName, __menuScope);\n return useMemo(() => propsItems ?? resolveGroupItems?.(group) ?? undefined, [propsItems, group, resolveGroupItems]);\n};\n\nexport { useMenu, createMenuScope, MenuProvider };\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useRef } from 'react';\n\nimport { Icon, type IconButtonProps, Toolbar as NaturalToolbar, type ToolbarRootProps } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\n\nimport { ActionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\nimport {\n type MenuAction,\n type MenuItem,\n isMenuGroup,\n isSeparator,\n type MenuItemGroup,\n type MenuActionProperties,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n} from '../defs';\n\nexport type ToolbarMenuDropdownMenuActionGroup = Omit<MenuActionProperties, 'variant' | 'icon'> & {\n variant: 'dropdownMenu';\n icon: string;\n applyActive?: boolean;\n};\n\nexport type ToolbarMenuToggleGroupActionGroup = Omit<MenuActionProperties, 'variant'> & {\n variant: 'toggleGroup';\n};\n\nexport type ToolbarMenuActionGroupProperties = (\n | ToolbarMenuDropdownMenuActionGroup\n | ToolbarMenuToggleGroupActionGroup\n) &\n (MenuSingleSelectActionGroup | MenuMultipleSelectActionGroup);\n\nexport type ToolbarMenuProps = ToolbarRootProps;\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nconst ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {\n const { onAction, iconSize } = useMenu('ActionToolbarItem', __menuScope);\n const handleClick = useCallback(() => {\n onAction?.(action);\n }, [action, onAction]);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: <ActionLabel action={action} /> }\n : { children: <ActionLabel action={action} /> };\n return hidden ? null : (\n <Root\n key={action.id}\n disabled={disabled}\n onClick={handleClick}\n variant='ghost'\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as IconButtonProps)}\n classNames={classNames}\n />\n );\n};\n\nconst DropdownMenuToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const { iconOnly, disabled, testId } = group.properties;\n const suppressNextTooltip = useRef(false);\n const { iconSize } = useMenu('DropdownMenuToolbarItem', __menuScope);\n const items = useMenuItems(group, propsItems, 'DropdownMenuToolbarItem', __menuScope);\n const activeItem = items?.find((item) => !!(item as MenuAction).properties.checked);\n const icon =\n ((group.properties as any).applyActive &&\n // TODO(thure): Handle other menu item types.\n (activeItem as MenuAction)?.properties.icon) ||\n group.properties.icon;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const label = (\n <ActionLabel action={(group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group} />\n );\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label, caretDown: true, suppressNextTooltip }\n : {\n children: (\n <>\n {label}\n <Icon size={3} icon='ph--caret-down--bold' classNames='mis-1' />\n </>\n ),\n };\n return (\n <DropdownMenu.Root group={group} items={items} suppressNextTooltip={suppressNextTooltip}>\n <DropdownMenu.Trigger asChild>\n <Root\n variant='ghost'\n disabled={disabled}\n {...(rootProps as IconButtonProps)}\n {...(testId && { 'data-testid': testId })}\n />\n </DropdownMenu.Trigger>\n </DropdownMenu.Root>\n );\n};\n\nconst ToggleGroupItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {\n const { iconSize, onAction } = useMenu('ToggleGroupItem', __menuScope);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const handleClick = useCallback(() => {\n onAction?.(action);\n }, [action, onAction]);\n const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: <ActionLabel action={action} /> }\n : { children: <ActionLabel action={action} /> };\n return hidden ? null : (\n <Root\n key={action.id}\n value={action.id as any}\n disabled={disabled}\n onClick={handleClick}\n variant='ghost'\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as IconButtonProps)}\n classNames={classNames}\n />\n );\n};\n\nconst ToggleGroupToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const items = useMenuItems(group, propsItems, 'ToggleGroupToolbarItem', __menuScope);\n const { selectCardinality, value } = group.properties;\n return (\n // TODO(thure): The type here is difficult to manage, what do?\n // @ts-ignore\n <NaturalToolbar.ToggleGroup type={selectCardinality} value={value}>\n {\n // TODO(thure): Handle other menu item types.\n (items as MenuAction[]).map((action) => (\n <ToggleGroupItem key={action.id} action={action} />\n ))\n }\n </NaturalToolbar.ToggleGroup>\n );\n};\n\nexport const ToolbarMenu = ({ __menuScope, classNames, ...props }: MenuScopedProps<ToolbarMenuProps>) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId } = useMenu('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n return (\n <NaturalToolbar.Root\n {...props}\n classNames={['p-0 pointer-fine:p-1 attention-surface', !hasAttention && 'opacity-20', classNames]}\n >\n {items?.map((item: MenuItem, i: number) =>\n isSeparator(item) ? (\n <NaturalToolbar.Separator key={i} variant={item.properties.variant} />\n ) : isMenuGroup(item) ? (\n item.properties.variant === 'dropdownMenu' ? (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <DropdownMenuToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />\n ) : (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <ToggleGroupToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />\n )\n ) : (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <ActionToolbarItem key={item.id} action={item as MenuAction} />\n ),\n )}\n </NaturalToolbar.Root>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Node, type Action, type ActionGroup, ACTION_GROUP_TYPE } from '@dxos/app-graph';\nimport { type ToolbarSeparatorProps, type Label, type IconButtonProps, type ClassNameValue } from '@dxos/react-ui';\n\nexport type MenuActionProperties = {\n label: Label;\n icon?: string;\n value?: string;\n disabled?: boolean;\n hidden?: boolean;\n iconOnly?: boolean;\n testId?: string;\n variant?: 'action' | 'toggle';\n checked?: boolean;\n classNames?: ClassNameValue;\n};\n\nexport type MenuItemGroupProperties = {\n label: Label;\n icon?: string;\n iconOnly?: boolean;\n};\n\nexport type MenuAction<P extends {} = {}> = Action<P & MenuActionProperties>;\n\nexport type MenuActionHandler<A extends Node = MenuAction> = (action: A) => void;\n\nexport const MenuSeparatorType = '@dxos/react-ui-toolbar/separator' as const;\n\nexport type MenuSeparator = Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {\n type: typeof MenuSeparatorType;\n};\n\nexport const isSeparator = (node: Node): node is MenuSeparator => node.type === MenuSeparatorType;\n\nexport type MenuSingleSelectActionGroup = { selectCardinality: 'single'; value: string };\nexport type MenuMultipleSelectActionGroup = { selectCardinality: 'multiple'; value: string[] };\n\nexport type MenuItemGroup<P extends Record<string, any> = Record<string, any>> = ActionGroup<P>;\n\nexport const isMenuGroup = (node: Node): node is MenuItemGroup => node.type === ACTION_GROUP_TYPE;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;\n\nexport type MenuItemsResolver = (group?: MenuItemGroup) => MenuItem[] | null;\n\nexport type MenuContextValue<A extends Node = MenuAction> = {\n resolveGroupItems: MenuItemsResolver;\n iconSize: IconButtonProps['size'];\n onAction: MenuActionHandler<A>;\n attendableId?: string;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { useSignalEffect } from '@preact/signals-react';\nimport { useCallback, useState } from 'react';\n\nimport { Graph, type NodeArg, type Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup } from './defs';\n\ntype Edge = { source: string; target: string };\n\nconst edgesArrayToRecord = (edges: { source: string; target: string }[]): Record<string, string[]> => {\n return Object.fromEntries(\n Object.entries(\n edges.reduce((acc: Record<string, { inbound: string[]; outbound: string[] }>, { source, target }) => {\n if (!acc[source]) {\n acc[source] = { inbound: [], outbound: [] };\n }\n if (!acc[target]) {\n acc[target] = { inbound: [], outbound: [] };\n }\n\n const sourceEdges = acc[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = acc[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n\n return acc;\n }, {}),\n ).map(([id, { outbound }]): [string, string[]] => [id, outbound]),\n );\n};\n\nexport type ActionGraphNodes = NodeArg<any>[];\nexport type ActionGraphEdges = Edge[];\nexport type ActionGraphProps = { nodes: ActionGraphNodes; edges: ActionGraphEdges };\n\nexport const useMenuActions = (actionCreator: () => ActionGraphProps) => {\n const initialMenuGraphProps = actionCreator();\n\n const [graph] = useState(\n new Graph({ nodes: initialMenuGraphProps.nodes as Node[], edges: edgesArrayToRecord(initialMenuGraphProps.edges) }),\n );\n\n useSignalEffect(() => {\n const menuGraphProps = actionCreator();\n // @ts-ignore\n graph._addNodes(menuGraphProps.nodes);\n // @ts-ignore\n graph._addEdges(menuGraphProps.edges);\n });\n\n const resolveGroupItems = useCallback(\n (sourceNode: MenuItemGroup = graph.root as MenuItemGroup) => {\n if (graph) {\n return (graph.nodes(sourceNode, { filter: (n): n is any => true }) || null) as MenuItem[] | null;\n } else {\n return null;\n }\n },\n [graph],\n );\n\n return { resolveGroupItems };\n};\n"],
5
- "mappings": "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",
6
- "names": ["useControllableState", "React", "useCallback", "DropdownMenu", "NaturalDropdownMenu", "Icon", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "descriptionText", "translationKey", "ACTION_GROUP_TYPE", "ACTION_TYPE", "actionGroupSymbol", "getHostPlatform", "getShortcut", "action", "properties", "keyBinding", "getHostPlatform", "noop", "createMenuAction", "id", "properties", "type", "ACTION_TYPE", "data", "createMenuItemGroup", "ACTION_GROUP_TYPE", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "createLineSeparator", "ActionLabel", "action", "shortcut", "getShortcut", "t", "useTranslation", "translationKey", "span", "className", "toLocalizedString", "properties", "label", "mx", "descriptionText", "keySymbols", "join", "createContextScope", "React", "useMemo", "MENU_NAME", "createMenuContext", "createMenuScope", "createContextScope", "MenuContextProvider", "useMenu", "menuContextDefaults", "iconSize", "onAction", "resolveGroupItems", "useMenuScope", "MenuProvider", "children", "attendableId", "scope", "undefined", "React", "useMenuItems", "group", "propsItems", "consumerName", "__menuScope", "useMemo", "DropdownMenuItem", "item", "onClick", "__menuScope", "action", "handleClick", "useCallback", "event", "iconSize", "useMenu", "React", "NaturalDropdownMenu", "Item", "classNames", "disabled", "properties", "testId", "icon", "Icon", "size", "ActionLabel", "DropdownMenuRoot", "items", "propsItems", "group", "open", "defaultOpen", "onOpenChange", "suppressNextTooltip", "children", "naturalProps", "optionsMenuOpen", "setOptionsMenuOpen", "useControllableState", "prop", "defaultProp", "onChange", "onAction", "handleActionClick", "stopPropagation", "current", "useMenuItems", "Root", "nextOpen", "Portal", "Content", "Viewport", "map", "key", "id", "Arrow", "DropdownMenu", "Trigger", "VirtualTrigger", "React", "useCallback", "useRef", "Icon", "Toolbar", "NaturalToolbar", "useAttention", "ACTION_GROUP_TYPE", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "ACTION_GROUP_TYPE", "ActionToolbarItem", "action", "__menuScope", "onAction", "iconSize", "useMenu", "handleClick", "useCallback", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "properties", "Root", "NaturalToolbar", "IconButton", "Button", "rootProps", "size", "label", "React", "ActionLabel", "children", "key", "id", "onClick", "variant", "DropdownMenuToolbarItem", "group", "items", "propsItems", "suppressNextTooltip", "useRef", "useMenuItems", "activeItem", "find", "item", "checked", "applyActive", "caretDown", "Icon", "DropdownMenu", "Trigger", "asChild", "ToggleGroupItem", "ToggleGroupIconItem", "value", "ToggleGroupToolbarItem", "selectCardinality", "ToggleGroup", "type", "map", "ToolbarMenu", "props", "undefined", "attendableId", "hasAttention", "useAttention", "i", "isSeparator", "Separator", "isMenuGroup", "useSignalEffect", "useCallback", "useState", "Graph", "edgesArrayToRecord", "edges", "Object", "fromEntries", "entries", "reduce", "acc", "source", "target", "inbound", "outbound", "sourceEdges", "includes", "push", "targetEdges", "map", "id", "useMenuActions", "actionCreator", "initialMenuGraphProps", "graph", "useState", "Graph", "nodes", "useSignalEffect", "menuGraphProps", "_addNodes", "_addEdges", "resolveGroupItems", "useCallback", "sourceNode", "root", "filter", "n"]
3
+ "sources": ["../../../src/components/DropdownMenu.tsx", "../../../src/components/ActionLabel.tsx", "../../../src/translations.ts", "../../../src/util.ts", "../../../src/components/MenuContext.tsx", "../../../src/components/ToolbarMenu.tsx", "../../../src/types.ts", "../../../src/hooks/useMenuActions.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type MouseEvent, type MutableRefObject, useCallback } from 'react';\n\nimport { DropdownMenu as NaturalDropdownMenu, Icon, type DropdownMenuRootProps } from '@dxos/react-ui';\n\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\nimport { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';\n\nexport type DropdownMenuProps = DropdownMenuRootProps & {\n group?: MenuItemGroup;\n items?: MenuItem[];\n suppressNextTooltip?: MutableRefObject<boolean>;\n caller?: string;\n};\n\nconst DropdownMenuItem = ({\n item,\n onClick,\n __menuScope,\n}: MenuScopedProps<{\n item: MenuItem;\n onClick: (action: MenuAction, event: MouseEvent) => void;\n}>) => {\n // TODO(thure): handle other items.\n const action = item as MenuAction;\n const handleClick = useCallback((event: MouseEvent) => onClick(action, event), [action, onClick]);\n const { iconSize } = useMenu('DropdownMenuItem', __menuScope);\n return (\n <NaturalDropdownMenu.Item\n onClick={handleClick}\n classNames='gap-2'\n disabled={action.properties?.disabled}\n {...(action.properties?.testId && { 'data-testid': action.properties.testId })}\n >\n {action.properties?.icon && <Icon icon={action.properties!.icon} size={iconSize} />}\n <ActionLabel action={action} />\n </NaturalDropdownMenu.Item>\n );\n};\n\nconst DropdownMenuRoot = ({\n items: propsItems,\n group,\n open,\n defaultOpen,\n onOpenChange,\n suppressNextTooltip,\n caller,\n children,\n __menuScope,\n ...naturalProps\n}: MenuScopedProps<DropdownMenuProps>) => {\n const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({\n prop: open,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n const handleActionClick = useCallback(\n (action: MenuAction, event: MouseEvent) => {\n if (action.properties?.disabled) {\n return;\n }\n event.stopPropagation();\n // TODO(thure): Why does Dialog’s modal-ness cause issues if we don’t explicitly close the menu here?\n if (suppressNextTooltip) {\n suppressNextTooltip.current = true;\n }\n setOptionsMenuOpen(false);\n void action.data?.({ parent: group, caller });\n },\n [suppressNextTooltip, group, caller],\n );\n\n const items = useMenuItems(group, propsItems);\n\n return (\n <NaturalDropdownMenu.Root\n {...{\n open: optionsMenuOpen,\n onOpenChange: (nextOpen: boolean) => {\n if (!nextOpen && suppressNextTooltip) {\n suppressNextTooltip.current = true;\n }\n return setOptionsMenuOpen(nextOpen);\n },\n }}\n {...naturalProps}\n >\n {children}\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {items?.map((item) => <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />)}\n </NaturalDropdownMenu.Viewport>\n <NaturalDropdownMenu.Arrow />\n </NaturalDropdownMenu.Content>\n </NaturalDropdownMenu.Portal>\n </NaturalDropdownMenu.Root>\n );\n};\n\nexport const DropdownMenu = {\n Root: DropdownMenuRoot,\n Trigger: NaturalDropdownMenu.Trigger,\n VirtualTrigger: NaturalDropdownMenu.VirtualTrigger,\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type Action as GraphAction, type ActionGroup } from '@dxos/app-graph';\nimport { keySymbols } from '@dxos/keyboard';\nimport { toLocalizedString, useTranslation, type TFunction } from '@dxos/react-ui';\nimport { mx, descriptionText } from '@dxos/react-ui-theme';\n\nimport { translationKey } from '../translations';\nimport { type MenuActionProperties } from '../types';\nimport { getShortcut } from '../util';\n\ntype Action = GraphAction<MenuActionProperties> | ActionGroup<Omit<MenuActionProperties, 'variant'>>;\n\nexport const ActionLabel = ({ action }: { action: Action }) => {\n const shortcut = getShortcut(action);\n const { t } = useTranslation(translationKey);\n\n return (\n <>\n <span className='grow truncate'>{toLocalizedString(action.properties!.label, t)}</span>\n {shortcut && <span className={mx('shrink-0', descriptionText)}>{keySymbols(shortcut).join('')}</span>}\n </>\n );\n};\n\nexport const actionLabel = (action: Action, t: TFunction) => {\n const shortcut = getShortcut(action);\n return `${toLocalizedString(action.properties!.label, t)}${shortcut ? ` (${keySymbols(shortcut).join('')})` : ''}`;\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nexport const translationKey = 'menus';\n\nexport default [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const;\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, actionGroupSymbol, type ActionLike } from '@dxos/app-graph';\nimport { getHostPlatform } from '@dxos/util';\n\nimport {\n type MenuAction,\n type MenuActionProperties,\n type MenuItemGroup,\n type MenuItemGroupProperties,\n type MenuSeparator,\n} from './types';\n\nexport const getShortcut = (action: ActionLike) => {\n return typeof action.properties?.keyBinding === 'string'\n ? action.properties.keyBinding\n : action.properties?.keyBinding?.[getHostPlatform()];\n};\n\nexport const fallbackIcon = 'ph--placeholder--regular';\n\nexport const createMenuAction = <P extends {} = {}>(\n id: string,\n invoke: () => void,\n properties: P & MenuActionProperties,\n) =>\n ({\n id,\n type: ACTION_TYPE,\n properties,\n data: invoke,\n }) satisfies MenuAction;\n\nexport const createMenuItemGroup = <\n P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,\n>(\n id: string,\n properties: P,\n) =>\n ({\n id,\n type: ACTION_GROUP_TYPE,\n properties,\n data: actionGroupSymbol,\n }) satisfies MenuItemGroup;\n\nexport const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'gap' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [{ source, target: id }],\n});\n\nexport const createLineSeparator = (id: string = 'line', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'line' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [{ source, target: id }],\n});\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { createContextScope, type Scope } from '@radix-ui/react-context';\nimport React, { type PropsWithChildren, useMemo } from 'react';\n\nimport { type MenuContextValue, type MenuItem, type MenuItemGroup } from '../types';\n\nexport type MenuScopedProps<P> = P & { __menuScope?: Scope };\n\nconst MENU_NAME = 'GraphMenu';\n\nconst [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);\n\nconst [MenuContextProvider, useMenu] = createMenuContext<MenuContextValue>(MENU_NAME);\n\nexport const menuContextDefaults: MenuContextValue = {\n iconSize: 5,\n useGroupItems: () => null,\n};\n\nconst useMenuScope = createMenuScope();\n\nconst MenuProvider = ({\n children,\n useGroupItems = menuContextDefaults.useGroupItems,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n}: PropsWithChildren<Partial<MenuContextValue>>) => {\n const { scope } = useMenuScope(undefined);\n return (\n <MenuContextProvider useGroupItems={useGroupItems} iconSize={iconSize} attendableId={attendableId} scope={scope}>\n {children}\n </MenuContextProvider>\n );\n};\n\nexport const useMenuItems = (\n group?: MenuItemGroup,\n propsItems?: MenuItem[],\n consumerName: string = 'useMenuItemConsumer',\n __menuScope?: Scope,\n) => {\n const { useGroupItems } = useMenu(consumerName, __menuScope);\n const groupItems = useGroupItems(group);\n return useMemo(() => propsItems ?? groupItems ?? undefined, [propsItems, groupItems]);\n};\n\nexport { useMenu, createMenuScope, MenuProvider };\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useRef } from 'react';\n\nimport { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\n\nimport { actionLabel, ActionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\nimport { translationKey } from '../translations';\nimport {\n type MenuAction,\n type MenuItem,\n isMenuGroup,\n isSeparator,\n type MenuItemGroup,\n type MenuActionProperties,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n} from '../types';\n\nexport type ToolbarMenuDropdownMenuActionGroup = Omit<MenuActionProperties, 'variant' | 'icon'> & {\n variant: 'dropdownMenu';\n icon: string;\n applyActive?: boolean;\n};\n\nexport type ToolbarMenuToggleGroupActionGroup = Omit<MenuActionProperties, 'variant'> & {\n variant: 'toggleGroup';\n};\n\nexport type ToolbarMenuActionGroupProperties = (\n | ToolbarMenuDropdownMenuActionGroup\n | ToolbarMenuToggleGroupActionGroup\n) &\n (MenuSingleSelectActionGroup | MenuMultipleSelectActionGroup);\n\nexport type ToolbarMenuProps = ToolbarRootProps;\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuActionProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n action: MenuAction;\n};\n\nconst ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {\n const { iconSize } = useMenu('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const handleClick = useCallback(() => action.data?.(), [action]);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }\n : { children: <ActionLabel action={action} /> };\n return hidden ? null : (\n <Root\n key={action.id}\n disabled={disabled}\n onClick={handleClick}\n variant='ghost'\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as any)}\n classNames={classNames}\n />\n );\n};\n\nconst DropdownMenuToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const { iconOnly, disabled, testId } = group.properties;\n const suppressNextTooltip = useRef(false);\n const { t } = useTranslation(translationKey);\n const { iconSize } = useMenu('DropdownMenuToolbarItem', __menuScope);\n const items = useMenuItems(group, propsItems, 'DropdownMenuToolbarItem', __menuScope);\n const activeItem = items?.find((item) => !!(item as MenuAction).properties.checked);\n const icon =\n ((group.properties as any).applyActive &&\n // TODO(thure): Handle other menu item types.\n (activeItem as MenuAction)?.properties.icon) ||\n group.properties.icon;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: actionLabel(labelAction, t), caretDown: true, suppressNextTooltip }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='mis-1' />\n </>\n ),\n };\n return (\n <DropdownMenu.Root group={group} items={items} suppressNextTooltip={suppressNextTooltip}>\n <DropdownMenu.Trigger asChild>\n <Root variant='ghost' disabled={disabled} {...(rootProps as any)} {...(testId && { 'data-testid': testId })} />\n </DropdownMenu.Trigger>\n </DropdownMenu.Root>\n );\n};\n\nconst ToggleGroupItem = ({ group, action, __menuScope }: MenuScopedProps<ToolbarMenuActionProps>) => {\n const { iconSize } = useMenu('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const handleClick = useCallback(() => action.data?.({ parent: group }), [action, group]);\n const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }\n : { children: <ActionLabel action={action} /> };\n return hidden ? null : (\n <Root\n key={action.id}\n value={action.id as any}\n disabled={disabled}\n onClick={handleClick}\n variant='ghost'\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as any)}\n classNames={classNames}\n />\n );\n};\n\nconst ToggleGroupToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const items = useMenuItems(group, propsItems, 'ToggleGroupToolbarItem', __menuScope);\n const { selectCardinality, value } = group.properties;\n return (\n // TODO(thure): The type here is difficult to manage, what do?\n // @ts-ignore\n <NaturalToolbar.ToggleGroup type={selectCardinality} value={value}>\n {\n // TODO(thure): Handle other menu item types.\n (items as MenuAction[]).map((action) => (\n <ToggleGroupItem key={action.id} group={group} action={action} />\n ))\n }\n </NaturalToolbar.ToggleGroup>\n );\n};\n\nexport const ToolbarMenu = ({ __menuScope, classNames, ...props }: MenuScopedProps<ToolbarMenuProps>) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId } = useMenu('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n return (\n <NaturalToolbar.Root\n {...props}\n classNames={['p-1', !hasAttention && '[&>*]:opacity-20 !bg-transparent', classNames]}\n >\n {items?.map((item: MenuItem, i: number) =>\n isSeparator(item) ? (\n <NaturalToolbar.Separator key={i} variant={item.properties.variant} />\n ) : isMenuGroup(item) ? (\n item.properties.variant === 'dropdownMenu' ? (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <DropdownMenuToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />\n ) : (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <ToggleGroupToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />\n )\n ) : (\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n <ActionToolbarItem key={item.id} action={item as MenuAction} />\n ),\n )}\n </NaturalToolbar.Root>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Node, type Action, type ActionGroup, ACTION_GROUP_TYPE } from '@dxos/app-graph';\nimport { type ToolbarSeparatorProps, type Label, type IconButtonProps, type ClassNameValue } from '@dxos/react-ui';\n\nexport type MenuActionProperties = {\n label: Label;\n icon?: string;\n value?: string;\n disabled?: boolean;\n hidden?: boolean;\n iconOnly?: boolean;\n testId?: string;\n variant?: 'action' | 'toggle';\n checked?: boolean;\n classNames?: ClassNameValue;\n};\n\nexport type MenuItemGroupProperties = {\n label: Label;\n icon?: string;\n iconOnly?: boolean;\n};\n\nexport type MenuAction<P extends {} = {}> = Action<P & MenuActionProperties>;\n\nexport const MenuSeparatorType = '@dxos/react-ui-toolbar/separator' as const;\n\nexport type MenuSeparator = Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {\n type: typeof MenuSeparatorType;\n};\n\nexport const isSeparator = (node: Node): node is MenuSeparator => node.type === MenuSeparatorType;\n\nexport type MenuSingleSelectActionGroup = { selectCardinality: 'single'; value: string };\nexport type MenuMultipleSelectActionGroup = { selectCardinality: 'multiple'; value: string[] };\n\nexport type MenuItemGroup<P extends Record<string, any> = Record<string, any>> = ActionGroup<P>;\n\nexport const isMenuGroup = (node: Node): node is MenuItemGroup => node.type === ACTION_GROUP_TYPE;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;\n\nexport type MenuItemsResolver = (group?: MenuItemGroup) => MenuItem[] | null;\n\nexport type MenuContextValue = {\n useGroupItems: MenuItemsResolver;\n iconSize: IconButtonProps['size'];\n attendableId?: string;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { RegistryContext, useRxValue } from '@effect-rx/rx-react';\nimport { useSignalEffect } from '@preact/signals-react';\nimport { useCallback, useContext, useState } from 'react';\n\nimport { type Edge, type Edges, Graph, type NodeArg, type Node, ROOT_ID } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup } from '../types';\n\nconst edgesArrayToRecord = (edges: Edge[]): Record<string, Edges> => {\n return Object.fromEntries(\n Object.entries(\n edges.reduce((acc: Record<string, { inbound: string[]; outbound: string[] }>, { source, target }) => {\n if (!acc[source]) {\n acc[source] = { inbound: [], outbound: [] };\n }\n if (!acc[target]) {\n acc[target] = { inbound: [], outbound: [] };\n }\n\n const sourceEdges = acc[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = acc[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n\n return acc;\n }, {}),\n ),\n );\n};\n\nexport type ActionGraphNodes = NodeArg<any>[];\nexport type ActionGraphEdges = Edge[];\nexport type ActionGraphProps = { nodes: ActionGraphNodes; edges: ActionGraphEdges };\n\nexport const useMenuActions = (actionCreator: () => ActionGraphProps) => {\n const registry = useContext(RegistryContext);\n const initialMenuGraphProps = actionCreator();\n\n const [graph] = useState(\n new Graph({\n registry,\n nodes: initialMenuGraphProps.nodes as Node[],\n edges: edgesArrayToRecord(initialMenuGraphProps.edges),\n }),\n );\n\n // TODO(wittjosiah): Remove dependence on signals.\n useSignalEffect(() => {\n const menuGraphProps = actionCreator();\n graph.addNodes(menuGraphProps.nodes);\n graph.addEdges(menuGraphProps.edges);\n });\n\n const useGroupItems = useCallback(\n (sourceNode?: MenuItemGroup) => {\n const items = useRxValue(graph.connections(sourceNode?.id || ROOT_ID)) as MenuItem[];\n return items;\n },\n [graph],\n );\n\n return { useGroupItems };\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["useControllableState", "React", "useCallback", "DropdownMenu", "NaturalDropdownMenu", "Icon", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "descriptionText", "translationKey", "ACTION_GROUP_TYPE", "ACTION_TYPE", "actionGroupSymbol", "getHostPlatform", "getShortcut", "action", "properties", "keyBinding", "getHostPlatform", "createMenuAction", "id", "invoke", "properties", "type", "ACTION_TYPE", "data", "createMenuItemGroup", "ACTION_GROUP_TYPE", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "createLineSeparator", "ActionLabel", "action", "shortcut", "getShortcut", "t", "useTranslation", "translationKey", "span", "className", "toLocalizedString", "properties", "label", "mx", "descriptionText", "keySymbols", "join", "actionLabel", "createContextScope", "React", "useMemo", "MENU_NAME", "createMenuContext", "createMenuScope", "createContextScope", "MenuContextProvider", "useMenu", "menuContextDefaults", "iconSize", "useGroupItems", "useMenuScope", "MenuProvider", "children", "attendableId", "scope", "undefined", "React", "useMenuItems", "group", "propsItems", "consumerName", "__menuScope", "groupItems", "useMemo", "DropdownMenuItem", "item", "onClick", "__menuScope", "action", "handleClick", "useCallback", "event", "iconSize", "useMenu", "React", "NaturalDropdownMenu", "Item", "classNames", "disabled", "properties", "testId", "icon", "Icon", "size", "ActionLabel", "DropdownMenuRoot", "items", "propsItems", "group", "open", "defaultOpen", "onOpenChange", "suppressNextTooltip", "caller", "children", "naturalProps", "optionsMenuOpen", "setOptionsMenuOpen", "useControllableState", "prop", "defaultProp", "onChange", "handleActionClick", "stopPropagation", "current", "data", "parent", "useMenuItems", "Root", "nextOpen", "Portal", "Content", "Viewport", "map", "key", "id", "Arrow", "DropdownMenu", "Trigger", "VirtualTrigger", "React", "useCallback", "useRef", "Icon", "Toolbar", "NaturalToolbar", "useTranslation", "useAttention", "ACTION_GROUP_TYPE", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "ACTION_GROUP_TYPE", "ActionToolbarItem", "action", "__menuScope", "iconSize", "useMenu", "t", "useTranslation", "translationKey", "handleClick", "useCallback", "data", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "properties", "Root", "NaturalToolbar", "IconButton", "Button", "rootProps", "size", "label", "actionLabel", "children", "React", "ActionLabel", "key", "id", "onClick", "variant", "DropdownMenuToolbarItem", "group", "items", "propsItems", "suppressNextTooltip", "useRef", "useMenuItems", "activeItem", "find", "item", "checked", "applyActive", "labelAction", "caretDown", "Icon", "DropdownMenu", "Trigger", "asChild", "ToggleGroupItem", "parent", "ToggleGroupIconItem", "value", "ToggleGroupToolbarItem", "selectCardinality", "ToggleGroup", "type", "map", "ToolbarMenu", "props", "undefined", "attendableId", "hasAttention", "useAttention", "i", "isSeparator", "Separator", "isMenuGroup", "RegistryContext", "useRxValue", "useSignalEffect", "useCallback", "useContext", "useState", "Graph", "ROOT_ID", "edgesArrayToRecord", "edges", "Object", "fromEntries", "entries", "reduce", "acc", "source", "target", "inbound", "outbound", "sourceEdges", "includes", "push", "targetEdges", "useMenuActions", "actionCreator", "registry", "useContext", "RegistryContext", "initialMenuGraphProps", "graph", "useState", "Graph", "nodes", "useSignalEffect", "menuGraphProps", "addNodes", "addEdges", "useGroupItems", "useCallback", "sourceNode", "items", "useRxValue", "connections", "id", "ROOT_ID"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/ui/react-ui-menu/src/translations.ts":{"bytes":909,"imports":[],"format":"esm"},"packages/ui/react-ui-menu/src/util.ts":{"bytes":6574,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/ActionLabel.tsx":{"bytes":3310,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"packages/ui/react-ui-menu/src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"packages/ui/react-ui-menu/src/components/MenuContext.tsx":{"bytes":5704,"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx":{"bytes":11213,"imports":[{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"packages/ui/react-ui-menu/src/defs.ts":{"bytes":3442,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx":{"bytes":21829,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"},{"path":"packages/ui/react-ui-menu/src/defs.ts","kind":"import-statement","original":"../defs"}],"format":"esm"},"packages/ui/react-ui-menu/src/components/index.ts":{"bytes":718,"imports":[{"path":"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"packages/ui/react-ui-menu/src/hooks.ts":{"bytes":7464,"imports":[{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/index.ts":{"bytes":1113,"imports":[{"path":"packages/ui/react-ui-menu/src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"packages/ui/react-ui-menu/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/ui/react-ui-menu/src/hooks.ts","kind":"import-statement","original":"./hooks"},{"path":"packages/ui/react-ui-menu/src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"}},"outputs":{"packages/ui/react-ui-menu/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":31412},"packages/ui/react-ui-menu/dist/lib/browser/index.mjs":{"imports":[{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"exports":["DropdownMenu","MenuProvider","MenuSeparatorType","ToolbarMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","createMenuScope","isMenuGroup","isSeparator","menuContextDefaults","useMenu","useMenuActions","useMenuItems"],"entryPoint":"packages/ui/react-ui-menu/src/index.ts","inputs":{"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx":{"bytesInOutput":2542},"packages/ui/react-ui-menu/src/components/ActionLabel.tsx":{"bytesInOutput":667},"packages/ui/react-ui-menu/src/translations.ts":{"bytesInOutput":118},"packages/ui/react-ui-menu/src/util.ts":{"bytesInOutput":1125},"packages/ui/react-ui-menu/src/components/MenuContext.tsx":{"bytesInOutput":1119},"packages/ui/react-ui-menu/src/components/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx":{"bytesInOutput":5542},"packages/ui/react-ui-menu/src/defs.ts":{"bytesInOutput":258},"packages/ui/react-ui-menu/src/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-menu/src/hooks.ts":{"bytesInOutput":1519}},"bytes":13814}}}
1
+ {"inputs":{"packages/ui/react-ui-menu/src/translations.ts":{"bytes":909,"imports":[],"format":"esm"},"packages/ui/react-ui-menu/src/util.ts":{"bytes":5996,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/ActionLabel.tsx":{"bytes":4200,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"packages/ui/react-ui-menu/src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"packages/ui/react-ui-menu/src/components/MenuContext.tsx":{"bytes":5088,"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx":{"bytes":11327,"imports":[{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"packages/ui/react-ui-menu/src/types.ts":{"bytes":3243,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx":{"bytes":22596,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-menu/src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"},{"path":"packages/ui/react-ui-menu/src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"packages/ui/react-ui-menu/src/types.ts","kind":"import-statement","original":"../types"}],"format":"esm"},"packages/ui/react-ui-menu/src/components/index.ts":{"bytes":718,"imports":[{"path":"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"},{"path":"packages/ui/react-ui-menu/src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"packages/ui/react-ui-menu/src/hooks/useMenuActions.ts":{"bytes":7433,"imports":[{"path":"@effect-rx/rx-react","kind":"import-statement","external":true},{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/react-ui-menu/src/hooks/index.ts":{"bytes":521,"imports":[{"path":"packages/ui/react-ui-menu/src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"packages/ui/react-ui-menu/src/index.ts":{"bytes":1114,"imports":[{"path":"packages/ui/react-ui-menu/src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"packages/ui/react-ui-menu/src/hooks/index.ts","kind":"import-statement","original":"./hooks"},{"path":"packages/ui/react-ui-menu/src/types.ts","kind":"import-statement","original":"./types"},{"path":"packages/ui/react-ui-menu/src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"}},"outputs":{"packages/ui/react-ui-menu/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":31698},"packages/ui/react-ui-menu/dist/lib/browser/index.mjs":{"imports":[{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@effect-rx/rx-react","kind":"import-statement","external":true},{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"exports":["DropdownMenu","MenuProvider","MenuSeparatorType","ToolbarMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","createMenuScope","isMenuGroup","isSeparator","menuContextDefaults","useMenu","useMenuActions","useMenuItems"],"entryPoint":"packages/ui/react-ui-menu/src/index.ts","inputs":{"packages/ui/react-ui-menu/src/components/DropdownMenu.tsx":{"bytesInOutput":2562},"packages/ui/react-ui-menu/src/components/ActionLabel.tsx":{"bytesInOutput":862},"packages/ui/react-ui-menu/src/translations.ts":{"bytesInOutput":118},"packages/ui/react-ui-menu/src/util.ts":{"bytesInOutput":1113},"packages/ui/react-ui-menu/src/components/MenuContext.tsx":{"bytesInOutput":1028},"packages/ui/react-ui-menu/src/components/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx":{"bytesInOutput":5638},"packages/ui/react-ui-menu/src/types.ts":{"bytesInOutput":258},"packages/ui/react-ui-menu/src/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-menu/src/hooks/useMenuActions.ts":{"bytesInOutput":1544},"packages/ui/react-ui-menu/src/hooks/index.ts":{"bytesInOutput":0}},"bytes":14063}}}