@dxos/react-ui-menu 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-menu",
3
- "version": "0.8.4-main.dedc0f3",
3
+ "version": "0.8.4-main.e8ec1fe",
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",
@@ -26,38 +26,38 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@preact-signals/safe-react": "^0.9.0",
29
- "@preact/signals-react": "^3.2.0",
29
+ "@preact/signals-react": "^3.3.0",
30
30
  "@radix-ui/react-context": "1.1.1",
31
31
  "@radix-ui/react-use-controllable-state": "1.1.0",
32
- "@dxos/invariant": "0.8.4-main.dedc0f3",
33
- "@dxos/app-graph": "0.8.4-main.dedc0f3",
34
- "@dxos/keyboard": "0.8.4-main.dedc0f3",
35
- "@dxos/react-ui-attention": "0.8.4-main.dedc0f3",
36
- "@dxos/util": "0.8.4-main.dedc0f3"
32
+ "@dxos/app-graph": "0.8.4-main.e8ec1fe",
33
+ "@dxos/invariant": "0.8.4-main.e8ec1fe",
34
+ "@dxos/keyboard": "0.8.4-main.e8ec1fe",
35
+ "@dxos/react-ui-attention": "0.8.4-main.e8ec1fe",
36
+ "@dxos/util": "0.8.4-main.e8ec1fe"
37
37
  },
38
38
  "devDependencies": {
39
- "@effect-rx/rx-react": "0.38.0",
40
- "@effect/platform": "0.90.2",
41
- "@types/react": "~18.2.0",
42
- "@types/react-dom": "~18.2.0",
43
- "effect": "3.17.7",
44
- "react": "~18.2.0",
45
- "react-dom": "~18.2.0",
46
- "vite": "7.1.1",
47
- "@dxos/live-object": "0.8.4-main.dedc0f3",
48
- "@dxos/random": "0.8.4-main.dedc0f3",
49
- "@dxos/react-ui": "0.8.4-main.dedc0f3",
50
- "@dxos/react-ui-theme": "0.8.4-main.dedc0f3",
51
- "@dxos/storybook-utils": "0.8.4-main.dedc0f3"
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.e8ec1fe",
48
+ "@dxos/react-ui": "0.8.4-main.e8ec1fe",
49
+ "@dxos/react-ui-theme": "0.8.4-main.e8ec1fe",
50
+ "@dxos/random": "0.8.4-main.e8ec1fe",
51
+ "@dxos/storybook-utils": "0.8.4-main.e8ec1fe"
52
52
  },
53
53
  "peerDependencies": {
54
- "@effect-rx/rx-react": "^0.34.1",
54
+ "@effect-atom/atom-react": "^0.3.4",
55
55
  "@effect/platform": "^0.80.12",
56
56
  "effect": "^3.13.3",
57
- "react": "~18.2.0",
58
- "react-dom": "~18.2.0",
59
- "@dxos/react-ui": "0.8.4-main.dedc0f3",
60
- "@dxos/react-ui-theme": "0.8.4-main.dedc0f3"
57
+ "react": "^19.0.0",
58
+ "react-dom": "^19.0.0",
59
+ "@dxos/react-ui": "0.8.4-main.e8ec1fe",
60
+ "@dxos/react-ui-theme": "0.8.4-main.e8ec1fe"
61
61
  },
62
62
  "publishConfig": {
63
63
  "access": "public"
@@ -9,7 +9,7 @@ import { type MenuContextValue, type MenuItem, type MenuItemGroup } from '../typ
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,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
6
  import React, { useCallback, useMemo } from 'react';
9
7
 
10
8
  import { faker } from '@dxos/random';
11
9
  import { IconButton } from '@dxos/react-ui';
12
- import { withTheme } from '@dxos/storybook-utils';
10
+ import { withTheme } from '@dxos/react-ui/testing';
13
11
 
14
12
  import { MenuProvider, DropdownMenu as NaturalDropdownMenu, ToolbarMenu } from '../components';
15
13
  import { useMenuActions } from '../hooks';
@@ -42,7 +40,7 @@ export const DropdownMenu: Story = {
42
40
  <MenuProvider useGroupItems={resolveGroupItems}>
43
41
  <NaturalDropdownMenu.Root>
44
42
  <NaturalDropdownMenu.Trigger asChild>
45
- <IconButton icon='ph--list-checks--regular' size={5} label='Options' />
43
+ <IconButton icon='ph--list-checks--regular' label='Options' />
46
44
  </NaturalDropdownMenu.Trigger>
47
45
  </NaturalDropdownMenu.Root>
48
46
  </MenuProvider>
@@ -6,7 +6,7 @@ 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
11
  import { translationKey } from '../translations';
12
12
  import {
@@ -55,13 +55,15 @@ export type ToolbarMenuActionProps = {
55
55
  const ActionToolbarItem = ({ action, __menuScope }: MenuScopedProps<{ action: MenuAction }>) => {
56
56
  const { iconSize } = useMenu('ActionToolbarItem', __menuScope);
57
57
  const { t } = useTranslation(translationKey);
58
- const handleClick = useCallback(() => action.data?.(), [action]);
58
+
59
59
  const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
60
60
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
61
61
  const rootProps = icon
62
62
  ? { icon, size: iconSize, iconOnly, label: actionLabel(action, t) }
63
63
  : { children: <ActionLabel action={action} /> };
64
64
 
65
+ const handleClick = useCallback(() => action.data?.(), [action]);
66
+
65
67
  return hidden ? null : (
66
68
  <Root
67
69
  key={action.id}
@@ -158,23 +160,26 @@ const ToggleGroupToolbarItem = ({
158
160
  );
159
161
  };
160
162
 
163
+ // TODO(burdon): Reconcile with react-ui/Toolbar (incl. textBlockWidth)
161
164
  export const ToolbarMenu = ({
162
165
  __menuScope,
163
166
  classNames,
164
- textBlockWidth: wrapContents,
167
+ textBlockWidth: textBlockWidthParam,
165
168
  ...props
166
169
  }: MenuScopedProps<ToolbarMenuProps>) => {
167
170
  const items = useMenuItems(undefined, undefined, 'ToolbarMenu', __menuScope);
168
171
  const { attendableId } = useMenu('ToolbarMenu', __menuScope);
169
172
  const { hasAttention } = useAttention(attendableId);
170
- const InnerRoot = wrapContents ? 'div' : Fragment;
171
- 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
+ : {};
172
177
 
173
178
  return (
174
179
  <NaturalToolbar.Root
175
180
  {...props}
176
- layoutManaged={wrapContents}
177
- classNames={[attendableId && !hasAttention && '*:opacity-20 !bg-transparent', classNames]}
181
+ classNames={[attendableId && !hasAttention && toolbarInactive, classNames]}
182
+ layoutManaged={textBlockWidthParam}
178
183
  >
179
184
  <InnerRoot {...innerRootProps}>
180
185
  {items?.map((item: MenuItem, i: number) => (
@@ -2,7 +2,7 @@
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
8
  import { type Edge, type Edges, Graph, type Node, type NodeArg, ROOT_ID } from '@dxos/app-graph';
@@ -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,7 +2,7 @@
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 {
@@ -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/util.ts CHANGED
@@ -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') => ({