@dxos/react-ui-menu 0.9.0 → 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.
- package/dist/lib/browser/index.mjs +156 -43
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +3 -1
- package/dist/lib/browser/translations.mjs.map +2 -2
- package/dist/lib/node-esm/index.mjs +156 -43
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +3 -1
- package/dist/lib/node-esm/translations.mjs.map +2 -2
- package/dist/types/src/builder.d.ts +15 -3
- package/dist/types/src/builder.d.ts.map +1 -1
- package/dist/types/src/components/ActionLabel.d.ts +2 -2
- package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +4 -4
- package/dist/types/src/components/Menu.d.ts.map +1 -1
- package/dist/types/src/components/Menu.stories.d.ts +3 -1
- package/dist/types/src/components/Menu.stories.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.d.ts +14 -12
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +7 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useGraphMenuActions.d.ts +31 -0
- package/dist/types/src/hooks/useGraphMenuActions.d.ts.map +1 -0
- package/dist/types/src/hooks/useGraphMenuActions.test.d.ts +2 -0
- package/dist/types/src/hooks/useGraphMenuActions.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +7 -11
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +8 -3
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -25
- package/src/builder.test.ts +50 -11
- package/src/builder.ts +36 -5
- package/src/components/ActionLabel.tsx +2 -2
- package/src/components/Menu.tsx +7 -12
- package/src/components/ToolbarMenu.stories.tsx +31 -2
- package/src/components/ToolbarMenu.tsx +125 -66
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useGraphMenuActions.test.ts +93 -0
- package/src/hooks/useGraphMenuActions.ts +96 -0
- package/src/index.ts +1 -1
- package/src/translations.ts +3 -1
- package/src/types.ts +9 -6
- package/src/util.ts +1 -6
|
@@ -4,7 +4,7 @@ import { createContextScope } from "@radix-ui/react-context";
|
|
|
4
4
|
import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
|
|
5
5
|
import React4, { createContext, useCallback as useCallback3, useContext, useMemo } from "react";
|
|
6
6
|
import { log } from "@dxos/log";
|
|
7
|
-
import { Icon as
|
|
7
|
+
import { Icon as Icon2, DropdownMenu as NaturalDropdownMenu2 } from "@dxos/react-ui";
|
|
8
8
|
|
|
9
9
|
// src/util.ts
|
|
10
10
|
import * as Effect from "effect/Effect";
|
|
@@ -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 {
|
|
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,46 +219,75 @@ 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
|
-
const { iconOnly, disabled, testId } = group.properties;
|
|
224
255
|
const { t } = useTranslation2(translationKey2);
|
|
225
256
|
const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
|
|
226
257
|
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
258
|
+
const { iconOnly, disabled, testId, applyActive, caretDown = true, icon: groupIcon, iconClassNames: groupIconClassNames } = group.properties;
|
|
227
259
|
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
228
|
-
const icon =
|
|
229
|
-
activeItem?.properties.icon ||
|
|
230
|
-
const iconClassNames =
|
|
231
|
-
const
|
|
232
|
-
const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
|
|
233
|
-
const rootProps = icon ? {
|
|
234
|
-
icon,
|
|
235
|
-
size: iconSize,
|
|
236
|
-
iconOnly,
|
|
237
|
-
iconClassNames,
|
|
238
|
-
label: actionLabel(labelAction, t),
|
|
239
|
-
caretDown: true
|
|
240
|
-
} : {
|
|
241
|
-
children: /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
242
|
-
action: labelAction
|
|
243
|
-
}), /* @__PURE__ */ React3.createElement(Icon2, {
|
|
244
|
-
size: 3,
|
|
245
|
-
icon: "ph--caret-down--bold",
|
|
246
|
-
classNames: "ms-1"
|
|
247
|
-
}))
|
|
248
|
-
};
|
|
260
|
+
const icon = applyActive && // TODO(thure): Handle other menu item types.
|
|
261
|
+
activeItem?.properties.icon || groupIcon;
|
|
262
|
+
const iconClassNames = applyActive && activeItem?.properties.iconClassNames || groupIconClassNames;
|
|
263
|
+
const labelAction = applyActive && activeItem ? activeItem : group;
|
|
249
264
|
return /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
|
|
250
265
|
group,
|
|
251
266
|
items
|
|
252
267
|
}, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
|
|
253
268
|
asChild: true
|
|
254
|
-
}, /* @__PURE__ */ React3.createElement(
|
|
269
|
+
}, icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.IconButton, {
|
|
255
270
|
variant: "ghost",
|
|
256
271
|
disabled,
|
|
257
|
-
|
|
272
|
+
icon,
|
|
273
|
+
size: iconSize,
|
|
274
|
+
iconOnly,
|
|
275
|
+
iconClassNames,
|
|
276
|
+
label: actionLabel(labelAction, t),
|
|
277
|
+
caretDown,
|
|
258
278
|
...testId && {
|
|
259
279
|
"data-testid": testId
|
|
260
280
|
}
|
|
261
|
-
})
|
|
281
|
+
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
|
|
282
|
+
variant: "ghost",
|
|
283
|
+
disabled,
|
|
284
|
+
caretDown,
|
|
285
|
+
...testId && {
|
|
286
|
+
"data-testid": testId
|
|
287
|
+
}
|
|
288
|
+
}, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
289
|
+
action: labelAction
|
|
290
|
+
}))));
|
|
262
291
|
};
|
|
263
292
|
var ToggleGroupItem = ({ __menuScope, group, action }) => {
|
|
264
293
|
const { iconSize, onAction } = useMenuScoped("ToggleGroupItem", __menuScope);
|
|
@@ -348,16 +377,25 @@ var ToolbarMenuItem = ({ __menuScope, item }) => {
|
|
|
348
377
|
__menuScope,
|
|
349
378
|
group: item
|
|
350
379
|
});
|
|
351
|
-
} else {
|
|
352
|
-
return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
|
|
353
|
-
__menuScope,
|
|
354
|
-
group: item
|
|
355
|
-
});
|
|
356
380
|
}
|
|
381
|
+
return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
|
|
382
|
+
__menuScope,
|
|
383
|
+
group: item
|
|
384
|
+
});
|
|
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());
|
|
357
395
|
}
|
|
358
396
|
return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
|
|
359
397
|
__menuScope,
|
|
360
|
-
action
|
|
398
|
+
action
|
|
361
399
|
});
|
|
362
400
|
};
|
|
363
401
|
|
|
@@ -386,12 +424,7 @@ var MenuDropdownContext = /* @__PURE__ */ createContext({
|
|
|
386
424
|
var DEFAULT_PRIORITY = 100;
|
|
387
425
|
var sortMenuItems = (items) => [
|
|
388
426
|
...items
|
|
389
|
-
].sort((a, b) =>
|
|
390
|
-
if (a.priority !== b.priority) {
|
|
391
|
-
return a.priority - b.priority;
|
|
392
|
-
}
|
|
393
|
-
return a.id.localeCompare(b.id);
|
|
394
|
-
});
|
|
427
|
+
].sort((a, b) => a.priority !== b.priority ? a.priority - b.priority : a.id.localeCompare(b.id));
|
|
395
428
|
var MenuProvider = ({ children, items = menuContextDefaults.items, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
|
|
396
429
|
const { scope } = useMenuScope(void 0);
|
|
397
430
|
const registry = useContext(RegistryContext);
|
|
@@ -444,7 +477,7 @@ var resolveItems = (baseItems, group, entries) => {
|
|
|
444
477
|
log.warn("multiple replacement entries found", {
|
|
445
478
|
ids: replacements.map((r) => r.id).join(", "),
|
|
446
479
|
using: replacements[0].id
|
|
447
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L:
|
|
480
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 89, S: void 0 });
|
|
448
481
|
}
|
|
449
482
|
return replacements[0].items;
|
|
450
483
|
}
|
|
@@ -509,7 +542,7 @@ var MenuContentItem = ({ item, onClick, __menuScope }) => {
|
|
|
509
542
|
...action.properties?.testId && {
|
|
510
543
|
"data-testid": action.properties.testId
|
|
511
544
|
}
|
|
512
|
-
}, action.properties?.icon && /* @__PURE__ */ React4.createElement(
|
|
545
|
+
}, action.properties?.icon && /* @__PURE__ */ React4.createElement(Icon2, {
|
|
513
546
|
icon: action.properties.icon,
|
|
514
547
|
size: iconSize
|
|
515
548
|
}), /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
@@ -558,6 +591,11 @@ var Menu = {
|
|
|
558
591
|
Toolbar: ToolbarMenu
|
|
559
592
|
};
|
|
560
593
|
|
|
594
|
+
// src/hooks/useGraphMenuActions.ts
|
|
595
|
+
import { Atom as Atom3 } from "@effect-atom/atom-react";
|
|
596
|
+
import { useMemo as useMemo3 } from "react";
|
|
597
|
+
import { Node as Node4 } from "@dxos/app-graph";
|
|
598
|
+
|
|
561
599
|
// src/hooks/useMenuActions.ts
|
|
562
600
|
import { Atom as Atom2, RegistryContext as RegistryContext2, useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
|
|
563
601
|
import { useCallback as useCallback4, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
@@ -589,9 +627,72 @@ var useMenuBuilder = (build, deps) => {
|
|
|
589
627
|
return useMenuActions(atom);
|
|
590
628
|
};
|
|
591
629
|
|
|
630
|
+
// src/hooks/useGraphMenuActions.ts
|
|
631
|
+
var buildGraphMenu = (resolve, nodeId, options = {}) => {
|
|
632
|
+
const { rootId = Node4.RootId, filter } = options;
|
|
633
|
+
const nodes = [];
|
|
634
|
+
const edges = [];
|
|
635
|
+
const seen = /* @__PURE__ */ new Set();
|
|
636
|
+
const visit = (parentId, sourceId) => {
|
|
637
|
+
for (const action of resolve(sourceId)) {
|
|
638
|
+
if (filter && !filter(action)) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
edges.push({
|
|
642
|
+
source: parentId,
|
|
643
|
+
target: action.id,
|
|
644
|
+
relation: "child"
|
|
645
|
+
});
|
|
646
|
+
if (seen.has(action.id)) {
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
seen.add(action.id);
|
|
650
|
+
nodes.push(action);
|
|
651
|
+
if (Node4.isActionGroup(action)) {
|
|
652
|
+
visit(action.id, action.id);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
visit(rootId, nodeId);
|
|
657
|
+
return {
|
|
658
|
+
nodes,
|
|
659
|
+
edges
|
|
660
|
+
};
|
|
661
|
+
};
|
|
662
|
+
var graphActions = (graph, get, nodeId, options) => graph && nodeId ? buildGraphMenu((id) => get(graph.actions(id)), nodeId, options) : {
|
|
663
|
+
nodes: [],
|
|
664
|
+
edges: []
|
|
665
|
+
};
|
|
666
|
+
var useGraphMenuActions = (graph, nodeId, options) => {
|
|
667
|
+
const atom = useMemo3(
|
|
668
|
+
() => Atom3.make((get) => graphActions(graph, get, nodeId, options)),
|
|
669
|
+
// `options` is expected to be stable; `rootId` participates since it reshapes the graph.
|
|
670
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
671
|
+
[
|
|
672
|
+
graph,
|
|
673
|
+
nodeId,
|
|
674
|
+
options?.rootId
|
|
675
|
+
]
|
|
676
|
+
);
|
|
677
|
+
return useMenuActions(atom);
|
|
678
|
+
};
|
|
679
|
+
|
|
592
680
|
// src/builder.ts
|
|
593
681
|
import { invariant } from "@dxos/invariant";
|
|
682
|
+
import { translationKey as translationKey3 } from "#translations";
|
|
594
683
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/builder.ts";
|
|
684
|
+
var overflowMenuProperties = {
|
|
685
|
+
label: [
|
|
686
|
+
"toolbar-overflow.menu",
|
|
687
|
+
{
|
|
688
|
+
ns: translationKey3
|
|
689
|
+
}
|
|
690
|
+
],
|
|
691
|
+
icon: "ph--dots-three-vertical--regular",
|
|
692
|
+
iconOnly: true,
|
|
693
|
+
caretDown: false,
|
|
694
|
+
variant: "dropdownMenu"
|
|
695
|
+
};
|
|
595
696
|
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
596
697
|
_data;
|
|
597
698
|
_rootId;
|
|
@@ -601,8 +702,8 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
601
702
|
this._rootId = _rootId;
|
|
602
703
|
}
|
|
603
704
|
root(props) {
|
|
604
|
-
invariant(this._rootId === "root", "Root group can only be at the top level", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L:
|
|
605
|
-
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L:
|
|
705
|
+
invariant(this._rootId === "root", "Root group can only be at the top level", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 29, S: this, A: ["this._rootId === 'root'", "'Root group can only be at the top level'"] });
|
|
706
|
+
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 30, S: this, A: ["this._data.nodes.find((node)=>node.id === 'root') === undefined", "'Root group can only be created once'"] });
|
|
606
707
|
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
607
708
|
return this;
|
|
608
709
|
}
|
|
@@ -618,6 +719,12 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
618
719
|
});
|
|
619
720
|
return this;
|
|
620
721
|
}
|
|
722
|
+
switch(id, props, invoke) {
|
|
723
|
+
return this.action(id, {
|
|
724
|
+
...props,
|
|
725
|
+
variant: "switch"
|
|
726
|
+
}, invoke);
|
|
727
|
+
}
|
|
621
728
|
group(id, props, cb) {
|
|
622
729
|
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
623
730
|
this._data.edges.push({
|
|
@@ -628,6 +735,9 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
628
735
|
cb(new _MenuBuilderImpl(this._data, id));
|
|
629
736
|
return this;
|
|
630
737
|
}
|
|
738
|
+
menu(id, cb) {
|
|
739
|
+
return this.group(id, overflowMenuProperties, cb);
|
|
740
|
+
}
|
|
631
741
|
subgraph(subgraphOrCb) {
|
|
632
742
|
if (!subgraphOrCb) {
|
|
633
743
|
return this;
|
|
@@ -668,13 +778,16 @@ export {
|
|
|
668
778
|
Menu,
|
|
669
779
|
MenuBuilder,
|
|
670
780
|
MenuSeparatorType,
|
|
781
|
+
buildGraphMenu,
|
|
671
782
|
createGapSeparator,
|
|
672
783
|
createLineSeparator,
|
|
673
784
|
createMenuAction,
|
|
674
785
|
createMenuItemGroup,
|
|
786
|
+
graphActions,
|
|
675
787
|
isMenuGroup,
|
|
676
788
|
isSeparator,
|
|
677
789
|
menuContextDefaults,
|
|
790
|
+
useGraphMenuActions,
|
|
678
791
|
useMenu,
|
|
679
792
|
useMenuActions,
|
|
680
793
|
useMenuBuilder,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 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/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 MenuItem,\n type MenuItemGroup,\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) => {\n if (a.priority !== b.priority) {\n return a.priority - b.priority;\n }\n return a.id.localeCompare(b.id);\n });\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: MenuItemGroup | 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?: MenuItemGroup,\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?: MenuItemGroup;\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 = <\n P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,\n>(\n id: string,\n properties: P,\n) =>\n ({\n id,\n type: Node.ActionGroupType,\n properties,\n data: Node.actionGroupSymbol,\n }) satisfies MenuItemGroup;\n\nexport const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'gap' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [\n {\n source,\n target: id,\n 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 } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport { getShortcut } from '../util';\n\ntype Action = Node.Action<MenuActionProperties> | Node.ActionGroup<Omit<MenuActionProperties, 'variant'>>;\n\nexport const ActionLabel = ({ action }: { action: Action }) => {\n const { t } = useTranslation(translationKey);\n const shortcut = getShortcut(action);\n return (\n <>\n <span className='grow truncate'>{toLocalizedString(action.properties!.label, t)}</span>\n {shortcut && <span className={mx('shrink-0', '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 { Icon, 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 MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '#translations';\n\nimport {\n type MenuAction,\n type MenuItem,\n type MenuItemGroup,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n isMenuGroup,\n isSeparator,\n} from '../types';\nimport { executeMenuAction } from '../util';\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';\n\nexport type ToolbarMenuDropdownMenuActionGroup = Omit<MenuActionProperties, 'variant' | 'icon'> & {\n variant: 'dropdownMenu';\n icon: string;\n applyActive?: boolean;\n};\n\nexport type ToolbarMenuToggleGroupActionGroup = Omit<MenuActionProperties, 'variant'> & {\n variant: 'toggleGroup';\n};\n\nexport type ToolbarMenuActionGroupProperties = (\n | ToolbarMenuDropdownMenuActionGroup\n | ToolbarMenuToggleGroupActionGroup\n) &\n (MenuSingleSelectActionGroup | MenuMultipleSelectActionGroup);\n\nexport type ToolbarMenuProps = ToolbarRootProps;\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuActionProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n action: MenuAction;\n};\n\nconst ActionToolbarItem = ({ __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<ToolbarMenuActionGroupProps>) => {\n const { iconOnly, disabled, testId } = group.properties;\n const { t } = useTranslation(translationKey);\n const { iconSize } = useMenuScoped('DropdownMenuToolbarItem', __menuScope);\n const items = useMenuItems(group, propsItems, 'DropdownMenuToolbarItem', __menuScope);\n const activeItem = items?.find((item) => !!(item as MenuAction).properties.checked);\n const icon =\n ((group.properties as any).applyActive &&\n // TODO(thure): Handle other menu item types.\n (activeItem as MenuAction)?.properties.icon) ||\n group.properties.icon;\n // Follow the same `applyActive` rule for `iconClassNames` so a per-item\n // accent (e.g. tag colour) tracks the displayed icon.\n const iconClassNames =\n ((group.properties as any).applyActive && (activeItem as MenuAction)?.properties.iconClassNames) ||\n (group.properties as { iconClassNames?: any }).iconClassNames;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;\n const rootProps = icon\n ? {\n icon,\n size: iconSize,\n iconOnly,\n iconClassNames,\n label: actionLabel(labelAction, t),\n caretDown: true,\n }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='ms-1' />\n </>\n ),\n };\n\n return (\n <DropdownMenu.Root group={group} items={items}>\n <DropdownMenu.Trigger asChild>\n <Root variant='ghost' disabled={disabled} {...(rootProps as any)} {...(testId && { 'data-testid': testId })} />\n </DropdownMenu.Trigger>\n </DropdownMenu.Root>\n );\n};\n\nconst ToggleGroupItem = ({ __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<ToolbarMenuActionGroupProps>) => {\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<ToolbarMenuActionGroupProperties>}\n />\n );\n } else {\n return (\n <ToggleGroupToolbarItem\n __menuScope={__menuScope}\n group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>}\n />\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 MenuSingleSelectActionGroup = { selectCardinality: 'single'; value: string };\nexport type MenuMultipleSelectActionGroup = { selectCardinality: 'multiple'; value: string[] };\n\nexport type MenuItemGroup<P extends Record<string, any> = Record<string, any>> = Node.ActionGroup<P>;\n\nexport const isMenuGroup = (node: Node.Node): node is MenuItemGroup => node.type === Node.ActionGroupType;\n\nexport type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;\n\n/** Atom-family-style accessor: returns an atom of items for a given group (or root when undefined). */\nexport type MenuItemsAccessor = (group?: MenuItemGroup) => 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?: MenuItemGroup) => 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 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 { MenuActionProperties, MenuItemGroupProperties } from '@dxos/ui-types';\n\nimport type { ActionGraphProps } from './hooks';\nimport { MenuSeparatorType } from './types';\nimport { createMenuAction, createMenuItemGroup } from './util';\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<P extends {} = {}>(id: string, props: P & 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 /** Set properties on the root menu group. May only be called once. */\n root(props: MenuItemGroupProperties): this;\n\n /** Return the assembled action graph. */\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<P extends {} = {}>(id: string, props: P & 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 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", "
|
|
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, { 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": "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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", "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
|
}
|