@dxos/react-ui-menu 0.9.1-staging.ee54ba693a → 0.11.0
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/index.mjs +747 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/translations.mjs +7 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/builder.d.ts +1 -1
- package/dist/types/src/builder.d.ts.map +1 -1
- package/dist/types/src/components/ActionLabel.d.ts +0 -2
- package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
- package/dist/types/src/components/DropdownMenu.d.ts +2 -4
- package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +5 -15
- package/dist/types/src/components/Menu.d.ts.map +1 -1
- package/dist/types/src/components/MenuContext.d.ts +28 -0
- package/dist/types/src/components/MenuContext.d.ts.map +1 -0
- package/dist/types/src/components/ToolbarMenu.d.ts +2 -2
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +2 -2
- package/dist/types/src/components/action-label.d.ts +7 -0
- package/dist/types/src/components/action-label.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useGraphMenuActions.d.ts +13 -1
- package/dist/types/src/hooks/useGraphMenuActions.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/presentation.d.ts +8 -0
- package/dist/types/src/presentation.d.ts.map +1 -0
- package/dist/types/src/toolbar.d.ts +6 -0
- package/dist/types/src/toolbar.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +1 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +5 -3
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -20
- package/src/builder.ts +3 -3
- package/src/components/ActionLabel.tsx +1 -6
- package/src/components/DropdownMenu.tsx +30 -8
- package/src/components/Menu.stories.tsx +1 -1
- package/src/components/Menu.test.tsx +3 -2
- package/src/components/Menu.tsx +32 -122
- package/src/components/MenuContext.ts +129 -0
- package/src/components/ToolbarMenu.tsx +27 -13
- package/src/components/action-label.ts +20 -0
- package/src/components/index.ts +3 -0
- package/src/hooks/useGraphMenuActions.ts +16 -3
- package/src/index.ts +2 -0
- package/src/presentation.ts +19 -0
- package/src/toolbar.ts +11 -0
- package/src/types.ts +1 -1
- package/src/util.ts +2 -2
- package/dist/lib/browser/index.mjs +0 -797
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/translations.mjs +0 -16
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -799
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/translations.mjs +0 -18
- package/dist/lib/node-esm/translations.mjs.map +0 -7
|
@@ -1,797 +0,0 @@
|
|
|
1
|
-
// src/components/Menu.tsx
|
|
2
|
-
import { Atom, RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
3
|
-
import { createContextScope } from "@radix-ui/react-context";
|
|
4
|
-
import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
|
|
5
|
-
import React4, { createContext, useCallback as useCallback3, useContext, useMemo } from "react";
|
|
6
|
-
import { log } from "@dxos/log";
|
|
7
|
-
import { Icon as Icon2, DropdownMenu as NaturalDropdownMenu2 } from "@dxos/react-ui";
|
|
8
|
-
|
|
9
|
-
// src/util.ts
|
|
10
|
-
import * as Effect from "effect/Effect";
|
|
11
|
-
import { Node } from "@dxos/app-graph";
|
|
12
|
-
import { EffectEx } from "@dxos/effect";
|
|
13
|
-
import { getHostPlatform } from "@dxos/util";
|
|
14
|
-
var executeMenuAction = async (action, params = {}) => {
|
|
15
|
-
let effect = action.data(params);
|
|
16
|
-
if (action._actionContext) {
|
|
17
|
-
effect = effect.pipe(Effect.provide(action._actionContext));
|
|
18
|
-
}
|
|
19
|
-
await EffectEx.runAndForwardErrors(effect);
|
|
20
|
-
};
|
|
21
|
-
var getShortcut = (action) => {
|
|
22
|
-
return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
|
|
23
|
-
};
|
|
24
|
-
var createMenuAction = (id, invoke, properties) => ({
|
|
25
|
-
id,
|
|
26
|
-
type: Node.ActionType,
|
|
27
|
-
properties,
|
|
28
|
-
data: () => Effect.sync(invoke)
|
|
29
|
-
});
|
|
30
|
-
var createMenuItemGroup = (id, properties) => ({
|
|
31
|
-
id,
|
|
32
|
-
type: Node.ActionGroupType,
|
|
33
|
-
properties,
|
|
34
|
-
data: Node.actionGroupSymbol
|
|
35
|
-
});
|
|
36
|
-
var createGapSeparator = (id = "gap", source = "root") => ({
|
|
37
|
-
nodes: [
|
|
38
|
-
{
|
|
39
|
-
id,
|
|
40
|
-
type: "@dxos/react-ui-toolbar/separator",
|
|
41
|
-
properties: {
|
|
42
|
-
variant: "gap"
|
|
43
|
-
},
|
|
44
|
-
data: void 0
|
|
45
|
-
}
|
|
46
|
-
],
|
|
47
|
-
edges: [
|
|
48
|
-
{
|
|
49
|
-
source,
|
|
50
|
-
target: id,
|
|
51
|
-
relation: "child"
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
});
|
|
55
|
-
var createLineSeparator = (id = "line", source = "root") => ({
|
|
56
|
-
nodes: [
|
|
57
|
-
{
|
|
58
|
-
id,
|
|
59
|
-
type: "@dxos/react-ui-toolbar/separator",
|
|
60
|
-
properties: {
|
|
61
|
-
variant: "line"
|
|
62
|
-
},
|
|
63
|
-
data: void 0
|
|
64
|
-
}
|
|
65
|
-
],
|
|
66
|
-
edges: [
|
|
67
|
-
{
|
|
68
|
-
source,
|
|
69
|
-
target: id,
|
|
70
|
-
relation: "child"
|
|
71
|
-
}
|
|
72
|
-
]
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// src/components/ActionLabel.tsx
|
|
76
|
-
import React from "react";
|
|
77
|
-
import { keySymbols } from "@dxos/keyboard";
|
|
78
|
-
import { toLocalizedString, useTranslation } from "@dxos/react-ui";
|
|
79
|
-
import { mx } from "@dxos/ui-theme";
|
|
80
|
-
import { translationKey } from "#translations";
|
|
81
|
-
var ActionLabel = ({ action }) => {
|
|
82
|
-
const { t } = useTranslation(translationKey);
|
|
83
|
-
const shortcut = getShortcut(action);
|
|
84
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
|
|
85
|
-
className: "grow truncate"
|
|
86
|
-
}, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
|
|
87
|
-
className: mx("shrink-0", "text-description")
|
|
88
|
-
}, keySymbols(shortcut).join("")));
|
|
89
|
-
};
|
|
90
|
-
var actionLabel = (action, t) => {
|
|
91
|
-
const shortcut = getShortcut(action);
|
|
92
|
-
return `${toLocalizedString(action.properties.label, t)}${shortcut ? ` (${keySymbols(shortcut).join("")})` : ""}`;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// src/components/ToolbarMenu.tsx
|
|
96
|
-
import React3, { useCallback as useCallback2 } from "react";
|
|
97
|
-
import { Input, Toolbar as NaturalToolbar, Tooltip, toLocalizedString as toLocalizedString2, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
98
|
-
import { composable, composableProps } from "@dxos/react-ui";
|
|
99
|
-
import { useAttention } from "@dxos/react-ui-attention";
|
|
100
|
-
import { translationKey as translationKey2 } from "#translations";
|
|
101
|
-
|
|
102
|
-
// src/types.ts
|
|
103
|
-
import { Node as Node2 } from "@dxos/app-graph";
|
|
104
|
-
var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
|
|
105
|
-
var isSeparator = (node) => node.type === MenuSeparatorType;
|
|
106
|
-
var isMenuGroup = (node) => node.type === Node2.ActionGroupType;
|
|
107
|
-
|
|
108
|
-
// src/components/DropdownMenu.tsx
|
|
109
|
-
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
110
|
-
import React2, { useCallback } from "react";
|
|
111
|
-
import { Icon, DropdownMenu as NaturalDropdownMenu } from "@dxos/react-ui";
|
|
112
|
-
var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
|
|
113
|
-
const action = item;
|
|
114
|
-
const handleClick = useCallback((event) => onClick(action, event), [
|
|
115
|
-
action,
|
|
116
|
-
onClick
|
|
117
|
-
]);
|
|
118
|
-
const { iconSize } = useMenuScoped("DropdownMenuItem", __menuScope);
|
|
119
|
-
return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Item, {
|
|
120
|
-
onClick: handleClick,
|
|
121
|
-
classNames: "gap-2",
|
|
122
|
-
disabled: action.properties?.disabled,
|
|
123
|
-
...action.properties?.testId && {
|
|
124
|
-
"data-testid": action.properties.testId
|
|
125
|
-
}
|
|
126
|
-
}, action.properties?.icon && /* @__PURE__ */ React2.createElement(Icon, {
|
|
127
|
-
icon: action.properties.icon,
|
|
128
|
-
size: iconSize
|
|
129
|
-
}), /* @__PURE__ */ React2.createElement(ActionLabel, {
|
|
130
|
-
action
|
|
131
|
-
}));
|
|
132
|
-
};
|
|
133
|
-
var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, caller, children, __menuScope, ...naturalProps }) => {
|
|
134
|
-
const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
|
|
135
|
-
prop: open,
|
|
136
|
-
defaultProp: defaultOpen,
|
|
137
|
-
onChange: onOpenChange
|
|
138
|
-
});
|
|
139
|
-
const { onAction } = useMenuScoped("DropdownMenuRoot", __menuScope);
|
|
140
|
-
const handleActionClick = useCallback((action, event) => {
|
|
141
|
-
if (action.properties?.disabled) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
event.stopPropagation();
|
|
145
|
-
setOptionsMenuOpen(false);
|
|
146
|
-
if (onAction) {
|
|
147
|
-
onAction(action, {
|
|
148
|
-
parent: group,
|
|
149
|
-
caller
|
|
150
|
-
});
|
|
151
|
-
} else {
|
|
152
|
-
void executeMenuAction(action, {
|
|
153
|
-
parent: group,
|
|
154
|
-
caller
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}, [
|
|
158
|
-
group,
|
|
159
|
-
caller,
|
|
160
|
-
onAction
|
|
161
|
-
]);
|
|
162
|
-
const items = useMenuItems(group, propsItems);
|
|
163
|
-
return /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Root, {
|
|
164
|
-
open: optionsMenuOpen,
|
|
165
|
-
onOpenChange: setOptionsMenuOpen,
|
|
166
|
-
...naturalProps
|
|
167
|
-
}, children, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React2.createElement(DropdownMenuItem, {
|
|
168
|
-
key: item.id,
|
|
169
|
-
item,
|
|
170
|
-
onClick: handleActionClick
|
|
171
|
-
}))), /* @__PURE__ */ React2.createElement(NaturalDropdownMenu.Arrow, null))));
|
|
172
|
-
};
|
|
173
|
-
var DropdownMenu = {
|
|
174
|
-
Root: DropdownMenuRoot,
|
|
175
|
-
Trigger: NaturalDropdownMenu.Trigger,
|
|
176
|
-
VirtualTrigger: NaturalDropdownMenu.VirtualTrigger
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// src/components/ToolbarMenu.tsx
|
|
180
|
-
var ActionToolbarItem = ({ __menuScope, action }) => {
|
|
181
|
-
const { iconSize, onAction } = useMenuScoped("ActionToolbarItem", __menuScope);
|
|
182
|
-
const { t } = useTranslation2(translationKey2);
|
|
183
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
|
|
184
|
-
const buttonVariant = action.properties.variant === "primary" ? "primary" : "ghost";
|
|
185
|
-
const handleClick = useCallback2(() => {
|
|
186
|
-
if (onAction) {
|
|
187
|
-
onAction(action, {});
|
|
188
|
-
} else {
|
|
189
|
-
void executeMenuAction(action);
|
|
190
|
-
}
|
|
191
|
-
}, [
|
|
192
|
-
action,
|
|
193
|
-
onAction
|
|
194
|
-
]);
|
|
195
|
-
const commonProps = {
|
|
196
|
-
variant: buttonVariant,
|
|
197
|
-
disabled,
|
|
198
|
-
classNames,
|
|
199
|
-
onClick: handleClick,
|
|
200
|
-
...testId && {
|
|
201
|
-
"data-testid": testId
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
if (hidden) {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
return icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.IconButton, {
|
|
208
|
-
key: action.id,
|
|
209
|
-
...commonProps,
|
|
210
|
-
icon,
|
|
211
|
-
size: iconSize,
|
|
212
|
-
iconOnly,
|
|
213
|
-
iconClassNames,
|
|
214
|
-
label: actionLabel(action, t)
|
|
215
|
-
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
|
|
216
|
-
key: action.id,
|
|
217
|
-
...commonProps
|
|
218
|
-
}, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
219
|
-
action
|
|
220
|
-
}));
|
|
221
|
-
};
|
|
222
|
-
var SwitchToolbarItem = ({ __menuScope, action }) => {
|
|
223
|
-
const { onAction } = useMenuScoped("SwitchToolbarItem", __menuScope);
|
|
224
|
-
const { t } = useTranslation2(translationKey2);
|
|
225
|
-
const { label, iconOnly, disabled, testId, hidden, checked } = action.properties;
|
|
226
|
-
const labelStr = toLocalizedString2(label, t);
|
|
227
|
-
const handleCheckedChange = useCallback2(() => {
|
|
228
|
-
if (onAction) {
|
|
229
|
-
onAction(action, {});
|
|
230
|
-
} else {
|
|
231
|
-
void executeMenuAction(action);
|
|
232
|
-
}
|
|
233
|
-
}, [
|
|
234
|
-
action,
|
|
235
|
-
onAction
|
|
236
|
-
]);
|
|
237
|
-
if (hidden) {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
const switchInput = /* @__PURE__ */ React3.createElement(Input.Switch, {
|
|
241
|
-
checked,
|
|
242
|
-
disabled,
|
|
243
|
-
"aria-label": iconOnly ? labelStr : void 0,
|
|
244
|
-
onCheckedChange: handleCheckedChange,
|
|
245
|
-
...testId && {
|
|
246
|
-
"data-testid": testId
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
return /* @__PURE__ */ React3.createElement(Input.Root, null, iconOnly ? /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
250
|
-
asChild: true,
|
|
251
|
-
content: labelStr
|
|
252
|
-
}, /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput)) : /* @__PURE__ */ React3.createElement(Input.Block, null, switchInput), !iconOnly && /* @__PURE__ */ React3.createElement(Input.Label, null, labelStr));
|
|
253
|
-
};
|
|
254
|
-
var DropdownMenuToolbarItem = ({ __menuScope, group, items: propsItems }) => {
|
|
255
|
-
const { t } = useTranslation2(translationKey2);
|
|
256
|
-
const { iconSize } = useMenuScoped("DropdownMenuToolbarItem", __menuScope);
|
|
257
|
-
const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
|
|
258
|
-
const { iconOnly, disabled, testId, applyActive, caretDown = true, icon: groupIcon, iconClassNames: groupIconClassNames } = group.properties;
|
|
259
|
-
const activeItem = items?.find((item) => !!item.properties.checked);
|
|
260
|
-
const icon = applyActive && // TODO(thure): Handle other menu item types.
|
|
261
|
-
activeItem?.properties.icon || groupIcon;
|
|
262
|
-
const iconClassNames = applyActive && activeItem?.properties.iconClassNames || groupIconClassNames;
|
|
263
|
-
const labelAction = applyActive && activeItem ? activeItem : group;
|
|
264
|
-
return /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
|
|
265
|
-
group,
|
|
266
|
-
items
|
|
267
|
-
}, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
|
|
268
|
-
asChild: true
|
|
269
|
-
}, icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.IconButton, {
|
|
270
|
-
variant: "ghost",
|
|
271
|
-
disabled,
|
|
272
|
-
icon,
|
|
273
|
-
size: iconSize,
|
|
274
|
-
iconOnly,
|
|
275
|
-
iconClassNames,
|
|
276
|
-
label: actionLabel(labelAction, t),
|
|
277
|
-
caretDown,
|
|
278
|
-
...testId && {
|
|
279
|
-
"data-testid": testId
|
|
280
|
-
}
|
|
281
|
-
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
|
|
282
|
-
variant: "ghost",
|
|
283
|
-
disabled,
|
|
284
|
-
caretDown,
|
|
285
|
-
...testId && {
|
|
286
|
-
"data-testid": testId
|
|
287
|
-
}
|
|
288
|
-
}, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
289
|
-
action: labelAction
|
|
290
|
-
}))));
|
|
291
|
-
};
|
|
292
|
-
var ToggleGroupItem = ({ __menuScope, group, action }) => {
|
|
293
|
-
const { iconSize, onAction } = useMenuScoped("ToggleGroupItem", __menuScope);
|
|
294
|
-
const { t } = useTranslation2(translationKey2);
|
|
295
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = 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 commonProps = {
|
|
312
|
-
value: action.id,
|
|
313
|
-
disabled,
|
|
314
|
-
variant: "ghost",
|
|
315
|
-
classNames,
|
|
316
|
-
onClick: handleClick,
|
|
317
|
-
...testId && {
|
|
318
|
-
"data-testid": testId
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
return hidden ? null : icon ? /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupIconItem, {
|
|
322
|
-
...commonProps,
|
|
323
|
-
icon,
|
|
324
|
-
size: iconSize,
|
|
325
|
-
iconOnly,
|
|
326
|
-
iconClassNames,
|
|
327
|
-
label: actionLabel(action, t)
|
|
328
|
-
}) : /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, commonProps, /* @__PURE__ */ React3.createElement(ActionLabel, {
|
|
329
|
-
action
|
|
330
|
-
}));
|
|
331
|
-
};
|
|
332
|
-
var ToggleGroupToolbarItem = ({ __menuScope, group, items: itemsProp }) => {
|
|
333
|
-
const items = useMenuItems(group, itemsProp, "ToggleGroupToolbarItem", __menuScope);
|
|
334
|
-
const { selectCardinality } = group.properties;
|
|
335
|
-
const children = items.map((action) => /* @__PURE__ */ React3.createElement(ToggleGroupItem, {
|
|
336
|
-
key: action.id,
|
|
337
|
-
group,
|
|
338
|
-
action
|
|
339
|
-
}));
|
|
340
|
-
if (selectCardinality === "multiple") {
|
|
341
|
-
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
342
|
-
type: "multiple",
|
|
343
|
-
value: group.properties.value
|
|
344
|
-
}, children);
|
|
345
|
-
} else {
|
|
346
|
-
return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
|
|
347
|
-
type: "single",
|
|
348
|
-
value: group.properties.value
|
|
349
|
-
}, children);
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
var ToolbarMenu = composable(({ __menuScope, children, ...props }, forwardedRef) => {
|
|
353
|
-
const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
|
|
354
|
-
const { attendableId, alwaysActive } = useMenuScoped("ToolbarMenu", __menuScope);
|
|
355
|
-
const { hasAttention } = useAttention(attendableId);
|
|
356
|
-
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
|
|
357
|
-
...composableProps(props, {
|
|
358
|
-
classNames: attendableId
|
|
359
|
-
}),
|
|
360
|
-
disabled: !alwaysActive && !hasAttention,
|
|
361
|
-
ref: forwardedRef
|
|
362
|
-
}, items?.map((item) => /* @__PURE__ */ React3.createElement(ToolbarMenuItem, {
|
|
363
|
-
key: item.id,
|
|
364
|
-
__menuScope,
|
|
365
|
-
item
|
|
366
|
-
})), children);
|
|
367
|
-
});
|
|
368
|
-
var ToolbarMenuItem = ({ __menuScope, item }) => {
|
|
369
|
-
if (isSeparator(item)) {
|
|
370
|
-
return /* @__PURE__ */ React3.createElement(NaturalToolbar.Separator, {
|
|
371
|
-
variant: item.properties.variant
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
if (isMenuGroup(item)) {
|
|
375
|
-
if (item.properties.variant === "dropdownMenu") {
|
|
376
|
-
return /* @__PURE__ */ React3.createElement(DropdownMenuToolbarItem, {
|
|
377
|
-
__menuScope,
|
|
378
|
-
group: item
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
return /* @__PURE__ */ React3.createElement(ToggleGroupToolbarItem, {
|
|
382
|
-
__menuScope,
|
|
383
|
-
group: item
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
const action = item;
|
|
387
|
-
if (action.properties?.variant === "switch") {
|
|
388
|
-
return /* @__PURE__ */ React3.createElement(SwitchToolbarItem, {
|
|
389
|
-
__menuScope,
|
|
390
|
-
action
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
if (action.properties?.variant === "custom" && action.properties.render) {
|
|
394
|
-
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, action.properties.render());
|
|
395
|
-
}
|
|
396
|
-
return /* @__PURE__ */ React3.createElement(ActionToolbarItem, {
|
|
397
|
-
__menuScope,
|
|
398
|
-
action
|
|
399
|
-
});
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
// src/components/Menu.tsx
|
|
403
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/components/Menu.tsx";
|
|
404
|
-
var MENU_NAME = "Menu";
|
|
405
|
-
var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
|
|
406
|
-
var nullItemsAtom = Atom.make(null);
|
|
407
|
-
var defaultItemsAccessor = () => nullItemsAtom;
|
|
408
|
-
var menuContextDefaults = {
|
|
409
|
-
iconSize: 5,
|
|
410
|
-
items: defaultItemsAccessor,
|
|
411
|
-
onAction: void 0,
|
|
412
|
-
menuItemsAtom: Atom.make(/* @__PURE__ */ new Map()),
|
|
413
|
-
addMenuItems: () => {
|
|
414
|
-
},
|
|
415
|
-
removeMenuItems: () => {
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
var [MenuContextProvider, useMenuScoped] = createMenuContext(MENU_NAME, menuContextDefaults);
|
|
419
|
-
var useMenuScope = createMenuScope();
|
|
420
|
-
var MenuDropdownContext = /* @__PURE__ */ createContext({
|
|
421
|
-
closeMenu: () => {
|
|
422
|
-
}
|
|
423
|
-
});
|
|
424
|
-
var DEFAULT_PRIORITY = 100;
|
|
425
|
-
var sortMenuItems = (items) => [
|
|
426
|
-
...items
|
|
427
|
-
].sort((a, b) => a.priority !== b.priority ? a.priority - b.priority : a.id.localeCompare(b.id));
|
|
428
|
-
var MenuProvider = ({ children, items = menuContextDefaults.items, iconSize = menuContextDefaults.iconSize, attendableId, alwaysActive, onAction }) => {
|
|
429
|
-
const { scope } = useMenuScope(void 0);
|
|
430
|
-
const registry = useContext(RegistryContext);
|
|
431
|
-
const menuItemsAtom = useMemo(() => Atom.make(/* @__PURE__ */ new Map()).pipe(Atom.keepAlive), []);
|
|
432
|
-
const addMenuItems = useCallback3((props) => {
|
|
433
|
-
const priority = props.priority ?? DEFAULT_PRIORITY;
|
|
434
|
-
const prev = registry.get(menuItemsAtom);
|
|
435
|
-
const next = new Map(prev);
|
|
436
|
-
next.set(props.id, {
|
|
437
|
-
...props,
|
|
438
|
-
priority
|
|
439
|
-
});
|
|
440
|
-
registry.set(menuItemsAtom, next);
|
|
441
|
-
}, [
|
|
442
|
-
registry,
|
|
443
|
-
menuItemsAtom
|
|
444
|
-
]);
|
|
445
|
-
const removeMenuItems = useCallback3((id) => {
|
|
446
|
-
const prev = registry.get(menuItemsAtom);
|
|
447
|
-
const next = new Map(prev);
|
|
448
|
-
next.delete(id);
|
|
449
|
-
registry.set(menuItemsAtom, next);
|
|
450
|
-
}, [
|
|
451
|
-
registry,
|
|
452
|
-
menuItemsAtom
|
|
453
|
-
]);
|
|
454
|
-
return /* @__PURE__ */ React4.createElement(MenuContextProvider, {
|
|
455
|
-
items,
|
|
456
|
-
iconSize,
|
|
457
|
-
attendableId,
|
|
458
|
-
alwaysActive,
|
|
459
|
-
menuItemsAtom,
|
|
460
|
-
addMenuItems,
|
|
461
|
-
removeMenuItems,
|
|
462
|
-
onAction,
|
|
463
|
-
scope
|
|
464
|
-
}, children);
|
|
465
|
-
};
|
|
466
|
-
var resolveItems = (baseItems, group, entries) => {
|
|
467
|
-
const applicable = [
|
|
468
|
-
...entries.values()
|
|
469
|
-
].filter((entry) => !entry.groupFilter || entry.groupFilter(group));
|
|
470
|
-
if (applicable.length === 0) {
|
|
471
|
-
return baseItems;
|
|
472
|
-
}
|
|
473
|
-
const sorted = sortMenuItems(applicable);
|
|
474
|
-
const replacements = sorted.filter((entry) => entry.mode === "replacement");
|
|
475
|
-
if (replacements.length > 0) {
|
|
476
|
-
if (replacements.length > 1) {
|
|
477
|
-
log.warn("multiple replacement entries found", {
|
|
478
|
-
ids: replacements.map((r) => r.id).join(", "),
|
|
479
|
-
using: replacements[0].id
|
|
480
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 89, S: void 0 });
|
|
481
|
-
}
|
|
482
|
-
return replacements[0].items;
|
|
483
|
-
}
|
|
484
|
-
const additive = sorted.filter((entry) => entry.mode === "additive");
|
|
485
|
-
const additiveItems = additive.flatMap((entry) => entry.items);
|
|
486
|
-
if (!baseItems || baseItems.length === 0) {
|
|
487
|
-
return additiveItems.length > 0 ? additiveItems : null;
|
|
488
|
-
}
|
|
489
|
-
return [
|
|
490
|
-
...baseItems,
|
|
491
|
-
...additiveItems
|
|
492
|
-
];
|
|
493
|
-
};
|
|
494
|
-
var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
|
|
495
|
-
const { items, menuItemsAtom } = useMenuScoped(consumerName, __menuScope);
|
|
496
|
-
const groupItems = useAtomValue(items(group));
|
|
497
|
-
const entries = useAtomValue(menuItemsAtom) ?? /* @__PURE__ */ new Map();
|
|
498
|
-
const baseItems = useMemo(() => propsItems ?? groupItems ?? null, [
|
|
499
|
-
propsItems,
|
|
500
|
-
groupItems
|
|
501
|
-
]);
|
|
502
|
-
const resolved = useMemo(() => resolveItems(baseItems, group, entries), [
|
|
503
|
-
baseItems,
|
|
504
|
-
group,
|
|
505
|
-
entries
|
|
506
|
-
]);
|
|
507
|
-
return resolved ?? void 0;
|
|
508
|
-
};
|
|
509
|
-
var useMenu = (consumerName) => {
|
|
510
|
-
return useMenuScoped(consumerName, void 0);
|
|
511
|
-
};
|
|
512
|
-
var MenuRoot = ({ children, open, defaultOpen, onOpenChange, caller, ...props }) => {
|
|
513
|
-
const [menuOpen, setMenuOpen] = useControllableState2({
|
|
514
|
-
prop: open,
|
|
515
|
-
defaultProp: defaultOpen,
|
|
516
|
-
onChange: onOpenChange
|
|
517
|
-
});
|
|
518
|
-
const closeMenu = useCallback3(() => setMenuOpen(false), [
|
|
519
|
-
setMenuOpen
|
|
520
|
-
]);
|
|
521
|
-
return /* @__PURE__ */ React4.createElement(MenuProvider, props, /* @__PURE__ */ React4.createElement(MenuDropdownContext.Provider, {
|
|
522
|
-
value: {
|
|
523
|
-
closeMenu,
|
|
524
|
-
caller
|
|
525
|
-
}
|
|
526
|
-
}, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Root, {
|
|
527
|
-
open: menuOpen,
|
|
528
|
-
onOpenChange: setMenuOpen
|
|
529
|
-
}, children)));
|
|
530
|
-
};
|
|
531
|
-
var MenuContentItem = ({ item, onClick, __menuScope }) => {
|
|
532
|
-
const action = item;
|
|
533
|
-
const handleClick = useCallback3((event) => onClick(action, event), [
|
|
534
|
-
action,
|
|
535
|
-
onClick
|
|
536
|
-
]);
|
|
537
|
-
const { iconSize } = useMenuScoped("MenuContentItem", __menuScope);
|
|
538
|
-
return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Item, {
|
|
539
|
-
onClick: handleClick,
|
|
540
|
-
classNames: "gap-2",
|
|
541
|
-
disabled: action.properties?.disabled,
|
|
542
|
-
...action.properties?.testId && {
|
|
543
|
-
"data-testid": action.properties.testId
|
|
544
|
-
}
|
|
545
|
-
}, action.properties?.icon && /* @__PURE__ */ React4.createElement(Icon2, {
|
|
546
|
-
icon: action.properties.icon,
|
|
547
|
-
size: iconSize
|
|
548
|
-
}), /* @__PURE__ */ React4.createElement(ActionLabel, {
|
|
549
|
-
action
|
|
550
|
-
}));
|
|
551
|
-
};
|
|
552
|
-
var MenuContent = ({ group, items: propsItems, caller: callerOverride, __menuScope }) => {
|
|
553
|
-
const { closeMenu, caller: contextCaller } = useContext(MenuDropdownContext);
|
|
554
|
-
const caller = callerOverride ?? contextCaller;
|
|
555
|
-
const { onAction } = useMenuScoped("MenuContent", __menuScope);
|
|
556
|
-
const resolvedItems = useMenuItems(group, propsItems, "MenuContent", __menuScope);
|
|
557
|
-
const handleActionClick = useCallback3((action, event) => {
|
|
558
|
-
if (action.properties?.disabled) {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
event.stopPropagation();
|
|
562
|
-
closeMenu();
|
|
563
|
-
if (onAction) {
|
|
564
|
-
onAction(action, {
|
|
565
|
-
parent: group,
|
|
566
|
-
caller
|
|
567
|
-
});
|
|
568
|
-
} else {
|
|
569
|
-
void executeMenuAction(action, {
|
|
570
|
-
parent: group,
|
|
571
|
-
caller
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
}, [
|
|
575
|
-
group,
|
|
576
|
-
caller,
|
|
577
|
-
onAction,
|
|
578
|
-
closeMenu
|
|
579
|
-
]);
|
|
580
|
-
return /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Portal, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Viewport, null, resolvedItems?.map((item) => /* @__PURE__ */ React4.createElement(MenuContentItem, {
|
|
581
|
-
key: item.id,
|
|
582
|
-
item,
|
|
583
|
-
onClick: handleActionClick
|
|
584
|
-
}))), /* @__PURE__ */ React4.createElement(NaturalDropdownMenu2.Arrow, null)));
|
|
585
|
-
};
|
|
586
|
-
var Menu = {
|
|
587
|
-
Root: MenuRoot,
|
|
588
|
-
Trigger: NaturalDropdownMenu2.Trigger,
|
|
589
|
-
Content: MenuContent,
|
|
590
|
-
VirtualTrigger: NaturalDropdownMenu2.VirtualTrigger,
|
|
591
|
-
Toolbar: ToolbarMenu
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
// src/hooks/useGraphMenuActions.ts
|
|
595
|
-
import { Atom as Atom3 } from "@effect-atom/atom-react";
|
|
596
|
-
import { useMemo as useMemo3 } from "react";
|
|
597
|
-
import { Node as Node4 } from "@dxos/app-graph";
|
|
598
|
-
|
|
599
|
-
// src/hooks/useMenuActions.ts
|
|
600
|
-
import { Atom as Atom2, RegistryContext as RegistryContext2, useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
|
|
601
|
-
import { useCallback as useCallback4, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
602
|
-
import { Graph, Node as Node3 } from "@dxos/app-graph";
|
|
603
|
-
var useMenuActions = (props) => {
|
|
604
|
-
const registry = useContext2(RegistryContext2);
|
|
605
|
-
const menuGraphProps = useAtomValue2(props);
|
|
606
|
-
const graph = useMemo2(() => {
|
|
607
|
-
const newGraph = Graph.make({
|
|
608
|
-
registry
|
|
609
|
-
});
|
|
610
|
-
newGraph.pipe(Graph.addNodes(menuGraphProps.nodes), Graph.addEdges(menuGraphProps.edges));
|
|
611
|
-
return newGraph;
|
|
612
|
-
}, [
|
|
613
|
-
registry,
|
|
614
|
-
menuGraphProps
|
|
615
|
-
]);
|
|
616
|
-
const items = useCallback4((group) => {
|
|
617
|
-
return graph.connections(group?.id || Node3.RootId, "child");
|
|
618
|
-
}, [
|
|
619
|
-
graph
|
|
620
|
-
]);
|
|
621
|
-
return {
|
|
622
|
-
items
|
|
623
|
-
};
|
|
624
|
-
};
|
|
625
|
-
var useMenuBuilder = (build, deps) => {
|
|
626
|
-
const atom = useMemo2(() => Atom2.make(build), deps);
|
|
627
|
-
return useMenuActions(atom);
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
// src/hooks/useGraphMenuActions.ts
|
|
631
|
-
var buildGraphMenu = (resolve, nodeId, options = {}) => {
|
|
632
|
-
const { rootId = Node4.RootId, filter } = options;
|
|
633
|
-
const nodes = [];
|
|
634
|
-
const edges = [];
|
|
635
|
-
const seen = /* @__PURE__ */ new Set();
|
|
636
|
-
const visit = (parentId, sourceId) => {
|
|
637
|
-
for (const action of resolve(sourceId)) {
|
|
638
|
-
if (filter && !filter(action)) {
|
|
639
|
-
continue;
|
|
640
|
-
}
|
|
641
|
-
edges.push({
|
|
642
|
-
source: parentId,
|
|
643
|
-
target: action.id,
|
|
644
|
-
relation: "child"
|
|
645
|
-
});
|
|
646
|
-
if (seen.has(action.id)) {
|
|
647
|
-
continue;
|
|
648
|
-
}
|
|
649
|
-
seen.add(action.id);
|
|
650
|
-
nodes.push(action);
|
|
651
|
-
if (Node4.isActionGroup(action)) {
|
|
652
|
-
visit(action.id, action.id);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
visit(rootId, nodeId);
|
|
657
|
-
return {
|
|
658
|
-
nodes,
|
|
659
|
-
edges
|
|
660
|
-
};
|
|
661
|
-
};
|
|
662
|
-
var graphActions = (graph, get, nodeId, options) => graph && nodeId ? buildGraphMenu((id) => get(graph.actions(id)), nodeId, options) : {
|
|
663
|
-
nodes: [],
|
|
664
|
-
edges: []
|
|
665
|
-
};
|
|
666
|
-
var useGraphMenuActions = (graph, nodeId, options) => {
|
|
667
|
-
const atom = useMemo3(
|
|
668
|
-
() => Atom3.make((get) => graphActions(graph, get, nodeId, options)),
|
|
669
|
-
// `options` is expected to be stable; `rootId` participates since it reshapes the graph.
|
|
670
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
671
|
-
[
|
|
672
|
-
graph,
|
|
673
|
-
nodeId,
|
|
674
|
-
options?.rootId
|
|
675
|
-
]
|
|
676
|
-
);
|
|
677
|
-
return useMenuActions(atom);
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
// src/builder.ts
|
|
681
|
-
import { invariant } from "@dxos/invariant";
|
|
682
|
-
import { translationKey as translationKey3 } from "#translations";
|
|
683
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-menu/src/builder.ts";
|
|
684
|
-
var overflowMenuProperties = {
|
|
685
|
-
label: [
|
|
686
|
-
"toolbar-overflow.menu",
|
|
687
|
-
{
|
|
688
|
-
ns: translationKey3
|
|
689
|
-
}
|
|
690
|
-
],
|
|
691
|
-
icon: "ph--dots-three-vertical--regular",
|
|
692
|
-
iconOnly: true,
|
|
693
|
-
caretDown: false,
|
|
694
|
-
variant: "dropdownMenu"
|
|
695
|
-
};
|
|
696
|
-
var MenuBuilderImpl = class _MenuBuilderImpl {
|
|
697
|
-
_data;
|
|
698
|
-
_rootId;
|
|
699
|
-
_separatorCount = 0;
|
|
700
|
-
constructor(_data, _rootId) {
|
|
701
|
-
this._data = _data;
|
|
702
|
-
this._rootId = _rootId;
|
|
703
|
-
}
|
|
704
|
-
root(props) {
|
|
705
|
-
invariant(this._rootId === "root", "Root group can only be at the top level", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 29, S: this, A: ["this._rootId === 'root'", "'Root group can only be at the top level'"] });
|
|
706
|
-
invariant(this._data.nodes.find((node) => node.id === "root") === void 0, "Root group can only be created once", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 30, S: this, A: ["this._data.nodes.find((node)=>node.id === 'root') === undefined", "'Root group can only be created once'"] });
|
|
707
|
-
this._data.nodes.push(createMenuItemGroup("root", props));
|
|
708
|
-
return this;
|
|
709
|
-
}
|
|
710
|
-
build() {
|
|
711
|
-
return this._data;
|
|
712
|
-
}
|
|
713
|
-
action(id, props, invoke) {
|
|
714
|
-
this._data.nodes.push(createMenuAction(id, invoke, props));
|
|
715
|
-
this._data.edges.push({
|
|
716
|
-
source: this._rootId,
|
|
717
|
-
target: id,
|
|
718
|
-
relation: "child"
|
|
719
|
-
});
|
|
720
|
-
return this;
|
|
721
|
-
}
|
|
722
|
-
switch(id, props, invoke) {
|
|
723
|
-
return this.action(id, {
|
|
724
|
-
...props,
|
|
725
|
-
variant: "switch"
|
|
726
|
-
}, invoke);
|
|
727
|
-
}
|
|
728
|
-
group(id, props, cb) {
|
|
729
|
-
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
730
|
-
this._data.edges.push({
|
|
731
|
-
source: this._rootId,
|
|
732
|
-
target: id,
|
|
733
|
-
relation: "child"
|
|
734
|
-
});
|
|
735
|
-
cb(new _MenuBuilderImpl(this._data, id));
|
|
736
|
-
return this;
|
|
737
|
-
}
|
|
738
|
-
menu(id, cb) {
|
|
739
|
-
return this.group(id, overflowMenuProperties, cb);
|
|
740
|
-
}
|
|
741
|
-
subgraph(subgraphOrCb) {
|
|
742
|
-
if (!subgraphOrCb) {
|
|
743
|
-
return this;
|
|
744
|
-
}
|
|
745
|
-
if (typeof subgraphOrCb === "function") {
|
|
746
|
-
subgraphOrCb(new _MenuBuilderImpl(this._data, this._rootId));
|
|
747
|
-
} else {
|
|
748
|
-
this._data.nodes.push(...subgraphOrCb.nodes);
|
|
749
|
-
this._data.edges.push(...subgraphOrCb.edges);
|
|
750
|
-
}
|
|
751
|
-
return this;
|
|
752
|
-
}
|
|
753
|
-
separator(variant = "gap") {
|
|
754
|
-
const id = `separator-${++this._separatorCount}`;
|
|
755
|
-
this._data.nodes.push({
|
|
756
|
-
id,
|
|
757
|
-
type: MenuSeparatorType,
|
|
758
|
-
properties: {
|
|
759
|
-
variant
|
|
760
|
-
},
|
|
761
|
-
data: void 0
|
|
762
|
-
});
|
|
763
|
-
this._data.edges.push({
|
|
764
|
-
source: this._rootId,
|
|
765
|
-
target: id,
|
|
766
|
-
relation: "child"
|
|
767
|
-
});
|
|
768
|
-
return this;
|
|
769
|
-
}
|
|
770
|
-
};
|
|
771
|
-
var MenuBuilder = Object.freeze({
|
|
772
|
-
make: () => new MenuBuilderImpl({
|
|
773
|
-
nodes: [],
|
|
774
|
-
edges: []
|
|
775
|
-
}, "root")
|
|
776
|
-
});
|
|
777
|
-
export {
|
|
778
|
-
Menu,
|
|
779
|
-
MenuBuilder,
|
|
780
|
-
MenuSeparatorType,
|
|
781
|
-
buildGraphMenu,
|
|
782
|
-
createGapSeparator,
|
|
783
|
-
createLineSeparator,
|
|
784
|
-
createMenuAction,
|
|
785
|
-
createMenuItemGroup,
|
|
786
|
-
graphActions,
|
|
787
|
-
isMenuGroup,
|
|
788
|
-
isSeparator,
|
|
789
|
-
menuContextDefaults,
|
|
790
|
-
useGraphMenuActions,
|
|
791
|
-
useMenu,
|
|
792
|
-
useMenuActions,
|
|
793
|
-
useMenuBuilder,
|
|
794
|
-
useMenuItems,
|
|
795
|
-
useMenuScoped
|
|
796
|
-
};
|
|
797
|
-
//# sourceMappingURL=index.mjs.map
|