@radix-ui/react-navigation-menu 1.2.20 → 1.2.21

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/dist/index.d.mts CHANGED
@@ -5,8 +5,21 @@ import { Primitive } from '@radix-ui/react-primitive';
5
5
  import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
6
6
  import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';
7
7
 
8
- type Orientation = 'vertical' | 'horizontal';
9
- type Direction = 'ltr' | 'rtl';
8
+ declare const Orientation: {
9
+ readonly Vertical: "vertical";
10
+ readonly Horizontal: "horizontal";
11
+ };
12
+ type Orientation = (typeof Orientation)[keyof typeof Orientation];
13
+ declare const Direction: {
14
+ readonly LTR: "ltr";
15
+ readonly RTL: "rtl";
16
+ };
17
+ type Direction = (typeof Direction)[keyof typeof Direction];
18
+ declare const ActivationMode: {
19
+ readonly Automatic: "automatic";
20
+ readonly Manual: "manual";
21
+ };
22
+ type ActivationMode = (typeof ActivationMode)[keyof typeof ActivationMode];
10
23
  declare const createNavigationMenuScope: _radix_ui_react_context.CreateScope;
11
24
  type NavigationMenuElement = React.ComponentRef<typeof Primitive.nav>;
12
25
  type PrimitiveNavProps = React.ComponentPropsWithoutRef<typeof Primitive.nav>;
@@ -17,15 +30,28 @@ interface NavigationMenuProps extends Omit<NavigationMenuProviderProps, keyof Na
17
30
  dir?: Direction;
18
31
  orientation?: Orientation;
19
32
  /**
20
- * The duration from when the pointer enters the trigger until the tooltip gets opened.
21
- * @defaultValue 200
33
+ * The duration from when the pointer enters the trigger until the tooltip
34
+ * gets opened. When `activationMode` is `manual`, this prop is ignored.
35
+ *
36
+ * @default 200
22
37
  */
23
38
  delayDuration?: number;
24
39
  /**
25
- * How much time a user has to enter another trigger without incurring a delay again.
26
- * @defaultValue 300
40
+ * How much time a user has to enter another trigger without incurring a delay
41
+ * again. When `activationMode` is `manual`, this prop is ignored.
42
+ *
43
+ * @default 300
27
44
  */
28
45
  skipDelayDuration?: number;
46
+ /**
47
+ * Whether an item is activated automatically or manually.
48
+ * - `"automatic"`: hovering or focusing a trigger opens its item, and moving
49
+ * away closes it after a short delay.
50
+ * - `"manual"`: clicking a trigger toggles the item; hover and focus are ignored
51
+ *
52
+ * @default "automatic"
53
+ */
54
+ activationMode?: ActivationMode;
29
55
  }
30
56
  declare const NavigationMenu: React.ForwardRefExoticComponent<NavigationMenuProps & React.RefAttributes<HTMLElement>>;
31
57
  type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
@@ -34,6 +60,24 @@ interface NavigationMenuSubProps extends Omit<NavigationMenuProviderProps, keyof
34
60
  defaultValue?: string;
35
61
  onValueChange?: (value: string) => void;
36
62
  orientation?: Orientation;
63
+ /**
64
+ * Whether an item is activated automatically or manually.
65
+ * - `"automatic"`: hovering or focusing a trigger opens its item, and moving
66
+ * away closes it after a short delay.
67
+ * - `"manual"`: clicking a trigger toggles the item; hover and focus are
68
+ * ignored
69
+ *
70
+ * The default value is inherited from the parent Navigation Menu root
71
+ * component. If no value is provided to the parent, the default value is
72
+ * `"automatic"`.
73
+ */
74
+ activationMode?: ActivationMode;
75
+ /**
76
+ * When true, clicking a sub-menu item's trigger once it's active will not deactivate it.
77
+ *
78
+ * @default true
79
+ */
80
+ disableToggle?: boolean;
37
81
  }
38
82
  declare const NavigationMenuSub: React.ForwardRefExoticComponent<NavigationMenuSubProps & React.RefAttributes<HTMLDivElement>>;
39
83
  interface NavigationMenuProviderPrivateProps {
@@ -42,6 +86,7 @@ interface NavigationMenuProviderPrivateProps {
42
86
  children: React.ReactNode;
43
87
  orientation: Orientation;
44
88
  dir: Direction;
89
+ activationMode: ActivationMode;
45
90
  rootNavigationMenu: NavigationMenuElement | null;
46
91
  value: string;
47
92
  onTriggerEnter(itemValue: string): void;
package/dist/index.d.ts CHANGED
@@ -5,8 +5,21 @@ import { Primitive } from '@radix-ui/react-primitive';
5
5
  import { DismissableLayer } from '@radix-ui/react-dismissable-layer';
6
6
  import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';
7
7
 
8
- type Orientation = 'vertical' | 'horizontal';
9
- type Direction = 'ltr' | 'rtl';
8
+ declare const Orientation: {
9
+ readonly Vertical: "vertical";
10
+ readonly Horizontal: "horizontal";
11
+ };
12
+ type Orientation = (typeof Orientation)[keyof typeof Orientation];
13
+ declare const Direction: {
14
+ readonly LTR: "ltr";
15
+ readonly RTL: "rtl";
16
+ };
17
+ type Direction = (typeof Direction)[keyof typeof Direction];
18
+ declare const ActivationMode: {
19
+ readonly Automatic: "automatic";
20
+ readonly Manual: "manual";
21
+ };
22
+ type ActivationMode = (typeof ActivationMode)[keyof typeof ActivationMode];
10
23
  declare const createNavigationMenuScope: _radix_ui_react_context.CreateScope;
11
24
  type NavigationMenuElement = React.ComponentRef<typeof Primitive.nav>;
12
25
  type PrimitiveNavProps = React.ComponentPropsWithoutRef<typeof Primitive.nav>;
@@ -17,15 +30,28 @@ interface NavigationMenuProps extends Omit<NavigationMenuProviderProps, keyof Na
17
30
  dir?: Direction;
18
31
  orientation?: Orientation;
19
32
  /**
20
- * The duration from when the pointer enters the trigger until the tooltip gets opened.
21
- * @defaultValue 200
33
+ * The duration from when the pointer enters the trigger until the tooltip
34
+ * gets opened. When `activationMode` is `manual`, this prop is ignored.
35
+ *
36
+ * @default 200
22
37
  */
23
38
  delayDuration?: number;
24
39
  /**
25
- * How much time a user has to enter another trigger without incurring a delay again.
26
- * @defaultValue 300
40
+ * How much time a user has to enter another trigger without incurring a delay
41
+ * again. When `activationMode` is `manual`, this prop is ignored.
42
+ *
43
+ * @default 300
27
44
  */
28
45
  skipDelayDuration?: number;
46
+ /**
47
+ * Whether an item is activated automatically or manually.
48
+ * - `"automatic"`: hovering or focusing a trigger opens its item, and moving
49
+ * away closes it after a short delay.
50
+ * - `"manual"`: clicking a trigger toggles the item; hover and focus are ignored
51
+ *
52
+ * @default "automatic"
53
+ */
54
+ activationMode?: ActivationMode;
29
55
  }
30
56
  declare const NavigationMenu: React.ForwardRefExoticComponent<NavigationMenuProps & React.RefAttributes<HTMLElement>>;
31
57
  type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
@@ -34,6 +60,24 @@ interface NavigationMenuSubProps extends Omit<NavigationMenuProviderProps, keyof
34
60
  defaultValue?: string;
35
61
  onValueChange?: (value: string) => void;
36
62
  orientation?: Orientation;
63
+ /**
64
+ * Whether an item is activated automatically or manually.
65
+ * - `"automatic"`: hovering or focusing a trigger opens its item, and moving
66
+ * away closes it after a short delay.
67
+ * - `"manual"`: clicking a trigger toggles the item; hover and focus are
68
+ * ignored
69
+ *
70
+ * The default value is inherited from the parent Navigation Menu root
71
+ * component. If no value is provided to the parent, the default value is
72
+ * `"automatic"`.
73
+ */
74
+ activationMode?: ActivationMode;
75
+ /**
76
+ * When true, clicking a sub-menu item's trigger once it's active will not deactivate it.
77
+ *
78
+ * @default true
79
+ */
80
+ disableToggle?: boolean;
37
81
  }
38
82
  declare const NavigationMenuSub: React.ForwardRefExoticComponent<NavigationMenuSubProps & React.RefAttributes<HTMLDivElement>>;
39
83
  interface NavigationMenuProviderPrivateProps {
@@ -42,6 +86,7 @@ interface NavigationMenuProviderPrivateProps {
42
86
  children: React.ReactNode;
43
87
  orientation: Orientation;
44
88
  dir: Direction;
89
+ activationMode: ActivationMode;
45
90
  rootNavigationMenu: NavigationMenuElement | null;
46
91
  value: string;
47
92
  onTriggerEnter(itemValue: string): void;
package/dist/index.js CHANGED
@@ -72,6 +72,18 @@ var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect"
72
72
  var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
73
73
  var VisuallyHiddenPrimitive = __toESM(require("@radix-ui/react-visually-hidden"));
74
74
  var import_jsx_runtime = require("react/jsx-runtime");
75
+ var ActivationMode = {
76
+ Automatic: "automatic",
77
+ Manual: "manual"
78
+ };
79
+ var Orientation = {
80
+ Vertical: "vertical",
81
+ Horizontal: "horizontal"
82
+ };
83
+ var Direction = {
84
+ LTR: "ltr",
85
+ RTL: "rtl"
86
+ };
75
87
  var NAVIGATION_MENU_NAME = "NavigationMenu";
76
88
  var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME);
77
89
  var [FocusGroupCollection, useFocusGroupCollection, createFocusGroupCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME);
@@ -90,8 +102,9 @@ var NavigationMenu = /* @__PURE__ */ React.forwardRef(
90
102
  defaultValue,
91
103
  delayDuration = 200,
92
104
  skipDelayDuration = 300,
93
- orientation = "horizontal",
105
+ orientation = Orientation.Horizontal,
94
106
  dir,
107
+ activationMode = ActivationMode.Automatic,
95
108
  ...NavigationMenuProps
96
109
  } = props;
97
110
  const [navigationMenu, setNavigationMenu] = React.useState(null);
@@ -161,18 +174,34 @@ var NavigationMenu = /* @__PURE__ */ React.forwardRef(
161
174
  value,
162
175
  dir: direction,
163
176
  orientation,
177
+ activationMode,
164
178
  rootNavigationMenu: navigationMenu,
165
179
  onTriggerEnter: (itemValue) => {
166
- window.clearTimeout(openTimerRef.current);
167
- if (isOpenDelayed) handleDelayedOpen(itemValue);
168
- else handleOpen(itemValue);
180
+ if (activationMode === ActivationMode.Automatic) {
181
+ window.clearTimeout(openTimerRef.current);
182
+ if (isOpenDelayed) {
183
+ handleDelayedOpen(itemValue);
184
+ } else {
185
+ handleOpen(itemValue);
186
+ }
187
+ }
169
188
  },
170
189
  onTriggerLeave: () => {
171
- window.clearTimeout(openTimerRef.current);
172
- startCloseTimer();
190
+ if (activationMode === ActivationMode.Automatic) {
191
+ window.clearTimeout(openTimerRef.current);
192
+ startCloseTimer();
193
+ }
194
+ },
195
+ onContentEnter: () => {
196
+ if (activationMode === ActivationMode.Automatic) {
197
+ window.clearTimeout(closeTimerRef.current);
198
+ }
199
+ },
200
+ onContentLeave: () => {
201
+ if (activationMode === ActivationMode.Automatic) {
202
+ startCloseTimer();
203
+ }
173
204
  },
174
- onContentEnter: () => window.clearTimeout(closeTimerRef.current),
175
- onContentLeave: startCloseTimer,
176
205
  onItemSelect: (itemValue) => {
177
206
  setValue((prevValue) => prevValue === itemValue ? "" : itemValue);
178
207
  },
@@ -200,10 +229,13 @@ var NavigationMenuSub = /* @__PURE__ */ React.forwardRef(
200
229
  value: valueProp,
201
230
  onValueChange,
202
231
  defaultValue,
203
- orientation = "horizontal",
232
+ orientation = Orientation.Horizontal,
233
+ activationMode: activationModeProp,
234
+ disableToggle = true,
204
235
  ...subProps
205
236
  } = props;
206
237
  const context = useNavigationMenuContext(SUB_NAME, __scopeNavigationMenu);
238
+ const activationMode = activationModeProp ?? context.activationMode;
207
239
  const [value, setValue] = (0, import_react_use_controllable_state.useControllableState)({
208
240
  prop: valueProp,
209
241
  onChange: onValueChange,
@@ -218,9 +250,16 @@ var NavigationMenuSub = /* @__PURE__ */ React.forwardRef(
218
250
  value,
219
251
  dir: context.dir,
220
252
  orientation,
253
+ activationMode,
221
254
  rootNavigationMenu: context.rootNavigationMenu,
222
- onTriggerEnter: (itemValue) => setValue(itemValue),
223
- onItemSelect: (itemValue) => setValue(itemValue),
255
+ onTriggerEnter: (itemValue) => {
256
+ if (activationMode === ActivationMode.Automatic) {
257
+ setValue(itemValue);
258
+ }
259
+ },
260
+ onItemSelect: (itemValue) => {
261
+ setValue((prevValue) => disableToggle || prevValue !== itemValue ? itemValue : "");
262
+ },
224
263
  onItemDismiss: () => setValue(""),
225
264
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { "data-orientation": orientation, ...subProps, ref: forwardedRef })
226
265
  }
@@ -234,6 +273,7 @@ var NavigationMenuProvider = /* @__PURE__ */ __name((props) => {
234
273
  rootNavigationMenu,
235
274
  dir,
236
275
  orientation,
276
+ activationMode,
237
277
  children,
238
278
  value,
239
279
  onItemSelect,
@@ -257,6 +297,7 @@ var NavigationMenuProvider = /* @__PURE__ */ __name((props) => {
257
297
  baseId: (0, import_react_id.useId)(),
258
298
  dir,
259
299
  orientation,
300
+ activationMode,
260
301
  viewport,
261
302
  onViewportChange: setViewport,
262
303
  indicatorTrack,
@@ -389,7 +430,7 @@ var NavigationMenuTrigger = /* @__PURE__ */ React.forwardRef(/* @__PURE__ */ __n
389
430
  wasClickCloseRef.current = open;
390
431
  }),
391
432
  onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => {
392
- const verticalEntryKey = context.dir === "rtl" ? "ArrowLeft" : "ArrowRight";
433
+ const verticalEntryKey = context.dir === Direction.RTL ? "ArrowLeft" : "ArrowRight";
393
434
  const entryKey = { horizontal: "ArrowDown", vertical: verticalEntryKey }[context.orientation];
394
435
  if (open && event.key === entryKey) {
395
436
  itemContext.onEntryKeyDown();
@@ -474,7 +515,7 @@ var NavigationMenuIndicatorImpl = /* @__PURE__ */ React.forwardRef(/* @__PURE__
474
515
  null
475
516
  );
476
517
  const [position, setPosition] = React.useState(null);
477
- const isHorizontal = context.orientation === "horizontal";
518
+ const isHorizontal = context.orientation === Orientation.Horizontal;
478
519
  const isVisible = Boolean(context.value);
479
520
  React.useEffect(() => {
480
521
  const items = getItems();
@@ -601,7 +642,7 @@ var NavigationMenuContentImpl = /* @__PURE__ */ React.forwardRef(/* @__PURE__ */
601
642
  const motionAttribute = React.useMemo(() => {
602
643
  const items = getItems();
603
644
  const values = items.map((item) => item.value);
604
- if (context.dir === "rtl") values.reverse();
645
+ if (context.dir === Direction.RTL) values.reverse();
605
646
  const index = values.indexOf(context.value);
606
647
  const prevIndex = values.indexOf(context.previousValue);
607
648
  const isSelected = value === context.value;
@@ -637,7 +678,12 @@ var NavigationMenuContentImpl = /* @__PURE__ */ React.forwardRef(/* @__PURE__ */
637
678
  onFocusOutside: (0, import_primitive.composeEventHandlers)(props.onFocusOutside, (event) => {
638
679
  onContentFocusOutside();
639
680
  const target = event.target;
640
- if (context.rootNavigationMenu?.contains(target)) event.preventDefault();
681
+ const relatedTarget = event.detail.originalEvent.relatedTarget;
682
+ const focusMovedIntoMenu = context.rootNavigationMenu?.contains(target);
683
+ const focusCameFromMenu = context.rootNavigationMenu?.contains(relatedTarget);
684
+ if (focusMovedIntoMenu || !focusCameFromMenu) {
685
+ event.preventDefault();
686
+ }
641
687
  }),
642
688
  onPointerDownOutside: (0, import_primitive.composeEventHandlers)(props.onPointerDownOutside, (event) => {
643
689
  const target = event.target;
@@ -764,7 +810,7 @@ var FocusGroupItem = /* @__PURE__ */ React.forwardRef(
764
810
  const isFocusNavigationKey = ["Home", "End", ...ARROW_KEYS].includes(event.key);
765
811
  if (isFocusNavigationKey) {
766
812
  let candidateNodes = getItems().map((item) => item.ref.current);
767
- const prevItemKey = context.dir === "rtl" ? "ArrowRight" : "ArrowLeft";
813
+ const prevItemKey = context.dir === Direction.RTL ? "ArrowRight" : "ArrowLeft";
768
814
  const prevKeys = [prevItemKey, "ArrowUp", "End"];
769
815
  if (prevKeys.includes(event.key)) candidateNodes.reverse();
770
816
  if (ARROW_KEYS.includes(event.key)) {