diff --git a/src/components/Application.js b/src/components/Application.js index 00460f3c..2da9f956 100644 --- a/src/components/Application.js +++ b/src/components/Application.js @@ -1,12 +1,15 @@ import { createElement, + forwardRef, useEffect, + useImperativeHandle, useRef, + useState, } from 'react'; import { render } from '../render.js'; -/** @typedef {import('pixi.js').Application} Application */ -/** @typedef {import('pixi.js').ApplicationOptions} ApplicationOptions */ +/** @typedef {import('pixi.js').Application} PixiApplication */ +/** @typedef {import('pixi.js').ApplicationOptions} PixiApplicationOptions */ /** * @template T * @typedef {import('react').PropsWithChildren} PropsWithChildren @@ -30,16 +33,16 @@ import { render } from '../render.js'; * @property {string} [className] CSS classes to be applied to the Pixi Application's canvas element. */ -/** @typedef {PropsWithChildren>>} ApplicationPropsWithChildren */ -/** @typedef {PropsWithRef<{ ref?: RefObject }>} ApplicationPropsWithRef */ -/** @typedef {BaseApplicationProps & ApplicationPropsWithChildren & ApplicationPropsWithRef} ApplicationProps */ +/** @typedef {PropsWithChildren>>} ApplicationPropsWithChildren */ +/** @typedef {PropsWithRef<{ ref?: RefObject }>} ApplicationPropsWithRef */ +/** @typedef {BaseApplicationProps & ApplicationPropsWithChildren} ApplicationProps */ /** * Creates a React root and renders a Pixi application. * - * @param {ApplicationProps} props All props. + * @type {import('react').ForwardRefRenderFunction} */ -export function Application(props) +export const ApplicationFunction = (props, forwardedRef) => { const { children, @@ -50,18 +53,29 @@ export function Application(props) /** @type {RefObject} */ const canvasRef = useRef(null); + const [application, setApplication] = /** @type {PixiApplication} */ useState(); + + useImperativeHandle(forwardedRef, () => /** @type {PixiApplication} */ /** @type {*} */ (application)); + useEffect(() => { const canvasElement = canvasRef.current; if (canvasElement) { - render(children, canvasElement, applicationProps); + setApplication(render(children, canvasElement, applicationProps)); } - }, []); + }, [ + applicationProps, + children, + ]); return createElement('canvas', { ref: canvasRef, className, }); -} +}; + +ApplicationFunction.displayName = 'Application'; + +export const Application = forwardRef(ApplicationFunction); diff --git a/src/render.js b/src/render.js index da6a7355..7925b450 100644 --- a/src/render.js +++ b/src/render.js @@ -17,8 +17,28 @@ const context = createContext(null); const roots = new Map(); /** @typedef {import('pixi.js').ApplicationOptions} ApplicationOptions */ -/** @typedef {import('react').PropsWithChildren} PropsWithChildren */ -/** @typedef {Partial} RenderProps */ + +/** + * @template T + * @typedef {import('react').PropsWithChildren} PropsWithChildren + */ +/** + * @template T + * @typedef {import('react').PropsWithRef} PropsWithRef + */ +/** + * @template T + * @typedef {import('react').RefObject} RefObject + */ + +/** + * @template T + * @typedef {import('./typedefs/OmitChildren.js').OmitChildren} OmitChildren + */ + +/** @typedef {PropsWithChildren>} ApplicationPropsWithChildren */ +/** @typedef {PropsWithRef<{ ref: RefObject }>} ApplicationPropsWithRef */ +/** @typedef {Partial} RenderProps */ /** * This renders an element to a canvas, creates a renderer, scene, etc. @@ -131,5 +151,5 @@ export function render( () => undefined ); - return state; + return state.app; }