UNPKG

@shopify/react-native-skia

Version:

High-performance React Native Graphics using Skia

111 lines (99 loc) 2.75 kB
import React, { useEffect, useRef } from "react"; import { StyleSheet } from "react-native"; import type { Int32 } from "react-native/Libraries/Types/CodegenTypes"; import type { ViewProps } from "react-native"; import { contextIdToId } from "./utils"; export interface NativeProps extends ViewProps { contextId: Int32; transparent: boolean; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function debounce<T extends (...args: any[]) => void>( func: T, wait: number, immediate = false ) { let timeout: ReturnType<typeof setTimeout> | undefined; return function debounced( this: ThisParameterType<T>, ...args: Parameters<T> ) { const context = this; const callNow = immediate && !timeout; if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { timeout = undefined; if (!immediate) { func.apply(context, args); } }, wait); if (callNow) { func.apply(context, args); } }; } function resizeCanvas(canvas: HTMLCanvasElement | null) { if (!canvas) { return; } const dpr = window.devicePixelRatio || 1; const { height, width } = canvas.getBoundingClientRect(); canvas.setAttribute("height", (height * dpr).toString()); canvas.setAttribute("width", (width * dpr).toString()); } // eslint-disable-next-line import/no-default-export export default function WebGPUViewNativeComponent( props: NativeProps ): React.JSX.Element { const { contextId, style, transparent, ...rest } = props; const canvasElm = useRef<HTMLCanvasElement>(null); useEffect(() => { const onResize = debounce(() => resizeCanvas(canvasElm.current), 100); window.addEventListener("resize", onResize); return () => { window.removeEventListener("resize", onResize); }; }, []); return React.createElement("canvas", { ...rest, id: contextIdToId(contextId), style: { ...styles.view, ...styles.flex1, ...(transparent === false ? { backgroundColor: "white" } : {}), ...(typeof style === "object" ? style : {}), }, ref: (ref: HTMLCanvasElement) => { canvasElm.current = ref; if (ref) { resizeCanvas(ref); } }, }); } const styles = StyleSheet.create({ flex1: { flex: 1, }, view: { alignItems: "stretch", backgroundColor: "transparent", // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error border: "0 solid black", boxSizing: "border-box", display: "flex", flexBasis: "auto", flexDirection: "column", flexShrink: 0, listStyle: "none", margin: 0, minHeight: 0, minWidth: 0, padding: 0, position: "relative", zIndex: 0, }, });