File size: 3,195 Bytes
2485dd8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
import {useRef, useEffect} from 'react';
import * as THREE from 'three';
import {extend} from '@react-three/fiber';
import ThreeMeshUI from 'three-mesh-ui';
import ThreeMeshUIText, {ThreeMeshUITextType} from './ThreeMeshUIText';
import {Interactive} from '@react-three/xr';
/**
* Using `?url` at the end of this import tells vite this is a static asset, and
* provides us a URL to the hashed version of the file when the project is built.
* See: https://vitejs.dev/guide/assets.html#explicit-url-imports
*/
import robotoFontFamilyJson from '../assets/RobotoMono-Regular-msdf.json?url';
import robotoFontTexture from '../assets/RobotoMono-Regular.png';
extend(ThreeMeshUI);
/**
* Button component that renders as a three-mesh-ui block
*/
export default function Button({
onClick,
content,
width,
height,
fontSize,
borderRadius,
padding,
}) {
const button = useRef<JSX.IntrinsicElements['block']>();
const textRef = useRef<ThreeMeshUITextType>();
useEffect(() => {
if (textRef.current != null) {
textRef.current.set({content});
}
}, [textRef, content]);
useEffect(() => {
if (!button.current) {
return;
}
button.current.setupState({
state: 'hovered',
attributes: {
offset: 0.002,
backgroundColor: new THREE.Color(0x607b8f),
fontColor: new THREE.Color(0xffffff),
},
});
button.current.setupState({
state: 'idle',
attributes: {
offset: 0.001,
backgroundColor: new THREE.Color(0x465a69),
fontColor: new THREE.Color(0xffffff),
},
});
button.current.setupState({
state: 'selected',
attributes: {
offset: 0.005,
backgroundColor: new THREE.Color(0x000000),
fontColor: new THREE.Color(0xffffff),
},
});
button.current.setState('idle');
}, []);
const args = [
{
width,
height,
fontSize,
padding,
justifyContent: 'end',
textAlign: 'center',
alignItems: 'center',
borderRadius,
fontFamily: robotoFontFamilyJson,
fontTexture: robotoFontTexture,
backgroundOpacity: 1,
backgroundColor: new THREE.Color(0x779092),
fontColor: new THREE.Color(0x000000),
},
];
return (
<Interactive
// These are for XR mode
onSelect={() => {
onClick();
}}
onHover={() => button.current.setState('hovered')}
onBlur={() => button.current.setState('idle')}
onSelectStart={() => button.current.setState('selected')}
onSelectEnd={() => button.current.setState('idle')}>
<block
// These are for non-XR modes
onPointerEnter={() => button.current.setState('hovered')}
onPointerLeave={() => button.current.setState('idle')}
onPointerDown={() => button.current.setState('selected')}
onPointerUp={() => {
button.current.setState('hovered');
onClick();
}}>
<block args={args} ref={button}>
<ThreeMeshUIText
ref={textRef}
fontColor={new THREE.Color(0xffffff)}
content={content}
/>
</block>
</block>
</Interactive>
);
}
|