@dxos/react-ui-menu 0.8.4-main.f9ba587 → 0.8.4-main.fffef41

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.
Files changed (43) hide show
  1. package/dist/lib/browser/index.mjs +63 -53
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +63 -53
  5. package/dist/lib/node-esm/index.mjs.map +3 -3
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/builder.d.ts +2 -2
  8. package/dist/types/src/builder.d.ts.map +1 -1
  9. package/dist/types/src/components/ActionLabel.d.ts +1 -1
  10. package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
  11. package/dist/types/src/components/DropdownMenu.d.ts +1 -1
  12. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  13. package/dist/types/src/components/MenuContext.d.ts +3 -1
  14. package/dist/types/src/components/MenuContext.d.ts.map +1 -1
  15. package/dist/types/src/components/ToolbarMenu.d.ts +2 -2
  16. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
  17. package/dist/types/src/components/ToolbarMenu.stories.d.ts +20 -0
  18. package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -0
  19. package/dist/types/src/hooks/useMenuActions.d.ts +3 -2
  20. package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
  21. package/dist/types/src/index.d.ts +1 -1
  22. package/dist/types/src/index.d.ts.map +1 -1
  23. package/dist/types/src/testing/generator.d.ts +4 -4
  24. package/dist/types/src/testing/generator.d.ts.map +1 -1
  25. package/dist/types/src/types.d.ts +2 -2
  26. package/dist/types/src/types.d.ts.map +1 -1
  27. package/dist/types/src/util.d.ts +1 -1
  28. package/dist/types/src/util.d.ts.map +1 -1
  29. package/dist/types/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +26 -25
  31. package/src/builder.ts +10 -10
  32. package/src/components/ActionLabel.tsx +3 -3
  33. package/src/components/DropdownMenu.tsx +6 -3
  34. package/src/components/MenuContext.tsx +7 -3
  35. package/src/components/{Menus.stories.tsx → ToolbarMenu.stories.tsx} +14 -10
  36. package/src/components/ToolbarMenu.tsx +45 -30
  37. package/src/hooks/useMenuActions.ts +13 -6
  38. package/src/index.ts +1 -1
  39. package/src/testing/generator.ts +6 -6
  40. package/src/types.ts +2 -2
  41. package/src/util.ts +7 -2
  42. package/dist/types/src/components/Menus.stories.d.ts +0 -25
  43. package/dist/types/src/components/Menus.stories.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-menu",
3
- "version": "0.8.4-main.f9ba587",
3
+ "version": "0.8.4-main.fffef41",
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",
@@ -10,6 +10,7 @@
10
10
  "type": "module",
11
11
  "exports": {
12
12
  ".": {
13
+ "source": "./src/index.ts",
13
14
  "types": "./dist/types/src/index.d.ts",
14
15
  "browser": "./dist/lib/browser/index.mjs",
15
16
  "node": "./dist/lib/node-esm/index.mjs"
@@ -25,38 +26,38 @@
25
26
  ],
26
27
  "dependencies": {
27
28
  "@preact-signals/safe-react": "^0.9.0",
28
- "@preact/signals-react": "^3.2.0",
29
+ "@preact/signals-react": "^3.3.0",
29
30
  "@radix-ui/react-context": "1.1.1",
30
31
  "@radix-ui/react-use-controllable-state": "1.1.0",
31
- "@dxos/app-graph": "0.8.4-main.f9ba587",
32
- "@dxos/invariant": "0.8.4-main.f9ba587",
33
- "@dxos/keyboard": "0.8.4-main.f9ba587",
34
- "@dxos/react-ui-attention": "0.8.4-main.f9ba587",
35
- "@dxos/util": "0.8.4-main.f9ba587"
32
+ "@dxos/app-graph": "0.8.4-main.fffef41",
33
+ "@dxos/invariant": "0.8.4-main.fffef41",
34
+ "@dxos/react-ui-attention": "0.8.4-main.fffef41",
35
+ "@dxos/keyboard": "0.8.4-main.fffef41",
36
+ "@dxos/util": "0.8.4-main.fffef41"
36
37
  },
37
38
  "devDependencies": {
38
- "@effect-rx/rx-react": "0.38.0",
39
- "@effect/platform": "0.88.0",
40
- "@types/react": "~18.2.0",
41
- "@types/react-dom": "~18.2.0",
42
- "effect": "3.16.13",
43
- "react": "~18.2.0",
44
- "react-dom": "~18.2.0",
45
- "vite": "5.4.7",
46
- "@dxos/live-object": "0.8.4-main.f9ba587",
47
- "@dxos/random": "0.8.4-main.f9ba587",
48
- "@dxos/react-ui-theme": "0.8.4-main.f9ba587",
49
- "@dxos/react-ui": "0.8.4-main.f9ba587",
50
- "@dxos/storybook-utils": "0.8.4-main.f9ba587"
39
+ "@effect-atom/atom-react": "^0.3.4",
40
+ "@effect/platform": "0.92.1",
41
+ "@types/react": "~19.2.2",
42
+ "@types/react-dom": "~19.2.2",
43
+ "effect": "3.18.3",
44
+ "react": "~19.2.0",
45
+ "react-dom": "~19.2.0",
46
+ "vite": "7.1.9",
47
+ "@dxos/live-object": "0.8.4-main.fffef41",
48
+ "@dxos/random": "0.8.4-main.fffef41",
49
+ "@dxos/react-ui": "0.8.4-main.fffef41",
50
+ "@dxos/react-ui-theme": "0.8.4-main.fffef41",
51
+ "@dxos/storybook-utils": "0.8.4-main.fffef41"
51
52
  },
52
53
  "peerDependencies": {
53
- "@effect-rx/rx-react": "^0.34.1",
54
+ "@effect-atom/atom-react": "^0.3.4",
54
55
  "@effect/platform": "^0.80.12",
55
56
  "effect": "^3.13.3",
56
- "react": "~18.2.0",
57
- "react-dom": "~18.2.0",
58
- "@dxos/react-ui": "0.8.4-main.f9ba587",
59
- "@dxos/react-ui-theme": "0.8.4-main.f9ba587"
57
+ "react": "^19.0.0",
58
+ "react-dom": "^19.0.0",
59
+ "@dxos/react-ui": "0.8.4-main.fffef41",
60
+ "@dxos/react-ui-theme": "0.8.4-main.fffef41"
60
61
  },
61
62
  "publishConfig": {
62
63
  "access": "public"
package/src/builder.ts CHANGED
@@ -9,10 +9,10 @@ import type { MenuActionProperties, MenuItemGroupProperties } from './types';
9
9
  import { createMenuAction, createMenuItemGroup } from './util';
10
10
 
11
11
  export interface ActionGroupBuilder {
12
- action<P extends {} = {}>(id: string, invoke: () => void, properties: P & MenuActionProperties): this;
12
+ action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this;
13
13
  group<P extends {} = {}>(
14
14
  id: string,
15
- properties: P & MenuItemGroupProperties,
15
+ props: P & MenuItemGroupProperties,
16
16
  cb: (builder: ActionGroupBuilder) => void,
17
17
  ): this;
18
18
  }
@@ -32,12 +32,6 @@ class MenuBuilderImpl implements MenuBuilder {
32
32
  private readonly _rootId: string,
33
33
  ) {}
34
34
 
35
- action<P extends {} = {}>(id: string, invoke: () => void, properties: P & MenuActionProperties): this {
36
- this._data.nodes.push(createMenuAction(id, invoke, properties));
37
- this._data.edges.push({ source: this._rootId, target: id });
38
- return this;
39
- }
40
-
41
35
  root(props: MenuItemGroupProperties): this {
42
36
  invariant(this._rootId === 'root', 'Root group can only be at the top level');
43
37
  invariant(this._data.nodes.find((node) => node.id === 'root') === undefined, 'Root group can only be created once');
@@ -45,12 +39,18 @@ class MenuBuilderImpl implements MenuBuilder {
45
39
  return this;
46
40
  }
47
41
 
42
+ action<P extends {} = {}>(id: string, props: P & MenuActionProperties, invoke: () => void): this {
43
+ this._data.nodes.push(createMenuAction(id, invoke, props));
44
+ this._data.edges.push({ source: this._rootId, target: id });
45
+ return this;
46
+ }
47
+
48
48
  group<P extends {} = {}>(
49
49
  id: string,
50
- properties: P & MenuItemGroupProperties,
50
+ props: P & MenuItemGroupProperties,
51
51
  cb: (builder: ActionGroupBuilder) => void,
52
52
  ): this {
53
- this._data.nodes.push(createMenuItemGroup(id, properties));
53
+ this._data.nodes.push(createMenuItemGroup(id, props));
54
54
  this._data.edges.push({ source: this._rootId, target: id });
55
55
  cb(new MenuBuilderImpl(this._data, id));
56
56
  return this;
@@ -4,10 +4,10 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { type Action as GraphAction, type ActionGroup } from '@dxos/app-graph';
7
+ import { type ActionGroup, type Action as GraphAction } from '@dxos/app-graph';
8
8
  import { keySymbols } from '@dxos/keyboard';
9
- import { toLocalizedString, useTranslation, type TFunction } from '@dxos/react-ui';
10
- import { mx, descriptionText } from '@dxos/react-ui-theme';
9
+ import { type TFunction, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
+ import { descriptionText, mx } from '@dxos/react-ui-theme';
11
11
 
12
12
  import { translationKey } from '../translations';
13
13
  import { type MenuActionProperties } from '../types';
@@ -5,11 +5,12 @@
5
5
  import { useControllableState } from '@radix-ui/react-use-controllable-state';
6
6
  import React, { type MouseEvent, useCallback } from 'react';
7
7
 
8
- import { DropdownMenu as NaturalDropdownMenu, Icon, type DropdownMenuRootProps } from '@dxos/react-ui';
8
+ import { type DropdownMenuRootProps, Icon, DropdownMenu as NaturalDropdownMenu } from '@dxos/react-ui';
9
+
10
+ import { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';
9
11
 
10
12
  import { ActionLabel } from './ActionLabel';
11
13
  import { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';
12
- import { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';
13
14
 
14
15
  export type DropdownMenuProps = DropdownMenuRootProps & {
15
16
  group?: MenuItemGroup;
@@ -80,7 +81,9 @@ const DropdownMenuRoot = ({
80
81
  <NaturalDropdownMenu.Portal>
81
82
  <NaturalDropdownMenu.Content>
82
83
  <NaturalDropdownMenu.Viewport>
83
- {items?.map((item) => <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />)}
84
+ {items?.map((item) => (
85
+ <DropdownMenuItem key={item.id} item={item} onClick={handleActionClick} />
86
+ ))}
84
87
  </NaturalDropdownMenu.Viewport>
85
88
  <NaturalDropdownMenu.Arrow />
86
89
  </NaturalDropdownMenu.Content>
@@ -2,14 +2,14 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { createContextScope, type Scope } from '@radix-ui/react-context';
5
+ import { type Scope, createContextScope } from '@radix-ui/react-context';
6
6
  import React, { type PropsWithChildren, useMemo } from 'react';
7
7
 
8
8
  import { type MenuContextValue, type MenuItem, type MenuItemGroup } from '../types';
9
9
 
10
10
  export type MenuScopedProps<P> = P & { __menuScope?: Scope };
11
11
 
12
- const MENU_NAME = 'GraphMenu';
12
+ const MENU_NAME = 'Menu';
13
13
 
14
14
  const [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
15
15
 
@@ -22,12 +22,14 @@ export const menuContextDefaults: MenuContextValue = {
22
22
 
23
23
  const useMenuScope = createMenuScope();
24
24
 
25
+ type MenuProviderProps = PropsWithChildren<Partial<MenuContextValue>>;
26
+
25
27
  const MenuProvider = ({
26
28
  children,
27
29
  useGroupItems = menuContextDefaults.useGroupItems,
28
30
  iconSize = menuContextDefaults.iconSize,
29
31
  attendableId,
30
- }: PropsWithChildren<Partial<MenuContextValue>>) => {
32
+ }: MenuProviderProps) => {
31
33
  const { scope } = useMenuScope(undefined);
32
34
  return (
33
35
  <MenuContextProvider useGroupItems={useGroupItems} iconSize={iconSize} attendableId={attendableId} scope={scope}>
@@ -48,3 +50,5 @@ export const useMenuItems = (
48
50
  };
49
51
 
50
52
  export { useMenu, createMenuScope, MenuProvider };
53
+
54
+ export type { MenuProviderProps };
@@ -2,14 +2,14 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useCallback, useMemo } from 'react';
7
7
 
8
8
  import { faker } from '@dxos/random';
9
9
  import { IconButton } from '@dxos/react-ui';
10
- import { withTheme } from '@dxos/storybook-utils';
10
+ import { withTheme } from '@dxos/react-ui/testing';
11
11
 
12
- import { DropdownMenu as NaturalDropdownMenu, ToolbarMenu, MenuProvider } from '../components';
12
+ import { MenuProvider, DropdownMenu as NaturalDropdownMenu, ToolbarMenu } from '../components';
13
13
  import { useMenuActions } from '../hooks';
14
14
  import { createActions, createNestedActions, createNestedActionsResolver, useMutateActions } from '../testing';
15
15
  import { translations } from '../translations';
@@ -17,16 +17,20 @@ import { type MenuAction } from '../types';
17
17
 
18
18
  faker.seed(1234);
19
19
 
20
- export default {
21
- title: 'ui/react-ui-menu/Menus',
20
+ const meta = {
21
+ title: 'ui/react-ui-menu/ToolbarMenu',
22
22
  component: ToolbarMenu,
23
23
  decorators: [withTheme],
24
24
  parameters: {
25
25
  translations,
26
26
  },
27
- };
27
+ } satisfies Meta<typeof ToolbarMenu>;
28
+
29
+ export default meta;
30
+
31
+ type Story = StoryObj<typeof meta>;
28
32
 
29
- export const DropdownMenu = {
33
+ export const DropdownMenu: Story = {
30
34
  render: () => {
31
35
  const menuActions = useMemo(() => createActions() as MenuAction[], []);
32
36
  const resolveGroupItems = useCallback(() => menuActions, [menuActions]);
@@ -36,7 +40,7 @@ export const DropdownMenu = {
36
40
  <MenuProvider useGroupItems={resolveGroupItems}>
37
41
  <NaturalDropdownMenu.Root>
38
42
  <NaturalDropdownMenu.Trigger asChild>
39
- <IconButton icon='ph--list-checks--regular' size={5} label='Options' />
43
+ <IconButton icon='ph--list-checks--regular' label='Options' />
40
44
  </NaturalDropdownMenu.Trigger>
41
45
  </NaturalDropdownMenu.Root>
42
46
  </MenuProvider>
@@ -44,7 +48,7 @@ export const DropdownMenu = {
44
48
  },
45
49
  };
46
50
 
47
- export const Toolbar = {
51
+ export const Toolbar: Story = {
48
52
  render: () => {
49
53
  const nestedMenuActions = useMemo(() => createNestedActionsResolver(), []);
50
54
 
@@ -56,7 +60,7 @@ export const Toolbar = {
56
60
  },
57
61
  };
58
62
 
59
- export const UseMenuActionsToolbar = {
63
+ export const UseMenuActionsToolbar: Story = {
60
64
  render: () => {
61
65
  const menu = useMenuActions(createNestedActions);
62
66
 
@@ -6,23 +6,24 @@ import React, { Fragment, 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 { mx, textBlockWidth, toolbarLayout } from '@dxos/react-ui-theme';
9
+ import { mx, textBlockWidth, toolbarInactive, toolbarLayout } from '@dxos/react-ui-theme';
10
10
 
11
- import { actionLabel, ActionLabel } from './ActionLabel';
12
- import { DropdownMenu } from './DropdownMenu';
13
- import { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';
14
11
  import { translationKey } from '../translations';
15
12
  import {
16
13
  type MenuAction,
14
+ type MenuActionProperties,
17
15
  type MenuItem,
18
- isMenuGroup,
19
- isSeparator,
20
16
  type MenuItemGroup,
21
- type MenuActionProperties,
22
17
  type MenuMultipleSelectActionGroup,
23
18
  type MenuSingleSelectActionGroup,
19
+ isMenuGroup,
20
+ isSeparator,
24
21
  } from '../types';
25
22
 
23
+ import { ActionLabel, actionLabel } from './ActionLabel';
24
+ import { DropdownMenu } from './DropdownMenu';
25
+ import { type MenuScopedProps, useMenu, useMenuItems } from './MenuContext';
26
+
26
27
  export type ToolbarMenuDropdownMenuActionGroup = Omit<MenuActionProperties, 'variant' | 'icon'> & {
27
28
  variant: 'dropdownMenu';
28
29
  icon: string;
@@ -54,12 +55,15 @@ export type ToolbarMenuActionProps = {
54
55
  const ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {
55
56
  const { iconSize } = useMenu('ActionToolbarItem', __menuScope);
56
57
  const { t } = useTranslation(translationKey);
57
- const handleClick = useCallback(() => action.data?.(), [action]);
58
+
58
59
  const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
59
60
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
60
61
  const rootProps = icon
61
62
  ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }
62
63
  : { children: <ActionLabel action={action} /> };
64
+
65
+ const handleClick = useCallback(() => action.data?.(), [action]);
66
+
63
67
  return hidden ? null : (
64
68
  <Root
65
69
  key={action.id}
@@ -100,6 +104,7 @@ const DropdownMenuToolbarItem = ({
100
104
  </>
101
105
  ),
102
106
  };
107
+
103
108
  return (
104
109
  <DropdownMenu.Root group={group} items={items}>
105
110
  <DropdownMenu.Trigger asChild>
@@ -118,6 +123,7 @@ const ToggleGroupItem = ({ group, action, __menuScope }: MenuScopedProps<Toolbar
118
123
  const rootProps = icon
119
124
  ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }
120
125
  : { children: <ActionLabel action={action} /> };
126
+
121
127
  return hidden ? null : (
122
128
  <Root
123
129
  key={action.id}
@@ -139,8 +145,9 @@ const ToggleGroupToolbarItem = ({
139
145
  }: MenuScopedProps<ToolbarMenuActionGroupProps>) => {
140
146
  const items = useMenuItems(group, propsItems, 'ToggleGroupToolbarItem', __menuScope);
141
147
  const { selectCardinality, value } = group.properties;
148
+
142
149
  return (
143
- // TODO(thure): The type here is difficult to manage, what do?
150
+ // TODO(thure): Fix.
144
151
  // @ts-ignore
145
152
  <NaturalToolbar.ToggleGroup type={selectCardinality} value={value}>
146
153
  {
@@ -153,41 +160,49 @@ const ToggleGroupToolbarItem = ({
153
160
  );
154
161
  };
155
162
 
163
+ // TODO(burdon): Reconcile with react-ui/Toolbar (incl. textBlockWidth)
156
164
  export const ToolbarMenu = ({
157
165
  __menuScope,
158
166
  classNames,
159
- textBlockWidth: wrapContents,
167
+ textBlockWidth: textBlockWidthParam,
160
168
  ...props
161
169
  }: MenuScopedProps<ToolbarMenuProps>) => {
162
170
  const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);
163
171
  const { attendableId } = useMenu('ToolbarMenu', __menuScope);
164
172
  const { hasAttention } = useAttention(attendableId);
165
- const InnerRoot = wrapContents ? 'div' : Fragment;
166
- const innerRootProps = wrapContents ? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'bs-full') } : {};
173
+ const InnerRoot = textBlockWidthParam ? 'div' : Fragment;
174
+ const innerRootProps = textBlockWidthParam
175
+ ? { role: 'none', className: mx(textBlockWidth, toolbarLayout, 'bs-full') }
176
+ : {};
177
+
167
178
  return (
168
179
  <NaturalToolbar.Root
169
180
  {...props}
170
- layoutManaged={wrapContents}
171
- classNames={[attendableId && !hasAttention && '*:opacity-20 !bg-transparent', classNames]}
181
+ classNames={[attendableId && !hasAttention && toolbarInactive, classNames]}
182
+ layoutManaged={textBlockWidthParam}
172
183
  >
173
184
  <InnerRoot {...innerRootProps}>
174
- {items?.map((item: MenuItem, i: number) =>
175
- isSeparator(item) ? (
176
- <NaturalToolbar.Separator key={i} variant={item.properties.variant} />
177
- ) : isMenuGroup(item) ? (
178
- item.properties.variant === 'dropdownMenu' ? (
179
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
180
- <DropdownMenuToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />
181
- ) : (
182
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
183
- <ToggleGroupToolbarItem key={item.id} group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />
184
- )
185
- ) : (
186
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
187
- <ActionToolbarItem key={item.id} action={item as MenuAction} />
188
- ),
189
- )}
185
+ {items?.map((item: MenuItem, i: number) => (
186
+ <ToolbarMenuItem key={item.id ?? i} item={item} />
187
+ ))}
190
188
  </InnerRoot>
191
189
  </NaturalToolbar.Root>
192
190
  );
193
191
  };
192
+
193
+ const ToolbarMenuItem = ({ item }: { item: MenuItem }) => {
194
+ if (isSeparator(item)) {
195
+ return <NaturalToolbar.Separator variant={item.properties.variant} />;
196
+ }
197
+
198
+ // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
199
+ if (isMenuGroup(item)) {
200
+ if (item.properties.variant === 'dropdownMenu') {
201
+ return <DropdownMenuToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;
202
+ } else {
203
+ return <ToggleGroupToolbarItem group={item as MenuItemGroup<ToolbarMenuActionGroupProperties>} />;
204
+ }
205
+ }
206
+
207
+ return <ActionToolbarItem action={item as MenuAction} />;
208
+ };
@@ -2,10 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { RegistryContext, type Rx, useRxValue } from '@effect-rx/rx-react';
5
+ import { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
6
  import { useCallback, useContext, useEffect, useState } from 'react';
7
7
 
8
- import { type Edge, type Edges, Graph, type NodeArg, type Node, ROOT_ID } from '@dxos/app-graph';
8
+ import { type Edge, type Edges, Graph, type Node, type NodeArg, ROOT_ID } from '@dxos/app-graph';
9
9
 
10
10
  import { type MenuItem, type MenuItemGroup } from '../types';
11
11
 
@@ -38,11 +38,18 @@ const edgesArrayToRecord = (edges: Edge[]): Record<string, Edges> => {
38
38
 
39
39
  export type ActionGraphNodes = NodeArg<any>[];
40
40
  export type ActionGraphEdges = Edge[];
41
- export type ActionGraphProps = { nodes: ActionGraphNodes; edges: ActionGraphEdges };
41
+ export type ActionGraphProps = {
42
+ nodes: ActionGraphNodes;
43
+ edges: ActionGraphEdges;
44
+ };
45
+
46
+ export type MenuActions = {
47
+ useGroupItems: (sourceNode?: MenuItemGroup) => MenuItem[];
48
+ };
42
49
 
43
- export const useMenuActions = (props: Rx.Rx<ActionGraphProps>) => {
50
+ export const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions => {
44
51
  const registry = useContext(RegistryContext);
45
- const menuGraphProps = useRxValue(props);
52
+ const menuGraphProps = useAtomValue(props);
46
53
 
47
54
  const [graph] = useState(
48
55
  new Graph({
@@ -59,7 +66,7 @@ export const useMenuActions = (props: Rx.Rx<ActionGraphProps>) => {
59
66
 
60
67
  const useGroupItems = useCallback(
61
68
  (sourceNode?: MenuItemGroup) => {
62
- const items = useRxValue(graph.connections(sourceNode?.id || ROOT_ID)) as MenuItem[];
69
+ const items = useAtomValue(graph.connections(sourceNode?.id || ROOT_ID)) as MenuItem[];
63
70
  return items;
64
71
  },
65
72
  [graph],
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export { rxFromSignal } from '@dxos/app-graph';
5
+ export { atomFromSignal } from '@dxos/app-graph';
6
6
 
7
7
  export * from './components';
8
8
  export * from './hooks';
@@ -2,24 +2,24 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
6
  import { useEffect } from 'react';
7
7
 
8
8
  import {
9
+ ACTION_GROUP_TYPE,
10
+ ACTION_TYPE,
9
11
  type Action,
10
12
  Graph,
11
13
  type NodeArg,
12
- ACTION_TYPE,
13
- ACTION_GROUP_TYPE,
14
- actionGroupSymbol,
15
14
  ROOT_ID,
15
+ actionGroupSymbol,
16
16
  } from '@dxos/app-graph';
17
17
  import { live } from '@dxos/live-object';
18
18
  import { faker } from '@dxos/random';
19
19
  import { type DeepWriteable } from '@dxos/util';
20
20
 
21
21
  import { type ActionGraphProps } from '../hooks/useMenuActions';
22
- import { type MenuAction, type MenuItemGroup, type MenuItem } from '../types';
22
+ import { type MenuAction, type MenuItem, type MenuItemGroup } from '../types';
23
23
 
24
24
  export type CreateActionsParams = Partial<{
25
25
  type?: typeof ACTION_TYPE | typeof ACTION_GROUP_TYPE;
@@ -66,7 +66,7 @@ export const createActions = (params?: CreateActionsParams) => {
66
66
  );
67
67
  };
68
68
 
69
- export const createNestedActions = Rx.make(() => {
69
+ export const createNestedActions = Atom.make(() => {
70
70
  const result: ActionGraphProps = { edges: [], nodes: [] };
71
71
  const actionGroups = createActions({ type: ACTION_GROUP_TYPE });
72
72
  actionGroups.forEach((group) => {
package/src/types.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Node, type Action, type ActionGroup, ACTION_GROUP_TYPE } from '@dxos/app-graph';
6
- import { type ToolbarSeparatorProps, type Label, type IconButtonProps, type ClassNameValue } from '@dxos/react-ui';
5
+ import { ACTION_GROUP_TYPE, type Action, type ActionGroup, type Node } from '@dxos/app-graph';
6
+ import { type ClassNameValue, type IconButtonProps, type Label, type ToolbarSeparatorProps } from '@dxos/react-ui';
7
7
 
8
8
  export type MenuActionProperties = {
9
9
  label: Label;
package/src/util.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { ACTION_GROUP_TYPE, ACTION_TYPE, actionGroupSymbol, type ActionLike } from '@dxos/app-graph';
5
+ import { ACTION_GROUP_TYPE, ACTION_TYPE, type ActionLike, actionGroupSymbol } from '@dxos/app-graph';
6
6
  import { getHostPlatform } from '@dxos/util';
7
7
 
8
8
  import {
@@ -55,7 +55,12 @@ export const createGapSeparator = (id: string = 'gap', source: string = 'root')
55
55
  data: undefined as never,
56
56
  } satisfies MenuSeparator,
57
57
  ],
58
- edges: [{ source, target: id }],
58
+ edges: [
59
+ {
60
+ source,
61
+ target: id,
62
+ },
63
+ ],
59
64
  });
60
65
 
61
66
  export const createLineSeparator = (id: string = 'line', source: string = 'root') => ({
@@ -1,25 +0,0 @@
1
- import '@dxos-theme';
2
- import React from 'react';
3
- declare const _default: {
4
- title: string;
5
- component: ({ __menuScope, classNames, textBlockWidth: wrapContents, ...props }: import("./MenuContext").MenuScopedProps<import("./ToolbarMenu").ToolbarMenuProps>) => React.JSX.Element;
6
- decorators: import("@storybook/react").Decorator[];
7
- parameters: {
8
- translations: [{
9
- readonly 'en-US': {
10
- readonly "react-ui-menu": {};
11
- };
12
- }];
13
- };
14
- };
15
- export default _default;
16
- export declare const DropdownMenu: {
17
- render: () => React.JSX.Element;
18
- };
19
- export declare const Toolbar: {
20
- render: () => React.JSX.Element;
21
- };
22
- export declare const UseMenuActionsToolbar: {
23
- render: () => React.JSX.Element;
24
- };
25
- //# sourceMappingURL=Menus.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Menus.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/Menus.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AACrB,OAAO,KAA+B,MAAM,OAAO,CAAC;;;;;;;;;;;;;AAcpD,wBAOE;AAEF,eAAO,MAAM,YAAY;;CAgBxB,CAAC;AAEF,eAAO,MAAM,OAAO;;CAUnB,CAAC;AAEF,eAAO,MAAM,qBAAqB;;CAUjC,CAAC"}