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