/** * Copyright (c) TonTech. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { createContext, forwardRef, useContext, useEffect, useLayoutEffect, useState } from 'react'; import type { ComponentPropsWithoutRef, ComponentRef } from 'react'; import clsx from 'clsx'; import { useImageLoadingStatus } from './use-image-loading-status'; import type { ImageLoadingStatus } from './use-image-loading-status'; import styles from './logo.module.css'; interface LogoContextValue { imageLoadingStatus: ImageLoadingStatus; onImageLoadingStatusChange: (status: ImageLoadingStatus) => void; } const LogoContext = createContext(null); const useLogoContext = (): LogoContextValue => { const ctx = useContext(LogoContext); if (!ctx) throw new Error('Logo compound components must be used within Logo.Root'); return ctx; }; const LogoRoot = forwardRef, ComponentPropsWithoutRef<'span'>>(({ className, ...props }, ref) => { const [imageLoadingStatus, setImageLoadingStatus] = useState('idle'); return ( ); }); LogoRoot.displayName = 'LogoRoot'; interface LogoImageProps extends ComponentPropsWithoutRef<'img'> { onLoadingStatusChange?: (status: ImageLoadingStatus) => void; } const LogoImage = forwardRef, LogoImageProps>( ({ src, onLoadingStatusChange, className, ...props }, ref) => { const context = useLogoContext(); const loadingStatus = useImageLoadingStatus(src); useLayoutEffect(() => { if (loadingStatus !== 'idle') { onLoadingStatusChange?.(loadingStatus); context.onImageLoadingStatusChange(loadingStatus); } }, [loadingStatus]); return loadingStatus === 'loaded' ? ( ) : null; }, ); LogoImage.displayName = 'LogoImage'; interface LogoFallbackProps extends ComponentPropsWithoutRef<'span'> { delayMs?: number; } const LogoFallback = forwardRef, LogoFallbackProps>(({ delayMs, className, ...props }, ref) => { const context = useLogoContext(); const [canRender, setCanRender] = useState(delayMs === undefined); useEffect(() => { if (delayMs !== undefined) { const id = window.setTimeout(() => setCanRender(true), delayMs); return () => window.clearTimeout(id); } return undefined; }, [delayMs]); return canRender && context.imageLoadingStatus !== 'loaded' ? ( ) : null; }); LogoFallback.displayName = 'LogoFallback'; export interface LogoProps extends ComponentPropsWithoutRef<'span'> { size?: number; src?: string; alt?: string; fallback?: string; } export const Logo = forwardRef, LogoProps>(({ size = 30, src, alt, fallback, ...props }, ref) => { return ( {(fallback || alt) && {fallback ? fallback : alt?.[0]}} ); }); Logo.displayName = 'Logo';