diff --git a/example/src/App.js b/example/src/App.js index b6dce62..98546e6 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -19,8 +19,14 @@ const geometries = [ function ToggleButton(props) { const a11y = useA11y() + console.log(a11y) return ( - + { + console.log(a11y) + a11y.refHtml.a11yNeedUpdate = true + }}> diff --git a/src/A11y.tsx b/src/A11y.tsx index bd2846b..3a5f856 100644 --- a/src/A11y.tsx +++ b/src/A11y.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState, useContext } from 'react'; import { useThree } from '@react-three/fiber'; import useAnnounceStore from './announceStore'; +import useA11yStore from './a11yStore'; import { useA11ySectionContext } from './A11ySection'; import { stylesHiddenButScreenreadable } from './A11yConsts'; import { Html } from './Html'; @@ -75,6 +76,7 @@ const A11yContext = React.createContext({ focus: false, hover: false, pressed: false, + refHtml: null, }); A11yContext.displayName = 'A11yContext'; @@ -118,15 +120,18 @@ export const A11y: React.FC = ({ }); const a11yScreenReader = useAnnounceStore(state => state.a11yScreenReader); + const registerA11YObj = useA11yStore(state => state.registerA11YObj); const overHtml = useRef(false); const overMesh = useRef(false); + const refHtml = useRef(null); const domElement = useThree(state => state.gl.domElement); // temporary fix to prevent error -> keep track of our component's mounted state const componentIsMounted = useRef(true); useEffect(() => { + registerA11YObj(refHtml.current); return () => { domElement.style.cursor = 'default'; componentIsMounted.current = false; @@ -454,6 +459,7 @@ export const A11y: React.FC = ({ hover: a11yState.hovered, focus: a11yState.focused, pressed: a11yState.pressed, + refHtml: refHtml.current, }} > = ({ children.props.position ? children.props.position : 0 } {...portal} + ref={refHtml} > {AltText} {HtmlAccessibleElement} diff --git a/src/Html.tsx b/src/Html.tsx index 501926c..4be7091 100644 --- a/src/Html.tsx +++ b/src/Html.tsx @@ -82,22 +82,23 @@ export const Html = React.forwardRef( zIndexRange = [16777271, 0], ...props }: HtmlProps, - ref: React.Ref + ref: React.Ref ) => { const gl = useThree(({ gl }) => gl); const camera = useThree(({ camera }) => camera); const scene = useThree(({ scene }) => scene); const size = useThree(({ size }) => size); const [el] = React.useState(() => document.createElement('div')); - const group = React.useRef(null); const oldZoom = React.useRef(0); const oldPosition = React.useRef([0, 0]); const target = portal?.current ?? gl.domElement.parentNode; React.useEffect(() => { - if (group.current) { + //@ts-ignore + if (ref.current) { scene.updateMatrixWorld(); - const vec = calculatePosition(group.current, camera, size); + //@ts-ignore + const vec = calculatePosition(ref.current, camera, size); el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(${vec[0]}px,${vec[1]}px,0);transform-origin:0 0;`; if (target) { target.appendChild(el); @@ -120,41 +121,42 @@ export const Html = React.forwardRef( React.useLayoutEffect(() => { ReactDOM.render( -
, +
, el ); }); useFrame(() => { - if (group.current) { + if ( + //@ts-ignore + (ref.current && ref.current.a11yAutoUpdate) || + //@ts-ignore + ref.current.a11yNeedUpdate + ) { camera.updateMatrixWorld(); - const vec = calculatePosition(group.current, camera, size); + //@ts-ignore + const vec = calculatePosition(ref.current, camera, size); if ( Math.abs(oldZoom.current - camera.zoom) > eps || Math.abs(oldPosition.current[0] - vec[0]) > eps || Math.abs(oldPosition.current[1] - vec[1]) > eps ) { - el.style.display = !isObjectBehindCamera(group.current, camera) + //@ts-ignore + el.style.display = !isObjectBehindCamera(ref.current, camera) ? 'block' : 'none'; - el.style.zIndex = `${objectZIndex( - group.current, - camera, - zIndexRange - )}`; + //@ts-ignore + el.style.zIndex = `${objectZIndex(ref.current, camera, zIndexRange)}`; el.style.transform = `translate3d(${vec[0]}px,${vec[1]}px,0) scale(1)`; oldPosition.current = vec; oldZoom.current = camera.zoom; } + //@ts-ignore + ref.current.a11yNeedUpdate = false; } }); - return ; + return ; } ); diff --git a/src/a11yStore.tsx b/src/a11yStore.tsx new file mode 100644 index 0000000..b931327 --- /dev/null +++ b/src/a11yStore.tsx @@ -0,0 +1,25 @@ +import { Group } from 'three'; +import create from 'zustand'; + +type State = { + a11yObj: Array>; + registerA11YObj: (a11yObj: React.Ref) => void; +}; + +const useA11yStore = create(set => { + return { + a11yObj: [], + registerA11YObj: a11yObj => { + set(state => { + let newA11yObj = state.a11yObj; + newA11yObj.push(a11yObj); + + return { + a11yObj: newA11yObj, + }; + }); + }, + }; +}); + +export default useA11yStore;