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