'use client'; import * as React from 'react'; import { useControllableState, useEventCallback, useMergedRefs, slot, getIntrinsicElementProps } from '@fluentui/react-utilities'; /** * Initial value for the uncontrolled case of the list of open indexes */ function initializeUncontrolledOpenCategories({ defaultOpenCategories, multiple }) { if (defaultOpenCategories !== undefined) { if (Array.isArray(defaultOpenCategories)) { return multiple ? defaultOpenCategories : [ defaultOpenCategories[0] ]; } return [ defaultOpenCategories ]; } return undefined; } /** * Updates the list of open indexes based on an index that changes * @param value - the index that will change * @param previousOpenItems - list of current open indexes * @param multiple - if Nav supports open categories at the same time */ const updateOpenCategories = (value, previousOpenItems, multiple)=>{ if (multiple) { if (previousOpenItems.includes(value)) { return previousOpenItems.filter((i)=>i !== value); } else { return [ ...previousOpenItems, value ]; } } return previousOpenItems[0] === value ? [] : [ value ]; }; /** * Create the state required to render Nav. * * The returned state can be modified with hooks such as useNavStyles, * before being passed to renderNav. * * @param props - props from this instance of Nav * @param ref - reference to root HTMLDivElement of Nav */ export const useNav_unstable = (props, ref)=>{ const { onNavItemSelect, onNavCategoryItemToggle, multiple = true, density = 'medium', openCategories: controlledOpenCategoryItems, selectedCategoryValue: controlledSelectedCategoryValue, selectedValue: controlledSelectedValue, defaultOpenCategories, defaultSelectedValue, defaultSelectedCategoryValue } = props; const innerRef = React.useRef(null); const [openCategories, setOpenCategories] = useControllableState({ state: controlledOpenCategoryItems, defaultState: initializeUncontrolledOpenCategories({ defaultOpenCategories, multiple }), initialState: [] }); const [selectedCategoryValue, setSelectedCategoryValue] = useControllableState({ state: controlledSelectedCategoryValue, defaultState: defaultSelectedCategoryValue, initialState: undefined }); const [selectedValue, setSelectedValue] = useControllableState({ state: controlledSelectedValue, defaultState: defaultSelectedValue, initialState: undefined }); // considered usePrevious, but it is sensitive to re-renders // this could cause the previous to move to current in the case where the navItem list re-renders. // these refs avoid getRegisteredNavItems changing when selectedValue changes and causing // renders for navItems that have not changed. const currentSelectedValue = React.useRef(undefined); const previousSelectedValue = React.useRef(undefined); const currentSelectedCategoryValue = React.useRef(undefined); const previousSelectedCategoryValue = React.useRef(undefined); if (currentSelectedValue.current !== selectedValue) { previousSelectedValue.current = currentSelectedValue.current; currentSelectedValue.current = selectedValue; } if (currentSelectedCategoryValue.current !== selectedCategoryValue) { previousSelectedCategoryValue.current = currentSelectedCategoryValue.current; currentSelectedCategoryValue.current = selectedCategoryValue; } // used for NavItems and NavSubItems const onSelect = useEventCallback((event, data)=>{ setSelectedValue(data.value); setSelectedCategoryValue(data.categoryValue ? data.categoryValue : ''); onNavItemSelect === null || onNavItemSelect === void 0 ? void 0 : onNavItemSelect(event, data); }); // used for NavCategoryItems const onRequestNavCategoryItemToggle = useEventCallback((event, data)=>{ if (data.categoryValue !== undefined) { const nextOpenCategories = updateOpenCategories(data.categoryValue, openCategories !== null && openCategories !== void 0 ? openCategories : [], multiple); onNavCategoryItemToggle === null || onNavCategoryItemToggle === void 0 ? void 0 : onNavCategoryItemToggle(event, data); setOpenCategories(nextOpenCategories); } }); const registeredNavItems = React.useRef({}); const onRegister = React.useCallback((data)=>{ registeredNavItems.current[JSON.stringify(data.value)] = data; }, []); const onUnregister = React.useCallback((data)=>{ delete registeredNavItems.current[JSON.stringify(data.value)]; }, []); const getRegisteredNavItems = React.useCallback(()=>{ return { selectedValue: currentSelectedValue.current, previousSelectedValue: previousSelectedValue.current, selectedCategoryValue: currentSelectedCategoryValue.current, previousSelectedCategoryValue: previousSelectedCategoryValue.current, registeredNavItems: registeredNavItems.current }; }, []); return { components: { root: 'div' }, root: slot.always(getIntrinsicElementProps('div', { ref: useMergedRefs(ref, innerRef), ...props }), { elementType: 'div' }), openCategories, selectedValue, selectedCategoryValue, onRegister, onUnregister, onSelect, getRegisteredNavItems, onRequestNavCategoryItemToggle, multiple, density, tabbable: false }; };