@dxos/react-ui-menu 0.8.2-staging.7ac8446 → 0.8.2

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 (52) hide show
  1. package/dist/lib/browser/index.mjs +298 -262
  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 +299 -264
  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 +298 -262
  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/ActionLabel.d.ts +8 -4
  11. package/dist/types/src/components/ActionLabel.d.ts.map +1 -1
  12. package/dist/types/src/components/DropdownMenu.d.ts +4 -4
  13. package/dist/types/src/components/DropdownMenu.d.ts.map +1 -1
  14. package/dist/types/src/components/MenuContext.d.ts +4 -13
  15. package/dist/types/src/components/MenuContext.d.ts.map +1 -1
  16. package/dist/types/src/{testing → components}/Menus.stories.d.ts +1 -1
  17. package/dist/types/src/components/Menus.stories.d.ts.map +1 -0
  18. package/dist/types/src/components/ToolbarMenu.d.ts +5 -1
  19. package/dist/types/src/components/ToolbarMenu.d.ts.map +1 -1
  20. package/dist/types/src/hooks/index.d.ts +2 -0
  21. package/dist/types/src/hooks/index.d.ts.map +1 -0
  22. package/dist/types/src/hooks/useMenuActions.d.ts +13 -0
  23. package/dist/types/src/hooks/useMenuActions.d.ts.map +1 -0
  24. package/dist/types/src/index.d.ts +2 -1
  25. package/dist/types/src/index.d.ts.map +1 -1
  26. package/dist/types/src/testing/generator.d.ts +27 -0
  27. package/dist/types/src/testing/generator.d.ts.map +1 -0
  28. package/dist/types/src/testing/index.d.ts +1 -25
  29. package/dist/types/src/testing/index.d.ts.map +1 -1
  30. package/dist/types/src/{defs.d.ts → types.d.ts} +3 -5
  31. package/dist/types/src/types.d.ts.map +1 -0
  32. package/dist/types/src/util.d.ts +2 -2
  33. package/dist/types/src/util.d.ts.map +1 -1
  34. package/dist/types/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +20 -13
  36. package/src/components/ActionLabel.tsx +11 -8
  37. package/src/components/DropdownMenu.tsx +7 -23
  38. package/src/components/MenuContext.tsx +11 -26
  39. package/src/{testing → components}/Menus.stories.tsx +13 -13
  40. package/src/components/ToolbarMenu.tsx +29 -32
  41. package/src/hooks/index.ts +5 -0
  42. package/src/hooks/useMenuActions.ts +69 -0
  43. package/src/index.ts +3 -1
  44. package/src/testing/generator.ts +116 -0
  45. package/src/testing/index.ts +1 -107
  46. package/src/{defs.ts → types.ts} +2 -5
  47. package/src/util.ts +7 -7
  48. package/dist/types/src/defs.d.ts.map +0 -1
  49. package/dist/types/src/hooks.d.ts +0 -17
  50. package/dist/types/src/hooks.d.ts.map +0 -1
  51. package/dist/types/src/testing/Menus.stories.d.ts.map +0 -1
  52. package/src/hooks.ts +0 -72
@@ -1,9 +1,14 @@
1
+ // packages/ui/react-ui-menu/src/index.ts
2
+ import { rxFromSignal } from "@dxos/app-graph";
3
+
1
4
  // packages/ui/react-ui-menu/src/components/DropdownMenu.tsx
5
+ import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
2
6
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
3
7
  import React3, { useCallback } from "react";
4
8
  import { DropdownMenu as NaturalDropdownMenu, Icon } from "@dxos/react-ui";
5
9
 
6
10
  // packages/ui/react-ui-menu/src/components/ActionLabel.tsx
11
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
7
12
  import React from "react";
8
13
  import { keySymbols } from "@dxos/keyboard";
9
14
  import { toLocalizedString, useTranslation } from "@dxos/react-ui";
@@ -25,13 +30,11 @@ import { getHostPlatform } from "@dxos/util";
25
30
  var getShortcut = (action) => {
26
31
  return typeof action.properties?.keyBinding === "string" ? action.properties.keyBinding : action.properties?.keyBinding?.[getHostPlatform()];
27
32
  };
28
- var noop = () => {
29
- };
30
- var createMenuAction = (id, properties) => ({
33
+ var createMenuAction = (id, invoke, properties) => ({
31
34
  id,
32
35
  type: ACTION_TYPE,
33
36
  properties,
34
- data: noop
37
+ data: invoke
35
38
  });
36
39
  var createMenuItemGroup = (id, properties) => ({
37
40
  id,
@@ -78,16 +81,26 @@ var createLineSeparator = (id = "line", source = "root") => ({
78
81
 
79
82
  // packages/ui/react-ui-menu/src/components/ActionLabel.tsx
80
83
  var ActionLabel = ({ action }) => {
84
+ var _effect = _useSignals();
85
+ try {
86
+ const shortcut = getShortcut(action);
87
+ const { t } = useTranslation(translationKey);
88
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
89
+ className: "grow truncate"
90
+ }, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
91
+ className: mx("shrink-0", descriptionText)
92
+ }, keySymbols(shortcut).join("")));
93
+ } finally {
94
+ _effect.f();
95
+ }
96
+ };
97
+ var actionLabel = (action, t) => {
81
98
  const shortcut = getShortcut(action);
82
- const { t } = useTranslation(translationKey);
83
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
84
- className: "grow truncate"
85
- }, toLocalizedString(action.properties.label, t)), shortcut && /* @__PURE__ */ React.createElement("span", {
86
- className: mx("shrink-0", descriptionText)
87
- }, keySymbols(shortcut).join("")));
99
+ return `${toLocalizedString(action.properties.label, t)}${shortcut ? ` (${keySymbols(shortcut).join("")})` : ""}`;
88
100
  };
89
101
 
90
102
  // packages/ui/react-ui-menu/src/components/MenuContext.tsx
103
+ import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
91
104
  import { createContextScope } from "@radix-ui/react-context";
92
105
  import React2, { useMemo } from "react";
93
106
  var MENU_NAME = "GraphMenu";
@@ -95,87 +108,94 @@ var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, []);
95
108
  var [MenuContextProvider, useMenu] = createMenuContext(MENU_NAME);
96
109
  var menuContextDefaults = {
97
110
  iconSize: 5,
98
- onAction: () => {
99
- },
100
- resolveGroupItems: () => null
111
+ useGroupItems: () => null
101
112
  };
102
113
  var useMenuScope = createMenuScope();
103
- var MenuProvider = ({ children, resolveGroupItems = menuContextDefaults.resolveGroupItems, onAction = menuContextDefaults.onAction, iconSize = menuContextDefaults.iconSize, attendableId }) => {
104
- const { scope } = useMenuScope(void 0);
105
- return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
106
- resolveGroupItems,
107
- onAction,
108
- iconSize,
109
- attendableId,
110
- scope
111
- }, children);
114
+ var MenuProvider = ({ children, useGroupItems = menuContextDefaults.useGroupItems, iconSize = menuContextDefaults.iconSize, attendableId }) => {
115
+ var _effect = _useSignals2();
116
+ try {
117
+ const { scope } = useMenuScope(void 0);
118
+ return /* @__PURE__ */ React2.createElement(MenuContextProvider, {
119
+ useGroupItems,
120
+ iconSize,
121
+ attendableId,
122
+ scope
123
+ }, children);
124
+ } finally {
125
+ _effect.f();
126
+ }
112
127
  };
113
128
  var useMenuItems = (group, propsItems, consumerName = "useMenuItemConsumer", __menuScope) => {
114
- const { resolveGroupItems } = useMenu(consumerName, __menuScope);
115
- return useMemo(() => propsItems ?? resolveGroupItems?.(group) ?? void 0, [
129
+ const { useGroupItems } = useMenu(consumerName, __menuScope);
130
+ const groupItems = useGroupItems(group);
131
+ return useMemo(() => propsItems ?? groupItems ?? void 0, [
116
132
  propsItems,
117
- group,
118
- resolveGroupItems
133
+ groupItems
119
134
  ]);
120
135
  };
121
136
 
122
137
  // packages/ui/react-ui-menu/src/components/DropdownMenu.tsx
123
138
  var DropdownMenuItem = ({ item, onClick, __menuScope }) => {
124
- const action = item;
125
- const handleClick = useCallback((event) => onClick(action, event), [
126
- action,
127
- onClick
128
- ]);
129
- const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
130
- return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Item, {
131
- onClick: handleClick,
132
- classNames: "gap-2",
133
- disabled: action.properties?.disabled,
134
- ...action.properties?.testId && {
135
- "data-testid": action.properties.testId
136
- }
137
- }, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon, {
138
- icon: action.properties.icon,
139
- size: iconSize
140
- }), /* @__PURE__ */ React3.createElement(ActionLabel, {
141
- action
142
- }));
139
+ var _effect = _useSignals3();
140
+ try {
141
+ const action = item;
142
+ const handleClick = useCallback((event) => onClick(action, event), [
143
+ action,
144
+ onClick
145
+ ]);
146
+ const { iconSize } = useMenu("DropdownMenuItem", __menuScope);
147
+ return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Item, {
148
+ onClick: handleClick,
149
+ classNames: "gap-2",
150
+ disabled: action.properties?.disabled,
151
+ ...action.properties?.testId && {
152
+ "data-testid": action.properties.testId
153
+ }
154
+ }, action.properties?.icon && /* @__PURE__ */ React3.createElement(Icon, {
155
+ icon: action.properties.icon,
156
+ size: iconSize
157
+ }), /* @__PURE__ */ React3.createElement(ActionLabel, {
158
+ action
159
+ }));
160
+ } finally {
161
+ _effect.f();
162
+ }
143
163
  };
144
- var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, suppressNextTooltip, children, __menuScope, ...naturalProps }) => {
145
- const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
146
- prop: open,
147
- defaultProp: defaultOpen,
148
- onChange: onOpenChange
149
- });
150
- const { onAction } = useMenu("DropdownMenuRoot", __menuScope);
151
- const handleActionClick = useCallback((action, event) => {
152
- if (action.properties?.disabled) {
153
- return;
154
- }
155
- event.stopPropagation();
156
- if (suppressNextTooltip) {
157
- suppressNextTooltip.current = true;
158
- }
159
- setOptionsMenuOpen(false);
160
- onAction?.(action);
161
- }, [
162
- onAction
163
- ]);
164
- const items = useMenuItems(group, propsItems);
165
- return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
166
- open: optionsMenuOpen,
167
- onOpenChange: (nextOpen) => {
168
- if (!nextOpen && suppressNextTooltip) {
169
- suppressNextTooltip.current = true;
164
+ var DropdownMenuRoot = ({ items: propsItems, group, open, defaultOpen, onOpenChange, caller, children, __menuScope, ...naturalProps }) => {
165
+ var _effect = _useSignals3();
166
+ try {
167
+ const [optionsMenuOpen, setOptionsMenuOpen] = useControllableState({
168
+ prop: open,
169
+ defaultProp: defaultOpen,
170
+ onChange: onOpenChange
171
+ });
172
+ const handleActionClick = useCallback((action, event) => {
173
+ if (action.properties?.disabled) {
174
+ return;
170
175
  }
171
- return setOptionsMenuOpen(nextOpen);
172
- },
173
- ...naturalProps
174
- }, children, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React3.createElement(DropdownMenuItem, {
175
- key: item.id,
176
- item,
177
- onClick: handleActionClick
178
- }))), /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Arrow, null))));
176
+ event.stopPropagation();
177
+ setOptionsMenuOpen(false);
178
+ void action.data?.({
179
+ parent: group,
180
+ caller
181
+ });
182
+ }, [
183
+ group,
184
+ caller
185
+ ]);
186
+ const items = useMenuItems(group, propsItems);
187
+ return /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Root, {
188
+ open: optionsMenuOpen,
189
+ onOpenChange: setOptionsMenuOpen,
190
+ ...naturalProps
191
+ }, children, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Content, null, /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Viewport, null, items?.map((item) => /* @__PURE__ */ React3.createElement(DropdownMenuItem, {
192
+ key: item.id,
193
+ item,
194
+ onClick: handleActionClick
195
+ }))), /* @__PURE__ */ React3.createElement(NaturalDropdownMenu.Arrow, null))));
196
+ } finally {
197
+ _effect.f();
198
+ }
179
199
  };
180
200
  var DropdownMenu = {
181
201
  Root: DropdownMenuRoot,
@@ -184,11 +204,12 @@ var DropdownMenu = {
184
204
  };
185
205
 
186
206
  // packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx
187
- import React4, { useCallback as useCallback2, useRef } from "react";
188
- import { Icon as Icon2, Toolbar as NaturalToolbar } from "@dxos/react-ui";
207
+ import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
208
+ import React4, { useCallback as useCallback2 } from "react";
209
+ import { Icon as Icon2, Toolbar as NaturalToolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
189
210
  import { useAttention } from "@dxos/react-ui-attention";
190
211
 
191
- // packages/ui/react-ui-menu/src/defs.ts
212
+ // packages/ui/react-ui-menu/src/types.ts
192
213
  import { ACTION_GROUP_TYPE as ACTION_GROUP_TYPE2 } from "@dxos/app-graph";
193
214
  var MenuSeparatorType = "@dxos/react-ui-toolbar/separator";
194
215
  var isSeparator = (node) => node.type === MenuSeparatorType;
@@ -196,174 +217,193 @@ var isMenuGroup = (node) => node.type === ACTION_GROUP_TYPE2;
196
217
 
197
218
  // packages/ui/react-ui-menu/src/components/ToolbarMenu.tsx
198
219
  var ActionToolbarItem = ({ action, __menuScope }) => {
199
- const { onAction, iconSize } = useMenu("ActionToolbarItem", __menuScope);
200
- const handleClick = useCallback2(() => {
201
- onAction?.(action);
202
- }, [
203
- action,
204
- onAction
205
- ]);
206
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
207
- const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
208
- const rootProps = icon ? {
209
- icon,
210
- size: iconSize,
211
- iconOnly,
212
- label: /* @__PURE__ */ React4.createElement(ActionLabel, {
213
- action
214
- })
215
- } : {
216
- children: /* @__PURE__ */ React4.createElement(ActionLabel, {
220
+ var _effect = _useSignals4();
221
+ try {
222
+ const { iconSize } = useMenu("ActionToolbarItem", __menuScope);
223
+ const { t } = useTranslation2(translationKey);
224
+ const handleClick = useCallback2(() => action.data?.(), [
217
225
  action
218
- })
219
- };
220
- return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
221
- key: action.id,
222
- disabled,
223
- onClick: handleClick,
224
- variant: "ghost",
225
- ...testId && {
226
- "data-testid": testId
227
- },
228
- ...rootProps,
229
- classNames
230
- });
226
+ ]);
227
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
228
+ const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
229
+ const rootProps = icon ? {
230
+ icon,
231
+ size: iconSize,
232
+ iconOnly,
233
+ label: actionLabel(action, t)
234
+ } : {
235
+ children: /* @__PURE__ */ React4.createElement(ActionLabel, {
236
+ action
237
+ })
238
+ };
239
+ return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
240
+ key: action.id,
241
+ disabled,
242
+ onClick: handleClick,
243
+ variant: "ghost",
244
+ ...testId && {
245
+ "data-testid": testId
246
+ },
247
+ ...rootProps,
248
+ classNames
249
+ });
250
+ } finally {
251
+ _effect.f();
252
+ }
231
253
  };
232
254
  var DropdownMenuToolbarItem = ({ group, items: propsItems, __menuScope }) => {
233
- const { iconOnly, disabled, testId } = group.properties;
234
- const suppressNextTooltip = useRef(false);
235
- const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
236
- const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
237
- const activeItem = items?.find((item) => !!item.properties.checked);
238
- const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
239
- activeItem?.properties.icon || group.properties.icon;
240
- const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
241
- const label = /* @__PURE__ */ React4.createElement(ActionLabel, {
242
- action: group.properties.applyActive && activeItem ? activeItem : group
243
- });
244
- const rootProps = icon ? {
245
- icon,
246
- size: iconSize,
247
- iconOnly,
248
- label,
249
- caretDown: true,
250
- suppressNextTooltip
251
- } : {
252
- children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, label, /* @__PURE__ */ React4.createElement(Icon2, {
253
- size: 3,
254
- icon: "ph--caret-down--bold",
255
- classNames: "mis-1"
256
- }))
257
- };
258
- return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
259
- group,
260
- items,
261
- suppressNextTooltip
262
- }, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
263
- asChild: true
264
- }, /* @__PURE__ */ React4.createElement(Root, {
265
- variant: "ghost",
266
- disabled,
267
- ...rootProps,
268
- ...testId && {
269
- "data-testid": testId
270
- }
271
- })));
255
+ var _effect = _useSignals4();
256
+ try {
257
+ const { iconOnly, disabled, testId } = group.properties;
258
+ const { t } = useTranslation2(translationKey);
259
+ const { iconSize } = useMenu("DropdownMenuToolbarItem", __menuScope);
260
+ const items = useMenuItems(group, propsItems, "DropdownMenuToolbarItem", __menuScope);
261
+ const activeItem = items?.find((item) => !!item.properties.checked);
262
+ const icon = group.properties.applyActive && // TODO(thure): Handle other menu item types.
263
+ activeItem?.properties.icon || group.properties.icon;
264
+ const Root = icon ? NaturalToolbar.IconButton : NaturalToolbar.Button;
265
+ const labelAction = group.properties.applyActive && activeItem ? activeItem : group;
266
+ const rootProps = icon ? {
267
+ icon,
268
+ size: iconSize,
269
+ iconOnly,
270
+ label: actionLabel(labelAction, t),
271
+ caretDown: true
272
+ } : {
273
+ children: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(ActionLabel, {
274
+ action: labelAction
275
+ }), /* @__PURE__ */ React4.createElement(Icon2, {
276
+ size: 3,
277
+ icon: "ph--caret-down--bold",
278
+ classNames: "mis-1"
279
+ }))
280
+ };
281
+ return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
282
+ group,
283
+ items
284
+ }, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
285
+ asChild: true
286
+ }, /* @__PURE__ */ React4.createElement(Root, {
287
+ variant: "ghost",
288
+ disabled,
289
+ ...rootProps,
290
+ ...testId && {
291
+ "data-testid": testId
292
+ }
293
+ })));
294
+ } finally {
295
+ _effect.f();
296
+ }
272
297
  };
273
- var ToggleGroupItem = ({ action, __menuScope }) => {
274
- const { iconSize, onAction } = useMenu("ToggleGroupItem", __menuScope);
275
- const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
276
- const handleClick = useCallback2(() => {
277
- onAction?.(action);
278
- }, [
279
- action,
280
- onAction
281
- ]);
282
- const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
283
- const rootProps = icon ? {
284
- icon,
285
- size: iconSize,
286
- iconOnly,
287
- label: /* @__PURE__ */ React4.createElement(ActionLabel, {
288
- action
289
- })
290
- } : {
291
- children: /* @__PURE__ */ React4.createElement(ActionLabel, {
292
- action
293
- })
294
- };
295
- return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
296
- key: action.id,
297
- value: action.id,
298
- disabled,
299
- onClick: handleClick,
300
- variant: "ghost",
301
- ...testId && {
302
- "data-testid": testId
303
- },
304
- ...rootProps,
305
- classNames
306
- });
298
+ var ToggleGroupItem = ({ group, action, __menuScope }) => {
299
+ var _effect = _useSignals4();
300
+ try {
301
+ const { iconSize } = useMenu("ToggleGroupItem", __menuScope);
302
+ const { t } = useTranslation2(translationKey);
303
+ const { icon, iconOnly = true, disabled, testId, hidden, classNames } = action.properties;
304
+ const handleClick = useCallback2(() => action.data?.({
305
+ parent: group
306
+ }), [
307
+ action,
308
+ group
309
+ ]);
310
+ const Root = icon ? NaturalToolbar.ToggleGroupIconItem : NaturalToolbar.ToggleGroupItem;
311
+ const rootProps = icon ? {
312
+ icon,
313
+ size: iconSize,
314
+ iconOnly,
315
+ label: actionLabel(action, t)
316
+ } : {
317
+ children: /* @__PURE__ */ React4.createElement(ActionLabel, {
318
+ action
319
+ })
320
+ };
321
+ return hidden ? null : /* @__PURE__ */ React4.createElement(Root, {
322
+ key: action.id,
323
+ value: action.id,
324
+ disabled,
325
+ onClick: handleClick,
326
+ variant: "ghost",
327
+ ...testId && {
328
+ "data-testid": testId
329
+ },
330
+ ...rootProps,
331
+ classNames
332
+ });
333
+ } finally {
334
+ _effect.f();
335
+ }
307
336
  };
308
337
  var ToggleGroupToolbarItem = ({ group, items: propsItems, __menuScope }) => {
309
- const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
310
- const { selectCardinality, value } = group.properties;
311
- return (
312
- // TODO(thure): The type here is difficult to manage, what do?
313
- // @ts-ignore
314
- /* @__PURE__ */ React4.createElement(
315
- NaturalToolbar.ToggleGroup,
316
- {
317
- type: selectCardinality,
318
- value
319
- },
320
- // TODO(thure): Handle other menu item types.
321
- items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
322
- key: action.id,
323
- action
324
- }))
325
- )
326
- );
338
+ var _effect = _useSignals4();
339
+ try {
340
+ const items = useMenuItems(group, propsItems, "ToggleGroupToolbarItem", __menuScope);
341
+ const { selectCardinality, value } = group.properties;
342
+ return (
343
+ // TODO(thure): The type here is difficult to manage, what do?
344
+ // @ts-ignore
345
+ /* @__PURE__ */ React4.createElement(
346
+ NaturalToolbar.ToggleGroup,
347
+ {
348
+ type: selectCardinality,
349
+ value
350
+ },
351
+ // TODO(thure): Handle other menu item types.
352
+ items.map((action) => /* @__PURE__ */ React4.createElement(ToggleGroupItem, {
353
+ key: action.id,
354
+ group,
355
+ action
356
+ }))
357
+ )
358
+ );
359
+ } finally {
360
+ _effect.f();
361
+ }
327
362
  };
328
363
  var ToolbarMenu = ({ __menuScope, classNames, ...props }) => {
329
- const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
330
- const { attendableId } = useMenu("ToolbarMenu", __menuScope);
331
- const { hasAttention } = useAttention(attendableId);
332
- return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
333
- ...props,
334
- classNames: [
335
- "p-0 pointer-fine:p-1 attention-surface",
336
- !hasAttention && "opacity-20",
337
- classNames
338
- ]
339
- }, items?.map((item, i) => isSeparator(item) ? /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
340
- key: i,
341
- variant: item.properties.variant
342
- }) : isMenuGroup(item) ? item.properties.variant === "dropdownMenu" ? (
343
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
344
- /* @__PURE__ */ React4.createElement(DropdownMenuToolbarItem, {
345
- key: item.id,
346
- group: item
347
- })
348
- ) : (
349
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
350
- /* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
351
- key: item.id,
352
- group: item
353
- })
354
- ) : (
355
- // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
356
- /* @__PURE__ */ React4.createElement(ActionToolbarItem, {
357
- key: item.id,
358
- action: item
359
- })
360
- )));
364
+ var _effect = _useSignals4();
365
+ try {
366
+ const items = useMenuItems(void 0, void 0, "ToolbarMenu", __menuScope);
367
+ const { attendableId } = useMenu("ToolbarMenu", __menuScope);
368
+ const { hasAttention } = useAttention(attendableId);
369
+ return /* @__PURE__ */ React4.createElement(NaturalToolbar.Root, {
370
+ ...props,
371
+ classNames: [
372
+ "p-1",
373
+ attendableId && !hasAttention && "[&>*]:opacity-20 !bg-transparent",
374
+ classNames
375
+ ]
376
+ }, items?.map((item, i) => isSeparator(item) ? /* @__PURE__ */ React4.createElement(NaturalToolbar.Separator, {
377
+ key: i,
378
+ variant: item.properties.variant
379
+ }) : isMenuGroup(item) ? item.properties.variant === "dropdownMenu" ? (
380
+ // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
381
+ /* @__PURE__ */ React4.createElement(DropdownMenuToolbarItem, {
382
+ key: item.id,
383
+ group: item
384
+ })
385
+ ) : (
386
+ // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
387
+ /* @__PURE__ */ React4.createElement(ToggleGroupToolbarItem, {
388
+ key: item.id,
389
+ group: item
390
+ })
391
+ ) : (
392
+ // TODO(thure): Figure out type narrowing that doesn’t require so much use of `as`.
393
+ /* @__PURE__ */ React4.createElement(ActionToolbarItem, {
394
+ key: item.id,
395
+ action: item
396
+ })
397
+ )));
398
+ } finally {
399
+ _effect.f();
400
+ }
361
401
  };
362
402
 
363
- // packages/ui/react-ui-menu/src/hooks.ts
364
- import { useSignalEffect } from "@preact/signals-react";
365
- import { useCallback as useCallback3, useState } from "react";
366
- import { Graph } from "@dxos/app-graph";
403
+ // packages/ui/react-ui-menu/src/hooks/useMenuActions.ts
404
+ import { RegistryContext, useRxValue } from "@effect-rx/rx-react";
405
+ import { useCallback as useCallback3, useContext, useEffect, useState } from "react";
406
+ import { Graph, ROOT_ID } from "@dxos/app-graph";
367
407
  var edgesArrayToRecord = (edges) => {
368
408
  return Object.fromEntries(Object.entries(edges.reduce((acc, { source, target }) => {
369
409
  if (!acc[source]) {
@@ -387,35 +427,30 @@ var edgesArrayToRecord = (edges) => {
387
427
  targetEdges.inbound.push(source);
388
428
  }
389
429
  return acc;
390
- }, {})).map(([id, { outbound }]) => [
391
- id,
392
- outbound
393
- ]));
430
+ }, {})));
394
431
  };
395
- var useMenuActions = (actionCreator) => {
396
- const initialMenuGraphProps = actionCreator();
432
+ var useMenuActions = (props) => {
433
+ const registry = useContext(RegistryContext);
434
+ const menuGraphProps = useRxValue(props);
397
435
  const [graph] = useState(new Graph({
398
- nodes: initialMenuGraphProps.nodes,
399
- edges: edgesArrayToRecord(initialMenuGraphProps.edges)
436
+ registry,
437
+ nodes: menuGraphProps.nodes,
438
+ edges: edgesArrayToRecord(menuGraphProps.edges)
400
439
  }));
401
- useSignalEffect(() => {
402
- const menuGraphProps = actionCreator();
403
- graph._addNodes(menuGraphProps.nodes);
404
- graph._addEdges(menuGraphProps.edges);
405
- });
406
- const resolveGroupItems = useCallback3((sourceNode = graph.root) => {
407
- if (graph) {
408
- return graph.nodes(sourceNode, {
409
- filter: (n) => true
410
- }) || null;
411
- } else {
412
- return null;
413
- }
440
+ useEffect(() => {
441
+ graph.addNodes(menuGraphProps.nodes);
442
+ graph.addEdges(menuGraphProps.edges);
443
+ }, [
444
+ menuGraphProps
445
+ ]);
446
+ const useGroupItems = useCallback3((sourceNode) => {
447
+ const items = useRxValue(graph.connections(sourceNode?.id || ROOT_ID));
448
+ return items;
414
449
  }, [
415
450
  graph
416
451
  ]);
417
452
  return {
418
- resolveGroupItems
453
+ useGroupItems
419
454
  };
420
455
  };
421
456
  export {
@@ -431,6 +466,7 @@ export {
431
466
  isMenuGroup,
432
467
  isSeparator,
433
468
  menuContextDefaults,
469
+ rxFromSignal,
434
470
  useMenu,
435
471
  useMenuActions,
436
472
  useMenuItems