@dxos/react-ui-menu 0.8.4-main.b97322e → 0.8.4-main.bc674ce
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 +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 -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,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, useEffect,
|
|
414
|
-
import { Graph,
|
|
399
|
+
import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
400
|
+
import { useCallback as useCallback3, useContext, useEffect, 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,28 @@ 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
|
-
|
|
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);
|
|
448
440
|
useEffect(() => {
|
|
449
|
-
|
|
450
|
-
|
|
441
|
+
if (prevPropsRef.current !== menuGraphProps) {
|
|
442
|
+
prevPropsRef.current = menuGraphProps;
|
|
443
|
+
graph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
444
|
+
}
|
|
451
445
|
}, [
|
|
446
|
+
graph,
|
|
452
447
|
menuGraphProps
|
|
453
448
|
]);
|
|
454
449
|
const useGroupItems = useCallback3((sourceNode) => {
|
|
455
|
-
const items =
|
|
450
|
+
const items = useAtomValue(graph.connections(sourceNode?.id || Node3.RootId));
|
|
456
451
|
return items;
|
|
457
452
|
}, [
|
|
458
453
|
graph
|
|
@@ -472,22 +467,16 @@ var MenuBuilder = Object.freeze({
|
|
|
472
467
|
}, "root")
|
|
473
468
|
});
|
|
474
469
|
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
470
|
+
_data;
|
|
471
|
+
_rootId;
|
|
475
472
|
constructor(_data, _rootId) {
|
|
476
473
|
this._data = _data;
|
|
477
474
|
this._rootId = _rootId;
|
|
478
475
|
}
|
|
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
476
|
root(props) {
|
|
488
477
|
invariant(this._rootId === "root", "Root group can only be at the top level", {
|
|
489
478
|
F: __dxlog_file,
|
|
490
|
-
L:
|
|
479
|
+
L: 36,
|
|
491
480
|
S: this,
|
|
492
481
|
A: [
|
|
493
482
|
"this._rootId === 'root'",
|
|
@@ -496,7 +485,7 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
496
485
|
});
|
|
497
486
|
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", {
|
|
498
487
|
F: __dxlog_file,
|
|
499
|
-
L:
|
|
488
|
+
L: 37,
|
|
500
489
|
S: this,
|
|
501
490
|
A: [
|
|
502
491
|
"this._data.nodes.find((node) => node.id === 'root') === undefined",
|
|
@@ -506,8 +495,16 @@ var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
|
506
495
|
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
507
496
|
return this;
|
|
508
497
|
}
|
|
509
|
-
|
|
510
|
-
this._data.nodes.push(
|
|
498
|
+
action(id, props, invoke) {
|
|
499
|
+
this._data.nodes.push(createMenuAction(id, invoke, props));
|
|
500
|
+
this._data.edges.push({
|
|
501
|
+
source: this._rootId,
|
|
502
|
+
target: id
|
|
503
|
+
});
|
|
504
|
+
return this;
|
|
505
|
+
}
|
|
506
|
+
group(id, props, cb) {
|
|
507
|
+
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
511
508
|
this._data.edges.push({
|
|
512
509
|
source: this._rootId,
|
|
513
510
|
target: id
|
|
@@ -533,7 +530,6 @@ export {
|
|
|
533
530
|
isMenuGroup,
|
|
534
531
|
isSeparator,
|
|
535
532
|
menuContextDefaults,
|
|
536
|
-
rxFromSignal,
|
|
537
533
|
useMenu,
|
|
538
534
|
useMenuActions,
|
|
539
535
|
useMenuItems
|