@dxos/react-ui-menu 0.8.4-main.40e3dcdf1b → 0.8.4-main.422d1c7879
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 +99 -98
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +99 -98
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/builder.d.ts +23 -4
- package/dist/types/src/builder.d.ts.map +1 -1
- package/dist/types/src/builder.test.d.ts +2 -0
- package/dist/types/src/builder.test.d.ts.map +1 -0
- package/dist/types/src/components/DropdownMenu.d.ts +3 -1
- package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +8 -4
- package/dist/types/src/components/Menu.d.ts.map +1 -1
- package/dist/types/src/components/{MenuItems.stories.d.ts → Menu.stories.d.ts} +1 -1
- package/dist/types/src/components/Menu.stories.d.ts.map +1 -0
- package/dist/types/src/components/ToolbarMenu.d.ts +4 -4
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +3 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +7 -3
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +1 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -20
- package/src/builder.test.ts +224 -0
- package/src/builder.ts +41 -18
- package/src/components/DropdownMenu.tsx +0 -1
- package/src/components/Menu.test.tsx +0 -1
- package/src/components/Menu.tsx +9 -10
- package/src/components/ToolbarMenu.stories.tsx +13 -11
- package/src/components/ToolbarMenu.tsx +109 -85
- package/src/hooks/useMenuActions.ts +6 -7
- package/src/index.ts +1 -1
- package/src/testing/generator.ts +15 -10
- package/src/types.ts +1 -0
- package/dist/types/src/components/MenuItems.stories.d.ts.map +0 -1
- /package/src/components/{MenuItems.stories.tsx → Menu.stories.tsx} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Atom, RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
3
3
|
import { createContextScope } from "@radix-ui/react-context";
|
|
4
4
|
import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
|
|
5
|
-
import React4, { useCallback as useCallback3, useContext, useMemo } from "react";
|
|
5
|
+
import React4, { createContext, useCallback as useCallback3, useContext, useMemo } from "react";
|
|
6
6
|
import { log } from "@dxos/log";
|
|
7
7
|
import { Icon as Icon3, DropdownMenu as NaturalDropdownMenu2 } from "@dxos/react-ui";
|
|
8
8
|
|
|
@@ -104,10 +104,10 @@ var actionLabel = (action, t) => {
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
// src/components/ToolbarMenu.tsx
|
|
107
|
-
import React3, {
|
|
107
|
+
import React3, { useCallback as useCallback2 } from "react";
|
|
108
108
|
import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
109
109
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
110
|
-
import {
|
|
110
|
+
import { composable, composableProps } from "@dxos/ui-theme";
|
|
111
111
|
|
|
112
112
|
// src/types.ts
|
|
113
113
|
import { Node as Node2 } from "@dxos/app-graph";
|
|
@@ -187,21 +187,11 @@ var DropdownMenu = {
|
|
|
187
187
|
};
|
|
188
188
|
|
|
189
189
|
// src/components/ToolbarMenu.tsx
|
|
190
|
-
var ActionToolbarItem = ({
|
|
190
|
+
var ActionToolbarItem = ({ __menuScope, action }) => {
|
|
191
191
|
const { iconSize, onAction } = useMenuScoped("ActionToolbarItem", __menuScope);
|
|
192
192
|
const { t } = useTranslation2(translationKey);
|
|
193
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames
|
|
194
|
-
const
|
|
195
|
-
const rootProps = icon ? {
|
|
196
|
-
icon,
|
|
197
|
-
size: iconSize,
|
|
198
|
-
iconOnly,
|
|
199
|
-
label: actionLabel(action, t)
|
|
200
|
-
} : {
|
|
201
|
-
children: /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
202
|
-
action
|
|
203
|
-
})
|
|
204
|
-
};
|
|
193
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
194
|
+
const buttonVariant = action.properties.variant === "primary" ? "primary" : "ghost";
|
|
205
195
|
const handleClick = useCallback2(() => {
|
|
206
196
|
if (onAction) {
|
|
207
197
|
onAction(action, {});
|
|
@@ -212,19 +202,33 @@ var ActionToolbarItem = ({ action, __menuScope }) => {
|
|
|
212
202
|
action,
|
|
213
203
|
onAction
|
|
214
204
|
]);
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
const commonProps = {
|
|
206
|
+
variant: buttonVariant,
|
|
217
207
|
disabled,
|
|
208
|
+
classNames,
|
|
218
209
|
onClick: handleClick,
|
|
219
|
-
variant: variant ?? "ghost",
|
|
220
210
|
...testId && {
|
|
221
211
|
"data-testid": testId
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
if (hidden) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
return icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.IconButton, {
|
|
218
|
+
key: action.id,
|
|
219
|
+
...commonProps,
|
|
220
|
+
icon,
|
|
221
|
+
size: iconSize,
|
|
222
|
+
iconOnly,
|
|
223
|
+
label: actionLabel(action, t)
|
|
224
|
+
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
|
|
225
|
+
key: action.id,
|
|
226
|
+
...commonProps
|
|
227
|
+
}, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
228
|
+
action
|
|
229
|
+
}));
|
|
226
230
|
};
|
|
227
|
-
var DropdownMenuToolbarItem = ({ group, items: propsItems
|
|
231
|
+
var DropdownMenuToolbarItem = ({ __menuScope, group, items: propsItems }) => {
|
|
228
232
|
const { iconOnly, disabled, testId } = group.properties;
|
|
229
233
|
const { t } = useTranslation2(translationKey);
|
|
230
234
|
const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
|
|
@@ -263,7 +267,7 @@ var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
|
|
|
263
267
|
}
|
|
264
268
|
})));
|
|
265
269
|
};
|
|
266
|
-
var ToggleGroupItem = ({ group, action
|
|
270
|
+
var ToggleGroupItem = ({ __menuScope, group, action }) => {
|
|
267
271
|
const { iconSize, onAction } = useMenuScoped("ToggleGroupItem", __menuScope);
|
|
268
272
|
const { t } = useTranslation2(translationKey);
|
|
269
273
|
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
@@ -282,74 +286,63 @@ var ToggleGroupItem = ({ group, action, __menuScope }) => {
|
|
|
282
286
|
group,
|
|
283
287
|
onAction
|
|
284
288
|
]);
|
|
285
|
-
const
|
|
286
|
-
const rootProps = icon ? {
|
|
287
|
-
icon,
|
|
288
|
-
size: iconSize,
|
|
289
|
-
iconOnly,
|
|
290
|
-
label: actionLabel(action, t)
|
|
291
|
-
} : {
|
|
292
|
-
children: /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
293
|
-
action
|
|
294
|
-
})
|
|
295
|
-
};
|
|
296
|
-
return hidden ? null : /* @__PURE__ */ React3.createElement(Root, {
|
|
297
|
-
key: action.id,
|
|
289
|
+
const commonProps = {
|
|
298
290
|
value: action.id,
|
|
299
291
|
disabled,
|
|
300
|
-
onClick: handleClick,
|
|
301
292
|
variant: "ghost",
|
|
293
|
+
classNames,
|
|
294
|
+
onClick: handleClick,
|
|
302
295
|
...testId && {
|
|
303
296
|
"data-testid": testId
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
return hidden ? null : icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupIconItem, {
|
|
300
|
+
...commonProps,
|
|
301
|
+
icon,
|
|
302
|
+
size: iconSize,
|
|
303
|
+
iconOnly,
|
|
304
|
+
label: actionLabel(action, t)
|
|
305
|
+
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, commonProps, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
306
|
+
action
|
|
307
|
+
}));
|
|
308
308
|
};
|
|
309
|
-
var ToggleGroupToolbarItem = ({ group, items:
|
|
310
|
-
const items = useMenuItems(group,
|
|
311
|
-
const { selectCardinality
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
);
|
|
309
|
+
var ToggleGroupToolbarItem = ({ __menuScope, group, items: itemsProp }) => {
|
|
310
|
+
const items = useMenuItems(group, itemsProp, "ToggleGroupToolbarItem", __menuScope);
|
|
311
|
+
const { selectCardinality } = group.properties;
|
|
312
|
+
const children = items.map((action) => /* @__PURE__ */ React3.createElement(ToggleGroupItem, {
|
|
313
|
+
key: action.id,
|
|
314
|
+
group,
|
|
315
|
+
action
|
|
316
|
+
}));
|
|
317
|
+
if (selectCardinality === "multiple") {
|
|
318
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
319
|
+
type: "multiple",
|
|
320
|
+
value: group.properties.value
|
|
321
|
+
}, children);
|
|
322
|
+
} else {
|
|
323
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
324
|
+
type: "single",
|
|
325
|
+
value: group.properties.value
|
|
326
|
+
}, children);
|
|
327
|
+
}
|
|
329
328
|
};
|
|
330
|
-
var ToolbarMenu = ({ __menuScope,
|
|
329
|
+
var ToolbarMenu = composable(({ __menuScope, children, ...props }, forwardedRef) => {
|
|
331
330
|
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
332
331
|
const { attendableId, alwaysActive } = useMenuScoped("ToolbarMenu", __menuScope);
|
|
333
332
|
const { hasAttention } = useAttention(attendableId);
|
|
334
|
-
const InnerRoot = textBlockWidthProp ? "div" : Fragment;
|
|
335
|
-
const innerRootProps = textBlockWidthProp ? {
|
|
336
|
-
role: "none",
|
|
337
|
-
className: mx2(textBlockWidth, toolbarLayout, "h-full")
|
|
338
|
-
} : {};
|
|
339
333
|
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
|
|
340
|
-
...props,
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
classNames
|
|
344
|
-
],
|
|
334
|
+
...composableProps(props, {
|
|
335
|
+
classNames: attendableId
|
|
336
|
+
}),
|
|
345
337
|
disabled: !alwaysActive && !hasAttention,
|
|
346
|
-
|
|
347
|
-
},
|
|
348
|
-
key: item.id
|
|
338
|
+
ref: forwardedRef
|
|
339
|
+
}, items?.map((item) => /* @__PURE__ */ React3.createElement(ToolbarMenuItem, {
|
|
340
|
+
key: item.id,
|
|
341
|
+
__menuScope,
|
|
349
342
|
item
|
|
350
|
-
})))
|
|
351
|
-
};
|
|
352
|
-
var ToolbarMenuItem = ({ item }) => {
|
|
343
|
+
})), children);
|
|
344
|
+
});
|
|
345
|
+
var ToolbarMenuItem = ({ __menuScope, item }) => {
|
|
353
346
|
if (isSeparator(item)) {
|
|
354
347
|
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Separator, {
|
|
355
348
|
variant: item.properties.variant
|
|
@@ -358,15 +351,18 @@ var ToolbarMenuItem = ({ item }) => {
|
|
|
358
351
|
if (isMenuGroup(item)) {
|
|
359
352
|
if (item.properties.variant === "dropdownMenu") {
|
|
360
353
|
return /* @__PURE__ */ React3.createElement(DropdownMenuToolbarItem, {
|
|
354
|
+
__menuScope,
|
|
361
355
|
group: item
|
|
362
356
|
});
|
|
363
357
|
} else {
|
|
364
358
|
return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
|
|
359
|
+
__menuScope,
|
|
365
360
|
group: item
|
|
366
361
|
});
|
|
367
362
|
}
|
|
368
363
|
}
|
|
369
364
|
return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
|
|
365
|
+
__menuScope,
|
|
370
366
|
action: item
|
|
371
367
|
});
|
|
372
368
|
};
|
|
@@ -389,7 +385,7 @@ var menuContextDefaults = {
|
|
|
389
385
|
};
|
|
390
386
|
var [MenuContextProvider, useMenuScoped] = createMenuContext(MENU_NAME, menuContextDefaults);
|
|
391
387
|
var useMenuScope = createMenuScope();
|
|
392
|
-
var MenuDropdownContext = /* @__PURE__ */
|
|
388
|
+
var MenuDropdownContext = /* @__PURE__ */ createContext({
|
|
393
389
|
closeMenu: () => {
|
|
394
390
|
}
|
|
395
391
|
});
|
|
@@ -456,7 +452,7 @@ var resolveItems = (baseItems, group, entries) => {
|
|
|
456
452
|
using: replacements[0].id
|
|
457
453
|
}, {
|
|
458
454
|
F: __dxlog_file,
|
|
459
|
-
L:
|
|
455
|
+
L: 151,
|
|
460
456
|
S: void 0,
|
|
461
457
|
C: (f, a) => f(...a)
|
|
462
458
|
});
|
|
@@ -575,23 +571,21 @@ var Menu = {
|
|
|
575
571
|
|
|
576
572
|
// src/hooks/useMenuActions.ts
|
|
577
573
|
import { RegistryContext as RegistryContext2, useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
|
|
578
|
-
import { useCallback as useCallback4, useContext as useContext2,
|
|
574
|
+
import { useCallback as useCallback4, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
579
575
|
import { Graph, Node as Node3 } from "@dxos/app-graph";
|
|
580
576
|
var useMenuActions = (props) => {
|
|
581
577
|
const registry = useContext2(RegistryContext2);
|
|
582
578
|
const menuGraphProps = useAtomValue2(props);
|
|
583
|
-
const
|
|
584
|
-
if (!graphRef.current || graphRef.current.props !== menuGraphProps) {
|
|
579
|
+
const graph = useMemo2(() => {
|
|
585
580
|
const newGraph = Graph.make({
|
|
586
581
|
registry
|
|
587
582
|
});
|
|
588
583
|
newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const graph = graphRef.current.graph;
|
|
584
|
+
return newGraph;
|
|
585
|
+
}, [
|
|
586
|
+
registry,
|
|
587
|
+
menuGraphProps
|
|
588
|
+
]);
|
|
595
589
|
const items = useCallback4((group) => {
|
|
596
590
|
return graph.connections(group?.id || Node3.RootId, "child");
|
|
597
591
|
}, [
|
|
@@ -616,7 +610,7 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
616
610
|
root(props) {
|
|
617
611
|
invariant(this._rootId === "root", "Root group can only be at the top level", {
|
|
618
612
|
F: __dxlog_file2,
|
|
619
|
-
L:
|
|
613
|
+
L: 61,
|
|
620
614
|
S: this,
|
|
621
615
|
A: [
|
|
622
616
|
"this._rootId === 'root'",
|
|
@@ -625,7 +619,7 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
625
619
|
});
|
|
626
620
|
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
|
|
627
621
|
F: __dxlog_file2,
|
|
628
|
-
L:
|
|
622
|
+
L: 62,
|
|
629
623
|
S: this,
|
|
630
624
|
A: [
|
|
631
625
|
"this._data.nodes.find((node) => node.id === 'root') === undefined",
|
|
@@ -657,13 +651,20 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
657
651
|
cb(new _MenuBuilderImpl(this._data, id));
|
|
658
652
|
return this;
|
|
659
653
|
}
|
|
660
|
-
subgraph(
|
|
661
|
-
|
|
662
|
-
|
|
654
|
+
subgraph(subgraphOrCb) {
|
|
655
|
+
if (!subgraphOrCb) {
|
|
656
|
+
return this;
|
|
657
|
+
}
|
|
658
|
+
if (typeof subgraphOrCb === "function") {
|
|
659
|
+
subgraphOrCb(new _MenuBuilderImpl(this._data, this._rootId));
|
|
660
|
+
} else {
|
|
661
|
+
this._data.nodes.push(...subgraphOrCb.nodes);
|
|
662
|
+
this._data.edges.push(...subgraphOrCb.edges);
|
|
663
|
+
}
|
|
663
664
|
return this;
|
|
664
665
|
}
|
|
665
|
-
separator(
|
|
666
|
-
id
|
|
666
|
+
separator(variant = "gap") {
|
|
667
|
+
const id = `separator-${++this._separatorCount}`;
|
|
667
668
|
this._data.nodes.push({
|
|
668
669
|
id,
|
|
669
670
|
type: MenuSeparatorType,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/Menu.tsx", "../../../src/util.ts", "../../../src/components/ActionLabel.tsx", "../../../src/translations.ts", "../../../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, { 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';\n\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 = React.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 = PropsWithChildren<\n Omit<MenuProviderProps, 'children'> &\n Pick<DropdownMenuRootProps, 'open' | 'defaultOpen' | 'onOpenChange'> & {\n /** Identifies the component that owns this menu (passed to action handlers). */\n caller?: string;\n }\n>;\n\n/**\n * Menu context boundary.\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 { runAndForwardErrors } from '@dxos/effect';\nimport { type MenuActionProperties, type MenuItemGroupProperties } from '@dxos/ui-types';\nimport { getHostPlatform } from '@dxos/util';\n\nimport { type MenuAction, type MenuItemGroup, type MenuSeparator } from './types';\n\n/**\n * Execute a menu action's Effect with its captured context.\n * This provides the `_actionContext` layer if available.\n */\nexport const executeMenuAction = async (action: MenuAction, params: Node.InvokeProps = {}): Promise<void> => {\n let effect = action.data(params);\n\n // Provide captured action context if available.\n if (action._actionContext) {\n effect = effect.pipe(Effect.provide(action._actionContext));\n }\n\n await runAndForwardErrors(effect);\n};\n\nexport const getShortcut = (action: Node.ActionLike) => {\n return typeof action.properties?.keyBinding === 'string'\n ? action.properties.keyBinding\n : action.properties?.keyBinding?.[getHostPlatform()];\n};\n\nexport const fallbackIcon = 'ph--placeholder--regular';\n\nexport const createMenuAction = <P extends {} = {}>(\n id: string,\n invoke: () => void,\n properties: P & MenuActionProperties,\n) =>\n ({\n id,\n type: Node.ActionType,\n properties,\n data: () => Effect.sync(invoke),\n }) satisfies MenuAction;\n\nexport const createMenuItemGroup = <\n P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,\n>(\n id: string,\n properties: P,\n) =>\n ({\n id,\n type: Node.ActionGroupType,\n properties,\n data: Node.actionGroupSymbol,\n }) satisfies MenuItemGroup;\n\nexport const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'gap' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [\n {\n source,\n target: id,\n 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';\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 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-menu';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const satisfies Resource[];\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { Fragment, useCallback } from 'react';\n\nimport { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx, textBlockWidth, toolbarLayout } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport {\n type MenuAction,\n type MenuItem,\n type MenuItemGroup,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n isMenuGroup,\n isSeparator,\n} from '../types';\nimport { executeMenuAction } from '../util';\n\nimport { ActionLabel, actionLabel } from './ActionLabel';\nimport { DropdownMenu } from './DropdownMenu';\nimport { type MenuScopedProps, 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 & { textBlockWidth?: boolean };\n\nexport type ToolbarMenuActionGroupProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n items?: MenuItem[];\n};\n\nexport type ToolbarMenuActionProps = {\n group: MenuItemGroup<ToolbarMenuActionGroupProperties>;\n action: MenuAction;\n};\n\nconst ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {\n const { iconSize, onAction } = useMenuScoped('ActionToolbarItem', __menuScope);\n const { t } = useTranslation(translationKey);\n\n const { icon, iconOnly = true, disabled, testId, hidden, classNames, variant } = action.properties;\n const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }\n : { children: <ActionLabel action={action} /> };\n\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, {});\n } else {\n void executeMenuAction(action);\n }\n }, [action, onAction]);\n\n return hidden ? null : (\n <Root\n key={action.id}\n disabled={disabled}\n onClick={handleClick}\n variant={variant ?? 'ghost'}\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as any)}\n classNames={classNames}\n />\n );\n};\n\nconst DropdownMenuToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const { iconOnly, disabled, testId } = group.properties;\n const { t } = useTranslation(translationKey);\n const { iconSize } = 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 const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;\n const rootProps = icon\n ? {\n icon,\n size: iconSize,\n iconOnly,\n label: actionLabel(labelAction, t),\n caretDown: true,\n }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='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 = ({ group, action, __menuScope }: MenuScopedProps<ToolbarMenuActionProps>) => {\n const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);\n const { t } = useTranslation(translationKey);\n const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;\n const handleClick = useCallback(() => {\n if (onAction) {\n onAction(action, { parent: group });\n } else {\n void executeMenuAction(action, { parent: group });\n }\n }, [action, group, onAction]);\n const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;\n const rootProps = icon\n ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }\n : { children: <ActionLabel action={action} /> };\n\n return hidden ? null : (\n <Root\n key={action.id}\n value={action.id as any}\n disabled={disabled}\n onClick={handleClick}\n variant='ghost'\n {...(testId && { 'data-testid': testId })}\n {...(rootProps as any)}\n classNames={classNames}\n />\n );\n};\n\nconst ToggleGroupToolbarItem = ({\n group,\n items: propsItems,\n __menuScope,\n}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {\n const items = useMenuItems(group, propsItems, 'ToggleGroupToolbarItem', __menuScope);\n const { selectCardinality, value } = group.properties;\n\n return (\n // TODO(thure): Fix.\n // @ts-ignore\n <NaturalToolbar.ToggleGroup type={selectCardinality} value={value}>\n {\n // TODO(thure): Handle other menu item types.\n (items as MenuAction[]).map((action) => (\n <ToggleGroupItem key={action.id} group={group} action={action} />\n ))\n }\n </NaturalToolbar.ToggleGroup>\n );\n};\n\n// TODO(burdon): Reconcile with react-ui/Toolbar (incl. textBlockWidth)\nexport const ToolbarMenu = ({\n __menuScope,\n classNames,\n textBlockWidth: textBlockWidthProp,\n ...props\n}: MenuScopedProps<ToolbarMenuProps>) => {\n const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);\n const { attendableId, alwaysActive } = useMenuScoped('ToolbarMenu', __menuScope);\n const { hasAttention } = useAttention(attendableId);\n const InnerRoot = textBlockWidthProp ? 'div' : Fragment;\n const innerRootProps = textBlockWidthProp\n ? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'h-full') }\n : {};\n\n return (\n <NaturalToolbar.Root\n {...props}\n classNames={[attendableId, classNames]}\n disabled={!alwaysActive && !hasAttention}\n layoutManaged={textBlockWidthProp}\n >\n <InnerRoot {...innerRootProps}>\n {items?.map((item: MenuItem, i: number) => (\n <ToolbarMenuItem key={item.id ?? i} item={item} />\n ))}\n </InnerRoot>\n </NaturalToolbar.Root>\n );\n};\n\nconst ToolbarMenuItem = ({ item }: { item: MenuItem }) => {\n if (isSeparator(item)) {\n return <NaturalToolbar.Separator variant={item.properties.variant} />;\n }\n\n // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.\n if (isMenuGroup(item)) {\n if (item.properties.variant === 'dropdownMenu') {\n return <DropdownMenuToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n } else {\n return <ToggleGroupToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;\n }\n }\n\n return <ActionToolbarItem action={item as MenuAction} />;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { 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 /** 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';\n\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 { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { useCallback, useContext, useRef } from 'react';\n\nimport { Graph, Node } from '@dxos/app-graph';\n\nimport { type MenuItem, type MenuItemGroup, 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 const graphRef = useRef<{ graph: Graph.WritableGraph; props: ActionGraphProps } | null>(null);\n if (!graphRef.current || graphRef.current.props !== menuGraphProps) {\n const newGraph = Graph.make({ registry });\n newGraph.pipe(Graph.addNodes(menuGraphProps.nodes as Node.NodeArg<any>[]), Graph.addEdges(menuGraphProps.edges));\n graphRef.current = { graph: newGraph, props: menuGraphProps };\n }\n\n const graph = graphRef.current.graph;\n\n const 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// 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\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 /** Add a nested action group. */\n group<P extends {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this;\n /** Merge pre-built nodes and edges into this builder. */\n subgraph(subgraph: ActionGraphProps): this;\n /** Add a separator. */\n separator(id?: string, variant?: 'gap' | 'line'): this;\n}\n\nexport interface MenuBuilder extends ActionGroupBuilder {\n root(props: MenuItemGroupProperties): this;\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 {} = {}>(\n id: string,\n props: P & MenuItemGroupProperties,\n cb: (builder: ActionGroupBuilder) => void,\n ): this {\n this._data.nodes.push(createMenuItemGroup(id, props));\n this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });\n cb(new MenuBuilderImpl(this._data, id));\n return this;\n }\n\n subgraph(subgraph: ActionGraphProps): this {\n this._data.nodes.push(...subgraph.nodes);\n this._data.edges.push(...subgraph.edges);\n return this;\n }\n\n separator(id?: string, variant: 'gap' | 'line' = 'gap'): this {\n 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", "useCallback", "useContext", "useMemo", "log", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "runAndForwardErrors", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "getHostPlatform", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "relation", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "translationKey", "translations", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "keySymbols", "join", "actionLabel", "React", "
|
|
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 { runAndForwardErrors } from '@dxos/effect';\nimport { type MenuActionProperties, type MenuItemGroupProperties } from '@dxos/ui-types';\nimport { getHostPlatform } from '@dxos/util';\n\nimport { type MenuAction, type MenuItemGroup, type MenuSeparator } from './types';\n\n/**\n * Execute a menu action's Effect with its captured context.\n * This provides the `_actionContext` layer if available.\n */\nexport const executeMenuAction = async (action: MenuAction, params: Node.InvokeProps = {}): Promise<void> => {\n let effect = action.data(params);\n\n // Provide captured action context if available.\n if (action._actionContext) {\n effect = effect.pipe(Effect.provide(action._actionContext));\n }\n\n await runAndForwardErrors(effect);\n};\n\nexport const getShortcut = (action: Node.ActionLike) => {\n return typeof action.properties?.keyBinding === 'string'\n ? action.properties.keyBinding\n : action.properties?.keyBinding?.[getHostPlatform()];\n};\n\nexport const fallbackIcon = 'ph--placeholder--regular';\n\nexport const createMenuAction = <P extends {} = {}>(\n id: string,\n invoke: () => void,\n properties: P & MenuActionProperties,\n) =>\n ({\n id,\n type: Node.ActionType,\n properties,\n data: () => Effect.sync(invoke),\n }) satisfies MenuAction;\n\nexport const createMenuItemGroup = <\n P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,\n>(\n id: string,\n properties: P,\n) =>\n ({\n id,\n type: Node.ActionGroupType,\n properties,\n data: Node.actionGroupSymbol,\n }) satisfies MenuItemGroup;\n\nexport const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({\n nodes: [\n {\n id,\n type: '@dxos/react-ui-toolbar/separator',\n properties: { variant: 'gap' },\n data: undefined as never,\n } satisfies MenuSeparator,\n ],\n edges: [\n {\n source,\n target: id,\n 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';\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 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-menu';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {},\n },\n },\n] as const satisfies Resource[];\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback } from 'react';\n\nimport { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { composable, composableProps } from '@dxos/ui-theme';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { translationKey } from '../translations';\nimport {\n type MenuAction,\n type MenuItem,\n type MenuItemGroup,\n type MenuMultipleSelectActionGroup,\n type MenuSingleSelectActionGroup,\n isMenuGroup,\n isSeparator,\n} from '../types';\nimport { executeMenuAction } from '../util';\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 } = 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 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 const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;\n const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;\n const rootProps = icon\n ? {\n icon,\n size: iconSize,\n iconOnly,\n label: actionLabel(labelAction, t),\n caretDown: true,\n }\n : {\n children: (\n <>\n <ActionLabel action={labelAction} />\n <Icon size={3} icon='ph--caret-down--bold' classNames='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 } = 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 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 { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';\nimport { 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// 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": ";AAIA,SAASA,MAAMC,iBAAiBC,oBAAoB;AACpD,SAAqBC,0BAA0B;AAC/C,SAASC,wBAAAA,6BAA4B;AACrC,OAAOC,UAASC,eAAwDC,eAAAA,cAAaC,YAAYC,eAAe;AAEhH,SAASC,WAAW;AACpB,SAAqCC,QAAAA,OAAMC,gBAAgBC,4BAA2B;;;ACNtF,YAAYC,YAAY;AAExB,SAASC,YAAY;AACrB,SAASC,2BAA2B;AAEpC,SAASC,uBAAuB;AAQzB,IAAMC,oBAAoB,OAAOC,QAAoBC,SAA2B,CAAC,MAAC;AACvF,MAAIC,SAASF,OAAOG,KAAKF,MAAAA;AAGzB,MAAID,OAAOI,gBAAgB;AACzBF,aAASA,OAAOG,KAAYC,eAAQN,OAAOI,cAAc,CAAA;EAC3D;AAEA,QAAMG,oBAAoBL,MAAAA;AAC5B;AAEO,IAAMM,cAAc,CAACR,WAAAA;AAC1B,SAAO,OAAOA,OAAOS,YAAYC,eAAe,WAC5CV,OAAOS,WAAWC,aAClBV,OAAOS,YAAYC,aAAaC,gBAAAA,CAAAA;AACtC;AAIO,IAAMC,mBAAmB,CAC9BC,IACAC,QACAC,gBAEC;EACCF;EACAG,MAAMC,KAAKC;EACXH;EACAI,MAAM,MAAaC,YAAKN,MAAAA;AAC1B;AAEK,IAAMO,sBAAsB,CAGjCR,IACAE,gBAEC;EACCF;EACAG,MAAMC,KAAKK;EACXP;EACAI,MAAMF,KAAKM;AACb;AAEK,IAAMC,qBAAqB,CAACX,KAAa,OAAOY,SAAiB,YAAY;EAClFC,OAAO;IACL;MACEb;MACAG,MAAM;MACND,YAAY;QAAEY,SAAS;MAAM;MAC7BR,MAAMS;IACR;;EAEFC,OAAO;IACL;MACEJ;MACAK,QAAQjB;MACRkB,UAAU;IACZ;;AAEJ;AAEO,IAAMC,sBAAsB,CAACnB,KAAa,QAAQY,SAAiB,YAAY;EACpFC,OAAO;IACL;MACEb;MACAG,MAAM;MACND,YAAY;QAAEY,SAAS;MAAO;MAC9BR,MAAMS;IACR;;EAEFC,OAAO;IAAC;MAAEJ;MAAQK,QAAQjB;MAAIkB,UAAU;IAAiB;;AAC3D;;;ACrFA,OAAOE,WAAW;AAGlB,SAASC,kBAAkB;AAC3B,SAAyBC,mBAAmBC,sBAAsB;AAClE,SAASC,UAAU;;;ACHZ,IAAMC,iBAAiB;AAEvB,IAAMC,eAAe;EAC1B;IACE,SAAS;MACP,CAACD,cAAAA,GAAiB,CAAC;IACrB;EACF;;;;ADIK,IAAME,cAAc,CAAC,EAAEC,OAAM,MAAsB;AACxD,QAAM,EAAEC,EAAC,IAAKC,eAAeC,cAAAA;AAC7B,QAAMC,WAAWC,YAAYL,MAAAA;AAC7B,SACE,sBAAA,cAAA,MAAA,UAAA,MACE,sBAAA,cAACM,QAAAA;IAAKC,WAAU;KAAiBC,kBAAkBR,OAAOS,WAAYC,OAAOT,CAAAA,CAAAA,GAC5EG,YAAY,sBAAA,cAACE,QAAAA;IAAKC,WAAWI,GAAG,YAAY,kBAAA;KAAsBC,WAAWR,QAAAA,EAAUS,KAAK,EAAA,CAAA,CAAA;AAGnG;AAEO,IAAMC,cAAc,CAACd,QAAgBC,MAAAA;AAC1C,QAAMG,WAAWC,YAAYL,MAAAA;AAC7B,SAAO,GAAGQ,kBAAkBR,OAAOS,WAAYC,OAAOT,CAAAA,CAAAA,GAAKG,WAAW,KAAKQ,WAAWR,QAAAA,EAAUS,KAAK,EAAA,CAAA,MAAS,EAAA;AAChH;;;AE3BA,OAAOE,UAASC,eAAAA,oBAAmB;AAEnC,SAASC,QAAAA,OAAMC,WAAWC,gBAAuCC,kBAAAA,uBAAsB;AACvF,SAASC,oBAAoB;AAC7B,SAASC,YAAYC,uBAAuB;;;ACF5C,SAASC,QAAAA,aAAY;AAMd,IAAMC,oBAAoB;AAM1B,IAAMC,cAAc,CAACC,SAA2CA,KAAKC,SAASH;AAO9E,IAAMI,cAAc,CAACF,SAA2CA,KAAKC,SAASE,MAAKC;;;ACrB1F,SAASC,4BAA4B;AACrC,OAAOC,UAA0BC,mBAAmB;AAEpD,SAAqCC,MAAMC,gBAAgBC,2BAA2B;AAatF,IAAMC,mBAAmB,CAAC,EACxBC,MACAC,SACAC,YAAW,MAIX;AAEA,QAAMC,SAASH;AACf,QAAMI,cAAcC,YAAY,CAACC,UAAsBL,QAAQE,QAAQG,KAAAA,GAAQ;IAACH;IAAQF;GAAQ;AAChG,QAAM,EAAEM,SAAQ,IAAKC,cAAc,oBAAoBN,WAAAA;AACvD,SACE,gBAAAO,OAAA,cAACC,oBAAoBC,MAAI;IACvBV,SAASG;IACTQ,YAAW;IACXC,UAAUV,OAAOW,YAAYD;IAC5B,GAAIV,OAAOW,YAAYC,UAAU;MAAE,eAAeZ,OAAOW,WAAWC;IAAO;KAE3EZ,OAAOW,YAAYE,QAAQ,gBAAAP,OAAA,cAACQ,MAAAA;IAAKD,MAAMb,OAAOW,WAAYE;IAAME,MAAMX;MACvE,gBAAAE,OAAA,cAACU,aAAAA;IAAYhB;;AAGnB;AAEA,IAAMiB,mBAAmB,CAAC,EACxBC,OAAOC,YACPC,OACAC,MACAC,aACAC,cACAC,QACAC,UACA1B,aACA,GAAG2B,aAAAA,MACgC;AACnC,QAAM,CAACC,iBAAiBC,kBAAAA,IAAsBC,qBAAqB;IACjEC,MAAMT;IACNU,aAAaT;IACbU,UAAUT;EACZ,CAAA;AAEA,QAAM,EAAEU,SAAQ,IAAK5B,cAAc,oBAAoBN,WAAAA;AAEvD,QAAMmC,oBAAoBhC,YACxB,CAACF,QAAoBG,UAAAA;AACnB,QAAIH,OAAOW,YAAYD,UAAU;AAC/B;IACF;AACAP,UAAMgC,gBAAe;AAErBP,uBAAmB,KAAA;AACnB,QAAIK,UAAU;AACZA,eAASjC,QAAQ;QAAEoC,QAAQhB;QAAOI;MAAO,CAAA;IAC3C,OAAO;AACL,WAAKa,kBAAkBrC,QAAQ;QAAEoC,QAAQhB;QAAOI;MAAO,CAAA;IACzD;EACF,GACA;IAACJ;IAAOI;IAAQS;GAAS;AAG3B,QAAMf,QAAQoB,aAAalB,OAAOD,UAAAA;AAElC,SACE,gBAAAb,OAAA,cAACC,oBAAoBgC,MAAI;IAAClB,MAAMM;IAAiBJ,cAAcK;IAAqB,GAAGF;KACpFD,UACD,gBAAAnB,OAAA,cAACC,oBAAoBiC,QAAM,MACzB,gBAAAlC,OAAA,cAACC,oBAAoBkC,SAAO,MAC1B,gBAAAnC,OAAA,cAACC,oBAAoBmC,UAAQ,MAC1BxB,OAAOyB,IAAI,CAAC9C,SACX,gBAAAS,OAAA,cAACV,kBAAAA;IAAiBgD,KAAK/C,KAAKgD;IAAIhD;IAAYC,SAASoC;QAGzD,gBAAA5B,OAAA,cAACC,oBAAoBuC,OAAK,IAAA,CAAA,CAAA,CAAA;AAKpC;AAEO,IAAMC,eAAe;EAC1BR,MAAMtB;EACN+B,SAASzC,oBAAoByC;EAC7BC,gBAAgB1C,oBAAoB0C;AACtC;;;AFlDA,IAAMC,oBAAoB,CAAC,EAAEC,aAAaC,OAAM,MAA2C;AACzF,QAAM,EAAEC,UAAUC,SAAQ,IAAKC,cAAc,qBAAqBJ,WAAAA;AAClE,QAAM,EAAEK,EAAC,IAAKC,gBAAeC,cAAAA;AAE7B,QAAM,EAAEC,MAAMC,WAAW,MAAMC,UAAUC,QAAQC,QAAQC,WAAU,IAAKZ,OAAOa;AAC/E,QAAMC,gBACHd,OAAOa,WAAoCE,YAAY,YAAa,YAAuB;AAE9F,QAAMC,cAAcC,aAAY,MAAA;AAC9B,QAAIf,UAAU;AACZA,eAASF,QAAQ,CAAC,CAAA;IACpB,OAAO;AACL,WAAKkB,kBAAkBlB,MAAAA;IACzB;EACF,GAAG;IAACA;IAAQE;GAAS;AAErB,QAAMiB,cAAc;IAClBJ,SAASD;IACTL;IACAG;IACAQ,SAASJ;IACT,GAAIN,UAAU;MAAE,eAAeA;IAAO;EACxC;AAEA,MAAIC,QAAQ;AACV,WAAO;EACT;AAEA,SAAOJ,OACL,gBAAAc,OAAA,cAACC,eAAeC,YAAU;IACxBC,KAAKxB,OAAOyB;IACX,GAAGN;IACJZ;IACAmB,MAAMzB;IACNO;IACAmB,OAAOC,YAAY5B,QAAQI,CAAAA;OAG7B,gBAAAiB,OAAA,cAACC,eAAeO,QAAM;IAACL,KAAKxB,OAAOyB;IAAK,GAAGN;KACzC,gBAAAE,OAAA,cAACS,aAAAA;IAAY9B;;AAGnB;AAEA,IAAM+B,0BAA0B,CAAC,EAC/BhC,aACAiC,OACAC,OAAOC,WAAU,MAC4B;AAC7C,QAAM,EAAE1B,UAAUC,UAAUC,OAAM,IAAKsB,MAAMnB;AAC7C,QAAM,EAAET,EAAC,IAAKC,gBAAeC,cAAAA;AAC7B,QAAM,EAAEL,SAAQ,IAAKE,cAAc,2BAA2BJ,WAAAA;AAC9D,QAAMkC,QAAQE,aAAaH,OAAOE,YAAY,2BAA2BnC,WAAAA;AACzE,QAAMqC,aAAaH,OAAOI,KAAK,CAACC,SAAS,CAAC,CAAEA,KAAoBzB,WAAW0B,OAAO;AAClF,QAAMhC,OACFyB,MAAMnB,WAAmB2B;EAExBJ,YAA2BvB,WAAWN,QACzCyB,MAAMnB,WAAWN;AACnB,QAAMkC,OAAOlC,OAAOe,eAAeC,aAAaD,eAAeO;AAC/D,QAAMa,cAAeV,MAAMnB,WAAmB2B,eAAeJ,aAAcA,aAA4BJ;AACvG,QAAMW,YAAYpC,OACd;IACEA;IACAmB,MAAMzB;IACNO;IACAmB,OAAOC,YAAYc,aAAatC,CAAAA;IAChCwC,WAAW;EACb,IACA;IACEC,UACE,gBAAAxB,OAAA,cAAAA,OAAA,UAAA,MACE,gBAAAA,OAAA,cAACS,aAAAA;MAAY9B,QAAQ0C;QACrB,gBAAArB,OAAA,cAACyB,OAAAA;MAAKpB,MAAM;MAAGnB,MAAK;MAAuBK,YAAW;;EAG5D;AAEJ,SACE,gBAAAS,OAAA,cAAC0B,aAAaN,MAAI;IAACT;IAAcC;KAC/B,gBAAAZ,OAAA,cAAC0B,aAAaC,SAAO;IAACC,SAAAA;KACpB,gBAAA5B,OAAA,cAACoB,MAAAA;IAAK1B,SAAQ;IAAQN;IAAqB,GAAIkC;IAAoB,GAAIjC,UAAU;MAAE,eAAeA;IAAO;;AAIjH;AAEA,IAAMwC,kBAAkB,CAAC,EAAEnD,aAAaiC,OAAOhC,OAAM,MAA2C;AAC9F,QAAM,EAAEC,UAAUC,SAAQ,IAAKC,cAAc,mBAAmBJ,WAAAA;AAChE,QAAM,EAAEK,EAAC,IAAKC,gBAAeC,cAAAA;AAC7B,QAAM,EAAEC,MAAMC,WAAW,MAAMC,UAAUC,QAAQC,QAAQC,WAAU,IAAKZ,OAAOa;AAE/E,QAAMG,cAAcC,aAAY,MAAA;AAC9B,QAAIf,UAAU;AACZA,eAASF,QAAQ;QAAEmD,QAAQnB;MAAM,CAAA;IACnC,OAAO;AACL,WAAKd,kBAAkBlB,QAAQ;QAAEmD,QAAQnB;MAAM,CAAA;IACjD;EACF,GAAG;IAAChC;IAAQgC;IAAO9B;GAAS;AAE5B,QAAMiB,cAAc;IAClBiC,OAAOpD,OAAOyB;IACdhB;IACAM,SAAS;IACTH;IACAQ,SAASJ;IACT,GAAIN,UAAU;MAAE,eAAeA;IAAO;EACxC;AAEA,SAAOC,SAAS,OAAOJ,OACrB,gBAAAc,OAAA,cAACC,eAAe+B,qBAAmB;IAChC,GAAGlC;IACJZ;IACAmB,MAAMzB;IACNO;IACAmB,OAAOC,YAAY5B,QAAQI,CAAAA;OAG7B,gBAAAiB,OAAA,cAACC,eAAe4B,iBAAoB/B,aAClC,gBAAAE,OAAA,cAACS,aAAAA;IAAY9B;;AAGnB;AAEA,IAAMsD,yBAAyB,CAAC,EAC9BvD,aACAiC,OACAC,OAAOsB,UAAS,MAC6B;AAC7C,QAAMtB,QAAQE,aAAaH,OAAOuB,WAAW,0BAA0BxD,WAAAA;AACvE,QAAM,EAAEyD,kBAAiB,IAAKxB,MAAMnB;AAGpC,QAAMgC,WAAYZ,MAAuBwB,IAAI,CAACzD,WAC5C,gBAAAqB,OAAA,cAAC6B,iBAAAA;IAAgB1B,KAAKxB,OAAOyB;IAAIO;IAAchC;;AAGjD,MAAIwD,sBAAsB,YAAY;AACpC,WACE,gBAAAnC,OAAA,cAACC,eAAeoC,aAAW;MAACC,MAAK;MAAWP,OAAOpB,MAAMnB,WAAWuC;OACjEP,QAAAA;EAGP,OAAO;AACL,WACE,gBAAAxB,OAAA,cAACC,eAAeoC,aAAW;MAACC,MAAK;MAASP,OAAOpB,MAAMnB,WAAWuC;OAC/DP,QAAAA;EAGP;AACF;AAEO,IAAMe,cAAcC,WACzB,CAAC,EAAE9D,aAAa8C,UAAU,GAAGiB,MAAAA,GAASC,iBAAAA;AACpC,QAAM9B,QAAQE,aAAa6B,QAAWA,QAAW,eAAejE,WAAAA;AAChE,QAAM,EAAEkE,cAAcC,aAAY,IAAK/D,cAAc,eAAeJ,WAAAA;AACpE,QAAM,EAAEoE,aAAY,IAAKC,aAAaH,YAAAA;AAEtC,SACE,gBAAA5C,OAAA,cAACC,eAAemB,MAAI;IACjB,GAAG4B,gBAAgBP,OAAO;MAAElD,YAAYqD;IAAa,CAAA;IACtDxD,UAAU,CAACyD,gBAAgB,CAACC;IAC5BG,KAAKP;KAEJ9B,OAAOwB,IAAI,CAACnB,SACX,gBAAAjB,OAAA,cAACkD,iBAAAA;IAAgB/C,KAAKc,KAAKb;IAAI1B;IAA0BuC;OAE1DO,QAAAA;AAGP,CAAA;AAGF,IAAM0B,kBAAkB,CAAC,EAAExE,aAAauC,KAAI,MAAuC;AACjF,MAAIkC,YAAYlC,IAAAA,GAAO;AACrB,WAAO,gBAAAjB,OAAA,cAACC,eAAemD,WAAS;MAAC1D,SAASuB,KAAKzB,WAAWE;;EAC5D;AAEA,MAAI2D,YAAYpC,IAAAA,GAAO;AACrB,QAAIA,KAAKzB,WAAWE,YAAY,gBAAgB;AAC9C,aACE,gBAAAM,OAAA,cAACU,yBAAAA;QACChC;QACAiC,OAAOM;;IAGb,OAAO;AACL,aACE,gBAAAjB,OAAA,cAACiC,wBAAAA;QACCvD;QACAiC,OAAOM;;IAGb;EACF;AAEA,SAAO,gBAAAjB,OAAA,cAACvB,mBAAAA;IAAkBC;IAA0BC,QAAQsC;;AAC9D;;;;AJ3NA,IAAMqC,YAAY;AAElB,IAAM,CAACC,mBAAmBC,eAAAA,IAAmBC,mBAAmBH,WAAW,CAAA,CAAE;AAE7E,IAAMI,gBAAgBC,KAAKC,KAAwB,IAAA;AACnD,IAAMC,uBAA0C,MAAMH;AAEtD,IAAMI,sBAAwC;EAC5CC,UAAU;EACVC,OAAOH;EACPI,UAAUC;EACVC,eAAeR,KAAKC,KAAmB,oBAAIQ,IAAAA,CAAAA;EAC3CC,cAAc,MAAA;EAAO;EACrBC,iBAAiB,MAAA;EAAO;AAC1B;AAEA,IAAM,CAACC,qBAAqBC,aAAAA,IAAiBjB,kBAAoCD,WAAWQ,mBAAAA;AAE5F,IAAMW,eAAejB,gBAAAA;AAWrB,IAAMkB,sBAAsBC,8BAAwC;EAClEC,WAAW,MAAA;EAAO;AACpB,CAAA;AAMA,IAAMC,mBAAmB;AAEzB,IAAMC,gBAAgB,CAACd,UACrB;KAAIA;EAAOe,KAAK,CAACC,GAAGC,MAAAA;AAClB,MAAID,EAAEE,aAAaD,EAAEC,UAAU;AAC7B,WAAOF,EAAEE,WAAWD,EAAEC;EACxB;AACA,SAAOF,EAAEG,GAAGC,cAAcH,EAAEE,EAAE;AAChC,CAAA;AAIF,IAAME,eAAe,CAAC,EACpBC,UACAtB,QAAQF,oBAAoBE,OAC5BD,WAAWD,oBAAoBC,UAC/BwB,cACAC,cACAvB,SAAQ,MACU;AAClB,QAAM,EAAEwB,MAAK,IAAKhB,aAAaP,MAAAA;AAC/B,QAAMwB,WAAWC,WAAWC,eAAAA;AAC5B,QAAMzB,gBAAgB0B,QAAQ,MAAMlC,KAAKC,KAAmB,oBAAIQ,IAAAA,CAAAA,EAAO0B,KAAKnC,KAAKoC,SAAS,GAAG,CAAA,CAAE;AAE/F,QAAM1B,eAAe2B,aACnB,CAACC,UAAAA;AACC,UAAMf,WAAWe,MAAMf,YAAYL;AACnC,UAAMqB,OAAOR,SAASS,IAAIhC,aAAAA;AAC1B,UAAMiC,OAAO,IAAIhC,IAAI8B,IAAAA;AACrBE,SAAKC,IAAIJ,MAAMd,IAAI;MAAE,GAAGc;MAAOf;IAAS,CAAA;AACxCQ,aAASW,IAAIlC,eAAeiC,IAAAA;EAC9B,GACA;IAACV;IAAUvB;GAAc;AAG3B,QAAMG,kBAAkB0B,aACtB,CAACb,OAAAA;AACC,UAAMe,OAAOR,SAASS,IAAIhC,aAAAA;AAC1B,UAAMiC,OAAO,IAAIhC,IAAI8B,IAAAA;AACrBE,SAAKE,OAAOnB,EAAAA;AACZO,aAASW,IAAIlC,eAAeiC,IAAAA;EAC9B,GACA;IAACV;IAAUvB;GAAc;AAG3B,SACE,gBAAAoC,OAAA,cAAChC,qBAAAA;IACCP;IACAD;IACAwB;IACAC;IACArB;IACAE;IACAC;IACAL;IACAwB;KAECH,QAAAA;AAGP;AAMA,IAAMkB,eAAe,CACnBC,WACAC,OACAC,YAAAA;AAEA,QAAMC,aAAa;OAAID,QAAQE,OAAM;IAAIC,OAAO,CAACC,UAAU,CAACA,MAAMC,eAAeD,MAAMC,YAAYN,KAAAA,CAAAA;AACnG,MAAIE,WAAWK,WAAW,GAAG;AAC3B,WAAOR;EACT;AAEA,QAAMS,SAASpC,cAAc8B,UAAAA;AAE7B,QAAMO,eAAeD,OAAOJ,OAAO,CAACC,UAAUA,MAAMK,SAAS,aAAA;AAC7D,MAAID,aAAaF,SAAS,GAAG;AAC3B,QAAIE,aAAaF,SAAS,GAAG;AAC3BI,UAAIC,KAAK,sCAAsC;QAC7CC,KAAKJ,aAAaK,IAAI,CAACC,MAAMA,EAAEtC,EAAE,EAAEuC,KAAK,IAAA;QACxCC,OAAOR,aAAa,CAAA,EAAGhC;MACzB,GAAA;;;;;;IACF;AACA,WAAOgC,aAAa,CAAA,EAAGnD;EACzB;AAEA,QAAM4D,WAAWV,OAAOJ,OAAO,CAACC,UAAUA,MAAMK,SAAS,UAAA;AACzD,QAAMS,gBAAgBD,SAASE,QAAQ,CAACf,UAAUA,MAAM/C,KAAK;AAE7D,MAAI,CAACyC,aAAaA,UAAUQ,WAAW,GAAG;AACxC,WAAOY,cAAcZ,SAAS,IAAIY,gBAAgB;EACpD;AAEA,SAAO;OAAIpB;OAAcoB;;AAC3B;AAMA,IAAME,eAAe,CACnBrB,OACAsB,YACAC,eAAuB,uBACvBC,gBAAAA;AAEA,QAAM,EAAElE,OAAOG,cAAa,IAAKK,cAAcyD,cAAcC,WAAAA;AAC7D,QAAMC,aAAaC,aAAapE,MAAM0C,KAAAA,CAAAA;AACtC,QAAMC,UAAUyB,aAAajE,aAAAA,KAAkB,oBAAIC,IAAAA;AAEnD,QAAMqC,YAAYZ,QAAQ,MAAMmC,cAAcG,cAAc,MAAM;IAACH;IAAYG;GAAW;AAE1F,QAAME,WAAWxC,QACf,MAAMW,aAAaC,WAAWC,OAAOC,OAAAA,GACrC;IAACF;IAAWC;IAAOC;GAAQ;AAG7B,SAAO0B,YAAYnE;AACrB;AAGA,IAAMoE,UAAU,CAACL,iBAAAA;AACf,SAAOzD,cAAcyD,cAAc/D,MAAAA;AACrC;AAoBA,IAAMqE,WAAW,CAAC,EAAEjD,UAAUkD,MAAMC,aAAaC,cAAcC,QAAQ,GAAG1C,MAAAA,MAAsB;AAC9F,QAAM,CAAC2C,UAAUC,WAAAA,IAAeC,sBAAqB;IACnDC,MAAMP;IACNQ,aAAaP;IACbQ,UAAUP;EACZ,CAAA;AAEA,QAAM9D,YAAYoB,aAAY,MAAM6C,YAAY,KAAA,GAAQ;IAACA;GAAY;AAErE,SACE,gBAAAtC,OAAA,cAAClB,cAAiBY,OAChB,gBAAAM,OAAA,cAAC7B,oBAAoBwE,UAAQ;IAACC,OAAO;MAAEvE;MAAW+D;IAAO;KACvD,gBAAApC,OAAA,cAAC6C,qBAAoBC,MAAI;IAACb,MAAMI;IAAUF,cAAcG;KACrDvD,QAAAA,CAAAA,CAAAA;AAKX;AAYA,IAAMgE,kBAAkB,CAAC,EACvBC,MACAC,SACAtB,YAAW,MAIX;AACA,QAAMuB,SAASF;AACf,QAAMG,cAAc1D,aAAY,CAAC2D,UAAsBH,QAAQC,QAAQE,KAAAA,GAAQ;IAACF;IAAQD;GAAQ;AAChG,QAAM,EAAEzF,SAAQ,IAAKS,cAAc,mBAAmB0D,WAAAA;AACtD,SACE,gBAAA3B,OAAA,cAAC6C,qBAAoBQ,MAAI;IACvBJ,SAASE;IACTG,YAAW;IACXC,UAAUL,OAAOM,YAAYD;IAC5B,GAAIL,OAAOM,YAAYC,UAAU;MAAE,eAAeP,OAAOM,WAAWC;IAAO;KAE3EP,OAAOM,YAAYE,QAAQ,gBAAA1D,OAAA,cAAC2D,OAAAA;IAAKD,MAAMR,OAAOM,WAAYE;IAAME,MAAMpG;MACvE,gBAAAwC,OAAA,cAAC6D,aAAAA;IAAYX;;AAGnB;AAQA,IAAMY,cAAc,CAAC,EACnB3D,OACA1C,OAAOgE,YACPW,QAAQ2B,gBACRpC,YAAW,MACuB;AAClC,QAAM,EAAEtD,WAAW+D,QAAQ4B,cAAa,IAAK5E,WAAWjB,mBAAAA;AACxD,QAAMiE,SAAS2B,kBAAkBC;AACjC,QAAM,EAAEtG,SAAQ,IAAKO,cAAc,eAAe0D,WAAAA;AAClD,QAAMsC,gBAAgBzC,aAAarB,OAAOsB,YAAY,eAAeE,WAAAA;AAErE,QAAMuC,oBAAoBzE,aACxB,CAACyD,QAAoBE,UAAAA;AACnB,QAAIF,OAAOM,YAAYD,UAAU;AAC/B;IACF;AACAH,UAAMe,gBAAe;AACrB9F,cAAAA;AACA,QAAIX,UAAU;AACZA,eAASwF,QAAQ;QAAEkB,QAAQjE;QAAOiC;MAAO,CAAA;IAC3C,OAAO;AACL,WAAKiC,kBAAkBnB,QAAQ;QAAEkB,QAAQjE;QAAOiC;MAAO,CAAA;IACzD;EACF,GACA;IAACjC;IAAOiC;IAAQ1E;IAAUW;GAAU;AAGtC,SACE,gBAAA2B,OAAA,cAAC6C,qBAAoByB,QAAM,MACzB,gBAAAtE,OAAA,cAAC6C,qBAAoB0B,SAAO,MAC1B,gBAAAvE,OAAA,cAAC6C,qBAAoB2B,UAAQ,MAC1BP,eAAehD,IAAI,CAAC+B,SACnB,gBAAAhD,OAAA,cAAC+C,iBAAAA;IAAgB0B,KAAKzB,KAAKpE;IAAIoE;IAAYC,SAASiB;QAGxD,gBAAAlE,OAAA,cAAC6C,qBAAoB6B,OAAK,IAAA,CAAA,CAAA;AAIlC;AAcA,IAAMC,OAAO;EACX7B,MAAMd;EACN4C,SAAS/B,qBAAoB+B;EAC7BL,SAAST;EACTe,gBAAgBhC,qBAAoBgC;EACpCC,SAASC;AACX;;;AO1UA,SAAoBC,mBAAAA,kBAAiBC,gBAAAA,qBAAoB;AACzD,SAASC,eAAAA,cAAaC,cAAAA,aAAYC,WAAAA,gBAAe;AAEjD,SAASC,OAAOC,QAAAA,aAAY;AAerB,IAAMC,iBAAiB,CAACC,UAAAA;AAC7B,QAAMC,WAAWC,YAAWC,gBAAAA;AAC5B,QAAMC,iBAAiBC,cAAaL,KAAAA;AAMpC,QAAMM,QAAQC,SAAQ,MAAA;AACpB,UAAMC,WAAWC,MAAMC,KAAK;MAAET;IAAS,CAAA;AACvCO,aAASG,KAAKF,MAAMG,SAASR,eAAeS,KAAK,GAA0BJ,MAAMK,SAASV,eAAeW,KAAK,CAAA;AAC9G,WAAOP;EACT,GAAG;IAACP;IAAUG;GAAe;AAE7B,QAAMY,QAA2BC,aAC/B,CAACC,UAAAA;AAEC,WAAOZ,MAAMa,YAAYD,OAAOE,MAAMC,MAAKC,QAAQ,OAAA;EACrD,GACA;IAAChB;GAAM;AAGT,SAAO;IAAEU;EAAM;AACjB;;;ACzCA,SAASO,iBAAiB;;AA+C1B,IAAMC,kBAAN,MAAMA,iBAAAA;;;EACIC,kBAAkB;EAE1B,YACmBC,OACAC,SACjB;SAFiBD,QAAAA;SACAC,UAAAA;EAChB;EAEHC,KAAKC,OAAsC;AACzCC,cAAU,KAAKH,YAAY,QAAQ,2CAAA;;;;;;;;;AACnCG,cAAU,KAAKJ,MAAMK,MAAMC,KAAK,CAACC,SAASA,KAAKC,OAAO,MAAA,MAAYC,QAAW,uCAAA;;;;;;;;;AAC7E,SAAKT,MAAMK,MAAMK,KAAKC,oBAAoB,QAAQR,KAAAA,CAAAA;AAClD,WAAO;EACT;EAEAS,QAA0B;AACxB,WAAO,KAAKZ;EACd;EAEAa,OAA0BL,IAAYL,OAAiCW,QAA0B;AAC/F,SAAKd,MAAMK,MAAMK,KAAKK,iBAAiBP,IAAIM,QAAQX,KAAAA,CAAAA;AACnD,SAAKH,MAAMgB,MAAMN,KAAK;MAAEO,QAAQ,KAAKhB;MAASiB,QAAQV;MAAIW,UAAU;IAAQ,CAAA;AAC5E,WAAO;EACT;EAEAC,MAAyBZ,IAAYL,OAAoCkB,IAAgC;AACvG,SAAKrB,MAAMK,MAAMK,KAAKC,oBAAoBH,IAAIL,KAAAA,CAAAA;AAC9C,SAAKH,MAAMgB,MAAMN,KAAK;MAAEO,QAAQ,KAAKhB;MAASiB,QAAQV;MAAIW,UAAU;IAAQ,CAAA;AAC5EE,OAAG,IAAIvB,iBAAgB,KAAKE,OAAOQ,EAAAA,CAAAA;AACnC,WAAO;EACT;EAEAc,SAASC,cAAwF;AAC/F,QAAI,CAACA,cAAc;AACjB,aAAO;IACT;AACA,QAAI,OAAOA,iBAAiB,YAAY;AACtCA,mBAAa,IAAIzB,iBAAgB,KAAKE,OAAO,KAAKC,OAAO,CAAA;IAC3D,OAAO;AACL,WAAKD,MAAMK,MAAMK,KAAI,GAAIa,aAAalB,KAAK;AAC3C,WAAKL,MAAMgB,MAAMN,KAAI,GAAIa,aAAaP,KAAK;IAC7C;AACA,WAAO;EACT;EAEAQ,UAAUC,UAA0B,OAAa;AAC/C,UAAMjB,KAAK,aAAa,EAAE,KAAKT,eAAe;AAC9C,SAAKC,MAAMK,MAAMK,KAAK;MACpBF;MACAkB,MAAMC;MACNC,YAAY;QAAEH;MAAQ;MACtBI,MAAMpB;IACR,CAAA;AACA,SAAKT,MAAMgB,MAAMN,KAAK;MAAEO,QAAQ,KAAKhB;MAASiB,QAAQV;MAAIW,UAAU;IAAQ,CAAA;AAC5E,WAAO;EACT;AACF;AAEO,IAAMW,cAAcC,OAAOC,OAAO;EACvCC,MAAM,MAAmB,IAAInC,gBAAgB;IAAEO,OAAO,CAAA;IAAIW,OAAO,CAAA;EAAG,GAAG,MAAA;AACzE,CAAA;",
|
|
6
|
+
"names": ["Atom", "RegistryContext", "useAtomValue", "createContextScope", "useControllableState", "React", "createContext", "useCallback", "useContext", "useMemo", "log", "Icon", "DropdownMenu", "NaturalDropdownMenu", "Effect", "Node", "runAndForwardErrors", "getHostPlatform", "executeMenuAction", "action", "params", "effect", "data", "_actionContext", "pipe", "provide", "runAndForwardErrors", "getShortcut", "properties", "keyBinding", "getHostPlatform", "createMenuAction", "id", "invoke", "properties", "type", "Node", "ActionType", "data", "sync", "createMenuItemGroup", "ActionGroupType", "actionGroupSymbol", "createGapSeparator", "source", "nodes", "variant", "undefined", "edges", "target", "relation", "createLineSeparator", "React", "keySymbols", "toLocalizedString", "useTranslation", "mx", "translationKey", "translations", "ActionLabel", "action", "t", "useTranslation", "translationKey", "shortcut", "getShortcut", "span", "className", "toLocalizedString", "properties", "label", "mx", "keySymbols", "join", "actionLabel", "React", "useCallback", "Icon", "Toolbar", "NaturalToolbar", "useTranslation", "useAttention", "composable", "composableProps", "Node", "MenuSeparatorType", "isSeparator", "node", "type", "isMenuGroup", "Node", "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", "properties", "buttonVariant", "variant", "handleClick", "useCallback", "executeMenuAction", "commonProps", "onClick", "React", "NaturalToolbar", "IconButton", "key", "id", "size", "label", "actionLabel", "Button", "ActionLabel", "DropdownMenuToolbarItem", "group", "items", "propsItems", "useMenuItems", "activeItem", "find", "item", "checked", "applyActive", "Root", "labelAction", "rootProps", "caretDown", "children", "Icon", "DropdownMenu", "Trigger", "asChild", "ToggleGroupItem", "parent", "value", "ToggleGroupIconItem", "ToggleGroupToolbarItem", "itemsProp", "selectCardinality", "map", "ToggleGroup", "type", "ToolbarMenu", "composable", "props", "forwardedRef", "undefined", "attendableId", "alwaysActive", "hasAttention", "useAttention", "composableProps", "ref", "ToolbarMenuItem", "isSeparator", "Separator", "isMenuGroup", "MENU_NAME", "createMenuContext", "createMenuScope", "createContextScope", "nullItemsAtom", "Atom", "make", "defaultItemsAccessor", "menuContextDefaults", "iconSize", "items", "onAction", "undefined", "menuItemsAtom", "Map", "addMenuItems", "removeMenuItems", "MenuContextProvider", "useMenuScoped", "useMenuScope", "MenuDropdownContext", "createContext", "closeMenu", "DEFAULT_PRIORITY", "sortMenuItems", "sort", "a", "b", "priority", "id", "localeCompare", "MenuProvider", "children", "attendableId", "alwaysActive", "scope", "registry", "useContext", "RegistryContext", "useMemo", "pipe", "keepAlive", "useCallback", "props", "prev", "get", "next", "set", "delete", "React", "resolveItems", "baseItems", "group", "entries", "applicable", "values", "filter", "entry", "groupFilter", "length", "sorted", "replacements", "mode", "log", "warn", "ids", "map", "r", "join", "using", "additive", "additiveItems", "flatMap", "useMenuItems", "propsItems", "consumerName", "__menuScope", "groupItems", "useAtomValue", "resolved", "useMenu", "MenuRoot", "open", "defaultOpen", "onOpenChange", "caller", "menuOpen", "setMenuOpen", "useControllableState", "prop", "defaultProp", "onChange", "Provider", "value", "NaturalDropdownMenu", "Root", "MenuContentItem", "item", "onClick", "action", "handleClick", "event", "Item", "classNames", "disabled", "properties", "testId", "icon", "Icon", "size", "ActionLabel", "MenuContent", "callerOverride", "contextCaller", "resolvedItems", "handleActionClick", "stopPropagation", "parent", "executeMenuAction", "Portal", "Content", "Viewport", "key", "Arrow", "Menu", "Trigger", "VirtualTrigger", "Toolbar", "ToolbarMenu", "RegistryContext", "useAtomValue", "useCallback", "useContext", "useMemo", "Graph", "Node", "useMenuActions", "props", "registry", "useContext", "RegistryContext", "menuGraphProps", "useAtomValue", "graph", "useMemo", "newGraph", "Graph", "make", "pipe", "addNodes", "nodes", "addEdges", "edges", "items", "useCallback", "group", "connections", "id", "Node", "RootId", "invariant", "MenuBuilderImpl", "_separatorCount", "_data", "_rootId", "root", "props", "invariant", "nodes", "find", "node", "id", "undefined", "push", "createMenuItemGroup", "build", "action", "invoke", "createMenuAction", "edges", "source", "target", "relation", "group", "cb", "subgraph", "subgraphOrCb", "separator", "variant", "type", "MenuSeparatorType", "properties", "data", "MenuBuilder", "Object", "freeze", "make"]
|
|
7
7
|
}
|