@dxos/react-ui-menu 0.7.5-main.937ce75 → 0.7.5-main.9d2a38b

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 (56) hide show
  1. package/dist/lib/browser/index.mjs +322 -115
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +320 -103
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +322 -115
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/DropdownMenu.d.ts +9 -8
  11. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  12. package/dist/types/src/components/MenuContext.d.ts +13 -0
  13. package/dist/types/src/components/MenuContext.d.ts.map +1 -0
  14. package/dist/types/src/components/ToolbarMenu.d.ts +20 -0
  15. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -0
  16. package/dist/types/src/components/index.d.ts +2 -1
  17. package/dist/types/src/components/index.d.ts.map +1 -1
  18. package/dist/types/src/defs.d.ts +34 -7
  19. package/dist/types/src/defs.d.ts.map +1 -1
  20. package/dist/types/src/hooks.d.ts +17 -0
  21. package/dist/types/src/hooks.d.ts.map +1 -0
  22. package/dist/types/src/index.d.ts +2 -0
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/testing/Menus.stories.d.ts +4 -1
  25. package/dist/types/src/testing/Menus.stories.d.ts.map +1 -1
  26. package/dist/types/src/testing/index.d.ts +6 -6
  27. package/dist/types/src/testing/index.d.ts.map +1 -1
  28. package/dist/types/src/util.d.ts +42 -1
  29. package/dist/types/src/util.d.ts.map +1 -1
  30. package/dist/types/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +14 -11
  32. package/src/components/DropdownMenu.tsx +35 -27
  33. package/src/components/MenuContext.tsx +57 -0
  34. package/src/components/ToolbarMenu.tsx +185 -0
  35. package/src/components/index.ts +2 -1
  36. package/src/defs.ts +38 -7
  37. package/src/hooks.ts +72 -0
  38. package/src/index.ts +2 -0
  39. package/src/testing/Menus.stories.tsx +30 -18
  40. package/src/testing/index.ts +24 -5
  41. package/src/util.ts +58 -1
  42. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -4
  43. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  44. package/dist/types/src/components/Toolbar/ToolbarDropdownMenu.d.ts +0 -4
  45. package/dist/types/src/components/Toolbar/ToolbarDropdownMenu.d.ts.map +0 -1
  46. package/dist/types/src/components/Toolbar/ToolbarToggleGroup.d.ts +0 -4
  47. package/dist/types/src/components/Toolbar/ToolbarToggleGroup.d.ts.map +0 -1
  48. package/dist/types/src/components/Toolbar/defs.d.ts +0 -30
  49. package/dist/types/src/components/Toolbar/defs.d.ts.map +0 -1
  50. package/dist/types/src/components/Toolbar/index.d.ts +0 -3
  51. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  52. package/src/components/Toolbar/Toolbar.tsx +0 -71
  53. package/src/components/Toolbar/ToolbarDropdownMenu.tsx +0 -36
  54. package/src/components/Toolbar/ToolbarToggleGroup.tsx +0 -39
  55. package/src/components/Toolbar/defs.ts +0 -36
  56. package/src/components/Toolbar/index.ts +0 -6
package/src/util.ts CHANGED
@@ -2,9 +2,17 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type ActionLike } from '@dxos/app-graph';
5
+ import { ACTION_GROUP_TYPE, ACTION_TYPE, actionGroupSymbol, type ActionLike } from '@dxos/app-graph';
6
6
  import { getHostPlatform } from '@dxos/util';
7
7
 
8
+ import {
9
+ type MenuAction,
10
+ type MenuActionProperties,
11
+ type MenuItemGroup,
12
+ type MenuItemGroupProperties,
13
+ type MenuSeparator,
14
+ } from './defs';
15
+
8
16
  export const getShortcut = (action: ActionLike) => {
9
17
  return typeof action.properties?.keyBinding === 'string'
10
18
  ? action.properties.keyBinding
@@ -12,3 +20,52 @@ export const getShortcut = (action: ActionLike) => {
12
20
  };
13
21
 
14
22
  export const fallbackIcon = 'ph--placeholder--regular';
23
+
24
+ // TODO(thure,wittjosiah): This is probably a smell; consider the whether react-ui-menu should use action nodes if the
25
+ // callback in `data` is never used. See https://github.com/dxos/dxos/pull/8506#discussion_r1925855118
26
+ const noop = () => {};
27
+
28
+ export const createMenuAction = <P extends {} = {}>(id: string, properties: P & MenuActionProperties) =>
29
+ ({
30
+ id,
31
+ type: ACTION_TYPE,
32
+ properties,
33
+ data: noop,
34
+ }) satisfies MenuAction;
35
+
36
+ export const createMenuItemGroup = <
37
+ P extends MenuItemGroupProperties = MenuItemGroupProperties & Partial<MenuActionProperties>,
38
+ >(
39
+ id: string,
40
+ properties: P,
41
+ ) =>
42
+ ({
43
+ id,
44
+ type: ACTION_GROUP_TYPE,
45
+ properties,
46
+ data: actionGroupSymbol,
47
+ }) satisfies MenuItemGroup;
48
+
49
+ export const createGapSeparator = (id: string = 'gap', source: string = 'root') => ({
50
+ nodes: [
51
+ {
52
+ id,
53
+ type: '@dxos/react-ui-toolbar/separator',
54
+ properties: { variant: 'gap' },
55
+ data: undefined as never,
56
+ } satisfies MenuSeparator,
57
+ ],
58
+ edges: [{ source, target: id }],
59
+ });
60
+
61
+ export const createLineSeparator = (id: string = 'line', source: string = 'root') => ({
62
+ nodes: [
63
+ {
64
+ id,
65
+ type: '@dxos/react-ui-toolbar/separator',
66
+ properties: { variant: 'line' },
67
+ data: undefined as never,
68
+ } satisfies MenuSeparator,
69
+ ],
70
+ edges: [{ source, target: id }],
71
+ });
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import { type ToolbarProps } from './defs';
3
- export declare const Toolbar: ({ actions: items, onAction, iconSize, graph, ...props }: ToolbarProps) => React.JSX.Element;
4
- //# sourceMappingURL=Toolbar.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/Toolbar.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAM3C,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AA8BhE,eAAO,MAAM,OAAO,4DAAiE,YAAY,sBA8BhG,CAAC"}
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import { type ToolbarActionGroupProps } from './defs';
3
- export declare const ToolbarDropdownMenu: ({ actionGroup, graph, onAction, applyActiveIcon }: ToolbarActionGroupProps) => React.JSX.Element;
4
- //# sourceMappingURL=ToolbarDropdownMenu.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ToolbarDropdownMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/ToolbarDropdownMenu.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAI/C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AAKtD,eAAO,MAAM,mBAAmB,sDAAuD,uBAAuB,sBAsB7G,CAAC"}
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import type { ToolbarActionGroupProps } from './defs';
3
- export declare const ToolbarToggleGroup: ({ actionGroup, graph }: ToolbarActionGroupProps) => React.JSX.Element;
4
- //# sourceMappingURL=ToolbarToggleGroup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ToolbarToggleGroup.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/ToolbarToggleGroup.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AAkBtD,eAAO,MAAM,kBAAkB,2BAA4B,uBAAuB,sBAYjF,CAAC"}
@@ -1,30 +0,0 @@
1
- import { type Node, type ActionGroup, type Graph } from '@dxos/app-graph';
2
- import { type ToolbarRootProps, type ToolbarSeparatorProps, type IconButtonProps } from '@dxos/react-ui';
3
- import { type MenuAction, type MenuActionProperties, type MenuProps } from '../../defs';
4
- export declare const ToolbarSeparatorType: "@dxos/react-ui-toolbar/separator";
5
- export type ToolbarSeparatorNode = Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {
6
- type: typeof ToolbarSeparatorType;
7
- };
8
- export declare const isSeparator: (node: Node) => node is ToolbarSeparatorNode;
9
- export type ToolbarActionGroupProperties = Omit<MenuActionProperties, 'variant'> & {
10
- variant: 'dropdownMenu' | 'toggleGroup';
11
- } & ({
12
- selectCardinality?: 'single';
13
- value?: string;
14
- } | {
15
- selectCardinality?: 'multiple';
16
- value?: string[];
17
- });
18
- export type ToolbarActionGroup = ActionGroup<ToolbarActionGroupProperties>;
19
- export declare const isMenu: (node: Node) => node is ToolbarActionGroup;
20
- export type ToolbarItem = ToolbarSeparatorNode | MenuAction | ToolbarActionGroup;
21
- export type ToolbarProps = ToolbarRootProps & MenuProps<ToolbarItem, MenuAction> & {
22
- iconSize?: IconButtonProps['size'];
23
- graph?: Graph;
24
- };
25
- export type ToolbarActionGroupProps = Pick<ToolbarProps, 'iconSize'> & Omit<MenuProps<MenuAction>, 'actions'> & {
26
- actionGroup: ToolbarActionGroup;
27
- graph?: Graph;
28
- applyActiveIcon?: boolean;
29
- };
30
- //# sourceMappingURL=defs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/defs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAqB,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEzG,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAExF,eAAO,MAAM,oBAAoB,EAAG,kCAA2C,CAAC;AAEhF,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC,GAAG;IACvF,IAAI,EAAE,OAAO,oBAAoB,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,IAAI,KAAG,IAAI,IAAI,oBAA0D,CAAC;AAE5G,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,GAAG;IACjF,OAAO,EAAE,cAAc,GAAG,aAAa,CAAC;CACzC,GAAG,CAAC;IAAE,iBAAiB,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAE9G,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,4BAA4B,CAAC,CAAC;AAE3E,eAAO,MAAM,MAAM,SAAU,IAAI,KAAG,IAAI,IAAI,kBAAqD,CAAC;AAElG,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,UAAU,GAAG,kBAAkB,CAAC;AAEjF,MAAM,MAAM,YAAY,GAAG,gBAAgB,GACzC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAE7F,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,GAClE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,GAAG;IACvC,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC"}
@@ -1,3 +0,0 @@
1
- export * from './Toolbar';
2
- export * from './defs';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
@@ -1,71 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import React, { useCallback } from 'react';
6
-
7
- import { Toolbar as NaturalToolbar } from '@dxos/react-ui';
8
-
9
- import { ToolbarDropdownMenu } from './ToolbarDropdownMenu';
10
- import { ToolbarToggleGroup } from './ToolbarToggleGroup';
11
- import { isMenu, isSeparator, type ToolbarProps } from './defs';
12
- import { type MenuAction } from '../../defs';
13
- import { ActionLabel } from '../ActionLabel';
14
-
15
- const ToolbarItem = ({
16
- iconSize,
17
- action,
18
- onAction,
19
- }: Pick<ToolbarProps, 'iconSize' | 'onAction'> & {
20
- action: MenuAction;
21
- }) => {
22
- const handleClick = useCallback(() => {
23
- onAction?.(action);
24
- }, [action, onAction]);
25
- const { icon, iconOnly = true, disabled, testId } = action.properties;
26
- return (
27
- <NaturalToolbar.IconButton
28
- key={action.id}
29
- iconOnly={iconOnly}
30
- variant='ghost'
31
- icon={icon}
32
- size={iconSize}
33
- label={<ActionLabel action={action} />}
34
- disabled={disabled}
35
- onClick={handleClick}
36
- {...(testId && { 'data-testid': testId })}
37
- />
38
- );
39
- };
40
-
41
- export const Toolbar = ({ actions: items, onAction, iconSize = 5, graph, ...props }: ToolbarProps) => {
42
- return (
43
- <NaturalToolbar.Root {...props}>
44
- {items?.map((item, i) =>
45
- isSeparator(item) ? (
46
- <NaturalToolbar.Separator key={i} variant={item.properties.variant} />
47
- ) : isMenu(item) ? (
48
- item.properties.variant === 'dropdownMenu' ? (
49
- <ToolbarDropdownMenu
50
- key={item.id}
51
- actionGroup={item}
52
- onAction={onAction}
53
- iconSize={iconSize}
54
- graph={graph}
55
- />
56
- ) : (
57
- <ToolbarToggleGroup
58
- key={item.id}
59
- actionGroup={item}
60
- onAction={onAction}
61
- iconSize={iconSize}
62
- graph={graph}
63
- />
64
- )
65
- ) : (
66
- <ToolbarItem key={item.id} action={item as MenuAction} onAction={onAction} iconSize={iconSize} />
67
- ),
68
- )}
69
- </NaturalToolbar.Root>
70
- );
71
- };
@@ -1,36 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import React, { useMemo, useRef } from 'react';
6
-
7
- import { Toolbar as NaturalToolbar } from '@dxos/react-ui';
8
-
9
- import { type ToolbarActionGroupProps } from './defs';
10
- import { type MenuAction } from '../../defs';
11
- import { ActionLabel } from '../ActionLabel';
12
- import { DropdownMenu } from '../DropdownMenu';
13
-
14
- export const ToolbarDropdownMenu = ({ actionGroup, graph, onAction, applyActiveIcon }: ToolbarActionGroupProps) => {
15
- const menuActions = useMemo(() => (graph ? graph.actions(actionGroup) : []) as MenuAction[], [actionGroup, graph]);
16
- const { icon, iconOnly = true, disabled, testId } = actionGroup.properties;
17
- const suppressNextTooltip = useRef(false);
18
-
19
- return (
20
- <DropdownMenu.Root actions={menuActions} onAction={onAction} suppressNextTooltip={suppressNextTooltip}>
21
- <DropdownMenu.Trigger asChild>
22
- <NaturalToolbar.IconButton
23
- size={5}
24
- variant='ghost'
25
- iconOnly={iconOnly}
26
- disabled={disabled}
27
- icon={(applyActiveIcon && menuActions.find((action) => !!action.properties.checked)?.properties.icon) || icon}
28
- label={<ActionLabel action={actionGroup} />}
29
- {...(testId && { 'data-testid': testId })}
30
- suppressNextTooltip={suppressNextTooltip}
31
- caretDown
32
- />
33
- </DropdownMenu.Trigger>
34
- </DropdownMenu.Root>
35
- );
36
- };
@@ -1,39 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import React, { useMemo } from 'react';
6
-
7
- import { Toolbar as NaturalToolbar } from '@dxos/react-ui';
8
-
9
- import type { ToolbarActionGroupProps } from './defs';
10
- import { type MenuAction } from '../../defs';
11
- import { ActionLabel } from '../ActionLabel';
12
-
13
- const ToolbarToggleGroupItem = ({ action }: { action: MenuAction }) => {
14
- const { icon, iconOnly, disabled } = action.properties;
15
- return (
16
- <NaturalToolbar.ToggleGroupIconItem
17
- key={action.id}
18
- value={action.id}
19
- icon={icon}
20
- iconOnly={iconOnly}
21
- disabled={disabled}
22
- label={<ActionLabel action={action} />}
23
- />
24
- );
25
- };
26
-
27
- export const ToolbarToggleGroup = ({ actionGroup, graph }: ToolbarActionGroupProps) => {
28
- const menuActions = useMemo(() => (graph ? (graph.actions(actionGroup) as MenuAction[]) : []), [actionGroup, graph]);
29
- const { selectCardinality, value } = actionGroup.properties;
30
- return (
31
- // TODO(thure): This is extremely difficult to manage, what do?
32
- // @ts-ignore
33
- <NaturalToolbar.ToggleGroup type={selectCardinality} value={value}>
34
- {menuActions.map((action) => (
35
- <ToolbarToggleGroupItem key={action.id} action={action} />
36
- ))}
37
- </NaturalToolbar.ToggleGroup>
38
- );
39
- };
@@ -1,36 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { type Node, type ActionGroup, type Graph, ACTION_GROUP_TYPE } from '@dxos/app-graph';
6
- import { type ToolbarRootProps, type ToolbarSeparatorProps, type IconButtonProps } from '@dxos/react-ui';
7
-
8
- import { type MenuAction, type MenuActionProperties, type MenuProps } from '../../defs';
9
-
10
- export const ToolbarSeparatorType = '@dxos/react-ui-toolbar/separator' as const;
11
-
12
- export type ToolbarSeparatorNode = Node<never, Pick<ToolbarSeparatorProps, 'variant'>> & {
13
- type: typeof ToolbarSeparatorType;
14
- };
15
-
16
- export const isSeparator = (node: Node): node is ToolbarSeparatorNode => node.type === ToolbarSeparatorType;
17
-
18
- export type ToolbarActionGroupProperties = Omit<MenuActionProperties, 'variant'> & {
19
- variant: 'dropdownMenu' | 'toggleGroup';
20
- } & ({ selectCardinality?: 'single'; value?: string } | { selectCardinality?: 'multiple'; value?: string[] });
21
-
22
- export type ToolbarActionGroup = ActionGroup<ToolbarActionGroupProperties>;
23
-
24
- export const isMenu = (node: Node): node is ToolbarActionGroup => node.type === ACTION_GROUP_TYPE;
25
-
26
- export type ToolbarItem = ToolbarSeparatorNode | MenuAction | ToolbarActionGroup;
27
-
28
- export type ToolbarProps = ToolbarRootProps &
29
- MenuProps<ToolbarItem, MenuAction> & { iconSize?: IconButtonProps['size']; graph?: Graph };
30
-
31
- export type ToolbarActionGroupProps = Pick<ToolbarProps, 'iconSize'> &
32
- Omit<MenuProps<MenuAction>, 'actions'> & {
33
- actionGroup: ToolbarActionGroup;
34
- graph?: Graph;
35
- applyActiveIcon?: boolean;
36
- };
@@ -1,6 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- export * from './Toolbar';
6
- export * from './defs';