// Copyright (c) Meta Platforms, Inc. and affiliates. 'use client'; /** * @file Overlay.tsx * @input Uses React, useOverlay * @output Exports Overlay component * @position Overlay system component; thin wrapper over useOverlay * * Wraps content with an overlay scrim. Same pattern as Tooltip: * `children` is the base content, `content` is what appears on top. * * For applying overlay behavior to an existing container (Card), * use the useOverlay hook directly. */ import type { ReactNode, Ref } from 'react'; import * as stylex from "../style-runtime.js"; import { mergeProps } from "../utils/index.js"; import { useOverlay } from "./useOverlay.js"; import { useIsomorphicLayoutEffect } from "../hooks/useIsomorphicLayoutEffect.js"; import { overlayScope, overlayContainerStyles } from "./overlay.markers.stylex.js"; import { themeProps } from "../utils/themeProps.js"; import type { BaseProps } from "../BaseProps.js"; import type { OverlayScrimMode, OverlayPosition, OverlayAlign, OverlayShowOn } from "./OverlayScrim.js"; import { useMergedRefs } from "../hooks/useMergedRefs.js"; export interface OverlayProps extends Pick, 'xstyle' | 'className' | 'style'> { /** Ref forwarded to the container element. */ ref?: Ref; /** Base content (image, card, video, etc.). */ children?: ReactNode; /** Content rendered inside the overlay scrim. */ content: ReactNode; /** @default "always" */ showOn?: OverlayShowOn; /** JS-controlled visibility override. */ isOpen?: boolean; /** @default "dark" */ scrim?: OverlayScrimMode; /** @default "fill" */ position?: OverlayPosition; /** @default "end" */ align?: OverlayAlign; } /** * Overlay — renders content on top of media with a scrim background * and automatic theme inversion. * * `children` = base content, `content` = what appears on top. * * @compositionHint Wrap images, video, or media content. * * @example * ``` * }> * * * * * ``` */ export function Overlay({ children, content, showOn, isOpen, scrim, position, align, xstyle, className, style, ref }: OverlayProps) { const overlay = useOverlay({ content, showOn, isOpen, scrim, position, align }); // Border radius: mirror first child's radius onto the wrapper. // Only the component needs this — hook consumers have their own radius. useIsomorphicLayoutEffect(() => { const el = overlay.containerRef.current; if (!el) { return; } const firstChild = el.firstElementChild as HTMLElement | null; if (!firstChild) { return; } const radius = getComputedStyle(firstChild).borderRadius; if (radius && radius !== '0px') { // eslint-disable-next-line react-compiler/react-compiler -- imperative DOM: syncing border-radius from child el.style.borderRadius = radius; } }, []); return
{children} {overlay.element}
; } Overlay.displayName = 'Overlay';