/* - [ ] Font preloading */ import { useConst } from "@hmans/react-toolbox" import { Primitive, ReactorComponentProps } from "../reactor" import React, { FC, useLayoutEffect } from "react" import type { ColorRepresentation, Mesh } from "three" import { Text as TroikaText } from "troika-three-text" type TextProps = ReactorComponentProps & Partial<{ children: string characters: string color: ColorRepresentation fontSize: number 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" | "overflowWrap" outlineWidth: number | string outlineOffsetX: number | string outlineOffsetY: number | string outlineBlur: number | string outlineColor: ColorRepresentation outlineOpacity: number strokeWidth: number | string strokeColor: ColorRepresentation strokeOpacity: number text: string fillOpacity: number debugSDF: boolean }> export const Text: FC = ({ children, ...props }) => { const troika = useConst(() => new TroikaText()) /* Separate plaintext nodes from the rest */ const [nodes, text] = React.useMemo(() => { const nodes: React.ReactNode[] = [] let text = "" React.Children.forEach(children, (child) => { if (typeof child === "string" || typeof child === "number") { text += child } else { nodes.push(child) } }) return [nodes, text] }, [children]) /* Sync text object every time props change */ useLayoutEffect(() => troika.sync()) return ( {nodes} ) }