@dxos/react-ui-menu 0.8.3-staging.0fa589b → 0.8.4-main.03d5cd7b56
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 +566 -371
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +14 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +566 -371
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +16 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/builder.d.ts +39 -0
- package/dist/types/src/builder.d.ts.map +1 -0
- 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/ActionLabel.d.ts +3 -3
- package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
- package/dist/types/src/components/DropdownMenu.d.ts +4 -2
- package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +50 -0
- package/dist/types/src/components/Menu.d.ts.map +1 -0
- package/dist/types/src/components/Menu.stories.d.ts +21 -0
- package/dist/types/src/components/Menu.stories.d.ts.map +1 -0
- package/dist/types/src/components/Menu.test.d.ts +2 -0
- package/dist/types/src/components/Menu.test.d.ts.map +1 -0
- package/dist/types/src/components/ToolbarMenu.d.ts +7 -6
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +22 -0
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useMenuActions.d.ts +8 -7
- 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 +20 -14
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +38 -27
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +14 -5
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +45 -31
- package/src/builder.test.ts +224 -0
- package/src/builder.ts +112 -0
- package/src/components/ActionLabel.tsx +9 -9
- package/src/components/DropdownMenu.tsx +17 -8
- package/src/components/Menu.stories.tsx +266 -0
- package/src/components/Menu.test.tsx +447 -0
- package/src/components/Menu.tsx +348 -0
- package/src/components/ToolbarMenu.stories.tsx +83 -0
- package/src/components/ToolbarMenu.tsx +159 -99
- package/src/components/index.ts +1 -3
- package/src/hooks/useMenuActions.ts +30 -53
- package/src/index.ts +1 -2
- package/src/testing/generator.ts +74 -64
- package/src/translations.ts +5 -3
- package/src/types.ts +39 -27
- package/src/util.ts +34 -15
- package/dist/lib/node/index.cjs +0 -506
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/types/src/components/MenuContext.d.ts +0 -13
- package/dist/types/src/components/MenuContext.d.ts.map +0 -1
- package/dist/types/src/components/Menus.stories.d.ts +0 -25
- package/dist/types/src/components/Menus.stories.d.ts.map +0 -1
- package/src/components/MenuContext.tsx +0 -50
- package/src/components/Menus.stories.tsx +0 -67
package/src/types.ts
CHANGED
|
@@ -2,51 +2,63 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
6
|
-
import { type ToolbarSeparatorProps, type Label, type IconButtonProps, type ClassNameValue } from '@dxos/react-ui';
|
|
7
|
-
|
|
8
|
-
export type MenuActionProperties = {
|
|
9
|
-
label: Label;
|
|
10
|
-
icon?: string;
|
|
11
|
-
value?: string;
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
hidden?: boolean;
|
|
14
|
-
iconOnly?: boolean;
|
|
15
|
-
testId?: string;
|
|
16
|
-
variant?: 'action' | 'toggle';
|
|
17
|
-
checked?: boolean;
|
|
18
|
-
classNames?: ClassNameValue;
|
|
19
|
-
};
|
|
5
|
+
import { type Atom } from '@effect-atom/atom-react';
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
iconOnly?: boolean;
|
|
25
|
-
};
|
|
7
|
+
import { Node } from '@dxos/app-graph';
|
|
8
|
+
import { type IconButtonProps, type ToolbarSeparatorProps } from '@dxos/react-ui';
|
|
9
|
+
import { type MenuActionProperties } from '@dxos/ui-types';
|
|
26
10
|
|
|
27
|
-
export type MenuAction<P extends {} = {}> = Action<P & MenuActionProperties>;
|
|
11
|
+
export type MenuAction<P extends {} = {}> = Node.Action<P & MenuActionProperties>;
|
|
28
12
|
|
|
29
13
|
export const MenuSeparatorType = '@dxos/react-ui-toolbar/separator' as const;
|
|
30
14
|
|
|
31
|
-
export type MenuSeparator = Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {
|
|
15
|
+
export type MenuSeparator = Node.Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {
|
|
32
16
|
type: typeof MenuSeparatorType;
|
|
33
17
|
};
|
|
34
18
|
|
|
35
|
-
export const isSeparator = (node: Node): node is MenuSeparator => node.type === MenuSeparatorType;
|
|
19
|
+
export const isSeparator = (node: Node.Node): node is MenuSeparator => node.type === MenuSeparatorType;
|
|
36
20
|
|
|
37
21
|
export type MenuSingleSelectActionGroup = { selectCardinality: 'single'; value: string };
|
|
38
22
|
export type MenuMultipleSelectActionGroup = { selectCardinality: 'multiple'; value: string[] };
|
|
39
23
|
|
|
40
|
-
export type MenuItemGroup<P extends Record<string, any> = Record<string, any>> = ActionGroup<P>;
|
|
24
|
+
export type MenuItemGroup<P extends Record<string, any> = Record<string, any>> = Node.ActionGroup<P>;
|
|
41
25
|
|
|
42
|
-
export const isMenuGroup = (node: Node): node is MenuItemGroup => node.type ===
|
|
26
|
+
export const isMenuGroup = (node: Node.Node): node is MenuItemGroup => node.type === Node.ActionGroupType;
|
|
43
27
|
|
|
44
28
|
export type MenuItem = MenuSeparator | MenuAction | MenuItemGroup;
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
/** Atom-family-style accessor: returns an atom of items for a given group (or root when undefined). */
|
|
31
|
+
export type MenuItemsAccessor = (group?: MenuItemGroup) => Atom.Atom<MenuItem[] | null>;
|
|
32
|
+
|
|
33
|
+
export type ActionExecutor = (action: MenuAction, params: Node.InvokeProps) => void;
|
|
34
|
+
|
|
35
|
+
export type MenuItemsMode = 'additive' | 'replacement';
|
|
36
|
+
|
|
37
|
+
export type AddMenuItemsProps = {
|
|
38
|
+
id: string;
|
|
39
|
+
mode: MenuItemsMode;
|
|
40
|
+
priority?: number;
|
|
41
|
+
items: MenuItem[];
|
|
42
|
+
groupFilter?: (group?: MenuItemGroup) => boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type MenuItems = Omit<AddMenuItemsProps, 'priority'> & { priority: number };
|
|
46
|
+
export type MenuItemsMap = Map<string, MenuItems>;
|
|
47
47
|
|
|
48
48
|
export type MenuContextValue = {
|
|
49
|
-
|
|
49
|
+
/** Atom-family accessor for base menu items, keyed by group (similar to Tree model). */
|
|
50
|
+
items: MenuItemsAccessor;
|
|
50
51
|
iconSize: IconButtonProps['size'];
|
|
51
52
|
attendableId?: string;
|
|
53
|
+
/** TODO(burdon): Remove and assume always active if attendableId is undefined. */
|
|
54
|
+
/** If true, the menu is always active regardless of attention state. */
|
|
55
|
+
alwaysActive?: boolean;
|
|
56
|
+
/** Atom holding the current set of imperatively added menu items. */
|
|
57
|
+
menuItemsAtom: Atom.Atom<MenuItemsMap>;
|
|
58
|
+
/** Imperatively add menu items to the nearest MenuProvider. */
|
|
59
|
+
addMenuItems: (props: AddMenuItemsProps) => void;
|
|
60
|
+
/** Remove previously added menu items by id. */
|
|
61
|
+
removeMenuItems: (id: string) => void;
|
|
62
|
+
/** Optional action executor. If provided, will be used instead of default execution. */
|
|
63
|
+
onAction?: ActionExecutor;
|
|
52
64
|
};
|
package/src/util.ts
CHANGED
|
@@ -2,18 +2,31 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Node } from '@dxos/app-graph';
|
|
8
|
+
import { runAndForwardErrors } from '@dxos/effect';
|
|
9
|
+
import { type MenuActionProperties, type MenuItemGroupProperties } from '@dxos/ui-types';
|
|
6
10
|
import { getHostPlatform } from '@dxos/util';
|
|
7
11
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
12
|
+
import { type MenuAction, type MenuItemGroup, type MenuSeparator } from './types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Execute a menu action's Effect with its captured context.
|
|
16
|
+
* This provides the `_actionContext` layer if available.
|
|
17
|
+
*/
|
|
18
|
+
export const executeMenuAction = async (action: MenuAction, params: Node.InvokeProps = {}): Promise<void> => {
|
|
19
|
+
let effect = action.data(params);
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
// Provide captured action context if available.
|
|
22
|
+
if (action._actionContext) {
|
|
23
|
+
effect = effect.pipe(Effect.provide(action._actionContext));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await runAndForwardErrors(effect);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const getShortcut = (action: Node.ActionLike) => {
|
|
17
30
|
return typeof action.properties?.keyBinding === 'string'
|
|
18
31
|
? action.properties.keyBinding
|
|
19
32
|
: action.properties?.keyBinding?.[getHostPlatform()];
|
|
@@ -28,9 +41,9 @@ export const createMenuAction = <P extends {} = {}>(
|
|
|
28
41
|
) =>
|
|
29
42
|
({
|
|
30
43
|
id,
|
|
31
|
-
type:
|
|
44
|
+
type: Node.ActionType,
|
|
32
45
|
properties,
|
|
33
|
-
data: invoke,
|
|
46
|
+
data: () => Effect.sync(invoke),
|
|
34
47
|
}) satisfies MenuAction;
|
|
35
48
|
|
|
36
49
|
export const createMenuItemGroup = <
|
|
@@ -41,9 +54,9 @@ export const createMenuItemGroup = <
|
|
|
41
54
|
) =>
|
|
42
55
|
({
|
|
43
56
|
id,
|
|
44
|
-
type:
|
|
57
|
+
type: Node.ActionGroupType,
|
|
45
58
|
properties,
|
|
46
|
-
data: actionGroupSymbol,
|
|
59
|
+
data: Node.actionGroupSymbol,
|
|
47
60
|
}) satisfies MenuItemGroup;
|
|
48
61
|
|
|
49
62
|
export const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({
|
|
@@ -55,7 +68,13 @@ export const createGapSeparator = (id: string = 'gap', source: string = 'root')
|
|
|
55
68
|
data: undefined as never,
|
|
56
69
|
} satisfies MenuSeparator,
|
|
57
70
|
],
|
|
58
|
-
edges: [
|
|
71
|
+
edges: [
|
|
72
|
+
{
|
|
73
|
+
source,
|
|
74
|
+
target: id,
|
|
75
|
+
relation: 'child' as const,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
59
78
|
});
|
|
60
79
|
|
|
61
80
|
export const createLineSeparator = (id: string = 'line', source: string = 'root') => ({
|
|
@@ -67,5 +86,5 @@ export const createLineSeparator = (id: string = 'line', source: string = 'root'
|
|
|
67
86
|
data: undefined as never,
|
|
68
87
|
} satisfies MenuSeparator,
|
|
69
88
|
],
|
|
70
|
-
edges: [{ source, target: id }],
|
|
89
|
+
edges: [{ source, target: id, relation: 'child' as const }],
|
|
71
90
|
});
|
package/dist/lib/node/index.cjs
DELETED
|
@@ -1,506 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var node_exports = {};
|
|
30
|
-
__export(node_exports, {
|
|
31
|
-
DropdownMenu: () => DropdownMenu,
|
|
32
|
-
MenuProvider: () => MenuProvider,
|
|
33
|
-
MenuSeparatorType: () => MenuSeparatorType,
|
|
34
|
-
ToolbarMenu: () => ToolbarMenu,
|
|
35
|
-
createGapSeparator: () => createGapSeparator,
|
|
36
|
-
createLineSeparator: () => createLineSeparator,
|
|
37
|
-
createMenuAction: () => createMenuAction,
|
|
38
|
-
createMenuItemGroup: () => createMenuItemGroup,
|
|
39
|
-
createMenuScope: () => createMenuScope,
|
|
40
|
-
isMenuGroup: () => isMenuGroup,
|
|
41
|
-
isSeparator: () => isSeparator,
|
|
42
|
-
menuContextDefaults: () => menuContextDefaults,
|
|
43
|
-
rxFromSignal: () => import_app_graph.rxFromSignal,
|
|
44
|
-
useMenu: () => useMenu,
|
|
45
|
-
useMenuActions: () => useMenuActions,
|
|
46
|
-
useMenuItems: () => useMenuItems
|
|
47
|
-
});
|
|
48
|
-
module.exports = __toCommonJS(node_exports);
|
|
49
|
-
var import_app_graph = require("@dxos/app-graph");
|
|
50
|
-
var import_tracking = require("@preact-signals/safe-react/tracking");
|
|
51
|
-
var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state");
|
|
52
|
-
var import_react = __toESM(require("react"));
|
|
53
|
-
var import_react_ui = require("@dxos/react-ui");
|
|
54
|
-
var import_tracking2 = require("@preact-signals/safe-react/tracking");
|
|
55
|
-
var import_react2 = __toESM(require("react"));
|
|
56
|
-
var import_keyboard = require("@dxos/keyboard");
|
|
57
|
-
var import_react_ui2 = require("@dxos/react-ui");
|
|
58
|
-
var import_react_ui_theme = require("@dxos/react-ui-theme");
|
|
59
|
-
var import_app_graph2 = require("@dxos/app-graph");
|
|
60
|
-
var import_util = require("@dxos/util");
|
|
61
|
-
var import_tracking3 = require("@preact-signals/safe-react/tracking");
|
|
62
|
-
var import_react_context = require("@radix-ui/react-context");
|
|
63
|
-
var import_react3 = __toESM(require("react"));
|
|
64
|
-
var import_tracking4 = require("@preact-signals/safe-react/tracking");
|
|
65
|
-
var import_react4 = __toESM(require("react"));
|
|
66
|
-
var import_react_ui3 = require("@dxos/react-ui");
|
|
67
|
-
var import_react_ui_attention = require("@dxos/react-ui-attention");
|
|
68
|
-
var import_react_ui_theme2 = require("@dxos/react-ui-theme");
|
|
69
|
-
var import_app_graph3 = require("@dxos/app-graph");
|
|
70
|
-
var import_rx_react = require("@effect-rx/rx-react");
|
|
71
|
-
var import_react5 = require("react");
|
|
72
|
-
var import_app_graph4 = require("@dxos/app-graph");
|
|
73
|
-
var translationKey = "menus";
|
|
74
|
-
var translations_default = [
|
|
75
|
-
{
|
|
76
|
-
"en-US": {
|
|
77
|
-
[translationKey]: {}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
];
|
|
81
|
-
var getShortcut = (action) => {
|
|
82
|
-
return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[(0, import_util.getHostPlatform)()];
|
|
83
|
-
};
|
|
84
|
-
var createMenuAction = (id, invoke, properties) => ({
|
|
85
|
-
id,
|
|
86
|
-
type: import_app_graph2.ACTION_TYPE,
|
|
87
|
-
properties,
|
|
88
|
-
data: invoke
|
|
89
|
-
});
|
|
90
|
-
var createMenuItemGroup = (id, properties) => ({
|
|
91
|
-
id,
|
|
92
|
-
type: import_app_graph2.ACTION_GROUP_TYPE,
|
|
93
|
-
properties,
|
|
94
|
-
data: import_app_graph2.actionGroupSymbol
|
|
95
|
-
});
|
|
96
|
-
var createGapSeparator = (id = "gap", source = "root") => ({
|
|
97
|
-
nodes: [
|
|
98
|
-
{
|
|
99
|
-
id,
|
|
100
|
-
type: "@dxos/react-ui-toolbar/separator",
|
|
101
|
-
properties: {
|
|
102
|
-
variant: "gap"
|
|
103
|
-
},
|
|
104
|
-
data: void 0
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
edges: [
|
|
108
|
-
{
|
|
109
|
-
source,
|
|
110
|
-
target: id
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
});
|
|
114
|
-
var createLineSeparator = (id = "line", source = "root") => ({
|
|
115
|
-
nodes: [
|
|
116
|
-
{
|
|
117
|
-
id,
|
|
118
|
-
type: "@dxos/react-ui-toolbar/separator",
|
|
119
|
-
properties: {
|
|
120
|
-
variant: "line"
|
|
121
|
-
},
|
|
122
|
-
data: void 0
|
|
123
|
-
}
|
|
124
|
-
],
|
|
125
|
-
edges: [
|
|
126
|
-
{
|
|
127
|
-
source,
|
|
128
|
-
target: id
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
});
|
|
132
|
-
var ActionLabel = ({ action }) => {
|
|
133
|
-
var _effect = (0, import_tracking2.useSignals)();
|
|
134
|
-
try {
|
|
135
|
-
const shortcut = getShortcut(action);
|
|
136
|
-
const { t } = (0, import_react_ui2.useTranslation)(translationKey);
|
|
137
|
-
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("span", {
|
|
138
|
-
className: "grow truncate"
|
|
139
|
-
}, (0, import_react_ui2.toLocalizedString)(action.properties.label, t)), shortcut && /* @__PURE__ */ import_react2.default.createElement("span", {
|
|
140
|
-
className: (0, import_react_ui_theme.mx)("shrink-0", import_react_ui_theme.descriptionText)
|
|
141
|
-
}, (0, import_keyboard.keySymbols)(shortcut).join("")));
|
|
142
|
-
} finally {
|
|
143
|
-
_effect.f();
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
var actionLabel = (action, t) => {
|
|
147
|
-
const shortcut = getShortcut(action);
|
|
148
|
-
return `${(0, import_react_ui2.toLocalizedString)(action.properties.label, t)}${shortcut ? ` (${(0, import_keyboard.keySymbols)(shortcut).join("")})` : ""}`;
|
|
149
|
-
};
|
|
150
|
-
var MENU_NAME = "GraphMenu";
|
|
151
|
-
var [createMenuContext, createMenuScope] = (0, import_react_context.createContextScope)(MENU_NAME, []);
|
|
152
|
-
var [MenuContextProvider, useMenu] = createMenuContext(MENU_NAME);
|
|
153
|
-
var menuContextDefaults = {
|
|
154
|
-
iconSize: 5,
|
|
155
|
-
useGroupItems: () => null
|
|
156
|
-
};
|
|
157
|
-
var useMenuScope = createMenuScope();
|
|
158
|
-
var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
|
|
159
|
-
var _effect = (0, import_tracking3.useSignals)();
|
|
160
|
-
try {
|
|
161
|
-
const { scope } = useMenuScope(void 0);
|
|
162
|
-
return /* @__PURE__ */ import_react3.default.createElement(MenuContextProvider, {
|
|
163
|
-
useGroupItems,
|
|
164
|
-
iconSize,
|
|
165
|
-
attendableId,
|
|
166
|
-
scope
|
|
167
|
-
}, children);
|
|
168
|
-
} finally {
|
|
169
|
-
_effect.f();
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
173
|
-
const { useGroupItems } = useMenu(consumerName, __menuScope);
|
|
174
|
-
const groupItems = useGroupItems(group);
|
|
175
|
-
return (0, import_react3.useMemo)(() => propsItems ?? groupItems ?? void 0, [
|
|
176
|
-
propsItems,
|
|
177
|
-
groupItems
|
|
178
|
-
]);
|
|
179
|
-
};
|
|
180
|
-
var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
|
|
181
|
-
var _effect = (0, import_tracking.useSignals)();
|
|
182
|
-
try {
|
|
183
|
-
const action = item;
|
|
184
|
-
const handleClick = (0, import_react.useCallback)((event) => onClick(action, event), [
|
|
185
|
-
action,
|
|
186
|
-
onClick
|
|
187
|
-
]);
|
|
188
|
-
const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
|
|
189
|
-
return /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Item, {
|
|
190
|
-
onClick: handleClick,
|
|
191
|
-
classNames: "gap-2",
|
|
192
|
-
disabled: action.properties?.disabled,
|
|
193
|
-
...action.properties?.testId && {
|
|
194
|
-
"data-testid": action.properties.testId
|
|
195
|
-
}
|
|
196
|
-
}, action.properties?.icon && /* @__PURE__ */ import_react.default.createElement(import_react_ui.Icon, {
|
|
197
|
-
icon: action.properties.icon,
|
|
198
|
-
size: iconSize
|
|
199
|
-
}), /* @__PURE__ */ import_react.default.createElement(ActionLabel, {
|
|
200
|
-
action
|
|
201
|
-
}));
|
|
202
|
-
} finally {
|
|
203
|
-
_effect.f();
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, caller, children, __menuScope, ...naturalProps }) => {
|
|
207
|
-
var _effect = (0, import_tracking.useSignals)();
|
|
208
|
-
try {
|
|
209
|
-
const [optionsMenuOpen, setOptionsMenuOpen] = (0, import_react_use_controllable_state.useControllableState)({
|
|
210
|
-
prop: open,
|
|
211
|
-
defaultProp: defaultOpen,
|
|
212
|
-
onChange: onOpenChange
|
|
213
|
-
});
|
|
214
|
-
const handleActionClick = (0, import_react.useCallback)((action, event) => {
|
|
215
|
-
if (action.properties?.disabled) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
event.stopPropagation();
|
|
219
|
-
setOptionsMenuOpen(false);
|
|
220
|
-
void action.data?.({
|
|
221
|
-
parent: group,
|
|
222
|
-
caller
|
|
223
|
-
});
|
|
224
|
-
}, [
|
|
225
|
-
group,
|
|
226
|
-
caller
|
|
227
|
-
]);
|
|
228
|
-
const items = useMenuItems(group, propsItems);
|
|
229
|
-
return /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Root, {
|
|
230
|
-
open: optionsMenuOpen,
|
|
231
|
-
onOpenChange: setOptionsMenuOpen,
|
|
232
|
-
...naturalProps
|
|
233
|
-
}, children, /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Portal, null, /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Content, null, /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ import_react.default.createElement(DropdownMenuItem, {
|
|
234
|
-
key: item.id,
|
|
235
|
-
item,
|
|
236
|
-
onClick: handleActionClick
|
|
237
|
-
}))), /* @__PURE__ */ import_react.default.createElement(import_react_ui.DropdownMenu.Arrow, null))));
|
|
238
|
-
} finally {
|
|
239
|
-
_effect.f();
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
var DropdownMenu = {
|
|
243
|
-
Root: DropdownMenuRoot,
|
|
244
|
-
Trigger: import_react_ui.DropdownMenu.Trigger,
|
|
245
|
-
VirtualTrigger: import_react_ui.DropdownMenu.VirtualTrigger
|
|
246
|
-
};
|
|
247
|
-
var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
|
|
248
|
-
var isSeparator = (node) => node.type === MenuSeparatorType;
|
|
249
|
-
var isMenuGroup = (node) => node.type === import_app_graph3.ACTION_GROUP_TYPE;
|
|
250
|
-
var ActionToolbarItem = ({ action, __menuScope }) => {
|
|
251
|
-
var _effect = (0, import_tracking4.useSignals)();
|
|
252
|
-
try {
|
|
253
|
-
const { iconSize } = useMenu("ActionToolbarItem", __menuScope);
|
|
254
|
-
const { t } = (0, import_react_ui3.useTranslation)(translationKey);
|
|
255
|
-
const handleClick = (0, import_react4.useCallback)(() => action.data?.(), [
|
|
256
|
-
action
|
|
257
|
-
]);
|
|
258
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
259
|
-
const Root = icon ? import_react_ui3.Toolbar.IconButton : import_react_ui3.Toolbar.Button;
|
|
260
|
-
const rootProps = icon ? {
|
|
261
|
-
icon,
|
|
262
|
-
size: iconSize,
|
|
263
|
-
iconOnly,
|
|
264
|
-
label: actionLabel(action, t)
|
|
265
|
-
} : {
|
|
266
|
-
children: /* @__PURE__ */ import_react4.default.createElement(ActionLabel, {
|
|
267
|
-
action
|
|
268
|
-
})
|
|
269
|
-
};
|
|
270
|
-
return hidden ? null : /* @__PURE__ */ import_react4.default.createElement(Root, {
|
|
271
|
-
key: action.id,
|
|
272
|
-
disabled,
|
|
273
|
-
onClick: handleClick,
|
|
274
|
-
variant: "ghost",
|
|
275
|
-
...testId && {
|
|
276
|
-
"data-testid": testId
|
|
277
|
-
},
|
|
278
|
-
...rootProps,
|
|
279
|
-
classNames
|
|
280
|
-
});
|
|
281
|
-
} finally {
|
|
282
|
-
_effect.f();
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
|
|
286
|
-
var _effect = (0, import_tracking4.useSignals)();
|
|
287
|
-
try {
|
|
288
|
-
const { iconOnly, disabled, testId } = group.properties;
|
|
289
|
-
const { t } = (0, import_react_ui3.useTranslation)(translationKey);
|
|
290
|
-
const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
|
|
291
|
-
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
292
|
-
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
293
|
-
const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
|
|
294
|
-
activeItem?.properties.icon || group.properties.icon;
|
|
295
|
-
const Root = icon ? import_react_ui3.Toolbar.IconButton : import_react_ui3.Toolbar.Button;
|
|
296
|
-
const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
|
|
297
|
-
const rootProps = icon ? {
|
|
298
|
-
icon,
|
|
299
|
-
size: iconSize,
|
|
300
|
-
iconOnly,
|
|
301
|
-
label: actionLabel(labelAction, t),
|
|
302
|
-
caretDown: true
|
|
303
|
-
} : {
|
|
304
|
-
children: /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(ActionLabel, {
|
|
305
|
-
action: labelAction
|
|
306
|
-
}), /* @__PURE__ */ import_react4.default.createElement(import_react_ui3.Icon, {
|
|
307
|
-
size: 3,
|
|
308
|
-
icon: "ph--caret-down--bold",
|
|
309
|
-
classNames: "mis-1"
|
|
310
|
-
}))
|
|
311
|
-
};
|
|
312
|
-
return /* @__PURE__ */ import_react4.default.createElement(DropdownMenu.Root, {
|
|
313
|
-
group,
|
|
314
|
-
items
|
|
315
|
-
}, /* @__PURE__ */ import_react4.default.createElement(DropdownMenu.Trigger, {
|
|
316
|
-
asChild: true
|
|
317
|
-
}, /* @__PURE__ */ import_react4.default.createElement(Root, {
|
|
318
|
-
variant: "ghost",
|
|
319
|
-
disabled,
|
|
320
|
-
...rootProps,
|
|
321
|
-
...testId && {
|
|
322
|
-
"data-testid": testId
|
|
323
|
-
}
|
|
324
|
-
})));
|
|
325
|
-
} finally {
|
|
326
|
-
_effect.f();
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
var ToggleGroupItem = ({ group, action, __menuScope }) => {
|
|
330
|
-
var _effect = (0, import_tracking4.useSignals)();
|
|
331
|
-
try {
|
|
332
|
-
const { iconSize } = useMenu("ToggleGroupItem", __menuScope);
|
|
333
|
-
const { t } = (0, import_react_ui3.useTranslation)(translationKey);
|
|
334
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
335
|
-
const handleClick = (0, import_react4.useCallback)(() => action.data?.({
|
|
336
|
-
parent: group
|
|
337
|
-
}), [
|
|
338
|
-
action,
|
|
339
|
-
group
|
|
340
|
-
]);
|
|
341
|
-
const Root = icon ? import_react_ui3.Toolbar.ToggleGroupIconItem : import_react_ui3.Toolbar.ToggleGroupItem;
|
|
342
|
-
const rootProps = icon ? {
|
|
343
|
-
icon,
|
|
344
|
-
size: iconSize,
|
|
345
|
-
iconOnly,
|
|
346
|
-
label: actionLabel(action, t)
|
|
347
|
-
} : {
|
|
348
|
-
children: /* @__PURE__ */ import_react4.default.createElement(ActionLabel, {
|
|
349
|
-
action
|
|
350
|
-
})
|
|
351
|
-
};
|
|
352
|
-
return hidden ? null : /* @__PURE__ */ import_react4.default.createElement(Root, {
|
|
353
|
-
key: action.id,
|
|
354
|
-
value: action.id,
|
|
355
|
-
disabled,
|
|
356
|
-
onClick: handleClick,
|
|
357
|
-
variant: "ghost",
|
|
358
|
-
...testId && {
|
|
359
|
-
"data-testid": testId
|
|
360
|
-
},
|
|
361
|
-
...rootProps,
|
|
362
|
-
classNames
|
|
363
|
-
});
|
|
364
|
-
} finally {
|
|
365
|
-
_effect.f();
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
|
|
369
|
-
var _effect = (0, import_tracking4.useSignals)();
|
|
370
|
-
try {
|
|
371
|
-
const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
|
|
372
|
-
const { selectCardinality, value } = group.properties;
|
|
373
|
-
return (
|
|
374
|
-
// TODO(thure): The type here is difficult to manage, what do?
|
|
375
|
-
// @ts-ignore
|
|
376
|
-
/* @__PURE__ */ import_react4.default.createElement(
|
|
377
|
-
import_react_ui3.Toolbar.ToggleGroup,
|
|
378
|
-
{
|
|
379
|
-
type: selectCardinality,
|
|
380
|
-
value
|
|
381
|
-
},
|
|
382
|
-
// TODO(thure): Handle other menu item types.
|
|
383
|
-
items.map((action) => /* @__PURE__ */ import_react4.default.createElement(ToggleGroupItem, {
|
|
384
|
-
key: action.id,
|
|
385
|
-
group,
|
|
386
|
-
action
|
|
387
|
-
}))
|
|
388
|
-
)
|
|
389
|
-
);
|
|
390
|
-
} finally {
|
|
391
|
-
_effect.f();
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: wrapContents, ...props }) => {
|
|
395
|
-
var _effect = (0, import_tracking4.useSignals)();
|
|
396
|
-
try {
|
|
397
|
-
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
398
|
-
const { attendableId } = useMenu("ToolbarMenu", __menuScope);
|
|
399
|
-
const { hasAttention } = (0, import_react_ui_attention.useAttention)(attendableId);
|
|
400
|
-
const InnerRoot = wrapContents ? "div" : import_react4.Fragment;
|
|
401
|
-
const innerRootProps = wrapContents ? {
|
|
402
|
-
role: "none",
|
|
403
|
-
className: (0, import_react_ui_theme2.mx)(import_react_ui_theme2.textBlockWidth, import_react_ui_theme2.toolbarLayout)
|
|
404
|
-
} : {};
|
|
405
|
-
return /* @__PURE__ */ import_react4.default.createElement(import_react_ui3.Toolbar.Root, {
|
|
406
|
-
...props,
|
|
407
|
-
layoutManaged: wrapContents,
|
|
408
|
-
classNames: [
|
|
409
|
-
attendableId && !hasAttention && "*:opacity-20 !bg-transparent",
|
|
410
|
-
classNames
|
|
411
|
-
]
|
|
412
|
-
}, /* @__PURE__ */ import_react4.default.createElement(InnerRoot, innerRootProps, items?.map((item, i) => isSeparator(item) ? /* @__PURE__ */ import_react4.default.createElement(import_react_ui3.Toolbar.Separator, {
|
|
413
|
-
key: i,
|
|
414
|
-
variant: item.properties.variant
|
|
415
|
-
}) : isMenuGroup(item) ? item.properties.variant === "dropdownMenu" ? (
|
|
416
|
-
// TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
|
|
417
|
-
/* @__PURE__ */ import_react4.default.createElement(DropdownMenuToolbarItem, {
|
|
418
|
-
key: item.id,
|
|
419
|
-
group: item
|
|
420
|
-
})
|
|
421
|
-
) : (
|
|
422
|
-
// TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
|
|
423
|
-
/* @__PURE__ */ import_react4.default.createElement(ToggleGroupToolbarItem, {
|
|
424
|
-
key: item.id,
|
|
425
|
-
group: item
|
|
426
|
-
})
|
|
427
|
-
) : (
|
|
428
|
-
// TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
|
|
429
|
-
/* @__PURE__ */ import_react4.default.createElement(ActionToolbarItem, {
|
|
430
|
-
key: item.id,
|
|
431
|
-
action: item
|
|
432
|
-
})
|
|
433
|
-
))));
|
|
434
|
-
} finally {
|
|
435
|
-
_effect.f();
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
var edgesArrayToRecord = (edges) => {
|
|
439
|
-
return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
|
|
440
|
-
if (!acc[source]) {
|
|
441
|
-
acc[source] = {
|
|
442
|
-
inbound: [],
|
|
443
|
-
outbound: []
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
if (!acc[target]) {
|
|
447
|
-
acc[target] = {
|
|
448
|
-
inbound: [],
|
|
449
|
-
outbound: []
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
const sourceEdges = acc[source];
|
|
453
|
-
if (!sourceEdges.outbound.includes(target)) {
|
|
454
|
-
sourceEdges.outbound.push(target);
|
|
455
|
-
}
|
|
456
|
-
const targetEdges = acc[target];
|
|
457
|
-
if (!targetEdges.inbound.includes(source)) {
|
|
458
|
-
targetEdges.inbound.push(source);
|
|
459
|
-
}
|
|
460
|
-
return acc;
|
|
461
|
-
}, {})));
|
|
462
|
-
};
|
|
463
|
-
var useMenuActions = (props) => {
|
|
464
|
-
const registry = (0, import_react5.useContext)(import_rx_react.RegistryContext);
|
|
465
|
-
const menuGraphProps = (0, import_rx_react.useRxValue)(props);
|
|
466
|
-
const [graph] = (0, import_react5.useState)(new import_app_graph4.Graph({
|
|
467
|
-
registry,
|
|
468
|
-
nodes: menuGraphProps.nodes,
|
|
469
|
-
edges: edgesArrayToRecord(menuGraphProps.edges)
|
|
470
|
-
}));
|
|
471
|
-
(0, import_react5.useEffect)(() => {
|
|
472
|
-
graph.addNodes(menuGraphProps.nodes);
|
|
473
|
-
graph.addEdges(menuGraphProps.edges);
|
|
474
|
-
}, [
|
|
475
|
-
menuGraphProps
|
|
476
|
-
]);
|
|
477
|
-
const useGroupItems = (0, import_react5.useCallback)((sourceNode) => {
|
|
478
|
-
const items = (0, import_rx_react.useRxValue)(graph.connections(sourceNode?.id || import_app_graph4.ROOT_ID));
|
|
479
|
-
return items;
|
|
480
|
-
}, [
|
|
481
|
-
graph
|
|
482
|
-
]);
|
|
483
|
-
return {
|
|
484
|
-
useGroupItems
|
|
485
|
-
};
|
|
486
|
-
};
|
|
487
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
488
|
-
0 && (module.exports = {
|
|
489
|
-
DropdownMenu,
|
|
490
|
-
MenuProvider,
|
|
491
|
-
MenuSeparatorType,
|
|
492
|
-
ToolbarMenu,
|
|
493
|
-
createGapSeparator,
|
|
494
|
-
createLineSeparator,
|
|
495
|
-
createMenuAction,
|
|
496
|
-
createMenuItemGroup,
|
|
497
|
-
createMenuScope,
|
|
498
|
-
isMenuGroup,
|
|
499
|
-
isSeparator,
|
|
500
|
-
menuContextDefaults,
|
|
501
|
-
rxFromSignal,
|
|
502
|
-
useMenu,
|
|
503
|
-
useMenuActions,
|
|
504
|
-
useMenuItems
|
|
505
|
-
});
|
|
506
|
-
//# sourceMappingURL=index.cjs.map
|