@radix-ui/react-navigation-menu
Advanced tools
Comparing version 1.2.0-rc.2 to 1.2.0-rc.3
1558
dist/index.js
"use strict"; | ||
"use client"; | ||
(() => { | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { | ||
get: (a, b) => (typeof require !== "undefined" ? require : a)[b] | ||
}) : x)(function(x) { | ||
if (typeof require !== "undefined") return require.apply(this, arguments); | ||
throw Error('Dynamic require of "' + x + '" is not supported'); | ||
}); | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// packages/react/navigation-menu/src/NavigationMenu.tsx | ||
var React = __toESM(__require("react")); | ||
var import_react_dom = __toESM(__require("react-dom")); | ||
var import_react_context = __require("@radix-ui/react-context"); | ||
var import_primitive = __require("@radix-ui/primitive"); | ||
var import_react_primitive = __require("@radix-ui/react-primitive"); | ||
var import_react_use_controllable_state = __require("@radix-ui/react-use-controllable-state"); | ||
var import_react_compose_refs = __require("@radix-ui/react-compose-refs"); | ||
var import_react_direction = __require("@radix-ui/react-direction"); | ||
var import_react_presence = __require("@radix-ui/react-presence"); | ||
var import_react_id = __require("@radix-ui/react-id"); | ||
var import_react_collection = __require("@radix-ui/react-collection"); | ||
var import_react_dismissable_layer = __require("@radix-ui/react-dismissable-layer"); | ||
var import_react_use_previous = __require("@radix-ui/react-use-previous"); | ||
var import_react_use_layout_effect = __require("@radix-ui/react-use-layout-effect"); | ||
var import_react_use_callback_ref = __require("@radix-ui/react-use-callback-ref"); | ||
var VisuallyHiddenPrimitive = __toESM(__require("@radix-ui/react-visually-hidden")); | ||
var import_jsx_runtime = __require("react/jsx-runtime"); | ||
var NAVIGATION_MENU_NAME = "NavigationMenu"; | ||
var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME); | ||
var [FocusGroupCollection, useFocusGroupCollection, createFocusGroupCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME); | ||
var [createNavigationMenuContext, createNavigationMenuScope] = (0, import_react_context.createContextScope)( | ||
NAVIGATION_MENU_NAME, | ||
[createCollectionScope, createFocusGroupCollectionScope] | ||
); | ||
var [NavigationMenuProviderImpl, useNavigationMenuContext] = createNavigationMenuContext(NAVIGATION_MENU_NAME); | ||
var [ViewportContentProvider, useViewportContentContext] = createNavigationMenuContext(NAVIGATION_MENU_NAME); | ||
var NavigationMenu = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeNavigationMenu, | ||
value: valueProp, | ||
onValueChange, | ||
defaultValue, | ||
delayDuration = 200, | ||
skipDelayDuration = 300, | ||
orientation = "horizontal", | ||
dir, | ||
...NavigationMenuProps | ||
} = props; | ||
const [navigationMenu, setNavigationMenu] = React.useState(null); | ||
const composedRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node) => setNavigationMenu(node)); | ||
const direction = (0, import_react_direction.useDirection)(dir); | ||
const openTimerRef = React.useRef(0); | ||
const closeTimerRef = React.useRef(0); | ||
const skipDelayTimerRef = React.useRef(0); | ||
const [isOpenDelayed, setIsOpenDelayed] = React.useState(true); | ||
const [value = "", setValue] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: valueProp, | ||
onChange: (value2) => { | ||
const isOpen = value2 !== ""; | ||
const hasSkipDelayDuration = skipDelayDuration > 0; | ||
if (isOpen) { | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
if (hasSkipDelayDuration) setIsOpenDelayed(false); | ||
} else { | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
skipDelayTimerRef.current = window.setTimeout( | ||
() => setIsOpenDelayed(true), | ||
skipDelayDuration | ||
); | ||
} | ||
onValueChange?.(value2); | ||
}, | ||
defaultProp: defaultValue | ||
}); | ||
const startCloseTimer = React.useCallback(() => { | ||
// packages/react/navigation-menu/src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
Content: () => Content, | ||
Indicator: () => Indicator, | ||
Item: () => Item, | ||
Link: () => Link, | ||
List: () => List, | ||
NavigationMenu: () => NavigationMenu, | ||
NavigationMenuContent: () => NavigationMenuContent, | ||
NavigationMenuIndicator: () => NavigationMenuIndicator, | ||
NavigationMenuItem: () => NavigationMenuItem, | ||
NavigationMenuLink: () => NavigationMenuLink, | ||
NavigationMenuList: () => NavigationMenuList, | ||
NavigationMenuSub: () => NavigationMenuSub, | ||
NavigationMenuTrigger: () => NavigationMenuTrigger, | ||
NavigationMenuViewport: () => NavigationMenuViewport, | ||
Root: () => Root2, | ||
Sub: () => Sub, | ||
Trigger: () => Trigger, | ||
Viewport: () => Viewport, | ||
createNavigationMenuScope: () => createNavigationMenuScope | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// packages/react/navigation-menu/src/NavigationMenu.tsx | ||
var React = __toESM(require("react")); | ||
var import_react_dom = __toESM(require("react-dom")); | ||
var import_react_context = require("@radix-ui/react-context"); | ||
var import_primitive = require("@radix-ui/primitive"); | ||
var import_react_primitive = require("@radix-ui/react-primitive"); | ||
var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state"); | ||
var import_react_compose_refs = require("@radix-ui/react-compose-refs"); | ||
var import_react_direction = require("@radix-ui/react-direction"); | ||
var import_react_presence = require("@radix-ui/react-presence"); | ||
var import_react_id = require("@radix-ui/react-id"); | ||
var import_react_collection = require("@radix-ui/react-collection"); | ||
var import_react_dismissable_layer = require("@radix-ui/react-dismissable-layer"); | ||
var import_react_use_previous = require("@radix-ui/react-use-previous"); | ||
var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect"); | ||
var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); | ||
var VisuallyHiddenPrimitive = __toESM(require("@radix-ui/react-visually-hidden")); | ||
var import_jsx_runtime = require("react/jsx-runtime"); | ||
var NAVIGATION_MENU_NAME = "NavigationMenu"; | ||
var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME); | ||
var [FocusGroupCollection, useFocusGroupCollection, createFocusGroupCollectionScope] = (0, import_react_collection.createCollection)(NAVIGATION_MENU_NAME); | ||
var [createNavigationMenuContext, createNavigationMenuScope] = (0, import_react_context.createContextScope)( | ||
NAVIGATION_MENU_NAME, | ||
[createCollectionScope, createFocusGroupCollectionScope] | ||
); | ||
var [NavigationMenuProviderImpl, useNavigationMenuContext] = createNavigationMenuContext(NAVIGATION_MENU_NAME); | ||
var [ViewportContentProvider, useViewportContentContext] = createNavigationMenuContext(NAVIGATION_MENU_NAME); | ||
var NavigationMenu = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeNavigationMenu, | ||
value: valueProp, | ||
onValueChange, | ||
defaultValue, | ||
delayDuration = 200, | ||
skipDelayDuration = 300, | ||
orientation = "horizontal", | ||
dir, | ||
...NavigationMenuProps | ||
} = props; | ||
const [navigationMenu, setNavigationMenu] = React.useState(null); | ||
const composedRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node) => setNavigationMenu(node)); | ||
const direction = (0, import_react_direction.useDirection)(dir); | ||
const openTimerRef = React.useRef(0); | ||
const closeTimerRef = React.useRef(0); | ||
const skipDelayTimerRef = React.useRef(0); | ||
const [isOpenDelayed, setIsOpenDelayed] = React.useState(true); | ||
const [value = "", setValue] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: valueProp, | ||
onChange: (value2) => { | ||
const isOpen = value2 !== ""; | ||
const hasSkipDelayDuration = skipDelayDuration > 0; | ||
if (isOpen) { | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
if (hasSkipDelayDuration) setIsOpenDelayed(false); | ||
} else { | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
skipDelayTimerRef.current = window.setTimeout( | ||
() => setIsOpenDelayed(true), | ||
skipDelayDuration | ||
); | ||
} | ||
onValueChange?.(value2); | ||
}, | ||
defaultProp: defaultValue | ||
}); | ||
const startCloseTimer = React.useCallback(() => { | ||
window.clearTimeout(closeTimerRef.current); | ||
closeTimerRef.current = window.setTimeout(() => setValue(""), 150); | ||
}, [setValue]); | ||
const handleOpen = React.useCallback( | ||
(itemValue) => { | ||
window.clearTimeout(closeTimerRef.current); | ||
closeTimerRef.current = window.setTimeout(() => setValue(""), 150); | ||
}, [setValue]); | ||
const handleOpen = React.useCallback( | ||
(itemValue) => { | ||
setValue(itemValue); | ||
}, | ||
[setValue] | ||
); | ||
const handleDelayedOpen = React.useCallback( | ||
(itemValue) => { | ||
const isOpenItem = value === itemValue; | ||
if (isOpenItem) { | ||
window.clearTimeout(closeTimerRef.current); | ||
setValue(itemValue); | ||
}, | ||
[setValue] | ||
); | ||
const handleDelayedOpen = React.useCallback( | ||
(itemValue) => { | ||
const isOpenItem = value === itemValue; | ||
if (isOpenItem) { | ||
} else { | ||
openTimerRef.current = window.setTimeout(() => { | ||
window.clearTimeout(closeTimerRef.current); | ||
} else { | ||
openTimerRef.current = window.setTimeout(() => { | ||
window.clearTimeout(closeTimerRef.current); | ||
setValue(itemValue); | ||
}, delayDuration); | ||
} | ||
setValue(itemValue); | ||
}, delayDuration); | ||
} | ||
}, | ||
[value, setValue, delayDuration] | ||
); | ||
React.useEffect(() => { | ||
return () => { | ||
window.clearTimeout(openTimerRef.current); | ||
window.clearTimeout(closeTimerRef.current); | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
}; | ||
}, []); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuProvider, | ||
{ | ||
scope: __scopeNavigationMenu, | ||
isRootMenu: true, | ||
value, | ||
dir: direction, | ||
orientation, | ||
rootNavigationMenu: navigationMenu, | ||
onTriggerEnter: (itemValue) => { | ||
window.clearTimeout(openTimerRef.current); | ||
if (isOpenDelayed) handleDelayedOpen(itemValue); | ||
else handleOpen(itemValue); | ||
}, | ||
[value, setValue, delayDuration] | ||
); | ||
React.useEffect(() => { | ||
return () => { | ||
onTriggerLeave: () => { | ||
window.clearTimeout(openTimerRef.current); | ||
window.clearTimeout(closeTimerRef.current); | ||
window.clearTimeout(skipDelayTimerRef.current); | ||
}; | ||
}, []); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuProvider, | ||
{ | ||
scope: __scopeNavigationMenu, | ||
isRootMenu: true, | ||
value, | ||
dir: direction, | ||
orientation, | ||
rootNavigationMenu: navigationMenu, | ||
onTriggerEnter: (itemValue) => { | ||
window.clearTimeout(openTimerRef.current); | ||
if (isOpenDelayed) handleDelayedOpen(itemValue); | ||
else handleOpen(itemValue); | ||
}, | ||
onTriggerLeave: () => { | ||
window.clearTimeout(openTimerRef.current); | ||
startCloseTimer(); | ||
}, | ||
onContentEnter: () => window.clearTimeout(closeTimerRef.current), | ||
onContentLeave: startCloseTimer, | ||
onItemSelect: (itemValue) => { | ||
setValue((prevValue) => prevValue === itemValue ? "" : itemValue); | ||
}, | ||
onItemDismiss: () => setValue(""), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.nav, | ||
{ | ||
"aria-label": "Main", | ||
"data-orientation": orientation, | ||
dir: direction, | ||
...NavigationMenuProps, | ||
ref: composedRef | ||
} | ||
) | ||
} | ||
); | ||
} | ||
); | ||
NavigationMenu.displayName = NAVIGATION_MENU_NAME; | ||
var SUB_NAME = "NavigationMenuSub"; | ||
var NavigationMenuSub = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeNavigationMenu, | ||
value: valueProp, | ||
onValueChange, | ||
defaultValue, | ||
orientation = "horizontal", | ||
...subProps | ||
} = props; | ||
const context = useNavigationMenuContext(SUB_NAME, __scopeNavigationMenu); | ||
const [value = "", setValue] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: valueProp, | ||
onChange: onValueChange, | ||
defaultProp: defaultValue | ||
}); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuProvider, | ||
{ | ||
scope: __scopeNavigationMenu, | ||
isRootMenu: false, | ||
value, | ||
dir: context.dir, | ||
orientation, | ||
rootNavigationMenu: context.rootNavigationMenu, | ||
onTriggerEnter: (itemValue) => setValue(itemValue), | ||
onItemSelect: (itemValue) => setValue(itemValue), | ||
onItemDismiss: () => setValue(""), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { "data-orientation": orientation, ...subProps, ref: forwardedRef }) | ||
} | ||
); | ||
} | ||
); | ||
NavigationMenuSub.displayName = SUB_NAME; | ||
var NavigationMenuProvider = (props) => { | ||
startCloseTimer(); | ||
}, | ||
onContentEnter: () => window.clearTimeout(closeTimerRef.current), | ||
onContentLeave: startCloseTimer, | ||
onItemSelect: (itemValue) => { | ||
setValue((prevValue) => prevValue === itemValue ? "" : itemValue); | ||
}, | ||
onItemDismiss: () => setValue(""), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.nav, | ||
{ | ||
"aria-label": "Main", | ||
"data-orientation": orientation, | ||
dir: direction, | ||
...NavigationMenuProps, | ||
ref: composedRef | ||
} | ||
) | ||
} | ||
); | ||
} | ||
); | ||
NavigationMenu.displayName = NAVIGATION_MENU_NAME; | ||
var SUB_NAME = "NavigationMenuSub"; | ||
var NavigationMenuSub = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
scope, | ||
isRootMenu, | ||
rootNavigationMenu, | ||
dir, | ||
orientation, | ||
children, | ||
value, | ||
onItemSelect, | ||
onItemDismiss, | ||
onTriggerEnter, | ||
onTriggerLeave, | ||
onContentEnter, | ||
onContentLeave | ||
__scopeNavigationMenu, | ||
value: valueProp, | ||
onValueChange, | ||
defaultValue, | ||
orientation = "horizontal", | ||
...subProps | ||
} = props; | ||
const [viewport, setViewport] = React.useState(null); | ||
const [viewportContent, setViewportContent] = React.useState(/* @__PURE__ */ new Map()); | ||
const [indicatorTrack, setIndicatorTrack] = React.useState(null); | ||
const context = useNavigationMenuContext(SUB_NAME, __scopeNavigationMenu); | ||
const [value = "", setValue] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: valueProp, | ||
onChange: onValueChange, | ||
defaultProp: defaultValue | ||
}); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuProviderImpl, | ||
NavigationMenuProvider, | ||
{ | ||
scope, | ||
isRootMenu, | ||
rootNavigationMenu, | ||
scope: __scopeNavigationMenu, | ||
isRootMenu: false, | ||
value, | ||
previousValue: (0, import_react_use_previous.usePrevious)(value), | ||
baseId: (0, import_react_id.useId)(), | ||
dir, | ||
dir: context.dir, | ||
orientation, | ||
viewport, | ||
onViewportChange: setViewport, | ||
indicatorTrack, | ||
onIndicatorTrackChange: setIndicatorTrack, | ||
onTriggerEnter: (0, import_react_use_callback_ref.useCallbackRef)(onTriggerEnter), | ||
onTriggerLeave: (0, import_react_use_callback_ref.useCallbackRef)(onTriggerLeave), | ||
onContentEnter: (0, import_react_use_callback_ref.useCallbackRef)(onContentEnter), | ||
onContentLeave: (0, import_react_use_callback_ref.useCallbackRef)(onContentLeave), | ||
onItemSelect: (0, import_react_use_callback_ref.useCallbackRef)(onItemSelect), | ||
onItemDismiss: (0, import_react_use_callback_ref.useCallbackRef)(onItemDismiss), | ||
onViewportContentChange: React.useCallback((contentValue, contentData) => { | ||
setViewportContent((prevContent) => { | ||
prevContent.set(contentValue, contentData); | ||
return new Map(prevContent); | ||
}); | ||
}, []), | ||
onViewportContentRemove: React.useCallback((contentValue) => { | ||
setViewportContent((prevContent) => { | ||
if (!prevContent.has(contentValue)) return prevContent; | ||
prevContent.delete(contentValue); | ||
return new Map(prevContent); | ||
}); | ||
}, []), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ViewportContentProvider, { scope, items: viewportContent, children }) }) | ||
rootNavigationMenu: context.rootNavigationMenu, | ||
onTriggerEnter: (itemValue) => setValue(itemValue), | ||
onItemSelect: (itemValue) => setValue(itemValue), | ||
onItemDismiss: () => setValue(""), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { "data-orientation": orientation, ...subProps, ref: forwardedRef }) | ||
} | ||
); | ||
}; | ||
var LIST_NAME = "NavigationMenuList"; | ||
var NavigationMenuList = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...listProps } = props; | ||
const context = useNavigationMenuContext(LIST_NAME, __scopeNavigationMenu); | ||
const list = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.ul, { "data-orientation": context.orientation, ...listProps, ref: forwardedRef }); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { style: { position: "relative" }, ref: context.onIndicatorTrackChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: __scopeNavigationMenu, children: context.isRootMenu ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroup, { asChild: true, children: list }) : list }) }); | ||
} | ||
); | ||
NavigationMenuSub.displayName = SUB_NAME; | ||
var NavigationMenuProvider = (props) => { | ||
const { | ||
scope, | ||
isRootMenu, | ||
rootNavigationMenu, | ||
dir, | ||
orientation, | ||
children, | ||
value, | ||
onItemSelect, | ||
onItemDismiss, | ||
onTriggerEnter, | ||
onTriggerLeave, | ||
onContentEnter, | ||
onContentLeave | ||
} = props; | ||
const [viewport, setViewport] = React.useState(null); | ||
const [viewportContent, setViewportContent] = React.useState(/* @__PURE__ */ new Map()); | ||
const [indicatorTrack, setIndicatorTrack] = React.useState(null); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuProviderImpl, | ||
{ | ||
scope, | ||
isRootMenu, | ||
rootNavigationMenu, | ||
value, | ||
previousValue: (0, import_react_use_previous.usePrevious)(value), | ||
baseId: (0, import_react_id.useId)(), | ||
dir, | ||
orientation, | ||
viewport, | ||
onViewportChange: setViewport, | ||
indicatorTrack, | ||
onIndicatorTrackChange: setIndicatorTrack, | ||
onTriggerEnter: (0, import_react_use_callback_ref.useCallbackRef)(onTriggerEnter), | ||
onTriggerLeave: (0, import_react_use_callback_ref.useCallbackRef)(onTriggerLeave), | ||
onContentEnter: (0, import_react_use_callback_ref.useCallbackRef)(onContentEnter), | ||
onContentLeave: (0, import_react_use_callback_ref.useCallbackRef)(onContentLeave), | ||
onItemSelect: (0, import_react_use_callback_ref.useCallbackRef)(onItemSelect), | ||
onItemDismiss: (0, import_react_use_callback_ref.useCallbackRef)(onItemDismiss), | ||
onViewportContentChange: React.useCallback((contentValue, contentData) => { | ||
setViewportContent((prevContent) => { | ||
prevContent.set(contentValue, contentData); | ||
return new Map(prevContent); | ||
}); | ||
}, []), | ||
onViewportContentRemove: React.useCallback((contentValue) => { | ||
setViewportContent((prevContent) => { | ||
if (!prevContent.has(contentValue)) return prevContent; | ||
prevContent.delete(contentValue); | ||
return new Map(prevContent); | ||
}); | ||
}, []), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ViewportContentProvider, { scope, items: viewportContent, children }) }) | ||
} | ||
); | ||
NavigationMenuList.displayName = LIST_NAME; | ||
var ITEM_NAME = "NavigationMenuItem"; | ||
var [NavigationMenuItemContextProvider, useNavigationMenuItemContext] = createNavigationMenuContext(ITEM_NAME); | ||
var NavigationMenuItem = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, value: valueProp, ...itemProps } = props; | ||
const autoValue = (0, import_react_id.useId)(); | ||
const value = valueProp || autoValue || "LEGACY_REACT_AUTO_VALUE"; | ||
const contentRef = React.useRef(null); | ||
const triggerRef = React.useRef(null); | ||
const focusProxyRef = React.useRef(null); | ||
const restoreContentTabOrderRef = React.useRef(() => { | ||
}); | ||
const wasEscapeCloseRef = React.useRef(false); | ||
const handleContentEntry = React.useCallback((side = "start") => { | ||
if (contentRef.current) { | ||
restoreContentTabOrderRef.current(); | ||
const candidates = getTabbableCandidates(contentRef.current); | ||
if (candidates.length) focusFirst(side === "start" ? candidates : candidates.reverse()); | ||
} | ||
}, []); | ||
const handleContentExit = React.useCallback(() => { | ||
if (contentRef.current) { | ||
const candidates = getTabbableCandidates(contentRef.current); | ||
if (candidates.length) restoreContentTabOrderRef.current = removeFromTabOrder(candidates); | ||
} | ||
}, []); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuItemContextProvider, | ||
{ | ||
scope: __scopeNavigationMenu, | ||
value, | ||
triggerRef, | ||
contentRef, | ||
focusProxyRef, | ||
wasEscapeCloseRef, | ||
onEntryKeyDown: handleContentEntry, | ||
onFocusProxyEnter: handleContentEntry, | ||
onRootContentClose: handleContentExit, | ||
onContentFocusOutside: handleContentExit, | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.li, { ...itemProps, ref: forwardedRef }) | ||
} | ||
); | ||
} | ||
); | ||
NavigationMenuItem.displayName = ITEM_NAME; | ||
var TRIGGER_NAME = "NavigationMenuTrigger"; | ||
var NavigationMenuTrigger = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, disabled, ...triggerProps } = props; | ||
const context = useNavigationMenuContext(TRIGGER_NAME, props.__scopeNavigationMenu); | ||
const itemContext = useNavigationMenuItemContext(TRIGGER_NAME, props.__scopeNavigationMenu); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(ref, itemContext.triggerRef, forwardedRef); | ||
const triggerId = makeTriggerId(context.baseId, itemContext.value); | ||
const contentId = makeContentId(context.baseId, itemContext.value); | ||
const hasPointerMoveOpenedRef = React.useRef(false); | ||
const wasClickCloseRef = React.useRef(false); | ||
const open = itemContext.value === context.value; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.ItemSlot, { scope: __scopeNavigationMenu, value: itemContext.value, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
id: triggerId, | ||
disabled, | ||
"data-disabled": disabled ? "" : void 0, | ||
"data-state": getOpenState(open), | ||
"aria-expanded": open, | ||
"aria-controls": contentId, | ||
...triggerProps, | ||
ref: composedRefs, | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, () => { | ||
wasClickCloseRef.current = false; | ||
itemContext.wasEscapeCloseRef.current = false; | ||
}), | ||
onPointerMove: (0, import_primitive.composeEventHandlers)( | ||
props.onPointerMove, | ||
whenMouse(() => { | ||
if (disabled || wasClickCloseRef.current || itemContext.wasEscapeCloseRef.current || hasPointerMoveOpenedRef.current) | ||
return; | ||
context.onTriggerEnter(itemContext.value); | ||
hasPointerMoveOpenedRef.current = true; | ||
}) | ||
), | ||
onPointerLeave: (0, import_primitive.composeEventHandlers)( | ||
props.onPointerLeave, | ||
whenMouse(() => { | ||
if (disabled) return; | ||
context.onTriggerLeave(); | ||
hasPointerMoveOpenedRef.current = false; | ||
}) | ||
), | ||
onClick: (0, import_primitive.composeEventHandlers)(props.onClick, () => { | ||
context.onItemSelect(itemContext.value); | ||
wasClickCloseRef.current = open; | ||
}), | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
const verticalEntryKey = context.dir === "rtl" ? "ArrowLeft" : "ArrowRight"; | ||
const entryKey = { horizontal: "ArrowDown", vertical: verticalEntryKey }[context.orientation]; | ||
if (open && event.key === entryKey) { | ||
itemContext.onEntryKeyDown(); | ||
event.preventDefault(); | ||
} | ||
}) | ||
} | ||
) }) }), | ||
open && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
VisuallyHiddenPrimitive.Root, | ||
{ | ||
"aria-hidden": true, | ||
tabIndex: 0, | ||
ref: itemContext.focusProxyRef, | ||
onFocus: (event) => { | ||
const content = itemContext.contentRef.current; | ||
const prevFocusedElement = event.relatedTarget; | ||
const wasTriggerFocused = prevFocusedElement === ref.current; | ||
const wasFocusFromContent = content?.contains(prevFocusedElement); | ||
if (wasTriggerFocused || !wasFocusFromContent) { | ||
itemContext.onFocusProxyEnter(wasTriggerFocused ? "start" : "end"); | ||
} | ||
} | ||
} | ||
), | ||
context.viewport && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-owns": contentId }) | ||
] }) | ||
] }); | ||
}); | ||
NavigationMenuTrigger.displayName = TRIGGER_NAME; | ||
var LINK_NAME = "NavigationMenuLink"; | ||
var LINK_SELECT = "navigationMenu.linkSelect"; | ||
var NavigationMenuLink = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, active, onSelect, ...linkProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.a, | ||
{ | ||
"data-active": active ? "" : void 0, | ||
"aria-current": active ? "page" : void 0, | ||
...linkProps, | ||
ref: forwardedRef, | ||
onClick: (0, import_primitive.composeEventHandlers)( | ||
props.onClick, | ||
(event) => { | ||
const target = event.target; | ||
const linkSelectEvent = new CustomEvent(LINK_SELECT, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
target.addEventListener(LINK_SELECT, (event2) => onSelect?.(event2), { once: true }); | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(target, linkSelectEvent); | ||
if (!linkSelectEvent.defaultPrevented && !event.metaKey) { | ||
const rootContentDismissEvent = new CustomEvent(ROOT_CONTENT_DISMISS, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(target, rootContentDismissEvent); | ||
} | ||
}, | ||
{ checkForDefaultPrevented: false } | ||
) | ||
} | ||
) }); | ||
} | ||
); | ||
NavigationMenuLink.displayName = LINK_NAME; | ||
var INDICATOR_NAME = "NavigationMenuIndicator"; | ||
var NavigationMenuIndicator = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...indicatorProps } = props; | ||
const context = useNavigationMenuContext(INDICATOR_NAME, props.__scopeNavigationMenu); | ||
const isVisible = Boolean(context.value); | ||
return context.indicatorTrack ? import_react_dom.default.createPortal( | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || isVisible, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationMenuIndicatorImpl, { ...indicatorProps, ref: forwardedRef }) }), | ||
context.indicatorTrack | ||
) : null; | ||
}); | ||
NavigationMenuIndicator.displayName = INDICATOR_NAME; | ||
var NavigationMenuIndicatorImpl = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...indicatorProps } = props; | ||
const context = useNavigationMenuContext(INDICATOR_NAME, __scopeNavigationMenu); | ||
const getItems = useCollection(__scopeNavigationMenu); | ||
const [activeTrigger, setActiveTrigger] = React.useState( | ||
null | ||
); | ||
const [position, setPosition] = React.useState(null); | ||
const isHorizontal = context.orientation === "horizontal"; | ||
const isVisible = Boolean(context.value); | ||
React.useEffect(() => { | ||
const items = getItems(); | ||
const triggerNode = items.find((item) => item.value === context.value)?.ref.current; | ||
if (triggerNode) setActiveTrigger(triggerNode); | ||
}, [getItems, context.value]); | ||
const handlePositionChange = () => { | ||
if (activeTrigger) { | ||
setPosition({ | ||
size: isHorizontal ? activeTrigger.offsetWidth : activeTrigger.offsetHeight, | ||
offset: isHorizontal ? activeTrigger.offsetLeft : activeTrigger.offsetTop | ||
}); | ||
}; | ||
var LIST_NAME = "NavigationMenuList"; | ||
var NavigationMenuList = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...listProps } = props; | ||
const context = useNavigationMenuContext(LIST_NAME, __scopeNavigationMenu); | ||
const list = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.ul, { "data-orientation": context.orientation, ...listProps, ref: forwardedRef }); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { style: { position: "relative" }, ref: context.onIndicatorTrackChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: __scopeNavigationMenu, children: context.isRootMenu ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroup, { asChild: true, children: list }) : list }) }); | ||
} | ||
); | ||
NavigationMenuList.displayName = LIST_NAME; | ||
var ITEM_NAME = "NavigationMenuItem"; | ||
var [NavigationMenuItemContextProvider, useNavigationMenuItemContext] = createNavigationMenuContext(ITEM_NAME); | ||
var NavigationMenuItem = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, value: valueProp, ...itemProps } = props; | ||
const autoValue = (0, import_react_id.useId)(); | ||
const value = valueProp || autoValue || "LEGACY_REACT_AUTO_VALUE"; | ||
const contentRef = React.useRef(null); | ||
const triggerRef = React.useRef(null); | ||
const focusProxyRef = React.useRef(null); | ||
const restoreContentTabOrderRef = React.useRef(() => { | ||
}); | ||
const wasEscapeCloseRef = React.useRef(false); | ||
const handleContentEntry = React.useCallback((side = "start") => { | ||
if (contentRef.current) { | ||
restoreContentTabOrderRef.current(); | ||
const candidates = getTabbableCandidates(contentRef.current); | ||
if (candidates.length) focusFirst(side === "start" ? candidates : candidates.reverse()); | ||
} | ||
}; | ||
useResizeObserver(activeTrigger, handlePositionChange); | ||
useResizeObserver(context.indicatorTrack, handlePositionChange); | ||
return position ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
}, []); | ||
const handleContentExit = React.useCallback(() => { | ||
if (contentRef.current) { | ||
const candidates = getTabbableCandidates(contentRef.current); | ||
if (candidates.length) restoreContentTabOrderRef.current = removeFromTabOrder(candidates); | ||
} | ||
}, []); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuItemContextProvider, | ||
{ | ||
"aria-hidden": true, | ||
"data-state": isVisible ? "visible" : "hidden", | ||
"data-orientation": context.orientation, | ||
...indicatorProps, | ||
ref: forwardedRef, | ||
style: { | ||
position: "absolute", | ||
...isHorizontal ? { | ||
left: 0, | ||
width: position.size + "px", | ||
transform: `translateX(${position.offset}px)` | ||
} : { | ||
top: 0, | ||
height: position.size + "px", | ||
transform: `translateY(${position.offset}px)` | ||
}, | ||
...indicatorProps.style | ||
} | ||
scope: __scopeNavigationMenu, | ||
value, | ||
triggerRef, | ||
contentRef, | ||
focusProxyRef, | ||
wasEscapeCloseRef, | ||
onEntryKeyDown: handleContentEntry, | ||
onFocusProxyEnter: handleContentEntry, | ||
onRootContentClose: handleContentExit, | ||
onContentFocusOutside: handleContentExit, | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.li, { ...itemProps, ref: forwardedRef }) | ||
} | ||
) : null; | ||
}); | ||
var CONTENT_NAME = "NavigationMenuContent"; | ||
var NavigationMenuContent = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...contentProps } = props; | ||
const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const itemContext = useNavigationMenuItemContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(itemContext.contentRef, forwardedRef); | ||
const open = itemContext.value === context.value; | ||
const commonProps = { | ||
value: itemContext.value, | ||
triggerRef: itemContext.triggerRef, | ||
focusProxyRef: itemContext.focusProxyRef, | ||
wasEscapeCloseRef: itemContext.wasEscapeCloseRef, | ||
onContentFocusOutside: itemContext.onContentFocusOutside, | ||
onRootContentClose: itemContext.onRootContentClose, | ||
...contentProps | ||
}; | ||
return !context.viewport ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuContentImpl, | ||
); | ||
} | ||
); | ||
NavigationMenuItem.displayName = ITEM_NAME; | ||
var TRIGGER_NAME = "NavigationMenuTrigger"; | ||
var NavigationMenuTrigger = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, disabled, ...triggerProps } = props; | ||
const context = useNavigationMenuContext(TRIGGER_NAME, props.__scopeNavigationMenu); | ||
const itemContext = useNavigationMenuItemContext(TRIGGER_NAME, props.__scopeNavigationMenu); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(ref, itemContext.triggerRef, forwardedRef); | ||
const triggerId = makeTriggerId(context.baseId, itemContext.value); | ||
const contentId = makeContentId(context.baseId, itemContext.value); | ||
const hasPointerMoveOpenedRef = React.useRef(false); | ||
const wasClickCloseRef = React.useRef(false); | ||
const open = itemContext.value === context.value; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.ItemSlot, { scope: __scopeNavigationMenu, value: itemContext.value, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
id: triggerId, | ||
disabled, | ||
"data-disabled": disabled ? "" : void 0, | ||
"data-state": getOpenState(open), | ||
...commonProps, | ||
"aria-expanded": open, | ||
"aria-controls": contentId, | ||
...triggerProps, | ||
ref: composedRefs, | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, context.onContentEnter), | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, () => { | ||
wasClickCloseRef.current = false; | ||
itemContext.wasEscapeCloseRef.current = false; | ||
}), | ||
onPointerMove: (0, import_primitive.composeEventHandlers)( | ||
props.onPointerMove, | ||
whenMouse(() => { | ||
if (disabled || wasClickCloseRef.current || itemContext.wasEscapeCloseRef.current || hasPointerMoveOpenedRef.current) | ||
return; | ||
context.onTriggerEnter(itemContext.value); | ||
hasPointerMoveOpenedRef.current = true; | ||
}) | ||
), | ||
onPointerLeave: (0, import_primitive.composeEventHandlers)( | ||
props.onPointerLeave, | ||
whenMouse(context.onContentLeave) | ||
whenMouse(() => { | ||
if (disabled) return; | ||
context.onTriggerLeave(); | ||
hasPointerMoveOpenedRef.current = false; | ||
}) | ||
), | ||
style: { | ||
// Prevent interaction when animating out | ||
pointerEvents: !open && context.isRootMenu ? "none" : void 0, | ||
...commonProps.style | ||
onClick: (0, import_primitive.composeEventHandlers)(props.onClick, () => { | ||
context.onItemSelect(itemContext.value); | ||
wasClickCloseRef.current = open; | ||
}), | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
const verticalEntryKey = context.dir === "rtl" ? "ArrowLeft" : "ArrowRight"; | ||
const entryKey = { horizontal: "ArrowDown", vertical: verticalEntryKey }[context.orientation]; | ||
if (open && event.key === entryKey) { | ||
itemContext.onEntryKeyDown(); | ||
event.preventDefault(); | ||
} | ||
}) | ||
} | ||
) }) }), | ||
open && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
VisuallyHiddenPrimitive.Root, | ||
{ | ||
"aria-hidden": true, | ||
tabIndex: 0, | ||
ref: itemContext.focusProxyRef, | ||
onFocus: (event) => { | ||
const content = itemContext.contentRef.current; | ||
const prevFocusedElement = event.relatedTarget; | ||
const wasTriggerFocused = prevFocusedElement === ref.current; | ||
const wasFocusFromContent = content?.contains(prevFocusedElement); | ||
if (wasTriggerFocused || !wasFocusFromContent) { | ||
itemContext.onFocusProxyEnter(wasTriggerFocused ? "start" : "end"); | ||
} | ||
} | ||
} | ||
), | ||
context.viewport && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-owns": contentId }) | ||
] }) | ||
] }); | ||
}); | ||
NavigationMenuTrigger.displayName = TRIGGER_NAME; | ||
var LINK_NAME = "NavigationMenuLink"; | ||
var LINK_SELECT = "navigationMenu.linkSelect"; | ||
var NavigationMenuLink = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, active, onSelect, ...linkProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupItem, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.a, | ||
{ | ||
"data-active": active ? "" : void 0, | ||
"aria-current": active ? "page" : void 0, | ||
...linkProps, | ||
ref: forwardedRef, | ||
onClick: (0, import_primitive.composeEventHandlers)( | ||
props.onClick, | ||
(event) => { | ||
const target = event.target; | ||
const linkSelectEvent = new CustomEvent(LINK_SELECT, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
target.addEventListener(LINK_SELECT, (event2) => onSelect?.(event2), { once: true }); | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(target, linkSelectEvent); | ||
if (!linkSelectEvent.defaultPrevented && !event.metaKey) { | ||
const rootContentDismissEvent = new CustomEvent(ROOT_CONTENT_DISMISS, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(target, rootContentDismissEvent); | ||
} | ||
}, | ||
{ checkForDefaultPrevented: false } | ||
) | ||
} | ||
) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ViewportContentMounter, { forceMount, ...commonProps, ref: composedRefs }); | ||
}); | ||
NavigationMenuContent.displayName = CONTENT_NAME; | ||
var ViewportContentMounter = React.forwardRef((props, forwardedRef) => { | ||
const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const { onViewportContentChange, onViewportContentRemove } = context; | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
onViewportContentChange(props.value, { | ||
ref: forwardedRef, | ||
...props | ||
) }); | ||
} | ||
); | ||
NavigationMenuLink.displayName = LINK_NAME; | ||
var INDICATOR_NAME = "NavigationMenuIndicator"; | ||
var NavigationMenuIndicator = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...indicatorProps } = props; | ||
const context = useNavigationMenuContext(INDICATOR_NAME, props.__scopeNavigationMenu); | ||
const isVisible = Boolean(context.value); | ||
return context.indicatorTrack ? import_react_dom.default.createPortal( | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || isVisible, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationMenuIndicatorImpl, { ...indicatorProps, ref: forwardedRef }) }), | ||
context.indicatorTrack | ||
) : null; | ||
}); | ||
NavigationMenuIndicator.displayName = INDICATOR_NAME; | ||
var NavigationMenuIndicatorImpl = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...indicatorProps } = props; | ||
const context = useNavigationMenuContext(INDICATOR_NAME, __scopeNavigationMenu); | ||
const getItems = useCollection(__scopeNavigationMenu); | ||
const [activeTrigger, setActiveTrigger] = React.useState( | ||
null | ||
); | ||
const [position, setPosition] = React.useState(null); | ||
const isHorizontal = context.orientation === "horizontal"; | ||
const isVisible = Boolean(context.value); | ||
React.useEffect(() => { | ||
const items = getItems(); | ||
const triggerNode = items.find((item) => item.value === context.value)?.ref.current; | ||
if (triggerNode) setActiveTrigger(triggerNode); | ||
}, [getItems, context.value]); | ||
const handlePositionChange = () => { | ||
if (activeTrigger) { | ||
setPosition({ | ||
size: isHorizontal ? activeTrigger.offsetWidth : activeTrigger.offsetHeight, | ||
offset: isHorizontal ? activeTrigger.offsetLeft : activeTrigger.offsetTop | ||
}); | ||
}, [props, forwardedRef, onViewportContentChange]); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
return () => onViewportContentRemove(props.value); | ||
}, [props.value, onViewportContentRemove]); | ||
return null; | ||
}); | ||
var ROOT_CONTENT_DISMISS = "navigationMenu.rootContentDismiss"; | ||
var NavigationMenuContentImpl = React.forwardRef((props, forwardedRef) => { | ||
const { | ||
__scopeNavigationMenu, | ||
value, | ||
triggerRef, | ||
focusProxyRef, | ||
wasEscapeCloseRef, | ||
onRootContentClose, | ||
onContentFocusOutside, | ||
...contentProps | ||
} = props; | ||
const context = useNavigationMenuContext(CONTENT_NAME, __scopeNavigationMenu); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(ref, forwardedRef); | ||
const triggerId = makeTriggerId(context.baseId, value); | ||
const contentId = makeContentId(context.baseId, value); | ||
const getItems = useCollection(__scopeNavigationMenu); | ||
const prevMotionAttributeRef = React.useRef(null); | ||
const { onItemDismiss } = context; | ||
React.useEffect(() => { | ||
const content = ref.current; | ||
if (context.isRootMenu && content) { | ||
const handleClose = () => { | ||
onItemDismiss(); | ||
onRootContentClose(); | ||
if (content.contains(document.activeElement)) triggerRef.current?.focus(); | ||
}; | ||
content.addEventListener(ROOT_CONTENT_DISMISS, handleClose); | ||
return () => content.removeEventListener(ROOT_CONTENT_DISMISS, handleClose); | ||
} | ||
}; | ||
useResizeObserver(activeTrigger, handlePositionChange); | ||
useResizeObserver(context.indicatorTrack, handlePositionChange); | ||
return position ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
{ | ||
"aria-hidden": true, | ||
"data-state": isVisible ? "visible" : "hidden", | ||
"data-orientation": context.orientation, | ||
...indicatorProps, | ||
ref: forwardedRef, | ||
style: { | ||
position: "absolute", | ||
...isHorizontal ? { | ||
left: 0, | ||
width: position.size + "px", | ||
transform: `translateX(${position.offset}px)` | ||
} : { | ||
top: 0, | ||
height: position.size + "px", | ||
transform: `translateY(${position.offset}px)` | ||
}, | ||
...indicatorProps.style | ||
} | ||
}, [context.isRootMenu, props.value, triggerRef, onItemDismiss, onRootContentClose]); | ||
const motionAttribute = React.useMemo(() => { | ||
const items = getItems(); | ||
const values = items.map((item) => item.value); | ||
if (context.dir === "rtl") values.reverse(); | ||
const index = values.indexOf(context.value); | ||
const prevIndex = values.indexOf(context.previousValue); | ||
const isSelected = value === context.value; | ||
const wasSelected = prevIndex === values.indexOf(value); | ||
if (!isSelected && !wasSelected) return prevMotionAttributeRef.current; | ||
const attribute = (() => { | ||
if (index !== prevIndex) { | ||
if (isSelected && prevIndex !== -1) return index > prevIndex ? "from-end" : "from-start"; | ||
if (wasSelected && index !== -1) return index > prevIndex ? "to-start" : "to-end"; | ||
} | ||
) : null; | ||
}); | ||
var CONTENT_NAME = "NavigationMenuContent"; | ||
var NavigationMenuContent = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...contentProps } = props; | ||
const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const itemContext = useNavigationMenuItemContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(itemContext.contentRef, forwardedRef); | ||
const open = itemContext.value === context.value; | ||
const commonProps = { | ||
value: itemContext.value, | ||
triggerRef: itemContext.triggerRef, | ||
focusProxyRef: itemContext.focusProxyRef, | ||
wasEscapeCloseRef: itemContext.wasEscapeCloseRef, | ||
onContentFocusOutside: itemContext.onContentFocusOutside, | ||
onRootContentClose: itemContext.onRootContentClose, | ||
...contentProps | ||
}; | ||
return !context.viewport ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuContentImpl, | ||
{ | ||
"data-state": getOpenState(open), | ||
...commonProps, | ||
ref: composedRefs, | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, context.onContentEnter), | ||
onPointerLeave: (0, import_primitive.composeEventHandlers)( | ||
props.onPointerLeave, | ||
whenMouse(context.onContentLeave) | ||
), | ||
style: { | ||
// Prevent interaction when animating out | ||
pointerEvents: !open && context.isRootMenu ? "none" : void 0, | ||
...commonProps.style | ||
} | ||
} | ||
) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ViewportContentMounter, { forceMount, ...commonProps, ref: composedRefs }); | ||
}); | ||
NavigationMenuContent.displayName = CONTENT_NAME; | ||
var ViewportContentMounter = React.forwardRef((props, forwardedRef) => { | ||
const context = useNavigationMenuContext(CONTENT_NAME, props.__scopeNavigationMenu); | ||
const { onViewportContentChange, onViewportContentRemove } = context; | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
onViewportContentChange(props.value, { | ||
ref: forwardedRef, | ||
...props | ||
}); | ||
}, [props, forwardedRef, onViewportContentChange]); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
return () => onViewportContentRemove(props.value); | ||
}, [props.value, onViewportContentRemove]); | ||
return null; | ||
}); | ||
var ROOT_CONTENT_DISMISS = "navigationMenu.rootContentDismiss"; | ||
var NavigationMenuContentImpl = React.forwardRef((props, forwardedRef) => { | ||
const { | ||
__scopeNavigationMenu, | ||
value, | ||
triggerRef, | ||
focusProxyRef, | ||
wasEscapeCloseRef, | ||
onRootContentClose, | ||
onContentFocusOutside, | ||
...contentProps | ||
} = props; | ||
const context = useNavigationMenuContext(CONTENT_NAME, __scopeNavigationMenu); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(ref, forwardedRef); | ||
const triggerId = makeTriggerId(context.baseId, value); | ||
const contentId = makeContentId(context.baseId, value); | ||
const getItems = useCollection(__scopeNavigationMenu); | ||
const prevMotionAttributeRef = React.useRef(null); | ||
const { onItemDismiss } = context; | ||
React.useEffect(() => { | ||
const content = ref.current; | ||
if (context.isRootMenu && content) { | ||
const handleClose = () => { | ||
onItemDismiss(); | ||
onRootContentClose(); | ||
if (content.contains(document.activeElement)) triggerRef.current?.focus(); | ||
}; | ||
content.addEventListener(ROOT_CONTENT_DISMISS, handleClose); | ||
return () => content.removeEventListener(ROOT_CONTENT_DISMISS, handleClose); | ||
} | ||
}, [context.isRootMenu, props.value, triggerRef, onItemDismiss, onRootContentClose]); | ||
const motionAttribute = React.useMemo(() => { | ||
const items = getItems(); | ||
const values = items.map((item) => item.value); | ||
if (context.dir === "rtl") values.reverse(); | ||
const index = values.indexOf(context.value); | ||
const prevIndex = values.indexOf(context.previousValue); | ||
const isSelected = value === context.value; | ||
const wasSelected = prevIndex === values.indexOf(value); | ||
if (!isSelected && !wasSelected) return prevMotionAttributeRef.current; | ||
const attribute = (() => { | ||
if (index !== prevIndex) { | ||
if (isSelected && prevIndex !== -1) return index > prevIndex ? "from-end" : "from-start"; | ||
if (wasSelected && index !== -1) return index > prevIndex ? "to-start" : "to-end"; | ||
} | ||
return null; | ||
})(); | ||
prevMotionAttributeRef.current = attribute; | ||
return attribute; | ||
}, [context.previousValue, context.value, context.dir, getItems, value]); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroup, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_dismissable_layer.DismissableLayer, | ||
{ | ||
id: contentId, | ||
"aria-labelledby": triggerId, | ||
"data-motion": motionAttribute, | ||
"data-orientation": context.orientation, | ||
...contentProps, | ||
ref: composedRefs, | ||
disableOutsidePointerEvents: false, | ||
onDismiss: () => { | ||
const rootContentDismissEvent = new Event(ROOT_CONTENT_DISMISS, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
ref.current?.dispatchEvent(rootContentDismissEvent); | ||
}, | ||
onFocusOutside: (0, import_primitive.composeEventHandlers)(props.onFocusOutside, (event) => { | ||
onContentFocusOutside(); | ||
const target = event.target; | ||
if (context.rootNavigationMenu?.contains(target)) event.preventDefault(); | ||
}), | ||
onPointerDownOutside: (0, import_primitive.composeEventHandlers)(props.onPointerDownOutside, (event) => { | ||
const target = event.target; | ||
const isTrigger = getItems().some((item) => item.ref.current?.contains(target)); | ||
const isRootViewport = context.isRootMenu && context.viewport?.contains(target); | ||
if (isTrigger || isRootViewport || !context.isRootMenu) event.preventDefault(); | ||
}), | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey; | ||
const isTabKey = event.key === "Tab" && !isMetaKey; | ||
if (isTabKey) { | ||
const candidates = getTabbableCandidates(event.currentTarget); | ||
const focusedElement = document.activeElement; | ||
const index = candidates.findIndex((candidate) => candidate === focusedElement); | ||
const isMovingBackwards = event.shiftKey; | ||
const nextCandidates = isMovingBackwards ? candidates.slice(0, index).reverse() : candidates.slice(index + 1, candidates.length); | ||
if (focusFirst(nextCandidates)) { | ||
event.preventDefault(); | ||
} else { | ||
focusProxyRef.current?.focus(); | ||
} | ||
} | ||
return null; | ||
})(); | ||
prevMotionAttributeRef.current = attribute; | ||
return attribute; | ||
}, [context.previousValue, context.value, context.dir, getItems, value]); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroup, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_dismissable_layer.DismissableLayer, | ||
}), | ||
onEscapeKeyDown: (0, import_primitive.composeEventHandlers)(props.onEscapeKeyDown, (event) => { | ||
wasEscapeCloseRef.current = true; | ||
}) | ||
} | ||
) }); | ||
}); | ||
var VIEWPORT_NAME = "NavigationMenuViewport"; | ||
var NavigationMenuViewport = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...viewportProps } = props; | ||
const context = useNavigationMenuContext(VIEWPORT_NAME, props.__scopeNavigationMenu); | ||
const open = Boolean(context.value); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationMenuViewportImpl, { ...viewportProps, ref: forwardedRef }) }); | ||
}); | ||
NavigationMenuViewport.displayName = VIEWPORT_NAME; | ||
var NavigationMenuViewportImpl = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, children, ...viewportImplProps } = props; | ||
const context = useNavigationMenuContext(VIEWPORT_NAME, __scopeNavigationMenu); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, context.onViewportChange); | ||
const viewportContentContext = useViewportContentContext( | ||
CONTENT_NAME, | ||
props.__scopeNavigationMenu | ||
); | ||
const [size, setSize] = React.useState(null); | ||
const [content, setContent] = React.useState(null); | ||
const viewportWidth = size ? size?.width + "px" : void 0; | ||
const viewportHeight = size ? size?.height + "px" : void 0; | ||
const open = Boolean(context.value); | ||
const activeContentValue = open ? context.value : context.previousValue; | ||
const handleSizeChange = () => { | ||
if (content) setSize({ width: content.offsetWidth, height: content.offsetHeight }); | ||
}; | ||
useResizeObserver(content, handleSizeChange); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
{ | ||
"data-state": getOpenState(open), | ||
"data-orientation": context.orientation, | ||
...viewportImplProps, | ||
ref: composedRefs, | ||
style: { | ||
// Prevent interaction when animating out | ||
pointerEvents: !open && context.isRootMenu ? "none" : void 0, | ||
["--radix-navigation-menu-viewport-width"]: viewportWidth, | ||
["--radix-navigation-menu-viewport-height"]: viewportHeight, | ||
...viewportImplProps.style | ||
}, | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, context.onContentEnter), | ||
onPointerLeave: (0, import_primitive.composeEventHandlers)(props.onPointerLeave, whenMouse(context.onContentLeave)), | ||
children: Array.from(viewportContentContext.items).map(([value, { ref, forceMount, ...props2 }]) => { | ||
const isActive = activeContentValue === value; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || isActive, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuContentImpl, | ||
{ | ||
...props2, | ||
ref: (0, import_react_compose_refs.composeRefs)(ref, (node) => { | ||
if (isActive && node) setContent(node); | ||
}) | ||
} | ||
) }, value); | ||
}) | ||
} | ||
); | ||
}); | ||
var FOCUS_GROUP_NAME = "FocusGroup"; | ||
var FocusGroup = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...groupProps } = props; | ||
const context = useNavigationMenuContext(FOCUS_GROUP_NAME, __scopeNavigationMenu); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.Provider, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.Slot, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { dir: context.dir, ...groupProps, ref: forwardedRef }) }) }); | ||
} | ||
); | ||
var ARROW_KEYS = ["ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown"]; | ||
var FOCUS_GROUP_ITEM_NAME = "FocusGroupItem"; | ||
var FocusGroupItem = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...groupProps } = props; | ||
const getItems = useFocusGroupCollection(__scopeNavigationMenu); | ||
const context = useNavigationMenuContext(FOCUS_GROUP_ITEM_NAME, __scopeNavigationMenu); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.ItemSlot, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
id: contentId, | ||
"aria-labelledby": triggerId, | ||
"data-motion": motionAttribute, | ||
"data-orientation": context.orientation, | ||
...contentProps, | ||
ref: composedRefs, | ||
disableOutsidePointerEvents: false, | ||
onDismiss: () => { | ||
const rootContentDismissEvent = new Event(ROOT_CONTENT_DISMISS, { | ||
bubbles: true, | ||
cancelable: true | ||
}); | ||
ref.current?.dispatchEvent(rootContentDismissEvent); | ||
}, | ||
onFocusOutside: (0, import_primitive.composeEventHandlers)(props.onFocusOutside, (event) => { | ||
onContentFocusOutside(); | ||
const target = event.target; | ||
if (context.rootNavigationMenu?.contains(target)) event.preventDefault(); | ||
}), | ||
onPointerDownOutside: (0, import_primitive.composeEventHandlers)(props.onPointerDownOutside, (event) => { | ||
const target = event.target; | ||
const isTrigger = getItems().some((item) => item.ref.current?.contains(target)); | ||
const isRootViewport = context.isRootMenu && context.viewport?.contains(target); | ||
if (isTrigger || isRootViewport || !context.isRootMenu) event.preventDefault(); | ||
}), | ||
...groupProps, | ||
ref: forwardedRef, | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey; | ||
const isTabKey = event.key === "Tab" && !isMetaKey; | ||
if (isTabKey) { | ||
const candidates = getTabbableCandidates(event.currentTarget); | ||
const focusedElement = document.activeElement; | ||
const index = candidates.findIndex((candidate) => candidate === focusedElement); | ||
const isMovingBackwards = event.shiftKey; | ||
const nextCandidates = isMovingBackwards ? candidates.slice(0, index).reverse() : candidates.slice(index + 1, candidates.length); | ||
if (focusFirst(nextCandidates)) { | ||
event.preventDefault(); | ||
} else { | ||
focusProxyRef.current?.focus(); | ||
const isFocusNavigationKey = ["Home", "End", ...ARROW_KEYS].includes(event.key); | ||
if (isFocusNavigationKey) { | ||
let candidateNodes = getItems().map((item) => item.ref.current); | ||
const prevItemKey = context.dir === "rtl" ? "ArrowRight" : "ArrowLeft"; | ||
const prevKeys = [prevItemKey, "ArrowUp", "End"]; | ||
if (prevKeys.includes(event.key)) candidateNodes.reverse(); | ||
if (ARROW_KEYS.includes(event.key)) { | ||
const currentIndex = candidateNodes.indexOf(event.currentTarget); | ||
candidateNodes = candidateNodes.slice(currentIndex + 1); | ||
} | ||
setTimeout(() => focusFirst(candidateNodes)); | ||
event.preventDefault(); | ||
} | ||
}), | ||
onEscapeKeyDown: (0, import_primitive.composeEventHandlers)(props.onEscapeKeyDown, (event) => { | ||
wasEscapeCloseRef.current = true; | ||
}) | ||
} | ||
) }); | ||
} | ||
); | ||
function getTabbableCandidates(container) { | ||
const nodes = []; | ||
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, { | ||
acceptNode: (node) => { | ||
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; | ||
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; | ||
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; | ||
} | ||
}); | ||
var VIEWPORT_NAME = "NavigationMenuViewport"; | ||
var NavigationMenuViewport = React.forwardRef((props, forwardedRef) => { | ||
const { forceMount, ...viewportProps } = props; | ||
const context = useNavigationMenuContext(VIEWPORT_NAME, props.__scopeNavigationMenu); | ||
const open = Boolean(context.value); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationMenuViewportImpl, { ...viewportProps, ref: forwardedRef }) }); | ||
while (walker.nextNode()) nodes.push(walker.currentNode); | ||
return nodes; | ||
} | ||
function focusFirst(candidates) { | ||
const previouslyFocusedElement = document.activeElement; | ||
return candidates.some((candidate) => { | ||
if (candidate === previouslyFocusedElement) return true; | ||
candidate.focus(); | ||
return document.activeElement !== previouslyFocusedElement; | ||
}); | ||
NavigationMenuViewport.displayName = VIEWPORT_NAME; | ||
var NavigationMenuViewportImpl = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeNavigationMenu, children, ...viewportImplProps } = props; | ||
const context = useNavigationMenuContext(VIEWPORT_NAME, __scopeNavigationMenu); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, context.onViewportChange); | ||
const viewportContentContext = useViewportContentContext( | ||
CONTENT_NAME, | ||
props.__scopeNavigationMenu | ||
); | ||
const [size, setSize] = React.useState(null); | ||
const [content, setContent] = React.useState(null); | ||
const viewportWidth = size ? size?.width + "px" : void 0; | ||
const viewportHeight = size ? size?.height + "px" : void 0; | ||
const open = Boolean(context.value); | ||
const activeContentValue = open ? context.value : context.previousValue; | ||
const handleSizeChange = () => { | ||
if (content) setSize({ width: content.offsetWidth, height: content.offsetHeight }); | ||
}; | ||
useResizeObserver(content, handleSizeChange); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
{ | ||
"data-state": getOpenState(open), | ||
"data-orientation": context.orientation, | ||
...viewportImplProps, | ||
ref: composedRefs, | ||
style: { | ||
// Prevent interaction when animating out | ||
pointerEvents: !open && context.isRootMenu ? "none" : void 0, | ||
["--radix-navigation-menu-viewport-width"]: viewportWidth, | ||
["--radix-navigation-menu-viewport-height"]: viewportHeight, | ||
...viewportImplProps.style | ||
}, | ||
onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, context.onContentEnter), | ||
onPointerLeave: (0, import_primitive.composeEventHandlers)(props.onPointerLeave, whenMouse(context.onContentLeave)), | ||
children: Array.from(viewportContentContext.items).map(([value, { ref, forceMount, ...props2 }]) => { | ||
const isActive = activeContentValue === value; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || isActive, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
NavigationMenuContentImpl, | ||
{ | ||
...props2, | ||
ref: (0, import_react_compose_refs.composeRefs)(ref, (node) => { | ||
if (isActive && node) setContent(node); | ||
}) | ||
} | ||
) }, value); | ||
}) | ||
} | ||
); | ||
} | ||
function removeFromTabOrder(candidates) { | ||
candidates.forEach((candidate) => { | ||
candidate.dataset.tabindex = candidate.getAttribute("tabindex") || ""; | ||
candidate.setAttribute("tabindex", "-1"); | ||
}); | ||
var FOCUS_GROUP_NAME = "FocusGroup"; | ||
var FocusGroup = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...groupProps } = props; | ||
const context = useNavigationMenuContext(FOCUS_GROUP_NAME, __scopeNavigationMenu); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.Provider, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.Slot, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { dir: context.dir, ...groupProps, ref: forwardedRef }) }) }); | ||
} | ||
); | ||
var ARROW_KEYS = ["ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown"]; | ||
var FOCUS_GROUP_ITEM_NAME = "FocusGroupItem"; | ||
var FocusGroupItem = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeNavigationMenu, ...groupProps } = props; | ||
const getItems = useFocusGroupCollection(__scopeNavigationMenu); | ||
const context = useNavigationMenuContext(FOCUS_GROUP_ITEM_NAME, __scopeNavigationMenu); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusGroupCollection.ItemSlot, { scope: __scopeNavigationMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
...groupProps, | ||
ref: forwardedRef, | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
const isFocusNavigationKey = ["Home", "End", ...ARROW_KEYS].includes(event.key); | ||
if (isFocusNavigationKey) { | ||
let candidateNodes = getItems().map((item) => item.ref.current); | ||
const prevItemKey = context.dir === "rtl" ? "ArrowRight" : "ArrowLeft"; | ||
const prevKeys = [prevItemKey, "ArrowUp", "End"]; | ||
if (prevKeys.includes(event.key)) candidateNodes.reverse(); | ||
if (ARROW_KEYS.includes(event.key)) { | ||
const currentIndex = candidateNodes.indexOf(event.currentTarget); | ||
candidateNodes = candidateNodes.slice(currentIndex + 1); | ||
} | ||
setTimeout(() => focusFirst(candidateNodes)); | ||
event.preventDefault(); | ||
} | ||
}) | ||
} | ||
) }); | ||
} | ||
); | ||
function getTabbableCandidates(container) { | ||
const nodes = []; | ||
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, { | ||
acceptNode: (node) => { | ||
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; | ||
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; | ||
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; | ||
} | ||
}); | ||
while (walker.nextNode()) nodes.push(walker.currentNode); | ||
return nodes; | ||
} | ||
function focusFirst(candidates) { | ||
const previouslyFocusedElement = document.activeElement; | ||
return candidates.some((candidate) => { | ||
if (candidate === previouslyFocusedElement) return true; | ||
candidate.focus(); | ||
return document.activeElement !== previouslyFocusedElement; | ||
}); | ||
} | ||
function removeFromTabOrder(candidates) { | ||
return () => { | ||
candidates.forEach((candidate) => { | ||
candidate.dataset.tabindex = candidate.getAttribute("tabindex") || ""; | ||
candidate.setAttribute("tabindex", "-1"); | ||
const prevTabIndex = candidate.dataset.tabindex; | ||
candidate.setAttribute("tabindex", prevTabIndex); | ||
}); | ||
return () => { | ||
candidates.forEach((candidate) => { | ||
const prevTabIndex = candidate.dataset.tabindex; | ||
candidate.setAttribute("tabindex", prevTabIndex); | ||
}; | ||
} | ||
function useResizeObserver(element, onResize) { | ||
const handleResize = (0, import_react_use_callback_ref.useCallbackRef)(onResize); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
let rAF = 0; | ||
if (element) { | ||
const resizeObserver = new ResizeObserver(() => { | ||
cancelAnimationFrame(rAF); | ||
rAF = window.requestAnimationFrame(handleResize); | ||
}); | ||
}; | ||
} | ||
function useResizeObserver(element, onResize) { | ||
const handleResize = (0, import_react_use_callback_ref.useCallbackRef)(onResize); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
let rAF = 0; | ||
if (element) { | ||
const resizeObserver = new ResizeObserver(() => { | ||
cancelAnimationFrame(rAF); | ||
rAF = window.requestAnimationFrame(handleResize); | ||
}); | ||
resizeObserver.observe(element); | ||
return () => { | ||
window.cancelAnimationFrame(rAF); | ||
resizeObserver.unobserve(element); | ||
}; | ||
} | ||
}, [element, handleResize]); | ||
} | ||
function getOpenState(open) { | ||
return open ? "open" : "closed"; | ||
} | ||
function makeTriggerId(baseId, value) { | ||
return `${baseId}-trigger-${value}`; | ||
} | ||
function makeContentId(baseId, value) { | ||
return `${baseId}-content-${value}`; | ||
} | ||
function whenMouse(handler) { | ||
return (event) => event.pointerType === "mouse" ? handler(event) : void 0; | ||
} | ||
var Root2 = NavigationMenu; | ||
var Sub = NavigationMenuSub; | ||
var List = NavigationMenuList; | ||
var Item = NavigationMenuItem; | ||
var Trigger = NavigationMenuTrigger; | ||
var Link = NavigationMenuLink; | ||
var Indicator = NavigationMenuIndicator; | ||
var Content = NavigationMenuContent; | ||
var Viewport = NavigationMenuViewport; | ||
})(); | ||
resizeObserver.observe(element); | ||
return () => { | ||
window.cancelAnimationFrame(rAF); | ||
resizeObserver.unobserve(element); | ||
}; | ||
} | ||
}, [element, handleResize]); | ||
} | ||
function getOpenState(open) { | ||
return open ? "open" : "closed"; | ||
} | ||
function makeTriggerId(baseId, value) { | ||
return `${baseId}-trigger-${value}`; | ||
} | ||
function makeContentId(baseId, value) { | ||
return `${baseId}-content-${value}`; | ||
} | ||
function whenMouse(handler) { | ||
return (event) => event.pointerType === "mouse" ? handler(event) : void 0; | ||
} | ||
var Root2 = NavigationMenu; | ||
var Sub = NavigationMenuSub; | ||
var List = NavigationMenuList; | ||
var Item = NavigationMenuItem; | ||
var Trigger = NavigationMenuTrigger; | ||
var Link = NavigationMenuLink; | ||
var Indicator = NavigationMenuIndicator; | ||
var Content = NavigationMenuContent; | ||
var Viewport = NavigationMenuViewport; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@radix-ui/react-navigation-menu", | ||
"version": "1.2.0-rc.2", | ||
"version": "1.2.0-rc.3", | ||
"license": "MIT", | ||
@@ -31,16 +31,16 @@ "exports": { | ||
"dependencies": { | ||
"@radix-ui/primitive": "1.1.0-rc.2", | ||
"@radix-ui/react-collection": "1.1.0-rc.2", | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.2", | ||
"@radix-ui/react-context": "1.1.0-rc.2", | ||
"@radix-ui/react-direction": "1.1.0-rc.2", | ||
"@radix-ui/react-dismissable-layer": "1.1.0-rc.2", | ||
"@radix-ui/react-id": "1.1.0-rc.2", | ||
"@radix-ui/react-presence": "1.1.0-rc.2", | ||
"@radix-ui/react-primitive": "1.1.0-rc.2", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.2", | ||
"@radix-ui/react-use-controllable-state": "1.1.0-rc.2", | ||
"@radix-ui/react-use-layout-effect": "1.1.0-rc.2", | ||
"@radix-ui/react-use-previous": "1.1.0-rc.2", | ||
"@radix-ui/react-visually-hidden": "1.1.0-rc.2" | ||
"@radix-ui/primitive": "1.1.0-rc.3", | ||
"@radix-ui/react-collection": "1.1.0-rc.3", | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.3", | ||
"@radix-ui/react-context": "1.1.0-rc.3", | ||
"@radix-ui/react-direction": "1.1.0-rc.3", | ||
"@radix-ui/react-dismissable-layer": "1.1.0-rc.3", | ||
"@radix-ui/react-id": "1.1.0-rc.3", | ||
"@radix-ui/react-presence": "1.1.0-rc.3", | ||
"@radix-ui/react-primitive": "1.1.0-rc.3", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.3", | ||
"@radix-ui/react-use-controllable-state": "1.1.0-rc.3", | ||
"@radix-ui/react-use-layout-effect": "1.1.0-rc.3", | ||
"@radix-ui/react-use-previous": "1.1.0-rc.3", | ||
"@radix-ui/react-visually-hidden": "1.1.0-rc.3" | ||
}, | ||
@@ -47,0 +47,0 @@ "peerDependencies": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
1777
0
225563
+ Added@radix-ui/primitive@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-collection@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-compose-refs@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-context@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-direction@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-dismissable-layer@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-id@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-presence@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-primitive@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-slot@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-callback-ref@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-controllable-state@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-escape-keydown@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-layout-effect@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-previous@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-visually-hidden@1.1.0-rc.3(transitive)
- Removed@radix-ui/primitive@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-collection@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-compose-refs@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-context@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-direction@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-dismissable-layer@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-id@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-presence@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-primitive@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-slot@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-callback-ref@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-controllable-state@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-escape-keydown@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-layout-effect@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-previous@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-visually-hidden@1.1.0-rc.2(transitive)