@dxos/react-ui-menu 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a
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/LICENSE +102 -5
- package/dist/lib/browser/index.mjs +115 -136
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +14 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +115 -136
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +16 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/builder.d.ts +23 -4
- package/dist/types/src/builder.d.ts.map +1 -1
- package/dist/types/src/builder.test.d.ts +2 -0
- package/dist/types/src/builder.test.d.ts.map +1 -0
- package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
- package/dist/types/src/components/DropdownMenu.d.ts +3 -1
- package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +8 -4
- package/dist/types/src/components/Menu.d.ts.map +1 -1
- package/dist/types/src/components/{MenuItems.stories.d.ts → Menu.stories.d.ts} +1 -1
- package/dist/types/src/components/Menu.stories.d.ts.map +1 -0
- package/dist/types/src/components/ToolbarMenu.d.ts +4 -4
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +15 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useMenuActions.d.ts +9 -1
- package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +8 -4
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +2 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +2 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -22
- package/src/builder.test.ts +224 -0
- package/src/builder.ts +41 -18
- package/src/components/ActionLabel.tsx +2 -1
- package/src/components/DropdownMenu.tsx +0 -1
- package/src/components/{MenuItems.stories.tsx → Menu.stories.tsx} +2 -1
- package/src/components/Menu.test.tsx +0 -1
- package/src/components/Menu.tsx +9 -10
- package/src/components/ToolbarMenu.stories.tsx +27 -12
- package/src/components/ToolbarMenu.tsx +118 -85
- package/src/hooks/useMenuActions.ts +19 -8
- package/src/index.ts +1 -1
- package/src/testing/generator.ts +15 -10
- package/src/types.ts +1 -0
- package/dist/types/src/components/MenuItems.stories.d.ts.map +0 -1
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, {
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Icon, Toolbar as NaturalToolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
9
|
-
import {
|
|
9
|
+
import { composable, composableProps } from '@dxos/ui-theme';
|
|
10
10
|
import { type MenuActionProperties } from '@dxos/ui-types';
|
|
11
11
|
|
|
12
|
-
import { translationKey } from '
|
|
12
|
+
import { translationKey } from '#translations';
|
|
13
|
+
|
|
13
14
|
import {
|
|
14
15
|
type MenuAction,
|
|
15
16
|
type MenuItem,
|
|
@@ -20,7 +21,6 @@ import {
|
|
|
20
21
|
isSeparator,
|
|
21
22
|
} from '../types';
|
|
22
23
|
import { executeMenuAction } from '../util';
|
|
23
|
-
|
|
24
24
|
import { ActionLabel, actionLabel } from './ActionLabel';
|
|
25
25
|
import { DropdownMenu } from './DropdownMenu';
|
|
26
26
|
import { type MenuScopedProps, useMenuItems, useMenuScoped } from './Menu';
|
|
@@ -41,7 +41,7 @@ export type ToolbarMenuActionGroupProperties = (
|
|
|
41
41
|
) &
|
|
42
42
|
(MenuSingleSelectActionGroup | MenuMultipleSelectActionGroup);
|
|
43
43
|
|
|
44
|
-
export type ToolbarMenuProps = ToolbarRootProps
|
|
44
|
+
export type ToolbarMenuProps = ToolbarRootProps;
|
|
45
45
|
|
|
46
46
|
export type ToolbarMenuActionGroupProps = {
|
|
47
47
|
group: MenuItemGroup<ToolbarMenuActionGroupProperties>;
|
|
@@ -53,15 +53,13 @@ export type ToolbarMenuActionProps = {
|
|
|
53
53
|
action: MenuAction;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
const ActionToolbarItem = ({
|
|
56
|
+
const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: MenuAction }>) => {
|
|
57
57
|
const { iconSize, onAction } = useMenuScoped('ActionToolbarItem', __menuScope);
|
|
58
58
|
const { t } = useTranslation(translationKey);
|
|
59
59
|
|
|
60
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }
|
|
64
|
-
: { children: <ActionLabel action={action} /> };
|
|
60
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
|
|
61
|
+
const buttonVariant =
|
|
62
|
+
(action.properties as { variant?: string }).variant === 'primary' ? ('primary' as const) : ('ghost' as const);
|
|
65
63
|
|
|
66
64
|
const handleClick = useCallback(() => {
|
|
67
65
|
if (onAction) {
|
|
@@ -71,23 +69,39 @@ const ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: Me
|
|
|
71
69
|
}
|
|
72
70
|
}, [action, onAction]);
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
const commonProps = {
|
|
73
|
+
variant: buttonVariant,
|
|
74
|
+
disabled,
|
|
75
|
+
classNames,
|
|
76
|
+
onClick: handleClick,
|
|
77
|
+
...(testId && { 'data-testid': testId }),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (hidden) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return icon ? (
|
|
85
|
+
<NaturalToolbar.IconButton
|
|
76
86
|
key={action.id}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
{
|
|
82
|
-
|
|
87
|
+
{...commonProps}
|
|
88
|
+
icon={icon}
|
|
89
|
+
size={iconSize}
|
|
90
|
+
iconOnly={iconOnly}
|
|
91
|
+
iconClassNames={iconClassNames}
|
|
92
|
+
label={actionLabel(action, t)}
|
|
83
93
|
/>
|
|
94
|
+
) : (
|
|
95
|
+
<NaturalToolbar.Button key={action.id} {...commonProps}>
|
|
96
|
+
<ActionLabel action={action} />
|
|
97
|
+
</NaturalToolbar.Button>
|
|
84
98
|
);
|
|
85
99
|
};
|
|
86
100
|
|
|
87
101
|
const DropdownMenuToolbarItem = ({
|
|
102
|
+
__menuScope,
|
|
88
103
|
group,
|
|
89
104
|
items: propsItems,
|
|
90
|
-
__menuScope,
|
|
91
105
|
}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {
|
|
92
106
|
const { iconOnly, disabled, testId } = group.properties;
|
|
93
107
|
const { t } = useTranslation(translationKey);
|
|
@@ -99,6 +113,11 @@ const DropdownMenuToolbarItem = ({
|
|
|
99
113
|
// TODO(thure): Handle other menu item types.
|
|
100
114
|
(activeItem as MenuAction)?.properties.icon) ||
|
|
101
115
|
group.properties.icon;
|
|
116
|
+
// Follow the same `applyActive` rule for `iconClassNames` so a per-item
|
|
117
|
+
// accent (e.g. tag colour) tracks the displayed icon.
|
|
118
|
+
const iconClassNames =
|
|
119
|
+
((group.properties as any).applyActive && (activeItem as MenuAction)?.properties.iconClassNames) ||
|
|
120
|
+
(group.properties as { iconClassNames?: any }).iconClassNames;
|
|
102
121
|
const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
|
|
103
122
|
const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;
|
|
104
123
|
const rootProps = icon
|
|
@@ -106,6 +125,7 @@ const DropdownMenuToolbarItem = ({
|
|
|
106
125
|
icon,
|
|
107
126
|
size: iconSize,
|
|
108
127
|
iconOnly,
|
|
128
|
+
iconClassNames,
|
|
109
129
|
label: actionLabel(labelAction, t),
|
|
110
130
|
caretDown: true,
|
|
111
131
|
}
|
|
@@ -127,10 +147,11 @@ const DropdownMenuToolbarItem = ({
|
|
|
127
147
|
);
|
|
128
148
|
};
|
|
129
149
|
|
|
130
|
-
const ToggleGroupItem = ({ group, action
|
|
150
|
+
const ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<ToolbarMenuActionProps>) => {
|
|
131
151
|
const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);
|
|
132
152
|
const { t } = useTranslation(translationKey);
|
|
133
|
-
const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
|
|
153
|
+
const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
|
|
154
|
+
|
|
134
155
|
const handleClick = useCallback(() => {
|
|
135
156
|
if (onAction) {
|
|
136
157
|
onAction(action, { parent: group });
|
|
@@ -138,91 +159,103 @@ const ToggleGroupItem = ({ group, action, __menuScope }: MenuScopedProps<Toolbar
|
|
|
138
159
|
void executeMenuAction(action, { parent: group });
|
|
139
160
|
}
|
|
140
161
|
}, [action, group, onAction]);
|
|
141
|
-
const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
|
|
142
|
-
const rootProps = icon
|
|
143
|
-
? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }
|
|
144
|
-
: { children: <ActionLabel action={action} /> };
|
|
145
162
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
const commonProps = {
|
|
164
|
+
value: action.id,
|
|
165
|
+
disabled,
|
|
166
|
+
variant: 'ghost' as const,
|
|
167
|
+
classNames,
|
|
168
|
+
onClick: handleClick,
|
|
169
|
+
...(testId && { 'data-testid': testId }),
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return hidden ? null : icon ? (
|
|
173
|
+
<NaturalToolbar.ToggleGroupIconItem
|
|
174
|
+
{...commonProps}
|
|
175
|
+
icon={icon}
|
|
176
|
+
size={iconSize}
|
|
177
|
+
iconOnly={iconOnly}
|
|
178
|
+
iconClassNames={iconClassNames}
|
|
179
|
+
label={actionLabel(action, t)}
|
|
156
180
|
/>
|
|
181
|
+
) : (
|
|
182
|
+
<NaturalToolbar.ToggleGroupItem {...commonProps}>
|
|
183
|
+
<ActionLabel action={action} />
|
|
184
|
+
</NaturalToolbar.ToggleGroupItem>
|
|
157
185
|
);
|
|
158
186
|
};
|
|
159
187
|
|
|
160
188
|
const ToggleGroupToolbarItem = ({
|
|
161
|
-
group,
|
|
162
|
-
items: propsItems,
|
|
163
189
|
__menuScope,
|
|
190
|
+
group,
|
|
191
|
+
items: itemsProp,
|
|
164
192
|
}: MenuScopedProps<ToolbarMenuActionGroupProps>) => {
|
|
165
|
-
const items = useMenuItems(group,
|
|
166
|
-
const { selectCardinality
|
|
193
|
+
const items = useMenuItems(group, itemsProp, 'ToggleGroupToolbarItem', __menuScope);
|
|
194
|
+
const { selectCardinality } = group.properties;
|
|
167
195
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
196
|
+
// TODO(thure): Handle other menu item types.
|
|
197
|
+
const children = (items as MenuAction[]).map((action) => (
|
|
198
|
+
<ToggleGroupItem key={action.id} group={group} action={action} />
|
|
199
|
+
));
|
|
200
|
+
|
|
201
|
+
if (selectCardinality === 'multiple') {
|
|
202
|
+
return (
|
|
203
|
+
<NaturalToolbar.ToggleGroup type='multiple' value={group.properties.value}>
|
|
204
|
+
{children}
|
|
205
|
+
</NaturalToolbar.ToggleGroup>
|
|
206
|
+
);
|
|
207
|
+
} else {
|
|
208
|
+
return (
|
|
209
|
+
<NaturalToolbar.ToggleGroup type='single' value={group.properties.value}>
|
|
210
|
+
{children}
|
|
211
|
+
</NaturalToolbar.ToggleGroup>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
180
214
|
};
|
|
181
215
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
...props
|
|
188
|
-
}: MenuScopedProps<ToolbarMenuProps>) => {
|
|
189
|
-
const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);
|
|
190
|
-
const { attendableId, alwaysActive } = useMenuScoped('ToolbarMenu', __menuScope);
|
|
191
|
-
const { hasAttention } = useAttention(attendableId);
|
|
192
|
-
const InnerRoot = textBlockWidthProp ? 'div' : Fragment;
|
|
193
|
-
const innerRootProps = textBlockWidthProp
|
|
194
|
-
? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'h-full') }
|
|
195
|
-
: {};
|
|
216
|
+
export const ToolbarMenu = composable<HTMLDivElement, MenuScopedProps<ToolbarMenuProps>>(
|
|
217
|
+
({ __menuScope, children, ...props }, forwardedRef) => {
|
|
218
|
+
const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);
|
|
219
|
+
const { attendableId, alwaysActive } = useMenuScoped('ToolbarMenu', __menuScope);
|
|
220
|
+
const { hasAttention } = useAttention(attendableId);
|
|
196
221
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
{items?.map((item: MenuItem, i: number) => (
|
|
206
|
-
<ToolbarMenuItem key={item.id ?? i} item={item} />
|
|
222
|
+
return (
|
|
223
|
+
<NaturalToolbar.Root
|
|
224
|
+
{...composableProps(props, { classNames: attendableId })}
|
|
225
|
+
disabled={!alwaysActive && !hasAttention}
|
|
226
|
+
ref={forwardedRef}
|
|
227
|
+
>
|
|
228
|
+
{items?.map((item: MenuItem) => (
|
|
229
|
+
<ToolbarMenuItem key={item.id} __menuScope={__menuScope} item={item} />
|
|
207
230
|
))}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
231
|
+
{children}
|
|
232
|
+
</NaturalToolbar.Root>
|
|
233
|
+
);
|
|
234
|
+
},
|
|
235
|
+
);
|
|
212
236
|
|
|
213
|
-
const ToolbarMenuItem = ({ item }: { item: MenuItem }) => {
|
|
237
|
+
const ToolbarMenuItem = ({ __menuScope, item }: MenuScopedProps<{ item: MenuItem }>) => {
|
|
214
238
|
if (isSeparator(item)) {
|
|
215
239
|
return <NaturalToolbar.Separator variant={item.properties.variant} />;
|
|
216
240
|
}
|
|
217
241
|
|
|
218
|
-
// TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
|
|
219
242
|
if (isMenuGroup(item)) {
|
|
220
243
|
if (item.properties.variant === 'dropdownMenu') {
|
|
221
|
-
return
|
|
244
|
+
return (
|
|
245
|
+
<DropdownMenuToolbarItem
|
|
246
|
+
__menuScope={__menuScope}
|
|
247
|
+
group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>}
|
|
248
|
+
/>
|
|
249
|
+
);
|
|
222
250
|
} else {
|
|
223
|
-
return
|
|
251
|
+
return (
|
|
252
|
+
<ToggleGroupToolbarItem
|
|
253
|
+
__menuScope={__menuScope}
|
|
254
|
+
group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>}
|
|
255
|
+
/>
|
|
256
|
+
);
|
|
224
257
|
}
|
|
225
258
|
}
|
|
226
259
|
|
|
227
|
-
return <ActionToolbarItem action={item as MenuAction} />;
|
|
260
|
+
return <ActionToolbarItem __menuScope={__menuScope} action={item as MenuAction} />;
|
|
228
261
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { useCallback, useContext,
|
|
5
|
+
import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import { type DependencyList, useCallback, useContext, useMemo } from 'react';
|
|
7
7
|
|
|
8
8
|
import { Graph, Node } from '@dxos/app-graph';
|
|
9
9
|
|
|
@@ -26,14 +26,13 @@ export const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions
|
|
|
26
26
|
|
|
27
27
|
// Create a new graph whenever props change to preserve correct order.
|
|
28
28
|
// (Graph.addEdges appends rather than replaces, which breaks ordering on updates.)
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// NOTE: Using useMemo rather than a ref-mutation pattern to avoid calling registry.set during render,
|
|
30
|
+
// which would trigger atom state updates in other components (setState-in-render React warning).
|
|
31
|
+
const graph = useMemo(() => {
|
|
31
32
|
const newGraph = Graph.make({ registry });
|
|
32
33
|
newGraph.pipe(Graph.addNodes(menuGraphProps.nodes as Node.NodeArg<any>[]), Graph.addEdges(menuGraphProps.edges));
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const graph = graphRef.current.graph;
|
|
34
|
+
return newGraph;
|
|
35
|
+
}, [registry, menuGraphProps]);
|
|
37
36
|
|
|
38
37
|
const items: MenuItemsAccessor = useCallback(
|
|
39
38
|
(group?: MenuItemGroup) => {
|
|
@@ -45,3 +44,15 @@ export const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions
|
|
|
45
44
|
|
|
46
45
|
return { items };
|
|
47
46
|
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Convenience wrapper around `useMenuActions` that creates the backing atom inline.
|
|
50
|
+
* Pass a builder thunk and a dependency list — the hook memoizes `Atom.make(build)` and threads
|
|
51
|
+
* it through `useMenuActions`. Saves the `useMemo(() => Atom.make(...), deps)` boilerplate when
|
|
52
|
+
* the action graph is composed from local state (e.g. a toolbar driven by component state).
|
|
53
|
+
*/
|
|
54
|
+
export const useMenuBuilder = (build: (get: Atom.Context) => ActionGraphProps, deps: DependencyList): MenuActions => {
|
|
55
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
56
|
+
const atom = useMemo(() => Atom.make(build), deps);
|
|
57
|
+
return useMenuActions(atom);
|
|
58
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -6,4 +6,4 @@ export * from './components';
|
|
|
6
6
|
export * from './hooks';
|
|
7
7
|
export * from './types';
|
|
8
8
|
export { createMenuAction, createMenuItemGroup, createLineSeparator, createGapSeparator } from './util';
|
|
9
|
-
export { MenuBuilder } from './builder';
|
|
9
|
+
export { type ActionGroupBuilder, type ActionGroupBuilderFn, MenuBuilder } from './builder';
|
package/src/testing/generator.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Atom, RegistryContext } from '@effect-atom/atom-react';
|
|
5
|
+
import { Atom, Registry, RegistryContext } from '@effect-atom/atom-react';
|
|
6
6
|
import { useContext, useEffect } from 'react';
|
|
7
7
|
|
|
8
8
|
import { Graph, Node } from '@dxos/app-graph';
|
|
9
|
-
import {
|
|
9
|
+
import { random } from '@dxos/random';
|
|
10
10
|
|
|
11
11
|
import { type ActionGraphProps } from '../hooks/useMenuActions';
|
|
12
12
|
import { type MenuItem, type MenuItemGroup, type MenuItemsAccessor } from '../types';
|
|
@@ -38,15 +38,15 @@ const icons = {
|
|
|
38
38
|
|
|
39
39
|
export const createActions = (params?: CreateActionsProps) => {
|
|
40
40
|
const { callback = () => console.log('invoke'), count = 12, type = Node.ActionType } = params ?? {};
|
|
41
|
-
return
|
|
41
|
+
return random.helpers.multiple(
|
|
42
42
|
() => ({
|
|
43
|
-
id:
|
|
43
|
+
id: random.string.uuid(),
|
|
44
44
|
type,
|
|
45
45
|
data: type === Node.ActionGroupType ? Node.actionGroupSymbol : callback,
|
|
46
46
|
properties: {
|
|
47
|
-
label:
|
|
48
|
-
icon:
|
|
49
|
-
disabled:
|
|
47
|
+
label: random.lorem.words(2),
|
|
48
|
+
icon: random.helpers.arrayElement(icons[random.helpers.arrayElement(Object.keys(icons)) as keyof typeof icons]),
|
|
49
|
+
disabled: random.helpers.arrayElement([true, false]),
|
|
50
50
|
...(type === Node.ActionGroupType && { variant: 'dropdownMenu' }),
|
|
51
51
|
},
|
|
52
52
|
}),
|
|
@@ -70,8 +70,13 @@ const buildNestedActions = (): ActionGraphProps => {
|
|
|
70
70
|
|
|
71
71
|
export const createNestedActions = Atom.make(buildNestedActions()).pipe(Atom.keepAlive);
|
|
72
72
|
|
|
73
|
-
export const createNestedActionsResolver = (
|
|
74
|
-
|
|
73
|
+
export const createNestedActionsResolver = (props?: {
|
|
74
|
+
groupParams?: CreateActionsProps;
|
|
75
|
+
params?: CreateActionsProps;
|
|
76
|
+
registry?: Registry.Registry;
|
|
77
|
+
}) => {
|
|
78
|
+
const { groupParams, params, registry } = props ?? {};
|
|
79
|
+
const graph = Graph.make({ ...(registry && { registry }) });
|
|
75
80
|
const actionGroups = createActions({ type: Node.ActionGroupType, ...groupParams });
|
|
76
81
|
actionGroups.forEach((group) => {
|
|
77
82
|
const actions = createActions(params);
|
|
@@ -107,7 +112,7 @@ export const useMutateActions = (actionsAtom: Atom.Writable<ActionGraphProps>) =
|
|
|
107
112
|
...node,
|
|
108
113
|
properties: {
|
|
109
114
|
...node.properties,
|
|
110
|
-
icon:
|
|
115
|
+
icon: random.helpers.arrayElement(node.properties?.icon?.endsWith('regular') ? icons.fill : icons.regular),
|
|
111
116
|
disabled: !node.properties?.disabled,
|
|
112
117
|
},
|
|
113
118
|
};
|
package/src/types.ts
CHANGED
|
@@ -50,6 +50,7 @@ export type MenuContextValue = {
|
|
|
50
50
|
items: MenuItemsAccessor;
|
|
51
51
|
iconSize: IconButtonProps['size'];
|
|
52
52
|
attendableId?: string;
|
|
53
|
+
/** TODO(burdon): Remove and assume always active if attendableId is undefined. */
|
|
53
54
|
/** If true, the menu is always active regardless of attention state. */
|
|
54
55
|
alwaysActive?: boolean;
|
|
55
56
|
/** Atom holding the current set of imperatively added menu items. */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MenuItems.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/MenuItems.stories.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAuC,MAAM,OAAO,CAAC;AAgB5D,QAAA,MAAM,IAAI;;;;;;;;;;;CAOwB,CAAC;AAEnC,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA0CnC,eAAO,MAAM,WAAW,EAAE,KAsBzB,CAAC;AAaF,eAAO,MAAM,aAAa,EAAE,KA8C3B,CAAC;AAsBF,eAAO,MAAM,eAAe,EAAE,KAqB7B,CAAC;AA0CF,eAAO,MAAM,gBAAgB,EAAE,KAuB9B,CAAC"}
|