@dxos/react-ui-menu 0.8.4-main.21d9917 → 0.8.4-main.2244d791bb

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.
@@ -110,12 +110,13 @@ var menuContextDefaults = {
110
110
  onAction: void 0
111
111
  };
112
112
  var useMenuScope = createMenuScope();
113
- var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, onAction }) => {
113
+ var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
114
114
  const { scope } = useMenuScope(void 0);
115
115
  return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
116
116
  useGroupItems,
117
117
  iconSize,
118
118
  attendableId,
119
+ alwaysActive,
119
120
  onAction,
120
121
  scope
121
122
  }, children);
@@ -201,7 +202,7 @@ var DropdownMenu = {
201
202
  import React4, { Fragment, useCallback as useCallback2 } from "react";
202
203
  import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
203
204
  import { useAttention } from "@dxos/react-ui-attention";
204
- import { mx as mx2, textBlockWidth, toolbarInactive, toolbarLayout } from "@dxos/ui-theme";
205
+ import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/ui-theme";
205
206
 
206
207
  // src/types.ts
207
208
  import { Node as Node2 } from "@dxos/app-graph";
@@ -352,7 +353,7 @@ var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
352
353
  };
353
354
  var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp, ...props }) => {
354
355
  const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
355
- const { attendableId } = useMenu("ToolbarMenu", __menuScope);
356
+ const { attendableId, alwaysActive } = useMenu("ToolbarMenu", __menuScope);
356
357
  const { hasAttention } = useAttention(attendableId);
357
358
  const InnerRoot = textBlockWidthProp ? "div" : Fragment;
358
359
  const innerRootProps = textBlockWidthProp ? {
@@ -362,9 +363,10 @@ var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp
362
363
  return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
363
364
  ...props,
364
365
  classNames: [
365
- attendableId && !hasAttention && toolbarInactive,
366
+ attendableId,
366
367
  classNames
367
368
  ],
369
+ disabled: !alwaysActive && !hasAttention,
368
370
  layoutManaged: textBlockWidthProp
369
371
  }, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React4.createElement(ToolbarMenuItem, {
370
372
  key: item.id ?? i,
@@ -397,48 +399,21 @@ var ToolbarMenuItem = ({ item }) => {
397
399
  import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
398
400
  import { useCallback as useCallback3, useContext, useRef } from "react";
399
401
  import { Graph, Node as Node3 } from "@dxos/app-graph";
400
- var edgesArrayToRecord = (edges) => {
401
- return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
402
- if (!acc[source]) {
403
- acc[source] = {
404
- inbound: [],
405
- outbound: []
406
- };
407
- }
408
- if (!acc[target]) {
409
- acc[target] = {
410
- inbound: [],
411
- outbound: []
412
- };
413
- }
414
- const sourceEdges = acc[source];
415
- if (!sourceEdges.outbound.includes(target)) {
416
- sourceEdges.outbound.push(target);
417
- }
418
- const targetEdges = acc[target];
419
- if (!targetEdges.inbound.includes(source)) {
420
- targetEdges.inbound.push(source);
421
- }
422
- return acc;
423
- }, {})));
424
- };
425
402
  var useMenuActions = (props) => {
426
403
  const registry = useContext(RegistryContext);
427
404
  const menuGraphProps = useAtomValue(props);
428
405
  const graphRef = useRef(null);
429
- if (!graphRef.current) {
430
- graphRef.current = Graph.make({
431
- registry,
432
- nodes: menuGraphProps.nodes,
433
- edges: edgesArrayToRecord(menuGraphProps.edges)
406
+ if (!graphRef.current || graphRef.current.props !== menuGraphProps) {
407
+ const newGraph = Graph.make({
408
+ registry
434
409
  });
410
+ newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
411
+ graphRef.current = {
412
+ graph: newGraph,
413
+ props: menuGraphProps
414
+ };
435
415
  }
436
- const graph = graphRef.current;
437
- const prevPropsRef = useRef(menuGraphProps);
438
- if (prevPropsRef.current !== menuGraphProps) {
439
- prevPropsRef.current = menuGraphProps;
440
- graph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
441
- }
416
+ const graph = graphRef.current.graph;
442
417
  const useGroupItems = useCallback3((sourceNode) => {
443
418
  const items = useAtomValue(graph.connections(sourceNode?.id || Node3.RootId));
444
419
  return items;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/DropdownMenu.tsx", "../../../src/util.ts", "../../../src/components/ActionLabel.tsx", "../../../src/translations.ts", "../../../src/components/MenuContext.tsx", "../../../src/components/ToolbarMenu.tsx", "../../../src/types.ts", "../../../src/hooks/useMenuActions.ts", "../../../src/builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type MouseEvent, useCallback } from 'react';\n\nimport { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';\n\nimport { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';\nimport { executeMenuAction } from '../util';\n\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\n\nexport type DropdownMenuProps = DropdownMenuRootProps & {\n group?: MenuItemGroup;\n items?: MenuItem[];\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 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 { 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 setOptionsMenuOpen(false);\n if (onAction) {\n onAction(action, { parent: group, caller });\n } else {\n void executeMenuAction(action, { parent: group, caller });\n }\n },\n [group, caller, onAction],\n );\n\n const items = useMenuItems(group, propsItems);\n\n return (\n <NaturalDropdownMenu.Root open={optionsMenuOpen} onOpenChange={setOptionsMenuOpen} {...naturalProps}>\n {children}\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {items?.map((item) => (\n <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />\n ))}\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 * as Effect from 'effect/Effect';\n\nimport { Node } from '@dxos/app-graph';\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { type MenuActionProperties, type MenuItemGroupProperties } from '@dxos/ui-types';\nimport { getHostPlatform } from '@dxos/util';\n\nimport { type MenuAction, type MenuItemGroup, type MenuSeparator } from './types';\n\n/**\n * Execute a menu action's Effect with its captured context.\n * This provides the `_actionContext` layer if available.\n */\nexport const executeMenuAction = async (action: MenuAction, params: Node.InvokeProps = {}): Promise<void> => {\n let effect = action.data(params);\n\n // Provide captured action context if available.\n if (action._actionContext) {\n effect = effect.pipe(Effect.provide(action._actionContext));\n }\n\n await runAndForwardErrors(effect);\n};\n\nexport const getShortcut = (action: Node.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: Node.ActionType,\n properties,\n data: () => Effect.sync(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: Node.ActionGroupType,\n properties,\n data: Node.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: [\n {\n source,\n target: id,\n },\n ],\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 React from 'react';\n\nimport { type Node } from '@dxos/app-graph';\nimport { keySymbols } from '@dxos/keyboard';\nimport { type TFunction, toLocalizedString, useTranslation } from '@dxos/react-ui';\nimport { descriptionText, mx } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport { getShortcut } from '../util';\n\ntype Action = Node.Action<MenuActionProperties> | Node.ActionGroup<Omit<MenuActionProperties, 'variant'>>;\n\nexport const ActionLabel = ({ action }: { action: Action }) => {\n const { t } = useTranslation(translationKey);\n const shortcut = getShortcut(action);\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\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-menu';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const satisfies Resource[];\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Scope, createContextScope } 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 = 'Menu';\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 onAction: undefined,\n};\n\nconst useMenuScope = createMenuScope();\n\ntype MenuProviderProps = PropsWithChildren<Partial<MenuContextValue>>;\n\nconst MenuProvider = ({\n children,\n useGroupItems = menuContextDefaults.useGroupItems,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n onAction,\n}: MenuProviderProps) => {\n const { scope } = useMenuScope(undefined);\n return (\n <MenuContextProvider\n useGroupItems={useGroupItems}\n iconSize={iconSize}\n attendableId={attendableId}\n onAction={onAction}\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 { useGroupItems } = useMenu(consumerName, __menuScope);\n const groupItems = useGroupItems(group);\n return useMemo(() => propsItems ?? groupItems ?? undefined, [propsItems, groupItems]);\n};\n\nexport { useMenu, createMenuScope, MenuProvider };\n\nexport type { MenuProviderProps };\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { Fragment, useCallback } from 'react';\n\nimport { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx, textBlockWidth, toolbarInactive, toolbarLayout } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport {\n type MenuAction,\n type MenuItem,\n type MenuItemGroup,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n isMenuGroup,\n isSeparator,\n} from '../types';\nimport { executeMenuAction } from '../util';\n\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\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 & { textBlockWidth?: boolean };\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, onAction } = useMenu('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n\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\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\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 { 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 ? {\n icon,\n size: iconSize,\n iconOnly,\n label: actionLabel(labelAction, t),\n caretDown: true,\n }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='mis-1' />\n </>\n ),\n };\n\n return (\n <DropdownMenu.Root group={group} items={items}>\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, onAction } = useMenu('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, { parent: group });\n } else {\n void executeMenuAction(action, { parent: group });\n }\n }, [action, group, onAction]);\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\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\n return (\n // TODO(thure): Fix.\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\n// TODO(burdon): Reconcile with react-ui/Toolbar (incl. textBlockWidth)\nexport const ToolbarMenu = ({\n __menuScope,\n classNames,\n textBlockWidth: textBlockWidthProp,\n ...props\n}: MenuScopedProps<ToolbarMenuProps>) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId } = useMenu('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n const InnerRoot = textBlockWidthProp ? 'div' : Fragment;\n const innerRootProps = textBlockWidthProp\n ? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'bs-full') }\n : {};\n\n return (\n <NaturalToolbar.Root\n {...props}\n classNames={[attendableId && !hasAttention && toolbarInactive, classNames]}\n layoutManaged={textBlockWidthProp}\n >\n <InnerRoot {...innerRootProps}>\n {items?.map((item: MenuItem, i: number) => (\n <ToolbarMenuItem key={item.id ?? i} item={item} />\n ))}\n </InnerRoot>\n </NaturalToolbar.Root>\n );\n};\n\nconst ToolbarMenuItem = ({ item }: { item: MenuItem }) => {\n if (isSeparator(item)) {\n return <NaturalToolbar.Separator variant={item.properties.variant} />;\n }\n\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n if (isMenuGroup(item)) {\n if (item.properties.variant === 'dropdownMenu') {\n return <DropdownMenuToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n } else {\n return <ToggleGroupToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n }\n }\n\n return <ActionToolbarItem action={item as MenuAction} />;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Node } from '@dxos/app-graph';\nimport { type IconButtonProps, type ToolbarSeparatorProps } from '@dxos/react-ui';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nexport type MenuAction<P extends {} = {}> = Node.Action<P & MenuActionProperties>;\n\nexport const MenuSeparatorType = '@dxos/react-ui-toolbar/separator' as const;\n\nexport type MenuSeparator = Node.Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {\n type: typeof MenuSeparatorType;\n};\n\nexport const isSeparator = (node: 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>> = Node.ActionGroup<P>;\n\nexport const isMenuGroup = (node: Node.Node): node is MenuItemGroup => node.type === Node.ActionGroupType;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;\n\nexport type MenuItemsResolver = (group?: MenuItemGroup) => MenuItem[] | null;\n\nexport type ActionExecutor = (action: MenuAction, params: Node.InvokeProps) => void;\n\nexport type MenuContextValue = {\n useGroupItems: MenuItemsResolver;\n iconSize: IconButtonProps['size'];\n attendableId?: string;\n /** Optional action executor. If provided, will be used instead of default execution. */\n onAction?: ActionExecutor;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { useCallback, useContext, useRef } from 'react';\n\nimport { Graph, Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup } from '../types';\n\nconst edgesArrayToRecord = (edges: Graph.Edge[]): Record<string, Graph.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 = Node.NodeArg<any>[];\nexport type ActionGraphEdges = Graph.Edge[];\nexport type ActionGraphProps = {\n nodes: ActionGraphNodes;\n edges: ActionGraphEdges;\n};\n\nexport type MenuActions = {\n useGroupItems: (sourceNode?: MenuItemGroup) => MenuItem[];\n};\n\nexport const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions => {\n const registry = useContext(RegistryContext);\n const menuGraphProps = useAtomValue(props);\n\n // Create graph once, then update it when props change.\n const graphRef = useRef<Graph.WritableGraph | null>(null);\n if (!graphRef.current) {\n graphRef.current = Graph.make({\n registry,\n nodes: menuGraphProps.nodes as Node.Node[],\n edges: edgesArrayToRecord(menuGraphProps.edges),\n });\n }\n const graph = graphRef.current;\n\n // Update graph nodes synchronously when props change (before render completes).\n // Using a ref to track the previous value to detect changes.\n const prevPropsRef = useRef(menuGraphProps);\n if (prevPropsRef.current !== menuGraphProps) {\n prevPropsRef.current = menuGraphProps;\n graph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));\n }\n\n const useGroupItems = useCallback(\n (sourceNode?: MenuItemGroup) => {\n const items = useAtomValue(graph.connections(sourceNode?.id || Node.RootId)) as MenuItem[];\n return items;\n },\n [graph],\n );\n\n return { useGroupItems };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport type { MenuActionProperties, MenuItemGroupProperties } from '@dxos/ui-types';\n\nimport type { ActionGraphProps } from './hooks';\nimport { createMenuAction, createMenuItemGroup } from './util';\n\nexport interface ActionGroupBuilder {\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;\n group<P extends {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this;\n}\n\nexport interface MenuBuilder extends ActionGroupBuilder {\n root(props: MenuItemGroupProperties): this;\n build(): ActionGraphProps;\n}\n\nexport const MenuBuilder = Object.freeze({\n make: (): MenuBuilder => new MenuBuilderImpl({ nodes: [], edges: [] }, 'root'),\n});\n\nclass MenuBuilderImpl implements MenuBuilder {\n constructor(\n private readonly _data: ActionGraphProps,\n private readonly _rootId: string,\n ) {}\n\n root(props: MenuItemGroupProperties): this {\n invariant(this._rootId === 'root', 'Root group can only be at the top level');\n invariant(this._data.nodes.find((node) => node.id === 'root') === undefined, 'Root group can only be created once');\n this._data.nodes.push(createMenuItemGroup('root', props));\n return this;\n }\n\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this {\n this._data.nodes.push(createMenuAction(id, invoke, props));\n this._data.edges.push({ source: this._rootId, target: id });\n return this;\n }\n\n group<P extends {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this {\n this._data.nodes.push(createMenuItemGroup(id, props));\n this._data.edges.push({ source: this._rootId, target: id });\n cb(new MenuBuilderImpl(this._data, id));\n return this;\n }\n\n build(): ActionGraphProps {\n return this._data;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["useControllableState", "React", "useCallback", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "runAndForwardErrors", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "getHostPlatform", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "descriptionText", "mx", "translationKey", "translations", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "descriptionText", "keySymbols", "join", "actionLabel", "createContextScope", "React", "useMemo", "MENU_NAME", "createMenuContext", "createMenuScope", "createContextScope", "MenuContextProvider", "useMenu", "menuContextDefaults", "iconSize", "useGroupItems", "onAction", "undefined", "useMenuScope", "MenuProvider", "children", "attendableId", "scope", "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", "caller", "children", "naturalProps", "optionsMenuOpen", "setOptionsMenuOpen", "useControllableState", "prop", "defaultProp", "onChange", "onAction", "handleActionClick", "stopPropagation", "parent", "executeMenuAction", "useMenuItems", "Root", "Portal", "Content", "Viewport", "map", "key", "id", "Arrow", "DropdownMenu", "Trigger", "VirtualTrigger", "React", "Fragment", "useCallback", "Icon", "Toolbar", "NaturalToolbar", "useTranslation", "useAttention", "mx", "textBlockWidth", "toolbarInactive", "toolbarLayout", "Node", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "Node", "ActionGroupType", "ActionToolbarItem", "action", "__menuScope", "iconSize", "onAction", "useMenu", "t", "useTranslation", "translationKey", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "properties", "Root", "NaturalToolbar", "IconButton", "Button", "rootProps", "size", "label", "actionLabel", "children", "React", "ActionLabel", "handleClick", "useCallback", "executeMenuAction", "key", "id", "onClick", "variant", "DropdownMenuToolbarItem", "group", "items", "propsItems", "useMenuItems", "activeItem", "find", "item", "checked", "applyActive", "labelAction", "caretDown", "Icon", "DropdownMenu", "Trigger", "asChild", "ToggleGroupItem", "parent", "ToggleGroupIconItem", "value", "ToggleGroupToolbarItem", "selectCardinality", "ToggleGroup", "type", "map", "ToolbarMenu", "textBlockWidth", "textBlockWidthProp", "props", "undefined", "attendableId", "hasAttention", "useAttention", "InnerRoot", "Fragment", "innerRootProps", "role", "className", "mx", "toolbarLayout", "toolbarInactive", "layoutManaged", "i", "ToolbarMenuItem", "isSeparator", "Separator", "isMenuGroup", "RegistryContext", "useAtomValue", "useCallback", "useContext", "useRef", "Graph", "Node", "edgesArrayToRecord", "edges", "Object", "fromEntries", "entries", "reduce", "acc", "source", "target", "inbound", "outbound", "sourceEdges", "includes", "push", "targetEdges", "useMenuActions", "props", "registry", "useContext", "RegistryContext", "menuGraphProps", "useAtomValue", "graphRef", "useRef", "current", "Graph", "make", "nodes", "graph", "prevPropsRef", "pipe", "addNodes", "addEdges", "useGroupItems", "useCallback", "sourceNode", "items", "connections", "id", "Node", "RootId", "invariant", "MenuBuilder", "Object", "freeze", "make", "MenuBuilderImpl", "nodes", "edges", "_data", "_rootId", "root", "props", "invariant", "find", "node", "id", "undefined", "push", "createMenuItemGroup", "action", "invoke", "createMenuAction", "source", "target", "group", "cb", "build"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type MouseEvent, useCallback } from 'react';\n\nimport { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';\n\nimport { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';\nimport { executeMenuAction } from '../util';\n\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\n\nexport type DropdownMenuProps = DropdownMenuRootProps & {\n group?: MenuItemGroup;\n items?: MenuItem[];\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 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 { 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 setOptionsMenuOpen(false);\n if (onAction) {\n onAction(action, { parent: group, caller });\n } else {\n void executeMenuAction(action, { parent: group, caller });\n }\n },\n [group, caller, onAction],\n );\n\n const items = useMenuItems(group, propsItems);\n\n return (\n <NaturalDropdownMenu.Root open={optionsMenuOpen} onOpenChange={setOptionsMenuOpen} {...naturalProps}>\n {children}\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {items?.map((item) => (\n <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />\n ))}\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 * as Effect from 'effect/Effect';\n\nimport { Node } from '@dxos/app-graph';\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { type MenuActionProperties, type MenuItemGroupProperties } from '@dxos/ui-types';\nimport { getHostPlatform } from '@dxos/util';\n\nimport { type MenuAction, type MenuItemGroup, type MenuSeparator } from './types';\n\n/**\n * Execute a menu action's Effect with its captured context.\n * This provides the `_actionContext` layer if available.\n */\nexport const executeMenuAction = async (action: MenuAction, params: Node.InvokeProps = {}): Promise<void> => {\n let effect = action.data(params);\n\n // Provide captured action context if available.\n if (action._actionContext) {\n effect = effect.pipe(Effect.provide(action._actionContext));\n }\n\n await runAndForwardErrors(effect);\n};\n\nexport const getShortcut = (action: Node.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: Node.ActionType,\n properties,\n data: () => Effect.sync(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: Node.ActionGroupType,\n properties,\n data: Node.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: [\n {\n source,\n target: id,\n },\n ],\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 React from 'react';\n\nimport { type Node } from '@dxos/app-graph';\nimport { keySymbols } from '@dxos/keyboard';\nimport { type TFunction, toLocalizedString, useTranslation } from '@dxos/react-ui';\nimport { descriptionText, mx } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport { getShortcut } from '../util';\n\ntype Action = Node.Action<MenuActionProperties> | Node.ActionGroup<Omit<MenuActionProperties, 'variant'>>;\n\nexport const ActionLabel = ({ action }: { action: Action }) => {\n const { t } = useTranslation(translationKey);\n const shortcut = getShortcut(action);\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\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-menu';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const satisfies Resource[];\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Scope, createContextScope } 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 = 'Menu';\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 onAction: undefined,\n};\n\nconst useMenuScope = createMenuScope();\n\ntype MenuProviderProps = PropsWithChildren<Partial<MenuContextValue>>;\n\nconst MenuProvider = ({\n children,\n useGroupItems = menuContextDefaults.useGroupItems,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n alwaysActive,\n onAction,\n}: MenuProviderProps) => {\n const { scope } = useMenuScope(undefined);\n return (\n <MenuContextProvider\n useGroupItems={useGroupItems}\n iconSize={iconSize}\n attendableId={attendableId}\n alwaysActive={alwaysActive}\n onAction={onAction}\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 { useGroupItems } = useMenu(consumerName, __menuScope);\n const groupItems = useGroupItems(group);\n return useMemo(() => propsItems ?? groupItems ?? undefined, [propsItems, groupItems]);\n};\n\nexport { useMenu, createMenuScope, MenuProvider };\n\nexport type { MenuProviderProps };\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { Fragment, useCallback } from 'react';\n\nimport { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx, textBlockWidth, toolbarLayout } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport {\n type MenuAction,\n type MenuItem,\n type MenuItemGroup,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n isMenuGroup,\n isSeparator,\n} from '../types';\nimport { executeMenuAction } from '../util';\n\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';\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 & { textBlockWidth?: boolean };\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, onAction } = useMenu('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n\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\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\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 { 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 ? {\n icon,\n size: iconSize,\n iconOnly,\n label: actionLabel(labelAction, t),\n caretDown: true,\n }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='mis-1' />\n </>\n ),\n };\n\n return (\n <DropdownMenu.Root group={group} items={items}>\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, onAction } = useMenu('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, { parent: group });\n } else {\n void executeMenuAction(action, { parent: group });\n }\n }, [action, group, onAction]);\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\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\n return (\n // TODO(thure): Fix.\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\n// TODO(burdon): Reconcile with react-ui/Toolbar (incl. textBlockWidth)\nexport const ToolbarMenu = ({\n __menuScope,\n classNames,\n textBlockWidth: textBlockWidthProp,\n ...props\n}: MenuScopedProps<ToolbarMenuProps>) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId, alwaysActive } = useMenu('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n const InnerRoot = textBlockWidthProp ? 'div' : Fragment;\n const innerRootProps = textBlockWidthProp\n ? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'bs-full') }\n : {};\n\n return (\n <NaturalToolbar.Root\n {...props}\n classNames={[attendableId, classNames]}\n disabled={!alwaysActive && !hasAttention}\n layoutManaged={textBlockWidthProp}\n >\n <InnerRoot {...innerRootProps}>\n {items?.map((item: MenuItem, i: number) => (\n <ToolbarMenuItem key={item.id ?? i} item={item} />\n ))}\n </InnerRoot>\n </NaturalToolbar.Root>\n );\n};\n\nconst ToolbarMenuItem = ({ item }: { item: MenuItem }) => {\n if (isSeparator(item)) {\n return <NaturalToolbar.Separator variant={item.properties.variant} />;\n }\n\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n if (isMenuGroup(item)) {\n if (item.properties.variant === 'dropdownMenu') {\n return <DropdownMenuToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n } else {\n return <ToggleGroupToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n }\n }\n\n return <ActionToolbarItem action={item as MenuAction} />;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Node } from '@dxos/app-graph';\nimport { type IconButtonProps, type ToolbarSeparatorProps } from '@dxos/react-ui';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nexport type MenuAction<P extends {} = {}> = Node.Action<P & MenuActionProperties>;\n\nexport const MenuSeparatorType = '@dxos/react-ui-toolbar/separator' as const;\n\nexport type MenuSeparator = Node.Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {\n type: typeof MenuSeparatorType;\n};\n\nexport const isSeparator = (node: 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>> = Node.ActionGroup<P>;\n\nexport const isMenuGroup = (node: Node.Node): node is MenuItemGroup => node.type === Node.ActionGroupType;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;\n\nexport type MenuItemsResolver = (group?: MenuItemGroup) => MenuItem[] | null;\n\nexport type ActionExecutor = (action: MenuAction, params: Node.InvokeProps) => void;\n\nexport type MenuContextValue = {\n useGroupItems: MenuItemsResolver;\n iconSize: IconButtonProps['size'];\n attendableId?: string;\n /** If true, the menu is always active regardless of attention state. */\n alwaysActive?: boolean;\n /** Optional action executor. If provided, will be used instead of default execution. */\n onAction?: ActionExecutor;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { useCallback, useContext, useRef } from 'react';\n\nimport { Graph, Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup } from '../types';\n\nexport type ActionGraphNodes = Node.NodeArg<any>[];\nexport type ActionGraphEdges = Graph.Edge[];\nexport type ActionGraphProps = {\n nodes: ActionGraphNodes;\n edges: ActionGraphEdges;\n};\n\nexport type MenuActions = {\n useGroupItems: (sourceNode?: MenuItemGroup) => MenuItem[];\n};\n\nexport const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions => {\n const registry = useContext(RegistryContext);\n const menuGraphProps = useAtomValue(props);\n\n // Create a new graph whenever props change to preserve correct order.\n // (Graph.addEdges appends rather than replaces, which breaks ordering on updates.)\n const graphRef = useRef<{ graph: Graph.WritableGraph; props: ActionGraphProps } | null>(null);\n if (!graphRef.current || graphRef.current.props !== menuGraphProps) {\n const newGraph = Graph.make({ registry });\n newGraph.pipe(Graph.addNodes(menuGraphProps.nodes as Node.NodeArg<any>[]), Graph.addEdges(menuGraphProps.edges));\n graphRef.current = { graph: newGraph, props: menuGraphProps };\n }\n\n const graph = graphRef.current.graph;\n\n const useGroupItems = useCallback(\n (sourceNode?: MenuItemGroup) => {\n const items = useAtomValue(graph.connections(sourceNode?.id || Node.RootId)) as MenuItem[];\n return items;\n },\n [graph],\n );\n\n return { useGroupItems };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport type { MenuActionProperties, MenuItemGroupProperties } from '@dxos/ui-types';\n\nimport type { ActionGraphProps } from './hooks';\nimport { createMenuAction, createMenuItemGroup } from './util';\n\nexport interface ActionGroupBuilder {\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;\n group<P extends {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this;\n}\n\nexport interface MenuBuilder extends ActionGroupBuilder {\n root(props: MenuItemGroupProperties): this;\n build(): ActionGraphProps;\n}\n\nexport const MenuBuilder = Object.freeze({\n make: (): MenuBuilder => new MenuBuilderImpl({ nodes: [], edges: [] }, 'root'),\n});\n\nclass MenuBuilderImpl implements MenuBuilder {\n constructor(\n private readonly _data: ActionGraphProps,\n private readonly _rootId: string,\n ) {}\n\n root(props: MenuItemGroupProperties): this {\n invariant(this._rootId === 'root', 'Root group can only be at the top level');\n invariant(this._data.nodes.find((node) => node.id === 'root') === undefined, 'Root group can only be created once');\n this._data.nodes.push(createMenuItemGroup('root', props));\n return this;\n }\n\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this {\n this._data.nodes.push(createMenuAction(id, invoke, props));\n this._data.edges.push({ source: this._rootId, target: id });\n return this;\n }\n\n group<P extends {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this {\n this._data.nodes.push(createMenuItemGroup(id, props));\n this._data.edges.push({ source: this._rootId, target: id });\n cb(new MenuBuilderImpl(this._data, id));\n return this;\n }\n\n build(): ActionGraphProps {\n return this._data;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["useControllableState", "React", "useCallback", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "runAndForwardErrors", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "getHostPlatform", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "descriptionText", "mx", "translationKey", "translations", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "descriptionText", "keySymbols", "join", "actionLabel", "createContextScope", "React", "useMemo", "MENU_NAME", "createMenuContext", "createMenuScope", "createContextScope", "MenuContextProvider", "useMenu", "menuContextDefaults", "iconSize", "useGroupItems", "onAction", "undefined", "useMenuScope", "MenuProvider", "children", "attendableId", "alwaysActive", "scope", "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", "caller", "children", "naturalProps", "optionsMenuOpen", "setOptionsMenuOpen", "useControllableState", "prop", "defaultProp", "onChange", "onAction", "handleActionClick", "stopPropagation", "parent", "executeMenuAction", "useMenuItems", "Root", "Portal", "Content", "Viewport", "map", "key", "id", "Arrow", "DropdownMenu", "Trigger", "VirtualTrigger", "React", "Fragment", "useCallback", "Icon", "Toolbar", "NaturalToolbar", "useTranslation", "useAttention", "mx", "textBlockWidth", "toolbarLayout", "Node", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "Node", "ActionGroupType", "ActionToolbarItem", "action", "__menuScope", "iconSize", "onAction", "useMenu", "t", "useTranslation", "translationKey", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "properties", "Root", "NaturalToolbar", "IconButton", "Button", "rootProps", "size", "label", "actionLabel", "children", "React", "ActionLabel", "handleClick", "useCallback", "executeMenuAction", "key", "id", "onClick", "variant", "DropdownMenuToolbarItem", "group", "items", "propsItems", "useMenuItems", "activeItem", "find", "item", "checked", "applyActive", "labelAction", "caretDown", "Icon", "DropdownMenu", "Trigger", "asChild", "ToggleGroupItem", "parent", "ToggleGroupIconItem", "value", "ToggleGroupToolbarItem", "selectCardinality", "ToggleGroup", "type", "map", "ToolbarMenu", "textBlockWidth", "textBlockWidthProp", "props", "undefined", "attendableId", "alwaysActive", "hasAttention", "useAttention", "InnerRoot", "Fragment", "innerRootProps", "role", "className", "mx", "toolbarLayout", "layoutManaged", "i", "ToolbarMenuItem", "isSeparator", "Separator", "isMenuGroup", "RegistryContext", "useAtomValue", "useCallback", "useContext", "useRef", "Graph", "Node", "useMenuActions", "props", "registry", "useContext", "RegistryContext", "menuGraphProps", "useAtomValue", "graphRef", "useRef", "current", "newGraph", "Graph", "make", "pipe", "addNodes", "nodes", "addEdges", "edges", "graph", "useGroupItems", "useCallback", "sourceNode", "items", "connections", "id", "Node", "RootId", "invariant", "MenuBuilder", "Object", "freeze", "make", "MenuBuilderImpl", "nodes", "edges", "_data", "_rootId", "root", "props", "invariant", "find", "node", "id", "undefined", "push", "createMenuItemGroup", "action", "invoke", "createMenuAction", "source", "target", "group", "cb", "build"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"src/util.ts":{"bytes":7784,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"src/translations.ts":{"bytes":1055,"imports":[],"format":"esm"},"src/components/ActionLabel.tsx":{"bytes":4065,"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/ui-theme","kind":"import-statement","external":true},{"path":"src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"src/components/MenuContext.tsx":{"bytes":5361,"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/components/DropdownMenu.tsx":{"bytes":10921,"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":"src/util.ts","kind":"import-statement","original":"../util"},{"path":"src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/types.ts":{"bytes":2976,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/components/ToolbarMenu.tsx":{"bytes":24783,"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":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"src/types.ts","kind":"import-statement","original":"../types"},{"path":"src/util.ts","kind":"import-statement","original":"../util"},{"path":"src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/components/index.ts":{"bytes":673,"imports":[{"path":"src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"src/components/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/hooks/useMenuActions.ts":{"bytes":8348,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/hooks/index.ts":{"bytes":476,"imports":[{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/builder.ts":{"bytes":6561,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/index.ts":{"bytes":1218,"imports":[{"path":"src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"src/hooks/index.ts","kind":"import-statement","original":"./hooks"},{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/builder.ts","kind":"import-statement","original":"./builder"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":37656},"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":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/util","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/ui-theme","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/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"exports":["DropdownMenu","MenuBuilder","MenuProvider","MenuSeparatorType","ToolbarMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","createMenuScope","isMenuGroup","isSeparator","menuContextDefaults","useMenu","useMenuActions","useMenuItems"],"entryPoint":"src/index.ts","inputs":{"src/components/DropdownMenu.tsx":{"bytesInOutput":2504},"src/util.ts":{"bytesInOutput":1425},"src/components/ActionLabel.tsx":{"bytesInOutput":856},"src/translations.ts":{"bytesInOutput":124},"src/components/MenuContext.tsx":{"bytesInOutput":1067},"src/components/ToolbarMenu.tsx":{"bytesInOutput":6056},"src/types.ts":{"bytesInOutput":235},"src/index.ts":{"bytesInOutput":0},"src/hooks/useMenuActions.ts":{"bytesInOutput":1656},"src/builder.ts":{"bytesInOutput":1535}},"bytes":16146}}}
1
+ {"inputs":{"src/util.ts":{"bytes":7784,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"src/translations.ts":{"bytes":1055,"imports":[],"format":"esm"},"src/components/ActionLabel.tsx":{"bytes":4065,"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/ui-theme","kind":"import-statement","external":true},{"path":"src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"src/components/MenuContext.tsx":{"bytes":5531,"imports":[{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/components/DropdownMenu.tsx":{"bytes":10921,"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":"src/util.ts","kind":"import-statement","original":"../util"},{"path":"src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/types.ts":{"bytes":3112,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/components/ToolbarMenu.tsx":{"bytes":24814,"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":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"src/types.ts","kind":"import-statement","original":"../types"},{"path":"src/util.ts","kind":"import-statement","original":"../util"},{"path":"src/components/ActionLabel.tsx","kind":"import-statement","original":"./ActionLabel"},{"path":"src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/components/index.ts":{"bytes":673,"imports":[{"path":"src/components/DropdownMenu.tsx","kind":"import-statement","original":"./DropdownMenu"},{"path":"src/components/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"},{"path":"src/components/MenuContext.tsx","kind":"import-statement","original":"./MenuContext"}],"format":"esm"},"src/hooks/useMenuActions.ts":{"bytes":5046,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/hooks/index.ts":{"bytes":476,"imports":[{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/builder.ts":{"bytes":6561,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/index.ts":{"bytes":1218,"imports":[{"path":"src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"src/hooks/index.ts","kind":"import-statement","original":"./hooks"},{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/builder.ts","kind":"import-statement","original":"./builder"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":36076},"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":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/util","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/ui-theme","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/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"exports":["DropdownMenu","MenuBuilder","MenuProvider","MenuSeparatorType","ToolbarMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","createMenuScope","isMenuGroup","isSeparator","menuContextDefaults","useMenu","useMenuActions","useMenuItems"],"entryPoint":"src/index.ts","inputs":{"src/components/DropdownMenu.tsx":{"bytesInOutput":2504},"src/util.ts":{"bytesInOutput":1425},"src/components/ActionLabel.tsx":{"bytesInOutput":856},"src/translations.ts":{"bytesInOutput":124},"src/components/MenuContext.tsx":{"bytesInOutput":1099},"src/components/ToolbarMenu.tsx":{"bytesInOutput":6063},"src/types.ts":{"bytesInOutput":235},"src/index.ts":{"bytesInOutput":0},"src/hooks/useMenuActions.ts":{"bytesInOutput":930},"src/builder.ts":{"bytesInOutput":1535}},"bytes":15459}}}
@@ -112,12 +112,13 @@ var menuContextDefaults = {
112
112
  onAction: void 0
113
113
  };
114
114
  var useMenuScope = createMenuScope();
115
- var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, onAction }) => {
115
+ var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
116
116
  const { scope } = useMenuScope(void 0);
117
117
  return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
118
118
  useGroupItems,
119
119
  iconSize,
120
120
  attendableId,
121
+ alwaysActive,
121
122
  onAction,
122
123
  scope
123
124
  }, children);
@@ -203,7 +204,7 @@ var DropdownMenu = {
203
204
  import React4, { Fragment, useCallback as useCallback2 } from "react";
204
205
  import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
205
206
  import { useAttention } from "@dxos/react-ui-attention";
206
- import { mx as mx2, textBlockWidth, toolbarInactive, toolbarLayout } from "@dxos/ui-theme";
207
+ import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/ui-theme";
207
208
 
208
209
  // src/types.ts
209
210
  import { Node as Node2 } from "@dxos/app-graph";
@@ -354,7 +355,7 @@ var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
354
355
  };
355
356
  var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp, ...props }) => {
356
357
  const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
357
- const { attendableId } = useMenu("ToolbarMenu", __menuScope);
358
+ const { attendableId, alwaysActive } = useMenu("ToolbarMenu", __menuScope);
358
359
  const { hasAttention } = useAttention(attendableId);
359
360
  const InnerRoot = textBlockWidthProp ? "div" : Fragment;
360
361
  const innerRootProps = textBlockWidthProp ? {
@@ -364,9 +365,10 @@ var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp
364
365
  return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
365
366
  ...props,
366
367
  classNames: [
367
- attendableId && !hasAttention && toolbarInactive,
368
+ attendableId,
368
369
  classNames
369
370
  ],
371
+ disabled: !alwaysActive && !hasAttention,
370
372
  layoutManaged: textBlockWidthProp
371
373
  }, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React4.createElement(ToolbarMenuItem, {
372
374
  key: item.id ?? i,
@@ -399,48 +401,21 @@ var ToolbarMenuItem = ({ item }) => {
399
401
  import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
400
402
  import { useCallback as useCallback3, useContext, useRef } from "react";
401
403
  import { Graph, Node as Node3 } from "@dxos/app-graph";
402
- var edgesArrayToRecord = (edges) => {
403
- return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
404
- if (!acc[source]) {
405
- acc[source] = {
406
- inbound: [],
407
- outbound: []
408
- };
409
- }
410
- if (!acc[target]) {
411
- acc[target] = {
412
- inbound: [],
413
- outbound: []
414
- };
415
- }
416
- const sourceEdges = acc[source];
417
- if (!sourceEdges.outbound.includes(target)) {
418
- sourceEdges.outbound.push(target);
419
- }
420
- const targetEdges = acc[target];
421
- if (!targetEdges.inbound.includes(source)) {
422
- targetEdges.inbound.push(source);
423
- }
424
- return acc;
425
- }, {})));
426
- };
427
404
  var useMenuActions = (props) => {
428
405
  const registry = useContext(RegistryContext);
429
406
  const menuGraphProps = useAtomValue(props);
430
407
  const graphRef = useRef(null);
431
- if (!graphRef.current) {
432
- graphRef.current = Graph.make({
433
- registry,
434
- nodes: menuGraphProps.nodes,
435
- edges: edgesArrayToRecord(menuGraphProps.edges)
408
+ if (!graphRef.current || graphRef.current.props !== menuGraphProps) {
409
+ const newGraph = Graph.make({
410
+ registry
436
411
  });
412
+ newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
413
+ graphRef.current = {
414
+ graph: newGraph,
415
+ props: menuGraphProps
416
+ };
437
417
  }
438
- const graph = graphRef.current;
439
- const prevPropsRef = useRef(menuGraphProps);
440
- if (prevPropsRef.current !== menuGraphProps) {
441
- prevPropsRef.current = menuGraphProps;
442
- graph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
443
- }
418
+ const graph = graphRef.current.graph;
444
419
  const useGroupItems = useCallback3((sourceNode) => {
445
420
  const items = useAtomValue(graph.connections(sourceNode?.id || Node3.RootId));
446
421
  return items;