@dxos/react-ui-menu 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a

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.
@@ -94,7 +94,7 @@ var actionLabel = (action, t) => {
94
94
 
95
95
  // src/components/ToolbarMenu.tsx
96
96
  import React3, { useCallback as useCallback2 } from "react";
97
- import { Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
97
+ import { Input, Toolbar as NaturalToolbar, Tooltip, toLocalizedString as toLocalizedString2, useTranslation as useTranslation2 } from "@dxos/react-ui";
98
98
  import { composable, composableProps } from "@dxos/react-ui";
99
99
  import { useAttention } from "@dxos/react-ui-attention";
100
100
  import { translationKey as translationKey2 } from "#translations";
@@ -219,6 +219,38 @@ var ActionToolbarItem = ({ __menuScope, action }) => {
219
219
  action
220
220
  }));
221
221
  };
222
+ var SwitchToolbarItem = ({ __menuScope, action }) => {
223
+ const { onAction } = useMenuScoped("SwitchToolbarItem", __menuScope);
224
+ const { t } = useTranslation2(translationKey2);
225
+ const { label, iconOnly, disabled, testId, hidden, checked } = action.properties;
226
+ const labelStr = toLocalizedString2(label, t);
227
+ const handleCheckedChange = useCallback2(() => {
228
+ if (onAction) {
229
+ onAction(action, {});
230
+ } else {
231
+ void executeMenuAction(action);
232
+ }
233
+ }, [
234
+ action,
235
+ onAction
236
+ ]);
237
+ if (hidden) {
238
+ return null;
239
+ }
240
+ const switchInput = /* @__PURE__ */ React3.createElement(Input.Switch, {
241
+ checked,
242
+ disabled,
243
+ "aria-label": iconOnly ? labelStr : void 0,
244
+ onCheckedChange: handleCheckedChange,
245
+ ...testId && {
246
+ "data-testid": testId
247
+ }
248
+ });
249
+ return /* @__PURE__ */ React3.createElement(Input.Root, null, iconOnly ? /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
250
+ asChild: true,
251
+ content: labelStr
252
+ }, /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput)) : /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput), !iconOnly && /* @__PURE__ */ React3.createElement(Input.Label, null, labelStr));
253
+ };
222
254
  var DropdownMenuToolbarItem = ({ __menuScope, group, items: propsItems }) => {
223
255
  const { t } = useTranslation2(translationKey2);
224
256
  const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
@@ -351,9 +383,19 @@ var ToolbarMenuItem = ({ __menuScope, item }) => {
351
383
  group: item
352
384
  });
353
385
  }
386
+ const action = item;
387
+ if (action.properties?.variant === "switch") {
388
+ return /* @__PURE__ */ React3.createElement(SwitchToolbarItem, {
389
+ __menuScope,
390
+ action
391
+ });
392
+ }
393
+ if (action.properties?.variant === "custom" && action.properties.render) {
394
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, action.properties.render());
395
+ }
354
396
  return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
355
397
  __menuScope,
356
- action: item
398
+ action
357
399
  });
358
400
  };
359
401
 
@@ -677,6 +719,12 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
677
719
  });
678
720
  return this;
679
721
  }
722
+ switch(id, props, invoke) {
723
+ return this.action(id, {
724
+ ...props,
725
+ variant: "switch"
726
+ }, invoke);
727
+ }
680
728
  group(id, props, cb) {
681
729
  this._data.nodes.push(createMenuItemGroup(id, props));
682
730
  this._data.edges.push({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/Menu.tsx", "../../../src/util.ts", "../../../src/components/ActionLabel.tsx", "../../../src/components/ToolbarMenu.tsx", "../../../src/types.ts", "../../../src/components/DropdownMenu.tsx", "../../../src/hooks/useGraphMenuActions.ts", "../../../src/hooks/useMenuActions.ts", "../../../src/builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { type Scope, createContextScope } from '@radix-ui/react-context';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { createContext, type MouseEvent, type PropsWithChildren, useCallback, useContext, useMemo } from 'react';\n\nimport { log } from '@dxos/log';\nimport { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';\n\nimport {\n type AddMenuItemsProps,\n type MenuAction,\n type MenuContextValue,\n type MenuGroupContext,\n type MenuItem,\n type MenuItems,\n type MenuItemsAccessor,\n type MenuItemsMap,\n} from '../types';\nimport { executeMenuAction } from '../util';\nimport { ActionLabel } from './ActionLabel';\nimport { ToolbarMenu } from './ToolbarMenu';\n\n//\n// Scoped context.\n//\n\ntype MenuScopedProps<P> = P & { __menuScope?: Scope };\n\nconst MENU_NAME = 'Menu';\n\nconst [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);\n\nconst nullItemsAtom = Atom.make<MenuItem[] | null>(null);\nconst defaultItemsAccessor: MenuItemsAccessor = () => nullItemsAtom;\n\nconst menuContextDefaults: MenuContextValue = {\n iconSize: 5,\n items: defaultItemsAccessor,\n onAction: undefined,\n menuItemsAtom: Atom.make<MenuItemsMap>(new Map()),\n addMenuItems: () => {},\n removeMenuItems: () => {},\n};\n\nconst [MenuContextProvider, useMenuScoped] = createMenuContext<MenuContextValue>(MENU_NAME, menuContextDefaults);\n\nconst useMenuScope = createMenuScope();\n\n//\n// Dropdown context (internal) — allows Menu.Content to close the parent dropdown.\n//\n\ntype MenuDropdownContextValue = {\n closeMenu: () => void;\n caller?: string;\n};\n\nconst MenuDropdownContext = createContext<MenuDropdownContextValue>({\n closeMenu: () => {},\n});\n\n//\n// MenuProvider (internal) — the context provider used by Menu.Root.\n//\n\nconst DEFAULT_PRIORITY = 100;\n\nconst sortMenuItems = (items: MenuItems[]) =>\n [...items].sort((a, b) => (a.priority !== b.priority ? a.priority - b.priority : a.id.localeCompare(b.id)));\n\ntype MenuProviderProps = PropsWithChildren<Partial<MenuContextValue>>;\n\nconst MenuProvider = ({\n children,\n items = menuContextDefaults.items,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n alwaysActive,\n onAction,\n}: MenuProviderProps) => {\n const { scope } = useMenuScope(undefined);\n const registry = useContext(RegistryContext);\n const menuItemsAtom = useMemo(() => Atom.make<MenuItemsMap>(new Map()).pipe(Atom.keepAlive), []);\n\n const addMenuItems = useCallback(\n (props: AddMenuItemsProps) => {\n const priority = props.priority ?? DEFAULT_PRIORITY;\n const prev = registry.get(menuItemsAtom);\n const next = new Map(prev);\n next.set(props.id, { ...props, priority });\n registry.set(menuItemsAtom, next);\n },\n [registry, menuItemsAtom],\n );\n\n const removeMenuItems = useCallback(\n (id: string) => {\n const prev = registry.get(menuItemsAtom);\n const next = new Map(prev);\n next.delete(id);\n registry.set(menuItemsAtom, next);\n },\n [registry, menuItemsAtom],\n );\n\n return (\n <MenuContextProvider\n items={items}\n iconSize={iconSize}\n attendableId={attendableId}\n alwaysActive={alwaysActive}\n menuItemsAtom={menuItemsAtom}\n addMenuItems={addMenuItems}\n removeMenuItems={removeMenuItems}\n onAction={onAction}\n scope={scope}\n >\n {children}\n </MenuContextProvider>\n );\n};\n\n//\n// Item resolution.\n//\n\nconst resolveItems = (\n baseItems: MenuItem[] | null,\n group: MenuGroupContext | undefined,\n entries: ReadonlyMap<string, MenuItems>,\n): MenuItem[] | null => {\n const applicable = [...entries.values()].filter((entry) => !entry.groupFilter || entry.groupFilter(group));\n if (applicable.length === 0) {\n return baseItems;\n }\n\n const sorted = sortMenuItems(applicable);\n\n const replacements = sorted.filter((entry) => entry.mode === 'replacement');\n if (replacements.length > 0) {\n if (replacements.length > 1) {\n log.warn('multiple replacement entries found', {\n ids: replacements.map((r) => r.id).join(', '),\n using: replacements[0].id,\n });\n }\n return replacements[0].items;\n }\n\n const additive = sorted.filter((entry) => entry.mode === 'additive');\n const additiveItems = additive.flatMap((entry) => entry.items);\n\n if (!baseItems || baseItems.length === 0) {\n return additiveItems.length > 0 ? additiveItems : null;\n }\n\n return [...baseItems, ...additiveItems];\n};\n\n//\n// Public hooks.\n//\n\nconst useMenuItems = (\n group?: MenuGroupContext,\n propsItems?: MenuItem[],\n consumerName: string = 'useMenuItemConsumer',\n __menuScope?: Scope,\n) => {\n const { items, menuItemsAtom } = useMenuScoped(consumerName, __menuScope);\n const groupItems = useAtomValue(items(group));\n const entries = useAtomValue(menuItemsAtom) ?? new Map();\n\n const baseItems = useMemo(() => propsItems ?? groupItems ?? null, [propsItems, groupItems]);\n\n const resolved = useMemo(\n () => resolveItems(baseItems, group, entries as ReadonlyMap<string, MenuItems>),\n [baseItems, group, entries],\n );\n\n return resolved ?? undefined;\n};\n\n/** Returns the menu context without Radix scope. */\nconst useMenu = (consumerName: string): MenuContextValue => {\n return useMenuScoped(consumerName, undefined);\n};\n\n//\n// Menu.Root\n//\n\ntype MenuRootProps = MenuProviderProps &\n Pick<DropdownMenuRootProps, 'children' | 'open' | 'defaultOpen' | 'onOpenChange'> & {\n /** Identifies the component that owns this menu (passed to action handlers). */\n caller?: string;\n };\n\n/**\n * Menu context boundary.\n *\n * NOTE: This component is headless since it's root div has `contents`.\n *\n * Provides the menu context (action dispatch, contribution registry, icon size, etc.)\n * and an optional dropdown root for use with `Menu.Trigger` + `Menu.Content`.\n */\nconst MenuRoot = ({ children, open, defaultOpen, onOpenChange, caller, ...props }: MenuRootProps) => {\n const [menuOpen, setMenuOpen] = useControllableState({\n prop: open,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n const closeMenu = useCallback(() => setMenuOpen(false), [setMenuOpen]);\n\n return (\n <MenuProvider {...props}>\n <MenuDropdownContext.Provider value={{ closeMenu, caller }}>\n <NaturalDropdownMenu.Root open={menuOpen} onOpenChange={setMenuOpen}>\n {children}\n </NaturalDropdownMenu.Root>\n </MenuDropdownContext.Provider>\n </MenuProvider>\n );\n};\n\n//\n// Menu.Content\n//\n\ntype MenuContentProps = {\n group?: MenuGroupContext;\n items?: MenuItem[];\n caller?: string;\n};\n\nconst MenuContentItem = ({\n item,\n onClick,\n __menuScope,\n}: MenuScopedProps<{\n item: MenuItem;\n onClick: (action: MenuAction, event: MouseEvent) => void;\n}>) => {\n const action = item as MenuAction;\n const handleClick = useCallback((event: MouseEvent) => onClick(action, event), [action, onClick]);\n const { iconSize } = useMenuScoped('MenuContentItem', __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\n/**\n * Renders the dropdown menu portal, content, and graph-backed items.\n *\n * Must be a descendant of `Menu.Root`. Reads items via `useMenuItems` from the\n * nearest menu context, with optional `group`/`items` prop overrides.\n */\nconst MenuContent = ({\n group,\n items: propsItems,\n caller: callerOverride,\n __menuScope,\n}: MenuScopedProps<MenuContentProps>) => {\n const { closeMenu, caller: contextCaller } = useContext(MenuDropdownContext);\n const caller = callerOverride ?? contextCaller;\n const { onAction } = useMenuScoped('MenuContent', __menuScope);\n const resolvedItems = useMenuItems(group, propsItems, 'MenuContent', __menuScope);\n\n const handleActionClick = useCallback(\n (action: MenuAction, event: MouseEvent) => {\n if (action.properties?.disabled) {\n return;\n }\n event.stopPropagation();\n closeMenu();\n if (onAction) {\n onAction(action, { parent: group, caller });\n } else {\n void executeMenuAction(action, { parent: group, caller });\n }\n },\n [group, caller, onAction, closeMenu],\n );\n\n return (\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {resolvedItems?.map((item) => (\n <MenuContentItem key={item.id} item={item} onClick={handleActionClick} />\n ))}\n </NaturalDropdownMenu.Viewport>\n <NaturalDropdownMenu.Arrow />\n </NaturalDropdownMenu.Content>\n </NaturalDropdownMenu.Portal>\n );\n};\n\n//\n// Namespace.\n//\n\n/**\n * Primary namespace export for the menu system.\n *\n * - `Menu.Root` — context boundary (replaces `MenuProvider`); also provides a dropdown root.\n * - `Menu.Trigger` / `Menu.VirtualTrigger` — dropdown trigger (use with `Menu.Content`).\n * - `Menu.Content` — renders graph-backed dropdown items inside a portal.\n * - `Menu.Toolbar` — flat toolbar component with graph-backed item rendering.\n */\nconst Menu = {\n Root: MenuRoot,\n Trigger: NaturalDropdownMenu.Trigger,\n Content: MenuContent,\n VirtualTrigger: NaturalDropdownMenu.VirtualTrigger,\n Toolbar: ToolbarMenu,\n};\n\nexport { Menu, menuContextDefaults, useMenu, useMenuItems, useMenuScoped };\n\nexport type { MenuContentProps, MenuRootProps, MenuScopedProps };\n\nexport type {\n ToolbarMenuProps,\n ToolbarMenuActionGroupProperties,\n ToolbarMenuActionGroupProps,\n ToolbarMenuActionProps,\n ToolbarMenuDropdownMenuActionGroup,\n ToolbarMenuToggleGroupActionGroup,\n} from './ToolbarMenu';\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Node } from '@dxos/app-graph';\nimport { EffectEx } 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 EffectEx.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--circle-dashed--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 = <P extends MenuItemGroupProperties>(id: string, properties: P) =>\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 relation: 'child' as const,\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, relation: 'child' as const }],\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 { mx } from '@dxos/ui-theme';\nimport { type MenuActionProperties, type MenuItemChrome } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport { getShortcut } from '../util';\n\ntype Action = Node.Action<MenuActionProperties> | Node.ActionGroup<MenuItemChrome>;\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', 'text-description')}>{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 2025 DXOS.org\n//\n\nimport React, { useCallback } from 'react';\n\nimport { Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { type DropdownMenuItemGroupProperties, type ToggleGroupMenuItemGroupProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport { type MenuAction, type MenuItem, type MenuItemGroup, isMenuGroup, isSeparator } from '../types';\nimport { executeMenuAction } from '../util';\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';\n\nexport type ToolbarMenuDropdownMenuActionGroup = DropdownMenuItemGroupProperties;\n\nexport type ToolbarMenuToggleGroupActionGroup = ToggleGroupMenuItemGroupProperties;\n\nexport type ToolbarMenuActionGroupProperties = DropdownMenuItemGroupProperties | ToggleGroupMenuItemGroupProperties;\n\nexport type ToolbarMenuProps = ToolbarRootProps;\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuDropdownGroupProps = {\n group: MenuItemGroup<DropdownMenuItemGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuToggleGroupProps = {\n group: MenuItemGroup<ToggleGroupMenuItemGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuActionProps = {\n group: MenuItemGroup<ToggleGroupMenuItemGroupProperties>;\n action: MenuAction;\n};\n\nconst ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: MenuAction }>) => {\n const { iconSize, onAction } = useMenuScoped('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n\n const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;\n const buttonVariant =\n (action.properties as { variant?: string }).variant === 'primary' ? ('primary' as const) : ('ghost' as const);\n\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\n const commonProps = {\n variant: buttonVariant,\n disabled,\n classNames,\n onClick: handleClick,\n ...(testId && { 'data-testid': testId }),\n };\n\n if (hidden) {\n return null;\n }\n\n return icon ? (\n <NaturalToolbar.IconButton\n key={action.id}\n {...commonProps}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(action, t)}\n />\n ) : (\n <NaturalToolbar.Button key={action.id} {...commonProps}>\n <ActionLabel action={action} />\n </NaturalToolbar.Button>\n );\n};\n\nconst DropdownMenuToolbarItem = ({\n __menuScope,\n group,\n items: propsItems,\n}: MenuScopedProps<ToolbarMenuDropdownGroupProps>) => {\n const { t } = useTranslation(translationKey);\n const { iconSize } = useMenuScoped('DropdownMenuToolbarItem', __menuScope);\n const items = useMenuItems(group, propsItems, 'DropdownMenuToolbarItem', __menuScope);\n const {\n iconOnly,\n disabled,\n testId,\n applyActive,\n caretDown = true,\n icon: groupIcon,\n iconClassNames: groupIconClassNames,\n } = group.properties;\n const activeItem = items?.find((item) => !!(item as MenuAction).properties.checked) as MenuAction | undefined;\n const icon =\n (applyActive &&\n // TODO(thure): Handle other menu item types.\n activeItem?.properties.icon) ||\n groupIcon;\n // Follow the same `applyActive` rule for `iconClassNames` so a per-item accent (e.g. tag colour) tracks the displayed icon.\n const iconClassNames = (applyActive && activeItem?.properties.iconClassNames) || groupIconClassNames;\n const labelAction = applyActive && activeItem ? activeItem : group;\n\n return (\n <DropdownMenu.Root group={group} items={items}>\n <DropdownMenu.Trigger asChild>\n {icon ? (\n <NaturalToolbar.IconButton\n variant='ghost'\n disabled={disabled}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(labelAction, t)}\n caretDown={caretDown}\n {...(testId && { 'data-testid': testId })}\n />\n ) : (\n <NaturalToolbar.Button\n variant='ghost'\n disabled={disabled}\n caretDown={caretDown}\n {...(testId && { 'data-testid': testId })}\n >\n <ActionLabel action={labelAction} />\n </NaturalToolbar.Button>\n )}\n </DropdownMenu.Trigger>\n </DropdownMenu.Root>\n );\n};\n\nconst ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<ToolbarMenuActionProps>) => {\n const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;\n\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\n const commonProps = {\n value: action.id,\n disabled,\n variant: 'ghost' as const,\n classNames,\n onClick: handleClick,\n ...(testId && { 'data-testid': testId }),\n };\n\n return hidden ? null : icon ? (\n <NaturalToolbar.ToggleGroupIconItem\n {...commonProps}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(action, t)}\n />\n ) : (\n <NaturalToolbar.ToggleGroupItem {...commonProps}>\n <ActionLabel action={action} />\n </NaturalToolbar.ToggleGroupItem>\n );\n};\n\nconst ToggleGroupToolbarItem = ({\n __menuScope,\n group,\n items: itemsProp,\n}: MenuScopedProps<ToolbarMenuToggleGroupProps>) => {\n const items = useMenuItems(group, itemsProp, 'ToggleGroupToolbarItem', __menuScope);\n const { selectCardinality } = group.properties;\n\n // TODO(thure): Handle other menu item types.\n const children = (items as MenuAction[]).map((action) => (\n <ToggleGroupItem key={action.id} group={group} action={action} />\n ));\n\n if (selectCardinality === 'multiple') {\n return (\n <NaturalToolbar.ToggleGroup type='multiple' value={group.properties.value}>\n {children}\n </NaturalToolbar.ToggleGroup>\n );\n } else {\n return (\n <NaturalToolbar.ToggleGroup type='single' value={group.properties.value}>\n {children}\n </NaturalToolbar.ToggleGroup>\n );\n }\n};\n\nexport const ToolbarMenu = composable<HTMLDivElement, MenuScopedProps<ToolbarMenuProps>>(\n ({ __menuScope, children, ...props }, forwardedRef) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId, alwaysActive } = useMenuScoped('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n\n return (\n <NaturalToolbar.Root\n {...composableProps(props, { classNames: attendableId })}\n disabled={!alwaysActive && !hasAttention}\n ref={forwardedRef}\n >\n {items?.map((item: MenuItem) => (\n <ToolbarMenuItem key={item.id} __menuScope={__menuScope} item={item} />\n ))}\n {children}\n </NaturalToolbar.Root>\n );\n },\n);\n\nconst ToolbarMenuItem = ({ __menuScope, item }: MenuScopedProps<{ item: MenuItem }>) => {\n if (isSeparator(item)) {\n return <NaturalToolbar.Separator variant={item.properties.variant} />;\n }\n\n if (isMenuGroup(item)) {\n if (item.properties.variant === 'dropdownMenu') {\n return (\n <DropdownMenuToolbarItem\n __menuScope={__menuScope}\n group={item as MenuItemGroup<DropdownMenuItemGroupProperties>}\n />\n );\n }\n\n return (\n <ToggleGroupToolbarItem\n __menuScope={__menuScope}\n group={item as MenuItemGroup<ToggleGroupMenuItemGroupProperties>}\n />\n );\n }\n\n return <ActionToolbarItem __menuScope={__menuScope} action={item as MenuAction} />;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom } from '@effect-atom/atom-react';\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 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\n/** Graph-sourced menu nodes carry plugin-specific properties validated at runtime. */\nexport type GraphMenuItem = Node.Action | Node.ActionGroup;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup | GraphMenuItem;\n\n/** Group context for graph-backed dropdown menus (any graph node, not only action groups). */\nexport type MenuGroupContext = MenuItemGroup | Node.Node;\n\n/** Atom-family-style accessor: returns an atom of items for a given group (or root when undefined). */\nexport type MenuItemsAccessor = (group?: MenuGroupContext) => Atom.Atom<MenuItem[] | null>;\n\nexport type ActionExecutor = (action: MenuAction, params: Node.InvokeProps) => void;\n\nexport type MenuItemsMode = 'additive' | 'replacement';\n\nexport type AddMenuItemsProps = {\n id: string;\n mode: MenuItemsMode;\n priority?: number;\n items: MenuItem[];\n groupFilter?: (group?: MenuGroupContext) => boolean;\n};\n\nexport type MenuItems = Omit<AddMenuItemsProps, 'priority'> & { priority: number };\nexport type MenuItemsMap = Map<string, MenuItems>;\n\nexport type MenuContextValue = {\n /** Atom-family accessor for base menu items, keyed by group (similar to Tree model). */\n items: MenuItemsAccessor;\n iconSize: IconButtonProps['size'];\n attendableId?: string;\n /** TODO(burdon): Remove and assume always active if attendableId is undefined. */\n /** If true, the menu is always active regardless of attention state. */\n alwaysActive?: boolean;\n /** Atom holding the current set of imperatively added menu items. */\n menuItemsAtom: Atom.Atom<MenuItemsMap>;\n /** Imperatively add menu items to the nearest MenuProvider. */\n addMenuItems: (props: AddMenuItemsProps) => void;\n /** Remove previously added menu items by id. */\n removeMenuItems: (id: string) => void;\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 { 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';\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';\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 } = useMenuScoped('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 } = useMenuScoped('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 2026 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom-react';\nimport { useMemo } from 'react';\n\nimport { type Graph, Node } from '@dxos/app-graph';\n\nimport {\n type ActionGraphEdges,\n type ActionGraphNodes,\n type ActionGraphProps,\n type MenuActions,\n useMenuActions,\n} from './useMenuActions';\n\nexport type GraphMenuOptions = {\n /** Group the actions descend from. Defaults to the menu root (top-level toolbar items). */\n rootId?: string;\n /** Keep only the actions the predicate accepts (e.g. by `disposition`). */\n filter?: (action: Node.ActionLike) => boolean;\n};\n\n/**\n * Flatten a node's contributed actions (and nested {@link Node.ActionGroup}s) into the\n * `{ nodes, edges }` an {@link useMenuActions} / `Menu` consumes. The action nodes are spliced\n * verbatim, so their Effect `data` (and captured `_actionContext`) execute via `executeMenuAction`\n * without any `onAction` wiring.\n *\n * Pure over a `resolve` function so it is testable without a live graph; `resolve(id)` returns the\n * direct actions for `id` (a node id at the top level, a group id when expanding a group).\n */\nexport const buildGraphMenu = (\n resolve: (id: string) => Node.ActionLike[],\n nodeId: string,\n options: GraphMenuOptions = {},\n): ActionGraphProps => {\n const { rootId = Node.RootId, filter } = options;\n const nodes: ActionGraphNodes = [];\n const edges: ActionGraphEdges = [];\n const seen = new Set<string>();\n\n const visit = (parentId: string, sourceId: string) => {\n for (const action of resolve(sourceId)) {\n if (filter && !filter(action)) {\n continue;\n }\n // Always record the parent→child edge (a shared action may sit under multiple groups).\n edges.push({ source: parentId, target: action.id, relation: 'child' });\n if (seen.has(action.id)) {\n continue;\n }\n seen.add(action.id);\n nodes.push(action as ActionGraphNodes[number]);\n // A group's children are the actions contributed for the group's own id.\n if (Node.isActionGroup(action)) {\n visit(action.id, action.id);\n }\n }\n };\n\n visit(rootId, nodeId);\n return { nodes, edges };\n};\n\n/**\n * Read a node's contributed actions from the app-graph as menu `ActionGraphProps`, for splicing into a\n * hand-built toolbar via `MenuBuilder.subgraph(graphActions(graph, get, nodeId))`. Reactive: reads the\n * graph's action atoms through `get`, so contributed actions appear/disappear as extensions update.\n */\nexport const graphActions = (\n graph: Graph.ReadableGraph | undefined,\n get: Atom.Context,\n nodeId: string | undefined,\n options?: GraphMenuOptions,\n): ActionGraphProps =>\n graph && nodeId ? buildGraphMenu((id) => get(graph.actions(id)), nodeId, options) : { nodes: [], edges: [] };\n\n/**\n * Menu actions sourced entirely from a node's app-graph contributions — the common \"show every action\n * the graph offers for this object\" toolbar/menu. Compose with hand-built items via {@link graphActions}.\n */\nexport const useGraphMenuActions = (\n graph: Graph.ReadableGraph | undefined,\n nodeId: string | undefined,\n options?: GraphMenuOptions,\n): MenuActions => {\n const atom = useMemo(\n () => Atom.make((get) => graphActions(graph, get, nodeId, options)),\n // `options` is expected to be stable; `rootId` participates since it reshapes the graph.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [graph, nodeId, options?.rootId],\n );\n return useMenuActions(atom);\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { type DependencyList, useCallback, useContext, useMemo } from 'react';\n\nimport { Graph, Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup, type MenuItemsAccessor } 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 items: MenuItemsAccessor;\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 // NOTE: Using useMemo rather than a ref-mutation pattern to avoid calling registry.set during render,\n // which would trigger atom state updates in other components (setState-in-render React warning).\n const graph = useMemo(() => {\n const newGraph = Graph.make({ registry });\n newGraph.pipe(Graph.addNodes(menuGraphProps.nodes as Node.NodeArg<any>[]), Graph.addEdges(menuGraphProps.edges));\n return newGraph;\n }, [registry, menuGraphProps]);\n\n const items: MenuItemsAccessor = useCallback(\n (group?: MenuItemGroup) => {\n // TODO(wittjosiah): Migrate to using action relation instead of child.\n return graph.connections(group?.id || Node.RootId, 'child') as Atom.Atom<MenuItem[] | null>;\n },\n [graph],\n );\n\n return { items };\n};\n\n/**\n * Convenience wrapper around `useMenuActions` that creates the backing atom inline.\n * Pass a builder thunk and a dependency list — the hook memoizes `Atom.make(build)` and threads\n * it through `useMenuActions`. Saves the `useMemo(() => Atom.make(...), deps)` boilerplate when\n * the action graph is composed from local state (e.g. a toolbar driven by component state).\n *\n * Read reactive state via `get` inside the builder; `deps` should hold only stable references.\n */\nexport const useMenuBuilder = (build: (get: Atom.Context) => ActionGraphProps, deps: DependencyList): MenuActions => {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const atom = useMemo(() => Atom.make(build), deps);\n return useMenuActions(atom);\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport type { DropdownMenuItemGroupProperties, MenuActionProperties, MenuItemGroupProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport type { ActionGraphProps } from './hooks';\nimport { MenuSeparatorType } from './types';\nimport { createMenuAction, createMenuItemGroup } from './util';\n\n/** Default trigger for toolbar overflow (⋮) dropdown menus. */\nconst overflowMenuProperties = {\n label: ['toolbar-overflow.menu', { ns: translationKey }],\n icon: 'ph--dots-three-vertical--regular',\n iconOnly: true,\n caretDown: false,\n variant: 'dropdownMenu',\n} as const satisfies DropdownMenuItemGroupProperties;\n\n/** Callback that populates an action group builder. */\nexport type ActionGroupBuilderFn = (builder: ActionGroupBuilder) => void;\n\n/**\n * Fluent builder for composing menu action graphs.\n * Subgraph functions return a callback that receives the builder, enabling composition via partial application:\n * ```ts\n * const addHeadings = (state): ActionGroupBuilderFn => (builder) => {\n * builder.group('headings', { ... }, (group) => { ... });\n * };\n *\n * MenuBuilder.make()\n * .subgraph(showHeadings && addHeadings(state))\n * .subgraph(showFormatting && addFormatting(state))\n * .build();\n * ```\n */\nexport interface ActionGroupBuilder {\n /** Add an action node as a child of the current group. */\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;\n\n /** Add a nested action group. */\n group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this;\n\n /** Merge pre-built nodes and edges, or build a subgraph via callback scoped to the current group. Falsy values are ignored. */\n subgraph(subgraphOrCb: ActionGraphProps | ActionGroupBuilderFn | false | null | undefined): this;\n\n /** Add a separator. */\n separator(variant?: 'gap' | 'line'): this;\n}\n\n/** Top-level builder that creates the root group and produces the final action graph. */\nexport interface MenuBuilder extends ActionGroupBuilder {\n /**\n * Set properties on the root menu group. May only be called once.\n */\n root(props: MenuItemGroupProperties): this;\n\n /**\n * Add a root-level toolbar overflow dropdown (⋮) with built-in trigger styling.\n */\n menu(id: string, cb: ActionGroupBuilderFn): this;\n\n /**\n * Return the assembled action graph.\n */\n build(): ActionGraphProps;\n}\n\nclass MenuBuilderImpl implements MenuBuilder {\n private _separatorCount = 0;\n\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 build(): ActionGraphProps {\n return this._data;\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, relation: 'child' });\n return this;\n }\n\n group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this {\n this._data.nodes.push(createMenuItemGroup(id, props));\n this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });\n cb(new MenuBuilderImpl(this._data, id));\n return this;\n }\n\n menu(id: string, cb: ActionGroupBuilderFn): this {\n return this.group(id, overflowMenuProperties, cb);\n }\n\n subgraph(subgraphOrCb: ActionGraphProps | ActionGroupBuilderFn | false | null | undefined): this {\n if (!subgraphOrCb) {\n return this;\n }\n if (typeof subgraphOrCb === 'function') {\n subgraphOrCb(new MenuBuilderImpl(this._data, this._rootId));\n } else {\n this._data.nodes.push(...subgraphOrCb.nodes);\n this._data.edges.push(...subgraphOrCb.edges);\n }\n return this;\n }\n\n separator(variant: 'gap' | 'line' = 'gap'): this {\n const id = `separator-${++this._separatorCount}`;\n this._data.nodes.push({\n id,\n type: MenuSeparatorType,\n properties: { variant },\n data: undefined as never,\n });\n this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });\n return this;\n }\n}\n\nexport const MenuBuilder = Object.freeze({\n make: (): MenuBuilder => new MenuBuilderImpl({ nodes: [], edges: [] }, 'root'),\n});\n"],
5
- "mappings": "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",
6
- "names": ["Atom", "RegistryContext", "useAtomValue", "createContextScope", "useControllableState", "React", "createContext", "useCallback", "useContext", "useMemo", "log", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "EffectEx", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "relation", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "translationKey", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "keySymbols", "join", "actionLabel", "React", "useCallback", "Toolbar", "NaturalToolbar", "useTranslation", "composable", "composableProps", "useAttention", "translationKey", "Node", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "ActionGroupType", "useControllableState", "React", "useCallback", "Icon", "DropdownMenu", "NaturalDropdownMenu", "DropdownMenuItem", "item", "onClick", "__menuScope", "action", "handleClick", "useCallback", "event", "iconSize", "useMenuScoped", "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", "ActionToolbarItem", "__menuScope", "action", "iconSize", "onAction", "useMenuScoped", "t", "useTranslation", "translationKey", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "iconClassNames", "properties", "buttonVariant", "variant", "handleClick", "useCallback", "executeMenuAction", "commonProps", "onClick", "React", "NaturalToolbar", "IconButton", "key", "id", "size", "label", "actionLabel", "Button", "ActionLabel", "DropdownMenuToolbarItem", "group", "items", "propsItems", "useMenuItems", "applyActive", "caretDown", "groupIcon", "groupIconClassNames", "activeItem", "find", "item", "checked", "labelAction", "DropdownMenu", "Root", "Trigger", "asChild", "ToggleGroupItem", "parent", "value", "ToggleGroupIconItem", "ToggleGroupToolbarItem", "itemsProp", "selectCardinality", "children", "map", "ToggleGroup", "type", "ToolbarMenu", "composable", "props", "forwardedRef", "undefined", "attendableId", "alwaysActive", "hasAttention", "useAttention", "composableProps", "ref", "ToolbarMenuItem", "isSeparator", "Separator", "isMenuGroup", "MENU_NAME", "nullItemsAtom", "defaultItemsAccessor", "menuContextDefaults", "iconSize", "items", "onAction", "undefined", "menuItemsAtom", "addMenuItems", "removeMenuItems", "MenuContextProvider", "MenuDropdownContext", "createContext", "closeMenu", "sort", "priority", "MenuProvider", "scope", "useMenuScope", "useContext", "RegistryContext", "make", "useCallback", "props", "DEFAULT_PRIORITY", "registry", "next", "Map", "prev", "set", "delete", "id", "attendableId", "alwaysActive", "children", "values", "filter", "entry", "applicable", "length", "baseItems", "sorted", "replacements", "map", "using", "additive", "additiveItems", "groupItems", "useAtomValue", "group", "entries", "useMemo", "propsItems", "prop", "open", "defaultProp", "defaultOpen", "onChange", "caller", "onOpenChange", "setMenuOpen", "MenuContentItem", "event", "action", "onClick", "handleClick", "React", "NaturalDropdownMenu", "disabled", "properties", "icon", "callerOverride", "contextCaller", "useMenuScoped", "__menuScope", "resolvedItems", "useMenuItems", "handleActionClick", "parent", "item", "Trigger", "Content", "VirtualTrigger", "Toolbar", "ToolbarMenu", "Atom", "useMemo", "Node", "Atom", "RegistryContext", "useAtomValue", "useCallback", "useContext", "useMemo", "Graph", "Node", "useMenuActions", "props", "registry", "menuGraphProps", "graph", "newGraph", "make", "pipe", "addNodes", "nodes", "addEdges", "edges", "items", "group", "connections", "id", "RootId", "useMenuBuilder", "build", "deps", "atom", "buildGraphMenu", "resolve", "nodeId", "options", "rootId", "Node", "RootId", "filter", "nodes", "edges", "seen", "Set", "visit", "parentId", "sourceId", "action", "push", "source", "target", "id", "relation", "has", "add", "isActionGroup", "graphActions", "graph", "get", "actions", "useGraphMenuActions", "atom", "useMemo", "Atom", "make", "useMenuActions", "invariant", "translationKey", "__dxlog_file", "translationKey", "icon", "iconOnly", "caretDown", "variant", "MenuBuilderImpl", "_separatorCount", "_data", "_rootId", "root", "props", "invariant", "nodes", "createMenuItemGroup", "build", "action", "edges", "source", "target", "id", "relation", "group", "push", "menu", "subgraph", "subgraphOrCb", "separator", "type", "MenuSeparatorType", "properties", "data"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { type Scope, createContextScope } from '@radix-ui/react-context';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type MouseEvent, type PropsWithChildren, createContext, useCallback, useContext, useMemo } from 'react';\n\nimport { log } from '@dxos/log';\nimport { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';\n\nimport {\n type AddMenuItemsProps,\n type MenuAction,\n type MenuContextValue,\n type MenuGroupContext,\n type MenuItem,\n type MenuItems,\n type MenuItemsAccessor,\n type MenuItemsMap,\n} from '../types';\nimport { executeMenuAction } from '../util';\nimport { ActionLabel } from './ActionLabel';\nimport { ToolbarMenu } from './ToolbarMenu';\n\n//\n// Scoped context.\n//\n\ntype MenuScopedProps<P> = P & { __menuScope?: Scope };\n\nconst MENU_NAME = 'Menu';\n\nconst [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);\n\nconst nullItemsAtom = Atom.make<MenuItem[] | null>(null);\nconst defaultItemsAccessor: MenuItemsAccessor = () => nullItemsAtom;\n\nconst menuContextDefaults: MenuContextValue = {\n iconSize: 5,\n items: defaultItemsAccessor,\n onAction: undefined,\n menuItemsAtom: Atom.make<MenuItemsMap>(new Map()),\n addMenuItems: () => {},\n removeMenuItems: () => {},\n};\n\nconst [MenuContextProvider, useMenuScoped] = createMenuContext<MenuContextValue>(MENU_NAME, menuContextDefaults);\n\nconst useMenuScope = createMenuScope();\n\n//\n// Dropdown context (internal) — allows Menu.Content to close the parent dropdown.\n//\n\ntype MenuDropdownContextValue = {\n closeMenu: () => void;\n caller?: string;\n};\n\nconst MenuDropdownContext = createContext<MenuDropdownContextValue>({\n closeMenu: () => {},\n});\n\n//\n// MenuProvider (internal) — the context provider used by Menu.Root.\n//\n\nconst DEFAULT_PRIORITY = 100;\n\nconst sortMenuItems = (items: MenuItems[]) =>\n [...items].sort((a, b) => (a.priority !== b.priority ? a.priority - b.priority : a.id.localeCompare(b.id)));\n\ntype MenuProviderProps = PropsWithChildren<Partial<MenuContextValue>>;\n\nconst MenuProvider = ({\n children,\n items = menuContextDefaults.items,\n iconSize = menuContextDefaults.iconSize,\n attendableId,\n alwaysActive,\n onAction,\n}: MenuProviderProps) => {\n const { scope } = useMenuScope(undefined);\n const registry = useContext(RegistryContext);\n const menuItemsAtom = useMemo(() => Atom.make<MenuItemsMap>(new Map()).pipe(Atom.keepAlive), []);\n\n const addMenuItems = useCallback(\n (props: AddMenuItemsProps) => {\n const priority = props.priority ?? DEFAULT_PRIORITY;\n const prev = registry.get(menuItemsAtom);\n const next = new Map(prev);\n next.set(props.id, { ...props, priority });\n registry.set(menuItemsAtom, next);\n },\n [registry, menuItemsAtom],\n );\n\n const removeMenuItems = useCallback(\n (id: string) => {\n const prev = registry.get(menuItemsAtom);\n const next = new Map(prev);\n next.delete(id);\n registry.set(menuItemsAtom, next);\n },\n [registry, menuItemsAtom],\n );\n\n return (\n <MenuContextProvider\n items={items}\n iconSize={iconSize}\n attendableId={attendableId}\n alwaysActive={alwaysActive}\n menuItemsAtom={menuItemsAtom}\n addMenuItems={addMenuItems}\n removeMenuItems={removeMenuItems}\n onAction={onAction}\n scope={scope}\n >\n {children}\n </MenuContextProvider>\n );\n};\n\n//\n// Item resolution.\n//\n\nconst resolveItems = (\n baseItems: MenuItem[] | null,\n group: MenuGroupContext | undefined,\n entries: ReadonlyMap<string, MenuItems>,\n): MenuItem[] | null => {\n const applicable = [...entries.values()].filter((entry) => !entry.groupFilter || entry.groupFilter(group));\n if (applicable.length === 0) {\n return baseItems;\n }\n\n const sorted = sortMenuItems(applicable);\n\n const replacements = sorted.filter((entry) => entry.mode === 'replacement');\n if (replacements.length > 0) {\n if (replacements.length > 1) {\n log.warn('multiple replacement entries found', {\n ids: replacements.map((r) => r.id).join(', '),\n using: replacements[0].id,\n });\n }\n return replacements[0].items;\n }\n\n const additive = sorted.filter((entry) => entry.mode === 'additive');\n const additiveItems = additive.flatMap((entry) => entry.items);\n\n if (!baseItems || baseItems.length === 0) {\n return additiveItems.length > 0 ? additiveItems : null;\n }\n\n return [...baseItems, ...additiveItems];\n};\n\n//\n// Public hooks.\n//\n\nconst useMenuItems = (\n group?: MenuGroupContext,\n propsItems?: MenuItem[],\n consumerName: string = 'useMenuItemConsumer',\n __menuScope?: Scope,\n) => {\n const { items, menuItemsAtom } = useMenuScoped(consumerName, __menuScope);\n const groupItems = useAtomValue(items(group));\n const entries = useAtomValue(menuItemsAtom) ?? new Map();\n\n const baseItems = useMemo(() => propsItems ?? groupItems ?? null, [propsItems, groupItems]);\n\n const resolved = useMemo(\n () => resolveItems(baseItems, group, entries as ReadonlyMap<string, MenuItems>),\n [baseItems, group, entries],\n );\n\n return resolved ?? undefined;\n};\n\n/** Returns the menu context without Radix scope. */\nconst useMenu = (consumerName: string): MenuContextValue => {\n return useMenuScoped(consumerName, undefined);\n};\n\n//\n// Menu.Root\n//\n\ntype MenuRootProps = MenuProviderProps &\n Pick<DropdownMenuRootProps, 'children' | 'open' | 'defaultOpen' | 'onOpenChange'> & {\n /** Identifies the component that owns this menu (passed to action handlers). */\n caller?: string;\n };\n\n/**\n * Menu context boundary.\n *\n * NOTE: This component is headless since it's root div has `contents`.\n *\n * Provides the menu context (action dispatch, contribution registry, icon size, etc.)\n * and an optional dropdown root for use with `Menu.Trigger` + `Menu.Content`.\n */\nconst MenuRoot = ({ children, open, defaultOpen, onOpenChange, caller, ...props }: MenuRootProps) => {\n const [menuOpen, setMenuOpen] = useControllableState({\n prop: open,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n const closeMenu = useCallback(() => setMenuOpen(false), [setMenuOpen]);\n\n return (\n <MenuProvider {...props}>\n <MenuDropdownContext.Provider value={{ closeMenu, caller }}>\n <NaturalDropdownMenu.Root open={menuOpen} onOpenChange={setMenuOpen}>\n {children}\n </NaturalDropdownMenu.Root>\n </MenuDropdownContext.Provider>\n </MenuProvider>\n );\n};\n\n//\n// Menu.Content\n//\n\ntype MenuContentProps = {\n group?: MenuGroupContext;\n items?: MenuItem[];\n caller?: string;\n};\n\nconst MenuContentItem = ({\n item,\n onClick,\n __menuScope,\n}: MenuScopedProps<{\n item: MenuItem;\n onClick: (action: MenuAction, event: MouseEvent) => void;\n}>) => {\n const action = item as MenuAction;\n const handleClick = useCallback((event: MouseEvent) => onClick(action, event), [action, onClick]);\n const { iconSize } = useMenuScoped('MenuContentItem', __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\n/**\n * Renders the dropdown menu portal, content, and graph-backed items.\n *\n * Must be a descendant of `Menu.Root`. Reads items via `useMenuItems` from the\n * nearest menu context, with optional `group`/`items` prop overrides.\n */\nconst MenuContent = ({\n group,\n items: propsItems,\n caller: callerOverride,\n __menuScope,\n}: MenuScopedProps<MenuContentProps>) => {\n const { closeMenu, caller: contextCaller } = useContext(MenuDropdownContext);\n const caller = callerOverride ?? contextCaller;\n const { onAction } = useMenuScoped('MenuContent', __menuScope);\n const resolvedItems = useMenuItems(group, propsItems, 'MenuContent', __menuScope);\n\n const handleActionClick = useCallback(\n (action: MenuAction, event: MouseEvent) => {\n if (action.properties?.disabled) {\n return;\n }\n event.stopPropagation();\n closeMenu();\n if (onAction) {\n onAction(action, { parent: group, caller });\n } else {\n void executeMenuAction(action, { parent: group, caller });\n }\n },\n [group, caller, onAction, closeMenu],\n );\n\n return (\n <NaturalDropdownMenu.Portal>\n <NaturalDropdownMenu.Content>\n <NaturalDropdownMenu.Viewport>\n {resolvedItems?.map((item) => (\n <MenuContentItem key={item.id} item={item} onClick={handleActionClick} />\n ))}\n </NaturalDropdownMenu.Viewport>\n <NaturalDropdownMenu.Arrow />\n </NaturalDropdownMenu.Content>\n </NaturalDropdownMenu.Portal>\n );\n};\n\n//\n// Namespace.\n//\n\n/**\n * Primary namespace export for the menu system.\n *\n * - `Menu.Root` — context boundary (replaces `MenuProvider`); also provides a dropdown root.\n * - `Menu.Trigger` / `Menu.VirtualTrigger` — dropdown trigger (use with `Menu.Content`).\n * - `Menu.Content` — renders graph-backed dropdown items inside a portal.\n * - `Menu.Toolbar` — flat toolbar component with graph-backed item rendering.\n */\nconst Menu = {\n Root: MenuRoot,\n Trigger: NaturalDropdownMenu.Trigger,\n Content: MenuContent,\n VirtualTrigger: NaturalDropdownMenu.VirtualTrigger,\n Toolbar: ToolbarMenu,\n};\n\nexport { Menu, menuContextDefaults, useMenu, useMenuItems, useMenuScoped };\n\nexport type { MenuContentProps, MenuRootProps, MenuScopedProps };\n\nexport type {\n ToolbarMenuActionGroupProperties,\n ToolbarMenuActionGroupProps,\n ToolbarMenuActionProps,\n ToolbarMenuDropdownMenuActionGroup,\n ToolbarMenuProps,\n ToolbarMenuToggleGroupActionGroup,\n} from './ToolbarMenu';\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Node } from '@dxos/app-graph';\nimport { EffectEx } 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 EffectEx.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--circle-dashed--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 = <P extends MenuItemGroupProperties>(id: string, properties: P) =>\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 relation: 'child' as const,\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, relation: 'child' as const }],\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 { mx } from '@dxos/ui-theme';\nimport { type MenuActionProperties, type MenuItemChrome } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport { getShortcut } from '../util';\n\ntype Action = Node.Action<MenuActionProperties> | Node.ActionGroup<MenuItemChrome>;\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', 'text-description')}>{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 2025 DXOS.org\n//\n\nimport React, { useCallback } from 'react';\n\nimport {\n Input,\n Toolbar as NaturalToolbar,\n type ToolbarRootProps,\n Tooltip,\n toLocalizedString,\n useTranslation,\n} from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { type DropdownMenuItemGroupProperties, type ToggleGroupMenuItemGroupProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport { type MenuAction, type MenuItem, type MenuItemGroup, isMenuGroup, isSeparator } from '../types';\nimport { executeMenuAction } from '../util';\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';\n\nexport type ToolbarMenuDropdownMenuActionGroup = DropdownMenuItemGroupProperties;\n\nexport type ToolbarMenuToggleGroupActionGroup = ToggleGroupMenuItemGroupProperties;\n\nexport type ToolbarMenuActionGroupProperties = DropdownMenuItemGroupProperties | ToggleGroupMenuItemGroupProperties;\n\nexport type ToolbarMenuProps = ToolbarRootProps;\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuDropdownGroupProps = {\n group: MenuItemGroup<DropdownMenuItemGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuToggleGroupProps = {\n group: MenuItemGroup<ToggleGroupMenuItemGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuActionProps = {\n group: MenuItemGroup<ToggleGroupMenuItemGroupProperties>;\n action: MenuAction;\n};\n\nconst ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: MenuAction }>) => {\n const { iconSize, onAction } = useMenuScoped('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n\n const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;\n const buttonVariant =\n (action.properties as { variant?: string }).variant === 'primary' ? ('primary' as const) : ('ghost' as const);\n\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\n const commonProps = {\n variant: buttonVariant,\n disabled,\n classNames,\n onClick: handleClick,\n ...(testId && { 'data-testid': testId }),\n };\n\n if (hidden) {\n return null;\n }\n\n return icon ? (\n <NaturalToolbar.IconButton\n key={action.id}\n {...commonProps}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(action, t)}\n />\n ) : (\n <NaturalToolbar.Button key={action.id} {...commonProps}>\n <ActionLabel action={action} />\n </NaturalToolbar.Button>\n );\n};\n\nconst SwitchToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: MenuAction }>) => {\n const { onAction } = useMenuScoped('SwitchToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { label, iconOnly, disabled, testId, hidden, checked } = action.properties;\n const labelStr = toLocalizedString(label, t);\n\n const handleCheckedChange = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\n if (hidden) {\n return null;\n }\n\n const switchInput = (\n <Input.Switch\n checked={checked}\n disabled={disabled}\n aria-label={iconOnly ? labelStr : undefined}\n onCheckedChange={handleCheckedChange}\n {...(testId && { 'data-testid': testId })}\n />\n );\n\n return (\n <Input.Root>\n {iconOnly ? (\n <Tooltip.Trigger asChild content={labelStr}>\n <Input.Block>{switchInput}</Input.Block>\n </Tooltip.Trigger>\n ) : (\n <Input.Block>{switchInput}</Input.Block>\n )}\n {!iconOnly && <Input.Label>{labelStr}</Input.Label>}\n </Input.Root>\n );\n};\n\nconst DropdownMenuToolbarItem = ({\n __menuScope,\n group,\n items: propsItems,\n}: MenuScopedProps<ToolbarMenuDropdownGroupProps>) => {\n const { t } = useTranslation(translationKey);\n const { iconSize } = useMenuScoped('DropdownMenuToolbarItem', __menuScope);\n const items = useMenuItems(group, propsItems, 'DropdownMenuToolbarItem', __menuScope);\n const {\n iconOnly,\n disabled,\n testId,\n applyActive,\n caretDown = true,\n icon: groupIcon,\n iconClassNames: groupIconClassNames,\n } = group.properties;\n const activeItem = items?.find((item) => !!(item as MenuAction).properties.checked) as MenuAction | undefined;\n const icon =\n (applyActive &&\n // TODO(thure): Handle other menu item types.\n activeItem?.properties.icon) ||\n groupIcon;\n // Follow the same `applyActive` rule for `iconClassNames` so a per-item accent (e.g. tag colour) tracks the displayed icon.\n const iconClassNames = (applyActive && activeItem?.properties.iconClassNames) || groupIconClassNames;\n const labelAction = applyActive && activeItem ? activeItem : group;\n\n return (\n <DropdownMenu.Root group={group} items={items}>\n <DropdownMenu.Trigger asChild>\n {icon ? (\n <NaturalToolbar.IconButton\n variant='ghost'\n disabled={disabled}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(labelAction, t)}\n caretDown={caretDown}\n {...(testId && { 'data-testid': testId })}\n />\n ) : (\n <NaturalToolbar.Button\n variant='ghost'\n disabled={disabled}\n caretDown={caretDown}\n {...(testId && { 'data-testid': testId })}\n >\n <ActionLabel action={labelAction} />\n </NaturalToolbar.Button>\n )}\n </DropdownMenu.Trigger>\n </DropdownMenu.Root>\n );\n};\n\nconst ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<ToolbarMenuActionProps>) => {\n const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;\n\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\n const commonProps = {\n value: action.id,\n disabled,\n variant: 'ghost' as const,\n classNames,\n onClick: handleClick,\n ...(testId && { 'data-testid': testId }),\n };\n\n return hidden ? null : icon ? (\n <NaturalToolbar.ToggleGroupIconItem\n {...commonProps}\n icon={icon}\n size={iconSize}\n iconOnly={iconOnly}\n iconClassNames={iconClassNames}\n label={actionLabel(action, t)}\n />\n ) : (\n <NaturalToolbar.ToggleGroupItem {...commonProps}>\n <ActionLabel action={action} />\n </NaturalToolbar.ToggleGroupItem>\n );\n};\n\nconst ToggleGroupToolbarItem = ({\n __menuScope,\n group,\n items: itemsProp,\n}: MenuScopedProps<ToolbarMenuToggleGroupProps>) => {\n const items = useMenuItems(group, itemsProp, 'ToggleGroupToolbarItem', __menuScope);\n const { selectCardinality } = group.properties;\n\n // TODO(thure): Handle other menu item types.\n const children = (items as MenuAction[]).map((action) => (\n <ToggleGroupItem key={action.id} group={group} action={action} />\n ));\n\n if (selectCardinality === 'multiple') {\n return (\n <NaturalToolbar.ToggleGroup type='multiple' value={group.properties.value}>\n {children}\n </NaturalToolbar.ToggleGroup>\n );\n } else {\n return (\n <NaturalToolbar.ToggleGroup type='single' value={group.properties.value}>\n {children}\n </NaturalToolbar.ToggleGroup>\n );\n }\n};\n\nexport const ToolbarMenu = composable<HTMLDivElement, MenuScopedProps<ToolbarMenuProps>>(\n ({ __menuScope, children, ...props }, forwardedRef) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId, alwaysActive } = useMenuScoped('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n\n return (\n <NaturalToolbar.Root\n {...composableProps(props, { classNames: attendableId })}\n disabled={!alwaysActive && !hasAttention}\n ref={forwardedRef}\n >\n {items?.map((item: MenuItem) => (\n <ToolbarMenuItem key={item.id} __menuScope={__menuScope} item={item} />\n ))}\n {children}\n </NaturalToolbar.Root>\n );\n },\n);\n\nconst ToolbarMenuItem = ({ __menuScope, item }: MenuScopedProps<{ item: MenuItem }>) => {\n if (isSeparator(item)) {\n return <NaturalToolbar.Separator variant={item.properties.variant} />;\n }\n\n if (isMenuGroup(item)) {\n if (item.properties.variant === 'dropdownMenu') {\n return (\n <DropdownMenuToolbarItem\n __menuScope={__menuScope}\n group={item as MenuItemGroup<DropdownMenuItemGroupProperties>}\n />\n );\n }\n\n return (\n <ToggleGroupToolbarItem\n __menuScope={__menuScope}\n group={item as MenuItemGroup<ToggleGroupMenuItemGroupProperties>}\n />\n );\n }\n\n const action = item as MenuAction;\n if (action.properties?.variant === 'switch') {\n return <SwitchToolbarItem __menuScope={__menuScope} action={action} />;\n }\n\n // The contributor owns the rendered element (interactions the action model cannot express).\n if (action.properties?.variant === 'custom' && action.properties.render) {\n return <>{action.properties.render()}</>;\n }\n\n return <ActionToolbarItem __menuScope={__menuScope} action={action} />;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom } from '@effect-atom/atom-react';\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 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\n/** Graph-sourced menu nodes carry plugin-specific properties validated at runtime. */\nexport type GraphMenuItem = Node.Action | Node.ActionGroup;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup | GraphMenuItem;\n\n/** Group context for graph-backed dropdown menus (any graph node, not only action groups). */\nexport type MenuGroupContext = MenuItemGroup | Node.Node;\n\n/** Atom-family-style accessor: returns an atom of items for a given group (or root when undefined). */\nexport type MenuItemsAccessor = (group?: MenuGroupContext) => Atom.Atom<MenuItem[] | null>;\n\nexport type ActionExecutor = (action: MenuAction, params: Node.InvokeProps) => void;\n\nexport type MenuItemsMode = 'additive' | 'replacement';\n\nexport type AddMenuItemsProps = {\n id: string;\n mode: MenuItemsMode;\n priority?: number;\n items: MenuItem[];\n groupFilter?: (group?: MenuGroupContext) => boolean;\n};\n\nexport type MenuItems = Omit<AddMenuItemsProps, 'priority'> & { priority: number };\nexport type MenuItemsMap = Map<string, MenuItems>;\n\nexport type MenuContextValue = {\n /** Atom-family accessor for base menu items, keyed by group (similar to Tree model). */\n items: MenuItemsAccessor;\n iconSize: IconButtonProps['size'];\n attendableId?: string;\n /** TODO(burdon): Remove and assume always active if attendableId is undefined. */\n /** If true, the menu is always active regardless of attention state. */\n alwaysActive?: boolean;\n /** Atom holding the current set of imperatively added menu items. */\n menuItemsAtom: Atom.Atom<MenuItemsMap>;\n /** Imperatively add menu items to the nearest MenuProvider. */\n addMenuItems: (props: AddMenuItemsProps) => void;\n /** Remove previously added menu items by id. */\n removeMenuItems: (id: string) => void;\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 { 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';\nimport { ActionLabel } from './ActionLabel';\nimport { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';\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 } = useMenuScoped('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 } = useMenuScoped('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 2026 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom-react';\nimport { useMemo } from 'react';\n\nimport { type Graph, Node } from '@dxos/app-graph';\n\nimport {\n type ActionGraphEdges,\n type ActionGraphNodes,\n type ActionGraphProps,\n type MenuActions,\n useMenuActions,\n} from './useMenuActions';\n\nexport type GraphMenuOptions = {\n /** Group the actions descend from. Defaults to the menu root (top-level toolbar items). */\n rootId?: string;\n /** Keep only the actions the predicate accepts (e.g. by `disposition`). */\n filter?: (action: Node.ActionLike) => boolean;\n};\n\n/**\n * Flatten a node's contributed actions (and nested {@link Node.ActionGroup}s) into the\n * `{ nodes, edges }` an {@link useMenuActions} / `Menu` consumes. The action nodes are spliced\n * verbatim, so their Effect `data` (and captured `_actionContext`) execute via `executeMenuAction`\n * without any `onAction` wiring.\n *\n * Pure over a `resolve` function so it is testable without a live graph; `resolve(id)` returns the\n * direct actions for `id` (a node id at the top level, a group id when expanding a group).\n */\nexport const buildGraphMenu = (\n resolve: (id: string) => Node.ActionLike[],\n nodeId: string,\n options: GraphMenuOptions = {},\n): ActionGraphProps => {\n const { rootId = Node.RootId, filter } = options;\n const nodes: ActionGraphNodes = [];\n const edges: ActionGraphEdges = [];\n const seen = new Set<string>();\n\n const visit = (parentId: string, sourceId: string) => {\n for (const action of resolve(sourceId)) {\n if (filter && !filter(action)) {\n continue;\n }\n // Always record the parent→child edge (a shared action may sit under multiple groups).\n edges.push({ source: parentId, target: action.id, relation: 'child' });\n if (seen.has(action.id)) {\n continue;\n }\n seen.add(action.id);\n nodes.push(action as ActionGraphNodes[number]);\n // A group's children are the actions contributed for the group's own id.\n if (Node.isActionGroup(action)) {\n visit(action.id, action.id);\n }\n }\n };\n\n visit(rootId, nodeId);\n return { nodes, edges };\n};\n\n/**\n * Read a node's contributed actions from the app-graph as menu `ActionGraphProps`, for splicing into a\n * hand-built toolbar via `MenuBuilder.subgraph(graphActions(graph, get, nodeId))`. Reactive: reads the\n * graph's action atoms through `get`, so contributed actions appear/disappear as extensions update.\n */\nexport const graphActions = (\n graph: Graph.ReadableGraph | undefined,\n get: Atom.Context,\n nodeId: string | undefined,\n options?: GraphMenuOptions,\n): ActionGraphProps =>\n graph && nodeId ? buildGraphMenu((id) => get(graph.actions(id)), nodeId, options) : { nodes: [], edges: [] };\n\n/**\n * Menu actions sourced entirely from a node's app-graph contributions — the common \"show every action\n * the graph offers for this object\" toolbar/menu. Compose with hand-built items via {@link graphActions}.\n */\nexport const useGraphMenuActions = (\n graph: Graph.ReadableGraph | undefined,\n nodeId: string | undefined,\n options?: GraphMenuOptions,\n): MenuActions => {\n const atom = useMemo(\n () => Atom.make((get) => graphActions(graph, get, nodeId, options)),\n // `options` is expected to be stable; `rootId` participates since it reshapes the graph.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [graph, nodeId, options?.rootId],\n );\n return useMenuActions(atom);\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { type DependencyList, useCallback, useContext, useMemo } from 'react';\n\nimport { Graph, Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup, type MenuItemsAccessor } 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 items: MenuItemsAccessor;\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 // NOTE: Using useMemo rather than a ref-mutation pattern to avoid calling registry.set during render,\n // which would trigger atom state updates in other components (setState-in-render React warning).\n const graph = useMemo(() => {\n const newGraph = Graph.make({ registry });\n newGraph.pipe(Graph.addNodes(menuGraphProps.nodes as Node.NodeArg<any>[]), Graph.addEdges(menuGraphProps.edges));\n return newGraph;\n }, [registry, menuGraphProps]);\n\n const items: MenuItemsAccessor = useCallback(\n (group?: MenuItemGroup) => {\n // TODO(wittjosiah): Migrate to using action relation instead of child.\n return graph.connections(group?.id || Node.RootId, 'child') as Atom.Atom<MenuItem[] | null>;\n },\n [graph],\n );\n\n return { items };\n};\n\n/**\n * Convenience wrapper around `useMenuActions` that creates the backing atom inline.\n * Pass a builder thunk and a dependency list — the hook memoizes `Atom.make(build)` and threads\n * it through `useMenuActions`. Saves the `useMemo(() => Atom.make(...), deps)` boilerplate when\n * the action graph is composed from local state (e.g. a toolbar driven by component state).\n *\n * Read reactive state via `get` inside the builder; `deps` should hold only stable references.\n */\nexport const useMenuBuilder = (build: (get: Atom.Context) => ActionGraphProps, deps: DependencyList): MenuActions => {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const atom = useMemo(() => Atom.make(build), deps);\n return useMenuActions(atom);\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport type { DropdownMenuItemGroupProperties, MenuActionProperties, MenuItemGroupProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport type { ActionGraphProps } from './hooks';\nimport { MenuSeparatorType } from './types';\nimport { createMenuAction, createMenuItemGroup } from './util';\n\n/** Default trigger for toolbar overflow (⋮) dropdown menus. */\nconst overflowMenuProperties = {\n label: ['toolbar-overflow.menu', { ns: translationKey }],\n icon: 'ph--dots-three-vertical--regular',\n iconOnly: true,\n caretDown: false,\n variant: 'dropdownMenu',\n} as const satisfies DropdownMenuItemGroupProperties;\n\n/** Callback that populates an action group builder. */\nexport type ActionGroupBuilderFn = (builder: ActionGroupBuilder) => void;\n\n/**\n * Fluent builder for composing menu action graphs.\n * Subgraph functions return a callback that receives the builder, enabling composition via partial application:\n * ```ts\n * const addHeadings = (state): ActionGroupBuilderFn => (builder) => {\n * builder.group('headings', { ... }, (group) => { ... });\n * };\n *\n * MenuBuilder.make()\n * .subgraph(showHeadings && addHeadings(state))\n * .subgraph(showFormatting && addFormatting(state))\n * .build();\n * ```\n */\nexport interface ActionGroupBuilder {\n /** Add an action node as a child of the current group. */\n action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;\n\n /** Add a switch action rendered as a labeled Input.Switch. */\n switch(id: string, props: Omit<MenuActionProperties, 'variant'> & { checked: boolean }, invoke: () => void): this;\n\n /** Add a nested action group. */\n group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this;\n\n /** Merge pre-built nodes and edges, or build a subgraph via callback scoped to the current group. Falsy values are ignored. */\n subgraph(subgraphOrCb: ActionGraphProps | ActionGroupBuilderFn | false | null | undefined): this;\n\n /** Add a separator. */\n separator(variant?: 'gap' | 'line'): this;\n}\n\n/** Top-level builder that creates the root group and produces the final action graph. */\nexport interface MenuBuilder extends ActionGroupBuilder {\n /**\n * Set properties on the root menu group. May only be called once.\n */\n root(props: MenuItemGroupProperties): this;\n\n /**\n * Add a root-level toolbar overflow dropdown (⋮) with built-in trigger styling.\n */\n menu(id: string, cb: ActionGroupBuilderFn): this;\n\n /**\n * Return the assembled action graph.\n */\n build(): ActionGraphProps;\n}\n\nclass MenuBuilderImpl implements MenuBuilder {\n private _separatorCount = 0;\n\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 build(): ActionGraphProps {\n return this._data;\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, relation: 'child' });\n return this;\n }\n\n switch(id: string, props: Omit<MenuActionProperties, 'variant'> & { checked: boolean }, invoke: () => void): this {\n return this.action(id, { ...props, variant: 'switch' }, invoke);\n }\n\n group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this {\n this._data.nodes.push(createMenuItemGroup(id, props));\n this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });\n cb(new MenuBuilderImpl(this._data, id));\n return this;\n }\n\n menu(id: string, cb: ActionGroupBuilderFn): this {\n return this.group(id, overflowMenuProperties, cb);\n }\n\n subgraph(subgraphOrCb: ActionGraphProps | ActionGroupBuilderFn | false | null | undefined): this {\n if (!subgraphOrCb) {\n return this;\n }\n if (typeof subgraphOrCb === 'function') {\n subgraphOrCb(new MenuBuilderImpl(this._data, this._rootId));\n } else {\n this._data.nodes.push(...subgraphOrCb.nodes);\n this._data.edges.push(...subgraphOrCb.edges);\n }\n return this;\n }\n\n separator(variant: 'gap' | 'line' = 'gap'): this {\n const id = `separator-${++this._separatorCount}`;\n this._data.nodes.push({\n id,\n type: MenuSeparatorType,\n properties: { variant },\n data: undefined as never,\n });\n this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });\n return this;\n }\n}\n\nexport const MenuBuilder = Object.freeze({\n make: (): MenuBuilder => new MenuBuilderImpl({ nodes: [], edges: [] }, 'root'),\n});\n"],
5
+ "mappings": ";AAIA,SAASA,MAAMC,iBAAiBC,oBAAoB;AACpD,SAAqBC,0BAA0B;AAC/C,SAASC,wBAAAA,6BAA4B;AACrC,OAAOC,UAAkDC,eAAeC,eAAAA,cAAaC,YAAYC,eAAe;AAEhH,SAASC,WAAW;AACpB,SAAqCC,QAAAA,OAAMC,gBAAgBC,4BAA2B;;;ACNtF,YAAYC,YAAY;AAExB,SAASC,YAAY;AACrB,SAASC,gBAAgB;AAEzB,SAASC,uBAAuB;AAQzB,IAAMC,oBAAoB,OAAOC,QAAoBC,SAA2B,CAAC,MAAC;AACvF,MAAIC,SAASF,OAAOG,KAAKF,MAAAA;AAGzB,MAAID,OAAOI,gBAAgB;AACzBF,aAASA,OAAOG,KAAYC,eAAQN,OAAOI,cAAc,CAAA;EAC3D;AAEA,QAAMP,SAASU,oBAAoBL,MAAAA;AACrC;AAEO,IAAMM,cAAc,CAACR,WAAAA;AAC1B,SAAO,OAAOA,OAAOS,YAAYC,eAAe,WAC5CV,OAAOS,WAAWC,aAClBV,OAAOS,YAAYC,aAAaZ,gBAAAA,CAAAA;AACtC;AAIO,IAAMa,mBAAmB,CAC9BC,IACAC,QACAC,gBAEC;EACCF;EACAG,MAAMC,KAAKC;EACXH;EACAI,MAAM,MAAaC,YAAKN,MAAAA;AAC1B;AAEK,IAAMO,sBAAsB,CAAoCR,IAAYE,gBAChF;EACCF;EACAG,MAAMC,KAAKK;EACXP;EACAI,MAAMF,KAAKM;AACb;AAEK,IAAMC,qBAAqB,CAACX,KAAa,OAAOY,SAAiB,YAAY;EAClFC,OAAO;IACL;MACEb;MACAG,MAAM;MACND,YAAY;QAAEY,SAAS;MAAM;MAC7BR,MAAMS;IACR;;EAEFC,OAAO;IACL;MACEJ;MACAK,QAAQjB;MACRkB,UAAU;IACZ;;AAEJ;AAEO,IAAMC,sBAAsB,CAACnB,KAAa,QAAQY,SAAiB,YAAY;EACpFC,OAAO;IACL;MACEb;MACAG,MAAM;MACND,YAAY;QAAEY,SAAS;MAAO;MAC9BR,MAAMS;IACR;;EAEFC,OAAO;IAAC;MAAEJ;MAAQK,QAAQjB;MAAIkB,UAAU;IAAiB;;AAC3D;;;AChFA,OAAOE,WAAW;AAGlB,SAASC,kBAAkB;AAC3B,SAAyBC,mBAAmBC,sBAAsB;AAClE,SAASC,UAAU;AAGnB,SAASC,sBAAsB;AAMxB,IAAMC,cAAc,CAAC,EAAEC,OAAM,MAAsB;AACxD,QAAM,EAAEC,EAAC,IAAKC,eAAeC,cAAAA;AAC7B,QAAMC,WAAWC,YAAYL,MAAAA;AAC7B,SACE,sBAAA,cAAA,MAAA,UAAA,MACE,sBAAA,cAACM,QAAAA;IAAKC,WAAU;KAAiBC,kBAAkBR,OAAOS,WAAYC,OAAOT,CAAAA,CAAAA,GAC5EG,YAAY,sBAAA,cAACE,QAAAA;IAAKC,WAAWI,GAAG,YAAY,kBAAA;KAAsBC,WAAWR,QAAAA,EAAUS,KAAK,EAAA,CAAA,CAAA;AAGnG;AAEO,IAAMC,cAAc,CAACd,QAAgBC,MAAAA;AAC1C,QAAMG,WAAWC,YAAYL,MAAAA;AAC7B,SAAO,GAAGQ,kBAAkBR,OAAOS,WAAYC,OAAOT,CAAAA,CAAAA,GAAKG,WAAW,KAAKQ,WAAWR,QAAAA,EAAUS,KAAK,EAAA,CAAA,MAAS,EAAA;AAChH;;;AC5BA,OAAOE,UAASC,eAAAA,oBAAmB;AAEnC,SACEC,OACAC,WAAWC,gBAEXC,SACAC,qBAAAA,oBACAC,kBAAAA,uBACK;AACP,SAASC,YAAYC,uBAAuB;AAC5C,SAASC,oBAAoB;AAG7B,SAASC,kBAAAA,uBAAsB;;;ACZ/B,SAASC,QAAAA,aAAY;AAMd,IAAMC,oBAAoB;AAM1B,IAAMC,cAAc,CAACC,SAA2CA,KAAKC,SAASH;AAI9E,IAAMI,cAAc,CAACF,SAA2CA,KAAKC,SAASJ,MAAKM;;;AClB1F,SAASC,4BAA4B;AACrC,OAAOC,UAA0BC,mBAAmB;AAEpD,SAAqCC,MAAMC,gBAAgBC,2BAA2B;AAatF,IAAMC,mBAAmB,CAAC,EACxBC,MACAC,SACAC,YAAW,MAIX;AAEA,QAAMC,SAASH;AACf,QAAMI,cAAcC,YAAY,CAACC,UAAsBL,QAAQE,QAAQG,KAAAA,GAAQ;IAACH;IAAQF;GAAQ;AAChG,QAAM,EAAEM,SAAQ,IAAKC,cAAc,oBAAoBN,WAAAA;AACvD,SACE,gBAAAO,OAAA,cAACC,oBAAoBC,MAAI;IACvBV,SAASG;IACTQ,YAAW;IACXC,UAAUV,OAAOW,YAAYD;IAC5B,GAAIV,OAAOW,YAAYC,UAAU;MAAE,eAAeZ,OAAOW,WAAWC;IAAO;KAE3EZ,OAAOW,YAAYE,QAAQ,gBAAAP,OAAA,cAACQ,MAAAA;IAAKD,MAAMb,OAAOW,WAAYE;IAAME,MAAMX;MACvE,gBAAAE,OAAA,cAACU,aAAAA;IAAYhB;;AAGnB;AAEA,IAAMiB,mBAAmB,CAAC,EACxBC,OAAOC,YACPC,OACAC,MACAC,aACAC,cACAC,QACAC,UACA1B,aACA,GAAG2B,aAAAA,MACgC;AACnC,QAAM,CAACC,iBAAiBC,kBAAAA,IAAsBC,qBAAqB;IACjEC,MAAMT;IACNU,aAAaT;IACbU,UAAUT;EACZ,CAAA;AAEA,QAAM,EAAEU,SAAQ,IAAK5B,cAAc,oBAAoBN,WAAAA;AAEvD,QAAMmC,oBAAoBhC,YACxB,CAACF,QAAoBG,UAAAA;AACnB,QAAIH,OAAOW,YAAYD,UAAU;AAC/B;IACF;AACAP,UAAMgC,gBAAe;AAErBP,uBAAmB,KAAA;AACnB,QAAIK,UAAU;AACZA,eAASjC,QAAQ;QAAEoC,QAAQhB;QAAOI;MAAO,CAAA;IAC3C,OAAO;AACL,WAAKa,kBAAkBrC,QAAQ;QAAEoC,QAAQhB;QAAOI;MAAO,CAAA;IACzD;EACF,GACA;IAACJ;IAAOI;IAAQS;GAAS;AAG3B,QAAMf,QAAQoB,aAAalB,OAAOD,UAAAA;AAElC,SACE,gBAAAb,OAAA,cAACC,oBAAoBgC,MAAI;IAAClB,MAAMM;IAAiBJ,cAAcK;IAAqB,GAAGF;KACpFD,UACD,gBAAAnB,OAAA,cAACC,oBAAoBiC,QAAM,MACzB,gBAAAlC,OAAA,cAACC,oBAAoBkC,SAAO,MAC1B,gBAAAnC,OAAA,cAACC,oBAAoBmC,UAAQ,MAC1BxB,OAAOyB,IAAI,CAAC9C,SACX,gBAAAS,OAAA,cAACV,kBAAAA;IAAiBgD,KAAK/C,KAAKgD;IAAIhD;IAAYC,SAASoC;QAGzD,gBAAA5B,OAAA,cAACC,oBAAoBuC,OAAK,IAAA,CAAA,CAAA,CAAA;AAKpC;AAEO,IAAMC,eAAe;EAC1BR,MAAMtB;EACN+B,SAASzC,oBAAoByC;EAC7BC,gBAAgB1C,oBAAoB0C;AACtC;;;AFlDA,IAAMC,oBAAoB,CAAC,EAAEC,aAAaC,OAAM,MAA2C;AACzF,QAAM,EAAEC,UAAUC,SAAQ,IAAKC,cAAc,qBAAqBJ,WAAAA;AAClE,QAAM,EAAEK,EAAC,IAAKC,gBAAeC,eAAAA;AAE7B,QAAM,EAAEC,MAAMC,WAAW,MAAMC,UAAUC,QAAQC,QAAQC,YAAYC,eAAc,IAAKb,OAAOc;AAC/F,QAAMC,gBACHf,OAAOc,WAAoCE,YAAY,YAAa,YAAuB;AAE9F,QAAMC,cAAcC,aAAY,MAAA;AAC9B,QAAIhB,UAAU;AACZA,eAASF,QAAQ,CAAC,CAAA;IACpB,OAAO;AACL,WAAKmB,kBAAkBnB,MAAAA;IACzB;EACF,GAAG;IAACA;IAAQE;GAAS;AAErB,QAAMkB,cAAc;IAClBJ,SAASD;IACTN;IACAG;IACAS,SAASJ;IACT,GAAIP,UAAU;MAAE,eAAeA;IAAO;EACxC;AAEA,MAAIC,QAAQ;AACV,WAAO;EACT;AAEA,SAAOJ,OACL,gBAAAe,OAAA,cAACC,eAAeC,YAAU;IACxBC,KAAKzB,OAAO0B;IACX,GAAGN;IACJb;IACAoB,MAAM1B;IACNO;IACAK;IACAe,OAAOC,YAAY7B,QAAQI,CAAAA;OAG7B,gBAAAkB,OAAA,cAACC,eAAeO,QAAM;IAACL,KAAKzB,OAAO0B;IAAK,GAAGN;KACzC,gBAAAE,OAAA,cAACS,aAAAA;IAAY/B;;AAGnB;AAEA,IAAMgC,oBAAoB,CAAC,EAAEjC,aAAaC,OAAM,MAA2C;AACzF,QAAM,EAAEE,SAAQ,IAAKC,cAAc,qBAAqBJ,WAAAA;AACxD,QAAM,EAAEK,EAAC,IAAKC,gBAAeC,eAAAA;AAC7B,QAAM,EAAEsB,OAAOpB,UAAUC,UAAUC,QAAQC,QAAQsB,QAAO,IAAKjC,OAAOc;AACtE,QAAMoB,WAAWC,mBAAkBP,OAAOxB,CAAAA;AAE1C,QAAMgC,sBAAsBlB,aAAY,MAAA;AACtC,QAAIhB,UAAU;AACZA,eAASF,QAAQ,CAAC,CAAA;IACpB,OAAO;AACL,WAAKmB,kBAAkBnB,MAAAA;IACzB;EACF,GAAG;IAACA;IAAQE;GAAS;AAErB,MAAIS,QAAQ;AACV,WAAO;EACT;AAEA,QAAM0B,cACJ,gBAAAf,OAAA,cAACgB,MAAMC,QAAM;IACXN;IACAxB;IACA+B,cAAYhC,WAAW0B,WAAWO;IAClCC,iBAAiBN;IAChB,GAAI1B,UAAU;MAAE,eAAeA;IAAO;;AAI3C,SACE,gBAAAY,OAAA,cAACgB,MAAMK,MAAI,MACRnC,WACC,gBAAAc,OAAA,cAACsB,QAAQC,SAAO;IAACC,SAAAA;IAAQC,SAASb;KAChC,gBAAAZ,OAAA,cAACgB,MAAMU,OAAK,MAAEX,WAAAA,CAAAA,IAGhB,gBAAAf,OAAA,cAACgB,MAAMU,OAAK,MAAEX,WAAAA,GAEf,CAAC7B,YAAY,gBAAAc,OAAA,cAACgB,MAAMW,OAAK,MAAEf,QAAAA,CAAAA;AAGlC;AAEA,IAAMgB,0BAA0B,CAAC,EAC/BnD,aACAoD,OACAC,OAAOC,WAAU,MAC8B;AAC/C,QAAM,EAAEjD,EAAC,IAAKC,gBAAeC,eAAAA;AAC7B,QAAM,EAAEL,SAAQ,IAAKE,cAAc,2BAA2BJ,WAAAA;AAC9D,QAAMqD,QAAQE,aAAaH,OAAOE,YAAY,2BAA2BtD,WAAAA;AACzE,QAAM,EACJS,UACAC,UACAC,QACA6C,aACAC,YAAY,MACZjD,MAAMkD,WACN5C,gBAAgB6C,oBAAmB,IACjCP,MAAMrC;AACV,QAAM6C,aAAaP,OAAOQ,KAAK,CAACC,SAAS,CAAC,CAAEA,KAAoB/C,WAAWmB,OAAO;AAClF,QAAM1B,OACHgD;EAECI,YAAY7C,WAAWP,QACzBkD;AAEF,QAAM5C,iBAAkB0C,eAAeI,YAAY7C,WAAWD,kBAAmB6C;AACjF,QAAMI,cAAcP,eAAeI,aAAaA,aAAaR;AAE7D,SACE,gBAAA7B,OAAA,cAACyC,aAAapB,MAAI;IAACQ;IAAcC;KAC/B,gBAAA9B,OAAA,cAACyC,aAAalB,SAAO;IAACC,SAAAA;KACnBvC,OACC,gBAAAe,OAAA,cAACC,eAAeC,YAAU;IACxBR,SAAQ;IACRP;IACAF;IACAoB,MAAM1B;IACNO;IACAK;IACAe,OAAOC,YAAYiC,aAAa1D,CAAAA;IAChCoD;IACC,GAAI9C,UAAU;MAAE,eAAeA;IAAO;OAGzC,gBAAAY,OAAA,cAACC,eAAeO,QAAM;IACpBd,SAAQ;IACRP;IACA+C;IACC,GAAI9C,UAAU;MAAE,eAAeA;IAAO;KAEvC,gBAAAY,OAAA,cAACS,aAAAA;IAAY/B,QAAQ8D;;AAMjC;AAEA,IAAME,kBAAkB,CAAC,EAAEjE,aAAaoD,OAAOnD,OAAM,MAA2C;AAC9F,QAAM,EAAEC,UAAUC,SAAQ,IAAKC,cAAc,mBAAmBJ,WAAAA;AAChE,QAAM,EAAEK,EAAC,IAAKC,gBAAeC,eAAAA;AAC7B,QAAM,EAAEC,MAAMC,WAAW,MAAMC,UAAUC,QAAQC,QAAQC,YAAYC,eAAc,IAAKb,OAAOc;AAE/F,QAAMG,cAAcC,aAAY,MAAA;AAC9B,QAAIhB,UAAU;AACZA,eAASF,QAAQ;QAAEiE,QAAQd;MAAM,CAAA;IACnC,OAAO;AACL,WAAKhC,kBAAkBnB,QAAQ;QAAEiE,QAAQd;MAAM,CAAA;IACjD;EACF,GAAG;IAACnD;IAAQmD;IAAOjD;GAAS;AAE5B,QAAMkB,cAAc;IAClB8C,OAAOlE,OAAO0B;IACdjB;IACAO,SAAS;IACTJ;IACAS,SAASJ;IACT,GAAIP,UAAU;MAAE,eAAeA;IAAO;EACxC;AAEA,SAAOC,SAAS,OAAOJ,OACrB,gBAAAe,OAAA,cAACC,eAAe4C,qBAAmB;IAChC,GAAG/C;IACJb;IACAoB,MAAM1B;IACNO;IACAK;IACAe,OAAOC,YAAY7B,QAAQI,CAAAA;OAG7B,gBAAAkB,OAAA,cAACC,eAAeyC,iBAAoB5C,aAClC,gBAAAE,OAAA,cAACS,aAAAA;IAAY/B;;AAGnB;AAEA,IAAMoE,yBAAyB,CAAC,EAC9BrE,aACAoD,OACAC,OAAOiB,UAAS,MAC6B;AAC7C,QAAMjB,QAAQE,aAAaH,OAAOkB,WAAW,0BAA0BtE,WAAAA;AACvE,QAAM,EAAEuE,kBAAiB,IAAKnB,MAAMrC;AAGpC,QAAMyD,WAAYnB,MAAuBoB,IAAI,CAACxE,WAC5C,gBAAAsB,OAAA,cAAC0C,iBAAAA;IAAgBvC,KAAKzB,OAAO0B;IAAIyB;IAAcnD;;AAGjD,MAAIsE,sBAAsB,YAAY;AACpC,WACE,gBAAAhD,OAAA,cAACC,eAAekD,aAAW;MAACC,MAAK;MAAWR,OAAOf,MAAMrC,WAAWoD;OACjEK,QAAAA;EAGP,OAAO;AACL,WACE,gBAAAjD,OAAA,cAACC,eAAekD,aAAW;MAACC,MAAK;MAASR,OAAOf,MAAMrC,WAAWoD;OAC/DK,QAAAA;EAGP;AACF;AAEO,IAAMI,cAAcC,WACzB,CAAC,EAAE7E,aAAawE,UAAU,GAAGM,MAAAA,GAASC,iBAAAA;AACpC,QAAM1B,QAAQE,aAAab,QAAWA,QAAW,eAAe1C,WAAAA;AAChE,QAAM,EAAEgF,cAAcC,aAAY,IAAK7E,cAAc,eAAeJ,WAAAA;AACpE,QAAM,EAAEkF,aAAY,IAAKC,aAAaH,YAAAA;AAEtC,SACE,gBAAAzD,OAAA,cAACC,eAAeoB,MAAI;IACjB,GAAGwC,gBAAgBN,OAAO;MAAEjE,YAAYmE;IAAa,CAAA;IACtDtE,UAAU,CAACuE,gBAAgB,CAACC;IAC5BG,KAAKN;KAEJ1B,OAAOoB,IAAI,CAACX,SACX,gBAAAvC,OAAA,cAAC+D,iBAAAA;IAAgB5D,KAAKoC,KAAKnC;IAAI3B;IAA0B8D;OAE1DU,QAAAA;AAGP,CAAA;AAGF,IAAMc,kBAAkB,CAAC,EAAEtF,aAAa8D,KAAI,MAAuC;AACjF,MAAIyB,YAAYzB,IAAAA,GAAO;AACrB,WAAO,gBAAAvC,OAAA,cAACC,eAAegE,WAAS;MAACvE,SAAS6C,KAAK/C,WAAWE;;EAC5D;AAEA,MAAIwE,YAAY3B,IAAAA,GAAO;AACrB,QAAIA,KAAK/C,WAAWE,YAAY,gBAAgB;AAC9C,aACE,gBAAAM,OAAA,cAAC4B,yBAAAA;QACCnD;QACAoD,OAAOU;;IAGb;AAEA,WACE,gBAAAvC,OAAA,cAAC8C,wBAAAA;MACCrE;MACAoD,OAAOU;;EAGb;AAEA,QAAM7D,SAAS6D;AACf,MAAI7D,OAAOc,YAAYE,YAAY,UAAU;AAC3C,WAAO,gBAAAM,OAAA,cAACU,mBAAAA;MAAkBjC;MAA0BC;;EACtD;AAGA,MAAIA,OAAOc,YAAYE,YAAY,YAAYhB,OAAOc,WAAW2E,QAAQ;AACvE,WAAO,gBAAAnE,OAAA,cAAAA,OAAA,UAAA,MAAGtB,OAAOc,WAAW2E,OAAM,CAAA;EACpC;AAEA,SAAO,gBAAAnE,OAAA,cAACxB,mBAAAA;IAAkBC;IAA0BC;;AACtD;;;AH/RA,IAAA,eAAM0F;AAIN,IAAMC,YAAAA;AACN,IAAMC,CAAAA,mBAAAA,eAAgDD,IAAAA,mBAAAA,WAAAA,CAAAA,CAAAA;AAEtD,IAAME,gBAAAA,KAAAA,KAAwC,IAAA;IAC5CC,uBAAU,MAAA;IACVC,sBAAOH;EACPI,UAAUC;EACVC,OAAAA;EACAC,UAAAA;EACAC,eAAAA,KAAiB,KAAO,oBAAA,IAAA,CAAA;EAC1B,cAAA,MAAA;EAAA;EAEA,iBAAOC,MAAAA;EAAAA;AAEP;AAWA,IAAMC,CAAAA,qBAAAA,aAAAA,IAAsBC,kBAAwC,WAAA,mBAAA;IAClEC,eAAkB,gBAAA;AACpB,IAAA,sBAAA,8BAAA;EAEE,WAAA,MAAA;EAAA;AACF,CAAA;uBAMMT;IAAOU,gBAAkBC,CAAAA,UAAQ;EAIjCC,GAAAA;AAQJ,EAAA,KAAM,CAAEC,GAAAA,MAAO,EAAA,aAAGC,EAAaZ,WAAAA,EAAAA,WAAAA,EAAAA,WAAAA,EAAAA,GAAAA,cAAAA,EAAAA,EAAAA,CAAAA;IAC/B,eAAiBa,CAAAA,EAAAA,UAAWC,QAAAA,oBAAAA,OAAAA,WAAAA,oBAAAA,UAAAA,cAAAA,cAAAA,SAAAA,MAAAA;AAC5B,QAAMb,EAAAA,MAAAA,IAAAA,aAAwB,MAAWc;AAEzC,QAAMb,WAAAA,WAAec,eAClBC;QACC,gBAAiBA,QAAMR,MAAAA,KAAYS,KAAAA,oBAAAA,IAAAA,CAAAA,EAAAA,KAAAA,KAAAA,SAAAA,GAAAA,CAAAA,CAAAA;QACnC,eAAaC,aAAalB,CAAAA,UAAAA;AAC1B,UAAMmB,WAAWC,MAAIC,YAAAA;AACrBF,UAAKG,OAAIN,SAAU,IAAA,aAAA;UAAE,OAAQ,IAAA,IAAA,IAAA;SAAER,IAAAA,MAAAA,IAAAA;MAAS,GAAA;MACxCU;IAEF,CAAA;AAACA,aAAAA,IAAAA,eAAAA,IAAAA;;IAAwB;IAG3B;;QAGI,kBAAiBE,aAAIC,CAAAA,OAAAA;AACrBF,UAAKI,OAAOC,SAAAA,IAAAA,aAAAA;AACZN,UAAAA,OAAalB,IAAAA,IAAAA,IAAAA;AAEf,SAAA,OAAA,EAAA;AAACkB,aAAAA,IAAAA,eAAAA,IAAAA;;IAAwB;IAG3B;;SAGctB,gBAAAA,OAAAA,cAAAA,qBAAAA;IACV6B;IACAC;IACA1B;IACAC;IACAC;IACAJ;IACAY;IAECiB;IAGP;EAEE,GAAA,QAAA;AACF;mBAQiCC,CAAAA,WAAM,OAAA,YAAA;QAAIC,aAAmBC;IACxDC,GAAAA,QAAWC,OAAM;WACnB,CAAA,UAAOC,CAAAA,MAAAA,eAAAA,MAAAA,YAAAA,KAAAA,CAAAA;AACT,MAAA,WAAA,WAAA,GAAA;AAEA,WAAMC;EAEN;AACA,QAAIC,SAAAA,cAAyB,UAAA;QAC3B,eAAiBH,OAAM,OAAM,CAAA,UAAA,MAAA,SAAA,aAAA;mBAClB,SAAA,GAAA;qBACFG,SAAaC,GAAG;UACrBC,KAAAA,sCAAyB;QAC3B,KAAA,aAAA,IAAA,CAAA,MAAA,EAAA,EAAA,EAAA,KAAA,IAAA;QACF,OAAA,aAAA,CAAA,EAAA;MACA,GAAA,EAAOF,YAAAA,YAAqB,GAAA,cAAA,GAAA,IAAA,GAAA,OAAA,CAAA;IAC9B;AAEA,WAAMG,aAAkBT,CAAAA,EAAAA;EACxB;AAEA,QAAKI,WAAAA,OAAaA,OAAUD,CAAAA,UAAW,MAAG,SAAA,UAAA;QACxC,gBAAOO,SAAoB,QAAOA,CAAAA,UAAAA,MAAgB,KAAA;AACpD,MAAA,CAAA,aAAA,UAAA,WAAA,GAAA;AAEA,WAAO,cAAA,SAAA,IAAA,gBAAA;;SAAkBA;IAAc,GAAA;IACzC,GAAA;EAEE;AACF;IAUE,eAAMC,CAAAA,OAAaC,YAAa5C,eAAM6C,uBAAAA,gBAAAA;AACtC,QAAMC,EAAAA,OAAAA,cAAuB3C,IAAAA,cAAkB,cAAIoB,WAAAA;AAEnD,QAAMa,aAAYW,aAAcC,MAAAA,KAAAA,CAAcL;QAAqBK,UAAAA,aAAAA,aAAAA,KAAAA,oBAAAA,IAAAA;QAAYL,YAAAA,QAAAA,MAAAA,cAAAA,cAAAA,MAAAA;IAAW;IAE1F;;QAEcE,WAAAA,QAAAA,MAAAA,aAAAA,WAAAA,OAAAA,OAAAA,GAAAA;IAAOC;IAAQ;IAG7B;EACF,CAAA;AAEA,SAAA,YAAA;;AAGA,IAAA,UAAA,CAAA,iBAAA;AAYA,SAAA,cAAA,cAAA,MAAA;;IAUIG,WAAMC,CAAAA,EAAAA,UAAAA,MAAAA,aAAAA,cAAAA,QAAAA,GAAAA,MAAAA,MAAAA;QACNC,CAAAA,UAAaC,WAAAA,IAAAA,sBAAAA;IACbC,MAAAA;IACF,aAAA;IAEA,UAAM5C;;QAA+D,YAAAS,aAAA,MAAA,YAAA,KAAA,GAAA;IAErE;;SAE2CT,gBAAAA,OAAAA,cAAAA,cAAAA,OAAAA,gBAAAA,OAAAA,cAAAA,oBAAAA,UAAAA;WAAW6C;MAAO;;IAC7BJ;KAAgBK,gBAAAA,OAAcC,cAAAA,qBAAAA,MAAAA;IACrD1B,MAAAA;IAKX,cAAA;EAYA,GAAM2B,QAAAA,CAAAA,CAAAA;;IASJ,kBAAoBvC,CAAAA,EAAAA,MAAAA,SAAawC,YAA8BC,MAAAA;QAAiBA,SAAAA;QAAQC,cAAAA,aAAAA,CAAAA,UAAAA,QAAAA,QAAAA,KAAAA,GAAAA;IAAQ;IAChG;EACA,CAAA;QAEIA,EAAAA,SAASC,IAAAA,cAAAA,mBAAAA,WAAAA;SACE,gBAAAC,OAAA,cAAAC,qBAAA,MAAA;IACXC,SAAAA;IACC,YAAWC;cAAwB,OAAA,YAAsBA;IAAkB,GAAC,OAAA,YAAA,UAAA;MAE5EN,eAAmBO,OAAAA,WAAAA;IAAcA;YAAqCnE,YAAAA,QAAAA,gBAAAA,OAAAA,cAAAA,OAAAA;4BACvE;IAAa4D,MAAAA;;IAGnB;EAEA,CAAA,CAAA;;AAaE,IAAML,cAASa,CAAAA,EAAAA,OAAAA,OAAkBC,YAAAA,QAAAA,gBAAAA,YAAAA,MAAAA;AACjC,QAAM,EAAEnE,WAAU,QAAGoE,cAAc,IAAA,WAAeC,mBAAAA;AAClD,QAAMC,SAAAA,kBAAgBC;AAEtB,QAAMC,EAAAA,SAAAA,IAAAA,cAAoBvD,eACHwC,WAAAA;QACnB,gBAAWO,aAAYD,OAAU,YAAA,eAAA,WAAA;4BAC/B9C,aAAA,CAAA,QAAA,UAAA;AACF,QAAA,OAAA,YAAA,UAAA;AACAwC;IACAjD;AACA,UAAIR,gBAAU;cACZA;kBAAmByE;eAAepB,QAAAA;QAAO,QAAA;QACpC;MACL,CAAA;;WAAgDA,kBAAAA,QAAAA;QAAO,QAAA;QACzD;MAEF,CAAA;IAACT;;IAAe5C;IAAUQ;IAAU;IAGtC;;SAK+CkE,gBAAAA,OAAAA,cAAAA,qBAAAA,QAAAA,MAAAA,gBAAAA,OAAAA,cAAAA,qBAAAA,SAAAA,MAAAA,gBAAAA,OAAAA,cAAAA,qBAAAA,UAAAA,MAAAA,eAAAA,IAAAA,CAAAA,SAAAA,gBAAAA,OAAAA,cAAAA,iBAAAA;IAAMf,KAAAA,KAASa;;IAOhE,SAAA;EAEE,CAAA,CAAA,CAAA,GAAA,gBAAAX,OAAA,cAAAC,qBAAA,OAAA,IAAA,CAAA,CAAA;AACF;AAaEa,IAAAA,OAASb;EACTc,MAAAA;EACAC,SAAAA,qBAAgBf;EAChBgB,SAASC;EACX,gBAAAjB,qBAAA;EAEA,SAAa;;;;AMvUb,SAASkB,QAAAA,aAAY;AACrB,SAASC,WAAAA,gBAAe;AAExB,SAAqBC,QAAAA,aAAY;;;ACHjC,SAASC,QAAAA,OAAMC,mBAAAA,kBAAiBC,gBAAAA,qBAAoB;AACpD,SAA8BC,eAAAA,cAAaC,cAAAA,aAAYC,WAAAA,gBAAe;AAEtE,SAASC,OAAOC,QAAAA,aAAY;AAerB,IAAMC,iBAAiB,CAACC,UAAAA;AAC7B,QAAMC,WAAWN,YAAWH,gBAAAA;AAC5B,QAAMU,iBAAiBT,cAAaO,KAAAA;AAMpC,QAAMG,QAAQP,SAAQ,MAAA;AACpB,UAAMQ,WAAWP,MAAMQ,KAAK;MAAEJ;IAAS,CAAA;AACvCG,aAASE,KAAKT,MAAMU,SAASL,eAAeM,KAAK,GAA0BX,MAAMY,SAASP,eAAeQ,KAAK,CAAA;AAC9G,WAAON;EACT,GAAG;IAACH;IAAUC;GAAe;AAE7B,QAAMS,QAA2BjB,aAC/B,CAACkB,UAAAA;AAEC,WAAOT,MAAMU,YAAYD,OAAOE,MAAMhB,MAAKiB,QAAQ,OAAA;EACrD,GACA;IAACZ;GAAM;AAGT,SAAO;IAAEQ;EAAM;AACjB;AAUO,IAAMK,iBAAiB,CAACC,OAAgDC,SAAAA;AAE7E,QAAMC,OAAOvB,SAAQ,MAAML,MAAKc,KAAKY,KAAAA,GAAQC,IAAAA;AAC7C,SAAOnB,eAAeoB,IAAAA;AACxB;;;AD1BO,IAAMC,iBAAiB,CAC5BC,SACAC,QACAC,UAA4B,CAAC,MAAC;AAE9B,QAAM,EAAEC,SAASC,MAAKC,QAAQC,OAAM,IAAKJ;AACzC,QAAMK,QAA0B,CAAA;AAChC,QAAMC,QAA0B,CAAA;AAChC,QAAMC,OAAO,oBAAIC,IAAAA;AAEjB,QAAMC,QAAQ,CAACC,UAAkBC,aAAAA;AAC/B,eAAWC,UAAUd,QAAQa,QAAAA,GAAW;AACtC,UAAIP,UAAU,CAACA,OAAOQ,MAAAA,GAAS;AAC7B;MACF;AAEAN,YAAMO,KAAK;QAAEC,QAAQJ;QAAUK,QAAQH,OAAOI;QAAIC,UAAU;MAAQ,CAAA;AACpE,UAAIV,KAAKW,IAAIN,OAAOI,EAAE,GAAG;AACvB;MACF;AACAT,WAAKY,IAAIP,OAAOI,EAAE;AAClBX,YAAMQ,KAAKD,MAAAA;AAEX,UAAIV,MAAKkB,cAAcR,MAAAA,GAAS;AAC9BH,cAAMG,OAAOI,IAAIJ,OAAOI,EAAE;MAC5B;IACF;EACF;AAEAP,QAAMR,QAAQF,MAAAA;AACd,SAAO;IAAEM;IAAOC;EAAM;AACxB;AAOO,IAAMe,eAAe,CAC1BC,OACAC,KACAxB,QACAC,YAEAsB,SAASvB,SAASF,eAAe,CAACmB,OAAOO,IAAID,MAAME,QAAQR,EAAAA,CAAAA,GAAMjB,QAAQC,OAAAA,IAAW;EAAEK,OAAO,CAAA;EAAIC,OAAO,CAAA;AAAG;AAMtG,IAAMmB,sBAAsB,CACjCH,OACAvB,QACAC,YAAAA;AAEA,QAAM0B,OAAOC;IACX,MAAMC,MAAKC,KAAK,CAACN,QAAQF,aAAaC,OAAOC,KAAKxB,QAAQC,OAAAA,CAAAA;;;IAG1D;MAACsB;MAAOvB;MAAQC,SAASC;;EAAO;AAElC,SAAO6B,eAAeJ,IAAAA;AACxB;;;AE3FA,SAASK,iBAAiB;AAG1B,SAASC,kBAAAA,uBAAsB;AAM/B,IAAAC,gBAAA;AAEU,IAAA,yBAAA;SAAyB;;IAAqB;MAAE,IAAAC;IACxDC;EACAC;EACAC,MAAAA;EACAC,UAAS;EACX,WAAA;EAsDA,SAAMC;;;EACIC;EAER;oBACmBC;cACAC,OAAAA,SAAAA;AAChB,SAAA,QAAA;AAEHC,SAAKC,UAAsC;;OAEzCC,OAAAA;AACA,cAAU,KAACC,YAAWC,QAAAA,2CAA4BH,EAAAA,YAAAA,YAAAA,GAAAA,eAAAA,GAAAA,IAAAA,GAAAA,MAAAA,GAAAA,CAAAA,2BAAAA,2CAAAA,EAAAA,CAAAA;AAClD,cAAO,KAAI,MAAA,MAAA,KAAA,CAAA,SAAA,KAAA,OAAA,MAAA,MAAA,QAAA,uCAAA,EAAA,YAAA,YAAA,GAAAX,eAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,mEAAA,uCAAA,EAAA,CAAA;AACb,SAAA,MAAA,MAAA,KAAA,oBAAA,QAAA,KAAA,CAAA;AAEAe,WAA0B;;EAE1B,QAAA;AAEAC,WAAsCL,KAA+B;;SAEnE,IAAKH,OAAMS,QAAW;SAAEC,MAAAA,MAAaT,KAAAA,iBAAO,IAAA,QAAA,KAAA,CAAA;SAAEU,MAAAA,MAAQC,KAAAA;MAAIC,QAAAA,KAAU;MAAQ,QAAA;MAC5E,UAAW;IACb,CAAA;AAEAC,WAAmBX;;aACWA,OAAK,QAAA;WAAEN,KAAAA,OAAS,IAAA;MAAYkB,GAAAA;MAC1D,SAAA;IAEAC,GAAMJ,MAAYT;;QAEhB,IAAKH,OAAMS,IAAMQ;SAAOP,MAAAA,MAAaT,KAAAA,oBAAO,IAAA,KAAA,CAAA;SAAEU,MAAAA,MAAQC,KAAAA;MAAIC,QAAAA,KAAU;MAAQ,QAAA;MACzE,UAAIf;IACP,CAAA;AACF,OAAA,IAAA,iBAAA,KAAA,OAAA,EAAA,CAAA;AAEAoB,WAAyC;;EAEzC,KAAA,IAAA,IAAA;AAEAC,WAASC,KAAAA,MAAgF,IAAQ,wBAAA,EAAA;;WAE7F,cAAW;AACb,QAAA,CAAA,cAAA;AACI,aAAOA;;AAEX,QAAA,OAAO,iBAAA,YAAA;AACL,mBAAWf,IAAMY,iBAAQG,KAAaf,OAAK,KAAA,OAAA,CAAA;WAC3C;AACF,WAAA,MAAA,MAAA,KAAA,GAAA,aAAA,KAAA;AACA,WAAO,MAAI,MAAA,KAAA,GAAA,aAAA,KAAA;IACb;AAEAgB,WAAUxB;;YAEHG,UAAW,OAAM;UACpBY,KAAAA,aAAAA,EAAAA,KAAAA,eAAAA;SACAU,MAAMC,MAAAA,KAAAA;MACNC;YAAc3B;MAAQ,YAAA;QACtB4B;MACF;MACI,MAAM;;SAAoCd,MAAAA,MAAQC,KAAAA;MAAIC,QAAAA,KAAU;MAAQ,QAAA;MAC5E,UAAW;IACb,CAAA;AACF,WAAA;EAEA;;IACiDR,cAAS,OAAA,OAAA;cAAEI,IAAAA,gBAAS;IAAI,OAAA,CAAA;IACtE,OAAA,CAAA;;;",
6
+ "names": ["Atom", "RegistryContext", "useAtomValue", "createContextScope", "useControllableState", "React", "createContext", "useCallback", "useContext", "useMemo", "log", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "EffectEx", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "relation", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "translationKey", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "keySymbols", "join", "actionLabel", "React", "useCallback", "Input", "Toolbar", "NaturalToolbar", "Tooltip", "toLocalizedString", "useTranslation", "composable", "composableProps", "useAttention", "translationKey", "Node", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "ActionGroupType", "useControllableState", "React", "useCallback", "Icon", "DropdownMenu", "NaturalDropdownMenu", "DropdownMenuItem", "item", "onClick", "__menuScope", "action", "handleClick", "useCallback", "event", "iconSize", "useMenuScoped", "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", "ActionToolbarItem", "__menuScope", "action", "iconSize", "onAction", "useMenuScoped", "t", "useTranslation", "translationKey", "icon", "iconOnly", "disabled", "testId", "hidden", "classNames", "iconClassNames", "properties", "buttonVariant", "variant", "handleClick", "useCallback", "executeMenuAction", "commonProps", "onClick", "React", "NaturalToolbar", "IconButton", "key", "id", "size", "label", "actionLabel", "Button", "ActionLabel", "SwitchToolbarItem", "checked", "labelStr", "toLocalizedString", "handleCheckedChange", "switchInput", "Input", "Switch", "aria-label", "undefined", "onCheckedChange", "Root", "Tooltip", "Trigger", "asChild", "content", "Block", "Label", "DropdownMenuToolbarItem", "group", "items", "propsItems", "useMenuItems", "applyActive", "caretDown", "groupIcon", "groupIconClassNames", "activeItem", "find", "item", "labelAction", "DropdownMenu", "ToggleGroupItem", "parent", "value", "ToggleGroupIconItem", "ToggleGroupToolbarItem", "itemsProp", "selectCardinality", "children", "map", "ToggleGroup", "type", "ToolbarMenu", "composable", "props", "forwardedRef", "attendableId", "alwaysActive", "hasAttention", "useAttention", "composableProps", "ref", "ToolbarMenuItem", "isSeparator", "Separator", "isMenuGroup", "render", "MENU_NAME", "nullItemsAtom", "defaultItemsAccessor", "menuContextDefaults", "iconSize", "items", "onAction", "undefined", "menuItemsAtom", "addMenuItems", "removeMenuItems", "MenuContextProvider", "MenuDropdownContext", "createContext", "closeMenu", "sort", "priority", "MenuProvider", "scope", "useMenuScope", "useContext", "RegistryContext", "make", "useCallback", "props", "DEFAULT_PRIORITY", "registry", "next", "Map", "prev", "set", "delete", "id", "attendableId", "alwaysActive", "children", "values", "filter", "entry", "applicable", "length", "baseItems", "sorted", "replacements", "map", "using", "additive", "additiveItems", "groupItems", "useAtomValue", "group", "entries", "useMemo", "propsItems", "prop", "open", "defaultProp", "defaultOpen", "onChange", "caller", "onOpenChange", "setMenuOpen", "MenuContentItem", "event", "action", "onClick", "handleClick", "React", "NaturalDropdownMenu", "disabled", "properties", "icon", "callerOverride", "contextCaller", "useMenuScoped", "__menuScope", "resolvedItems", "useMenuItems", "handleActionClick", "parent", "item", "Trigger", "Content", "VirtualTrigger", "Toolbar", "ToolbarMenu", "Atom", "useMemo", "Node", "Atom", "RegistryContext", "useAtomValue", "useCallback", "useContext", "useMemo", "Graph", "Node", "useMenuActions", "props", "registry", "menuGraphProps", "graph", "newGraph", "make", "pipe", "addNodes", "nodes", "addEdges", "edges", "items", "group", "connections", "id", "RootId", "useMenuBuilder", "build", "deps", "atom", "buildGraphMenu", "resolve", "nodeId", "options", "rootId", "Node", "RootId", "filter", "nodes", "edges", "seen", "Set", "visit", "parentId", "sourceId", "action", "push", "source", "target", "id", "relation", "has", "add", "isActionGroup", "graphActions", "graph", "get", "actions", "useGraphMenuActions", "atom", "useMemo", "Atom", "make", "useMenuActions", "invariant", "translationKey", "__dxlog_file", "translationKey", "icon", "iconOnly", "caretDown", "variant", "MenuBuilderImpl", "_separatorCount", "_data", "_rootId", "root", "props", "invariant", "nodes", "createMenuItemGroup", "build", "action", "edges", "source", "target", "id", "relation", "switch", "invoke", "group", "push", "menu", "subgraph", "subgraphOrCb", "separator", "type", "MenuSeparatorType", "properties", "data"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"src/util.ts":{"bytes":7839,"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/components/ActionLabel.tsx":{"bytes":3891,"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":"#translations","kind":"import-statement","external":true},{"path":"src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"src/types.ts":{"bytes":4616,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/components/DropdownMenu.tsx":{"bytes":10853,"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/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/components/ToolbarMenu.tsx":{"bytes":26161,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","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":"#translations","kind":"import-statement","external":true},{"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/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/components/Menu.tsx":{"bytes":31436,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","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/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"}],"format":"esm"},"src/components/index.ts":{"bytes":368,"imports":[{"path":"src/components/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/hooks/useMenuActions.ts":{"bytes":6912,"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/useGraphMenuActions.ts":{"bytes":9917,"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},{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/hooks/index.ts":{"bytes":509,"imports":[{"path":"src/hooks/useGraphMenuActions.ts","kind":"import-statement","original":"./useGraphMenuActions"},{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/builder.ts":{"bytes":12976,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true},{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/index.ts":{"bytes":1214,"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"},"src/translations.ts":{"bytes":1117,"imports":[],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":59919},"dist/lib/browser/index.mjs":{"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","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":"#translations","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","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"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-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":"@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},{"path":"#translations","kind":"import-statement","external":true}],"exports":["Menu","MenuBuilder","MenuSeparatorType","buildGraphMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","graphActions","isMenuGroup","isSeparator","menuContextDefaults","useGraphMenuActions","useMenu","useMenuActions","useMenuBuilder","useMenuItems","useMenuScoped"],"entryPoint":"src/index.ts","inputs":{"src/components/Menu.tsx":{"bytesInOutput":6895},"src/util.ts":{"bytesInOutput":1473},"src/components/ActionLabel.tsx":{"bytesInOutput":890},"src/components/ToolbarMenu.tsx":{"bytesInOutput":6212},"src/types.ts":{"bytesInOutput":235},"src/components/DropdownMenu.tsx":{"bytesInOutput":2516},"src/index.ts":{"bytesInOutput":0},"src/hooks/useGraphMenuActions.ts":{"bytesInOutput":1454},"src/hooks/useMenuActions.ts":{"bytesInOutput":955},"src/builder.ts":{"bytesInOutput":2609}},"bytes":23961},"dist/lib/browser/translations.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":586},"dist/lib/browser/translations.mjs":{"imports":[],"exports":["translationKey","translations"],"entryPoint":"src/translations.ts","inputs":{"src/translations.ts":{"bytesInOutput":171}},"bytes":281}}}
1
+ {"inputs":{"src/util.ts":{"bytes":7839,"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/components/ActionLabel.tsx":{"bytes":3891,"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":"#translations","kind":"import-statement","external":true},{"path":"src/util.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"src/types.ts":{"bytes":4616,"imports":[{"path":"@dxos/app-graph","kind":"import-statement","external":true}],"format":"esm"},"src/components/DropdownMenu.tsx":{"bytes":10853,"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/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/components/ToolbarMenu.tsx":{"bytes":31846,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","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":"#translations","kind":"import-statement","external":true},{"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/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/components/Menu.tsx":{"bytes":31436,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","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/ToolbarMenu.tsx","kind":"import-statement","original":"./ToolbarMenu"}],"format":"esm"},"src/components/index.ts":{"bytes":368,"imports":[{"path":"src/components/Menu.tsx","kind":"import-statement","original":"./Menu"}],"format":"esm"},"src/hooks/useMenuActions.ts":{"bytes":6912,"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/useGraphMenuActions.ts":{"bytes":9917,"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},{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/hooks/index.ts":{"bytes":509,"imports":[{"path":"src/hooks/useGraphMenuActions.ts","kind":"import-statement","original":"./useGraphMenuActions"},{"path":"src/hooks/useMenuActions.ts","kind":"import-statement","original":"./useMenuActions"}],"format":"esm"},"src/builder.ts":{"bytes":13815,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true},{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/index.ts":{"bytes":1214,"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"},"src/translations.ts":{"bytes":1117,"imports":[],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":63377},"dist/lib/browser/index.mjs":{"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","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":"#translations","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","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true},{"path":"@dxos/app-graph","kind":"import-statement","external":true},{"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-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":"@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},{"path":"#translations","kind":"import-statement","external":true}],"exports":["Menu","MenuBuilder","MenuSeparatorType","buildGraphMenu","createGapSeparator","createLineSeparator","createMenuAction","createMenuItemGroup","graphActions","isMenuGroup","isSeparator","menuContextDefaults","useGraphMenuActions","useMenu","useMenuActions","useMenuBuilder","useMenuItems","useMenuScoped"],"entryPoint":"src/index.ts","inputs":{"src/components/Menu.tsx":{"bytesInOutput":6895},"src/util.ts":{"bytesInOutput":1473},"src/components/ActionLabel.tsx":{"bytesInOutput":890},"src/components/ToolbarMenu.tsx":{"bytesInOutput":7824},"src/types.ts":{"bytesInOutput":235},"src/components/DropdownMenu.tsx":{"bytesInOutput":2516},"src/index.ts":{"bytesInOutput":0},"src/hooks/useGraphMenuActions.ts":{"bytesInOutput":1454},"src/hooks/useMenuActions.ts":{"bytesInOutput":955},"src/builder.ts":{"bytesInOutput":2728}},"bytes":25692},"dist/lib/browser/translations.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":586},"dist/lib/browser/translations.mjs":{"imports":[],"exports":["translationKey","translations"],"entryPoint":"src/translations.ts","inputs":{"src/translations.ts":{"bytesInOutput":171}},"bytes":281}}}
@@ -96,7 +96,7 @@ var actionLabel = (action, t) => {
96
96
 
97
97
  // src/components/ToolbarMenu.tsx
98
98
  import React3, { useCallback as useCallback2 } from "react";
99
- import { Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
99
+ import { Input, Toolbar as NaturalToolbar, Tooltip, toLocalizedString as toLocalizedString2, useTranslation as useTranslation2 } from "@dxos/react-ui";
100
100
  import { composable, composableProps } from "@dxos/react-ui";
101
101
  import { useAttention } from "@dxos/react-ui-attention";
102
102
  import { translationKey as translationKey2 } from "#translations";
@@ -221,6 +221,38 @@ var ActionToolbarItem = ({ __menuScope, action }) => {
221
221
  action
222
222
  }));
223
223
  };
224
+ var SwitchToolbarItem = ({ __menuScope, action }) => {
225
+ const { onAction } = useMenuScoped("SwitchToolbarItem", __menuScope);
226
+ const { t } = useTranslation2(translationKey2);
227
+ const { label, iconOnly, disabled, testId, hidden, checked } = action.properties;
228
+ const labelStr = toLocalizedString2(label, t);
229
+ const handleCheckedChange = useCallback2(() => {
230
+ if (onAction) {
231
+ onAction(action, {});
232
+ } else {
233
+ void executeMenuAction(action);
234
+ }
235
+ }, [
236
+ action,
237
+ onAction
238
+ ]);
239
+ if (hidden) {
240
+ return null;
241
+ }
242
+ const switchInput = /* @__PURE__ */ React3.createElement(Input.Switch, {
243
+ checked,
244
+ disabled,
245
+ "aria-label": iconOnly ? labelStr : void 0,
246
+ onCheckedChange: handleCheckedChange,
247
+ ...testId && {
248
+ "data-testid": testId
249
+ }
250
+ });
251
+ return /* @__PURE__ */ React3.createElement(Input.Root, null, iconOnly ? /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
252
+ asChild: true,
253
+ content: labelStr
254
+ }, /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput)) : /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput), !iconOnly && /* @__PURE__ */ React3.createElement(Input.Label, null, labelStr));
255
+ };
224
256
  var DropdownMenuToolbarItem = ({ __menuScope, group, items: propsItems }) => {
225
257
  const { t } = useTranslation2(translationKey2);
226
258
  const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
@@ -353,9 +385,19 @@ var ToolbarMenuItem = ({ __menuScope, item }) => {
353
385
  group: item
354
386
  });
355
387
  }
388
+ const action = item;
389
+ if (action.properties?.variant === "switch") {
390
+ return /* @__PURE__ */ React3.createElement(SwitchToolbarItem, {
391
+ __menuScope,
392
+ action
393
+ });
394
+ }
395
+ if (action.properties?.variant === "custom" && action.properties.render) {
396
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, action.properties.render());
397
+ }
356
398
  return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
357
399
  __menuScope,
358
- action: item
400
+ action
359
401
  });
360
402
  };
361
403
 
@@ -679,6 +721,12 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
679
721
  });
680
722
  return this;
681
723
  }
724
+ switch(id, props, invoke) {
725
+ return this.action(id, {
726
+ ...props,
727
+ variant: "switch"
728
+ }, invoke);
729
+ }
682
730
  group(id, props, cb) {
683
731
  this._data.nodes.push(createMenuItemGroup(id, props));
684
732
  this._data.edges.push({