@dxos/react-ui-menu 0.8.4-main.67995b8 → 0.8.4-main.69d29f4
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 -317
- 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 -317
- 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 +34 -31
- 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 +16 -4
- package/src/components/ToolbarMenu.stories.tsx +81 -0
- package/src/components/ToolbarMenu.tsx +68 -34
- package/src/hooks/useMenuActions.ts +32 -19
- 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,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,26 @@ 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
|
-
}, children);
|
|
126
|
-
} finally {
|
|
127
|
-
_effect.f();
|
|
128
|
-
}
|
|
115
|
+
var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId, onAction }) => {
|
|
116
|
+
const { scope } = useMenuScope(void 0);
|
|
117
|
+
return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
|
|
118
|
+
useGroupItems,
|
|
119
|
+
iconSize,
|
|
120
|
+
attendableId,
|
|
121
|
+
onAction,
|
|
122
|
+
scope
|
|
123
|
+
}, children);
|
|
129
124
|
};
|
|
130
125
|
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
131
126
|
const { useGroupItems } = useMenu(consumerName, __menuScope);
|
|
@@ -138,66 +133,65 @@ var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __m
|
|
|
138
133
|
|
|
139
134
|
// src/components/DropdownMenu.tsx
|
|
140
135
|
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
|
-
}
|
|
136
|
+
const action = item;
|
|
137
|
+
const handleClick = useCallback((event) => onClick(action, event), [
|
|
138
|
+
action,
|
|
139
|
+
onClick
|
|
140
|
+
]);
|
|
141
|
+
const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
|
|
142
|
+
return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Item, {
|
|
143
|
+
onClick: handleClick,
|
|
144
|
+
classNames: "gap-2",
|
|
145
|
+
disabled: action.properties?.disabled,
|
|
146
|
+
...action.properties?.testId && {
|
|
147
|
+
"data-testid": action.properties.testId
|
|
148
|
+
}
|
|
149
|
+
}, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon, {
|
|
150
|
+
icon: action.properties.icon,
|
|
151
|
+
size: iconSize
|
|
152
|
+
}), /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
153
|
+
action
|
|
154
|
+
}));
|
|
165
155
|
};
|
|
166
156
|
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
|
-
|
|
157
|
+
const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
|
|
158
|
+
prop: open,
|
|
159
|
+
defaultProp: defaultOpen,
|
|
160
|
+
onChange: onOpenChange
|
|
161
|
+
});
|
|
162
|
+
const { onAction } = useMenu("DropdownMenuRoot", __menuScope);
|
|
163
|
+
const handleActionClick = useCallback((action, event) => {
|
|
164
|
+
if (action.properties?.disabled) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
event.stopPropagation();
|
|
168
|
+
setOptionsMenuOpen(false);
|
|
169
|
+
if (onAction) {
|
|
170
|
+
onAction(action, {
|
|
181
171
|
parent: group,
|
|
182
172
|
caller
|
|
183
173
|
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
174
|
+
} else {
|
|
175
|
+
void executeMenuAction(action, {
|
|
176
|
+
parent: group,
|
|
177
|
+
caller
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}, [
|
|
181
|
+
group,
|
|
182
|
+
caller,
|
|
183
|
+
onAction
|
|
184
|
+
]);
|
|
185
|
+
const items = useMenuItems(group, propsItems);
|
|
186
|
+
return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
|
|
187
|
+
open: optionsMenuOpen,
|
|
188
|
+
onOpenChange: setOptionsMenuOpen,
|
|
189
|
+
...naturalProps
|
|
190
|
+
}, 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, {
|
|
191
|
+
key: item.id,
|
|
192
|
+
item,
|
|
193
|
+
onClick: handleActionClick
|
|
194
|
+
}))), /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Arrow, null))));
|
|
201
195
|
};
|
|
202
196
|
var DropdownMenu = {
|
|
203
197
|
Root: DropdownMenuRoot,
|
|
@@ -206,212 +200,205 @@ var DropdownMenu = {
|
|
|
206
200
|
};
|
|
207
201
|
|
|
208
202
|
// src/components/ToolbarMenu.tsx
|
|
209
|
-
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
210
203
|
import React4, { Fragment, useCallback as useCallback2 } from "react";
|
|
211
204
|
import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
212
205
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
213
|
-
import { mx as mx2, textBlockWidth, toolbarLayout } from "@dxos/
|
|
206
|
+
import { mx as mx2, textBlockWidth, toolbarInactive, toolbarLayout } from "@dxos/ui-theme";
|
|
214
207
|
|
|
215
208
|
// src/types.ts
|
|
216
|
-
import {
|
|
209
|
+
import { Node as Node2 } from "@dxos/app-graph";
|
|
217
210
|
var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
|
|
218
211
|
var isSeparator = (node) => node.type === MenuSeparatorType;
|
|
219
|
-
var isMenuGroup = (node) => node.type ===
|
|
212
|
+
var isMenuGroup = (node) => node.type === Node2.ActionGroupType;
|
|
220
213
|
|
|
221
214
|
// src/components/ToolbarMenu.tsx
|
|
222
215
|
var ActionToolbarItem = ({ action, __menuScope }) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
216
|
+
const { iconSize, onAction } = useMenu("ActionToolbarItem", __menuScope);
|
|
217
|
+
const { t } = useTranslation2(translationKey);
|
|
218
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
219
|
+
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
220
|
+
const rootProps = icon ? {
|
|
221
|
+
icon,
|
|
222
|
+
size: iconSize,
|
|
223
|
+
iconOnly,
|
|
224
|
+
label: actionLabel(action, t)
|
|
225
|
+
} : {
|
|
226
|
+
children: /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
228
227
|
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
|
-
}
|
|
228
|
+
})
|
|
229
|
+
};
|
|
230
|
+
const handleClick = useCallback2(() => {
|
|
231
|
+
if (onAction) {
|
|
232
|
+
onAction(action, {});
|
|
233
|
+
} else {
|
|
234
|
+
void executeMenuAction(action);
|
|
235
|
+
}
|
|
236
|
+
}, [
|
|
237
|
+
action,
|
|
238
|
+
onAction
|
|
239
|
+
]);
|
|
240
|
+
return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
|
|
241
|
+
key: action.id,
|
|
242
|
+
disabled,
|
|
243
|
+
onClick: handleClick,
|
|
244
|
+
variant: "ghost",
|
|
245
|
+
...testId && {
|
|
246
|
+
"data-testid": testId
|
|
247
|
+
},
|
|
248
|
+
...rootProps,
|
|
249
|
+
classNames
|
|
250
|
+
});
|
|
256
251
|
};
|
|
257
252
|
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
|
-
}
|
|
253
|
+
const { iconOnly, disabled, testId } = group.properties;
|
|
254
|
+
const { t } = useTranslation2(translationKey);
|
|
255
|
+
const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
|
|
256
|
+
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
257
|
+
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
258
|
+
const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
|
|
259
|
+
activeItem?.properties.icon || group.properties.icon;
|
|
260
|
+
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
261
|
+
const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
|
|
262
|
+
const rootProps = icon ? {
|
|
263
|
+
icon,
|
|
264
|
+
size: iconSize,
|
|
265
|
+
iconOnly,
|
|
266
|
+
label: actionLabel(labelAction, t),
|
|
267
|
+
caretDown: true
|
|
268
|
+
} : {
|
|
269
|
+
children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
270
|
+
action: labelAction
|
|
271
|
+
}), /* @__PURE__ */ React4.createElement(Icon2, {
|
|
272
|
+
size: 3,
|
|
273
|
+
icon: "ph--caret-down--bold",
|
|
274
|
+
classNames: "mis-1"
|
|
275
|
+
}))
|
|
276
|
+
};
|
|
277
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
|
|
278
|
+
group,
|
|
279
|
+
items
|
|
280
|
+
}, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
|
|
281
|
+
asChild: true
|
|
282
|
+
}, /* @__PURE__ */ React4.createElement(Root, {
|
|
283
|
+
variant: "ghost",
|
|
284
|
+
disabled,
|
|
285
|
+
...rootProps,
|
|
286
|
+
...testId && {
|
|
287
|
+
"data-testid": testId
|
|
288
|
+
}
|
|
289
|
+
})));
|
|
300
290
|
};
|
|
301
291
|
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
|
-
|
|
292
|
+
const { iconSize, onAction } = useMenu("ToggleGroupItem", __menuScope);
|
|
293
|
+
const { t } = useTranslation2(translationKey);
|
|
294
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
295
|
+
const handleClick = useCallback2(() => {
|
|
296
|
+
if (onAction) {
|
|
297
|
+
onAction(action, {
|
|
298
|
+
parent: group
|
|
299
|
+
});
|
|
300
|
+
} else {
|
|
301
|
+
void executeMenuAction(action, {
|
|
302
|
+
parent: group
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}, [
|
|
306
|
+
action,
|
|
307
|
+
group,
|
|
308
|
+
onAction
|
|
309
|
+
]);
|
|
310
|
+
const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
|
|
311
|
+
const rootProps = icon ? {
|
|
312
|
+
icon,
|
|
313
|
+
size: iconSize,
|
|
314
|
+
iconOnly,
|
|
315
|
+
label: actionLabel(action, t)
|
|
316
|
+
} : {
|
|
317
|
+
children: /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
318
|
+
action
|
|
319
|
+
})
|
|
320
|
+
};
|
|
321
|
+
return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
|
|
322
|
+
key: action.id,
|
|
323
|
+
value: action.id,
|
|
324
|
+
disabled,
|
|
325
|
+
onClick: handleClick,
|
|
326
|
+
variant: "ghost",
|
|
327
|
+
...testId && {
|
|
328
|
+
"data-testid": testId
|
|
329
|
+
},
|
|
330
|
+
...rootProps,
|
|
331
|
+
classNames
|
|
332
|
+
});
|
|
339
333
|
};
|
|
340
334
|
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
|
-
}
|
|
335
|
+
const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
|
|
336
|
+
const { selectCardinality, value } = group.properties;
|
|
337
|
+
return (
|
|
338
|
+
// TODO(thure): Fix.
|
|
339
|
+
// @ts-ignore
|
|
340
|
+
/* @__PURE__ */ React4.createElement(
|
|
341
|
+
NaturalToolbar.ToggleGroup,
|
|
342
|
+
{
|
|
343
|
+
type: selectCardinality,
|
|
344
|
+
value
|
|
345
|
+
},
|
|
346
|
+
// TODO(thure): Handle other menu item types.
|
|
347
|
+
items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
|
|
348
|
+
key: action.id,
|
|
349
|
+
group,
|
|
350
|
+
action
|
|
351
|
+
}))
|
|
352
|
+
)
|
|
353
|
+
);
|
|
365
354
|
};
|
|
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
|
-
|
|
355
|
+
var ToolbarMenu = ({ __menuScope, classNames, textBlockWidth: textBlockWidthProp, ...props }) => {
|
|
356
|
+
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
357
|
+
const { attendableId } = useMenu("ToolbarMenu", __menuScope);
|
|
358
|
+
const { hasAttention } = useAttention(attendableId);
|
|
359
|
+
const InnerRoot = textBlockWidthProp ? "div" : Fragment;
|
|
360
|
+
const innerRootProps = textBlockWidthProp ? {
|
|
361
|
+
role: "none",
|
|
362
|
+
className: mx2(textBlockWidth, toolbarLayout, "bs-full")
|
|
363
|
+
} : {};
|
|
364
|
+
return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
|
|
365
|
+
...props,
|
|
366
|
+
classNames: [
|
|
367
|
+
attendableId && !hasAttention && toolbarInactive,
|
|
368
|
+
classNames
|
|
369
|
+
],
|
|
370
|
+
layoutManaged: textBlockWidthProp
|
|
371
|
+
}, /* @__PURE__ */ React4.createElement(InnerRoot, innerRootProps, items?.map((item, i) => /* @__PURE__ */ React4.createElement(ToolbarMenuItem, {
|
|
372
|
+
key: item.id ?? i,
|
|
373
|
+
item
|
|
374
|
+
}))));
|
|
375
|
+
};
|
|
376
|
+
var ToolbarMenuItem = ({ item }) => {
|
|
377
|
+
if (isSeparator(item)) {
|
|
378
|
+
return /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
|
|
386
379
|
variant: item.properties.variant
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (isMenuGroup(item)) {
|
|
383
|
+
if (item.properties.variant === "dropdownMenu") {
|
|
384
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenuToolbarItem, {
|
|
391
385
|
group: item
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
/* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
|
|
396
|
-
key: item.id,
|
|
386
|
+
});
|
|
387
|
+
} else {
|
|
388
|
+
return /* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
|
|
397
389
|
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();
|
|
390
|
+
});
|
|
391
|
+
}
|
|
408
392
|
}
|
|
393
|
+
return /* @__PURE__ */ React4.createElement(ActionToolbarItem, {
|
|
394
|
+
action: item
|
|
395
|
+
});
|
|
409
396
|
};
|
|
410
397
|
|
|
411
398
|
// src/hooks/useMenuActions.ts
|
|
412
|
-
import { RegistryContext,
|
|
413
|
-
import { useCallback as useCallback3, useContext,
|
|
414
|
-
import { Graph,
|
|
399
|
+
import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
400
|
+
import { useCallback as useCallback3, useContext, useRef } from "react";
|
|
401
|
+
import { Graph, Node as Node3 } from "@dxos/app-graph";
|
|
415
402
|
var edgesArrayToRecord = (edges) => {
|
|
416
403
|
return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
|
|
417
404
|
if (!acc[source]) {
|
|
@@ -439,20 +426,23 @@ var edgesArrayToRecord = (edges) => {
|
|
|
439
426
|
};
|
|
440
427
|
var useMenuActions = (props) => {
|
|
441
428
|
const registry = useContext(RegistryContext);
|
|
442
|
-
const menuGraphProps =
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
429
|
+
const menuGraphProps = useAtomValue(props);
|
|
430
|
+
const graphRef = useRef(null);
|
|
431
|
+
if (!graphRef.current) {
|
|
432
|
+
graphRef.current = Graph.make({
|
|
433
|
+
registry,
|
|
434
|
+
nodes: menuGraphProps.nodes,
|
|
435
|
+
edges: edgesArrayToRecord(menuGraphProps.edges)
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
const graph = graphRef.current;
|
|
439
|
+
const prevPropsRef = useRef(menuGraphProps);
|
|
440
|
+
if (prevPropsRef.current !== menuGraphProps) {
|
|
441
|
+
prevPropsRef.current = menuGraphProps;
|
|
442
|
+
graph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
443
|
+
}
|
|
454
444
|
const useGroupItems = useCallback3((sourceNode) => {
|
|
455
|
-
const items =
|
|
445
|
+
const items = useAtomValue(graph.connections(sourceNode?.id || Node3.RootId));
|
|
456
446
|
return items;
|
|
457
447
|
}, [
|
|
458
448
|
graph
|
|
@@ -472,22 +462,16 @@ var MenuBuilder = Object.freeze({
|
|
|
472
462
|
}, "root")
|
|
473
463
|
});
|
|
474
464
|
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
465
|
+
_data;
|
|
466
|
+
_rootId;
|
|
475
467
|
constructor(_data, _rootId) {
|
|
476
468
|
this._data = _data;
|
|
477
469
|
this._rootId = _rootId;
|
|
478
470
|
}
|
|
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
471
|
root(props) {
|
|
488
472
|
invariant(this._rootId === "root", "Root group can only be at the top level", {
|
|
489
473
|
F: __dxlog_file,
|
|
490
|
-
L:
|
|
474
|
+
L: 36,
|
|
491
475
|
S: this,
|
|
492
476
|
A: [
|
|
493
477
|
"this._rootId === 'root'",
|
|
@@ -496,7 +480,7 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
496
480
|
});
|
|
497
481
|
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
|
|
498
482
|
F: __dxlog_file,
|
|
499
|
-
L:
|
|
483
|
+
L: 37,
|
|
500
484
|
S: this,
|
|
501
485
|
A: [
|
|
502
486
|
"this._data.nodes.find((node) => node.id === 'root') === undefined",
|
|
@@ -506,8 +490,16 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
506
490
|
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
507
491
|
return this;
|
|
508
492
|
}
|
|
509
|
-
|
|
510
|
-
this._data.nodes.push(
|
|
493
|
+
action(id, props, invoke) {
|
|
494
|
+
this._data.nodes.push(createMenuAction(id, invoke, props));
|
|
495
|
+
this._data.edges.push({
|
|
496
|
+
source: this._rootId,
|
|
497
|
+
target: id
|
|
498
|
+
});
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
group(id, props, cb) {
|
|
502
|
+
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
511
503
|
this._data.edges.push({
|
|
512
504
|
source: this._rootId,
|
|
513
505
|
target: id
|
|
@@ -533,7 +525,6 @@ export {
|
|
|
533
525
|
isMenuGroup,
|
|
534
526
|
isSeparator,
|
|
535
527
|
menuContextDefaults,
|
|
536
|
-
rxFromSignal,
|
|
537
528
|
useMenu,
|
|
538
529
|
useMenuActions,
|
|
539
530
|
useMenuItems
|