@dxos/react-ui-menu 0.8.4-main.fffef41 → 0.9.0
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/LICENSE +102 -5
- package/dist/lib/browser/index.mjs +537 -402
- 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 +537 -402
- 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 +27 -2
- 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/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 +16 -2
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -1
- 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 +16 -6
- package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- 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 +2 -2
- 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 +15 -6
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +45 -33
- package/src/builder.test.ts +224 -0
- package/src/builder.ts +69 -19
- package/src/components/ActionLabel.tsx +7 -6
- package/src/components/DropdownMenu.tsx +12 -6
- 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 +50 -28
- package/src/components/ToolbarMenu.tsx +146 -93
- package/src/components/index.ts +1 -3
- package/src/hooks/useMenuActions.ts +36 -52
- package/src/index.ts +1 -3
- package/src/testing/generator.ts +74 -64
- package/src/translations.ts +1 -1
- package/src/types.ts +39 -27
- package/src/util.ts +29 -15
- package/dist/types/src/components/MenuContext.d.ts +0 -15
- package/dist/types/src/components/MenuContext.d.ts.map +0 -1
- package/src/components/MenuContext.tsx +0 -54
|
@@ -1,46 +1,37 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import { Icon, DropdownMenu as NaturalDropdownMenu } from "@dxos/react-ui";
|
|
9
|
-
|
|
10
|
-
// src/components/ActionLabel.tsx
|
|
11
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
12
|
-
import React from "react";
|
|
13
|
-
import { keySymbols } from "@dxos/keyboard";
|
|
14
|
-
import { toLocalizedString, useTranslation } from "@dxos/react-ui";
|
|
15
|
-
import { descriptionText, mx } from "@dxos/react-ui-theme";
|
|
16
|
-
|
|
17
|
-
// src/translations.ts
|
|
18
|
-
var translationKey = "react-ui-menu";
|
|
19
|
-
var translations = [
|
|
20
|
-
{
|
|
21
|
-
"en-US": {
|
|
22
|
-
[translationKey]: {}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
];
|
|
1
|
+
// src/components/Menu.tsx
|
|
2
|
+
import { Atom, RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
3
|
+
import { createContextScope } from "@radix-ui/react-context";
|
|
4
|
+
import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
|
|
5
|
+
import React4, { createContext, useCallback as useCallback3, useContext, useMemo } from "react";
|
|
6
|
+
import { log } from "@dxos/log";
|
|
7
|
+
import { Icon as Icon3, DropdownMenu as NaturalDropdownMenu2 } from "@dxos/react-ui";
|
|
26
8
|
|
|
27
9
|
// src/util.ts
|
|
28
|
-
import
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import { Node } from "@dxos/app-graph";
|
|
12
|
+
import { EffectEx } from "@dxos/effect";
|
|
29
13
|
import { getHostPlatform } from "@dxos/util";
|
|
14
|
+
var executeMenuAction = async (action, params = {}) => {
|
|
15
|
+
let effect = action.data(params);
|
|
16
|
+
if (action._actionContext) {
|
|
17
|
+
effect = effect.pipe(Effect.provide(action._actionContext));
|
|
18
|
+
}
|
|
19
|
+
await EffectEx.runAndForwardErrors(effect);
|
|
20
|
+
};
|
|
30
21
|
var getShortcut = (action) => {
|
|
31
22
|
return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
|
|
32
23
|
};
|
|
33
24
|
var createMenuAction = (id, invoke, properties) => ({
|
|
34
25
|
id,
|
|
35
|
-
type:
|
|
26
|
+
type: Node.ActionType,
|
|
36
27
|
properties,
|
|
37
|
-
data: invoke
|
|
28
|
+
data: () => Effect.sync(invoke)
|
|
38
29
|
});
|
|
39
30
|
var createMenuItemGroup = (id, properties) => ({
|
|
40
31
|
id,
|
|
41
|
-
type:
|
|
32
|
+
type: Node.ActionGroupType,
|
|
42
33
|
properties,
|
|
43
|
-
data: actionGroupSymbol
|
|
34
|
+
data: Node.actionGroupSymbol
|
|
44
35
|
});
|
|
45
36
|
var createGapSeparator = (id = "gap", source = "root") => ({
|
|
46
37
|
nodes: [
|
|
@@ -56,7 +47,8 @@ var createGapSeparator = (id = "gap", source = "root") => ({
|
|
|
56
47
|
edges: [
|
|
57
48
|
{
|
|
58
49
|
source,
|
|
59
|
-
target: id
|
|
50
|
+
target: id,
|
|
51
|
+
relation: "child"
|
|
60
52
|
}
|
|
61
53
|
]
|
|
62
54
|
});
|
|
@@ -74,128 +66,109 @@ var createLineSeparator = (id = "line", source = "root") => ({
|
|
|
74
66
|
edges: [
|
|
75
67
|
{
|
|
76
68
|
source,
|
|
77
|
-
target: id
|
|
69
|
+
target: id,
|
|
70
|
+
relation: "child"
|
|
78
71
|
}
|
|
79
72
|
]
|
|
80
73
|
});
|
|
81
74
|
|
|
82
75
|
// src/components/ActionLabel.tsx
|
|
76
|
+
import React from "react";
|
|
77
|
+
import { keySymbols } from "@dxos/keyboard";
|
|
78
|
+
import { toLocalizedString, useTranslation } from "@dxos/react-ui";
|
|
79
|
+
import { mx } from "@dxos/ui-theme";
|
|
80
|
+
import { translationKey } from "#translations";
|
|
83
81
|
var ActionLabel = ({ action }) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
className: mx("shrink-0", descriptionText)
|
|
92
|
-
}, keySymbols(shortcut).join("")));
|
|
93
|
-
} finally {
|
|
94
|
-
_effect.f();
|
|
95
|
-
}
|
|
82
|
+
const { t } = useTranslation(translationKey);
|
|
83
|
+
const shortcut = getShortcut(action);
|
|
84
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
|
|
85
|
+
className: "grow truncate"
|
|
86
|
+
}, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
|
|
87
|
+
className: mx("shrink-0", "text-description")
|
|
88
|
+
}, keySymbols(shortcut).join("")));
|
|
96
89
|
};
|
|
97
90
|
var actionLabel = (action, t) => {
|
|
98
91
|
const shortcut = getShortcut(action);
|
|
99
92
|
return `${toLocalizedString(action.properties.label, t)}${shortcut ? ` (${keySymbols(shortcut).join("")})` : ""}`;
|
|
100
93
|
};
|
|
101
94
|
|
|
102
|
-
// src/components/
|
|
103
|
-
import {
|
|
104
|
-
import {
|
|
105
|
-
import
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
var
|
|
114
|
-
var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
|
|
115
|
-
var _effect = _useSignals2();
|
|
116
|
-
try {
|
|
117
|
-
const { scope } = useMenuScope(void 0);
|
|
118
|
-
return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
|
|
119
|
-
useGroupItems,
|
|
120
|
-
iconSize,
|
|
121
|
-
attendableId,
|
|
122
|
-
scope
|
|
123
|
-
}, children);
|
|
124
|
-
} finally {
|
|
125
|
-
_effect.f();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
129
|
-
const { useGroupItems } = useMenu(consumerName, __menuScope);
|
|
130
|
-
const groupItems = useGroupItems(group);
|
|
131
|
-
return useMemo(() => propsItems ?? groupItems ?? void 0, [
|
|
132
|
-
propsItems,
|
|
133
|
-
groupItems
|
|
134
|
-
]);
|
|
135
|
-
};
|
|
95
|
+
// src/components/ToolbarMenu.tsx
|
|
96
|
+
import React3, { useCallback as useCallback2 } from "react";
|
|
97
|
+
import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
98
|
+
import { composable, composableProps } from "@dxos/react-ui";
|
|
99
|
+
import { useAttention } from "@dxos/react-ui-attention";
|
|
100
|
+
import { translationKey as translationKey2 } from "#translations";
|
|
101
|
+
|
|
102
|
+
// src/types.ts
|
|
103
|
+
import { Node as Node2 } from "@dxos/app-graph";
|
|
104
|
+
var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
|
|
105
|
+
var isSeparator = (node) => node.type === MenuSeparatorType;
|
|
106
|
+
var isMenuGroup = (node) => node.type === Node2.ActionGroupType;
|
|
136
107
|
|
|
137
108
|
// src/components/DropdownMenu.tsx
|
|
109
|
+
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
110
|
+
import React2, { useCallback } from "react";
|
|
111
|
+
import { Icon, DropdownMenu as NaturalDropdownMenu } from "@dxos/react-ui";
|
|
138
112
|
var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
action
|
|
159
|
-
}));
|
|
160
|
-
} finally {
|
|
161
|
-
_effect.f();
|
|
162
|
-
}
|
|
113
|
+
const action = item;
|
|
114
|
+
const handleClick = useCallback((event) => onClick(action, event), [
|
|
115
|
+
action,
|
|
116
|
+
onClick
|
|
117
|
+
]);
|
|
118
|
+
const { iconSize } = useMenuScoped("DropdownMenuItem", __menuScope);
|
|
119
|
+
return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Item, {
|
|
120
|
+
onClick: handleClick,
|
|
121
|
+
classNames: "gap-2",
|
|
122
|
+
disabled: action.properties?.disabled,
|
|
123
|
+
...action.properties?.testId && {
|
|
124
|
+
"data-testid": action.properties.testId
|
|
125
|
+
}
|
|
126
|
+
}, action.properties?.icon && /* @__PURE__ */ React2.createElement(Icon, {
|
|
127
|
+
icon: action.properties.icon,
|
|
128
|
+
size: iconSize
|
|
129
|
+
}), /* @__PURE__ */ React2.createElement(ActionLabel, {
|
|
130
|
+
action
|
|
131
|
+
}));
|
|
163
132
|
};
|
|
164
133
|
var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, caller, children, __menuScope, ...naturalProps }) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
134
|
+
const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
|
|
135
|
+
prop: open,
|
|
136
|
+
defaultProp: defaultOpen,
|
|
137
|
+
onChange: onOpenChange
|
|
138
|
+
});
|
|
139
|
+
const { onAction } = useMenuScoped("DropdownMenuRoot", __menuScope);
|
|
140
|
+
const handleActionClick = useCallback((action, event) => {
|
|
141
|
+
if (action.properties?.disabled) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
setOptionsMenuOpen(false);
|
|
146
|
+
if (onAction) {
|
|
147
|
+
onAction(action, {
|
|
179
148
|
parent: group,
|
|
180
149
|
caller
|
|
181
150
|
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
151
|
+
} else {
|
|
152
|
+
void executeMenuAction(action, {
|
|
153
|
+
parent: group,
|
|
154
|
+
caller
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}, [
|
|
158
|
+
group,
|
|
159
|
+
caller,
|
|
160
|
+
onAction
|
|
161
|
+
]);
|
|
162
|
+
const items = useMenuItems(group, propsItems);
|
|
163
|
+
return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Root, {
|
|
164
|
+
open: optionsMenuOpen,
|
|
165
|
+
onOpenChange: setOptionsMenuOpen,
|
|
166
|
+
...naturalProps
|
|
167
|
+
}, children, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React2.createElement(DropdownMenuItem, {
|
|
168
|
+
key: item.id,
|
|
169
|
+
item,
|
|
170
|
+
onClick: handleActionClick
|
|
171
|
+
}))), /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Arrow, null))));
|
|
199
172
|
};
|
|
200
173
|
var DropdownMenu = {
|
|
201
174
|
Root: DropdownMenuRoot,
|
|
@@ -204,313 +177,444 @@ var DropdownMenu = {
|
|
|
204
177
|
};
|
|
205
178
|
|
|
206
179
|
// src/components/ToolbarMenu.tsx
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
children: /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
234
|
-
action
|
|
235
|
-
})
|
|
236
|
-
};
|
|
237
|
-
const handleClick = useCallback2(() => action.data?.(), [
|
|
238
|
-
action
|
|
239
|
-
]);
|
|
240
|
-
return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
|
|
241
|
-
key: action.id,
|
|
242
|
-
disabled,
|
|
243
|
-
onClick: handleClick,
|
|
244
|
-
variant: "ghost",
|
|
245
|
-
...testId && {
|
|
246
|
-
"data-testid": testId
|
|
247
|
-
},
|
|
248
|
-
...rootProps,
|
|
249
|
-
classNames
|
|
250
|
-
});
|
|
251
|
-
} finally {
|
|
252
|
-
_effect.f();
|
|
180
|
+
var ActionToolbarItem = ({ __menuScope, action }) => {
|
|
181
|
+
const { iconSize, onAction } = useMenuScoped("ActionToolbarItem", __menuScope);
|
|
182
|
+
const { t } = useTranslation2(translationKey2);
|
|
183
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
|
|
184
|
+
const buttonVariant = action.properties.variant === "primary" ? "primary" : "ghost";
|
|
185
|
+
const handleClick = useCallback2(() => {
|
|
186
|
+
if (onAction) {
|
|
187
|
+
onAction(action, {});
|
|
188
|
+
} else {
|
|
189
|
+
void executeMenuAction(action);
|
|
190
|
+
}
|
|
191
|
+
}, [
|
|
192
|
+
action,
|
|
193
|
+
onAction
|
|
194
|
+
]);
|
|
195
|
+
const commonProps = {
|
|
196
|
+
variant: buttonVariant,
|
|
197
|
+
disabled,
|
|
198
|
+
classNames,
|
|
199
|
+
onClick: handleClick,
|
|
200
|
+
...testId && {
|
|
201
|
+
"data-testid": testId
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
if (hidden) {
|
|
205
|
+
return null;
|
|
253
206
|
}
|
|
207
|
+
return icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.IconButton, {
|
|
208
|
+
key: action.id,
|
|
209
|
+
...commonProps,
|
|
210
|
+
icon,
|
|
211
|
+
size: iconSize,
|
|
212
|
+
iconOnly,
|
|
213
|
+
iconClassNames,
|
|
214
|
+
label: actionLabel(action, t)
|
|
215
|
+
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
|
|
216
|
+
key: action.id,
|
|
217
|
+
...commonProps
|
|
218
|
+
}, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
219
|
+
action
|
|
220
|
+
}));
|
|
221
|
+
};
|
|
222
|
+
var DropdownMenuToolbarItem = ({ __menuScope, group, items: propsItems }) => {
|
|
223
|
+
const { iconOnly, disabled, testId } = group.properties;
|
|
224
|
+
const { t } = useTranslation2(translationKey2);
|
|
225
|
+
const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
|
|
226
|
+
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
227
|
+
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
228
|
+
const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
|
|
229
|
+
activeItem?.properties.icon || group.properties.icon;
|
|
230
|
+
const iconClassNames = group.properties.applyActive && activeItem?.properties.iconClassNames || group.properties.iconClassNames;
|
|
231
|
+
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
232
|
+
const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
|
|
233
|
+
const rootProps = icon ? {
|
|
234
|
+
icon,
|
|
235
|
+
size: iconSize,
|
|
236
|
+
iconOnly,
|
|
237
|
+
iconClassNames,
|
|
238
|
+
label: actionLabel(labelAction, t),
|
|
239
|
+
caretDown: true
|
|
240
|
+
} : {
|
|
241
|
+
children: /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
242
|
+
action: labelAction
|
|
243
|
+
}), /* @__PURE__ */ React3.createElement(Icon2, {
|
|
244
|
+
size: 3,
|
|
245
|
+
icon: "ph--caret-down--bold",
|
|
246
|
+
classNames: "ms-1"
|
|
247
|
+
}))
|
|
248
|
+
};
|
|
249
|
+
return /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
|
|
250
|
+
group,
|
|
251
|
+
items
|
|
252
|
+
}, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
|
|
253
|
+
asChild: true
|
|
254
|
+
}, /* @__PURE__ */ React3.createElement(Root, {
|
|
255
|
+
variant: "ghost",
|
|
256
|
+
disabled,
|
|
257
|
+
...rootProps,
|
|
258
|
+
...testId && {
|
|
259
|
+
"data-testid": testId
|
|
260
|
+
}
|
|
261
|
+
})));
|
|
254
262
|
};
|
|
255
|
-
var
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
263
|
+
var ToggleGroupItem = ({ __menuScope, group, action }) => {
|
|
264
|
+
const { iconSize, onAction } = useMenuScoped("ToggleGroupItem", __menuScope);
|
|
265
|
+
const { t } = useTranslation2(translationKey2);
|
|
266
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
|
|
267
|
+
const handleClick = useCallback2(() => {
|
|
268
|
+
if (onAction) {
|
|
269
|
+
onAction(action, {
|
|
270
|
+
parent: group
|
|
271
|
+
});
|
|
272
|
+
} else {
|
|
273
|
+
void executeMenuAction(action, {
|
|
274
|
+
parent: group
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}, [
|
|
278
|
+
action,
|
|
279
|
+
group,
|
|
280
|
+
onAction
|
|
281
|
+
]);
|
|
282
|
+
const commonProps = {
|
|
283
|
+
value: action.id,
|
|
284
|
+
disabled,
|
|
285
|
+
variant: "ghost",
|
|
286
|
+
classNames,
|
|
287
|
+
onClick: handleClick,
|
|
288
|
+
...testId && {
|
|
289
|
+
"data-testid": testId
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
return hidden ? null : icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupIconItem, {
|
|
293
|
+
...commonProps,
|
|
294
|
+
icon,
|
|
295
|
+
size: iconSize,
|
|
296
|
+
iconOnly,
|
|
297
|
+
iconClassNames,
|
|
298
|
+
label: actionLabel(action, t)
|
|
299
|
+
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, commonProps, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
300
|
+
action
|
|
301
|
+
}));
|
|
302
|
+
};
|
|
303
|
+
var ToggleGroupToolbarItem = ({ __menuScope, group, items: itemsProp }) => {
|
|
304
|
+
const items = useMenuItems(group, itemsProp, "ToggleGroupToolbarItem", __menuScope);
|
|
305
|
+
const { selectCardinality } = group.properties;
|
|
306
|
+
const children = items.map((action) => /* @__PURE__ */ React3.createElement(ToggleGroupItem, {
|
|
307
|
+
key: action.id,
|
|
308
|
+
group,
|
|
309
|
+
action
|
|
310
|
+
}));
|
|
311
|
+
if (selectCardinality === "multiple") {
|
|
312
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
313
|
+
type: "multiple",
|
|
314
|
+
value: group.properties.value
|
|
315
|
+
}, children);
|
|
316
|
+
} else {
|
|
317
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
318
|
+
type: "single",
|
|
319
|
+
value: group.properties.value
|
|
320
|
+
}, children);
|
|
297
321
|
}
|
|
298
322
|
};
|
|
299
|
-
var
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
action
|
|
320
|
-
})
|
|
321
|
-
};
|
|
322
|
-
return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
|
|
323
|
-
key: action.id,
|
|
324
|
-
value: action.id,
|
|
325
|
-
disabled,
|
|
326
|
-
onClick: handleClick,
|
|
327
|
-
variant: "ghost",
|
|
328
|
-
...testId && {
|
|
329
|
-
"data-testid": testId
|
|
330
|
-
},
|
|
331
|
-
...rootProps,
|
|
332
|
-
classNames
|
|
323
|
+
var ToolbarMenu = composable(({ __menuScope, children, ...props }, forwardedRef) => {
|
|
324
|
+
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
325
|
+
const { attendableId, alwaysActive } = useMenuScoped("ToolbarMenu", __menuScope);
|
|
326
|
+
const { hasAttention } = useAttention(attendableId);
|
|
327
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
|
|
328
|
+
...composableProps(props, {
|
|
329
|
+
classNames: attendableId
|
|
330
|
+
}),
|
|
331
|
+
disabled: !alwaysActive && !hasAttention,
|
|
332
|
+
ref: forwardedRef
|
|
333
|
+
}, items?.map((item) => /* @__PURE__ */ React3.createElement(ToolbarMenuItem, {
|
|
334
|
+
key: item.id,
|
|
335
|
+
__menuScope,
|
|
336
|
+
item
|
|
337
|
+
})), children);
|
|
338
|
+
});
|
|
339
|
+
var ToolbarMenuItem = ({ __menuScope, item }) => {
|
|
340
|
+
if (isSeparator(item)) {
|
|
341
|
+
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Separator, {
|
|
342
|
+
variant: item.properties.variant
|
|
333
343
|
});
|
|
334
|
-
} finally {
|
|
335
|
-
_effect.f();
|
|
336
344
|
}
|
|
345
|
+
if (isMenuGroup(item)) {
|
|
346
|
+
if (item.properties.variant === "dropdownMenu") {
|
|
347
|
+
return /* @__PURE__ */ React3.createElement(DropdownMenuToolbarItem, {
|
|
348
|
+
__menuScope,
|
|
349
|
+
group: item
|
|
350
|
+
});
|
|
351
|
+
} else {
|
|
352
|
+
return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
|
|
353
|
+
__menuScope,
|
|
354
|
+
group: item
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
|
|
359
|
+
__menuScope,
|
|
360
|
+
action: item
|
|
361
|
+
});
|
|
337
362
|
};
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
|
|
354
|
-
key: action.id,
|
|
355
|
-
group,
|
|
356
|
-
action
|
|
357
|
-
}))
|
|
358
|
-
)
|
|
359
|
-
);
|
|
360
|
-
} finally {
|
|
361
|
-
_effect.f();
|
|
363
|
+
|
|
364
|
+
// src/components/Menu.tsx
|
|
365
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/components/Menu.tsx";
|
|
366
|
+
var MENU_NAME = "Menu";
|
|
367
|
+
var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
|
|
368
|
+
var nullItemsAtom = Atom.make(null);
|
|
369
|
+
var defaultItemsAccessor = () => nullItemsAtom;
|
|
370
|
+
var menuContextDefaults = {
|
|
371
|
+
iconSize: 5,
|
|
372
|
+
items: defaultItemsAccessor,
|
|
373
|
+
onAction: void 0,
|
|
374
|
+
menuItemsAtom: Atom.make(/* @__PURE__ */ new Map()),
|
|
375
|
+
addMenuItems: () => {
|
|
376
|
+
},
|
|
377
|
+
removeMenuItems: () => {
|
|
362
378
|
}
|
|
363
379
|
};
|
|
364
|
-
var
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return
|
|
376
|
-
...props,
|
|
377
|
-
classNames: [
|
|
378
|
-
attendableId && !hasAttention && toolbarInactive,
|
|
379
|
-
classNames
|
|
380
|
-
],
|
|
381
|
-
layoutManaged: textBlockWidthParam
|
|
382
|
-
}, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React4.createElement(ToolbarMenuItem, {
|
|
383
|
-
key: item.id ?? i,
|
|
384
|
-
item
|
|
385
|
-
}))));
|
|
386
|
-
} finally {
|
|
387
|
-
_effect.f();
|
|
380
|
+
var [MenuContextProvider, useMenuScoped] = createMenuContext(MENU_NAME, menuContextDefaults);
|
|
381
|
+
var useMenuScope = createMenuScope();
|
|
382
|
+
var MenuDropdownContext = /* @__PURE__ */ createContext({
|
|
383
|
+
closeMenu: () => {
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
var DEFAULT_PRIORITY = 100;
|
|
387
|
+
var sortMenuItems = (items) => [
|
|
388
|
+
...items
|
|
389
|
+
].sort((a, b) => {
|
|
390
|
+
if (a.priority !== b.priority) {
|
|
391
|
+
return a.priority - b.priority;
|
|
388
392
|
}
|
|
393
|
+
return a.id.localeCompare(b.id);
|
|
394
|
+
});
|
|
395
|
+
var MenuProvider = ({ children, items = menuContextDefaults.items, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
|
|
396
|
+
const { scope } = useMenuScope(void 0);
|
|
397
|
+
const registry = useContext(RegistryContext);
|
|
398
|
+
const menuItemsAtom = useMemo(() => Atom.make(/* @__PURE__ */ new Map()).pipe(Atom.keepAlive), []);
|
|
399
|
+
const addMenuItems = useCallback3((props) => {
|
|
400
|
+
const priority = props.priority ?? DEFAULT_PRIORITY;
|
|
401
|
+
const prev = registry.get(menuItemsAtom);
|
|
402
|
+
const next = new Map(prev);
|
|
403
|
+
next.set(props.id, {
|
|
404
|
+
...props,
|
|
405
|
+
priority
|
|
406
|
+
});
|
|
407
|
+
registry.set(menuItemsAtom, next);
|
|
408
|
+
}, [
|
|
409
|
+
registry,
|
|
410
|
+
menuItemsAtom
|
|
411
|
+
]);
|
|
412
|
+
const removeMenuItems = useCallback3((id) => {
|
|
413
|
+
const prev = registry.get(menuItemsAtom);
|
|
414
|
+
const next = new Map(prev);
|
|
415
|
+
next.delete(id);
|
|
416
|
+
registry.set(menuItemsAtom, next);
|
|
417
|
+
}, [
|
|
418
|
+
registry,
|
|
419
|
+
menuItemsAtom
|
|
420
|
+
]);
|
|
421
|
+
return /* @__PURE__ */ React4.createElement(MenuContextProvider, {
|
|
422
|
+
items,
|
|
423
|
+
iconSize,
|
|
424
|
+
attendableId,
|
|
425
|
+
alwaysActive,
|
|
426
|
+
menuItemsAtom,
|
|
427
|
+
addMenuItems,
|
|
428
|
+
removeMenuItems,
|
|
429
|
+
onAction,
|
|
430
|
+
scope
|
|
431
|
+
}, children);
|
|
389
432
|
};
|
|
390
|
-
var
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
group: item
|
|
406
|
-
});
|
|
407
|
-
}
|
|
433
|
+
var resolveItems = (baseItems, group, entries) => {
|
|
434
|
+
const applicable = [
|
|
435
|
+
...entries.values()
|
|
436
|
+
].filter((entry) => !entry.groupFilter || entry.groupFilter(group));
|
|
437
|
+
if (applicable.length === 0) {
|
|
438
|
+
return baseItems;
|
|
439
|
+
}
|
|
440
|
+
const sorted = sortMenuItems(applicable);
|
|
441
|
+
const replacements = sorted.filter((entry) => entry.mode === "replacement");
|
|
442
|
+
if (replacements.length > 0) {
|
|
443
|
+
if (replacements.length > 1) {
|
|
444
|
+
log.warn("multiple replacement entries found", {
|
|
445
|
+
ids: replacements.map((r) => r.id).join(", "),
|
|
446
|
+
using: replacements[0].id
|
|
447
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 94, S: void 0 });
|
|
408
448
|
}
|
|
409
|
-
return
|
|
410
|
-
action: item
|
|
411
|
-
});
|
|
412
|
-
} finally {
|
|
413
|
-
_effect.f();
|
|
449
|
+
return replacements[0].items;
|
|
414
450
|
}
|
|
451
|
+
const additive = sorted.filter((entry) => entry.mode === "additive");
|
|
452
|
+
const additiveItems = additive.flatMap((entry) => entry.items);
|
|
453
|
+
if (!baseItems || baseItems.length === 0) {
|
|
454
|
+
return additiveItems.length > 0 ? additiveItems : null;
|
|
455
|
+
}
|
|
456
|
+
return [
|
|
457
|
+
...baseItems,
|
|
458
|
+
...additiveItems
|
|
459
|
+
];
|
|
415
460
|
};
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
461
|
+
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
462
|
+
const { items, menuItemsAtom } = useMenuScoped(consumerName, __menuScope);
|
|
463
|
+
const groupItems = useAtomValue(items(group));
|
|
464
|
+
const entries = useAtomValue(menuItemsAtom) ?? /* @__PURE__ */ new Map();
|
|
465
|
+
const baseItems = useMemo(() => propsItems ?? groupItems ?? null, [
|
|
466
|
+
propsItems,
|
|
467
|
+
groupItems
|
|
468
|
+
]);
|
|
469
|
+
const resolved = useMemo(() => resolveItems(baseItems, group, entries), [
|
|
470
|
+
baseItems,
|
|
471
|
+
group,
|
|
472
|
+
entries
|
|
473
|
+
]);
|
|
474
|
+
return resolved ?? void 0;
|
|
475
|
+
};
|
|
476
|
+
var useMenu = (consumerName) => {
|
|
477
|
+
return useMenuScoped(consumerName, void 0);
|
|
478
|
+
};
|
|
479
|
+
var MenuRoot = ({ children, open, defaultOpen, onOpenChange, caller, ...props }) => {
|
|
480
|
+
const [menuOpen, setMenuOpen] = useControllableState2({
|
|
481
|
+
prop: open,
|
|
482
|
+
defaultProp: defaultOpen,
|
|
483
|
+
onChange: onOpenChange
|
|
484
|
+
});
|
|
485
|
+
const closeMenu = useCallback3(() => setMenuOpen(false), [
|
|
486
|
+
setMenuOpen
|
|
487
|
+
]);
|
|
488
|
+
return /* @__PURE__ */ React4.createElement(MenuProvider, props, /* @__PURE__ */ React4.createElement(MenuDropdownContext.Provider, {
|
|
489
|
+
value: {
|
|
490
|
+
closeMenu,
|
|
491
|
+
caller
|
|
428
492
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
493
|
+
}, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Root, {
|
|
494
|
+
open: menuOpen,
|
|
495
|
+
onOpenChange: setMenuOpen
|
|
496
|
+
}, children)));
|
|
497
|
+
};
|
|
498
|
+
var MenuContentItem = ({ item, onClick, __menuScope }) => {
|
|
499
|
+
const action = item;
|
|
500
|
+
const handleClick = useCallback3((event) => onClick(action, event), [
|
|
501
|
+
action,
|
|
502
|
+
onClick
|
|
503
|
+
]);
|
|
504
|
+
const { iconSize } = useMenuScoped("MenuContentItem", __menuScope);
|
|
505
|
+
return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Item, {
|
|
506
|
+
onClick: handleClick,
|
|
507
|
+
classNames: "gap-2",
|
|
508
|
+
disabled: action.properties?.disabled,
|
|
509
|
+
...action.properties?.testId && {
|
|
510
|
+
"data-testid": action.properties.testId
|
|
434
511
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
512
|
+
}, action.properties?.icon && /* @__PURE__ */ React4.createElement(Icon3, {
|
|
513
|
+
icon: action.properties.icon,
|
|
514
|
+
size: iconSize
|
|
515
|
+
}), /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
516
|
+
action
|
|
517
|
+
}));
|
|
518
|
+
};
|
|
519
|
+
var MenuContent = ({ group, items: propsItems, caller: callerOverride, __menuScope }) => {
|
|
520
|
+
const { closeMenu, caller: contextCaller } = useContext(MenuDropdownContext);
|
|
521
|
+
const caller = callerOverride ?? contextCaller;
|
|
522
|
+
const { onAction } = useMenuScoped("MenuContent", __menuScope);
|
|
523
|
+
const resolvedItems = useMenuItems(group, propsItems, "MenuContent", __menuScope);
|
|
524
|
+
const handleActionClick = useCallback3((action, event) => {
|
|
525
|
+
if (action.properties?.disabled) {
|
|
526
|
+
return;
|
|
438
527
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
528
|
+
event.stopPropagation();
|
|
529
|
+
closeMenu();
|
|
530
|
+
if (onAction) {
|
|
531
|
+
onAction(action, {
|
|
532
|
+
parent: group,
|
|
533
|
+
caller
|
|
534
|
+
});
|
|
535
|
+
} else {
|
|
536
|
+
void executeMenuAction(action, {
|
|
537
|
+
parent: group,
|
|
538
|
+
caller
|
|
539
|
+
});
|
|
442
540
|
}
|
|
443
|
-
|
|
444
|
-
|
|
541
|
+
}, [
|
|
542
|
+
group,
|
|
543
|
+
caller,
|
|
544
|
+
onAction,
|
|
545
|
+
closeMenu
|
|
546
|
+
]);
|
|
547
|
+
return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Portal, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Viewport, null, resolvedItems?.map((item) => /* @__PURE__ */ React4.createElement(MenuContentItem, {
|
|
548
|
+
key: item.id,
|
|
549
|
+
item,
|
|
550
|
+
onClick: handleActionClick
|
|
551
|
+
}))), /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Arrow, null)));
|
|
552
|
+
};
|
|
553
|
+
var Menu = {
|
|
554
|
+
Root: MenuRoot,
|
|
555
|
+
Trigger: NaturalDropdownMenu2.Trigger,
|
|
556
|
+
Content: MenuContent,
|
|
557
|
+
VirtualTrigger: NaturalDropdownMenu2.VirtualTrigger,
|
|
558
|
+
Toolbar: ToolbarMenu
|
|
445
559
|
};
|
|
560
|
+
|
|
561
|
+
// src/hooks/useMenuActions.ts
|
|
562
|
+
import { Atom as Atom2, RegistryContext as RegistryContext2, useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
|
|
563
|
+
import { useCallback as useCallback4, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
564
|
+
import { Graph, Node as Node3 } from "@dxos/app-graph";
|
|
446
565
|
var useMenuActions = (props) => {
|
|
447
|
-
const registry =
|
|
448
|
-
const menuGraphProps =
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
graph.addNodes(menuGraphProps.nodes);
|
|
456
|
-
graph.addEdges(menuGraphProps.edges);
|
|
566
|
+
const registry = useContext2(RegistryContext2);
|
|
567
|
+
const menuGraphProps = useAtomValue2(props);
|
|
568
|
+
const graph = useMemo2(() => {
|
|
569
|
+
const newGraph = Graph.make({
|
|
570
|
+
registry
|
|
571
|
+
});
|
|
572
|
+
newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
573
|
+
return newGraph;
|
|
457
574
|
}, [
|
|
575
|
+
registry,
|
|
458
576
|
menuGraphProps
|
|
459
577
|
]);
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
return items;
|
|
578
|
+
const items = useCallback4((group) => {
|
|
579
|
+
return graph.connections(group?.id || Node3.RootId, "child");
|
|
463
580
|
}, [
|
|
464
581
|
graph
|
|
465
582
|
]);
|
|
466
583
|
return {
|
|
467
|
-
|
|
584
|
+
items
|
|
468
585
|
};
|
|
469
586
|
};
|
|
587
|
+
var useMenuBuilder = (build, deps) => {
|
|
588
|
+
const atom = useMemo2(() => Atom2.make(build), deps);
|
|
589
|
+
return useMenuActions(atom);
|
|
590
|
+
};
|
|
470
591
|
|
|
471
592
|
// src/builder.ts
|
|
472
593
|
import { invariant } from "@dxos/invariant";
|
|
473
|
-
var
|
|
474
|
-
var MenuBuilder = Object.freeze({
|
|
475
|
-
make: () => new MenuBuilderImpl({
|
|
476
|
-
nodes: [],
|
|
477
|
-
edges: []
|
|
478
|
-
}, "root")
|
|
479
|
-
});
|
|
594
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/builder.ts";
|
|
480
595
|
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
481
596
|
_data;
|
|
482
597
|
_rootId;
|
|
598
|
+
_separatorCount = 0;
|
|
483
599
|
constructor(_data, _rootId) {
|
|
484
600
|
this._data = _data;
|
|
485
601
|
this._rootId = _rootId;
|
|
486
602
|
}
|
|
487
603
|
root(props) {
|
|
488
|
-
invariant(this._rootId === "root", "Root group can only be at the top level", {
|
|
489
|
-
|
|
490
|
-
L: 36,
|
|
491
|
-
S: this,
|
|
492
|
-
A: [
|
|
493
|
-
"this._rootId === 'root'",
|
|
494
|
-
"'Root group can only be at the top level'"
|
|
495
|
-
]
|
|
496
|
-
});
|
|
497
|
-
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
|
|
498
|
-
F: __dxlog_file,
|
|
499
|
-
L: 37,
|
|
500
|
-
S: this,
|
|
501
|
-
A: [
|
|
502
|
-
"this._data.nodes.find((node) => node.id === 'root') === undefined",
|
|
503
|
-
"'Root group can only be created once'"
|
|
504
|
-
]
|
|
505
|
-
});
|
|
604
|
+
invariant(this._rootId === "root", "Root group can only be at the top level", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 16, S: this, A: ["this._rootId === 'root'", "'Root group can only be at the top level'"] });
|
|
605
|
+
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 17, S: this, A: ["this._data.nodes.find((node)=>node.id === 'root') === undefined", "'Root group can only be created once'"] });
|
|
506
606
|
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
507
607
|
return this;
|
|
508
608
|
}
|
|
609
|
+
build() {
|
|
610
|
+
return this._data;
|
|
611
|
+
}
|
|
509
612
|
action(id, props, invoke) {
|
|
510
613
|
this._data.nodes.push(createMenuAction(id, invoke, props));
|
|
511
614
|
this._data.edges.push({
|
|
512
615
|
source: this._rootId,
|
|
513
|
-
target: id
|
|
616
|
+
target: id,
|
|
617
|
+
relation: "child"
|
|
514
618
|
});
|
|
515
619
|
return this;
|
|
516
620
|
}
|
|
@@ -518,32 +622,63 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
518
622
|
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
519
623
|
this._data.edges.push({
|
|
520
624
|
source: this._rootId,
|
|
521
|
-
target: id
|
|
625
|
+
target: id,
|
|
626
|
+
relation: "child"
|
|
522
627
|
});
|
|
523
628
|
cb(new _MenuBuilderImpl(this._data, id));
|
|
524
629
|
return this;
|
|
525
630
|
}
|
|
526
|
-
|
|
527
|
-
|
|
631
|
+
subgraph(subgraphOrCb) {
|
|
632
|
+
if (!subgraphOrCb) {
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
if (typeof subgraphOrCb === "function") {
|
|
636
|
+
subgraphOrCb(new _MenuBuilderImpl(this._data, this._rootId));
|
|
637
|
+
} else {
|
|
638
|
+
this._data.nodes.push(...subgraphOrCb.nodes);
|
|
639
|
+
this._data.edges.push(...subgraphOrCb.edges);
|
|
640
|
+
}
|
|
641
|
+
return this;
|
|
642
|
+
}
|
|
643
|
+
separator(variant = "gap") {
|
|
644
|
+
const id = `separator-${++this._separatorCount}`;
|
|
645
|
+
this._data.nodes.push({
|
|
646
|
+
id,
|
|
647
|
+
type: MenuSeparatorType,
|
|
648
|
+
properties: {
|
|
649
|
+
variant
|
|
650
|
+
},
|
|
651
|
+
data: void 0
|
|
652
|
+
});
|
|
653
|
+
this._data.edges.push({
|
|
654
|
+
source: this._rootId,
|
|
655
|
+
target: id,
|
|
656
|
+
relation: "child"
|
|
657
|
+
});
|
|
658
|
+
return this;
|
|
528
659
|
}
|
|
529
660
|
};
|
|
661
|
+
var MenuBuilder = Object.freeze({
|
|
662
|
+
make: () => new MenuBuilderImpl({
|
|
663
|
+
nodes: [],
|
|
664
|
+
edges: []
|
|
665
|
+
}, "root")
|
|
666
|
+
});
|
|
530
667
|
export {
|
|
531
|
-
|
|
668
|
+
Menu,
|
|
532
669
|
MenuBuilder,
|
|
533
|
-
MenuProvider,
|
|
534
670
|
MenuSeparatorType,
|
|
535
|
-
ToolbarMenu,
|
|
536
|
-
atomFromSignal,
|
|
537
671
|
createGapSeparator,
|
|
538
672
|
createLineSeparator,
|
|
539
673
|
createMenuAction,
|
|
540
674
|
createMenuItemGroup,
|
|
541
|
-
createMenuScope,
|
|
542
675
|
isMenuGroup,
|
|
543
676
|
isSeparator,
|
|
544
677
|
menuContextDefaults,
|
|
545
678
|
useMenu,
|
|
546
679
|
useMenuActions,
|
|
547
|
-
|
|
680
|
+
useMenuBuilder,
|
|
681
|
+
useMenuItems,
|
|
682
|
+
useMenuScoped
|
|
548
683
|
};
|
|
549
684
|
//# sourceMappingURL=index.mjs.map
|