@dxos/react-ui-menu 0.8.4-main.74a063c4e0 → 0.8.4-main.765dc60934

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 (35) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +20 -42
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/translations.mjs +14 -0
  6. package/dist/lib/browser/translations.mjs.map +7 -0
  7. package/dist/lib/node-esm/index.mjs +20 -42
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/lib/node-esm/translations.mjs +16 -0
  11. package/dist/lib/node-esm/translations.mjs.map +7 -0
  12. package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
  13. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  14. package/dist/types/src/components/Menu.d.ts +1 -5
  15. package/dist/types/src/components/Menu.d.ts.map +1 -1
  16. package/dist/types/src/components/Menu.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/ToolbarMenu.d.ts +1 -5
  18. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
  19. package/dist/types/src/components/ToolbarMenu.stories.d.ts +13 -5
  20. package/dist/types/src/components/ToolbarMenu.stories.d.ts.map +1 -1
  21. package/dist/types/src/hooks/useMenuActions.d.ts +9 -1
  22. package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -1
  23. package/dist/types/src/testing/generator.d.ts +2 -2
  24. package/dist/types/src/testing/generator.d.ts.map +1 -1
  25. package/dist/types/src/types.d.ts +1 -1
  26. package/dist/types/src/types.d.ts.map +1 -1
  27. package/dist/types/src/util.d.ts +2 -2
  28. package/dist/types/src/util.d.ts.map +1 -1
  29. package/dist/types/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +26 -20
  31. package/src/components/ActionLabel.tsx +2 -1
  32. package/src/components/Menu.stories.tsx +2 -1
  33. package/src/components/ToolbarMenu.stories.tsx +14 -1
  34. package/src/components/ToolbarMenu.tsx +12 -3
  35. package/src/hooks/useMenuActions.ts +14 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-menu",
3
- "version": "0.8.4-main.74a063c4e0",
3
+ "version": "0.8.4-main.765dc60934",
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,22 +8,28 @@
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",
15
+ "imports": {
16
+ "#translations": "./src/translations.ts"
17
+ },
15
18
  "exports": {
16
19
  ".": {
17
20
  "source": "./src/index.ts",
18
21
  "types": "./dist/types/src/index.d.ts",
19
22
  "browser": "./dist/lib/browser/index.mjs",
20
23
  "node": "./dist/lib/node-esm/index.mjs"
24
+ },
25
+ "./translations": {
26
+ "source": "./src/translations.ts",
27
+ "types": "./dist/types/src/translations.d.ts",
28
+ "browser": "./dist/lib/browser/translations.mjs",
29
+ "node": "./dist/lib/node-esm/translations.mjs"
21
30
  }
22
31
  },
23
32
  "types": "dist/types/src/index.d.ts",
24
- "typesVersions": {
25
- "*": {}
26
- },
27
33
  "files": [
28
34
  "dist",
29
35
  "src"
@@ -31,14 +37,14 @@
31
37
  "dependencies": {
32
38
  "@radix-ui/react-context": "1.1.1",
33
39
  "@radix-ui/react-use-controllable-state": "1.1.0",
34
- "@dxos/app-graph": "0.8.4-main.74a063c4e0",
35
- "@dxos/effect": "0.8.4-main.74a063c4e0",
36
- "@dxos/invariant": "0.8.4-main.74a063c4e0",
37
- "@dxos/keyboard": "0.8.4-main.74a063c4e0",
38
- "@dxos/log": "0.8.4-main.74a063c4e0",
39
- "@dxos/react-ui-attention": "0.8.4-main.74a063c4e0",
40
- "@dxos/ui-types": "0.8.4-main.74a063c4e0",
41
- "@dxos/util": "0.8.4-main.74a063c4e0"
40
+ "@dxos/app-graph": "0.8.4-main.765dc60934",
41
+ "@dxos/log": "0.8.4-main.765dc60934",
42
+ "@dxos/effect": "0.8.4-main.765dc60934",
43
+ "@dxos/keyboard": "0.8.4-main.765dc60934",
44
+ "@dxos/util": "0.8.4-main.765dc60934",
45
+ "@dxos/react-ui-attention": "0.8.4-main.765dc60934",
46
+ "@dxos/ui-types": "0.8.4-main.765dc60934",
47
+ "@dxos/invariant": "0.8.4-main.765dc60934"
42
48
  },
43
49
  "devDependencies": {
44
50
  "@effect-atom/atom-react": "^0.5.0",
@@ -50,11 +56,11 @@
50
56
  "effect": "3.20.0",
51
57
  "react": "~19.2.3",
52
58
  "react-dom": "~19.2.3",
53
- "vite": "^7.1.11",
54
- "@dxos/random": "0.8.4-main.74a063c4e0",
55
- "@dxos/storybook-utils": "0.8.4-main.74a063c4e0",
56
- "@dxos/react-ui": "0.8.4-main.74a063c4e0",
57
- "@dxos/ui-theme": "0.8.4-main.74a063c4e0"
59
+ "vite": "^8.0.13",
60
+ "@dxos/random": "0.8.4-main.765dc60934",
61
+ "@dxos/react-ui": "0.8.4-main.765dc60934",
62
+ "@dxos/storybook-utils": "0.8.4-main.765dc60934",
63
+ "@dxos/ui-theme": "0.8.4-main.765dc60934"
58
64
  },
59
65
  "peerDependencies": {
60
66
  "@effect-atom/atom-react": "^0.5.0",
@@ -62,8 +68,8 @@
62
68
  "effect": "3.20.0",
63
69
  "react": "~19.2.3",
64
70
  "react-dom": "~19.2.3",
65
- "@dxos/react-ui": "0.8.4-main.74a063c4e0",
66
- "@dxos/ui-theme": "0.8.4-main.74a063c4e0"
71
+ "@dxos/react-ui": "0.8.4-main.765dc60934",
72
+ "@dxos/ui-theme": "0.8.4-main.765dc60934"
67
73
  },
68
74
  "publishConfig": {
69
75
  "access": "public"
@@ -10,7 +10,8 @@ import { type TFunction, toLocalizedString, useTranslation } from '@dxos/react-u
10
10
  import { mx } from '@dxos/ui-theme';
11
11
  import { type MenuActionProperties } from '@dxos/ui-types';
12
12
 
13
- import { translationKey } from '../translations';
13
+ import { translationKey } from '#translations';
14
+
14
15
  import { getShortcut } from '../util';
15
16
 
16
17
  type Action = Node.Action<MenuActionProperties> | Node.ActionGroup<Omit<MenuActionProperties, 'variant'>>;
@@ -11,10 +11,11 @@ import { Button, IconButton } from '@dxos/react-ui';
11
11
  import { withTheme } from '@dxos/react-ui/testing';
12
12
  import { withRegistry } from '@dxos/storybook-utils';
13
13
 
14
+ import { translations } from '#translations';
15
+
14
16
  import { Menu, useMenu } from '../components';
15
17
  import { type ActionGraphProps, useMenuActions } from '../hooks';
16
18
  import { createActions } from '../testing';
17
- import { translations } from '../translations';
18
19
  import { type MenuItem } from '../types';
19
20
  import { createMenuAction } from '../util';
20
21
 
@@ -11,10 +11,11 @@ import { IconButton } from '@dxos/react-ui';
11
11
  import { withTheme } from '@dxos/react-ui/testing';
12
12
  import { withRegistry } from '@dxos/storybook-utils';
13
13
 
14
+ import { translations } from '#translations';
15
+
14
16
  import { Menu } from '../components';
15
17
  import { type ActionGraphProps, useMenuActions } from '../hooks';
16
18
  import { createActions, createNestedActions, createNestedActionsResolver, useMutateActions } from '../testing';
17
- import { translations } from '../translations';
18
19
 
19
20
  random.seed(1234);
20
21
 
@@ -68,6 +69,18 @@ export const Toolbar: Story = {
68
69
  },
69
70
  };
70
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
+ */
71
84
  export const UseMenuActionsToolbar: Story = {
72
85
  render: () => {
73
86
  useMutateActions(createNestedActions);
@@ -9,7 +9,8 @@ import { useAttention } from '@dxos/react-ui-attention';
9
9
  import { composable, composableProps } from '@dxos/ui-theme';
10
10
  import { type MenuActionProperties } from '@dxos/ui-types';
11
11
 
12
- import { translationKey } from '../translations';
12
+ import { translationKey } from '#translations';
13
+
13
14
  import {
14
15
  type MenuAction,
15
16
  type MenuItem,
@@ -56,7 +57,7 @@ const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: Me
56
57
  const { iconSize, onAction } = useMenuScoped('ActionToolbarItem', __menuScope);
57
58
  const { t } = useTranslation(translationKey);
58
59
 
59
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
60
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
60
61
  const buttonVariant =
61
62
  (action.properties as { variant?: string }).variant === 'primary' ? ('primary' as const) : ('ghost' as const);
62
63
 
@@ -87,6 +88,7 @@ const ActionToolbarItem = ({ __menuScope, action }: MenuScopedProps<{ action: Me
87
88
  icon={icon}
88
89
  size={iconSize}
89
90
  iconOnly={iconOnly}
91
+ iconClassNames={iconClassNames}
90
92
  label={actionLabel(action, t)}
91
93
  />
92
94
  ) : (
@@ -111,6 +113,11 @@ const DropdownMenuToolbarItem = ({
111
113
  // TODO(thure): Handle other menu item types.
112
114
  (activeItem as MenuAction)?.properties.icon) ||
113
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;
114
121
  const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
115
122
  const labelAction = (group.properties as any).applyActive && activeItem ? (activeItem as MenuAction) : group;
116
123
  const rootProps = icon
@@ -118,6 +125,7 @@ const DropdownMenuToolbarItem = ({
118
125
  icon,
119
126
  size: iconSize,
120
127
  iconOnly,
128
+ iconClassNames,
121
129
  label: actionLabel(labelAction, t),
122
130
  caretDown: true,
123
131
  }
@@ -142,7 +150,7 @@ const DropdownMenuToolbarItem = ({
142
150
  const ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<ToolbarMenuActionProps>) => {
143
151
  const { iconSize, onAction } = useMenuScoped('ToggleGroupItem', __menuScope);
144
152
  const { t } = useTranslation(translationKey);
145
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
153
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames, iconClassNames } = action.properties;
146
154
 
147
155
  const handleClick = useCallback(() => {
148
156
  if (onAction) {
@@ -167,6 +175,7 @@ const ToggleGroupItem = ({ __menuScope, group, action }: MenuScopedProps<Toolbar
167
175
  icon={icon}
168
176
  size={iconSize}
169
177
  iconOnly={iconOnly}
178
+ iconClassNames={iconClassNames}
170
179
  label={actionLabel(action, t)}
171
180
  />
172
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
+ };