'use client'; import * as React from 'react'; import { DefaultInfoButtonIcon12, DefaultInfoButtonIcon16, DefaultInfoButtonIcon20 } from './DefaultInfoButtonIcons'; import { getIntrinsicElementProps, mergeCallbacks, useControllableState, slot, useMergedRefs, elementContains, useEventCallback } from '@fluentui/react-utilities'; import { Popover, PopoverSurface } from '@fluentui/react-popover'; const infoButtonIconMap = { small: /*#__PURE__*/ React.createElement(DefaultInfoButtonIcon12, null), medium: /*#__PURE__*/ React.createElement(DefaultInfoButtonIcon16, null), large: /*#__PURE__*/ React.createElement(DefaultInfoButtonIcon20, null) }; const popoverSizeMap = { small: 'small', medium: 'small', large: 'medium' }; /** * Create the state required to render InfoButton. * * The returned state can be modified with hooks such as useInfoButtonStyles_unstable, * before being passed to renderInfoButton_unstable. * * @param props - props from this instance of InfoButton * @param ref - reference to root HTMLButtonElement of InfoButton */ export const useInfoButton_unstable = (props, ref)=>{ const { size = 'medium', inline = true, popover, info, ...rest } = props; const rootRef = useMergedRefs(ref); const state = { inline, size, components: { root: 'button', popover: Popover, info: PopoverSurface }, root: slot.always(getIntrinsicElementProps('button', { children: infoButtonIconMap[size], type: 'button', 'aria-label': 'information', ...rest, ref: rootRef }), { elementType: 'button' }), popover: slot.always(popover, { defaultProps: { inline, positioning: 'above-start', size: popoverSizeMap[size], withArrow: true }, elementType: Popover }), info: slot.always(info, { defaultProps: { role: 'note', tabIndex: -1 }, elementType: PopoverSurface }) }; const [popoverOpen, setPopoverOpen] = useControllableState({ state: state.popover.open, defaultState: state.popover.defaultOpen, initialState: false }); state.popover.open = popoverOpen; state.popover.onOpenChange = mergeCallbacks(state.popover.onOpenChange, (e, data)=>setPopoverOpen(data.open)); const infoRef = useMergedRefs(state.info.ref); state.info.ref = infoRef; // Hide the popover when focus moves out of the button and popover const onBlurButtonOrInfo = (e)=>{ const nextFocused = e.relatedTarget; if (nextFocused && rootRef.current !== nextFocused && !elementContains(infoRef.current, nextFocused)) { setPopoverOpen(false); } }; state.root.onBlur = useEventCallback(mergeCallbacks(state.root.onBlur, onBlurButtonOrInfo)); state.info.onBlurCapture = useEventCallback(mergeCallbacks(state.info.onBlurCapture, onBlurButtonOrInfo)); return state; };