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