({
state,
isExiting,
UNSTABLE_portalContainer,
clearContexts,
...props
}: PopoverInnerProps)
| 208 | } |
| 209 | |
| 210 | function PopoverInner({ |
| 211 | state, |
| 212 | isExiting, |
| 213 | UNSTABLE_portalContainer, |
| 214 | clearContexts, |
| 215 | ...props |
| 216 | }: PopoverInnerProps) { |
| 217 | // Calculate the arrow size internally (and remove props.arrowSize from PopoverProps) |
| 218 | // Referenced from: packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx |
| 219 | let arrowRef = useRef<HTMLDivElement>(null); |
| 220 | let containerRef = useRef<HTMLDivElement | null>(null); |
| 221 | let groupCtx = useContext(PopoverGroupContext); |
| 222 | let isSubPopover = groupCtx && props.trigger === 'SubmenuTrigger'; |
| 223 | |
| 224 | let {popoverProps, underlayProps, arrowProps, placement, triggerAnchorPoint} = usePopover( |
| 225 | { |
| 226 | ...props, |
| 227 | offset: props.offset ?? 8, |
| 228 | arrowRef, |
| 229 | // If this is a submenu/subdialog, use the root popover's container |
| 230 | // to detect outside interaction and add aria-hidden. |
| 231 | groupRef: isSubPopover ? groupCtx! : containerRef |
| 232 | }, |
| 233 | state |
| 234 | ); |
| 235 | |
| 236 | let ref = props.popoverRef as RefObject<HTMLDivElement | null>; |
| 237 | let isEntering = useEnterAnimation(ref, !!placement) || props.isEntering || false; |
| 238 | let renderProps = useRenderProps({ |
| 239 | ...props, |
| 240 | defaultClassName: 'react-aria-Popover', |
| 241 | values: { |
| 242 | trigger: props.trigger || null, |
| 243 | placement, |
| 244 | isEntering, |
| 245 | isExiting |
| 246 | } |
| 247 | }); |
| 248 | |
| 249 | // Automatically render Popover with role=dialog except when isNonModal is true, |
| 250 | // or a dialog is already nested inside the popover. |
| 251 | let shouldBeDialog = !props.isNonModal || props.trigger === 'SubmenuTrigger'; |
| 252 | let [isDialog, setDialog] = useState(false); |
| 253 | useLayoutEffect(() => { |
| 254 | if (ref.current) { |
| 255 | setDialog(shouldBeDialog && !ref.current.querySelector('[role=dialog]')); |
| 256 | } |
| 257 | }, [ref, shouldBeDialog]); |
| 258 | |
| 259 | // Focus the popover itself on mount, unless a child element is already focused. |
| 260 | // Skip this for submenus since hovering a submenutrigger should keep focus on the trigger |
| 261 | useEffect(() => { |
| 262 | if ( |
| 263 | isDialog && |
| 264 | (props.trigger !== 'SubmenuTrigger' || getInteractionModality() !== 'pointer') && |
| 265 | ref.current && |
| 266 | !isFocusWithin(ref.current) |
| 267 | ) { |
nothing calls this directly
no test coverage detected