@react-three/uikit
Version:
Build performant 3D user interfaces with react-three-fiber and yoga.
50 lines (49 loc) • 1.89 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { forwardRef, useEffect } from 'react';
import { Image } from './image.js';
import { useLoader } from '@react-three/fiber';
import { SRGBColorSpace, TextureLoader } from 'three';
import { Video } from './video.js';
import { suspend } from 'suspend-react';
import { updateVideoElement } from '@pmndrs/uikit/internals';
/**
* be aware that this component does not dispose the loaded texture
*/
export const SuspendingImage = forwardRef(({ src, ...props }, ref) => {
const texture = useLoader(TextureLoader, src);
texture.colorSpace = SRGBColorSpace;
texture.matrixAutoUpdate = false;
return _jsx(Image, { ref: ref, src: texture, ...props });
});
const loadVideoElementSymbol = Symbol('load-video-element');
export const SuspendingVideo = forwardRef((props, ref) => {
const element = suspend(loadVideoElement, [loadVideoElementSymbol]);
updateVideoElement(element, props);
useEffect(() => {
// Need to append the element to the document, so auto play works.
document.body.appendChild(element);
return () => element.remove();
}, [element]);
return _jsx(Video, { ref: ref, ...props, src: element });
});
function loadVideoElement() {
const result = document.createElement('video');
result.style.position = 'absolute';
result.style.width = '1px';
result.style.zIndex = '-1000';
result.style.top = '0px';
result.style.left = '0px';
return new Promise((resolve) => {
const handleLoadedData = () => {
result.removeEventListener('loadeddata', handleLoadedData);
resolve(result);
};
// Check if the video already has data loaded
if (result.readyState >= 2) {
resolve(result);
}
else {
result.addEventListener('loadeddata', handleLoadedData);
}
});
}