-
Notifications
You must be signed in to change notification settings - Fork 730
/
Copy pathText.tsx
104 lines (97 loc) · 2.8 KB
/
Text.tsx
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
import * as React from 'react'
// @ts-ignore
import { Text as TextMeshImpl, preloadFont } from 'troika-three-text'
import { ReactThreeFiber, useThree } from '@react-three/fiber'
import { suspend } from 'suspend-react'
import { ForwardRefComponent } from '../helpers/ts-utils'
type Props = JSX.IntrinsicElements['mesh'] & {
children: React.ReactNode
characters?: string
color?: ReactThreeFiber.Color
/** Font size, default: 1 */
fontSize?: number
fontWeight?: number | string
fontStyle?: 'italic' | 'normal'
maxWidth?: number
lineHeight?: number
letterSpacing?: number
textAlign?: 'left' | 'right' | 'center' | 'justify'
font?: string
anchorX?: number | 'left' | 'center' | 'right'
anchorY?: number | 'top' | 'top-baseline' | 'middle' | 'bottom-baseline' | 'bottom'
clipRect?: [number, number, number, number]
depthOffset?: number
direction?: 'auto' | 'ltr' | 'rtl'
overflowWrap?: 'normal' | 'break-word'
whiteSpace?: 'normal' | 'overflowWrap' | 'nowrap'
outlineWidth?: number | string
outlineOffsetX?: number | string
outlineOffsetY?: number | string
outlineBlur?: number | string
outlineColor?: ReactThreeFiber.Color
outlineOpacity?: number
strokeWidth?: number | string
strokeColor?: ReactThreeFiber.Color
strokeOpacity?: number
fillOpacity?: number
sdfGlyphSize?: number
debugSDF?: boolean
onSync?: (troika: any) => void
}
export const Text: ForwardRefComponent<Props, any> = /* @__PURE__ */ React.forwardRef(
(
{
sdfGlyphSize = 64,
anchorX = 'center',
anchorY = 'middle',
font,
fontSize = 1,
children,
characters,
onSync,
...props
}: Props,
ref: React.ForwardedRef<any>
) => {
const invalidate = useThree(({ invalidate }) => invalidate)
const [troikaMesh] = React.useState(() => new TextMeshImpl())
const [nodes, text] = React.useMemo(() => {
const n: React.ReactNode[] = []
let t = ''
React.Children.forEach(children, (child) => {
if (typeof child === 'string' || typeof child === 'number') {
t += child
} else {
n.push(child)
}
})
return [n, t]
}, [children])
suspend(() => new Promise((res) => preloadFont({ font, characters }, res)), ['troika-text', font, characters])
React.useLayoutEffect(
() =>
void troikaMesh.sync(() => {
invalidate()
if (onSync) onSync(troikaMesh)
})
)
React.useEffect(() => {
return () => troikaMesh.dispose()
}, [troikaMesh])
return (
<primitive
object={troikaMesh}
ref={ref}
font={font}
text={text}
anchorX={anchorX}
anchorY={anchorY}
fontSize={fontSize}
sdfGlyphSize={sdfGlyphSize}
{...props}
>
{nodes}
</primitive>
)
}
)