/** * WordPress dependencies */ import { __experimentalText as WCText } from '@wordpress/components'; import { useContext, useEffect, useState, useRef } from '@wordpress/element'; import type { FontFamily, FontFace } from '@wordpress/core-data'; /** * Internal dependencies */ import { FontLibraryContext } from './context'; import { getFacePreviewStyle, getFamilyPreviewStyle, } from './utils/preview-styles'; import type { FontDemoProps } from './types'; function getPreviewUrl( fontFace: FontFace ): string | undefined { if ( fontFace.preview ) { return fontFace.preview; } if ( fontFace.src ) { return Array.isArray( fontFace.src ) ? fontFace.src[ 0 ] : fontFace.src; } return undefined; } function getDisplayFontFace( font: FontFamily | FontFace ): FontFace { // if this IS a font face return it if ( ( 'fontStyle' in font && font.fontStyle ) || ( 'fontWeight' in font && font.fontWeight ) ) { return font; } // if this is a font family with a collection of font faces // return the first one that is normal and 400 OR just the first one if ( 'fontFace' in font && font.fontFace && font.fontFace.length ) { return ( font.fontFace.find( ( face ) => face.fontStyle === 'normal' && face.fontWeight === '400' ) || font.fontFace[ 0 ] ); } // This must be a font family with no font faces // return a fake font face return { fontStyle: 'normal', fontWeight: '400', fontFamily: font.fontFamily, }; } function FontDemo( { font, text }: FontDemoProps ) { const ref = useRef< HTMLDivElement >( null ); const fontFace = getDisplayFontFace( font ); const style = getFamilyPreviewStyle( font ); text = text || ( 'name' in font ? font.name : '' ); const customPreviewUrl = font.preview; const [ isIntersecting, setIsIntersecting ] = useState< boolean >( false ); const [ isAssetLoaded, setIsAssetLoaded ] = useState< boolean >( false ); const { loadFontFaceAsset } = useContext( FontLibraryContext ); const previewUrl = customPreviewUrl ?? getPreviewUrl( fontFace ); const isPreviewImage = previewUrl && previewUrl.match( /\.(png|jpg|jpeg|gif|svg)$/i ); const faceStyles = getFacePreviewStyle( fontFace ); const textDemoStyle = { fontSize: '18px', lineHeight: 1, opacity: isAssetLoaded ? '1' : '0', ...style, ...faceStyles, }; useEffect( () => { const observer = new window.IntersectionObserver( ( [ entry ] ) => { setIsIntersecting( entry.isIntersecting ); }, {} ); if ( ref.current ) { observer.observe( ref.current ); } return () => observer.disconnect(); }, [ ref ] ); useEffect( () => { const loadAsset = async () => { if ( isIntersecting ) { if ( ! isPreviewImage && fontFace.src ) { await loadFontFaceAsset( fontFace ); } setIsAssetLoaded( true ); } }; loadAsset(); }, [ fontFace, isIntersecting, loadFontFaceAsset, isPreviewImage ] ); return (
{ isPreviewImage ? ( { ) : ( { text } ) }
); } export default FontDemo;