@dxos/react-ui-menu 0.8.4-main.3f58842 → 0.8.4-main.52d7546f51
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 +308 -342
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +308 -342
- 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 +3 -3
- 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/MenuContext.d.ts +3 -1
- package/dist/types/src/components/MenuContext.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.d.ts +3 -2
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +20 -0
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -0
- package/dist/types/src/hooks/useMenuActions.d.ts +6 -5
- 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 +13 -11
- 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 +13 -24
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +12 -5
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -29
- package/src/builder.ts +11 -11
- package/src/components/ActionLabel.tsx +5 -5
- package/src/components/DropdownMenu.tsx +13 -5
- package/src/components/MenuContext.tsx +18 -4
- package/src/components/ToolbarMenu.stories.tsx +81 -0
- package/src/components/ToolbarMenu.tsx +70 -35
- package/src/hooks/useMenuActions.ts +23 -45
- package/src/index.ts +0 -2
- package/src/testing/generator.ts +63 -58
- package/src/translations.ts +1 -1
- package/src/types.ts +14 -26
- package/src/util.ts +32 -14
- package/dist/types/src/components/Menus.stories.d.ts +0 -25
- package/dist/types/src/components/Menus.stories.d.ts.map +0 -1
- package/src/components/Menus.stories.tsx +0 -69
|
@@ -1,48 +1,36 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
|
|
3
|
-
// src/index.ts
|
|
4
|
-
import { rxFromSignal } from "@dxos/app-graph";
|
|
5
|
-
|
|
6
3
|
// src/components/DropdownMenu.tsx
|
|
7
|
-
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
8
4
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
9
5
|
import React3, { useCallback } from "react";
|
|
10
|
-
import { DropdownMenu as NaturalDropdownMenu
|
|
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 { mx, descriptionText } 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
|
-
];
|
|
6
|
+
import { Icon, DropdownMenu as NaturalDropdownMenu } from "@dxos/react-ui";
|
|
28
7
|
|
|
29
8
|
// src/util.ts
|
|
30
|
-
import
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import { Node } from "@dxos/app-graph";
|
|
11
|
+
import { runAndForwardErrors } from "@dxos/effect";
|
|
31
12
|
import { getHostPlatform } from "@dxos/util";
|
|
13
|
+
var executeMenuAction = async (action, params = {}) => {
|
|
14
|
+
let effect = action.data(params);
|
|
15
|
+
if (action._actionContext) {
|
|
16
|
+
effect = effect.pipe(Effect.provide(action._actionContext));
|
|
17
|
+
}
|
|
18
|
+
await runAndForwardErrors(effect);
|
|
19
|
+
};
|
|
32
20
|
var getShortcut = (action) => {
|
|
33
21
|
return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
|
|
34
22
|
};
|
|
35
23
|
var createMenuAction = (id, invoke, properties) => ({
|
|
36
24
|
id,
|
|
37
|
-
type:
|
|
25
|
+
type: Node.ActionType,
|
|
38
26
|
properties,
|
|
39
|
-
data: invoke
|
|
27
|
+
data: () => Effect.sync(invoke)
|
|
40
28
|
});
|
|
41
29
|
var createMenuItemGroup = (id, properties) => ({
|
|
42
30
|
id,
|
|
43
|
-
type:
|
|
31
|
+
type: Node.ActionGroupType,
|
|
44
32
|
properties,
|
|
45
|
-
data: actionGroupSymbol
|
|
33
|
+
data: Node.actionGroupSymbol
|
|
46
34
|
});
|
|
47
35
|
var createGapSeparator = (id = "gap", source = "root") => ({
|
|
48
36
|
nodes: [
|
|
@@ -82,19 +70,30 @@ var createLineSeparator = (id = "line", source = "root") => ({
|
|
|
82
70
|
});
|
|
83
71
|
|
|
84
72
|
// src/components/ActionLabel.tsx
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
73
|
+
import React from "react";
|
|
74
|
+
import { keySymbols } from "@dxos/keyboard";
|
|
75
|
+
import { toLocalizedString, useTranslation } from "@dxos/react-ui";
|
|
76
|
+
import { descriptionText, mx } from "@dxos/ui-theme";
|
|
77
|
+
|
|
78
|
+
// src/translations.ts
|
|
79
|
+
var translationKey = "@dxos/react-ui-menu";
|
|
80
|
+
var translations = [
|
|
81
|
+
{
|
|
82
|
+
"en-US": {
|
|
83
|
+
[translationKey]: {}
|
|
84
|
+
}
|
|
97
85
|
}
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
// src/components/ActionLabel.tsx
|
|
89
|
+
var ActionLabel = ({ action }) => {
|
|
90
|
+
const { t } = useTranslation(translationKey);
|
|
91
|
+
const shortcut = getShortcut(action);
|
|
92
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
|
|
93
|
+
className: "grow truncate"
|
|
94
|
+
}, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
|
|
95
|
+
className: mx("shrink-0", descriptionText)
|
|
96
|
+
}, keySymbols(shortcut).join("")));
|
|
98
97
|
};
|
|
99
98
|
var actionLabel = (action, t) => {
|
|
100
99
|
const shortcut = getShortcut(action);
|
|
@@ -102,30 +101,27 @@ var actionLabel = (action, t) => {
|
|
|
102
101
|
};
|
|
103
102
|
|
|
104
103
|
// src/components/MenuContext.tsx
|
|
105
|
-
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
106
104
|
import { createContextScope } from "@radix-ui/react-context";
|
|
107
105
|
import React2, { useMemo } from "react";
|
|
108
|
-
var MENU_NAME = "
|
|
106
|
+
var MENU_NAME = "Menu";
|
|
109
107
|
var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
|
|
110
108
|
var [MenuContextProvider, useMenu] = createMenuContext(MENU_NAME);
|
|
111
109
|
var menuContextDefaults = {
|
|
112
110
|
iconSize: 5,
|
|
113
|
-
useGroupItems: () => null
|
|
111
|
+
useGroupItems: () => null,
|
|
112
|
+
onAction: void 0
|
|
114
113
|
};
|
|
115
114
|
var useMenuScope = createMenuScope();
|
|
116
|
-
var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} finally {
|
|
127
|
-
_effect.f();
|
|
128
|
-
}
|
|
115
|
+
var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
|
|
116
|
+
const { scope } = useMenuScope(void 0);
|
|
117
|
+
return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
|
|
118
|
+
useGroupItems,
|
|
119
|
+
iconSize,
|
|
120
|
+
attendableId,
|
|
121
|
+
alwaysActive,
|
|
122
|
+
onAction,
|
|
123
|
+
scope
|
|
124
|
+
}, children);
|
|
129
125
|
};
|
|
130
126
|
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
131
127
|
const { useGroupItems } = useMenu(consumerName, __menuScope);
|
|
@@ -138,66 +134,65 @@ var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __m
|
|
|
138
134
|
|
|
139
135
|
// src/components/DropdownMenu.tsx
|
|
140
136
|
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
|
-
}
|
|
137
|
+
const action = item;
|
|
138
|
+
const handleClick = useCallback((event) => onClick(action, event), [
|
|
139
|
+
action,
|
|
140
|
+
onClick
|
|
141
|
+
]);
|
|
142
|
+
const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
|
|
143
|
+
return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Item, {
|
|
144
|
+
onClick: handleClick,
|
|
145
|
+
classNames: "gap-2",
|
|
146
|
+
disabled: action.properties?.disabled,
|
|
147
|
+
...action.properties?.testId && {
|
|
148
|
+
"data-testid": action.properties.testId
|
|
149
|
+
}
|
|
150
|
+
}, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon, {
|
|
151
|
+
icon: action.properties.icon,
|
|
152
|
+
size: iconSize
|
|
153
|
+
}), /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
154
|
+
action
|
|
155
|
+
}));
|
|
165
156
|
};
|
|
166
157
|
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
|
-
|
|
158
|
+
const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
|
|
159
|
+
prop: open,
|
|
160
|
+
defaultProp: defaultOpen,
|
|
161
|
+
onChange: onOpenChange
|
|
162
|
+
});
|
|
163
|
+
const { onAction } = useMenu("DropdownMenuRoot", __menuScope);
|
|
164
|
+
const handleActionClick = useCallback((action, event) => {
|
|
165
|
+
if (action.properties?.disabled) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
event.stopPropagation();
|
|
169
|
+
setOptionsMenuOpen(false);
|
|
170
|
+
if (onAction) {
|
|
171
|
+
onAction(action, {
|
|
181
172
|
parent: group,
|
|
182
173
|
caller
|
|
183
174
|
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
175
|
+
} else {
|
|
176
|
+
void executeMenuAction(action, {
|
|
177
|
+
parent: group,
|
|
178
|
+
caller
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}, [
|
|
182
|
+
group,
|
|
183
|
+
caller,
|
|
184
|
+
onAction
|
|
185
|
+
]);
|
|
186
|
+
const items = useMenuItems(group, propsItems);
|
|
187
|
+
return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
|
|
188
|
+
open: optionsMenuOpen,
|
|
189
|
+
onOpenChange: setOptionsMenuOpen,
|
|
190
|
+
...naturalProps
|
|
191
|
+
}, children, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React3.createElement(DropdownMenuItem, {
|
|
192
|
+
key: item.id,
|
|
193
|
+
item,
|
|
194
|
+
onClick: handleActionClick
|
|
195
|
+
}))), /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Arrow, null))));
|
|
201
196
|
};
|
|
202
197
|
var DropdownMenu = {
|
|
203
198
|
Root: DropdownMenuRoot,
|
|
@@ -206,253 +201,223 @@ var DropdownMenu = {
|
|
|
206
201
|
};
|
|
207
202
|
|
|
208
203
|
// src/components/ToolbarMenu.tsx
|
|
209
|
-
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
210
204
|
import React4, { Fragment, useCallback as useCallback2 } from "react";
|
|
211
205
|
import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
212
206
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
213
|
-
import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/
|
|
207
|
+
import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/ui-theme";
|
|
214
208
|
|
|
215
209
|
// src/types.ts
|
|
216
|
-
import {
|
|
210
|
+
import { Node as Node2 } from "@dxos/app-graph";
|
|
217
211
|
var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
|
|
218
212
|
var isSeparator = (node) => node.type === MenuSeparatorType;
|
|
219
|
-
var isMenuGroup = (node) => node.type ===
|
|
213
|
+
var isMenuGroup = (node) => node.type === Node2.ActionGroupType;
|
|
220
214
|
|
|
221
215
|
// src/components/ToolbarMenu.tsx
|
|
222
216
|
var ActionToolbarItem = ({ action, __menuScope }) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
217
|
+
const { iconSize, onAction } = useMenu("ActionToolbarItem", __menuScope);
|
|
218
|
+
const { t } = useTranslation2(translationKey);
|
|
219
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
220
|
+
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
221
|
+
const rootProps = icon ? {
|
|
222
|
+
icon,
|
|
223
|
+
size: iconSize,
|
|
224
|
+
iconOnly,
|
|
225
|
+
label: actionLabel(action, t)
|
|
226
|
+
} : {
|
|
227
|
+
children: /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
228
228
|
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
|
-
}
|
|
229
|
+
})
|
|
230
|
+
};
|
|
231
|
+
const handleClick = useCallback2(() => {
|
|
232
|
+
if (onAction) {
|
|
233
|
+
onAction(action, {});
|
|
234
|
+
} else {
|
|
235
|
+
void executeMenuAction(action);
|
|
236
|
+
}
|
|
237
|
+
}, [
|
|
238
|
+
action,
|
|
239
|
+
onAction
|
|
240
|
+
]);
|
|
241
|
+
return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
|
|
242
|
+
key: action.id,
|
|
243
|
+
disabled,
|
|
244
|
+
onClick: handleClick,
|
|
245
|
+
variant: "ghost",
|
|
246
|
+
...testId && {
|
|
247
|
+
"data-testid": testId
|
|
248
|
+
},
|
|
249
|
+
...rootProps,
|
|
250
|
+
classNames
|
|
251
|
+
});
|
|
256
252
|
};
|
|
257
253
|
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
|
-
}
|
|
254
|
+
const { iconOnly, disabled, testId } = group.properties;
|
|
255
|
+
const { t } = useTranslation2(translationKey);
|
|
256
|
+
const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
|
|
257
|
+
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
258
|
+
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
259
|
+
const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
|
|
260
|
+
activeItem?.properties.icon || group.properties.icon;
|
|
261
|
+
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
262
|
+
const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
|
|
263
|
+
const rootProps = icon ? {
|
|
264
|
+
icon,
|
|
265
|
+
size: iconSize,
|
|
266
|
+
iconOnly,
|
|
267
|
+
label: actionLabel(labelAction, t),
|
|
268
|
+
caretDown: true
|
|
269
|
+
} : {
|
|
270
|
+
children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
271
|
+
action: labelAction
|
|
272
|
+
}), /* @__PURE__ */ React4.createElement(Icon2, {
|
|
273
|
+
size: 3,
|
|
274
|
+
icon: "ph--caret-down--bold",
|
|
275
|
+
classNames: "mis-1"
|
|
276
|
+
}))
|
|
277
|
+
};
|
|
278
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
|
|
279
|
+
group,
|
|
280
|
+
items
|
|
281
|
+
}, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
|
|
282
|
+
asChild: true
|
|
283
|
+
}, /* @__PURE__ */ React4.createElement(Root, {
|
|
284
|
+
variant: "ghost",
|
|
285
|
+
disabled,
|
|
286
|
+
...rootProps,
|
|
287
|
+
...testId && {
|
|
288
|
+
"data-testid": testId
|
|
289
|
+
}
|
|
290
|
+
})));
|
|
300
291
|
};
|
|
301
292
|
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
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
293
|
+
const { iconSize, onAction } = useMenu("ToggleGroupItem", __menuScope);
|
|
294
|
+
const { t } = useTranslation2(translationKey);
|
|
295
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
296
|
+
const handleClick = useCallback2(() => {
|
|
297
|
+
if (onAction) {
|
|
298
|
+
onAction(action, {
|
|
299
|
+
parent: group
|
|
300
|
+
});
|
|
301
|
+
} else {
|
|
302
|
+
void executeMenuAction(action, {
|
|
303
|
+
parent: group
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}, [
|
|
307
|
+
action,
|
|
308
|
+
group,
|
|
309
|
+
onAction
|
|
310
|
+
]);
|
|
311
|
+
const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
|
|
312
|
+
const rootProps = icon ? {
|
|
313
|
+
icon,
|
|
314
|
+
size: iconSize,
|
|
315
|
+
iconOnly,
|
|
316
|
+
label: actionLabel(action, t)
|
|
317
|
+
} : {
|
|
318
|
+
children: /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
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
|
|
333
|
+
});
|
|
339
334
|
};
|
|
340
335
|
var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
)
|
|
361
|
-
);
|
|
362
|
-
} finally {
|
|
363
|
-
_effect.f();
|
|
364
|
-
}
|
|
336
|
+
const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
|
|
337
|
+
const { selectCardinality, value } = group.properties;
|
|
338
|
+
return (
|
|
339
|
+
// TODO(thure): Fix.
|
|
340
|
+
// @ts-ignore
|
|
341
|
+
/* @__PURE__ */ React4.createElement(
|
|
342
|
+
NaturalToolbar.ToggleGroup,
|
|
343
|
+
{
|
|
344
|
+
type: selectCardinality,
|
|
345
|
+
value
|
|
346
|
+
},
|
|
347
|
+
// TODO(thure): Handle other menu item types.
|
|
348
|
+
items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
|
|
349
|
+
key: action.id,
|
|
350
|
+
group,
|
|
351
|
+
action
|
|
352
|
+
}))
|
|
353
|
+
)
|
|
354
|
+
);
|
|
365
355
|
};
|
|
366
|
-
var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth:
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
356
|
+
var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp, ...props }) => {
|
|
357
|
+
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
358
|
+
const { attendableId, alwaysActive } = useMenu("ToolbarMenu", __menuScope);
|
|
359
|
+
const { hasAttention } = useAttention(attendableId);
|
|
360
|
+
const InnerRoot = textBlockWidthProp ? "div" : Fragment;
|
|
361
|
+
const innerRootProps = textBlockWidthProp ? {
|
|
362
|
+
role: "none",
|
|
363
|
+
className: mx2(textBlockWidth, toolbarLayout, "bs-full")
|
|
364
|
+
} : {};
|
|
365
|
+
return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
|
|
366
|
+
...props,
|
|
367
|
+
classNames: [
|
|
368
|
+
attendableId,
|
|
369
|
+
classNames
|
|
370
|
+
],
|
|
371
|
+
disabled: !alwaysActive && !hasAttention,
|
|
372
|
+
layoutManaged: textBlockWidthProp
|
|
373
|
+
}, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React4.createElement(ToolbarMenuItem, {
|
|
374
|
+
key: item.id ?? i,
|
|
375
|
+
item
|
|
376
|
+
}))));
|
|
377
|
+
};
|
|
378
|
+
var ToolbarMenuItem = ({ item }) => {
|
|
379
|
+
if (isSeparator(item)) {
|
|
380
|
+
return /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
|
|
386
381
|
variant: item.properties.variant
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
if (isMenuGroup(item)) {
|
|
385
|
+
if (item.properties.variant === "dropdownMenu") {
|
|
386
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenuToolbarItem, {
|
|
391
387
|
group: item
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
/* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
|
|
396
|
-
key: item.id,
|
|
388
|
+
});
|
|
389
|
+
} else {
|
|
390
|
+
return /* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
|
|
397
391
|
group: item
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
// TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
|
|
401
|
-
/* @__PURE__ */ React4.createElement(ActionToolbarItem, {
|
|
402
|
-
key: item.id,
|
|
403
|
-
action: item
|
|
404
|
-
})
|
|
405
|
-
))));
|
|
406
|
-
} finally {
|
|
407
|
-
_effect.f();
|
|
392
|
+
});
|
|
393
|
+
}
|
|
408
394
|
}
|
|
395
|
+
return /* @__PURE__ */ React4.createElement(ActionToolbarItem, {
|
|
396
|
+
action: item
|
|
397
|
+
});
|
|
409
398
|
};
|
|
410
399
|
|
|
411
400
|
// src/hooks/useMenuActions.ts
|
|
412
|
-
import { RegistryContext,
|
|
413
|
-
import { useCallback as useCallback3, useContext,
|
|
414
|
-
import { Graph,
|
|
415
|
-
var edgesArrayToRecord = (edges) => {
|
|
416
|
-
return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
|
|
417
|
-
if (!acc[source]) {
|
|
418
|
-
acc[source] = {
|
|
419
|
-
inbound: [],
|
|
420
|
-
outbound: []
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
if (!acc[target]) {
|
|
424
|
-
acc[target] = {
|
|
425
|
-
inbound: [],
|
|
426
|
-
outbound: []
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
const sourceEdges = acc[source];
|
|
430
|
-
if (!sourceEdges.outbound.includes(target)) {
|
|
431
|
-
sourceEdges.outbound.push(target);
|
|
432
|
-
}
|
|
433
|
-
const targetEdges = acc[target];
|
|
434
|
-
if (!targetEdges.inbound.includes(source)) {
|
|
435
|
-
targetEdges.inbound.push(source);
|
|
436
|
-
}
|
|
437
|
-
return acc;
|
|
438
|
-
}, {})));
|
|
439
|
-
};
|
|
401
|
+
import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
402
|
+
import { useCallback as useCallback3, useContext, useRef } from "react";
|
|
403
|
+
import { Graph, Node as Node3 } from "@dxos/app-graph";
|
|
440
404
|
var useMenuActions = (props) => {
|
|
441
405
|
const registry = useContext(RegistryContext);
|
|
442
|
-
const menuGraphProps =
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
406
|
+
const menuGraphProps = useAtomValue(props);
|
|
407
|
+
const graphRef = useRef(null);
|
|
408
|
+
if (!graphRef.current || graphRef.current.props !== menuGraphProps) {
|
|
409
|
+
const newGraph = Graph.make({
|
|
410
|
+
registry
|
|
411
|
+
});
|
|
412
|
+
newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
413
|
+
graphRef.current = {
|
|
414
|
+
graph: newGraph,
|
|
415
|
+
props: menuGraphProps
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
const graph = graphRef.current.graph;
|
|
454
419
|
const useGroupItems = useCallback3((sourceNode) => {
|
|
455
|
-
const items =
|
|
420
|
+
const items = useAtomValue(graph.connections(sourceNode?.id || Node3.RootId));
|
|
456
421
|
return items;
|
|
457
422
|
}, [
|
|
458
423
|
graph
|
|
@@ -472,22 +437,16 @@ var MenuBuilder = Object.freeze({
|
|
|
472
437
|
}, "root")
|
|
473
438
|
});
|
|
474
439
|
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
440
|
+
_data;
|
|
441
|
+
_rootId;
|
|
475
442
|
constructor(_data, _rootId) {
|
|
476
443
|
this._data = _data;
|
|
477
444
|
this._rootId = _rootId;
|
|
478
445
|
}
|
|
479
|
-
action(id, invoke, properties) {
|
|
480
|
-
this._data.nodes.push(createMenuAction(id, invoke, properties));
|
|
481
|
-
this._data.edges.push({
|
|
482
|
-
source: this._rootId,
|
|
483
|
-
target: id
|
|
484
|
-
});
|
|
485
|
-
return this;
|
|
486
|
-
}
|
|
487
446
|
root(props) {
|
|
488
447
|
invariant(this._rootId === "root", "Root group can only be at the top level", {
|
|
489
448
|
F: __dxlog_file,
|
|
490
|
-
L:
|
|
449
|
+
L: 36,
|
|
491
450
|
S: this,
|
|
492
451
|
A: [
|
|
493
452
|
"this._rootId === 'root'",
|
|
@@ -496,7 +455,7 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
496
455
|
});
|
|
497
456
|
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
|
|
498
457
|
F: __dxlog_file,
|
|
499
|
-
L:
|
|
458
|
+
L: 37,
|
|
500
459
|
S: this,
|
|
501
460
|
A: [
|
|
502
461
|
"this._data.nodes.find((node) => node.id === 'root') === undefined",
|
|
@@ -506,8 +465,16 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
506
465
|
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
507
466
|
return this;
|
|
508
467
|
}
|
|
509
|
-
|
|
510
|
-
this._data.nodes.push(
|
|
468
|
+
action(id, props, invoke) {
|
|
469
|
+
this._data.nodes.push(createMenuAction(id, invoke, props));
|
|
470
|
+
this._data.edges.push({
|
|
471
|
+
source: this._rootId,
|
|
472
|
+
target: id
|
|
473
|
+
});
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
group(id, props, cb) {
|
|
477
|
+
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
511
478
|
this._data.edges.push({
|
|
512
479
|
source: this._rootId,
|
|
513
480
|
target: id
|
|
@@ -533,7 +500,6 @@ export {
|
|
|
533
500
|
isMenuGroup,
|
|
534
501
|
isSeparator,
|
|
535
502
|
menuContextDefaults,
|
|
536
|
-
rxFromSignal,
|
|
537
503
|
useMenu,
|
|
538
504
|
useMenuActions,
|
|
539
505
|
useMenuItems
|