Skip to content

Commit

Permalink
feat: useMeasureFont
Browse files Browse the repository at this point in the history
  • Loading branch information
bbohlender committed Jun 24, 2024
1 parent 78401af commit b284e87
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 4 deletions.
21 changes: 20 additions & 1 deletion examples/uikit/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ComponentRef, StrictMode, Suspense, useEffect, useMemo, useRef, useState } from 'react'
import { Canvas } from '@react-three/fiber'
import { Box, PerspectiveCamera, OrthographicCamera, RenderTexture, OrbitControls } from '@react-three/drei'
import { Box, OrthographicCamera, RenderTexture } from '@react-three/drei'
import { signal } from '@preact/signals-core'
import {
DefaultProperties,
Expand All @@ -18,6 +18,7 @@ import {
ImageProperties,
canvasInputProps,
Video,
useMeasureFont,
} from '@react-three/uikit'
import { Texture } from 'three'
import { Skeleton } from '../../../packages/kits/default/src/skeleton.js'
Expand Down Expand Up @@ -47,6 +48,8 @@ export default function App() {
style={{ height: '100dvh', touchAction: 'none' }}
gl={{ localClippingEnabled: true }}
>
<MeasureText />
<OrthographicCamera makeDefault />
<StrictMode>
<FontFamilyProvider inter={{ normal: 'inter-normal.json' }}>
<color attach="background" args={['black']} />
Expand Down Expand Up @@ -299,6 +302,22 @@ export default function App() {
)
}

function MeasureText() {
const measure = useMeasureFont()

useEffect(
() =>
void measure({
fontSize: 100,
letterSpacing: 0,
lineHeight: '120%',
text: 'hello world',
wordBreak: 'keep-all',
}).then(console.log),
)
return null
}

/**
* text performance tests:
* <Root width={1920} height={1080} positionType="relative">
Expand Down
59 changes: 57 additions & 2 deletions packages/react/src/font.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { FontFamilies, FontFamilyUrls } from '@pmndrs/uikit/internals'
import { useContext, createContext, ReactNode } from 'react'
import {
Font,
FontFamilies,
FontFamilyUrls,
FontWeight,
GlyphLayoutProperties,
Initializers,
MergedProperties,
Subscriptions,
computedFont,
initialize,
measureGlyphLayout,
unsubscribeSubscriptions,
} from '@pmndrs/uikit/internals'
import { signal } from '@preact/signals-core'
import { useThree } from '@react-three/fiber'
import { useContext, createContext, ReactNode, useCallback, useEffect, useMemo } from 'react'

const FontFamiliesContext = createContext<FontFamilies>(null as any)

Expand All @@ -17,3 +32,43 @@ export function FontFamilyProvider<T extends string = never>(properties: {
export function useFontFamilies(): FontFamilies | undefined {
return useContext(FontFamiliesContext)
}

/**
* @returns a function that measure the text and returns the width and height if the font is already loaded. Else undefined
*/
export function useMeasureFont(fontFamily?: string, fontWeight?: FontWeight) {
const fontFamilies = useFontFamilies()
const propertiesSignal = useMemo(() => signal<MergedProperties>(new MergedProperties()), [])
propertiesSignal.value = new MergedProperties()
propertiesSignal.value.add('fontFamily', fontFamily)
propertiesSignal.value.add('fontWeight', fontWeight)
const initializers = useMemo<Initializers>(() => [], [])
const renderer = useThree((state) => state.gl)
const font = useMemo(
() => computedFont(propertiesSignal, signal(fontFamilies), renderer, initializers),
[fontFamilies, initializers, propertiesSignal, renderer],
)
useEffect(() => {
const subscriptions: Subscriptions = []
initialize(initializers, subscriptions)
return () => unsubscribeSubscriptions(subscriptions)
}, [initializers])
return useCallback(
async (properties: Omit<GlyphLayoutProperties, 'font'> & { availableWidth?: number }) => {
let fontValue = font.peek()
if (fontValue == null) {
fontValue = await new Promise<Font>((resolve) => {
const unsubscribe = font.subscribe((font) => {
if (font == null) {
return
}
unsubscribe()
resolve(font)
})
})
}
return measureGlyphLayout({ ...properties, font: fontValue }, properties.availableWidth)
},
[font],
)
}
2 changes: 1 addition & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { FontFamilyProvider } from './font.js'
export { FontFamilyProvider, useMeasureFont } from './font.js'
export { useRootSize } from './responsive.js'
export {
basedOnPreferredColorScheme,
Expand Down

0 comments on commit b284e87

Please sign in to comment.