'use client'; import * as React from 'react'; import { Suspense, type ReactNode, type ComponentType } from 'react'; import { cn } from '@djangocfg/ui-core/lib'; import { useAppT } from '@djangocfg/i18n'; // ============================================================================ // Loading Fallback Components // ============================================================================ export interface LoadingFallbackProps { /** Minimum height of the loading container */ minHeight?: string | number; /** Show loading text */ showText?: boolean; /** Custom loading text */ text?: string; /** Additional CSS classes */ className?: string; } /** * Spinner - Simple spinning loader */ export function Spinner({ className }: { className?: string }) { const t = useAppT(); const loadingLabel = t('ui.states.loading'); return (
); } /** * LoadingFallback - Default loading state for lazy components */ export function LoadingFallback({ minHeight = 200, showText = true, text, className, }: LoadingFallbackProps) { const t = useAppT(); const loadingText = text ?? t('ui.form.loading'); const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight; return (
{showText && (

{loadingText}

)}
); } /** * CardLoadingFallback - Loading state styled as a card */ export function CardLoadingFallback({ title, description, minHeight = 200, className, }: { title?: string; description?: string; minHeight?: string | number; className?: string; }) { const t = useAppT(); const cardTitle = title ?? t('ui.states.loading'); const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight; return (
{cardTitle}
{description && (

{description}

)}
); } /** * MapLoadingFallback - Loading state for map components */ export function MapLoadingFallback({ minHeight = 400, className, }: { minHeight?: string | number; className?: string; }) { const t = useAppT(); const loadingText = t('ui.form.loading'); const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight; return (

{loadingText}

); } // ============================================================================ // Lazy Wrapper // ============================================================================ export interface LazyWrapperProps { children: ReactNode; /** Custom fallback component */ fallback?: ReactNode; /** Use card-style fallback */ card?: boolean; /** Card title (when card=true) */ cardTitle?: string; /** Card description (when card=true) */ cardDescription?: string; /** Minimum height for fallback */ minHeight?: string | number; /** Additional CSS classes for fallback */ className?: string; } /** * LazyWrapper - Suspense wrapper with configurable fallbacks * * @example * // Basic usage * * * * * @example * // Card style fallback * * * * * @example * // Custom fallback * }> * * */ export function LazyWrapper({ children, fallback, card = false, cardTitle, cardDescription, minHeight = 200, className, }: LazyWrapperProps) { const defaultFallback = card ? ( ) : ( ); return {children}; } // ============================================================================ // Lazy Component Factory // ============================================================================ export interface CreateLazyComponentOptions

{ /** Loading fallback component */ fallback?: ReactNode | ((props: P) => ReactNode); /** Display name for the component */ displayName?: string; } /** * createLazyComponent - Factory for creating lazy-loaded components * * @example * const LazyMermaid = createLazyComponent( * () => import('./Mermaid.client'), * { * displayName: 'Mermaid', * fallback: , * } * ); */ export function createLazyComponent

( loader: () => Promise<{ default: ComponentType

}>, options: CreateLazyComponentOptions

= {} ): ComponentType

{ const LazyComponent = React.lazy(loader); const WrappedComponent = (props: P) => { const fallback = typeof options.fallback === 'function' ? options.fallback(props) : options.fallback ?? ; return ( ); }; WrappedComponent.displayName = options.displayName ?? 'LazyComponent'; return WrappedComponent; }