'use client'; import * as React from 'react'; import { getIntrinsicElementProps, getRTLSafeKey, useMergedRefs, slot } from '@fluentui/react-utilities'; import { useFocusFinders } from '@fluentui/react-tabster'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import { ArrowRight, ArrowLeft } from '@fluentui/keyboard-keys'; import { menuSplitGroupMultilineAttr } from './useMenuSplitGroupStyles.styles'; /** * Create the state required to render MenuSplitGroup. * * The returned state can be modified with hooks such as useMenuSplitGroupStyles_unstable, * before being passed to renderMenuSplitGroup_unstable. * * @param props - props from this instance of MenuSplitGroup * @param ref - reference to root HTMLElement of MenuSplitGroup */ export const useMenuSplitGroup_unstable = (props, ref)=>{ const innerRef = React.useRef(undefined); const { dir, targetDocument } = useFluent(); const nextArrowKey = getRTLSafeKey(ArrowRight, dir); const prevArrowKey = getRTLSafeKey(ArrowLeft, dir); const { findNextFocusable, findPrevFocusable } = useFocusFinders(); const { multilineRef, setMultiline } = useHandleMultilineMenuItem(); const onKeyDown = React.useCallback((e)=>{ var _innerRef_current; const activeElement = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement; if (!activeElement) { return; } if (!((_innerRef_current = innerRef.current) === null || _innerRef_current === void 0 ? void 0 : _innerRef_current.contains(activeElement))) { return; } if (e.key === nextArrowKey) { const next = findNextFocusable(activeElement, { container: innerRef.current }); next === null || next === void 0 ? void 0 : next.focus(); } if (e.key === prevArrowKey) { const prev = findPrevFocusable(activeElement, { container: innerRef.current }); prev === null || prev === void 0 ? void 0 : prev.focus(); } }, [ findNextFocusable, findPrevFocusable, targetDocument, nextArrowKey, prevArrowKey ]); return { components: { root: 'div' }, setMultiline, root: slot.always(getIntrinsicElementProps('div', { role: 'group', // FIXME: // `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement` // but since it would be a breaking change to fix it, we are casting ref to it's proper type ref: useMergedRefs(ref, innerRef, multilineRef), onKeyDown, ...props }), { elementType: 'div' }) }; }; /** * Creates a callback that lets a multiline menu item child set an attribute on this component * Children can mount before parents so we need to store the value and apply it when the parent is mounted */ const useHandleMultilineMenuItem = ()=>{ const [handle] = React.useState(()=>{ let isMultiline = false; let multilineNode = null; function applyAttr() { multilineNode === null || multilineNode === void 0 ? void 0 : multilineNode.toggleAttribute(menuSplitGroupMultilineAttr, isMultiline); } return { multilineRef: (node)=>{ if (node) { multilineNode = node; applyAttr(); } else { multilineNode = null; } }, setMultiline: (value)=>{ isMultiline = value; applyAttr(); } }; }); return handle; };