import { type FontItem } from "./fontUtils"; /** * FontManager: Singleton class that manages Google Fonts loading and caching * * Key responsibilities: * - Fetches and caches the Google Fonts list * - Manages font loading states to prevent duplicate loading * - Optimizes font loading through intersection observers * - Handles scroll-based lazy loading of fonts * * Usage: * const fontManager = FontManager.getInstance(apiKey); * await fontManager.getFontList(); * fontManager.loadFont('Font Name'); * * Implements multiple caching strategies: * 1. Browser cache for font stylesheets * 2. Durable L1 store (IndexedDB) for the font catalog + loaded-font registry * 3. Memory cache for runtime performance */ export interface FontData { family: string; category: FontItem['category']; isCustom?: boolean; /** Google Web Fonts API variant ids (e.g. "400", "700", "regular") */ variants?: string[]; } /** Maps Google Fonts API variant ids to display weight labels. */ export declare function mapGoogleVariantIdsToWeightNames(variants: string[]): string[]; declare class FontManager { private static readonly DEBUG_MODE; private static readonly WAIT_TIME; private static instance; private loadedFonts; private observers; private scrollTimeout; private apiKey; private fontListPromise; /** * Catalog lifecycle as an explicit union. Replaces the former * `initialFontsLoaded`/`allFontsLoaded` boolean pair whose ordering * ('initial' must precede 'complete') was only convention. Only the * 'complete' stage is ever persisted to the durable cache, preventing * partial catalogs from being written. */ private catalog; /** Current catalog contents regardless of stage (empty until loaded). */ private get catalogFonts(); private static readonly CACHE_KEY; private static readonly CACHE_DURATION; private static readonly LOADED_FONTS_KEY; private static readonly LEGACY_CACHE_KEY; private static readonly LEGACY_LOADED_FONTS_KEY; private static readonly CACHE_CONTROL; private visibleFonts; private static initialPreloadComplete; private static preloadPromise; private completeFontList; static isInitialized: boolean; static initialFontNumber: number; private static initializationPromise; private remainingTime; private preInitializedObservers; static readonly BATCH_SIZE = 100; private currentBatchIndex; private batchIndices; private categoryFonts; private customFonts; private static missingApiKeyWarned; private static forbiddenApiKeyWarned; private static badRequestApiKeyWarned; private catalogFetchPromise; private hasGoogleFontsApiKey; private warnMissingApiKey; private warnForbiddenApiKey; private warnBadRequestApiKey; /** * Fetches the full Google Fonts catalog (Web Fonts Developer API). * Returns null when key is missing or the request fails — callers use cache/custom fonts. */ private fetchGoogleFontsCatalog; private fetchGoogleFontsCatalogOnce; /** Variant ids from cached catalog (avoids per-font API calls). */ getGoogleFontVariantIds(family: string): string[] | null; /** * Private constructor to enforce singleton pattern * @param apiKey - Google Fonts API key */ private constructor(); /** * Gets or creates the singleton instance and initializes it */ static getInstance(apiKey: string): Promise; /** * Initializes the FontManager with initial fonts and setup */ private initialize; /** * Pre-initializes observers during FontManager initialization */ private preInitializeObservers; /** * Gets a pre-initialized observer */ getPreInitializedObserver(): IntersectionObserver | null; /** * Loads previously cached fonts from the durable L1 store (legacy localStorage fallback) */ private loadCachedFonts; /** * Saves the current state of loaded fonts to the durable L1 store */ private saveLoadedFonts; /** * Gets the stylesheet href for a font family with optimized parameters */ private getFontStylesheetHref; /** * Checks if a font is available in Google Fonts */ private isGoogleFont; /** * Inserts a font stylesheet into the document * @param family - Font family name * @param subset - Whether to use text subsetting (for preview) */ insertFontStylesheet(family: string, subset?: boolean): Promise; /** * Loads a font with full character set */ loadFullFont(family: string): Promise; /** * Checks if a font is in the initial fonts list */ private isInitialFont; /** * Checks if a font is in the browser cache */ private checkFontInBrowserCache; /** * Maps Google Fonts categories to our simplified category system * @param category - The category from Google Fonts API * @returns Simplified category name */ private mapCategory; /** * Ensures fonts are sorted by popularity */ private ensureFontSorting; /** * Gets initial font list (initial number of fonts + recent fonts) * @returns Promise resolving to initial font list */ getInitialFontList(): Promise; /** * Saves font list to the durable L1 cache. * Only 'complete' catalogs are persisted — a partial ('initial') catalog * written here used to be served for the full 24h cache duration. */ private saveFontListToCache; /** * Gets font list from the durable L1 cache (legacy localStorage fallback) */ private getFontListFromCache; /** * Gets complete font list (called when dropdown opens) */ getCompleteFontList(force?: boolean): Promise; /** * Preloads initial fonts with optimized loading strategy * Returns existing promise if preload is in progress */ preloadInitialFonts(): Promise; /** * Loads initial visible fonts */ private loadInitialVisibleFonts; /** * Creates or retrieves an intersection observer for a container * @param container - The HTML element to observe * @returns IntersectionObserver instance or null if container is invalid */ getObserver(container: HTMLElement | null): IntersectionObserver | null; /** * Gets the font sources for a given family, including fallbacks * @param fontFamily - Font family name * @returns CSS src string with font sources */ private getFontSources; /** * Generates a complete @font-face declaration * @param fontFamily - Font family name * @param options - Font face configuration options * @returns Complete @font-face CSS rule */ private generateFontFaceRule; /** * Loads a font with specified weights using FontFaceObserver * Simplified version with better error handling */ loadFont(family: string, weights?: string[]): Promise; /** * Handles scroll optimization for font loading * Implements debouncing to prevent excessive font loading * @param callback - Optional callback after fonts are loaded */ handleScroll(callback?: () => void): void; /** * Checks if a font is already loaded */ isFontLoaded(family: string): boolean; /** * Gets stats about loaded fonts */ getLoadedFontsStats(): { total: number; fonts: string[]; }; /** * Cleans up resources when a font container is removed * Prevents memory leaks from orphaned observers * @param containerId - ID of the container being cleaned up */ cleanup(containerId: string): void; /** * Categorizes a font based on its family name * Delegates to fontUtils for consistent categorization * @param family - Font family name to categorize */ private categorizeFont; isScrolling(): boolean; addVisibleFont(fontFamily: string): void; removeVisibleFont(family: string): void; /** * Verifies if a font is actually cached in the browser */ private verifyFontCache; /** * Gets list of fonts cached in browser with detailed status */ private getBrowserCachedFonts; /** * Gets the cached font list without making an API call */ getCachedFontList(): FontData[]; /** * Gets the next batch of fonts */ getNextBatch(controllerId: string, category?: string): FontData[]; /** * Checks if there are more fonts to load */ hasMoreFonts(controllerId: string, category?: string): boolean; /** * Resets the batch index to initial number * This allows each font input controller to start from the beginning */ resetBatchIndex(controllerId: string): void; getPreloadedFonts(category: FontItem['category']): FontData[]; /** * Gets the complete list of Google Fonts * @returns Promise resolving to FontData array */ private getGoogleFontsList; removeCustomFont(family: string): Promise; loadCustomFonts(): Promise; /** * Checks if a font is a custom font */ isCustomFont(family: string): boolean; /** * Gets custom font data if available */ getCustomFont(family: string): FontData | undefined; } export default FontManager;