@dxos/react-ui-menu 0.8.4-main.cb12b3f963 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-menu",
3
- "version": "0.8.4-main.cb12b3f963",
3
+ "version": "0.8.4-main.d05539e30a",
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",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": false,
14
14
  "type": "module",
@@ -37,14 +37,14 @@
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.8.4-main.cb12b3f963",
41
- "@dxos/invariant": "0.8.4-main.cb12b3f963",
42
- "@dxos/effect": "0.8.4-main.cb12b3f963",
43
- "@dxos/keyboard": "0.8.4-main.cb12b3f963",
44
- "@dxos/log": "0.8.4-main.cb12b3f963",
45
- "@dxos/react-ui-attention": "0.8.4-main.cb12b3f963",
46
- "@dxos/util": "0.8.4-main.cb12b3f963",
47
- "@dxos/ui-types": "0.8.4-main.cb12b3f963"
40
+ "@dxos/app-graph": "0.8.4-main.d05539e30a",
41
+ "@dxos/effect": "0.8.4-main.d05539e30a",
42
+ "@dxos/invariant": "0.8.4-main.d05539e30a",
43
+ "@dxos/keyboard": "0.8.4-main.d05539e30a",
44
+ "@dxos/react-ui-attention": "0.8.4-main.d05539e30a",
45
+ "@dxos/ui-types": "0.8.4-main.d05539e30a",
46
+ "@dxos/util": "0.8.4-main.d05539e30a",
47
+ "@dxos/log": "0.8.4-main.d05539e30a"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@effect-atom/atom-react": "^0.5.0",
@@ -56,11 +56,11 @@
56
56
  "effect": "3.20.0",
57
57
  "react": "~19.2.3",
58
58
  "react-dom": "~19.2.3",
59
- "vite": "^8.0.10",
60
- "@dxos/random": "0.8.4-main.cb12b3f963",
61
- "@dxos/react-ui": "0.8.4-main.cb12b3f963",
62
- "@dxos/storybook-utils": "0.8.4-main.cb12b3f963",
63
- "@dxos/ui-theme": "0.8.4-main.cb12b3f963"
59
+ "vite": "^8.0.13",
60
+ "@dxos/react-ui": "0.8.4-main.d05539e30a",
61
+ "@dxos/random": "0.8.4-main.d05539e30a",
62
+ "@dxos/storybook-utils": "0.8.4-main.d05539e30a",
63
+ "@dxos/ui-theme": "0.8.4-main.d05539e30a"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@effect-atom/atom-react": "^0.5.0",
@@ -68,8 +68,8 @@
68
68
  "effect": "3.20.0",
69
69
  "react": "~19.2.3",
70
70
  "react-dom": "~19.2.3",
71
- "@dxos/react-ui": "0.8.4-main.cb12b3f963",
72
- "@dxos/ui-theme": "0.8.4-main.cb12b3f963"
71
+ "@dxos/react-ui": "0.8.4-main.d05539e30a",
72
+ "@dxos/ui-theme": "0.8.4-main.d05539e30a"
73
73
  },
74
74
  "publishConfig": {
75
75
  "access": "public"
@@ -69,6 +69,18 @@ export const Toolbar: Story = {
69
69
  },
70
70
  };
71
71
 
72
+ /**
73
+ * Reactive toolbar driven by an atom-backed actions hook.
74
+ *
75
+ * Defining actions inside a hook lets them subscribe to reactive state
76
+ * (echo, atoms, settings) without re-rendering the toolbar shell.
77
+ * The menu structure is data, not JSX.
78
+ *
79
+ * @idiom org.dxos.react-ui-menu.toolbarMenu
80
+ * applies: Toolbars whose entries depend on reactive state
81
+ * instead-of: Hand-wired children inside a bespoke `Toolbar.Root`
82
+ * uses: {@link useMenuActions}, {@link Menu.Root}, {@link Menu.Toolbar}
83
+ */
72
84
  export const UseMenuActionsToolbar: Story = {
73
85
  render: () => {
74
86
  useMutateActions(createNestedActions);
@@ -57,7 +57,7 @@ const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: Me
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;
60
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
61
61
  const buttonVariant =
62
62
  (action.properties as { variant?: string }).variant === 'primary' ? ('primary' as const) : ('ghost' as const);
63
63
 
@@ -88,6 +88,7 @@ const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: Me
88
88
  icon={icon}
89
89
  size={iconSize}
90
90
  iconOnly={iconOnly}
91
+ iconClassNames={iconClassNames}
91
92
  label={actionLabel(action, t)}
92
93
  />
93
94
  ) : (
@@ -112,6 +113,11 @@ const DropdownMenuToolbarItem = ({
112
113
  // TODO(thure): Handle other menu item types.
113
114
  (activeItem as MenuAction)?.properties.icon) ||
114
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;
115
121
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
116
122
  const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;
117
123
  const rootProps = icon
@@ -119,6 +125,7 @@ const DropdownMenuToolbarItem = ({
119
125
  icon,
120
126
  size: iconSize,
121
127
  iconOnly,
128
+ iconClassNames,
122
129
  label: actionLabel(labelAction, t),
123
130
  caretDown: true,
124
131
  }
@@ -143,7 +150,7 @@ const DropdownMenuToolbarItem = ({
143
150
  const ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<ToolbarMenuActionProps>) => {
144
151
  const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);
145
152
  const { t } = useTranslation(translationKey);
146
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
153
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
147
154
 
148
155
  const handleClick = useCallback(() => {
149
156
  if (onAction) {
@@ -168,6 +175,7 @@ const ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<Toolbar
168
175
  icon={icon}
169
176
  size={iconSize}
170
177
  iconOnly={iconOnly}
178
+ iconClassNames={iconClassNames}
171
179
  label={actionLabel(action, t)}
172
180
  />
173
181
  ) : (
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Atom, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
- import { useCallback, useContext, useMemo } from 'react';
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
 
@@ -44,3 +44,15 @@ export const useMenuActions = (props: Atom.Atom<ActionGraphProps>): MenuActions
44
44
 
45
45
  return { items };
46
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
+ };