import { StackItem } from "@fluentui/react"; import { makeStyles } from "@griffel/react"; import { CSSProperties, ComponentType, HTMLAttributes, ReactNode, useImperativeHandle, useMemo, useRef, useState, } from "react"; import { forwardRef } from "../utils/with-display-name"; import { ResizeObserver, Size } from "./resize-observer"; export interface DeviceViewProps extends HTMLAttributes { width: number; height: number; BottomElement?: ComponentType<{ className: string; style: CSSProperties; children: ReactNode; }>; children?: ReactNode; } export interface DeviceViewRef { enterFullscreen(): void; } const useClasses = makeStyles({ outer: { width: "100%", height: "100%", backgroundColor: "black", }, inner: { position: "absolute", transformOrigin: "top left", }, bottom: { position: "absolute", }, }); export const DeviceView = forwardRef("DeviceView")( ( { width, height, BottomElement, children, ...props }: DeviceViewProps, ref ) => { const classes = useClasses(); const [containerSize, setContainerSize] = useState({ width: 0, height: 0, }); const [bottomSize, setBottomSize] = useState({ width: 0, height: 0, }); // Container size minus bottom element size const usableSize = useMemo( () => ({ width: containerSize.width, height: containerSize.height - bottomSize.height, }), [containerSize, bottomSize] ); // Compute sizes after scaling const childrenStyle = useMemo(() => { let scale: number; let childrenWidth: number; let childrenHeight: number; let childrenTop: number; let childrenLeft: number; if (width === 0 || usableSize.width === 0) { scale = 1; childrenWidth = 0; childrenHeight = 0; childrenTop = 0; childrenLeft = 0; } else { const videoRatio = width / height; const containerRatio = usableSize.width / usableSize.height; if (videoRatio > containerRatio) { scale = usableSize.width / width; childrenWidth = usableSize.width; childrenHeight = height * scale; childrenTop = (usableSize.height - childrenHeight) / 2; childrenLeft = 0; } else { scale = usableSize.height / height; childrenWidth = width * scale; childrenHeight = usableSize.height; childrenTop = 0; childrenLeft = (usableSize.width - childrenWidth) / 2; } } return { scale, width: childrenWidth, height: childrenHeight, top: childrenTop, left: childrenLeft, }; }, [width, height, usableSize]); const containerRef = useRef(null); useImperativeHandle( ref, () => ({ enterFullscreen() { containerRef.current!.requestFullscreen(); }, }), [] ); return (
{children}
{!!width && !!BottomElement && ( )}
); } );