@dxos/react-ui-menu 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a
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 +50 -2
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +50 -2
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/builder.d.ts +4 -0
- package/dist/types/src/builder.d.ts.map +1 -1
- package/dist/types/src/components/Menu.d.ts +1 -1
- package/dist/types/src/components/Menu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
- package/dist/types/src/components/ToolbarMenu.stories.d.ts +4 -0
- package/dist/types/src/components/ToolbarMenu.stories.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/util.d.ts +2 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -25
- package/src/builder.ts +7 -0
- package/src/components/Menu.tsx +2 -2
- package/src/components/ToolbarMenu.stories.tsx +31 -2
- package/src/components/ToolbarMenu.tsx +61 -2
- package/src/index.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-menu",
|
|
3
|
-
"version": "0.9.1-
|
|
3
|
+
"version": "0.9.1-staging.ee54ba693a",
|
|
4
4
|
"description": "Components for facilitating reactive and consistent menus.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -37,39 +37,39 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@radix-ui/react-context": "1.1.1",
|
|
39
39
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
40
|
-
"@dxos/app-graph": "0.9.1-
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/react-ui-attention": "0.9.1-
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
40
|
+
"@dxos/app-graph": "0.9.1-staging.ee54ba693a",
|
|
41
|
+
"@dxos/invariant": "0.9.1-staging.ee54ba693a",
|
|
42
|
+
"@dxos/keyboard": "0.9.1-staging.ee54ba693a",
|
|
43
|
+
"@dxos/effect": "0.9.1-staging.ee54ba693a",
|
|
44
|
+
"@dxos/react-ui-attention": "0.9.1-staging.ee54ba693a",
|
|
45
|
+
"@dxos/util": "0.9.1-staging.ee54ba693a",
|
|
46
|
+
"@dxos/log": "0.9.1-staging.ee54ba693a",
|
|
47
|
+
"@dxos/ui-types": "0.9.1-staging.ee54ba693a"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@effect-atom/atom-react": "^0.5.0",
|
|
51
|
-
"@effect/platform": "0.96.
|
|
51
|
+
"@effect/platform": "0.96.2",
|
|
52
52
|
"@testing-library/jest-dom": "^6.9.1",
|
|
53
|
-
"@testing-library/react": "^16.3.
|
|
54
|
-
"@types/react": "~19.2.
|
|
53
|
+
"@testing-library/react": "^16.3.2",
|
|
54
|
+
"@types/react": "~19.2.17",
|
|
55
55
|
"@types/react-dom": "~19.2.3",
|
|
56
|
-
"effect": "3.21.
|
|
57
|
-
"react": "~19.2.
|
|
58
|
-
"react-dom": "~19.2.
|
|
56
|
+
"effect": "3.21.4",
|
|
57
|
+
"react": "~19.2.7",
|
|
58
|
+
"react-dom": "~19.2.7",
|
|
59
59
|
"vite": "^8.0.16",
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/ui
|
|
63
|
-
"@dxos/
|
|
60
|
+
"@dxos/random": "0.9.1-staging.ee54ba693a",
|
|
61
|
+
"@dxos/storybook-utils": "0.9.1-staging.ee54ba693a",
|
|
62
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a",
|
|
63
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@effect-atom/atom-react": "^0.5.0",
|
|
67
|
-
"@effect/platform": "0.96.
|
|
68
|
-
"effect": "3.21.
|
|
69
|
-
"react": "~19.2.
|
|
70
|
-
"react-dom": "~19.2.
|
|
71
|
-
"@dxos/ui-theme": "0.9.1-
|
|
72
|
-
"@dxos/react-ui": "0.9.1-
|
|
67
|
+
"@effect/platform": "0.96.2",
|
|
68
|
+
"effect": "3.21.4",
|
|
69
|
+
"react": "~19.2.7",
|
|
70
|
+
"react-dom": "~19.2.7",
|
|
71
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
|
|
72
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a"
|
|
73
73
|
},
|
|
74
74
|
"publishConfig": {
|
|
75
75
|
"access": "public"
|
package/src/builder.ts
CHANGED
|
@@ -41,6 +41,9 @@ export interface ActionGroupBuilder {
|
|
|
41
41
|
/** Add an action node as a child of the current group. */
|
|
42
42
|
action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;
|
|
43
43
|
|
|
44
|
+
/** Add a switch action rendered as a labeled Input.Switch. */
|
|
45
|
+
switch(id: string, props: Omit<MenuActionProperties, 'variant'> & { checked: boolean }, invoke: () => void): this;
|
|
46
|
+
|
|
44
47
|
/** Add a nested action group. */
|
|
45
48
|
group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this;
|
|
46
49
|
|
|
@@ -94,6 +97,10 @@ class MenuBuilderImpl implements MenuBuilder {
|
|
|
94
97
|
return this;
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
switch(id: string, props: Omit<MenuActionProperties, 'variant'> & { checked: boolean }, invoke: () => void): this {
|
|
101
|
+
return this.action(id, { ...props, variant: 'switch' }, invoke);
|
|
102
|
+
}
|
|
103
|
+
|
|
97
104
|
group(id: string, props: MenuItemGroupProperties, cb: ActionGroupBuilderFn): this {
|
|
98
105
|
this._data.nodes.push(createMenuItemGroup(id, props));
|
|
99
106
|
this._data.edges.push({ source: this._rootId, target: id, relation: 'child' });
|
package/src/components/Menu.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
6
6
|
import { type Scope, createContextScope } from '@radix-ui/react-context';
|
|
7
7
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
8
|
-
import React, {
|
|
8
|
+
import React, { type MouseEvent, type PropsWithChildren, createContext, useCallback, useContext, useMemo } from 'react';
|
|
9
9
|
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
import { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';
|
|
@@ -334,10 +334,10 @@ export { Menu, menuContextDefaults, useMenu, useMenuItems, useMenuScoped };
|
|
|
334
334
|
export type { MenuContentProps, MenuRootProps, MenuScopedProps };
|
|
335
335
|
|
|
336
336
|
export type {
|
|
337
|
-
ToolbarMenuProps,
|
|
338
337
|
ToolbarMenuActionGroupProperties,
|
|
339
338
|
ToolbarMenuActionGroupProps,
|
|
340
339
|
ToolbarMenuActionProps,
|
|
341
340
|
ToolbarMenuDropdownMenuActionGroup,
|
|
341
|
+
ToolbarMenuProps,
|
|
342
342
|
ToolbarMenuToggleGroupActionGroup,
|
|
343
343
|
} from './ToolbarMenu';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Atom, RegistryContext } from '@effect-atom/atom-react';
|
|
6
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
-
import React, { useContext, useMemo } from 'react';
|
|
7
|
+
import React, { useContext, useMemo, useState } from 'react';
|
|
8
8
|
|
|
9
9
|
import { random } from '@dxos/random';
|
|
10
10
|
import { IconButton } from '@dxos/react-ui';
|
|
@@ -13,8 +13,9 @@ import { withRegistry } from '@dxos/storybook-utils';
|
|
|
13
13
|
|
|
14
14
|
import { translations } from '#translations';
|
|
15
15
|
|
|
16
|
+
import { MenuBuilder } from '../builder';
|
|
16
17
|
import { Menu } from '../components';
|
|
17
|
-
import { type ActionGraphProps, useMenuActions } from '../hooks';
|
|
18
|
+
import { type ActionGraphProps, useMenuActions, useMenuBuilder } from '../hooks';
|
|
18
19
|
import { createActions, createNestedActions, createNestedActionsResolver, useMutateActions } from '../testing';
|
|
19
20
|
|
|
20
21
|
random.seed(1234);
|
|
@@ -93,3 +94,31 @@ export const UseMenuActionsToolbar: Story = {
|
|
|
93
94
|
);
|
|
94
95
|
},
|
|
95
96
|
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Toolbar with both labeled and tooltip-only (iconOnly) Input.Switch items.
|
|
100
|
+
*/
|
|
101
|
+
export const SwitchToolbar: Story = {
|
|
102
|
+
render: () => {
|
|
103
|
+
const [wordWrap, setWordWrap] = useState(false);
|
|
104
|
+
const [lineNumbers, setLineNumbers] = useState(true);
|
|
105
|
+
|
|
106
|
+
const menuActions = useMenuBuilder(
|
|
107
|
+
() =>
|
|
108
|
+
MenuBuilder.make()
|
|
109
|
+
.root({ label: 'Editor settings' })
|
|
110
|
+
.switch('word-wrap', { label: 'Word wrap', checked: wordWrap }, () => setWordWrap((v) => !v))
|
|
111
|
+
.switch('line-numbers', { label: 'Line numbers', iconOnly: true, checked: lineNumbers }, () =>
|
|
112
|
+
setLineNumbers((v) => !v),
|
|
113
|
+
)
|
|
114
|
+
.build(),
|
|
115
|
+
[wordWrap, lineNumbers],
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Menu.Root {...menuActions} alwaysActive>
|
|
120
|
+
<Menu.Toolbar />
|
|
121
|
+
</Menu.Root>
|
|
122
|
+
);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Input,
|
|
9
|
+
Toolbar as NaturalToolbar,
|
|
10
|
+
type ToolbarRootProps,
|
|
11
|
+
Tooltip,
|
|
12
|
+
toLocalizedString,
|
|
13
|
+
useTranslation,
|
|
14
|
+
} from '@dxos/react-ui';
|
|
8
15
|
import { composable, composableProps } from '@dxos/react-ui';
|
|
9
16
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
10
17
|
import { type DropdownMenuItemGroupProperties, type ToggleGroupMenuItemGroupProperties } from '@dxos/ui-types';
|
|
@@ -90,6 +97,48 @@ const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: Me
|
|
|
90
97
|
);
|
|
91
98
|
};
|
|
92
99
|
|
|
100
|
+
const SwitchToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: MenuAction }>) => {
|
|
101
|
+
const { onAction } = useMenuScoped('SwitchToolbarItem', __menuScope);
|
|
102
|
+
const { t } = useTranslation(translationKey);
|
|
103
|
+
const { label, iconOnly, disabled, testId, hidden, checked } = action.properties;
|
|
104
|
+
const labelStr = toLocalizedString(label, t);
|
|
105
|
+
|
|
106
|
+
const handleCheckedChange = useCallback(() => {
|
|
107
|
+
if (onAction) {
|
|
108
|
+
onAction(action, {});
|
|
109
|
+
} else {
|
|
110
|
+
void executeMenuAction(action);
|
|
111
|
+
}
|
|
112
|
+
}, [action, onAction]);
|
|
113
|
+
|
|
114
|
+
if (hidden) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const switchInput = (
|
|
119
|
+
<Input.Switch
|
|
120
|
+
checked={checked}
|
|
121
|
+
disabled={disabled}
|
|
122
|
+
aria-label={iconOnly ? labelStr : undefined}
|
|
123
|
+
onCheckedChange={handleCheckedChange}
|
|
124
|
+
{...(testId && { 'data-testid': testId })}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<Input.Root>
|
|
130
|
+
{iconOnly ? (
|
|
131
|
+
<Tooltip.Trigger asChild content={labelStr}>
|
|
132
|
+
<Input.Block>{switchInput}</Input.Block>
|
|
133
|
+
</Tooltip.Trigger>
|
|
134
|
+
) : (
|
|
135
|
+
<Input.Block>{switchInput}</Input.Block>
|
|
136
|
+
)}
|
|
137
|
+
{!iconOnly && <Input.Label>{labelStr}</Input.Label>}
|
|
138
|
+
</Input.Root>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
93
142
|
const DropdownMenuToolbarItem = ({
|
|
94
143
|
__menuScope,
|
|
95
144
|
group,
|
|
@@ -257,5 +306,15 @@ const ToolbarMenuItem = ({ __menuScope, item }: MenuScopedProps<{ item: MenuItem
|
|
|
257
306
|
);
|
|
258
307
|
}
|
|
259
308
|
|
|
260
|
-
|
|
309
|
+
const action = item as MenuAction;
|
|
310
|
+
if (action.properties?.variant === 'switch') {
|
|
311
|
+
return <SwitchToolbarItem __menuScope={__menuScope} action={action} />;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// The contributor owns the rendered element (interactions the action model cannot express).
|
|
315
|
+
if (action.properties?.variant === 'custom' && action.properties.render) {
|
|
316
|
+
return <>{action.properties.render()}</>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return <ActionToolbarItem __menuScope={__menuScope} action={action} />;
|
|
261
320
|
};
|
package/src/index.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
export * from './components';
|
|
6
6
|
export * from './hooks';
|
|
7
7
|
export * from './types';
|
|
8
|
-
export {
|
|
8
|
+
export { createGapSeparator, createLineSeparator, createMenuAction, createMenuItemGroup } from './util';
|
|
9
9
|
export { type ActionGroupBuilder, type ActionGroupBuilderFn, MenuBuilder } from './builder';
|