UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

1 lines 21.6 kB
{"version":3,"file":"use-config.cjs","sources":["../../../src/hooks/use-config.ts"],"sourcesContent":["/**\n * @frank-auth/react - useConfig Hook\n *\n * Configuration hook that provides access to UI configuration, feature flags,\n * localization settings, and organization-specific configuration.\n */\n\nimport {useCallback, useMemo} from 'react';\n\nimport type {\n AppearanceConfig,\n ComponentOverrides,\n FrankAuthUIConfig,\n LocalizationConfig,\n OrganizationConfig,\n Theme,\n} from '../config';\n\nimport {useConfig as useConfigProvider} from '../provider/config-provider';\nimport {useAuth} from './use-auth';\n\nimport type {AuthFeatures, LinksPathConfig} from '../provider/types';\n\n// ============================================================================\n// Config Hook Interface\n// ============================================================================\n\nexport interface UseConfigReturn {\n // Core configuration\n config: FrankAuthUIConfig;\n publishableKey: string;\n apiUrl: string;\n userType: string;\n debug: boolean;\n\n // UI configuration\n theme: Theme;\n appearance: AppearanceConfig;\n localization: LocalizationConfig;\n components: ComponentOverrides;\n titleAlignment: 'left' | 'center' | 'right';\n linksPath?: LinksPathConfig;\n\n\n // Organization configuration\n organization: OrganizationConfig | undefined;\n organizationSettings: any;\n\n // Feature flags\n features: AuthFeatures;\n\n // Configuration methods\n updateConfig: (updates: Partial<FrankAuthUIConfig>) => void;\n setTheme: (theme: Partial<Theme>) => void;\n setAppearance: (appearance: Partial<AppearanceConfig>) => void;\n setLocale: (locale: string) => void;\n resetToDefaults: () => void;\n\n // Feature flag helpers\n hasFeature: (feature: keyof AuthFeatures) => boolean;\n requireFeature: (feature: keyof AuthFeatures) => void;\n\n // Validation\n isConfigValid: boolean;\n configErrors: string[];\n\n // State helpers\n isLoaded: boolean;\n isMultiTenant: boolean;\n isCustomBranded: boolean;\n}\n\n// ============================================================================\n// Main useConfig Hook\n// ============================================================================\n\n/**\n * Configuration hook providing access to all UI configuration and settings\n *\n * @example Basic configuration access\n * ```tsx\n * import { useConfig } from '@frank-auth/react';\n *\n * function ConfigDisplay() {\n * const {\n * theme,\n * features,\n * hasFeature,\n * organization,\n * setTheme\n * } = useConfig();\n *\n * return (\n * <div>\n * <p>Theme mode: {theme.mode}</p>\n * <p>MFA enabled: {hasFeature('mfa') ? 'Yes' : 'No'}</p>\n * {organization && <p>Organization: {organization.name}</p>}\n *\n * <button onClick={() => setTheme({ mode: 'dark' })}>\n * Switch to Dark Mode\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @example Feature-based conditional rendering\n * ```tsx\n * function ConditionalFeatures() {\n * const { hasFeature, requireFeature } = useConfig();\n *\n * // Conditional rendering\n * if (!hasFeature('mfa')) {\n * return <div>MFA not available</div>;\n * }\n *\n * // Feature requirement (throws if not available)\n * const handleMFASetup = () => {\n * requireFeature('mfa');\n * // MFA setup logic...\n * };\n *\n * return <button onClick={handleMFASetup}>Setup MFA</button>;\n * }\n * ```\n *\n * @example Organization-specific configuration\n * ```tsx\n * function OrganizationConfig() {\n * const {\n * organization,\n * organizationSettings,\n * isMultiTenant,\n * isCustomBranded\n * } = useConfig();\n *\n * if (!isMultiTenant) {\n * return <div>Single tenant mode</div>;\n * }\n *\n * return (\n * <div>\n * <h3>{organization?.name}</h3>\n * {isCustomBranded && (\n * <img src={organizationSettings?.branding?.logo} alt=\"Organization Logo\" />\n * )}\n * <p>MFA Required: {organizationSettings?.mfaRequired ? 'Yes' : 'No'}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useConfig(): UseConfigReturn {\n const configProvider = useConfigProvider();\n const { activeOrganization } = useAuth();\n\n // Feature flag helpers\n const hasFeature = useCallback((feature: keyof AuthFeatures): boolean => {\n return configProvider.features[feature];\n }, [configProvider.features]);\n\n const requireFeature = useCallback((feature: keyof AuthFeatures): void => {\n if (!configProvider.features[feature]) {\n throw new Error(`Feature ${feature} is not enabled`);\n }\n }, [configProvider.features]);\n\n // Configuration validation\n const { isConfigValid, configErrors } = useMemo(() => {\n const errors: string[] = [];\n\n // Validate required configuration\n if (!configProvider.publishableKey) {\n errors.push('Publishable key is required');\n }\n\n if (!configProvider.userType) {\n errors.push('User type is required');\n }\n\n // Validate publishable key format\n if (configProvider.publishableKey &&\n !/^pk_(test|live)_[a-zA-Z0-9_]+$/.test(configProvider.publishableKey)) {\n errors.push('Invalid publishable key format');\n }\n\n // Validate API URL format\n if (configProvider.apiUrl) {\n try {\n new URL(configProvider.apiUrl);\n } catch {\n errors.push('Invalid API URL format');\n }\n }\n\n // Validate user type\n if (configProvider.userType &&\n !['internal', 'external', 'end_user'].includes(configProvider.userType)) {\n errors.push('Invalid user type');\n }\n\n return {\n isConfigValid: errors.length === 0,\n configErrors: errors,\n };\n }, [configProvider.publishableKey, configProvider.userType, configProvider.apiUrl]);\n\n // State helpers\n const isMultiTenant = useMemo(() => !!configProvider.organizationConfig, [configProvider.organizationConfig]);\n const isCustomBranded = useMemo(() => {\n return !!(configProvider.organizationSettings?.branding?.logoUrl ||\n configProvider.organizationSettings?.branding?.primaryColor ||\n configProvider.organizationSettings?.branding?.customCss);\n }, [configProvider.organizationSettings]);\n\n return {\n // Core configuration\n config: configProvider.config,\n publishableKey: configProvider.publishableKey,\n apiUrl: configProvider.apiUrl,\n userType: configProvider.userType,\n debug: configProvider.debug,\n\n // UI configuration\n titleAlignment: configProvider.config?.appearance?.titleAlignment ?? 'left',\n theme: configProvider.theme,\n appearance: configProvider.appearance,\n localization: configProvider.localization,\n components: configProvider.components,\n linksPath: configProvider.linksPath,\n\n // Organization configuration\n organization: configProvider.organizationConfig,\n organizationSettings: configProvider.organizationSettings,\n\n // Feature flags\n features: configProvider.features,\n\n // Configuration methods\n updateConfig: configProvider.updateConfig,\n setTheme: configProvider.setTheme,\n setAppearance: configProvider.setAppearance,\n setLocale: configProvider.setLocale,\n resetToDefaults: configProvider.resetToDefaults,\n\n // Feature flag helpers\n hasFeature,\n requireFeature,\n\n // Validation\n isConfigValid,\n configErrors,\n\n // State helpers\n isLoaded: configProvider.isLoaded,\n isMultiTenant,\n isCustomBranded,\n };\n}\n\n// ============================================================================\n// Specialized Config Hooks\n// ============================================================================\n\n/**\n * Hook for feature flags only\n */\nexport function useFeatureFlags() {\n const { features, hasFeature, requireFeature } = useConfig();\n\n return {\n features,\n hasFeature,\n requireFeature,\n\n // Convenience methods for common features\n canSignUp: hasFeature('signUp'),\n canSignIn: hasFeature('signIn'),\n canResetPassword: hasFeature('passwordReset'),\n hasMFA: hasFeature('mfa'),\n hasPasskeys: hasFeature('passkeys'),\n hasOAuth: hasFeature('oauth'),\n hasMagicLink: hasFeature('magicLink'),\n hasSSO: hasFeature('sso'),\n hasOrganizationManagement: hasFeature('organizationManagement'),\n hasUserProfile: hasFeature('userProfile'),\n hasSessionManagement: hasFeature('sessionManagement'),\n };\n}\n\n/**\n * Hook for theme configuration\n */\nexport function useThemeConfig() {\n const { theme, setTheme, appearance, setAppearance } = useConfig();\n\n return {\n theme,\n appearance,\n setTheme,\n setAppearance,\n\n // Theme helpers\n mode: theme.mode,\n colors: theme.colors,\n typography: theme.typography,\n spacing: theme.spacing,\n borderRadius: theme.borderRadius,\n shadows: theme.shadows,\n\n // Appearance helpers\n layout: appearance.layout,\n components: appearance.components,\n branding: appearance.branding,\n\n // Quick theme updates\n setMode: (mode: 'light' | 'dark' | 'system') => setTheme({ mode }),\n setPrimaryColor: (color: string) => setTheme({\n colors: { ...theme.colors, primary: { ...theme.colors.primary, DEFAULT: color } }\n }),\n setSecondaryColor: (color: string) => setTheme({\n colors: { ...theme.colors, secondary: { ...theme.colors.secondary, DEFAULT: color } }\n }),\n };\n}\n\n/**\n * Hook for localization configuration\n */\nexport function useLocalizationConfig() {\n const { localization, setLocale } = useConfig();\n\n return {\n localization,\n setLocale,\n\n // Localization helpers\n currentLocale: localization.defaultLocale,\n supportedLocales: localization.supportedLocales,\n dateFormat: localization.dateFormat,\n timeFormat: localization.timeFormat,\n direction: localization.direction,\n\n // Quick locale updates\n isRTL: localization.direction === 'rtl',\n setEnglish: () => setLocale('en'),\n setSpanish: () => setLocale('es'),\n setFrench: () => setLocale('fr'),\n setGerman: () => setLocale('de'),\n };\n}\n\n/**\n * Hook for organization-specific configuration\n */\nexport function useOrganizationConfiguration() {\n const {\n organization,\n organizationSettings,\n isMultiTenant,\n isCustomBranded,\n features,\n } = useConfig();\n\n const organizationFeatures = useMemo(() => {\n if (!organization) return {};\n\n return {\n sso: organization.features?.sso || false,\n mfa: organization.features?.mfa || false,\n auditLogs: organization.features?.auditLogs || false,\n customBranding: organization.features?.customBranding || false,\n apiAccess: organization.features?.apiAccess || false,\n };\n }, [organization]);\n\n return {\n organization,\n organizationSettings,\n isMultiTenant,\n isCustomBranded,\n features: organizationFeatures,\n\n // Organization helpers\n organizationId: organization?.id || null,\n organizationName: organization?.name || null,\n organizationSlug: organization?.slug || null,\n\n // Settings helpers\n allowPublicSignup: organizationSettings?.allowPublicSignup || false,\n requireEmailVerification: organizationSettings?.requireEmailVerification || false,\n requirePhoneVerification: organizationSettings?.requirePhoneVerification || false,\n mfaRequired: organizationSettings?.mfaRequired || false,\n allowedMfaMethods: organizationSettings?.allowedMfaMethods || [],\n\n // Branding helpers\n branding: organizationSettings?.branding,\n logo: organizationSettings?.branding?.logo,\n primaryColor: organizationSettings?.branding?.primaryColor,\n secondaryColor: organizationSettings?.branding?.secondaryColor,\n customCSS: organizationSettings?.branding?.customCSS,\n\n // Limits\n limits: organization?.limits,\n maxUsers: organization?.limits?.maxUsers || 0,\n maxSessions: organization?.limits?.maxSessions || 0,\n apiRequestLimit: organization?.limits?.apiRequestLimit || 0,\n };\n}\n\n/**\n * Hook for component overrides\n */\nexport function useComponentConfiguration() {\n const { components } = useConfig();\n\n const getComponent = useCallback(<T extends keyof ComponentOverrides>(\n componentName: T,\n defaultComponent: any\n ) => {\n return components[componentName] || defaultComponent;\n }, [components]);\n\n const hasOverride = useCallback((componentName: keyof ComponentOverrides) => {\n return !!components[componentName];\n }, [components]);\n\n return {\n components,\n getComponent,\n hasOverride,\n\n // Component availability checks\n hasCustomLayout: hasOverride('Layout'),\n hasCustomHeader: hasOverride('Header'),\n hasCustomFooter: hasOverride('Footer'),\n hasCustomSignInForm: hasOverride('SignInForm'),\n hasCustomSignUpForm: hasOverride('SignUpForm'),\n hasCustomUserProfile: hasOverride('UserProfile'),\n hasCustomButton: hasOverride('Button'),\n hasCustomInput: hasOverride('Input'),\n hasCustomCard: hasOverride('Card'),\n hasCustomModal: hasOverride('Modal'),\n };\n}\n\n/**\n * Hook for configuration validation and debugging\n */\nexport function useConfigValidation() {\n const {\n isConfigValid,\n configErrors,\n debug,\n publishableKey,\n apiUrl,\n userType,\n } = useConfig();\n\n const warnings = useMemo(() => {\n const warnings: string[] = [];\n\n // Development warnings\n if (publishableKey?.startsWith('pk_test_') &&\n typeof window !== 'undefined' &&\n window.location.hostname !== 'localhost' &&\n !window.location.hostname.includes('127.0.0.1')) {\n warnings.push('Using test publishable key in production environment');\n }\n\n if (apiUrl?.startsWith('http://') &&\n typeof window !== 'undefined' &&\n window.location.protocol === 'https:') {\n warnings.push('Using HTTP API URL on HTTPS site');\n }\n\n return warnings;\n }, [publishableKey, apiUrl]);\n\n return {\n isValid: isConfigValid,\n errors: configErrors,\n warnings,\n debug,\n\n // Helper methods\n hasErrors: configErrors.length > 0,\n hasWarnings: warnings.length > 0,\n isProduction: !publishableKey?.startsWith('pk_test_'),\n isTestMode: publishableKey?.startsWith('pk_test_'),\n\n // Validation helpers\n validatePublishableKey: () => {\n if (!publishableKey) return false;\n return /^pk_(test|live)_[a-zA-Z0-9_]+$/.test(publishableKey);\n },\n validateApiUrl: () => {\n if (!apiUrl) return true; // Optional\n try {\n new URL(apiUrl);\n return true;\n } catch {\n return false;\n }\n },\n validateUserType: () => {\n return ['internal', 'external', 'end_user'].includes(userType);\n },\n };\n}"],"names":["useConfig","configProvider","useConfigProvider","activeOrganization","useAuth","hasFeature","useCallback","feature","requireFeature","isConfigValid","configErrors","useMemo","errors","isMultiTenant","isCustomBranded","useFeatureFlags","features","useThemeConfig","theme","setTheme","appearance","setAppearance","mode","color","useLocalizationConfig","localization","setLocale","useOrganizationConfiguration","organization","organizationSettings","organizationFeatures","useComponentConfiguration","components","getComponent","componentName","defaultComponent","hasOverride","useConfigValidation","debug","publishableKey","apiUrl","userType","warnings"],"mappings":"kLAwJO,SAASA,GAA6B,CACzC,MAAMC,EAAiBC,EAAAA,UAAkB,EACnC,CAAE,mBAAAC,CAAmB,EAAIC,UAAQ,EAGjCC,EAAaC,cAAaC,GACrBN,EAAe,SAASM,CAAO,EACvC,CAACN,EAAe,QAAQ,CAAC,EAEtBO,EAAiBF,cAAaC,GAAsC,CACtE,GAAI,CAACN,EAAe,SAASM,CAAO,EAChC,MAAM,IAAI,MAAM,WAAWA,CAAO,iBAAiB,CACvD,EACD,CAACN,EAAe,QAAQ,CAAC,EAGtB,CAAE,cAAAQ,EAAe,aAAAC,CAAa,EAAIC,UAAQ,IAAM,CAClD,MAAMC,EAAmB,CAAC,EAkB1B,GAfKX,EAAe,gBAChBW,EAAO,KAAK,6BAA6B,EAGxCX,EAAe,UAChBW,EAAO,KAAK,uBAAuB,EAInCX,EAAe,gBACf,CAAC,iCAAiC,KAAKA,EAAe,cAAc,GACpEW,EAAO,KAAK,gCAAgC,EAI5CX,EAAe,OACX,GAAA,CACI,IAAA,IAAIA,EAAe,MAAM,CAAA,MACzB,CACJW,EAAO,KAAK,wBAAwB,CAAA,CAKxC,OAAAX,EAAe,UACf,CAAC,CAAC,WAAY,WAAY,UAAU,EAAE,SAASA,EAAe,QAAQ,GACtEW,EAAO,KAAK,mBAAmB,EAG5B,CACH,cAAeA,EAAO,SAAW,EACjC,aAAcA,CAClB,CAAA,EACD,CAACX,EAAe,eAAgBA,EAAe,SAAUA,EAAe,MAAM,CAAC,EAG5EY,EAAgBF,EAAQ,QAAA,IAAM,CAAC,CAACV,EAAe,mBAAoB,CAACA,EAAe,kBAAkB,CAAC,EACtGa,EAAkBH,EAAAA,QAAQ,IACrB,CAAC,EAAEV,EAAe,sBAAsB,UAAU,SACrDA,EAAe,sBAAsB,UAAU,cAC/CA,EAAe,sBAAsB,UAAU,WACpD,CAACA,EAAe,oBAAoB,CAAC,EAEjC,MAAA,CAEH,OAAQA,EAAe,OACvB,eAAgBA,EAAe,eAC/B,OAAQA,EAAe,OACvB,SAAUA,EAAe,SACzB,MAAOA,EAAe,MAGtB,eAAgBA,EAAe,QAAQ,YAAY,gBAAkB,OACrE,MAAOA,EAAe,MACtB,WAAYA,EAAe,WAC3B,aAAcA,EAAe,aAC7B,WAAYA,EAAe,WAC3B,UAAWA,EAAe,UAG1B,aAAcA,EAAe,mBAC7B,qBAAsBA,EAAe,qBAGrC,SAAUA,EAAe,SAGzB,aAAcA,EAAe,aAC7B,SAAUA,EAAe,SACzB,cAAeA,EAAe,cAC9B,UAAWA,EAAe,UAC1B,gBAAiBA,EAAe,gBAGhC,WAAAI,EACA,eAAAG,EAGA,cAAAC,EACA,aAAAC,EAGA,SAAUT,EAAe,SACzB,cAAAY,EACA,gBAAAC,CACJ,CACJ,CASO,SAASC,GAAkB,CAC9B,KAAM,CAAE,SAAAC,EAAU,WAAAX,EAAY,eAAAG,CAAA,EAAmBR,EAAU,EAEpD,MAAA,CACH,SAAAgB,EACA,WAAAX,EACA,eAAAG,EAGA,UAAWH,EAAW,QAAQ,EAC9B,UAAWA,EAAW,QAAQ,EAC9B,iBAAkBA,EAAW,eAAe,EAC5C,OAAQA,EAAW,KAAK,EACxB,YAAaA,EAAW,UAAU,EAClC,SAAUA,EAAW,OAAO,EAC5B,aAAcA,EAAW,WAAW,EACpC,OAAQA,EAAW,KAAK,EACxB,0BAA2BA,EAAW,wBAAwB,EAC9D,eAAgBA,EAAW,aAAa,EACxC,qBAAsBA,EAAW,mBAAmB,CACxD,CACJ,CAKO,SAASY,GAAiB,CAC7B,KAAM,CAAE,MAAAC,EAAO,SAAAC,EAAU,WAAAC,EAAY,cAAAC,CAAA,EAAkBrB,EAAU,EAE1D,MAAA,CACH,MAAAkB,EACA,WAAAE,EACA,SAAAD,EACA,cAAAE,EAGA,KAAMH,EAAM,KACZ,OAAQA,EAAM,OACd,WAAYA,EAAM,WAClB,QAASA,EAAM,QACf,aAAcA,EAAM,aACpB,QAASA,EAAM,QAGf,OAAQE,EAAW,OACnB,WAAYA,EAAW,WACvB,SAAUA,EAAW,SAGrB,QAAUE,GAAsCH,EAAS,CAAE,KAAAG,EAAM,EACjE,gBAAkBC,GAAkBJ,EAAS,CACzC,OAAQ,CAAE,GAAGD,EAAM,OAAQ,QAAS,CAAE,GAAGA,EAAM,OAAO,QAAS,QAASK,CAAQ,CAAA,CAAA,CACnF,EACD,kBAAoBA,GAAkBJ,EAAS,CAC3C,OAAQ,CAAE,GAAGD,EAAM,OAAQ,UAAW,CAAE,GAAGA,EAAM,OAAO,UAAW,QAASK,CAAQ,CAAA,CACvF,CAAA,CACL,CACJ,CAKO,SAASC,GAAwB,CACpC,KAAM,CAAE,aAAAC,EAAc,UAAAC,CAAU,EAAI1B,EAAU,EAEvC,MAAA,CACH,aAAAyB,EACA,UAAAC,EAGA,cAAeD,EAAa,cAC5B,iBAAkBA,EAAa,iBAC/B,WAAYA,EAAa,WACzB,WAAYA,EAAa,WACzB,UAAWA,EAAa,UAGxB,MAAOA,EAAa,YAAc,MAClC,WAAY,IAAMC,EAAU,IAAI,EAChC,WAAY,IAAMA,EAAU,IAAI,EAChC,UAAW,IAAMA,EAAU,IAAI,EAC/B,UAAW,IAAMA,EAAU,IAAI,CACnC,CACJ,CAKO,SAASC,GAA+B,CACrC,KAAA,CACF,aAAAC,EACA,qBAAAC,EACA,cAAAhB,EACA,gBAAAC,EACA,SAAAE,GACAhB,EAAU,EAER8B,EAAuBnB,EAAAA,QAAQ,IAC5BiB,EAEE,CACH,IAAKA,EAAa,UAAU,KAAO,GACnC,IAAKA,EAAa,UAAU,KAAO,GACnC,UAAWA,EAAa,UAAU,WAAa,GAC/C,eAAgBA,EAAa,UAAU,gBAAkB,GACzD,UAAWA,EAAa,UAAU,WAAa,EACnD,EAR0B,CAAC,EAS5B,CAACA,CAAY,CAAC,EAEV,MAAA,CACH,aAAAA,EACA,qBAAAC,EACA,cAAAhB,EACA,gBAAAC,EACA,SAAUgB,EAGV,eAAgBF,GAAc,IAAM,KACpC,iBAAkBA,GAAc,MAAQ,KACxC,iBAAkBA,GAAc,MAAQ,KAGxC,kBAAmBC,GAAsB,mBAAqB,GAC9D,yBAA0BA,GAAsB,0BAA4B,GAC5E,yBAA0BA,GAAsB,0BAA4B,GAC5E,YAAaA,GAAsB,aAAe,GAClD,kBAAmBA,GAAsB,mBAAqB,CAAC,EAG/D,SAAUA,GAAsB,SAChC,KAAMA,GAAsB,UAAU,KACtC,aAAcA,GAAsB,UAAU,aAC9C,eAAgBA,GAAsB,UAAU,eAChD,UAAWA,GAAsB,UAAU,UAG3C,OAAQD,GAAc,OACtB,SAAUA,GAAc,QAAQ,UAAY,EAC5C,YAAaA,GAAc,QAAQ,aAAe,EAClD,gBAAiBA,GAAc,QAAQ,iBAAmB,CAC9D,CACJ,CAKO,SAASG,GAA4B,CAClC,KAAA,CAAE,WAAAC,CAAW,EAAIhC,EAAU,EAE3BiC,EAAe3B,EAAAA,YAAY,CAC7B4B,EACAC,IAEOH,EAAWE,CAAa,GAAKC,EACrC,CAACH,CAAU,CAAC,EAETI,EAAc9B,cAAa4B,GACtB,CAAC,CAACF,EAAWE,CAAa,EAClC,CAACF,CAAU,CAAC,EAER,MAAA,CACH,WAAAA,EACA,aAAAC,EACA,YAAAG,EAGA,gBAAiBA,EAAY,QAAQ,EACrC,gBAAiBA,EAAY,QAAQ,EACrC,gBAAiBA,EAAY,QAAQ,EACrC,oBAAqBA,EAAY,YAAY,EAC7C,oBAAqBA,EAAY,YAAY,EAC7C,qBAAsBA,EAAY,aAAa,EAC/C,gBAAiBA,EAAY,QAAQ,EACrC,eAAgBA,EAAY,OAAO,EACnC,cAAeA,EAAY,MAAM,EACjC,eAAgBA,EAAY,OAAO,CACvC,CACJ,CAKO,SAASC,GAAsB,CAC5B,KAAA,CACF,cAAA5B,EACA,aAAAC,EACA,MAAA4B,EACA,eAAAC,EACA,OAAAC,EACA,SAAAC,GACAzC,EAAU,EAER0C,EAAW/B,EAAAA,QAAQ,IAAM,CAC3B,MAAM+B,EAAqB,CAAC,EAG5B,OAAIH,GAAgB,WAAW,UAAU,GACrC,OAAO,OAAW,KAClB,OAAO,SAAS,WAAa,aAC7B,CAAC,OAAO,SAAS,SAAS,SAAS,WAAW,GAC9CG,EAAS,KAAK,sDAAsD,EAGpEF,GAAQ,WAAW,SAAS,GAC5B,OAAO,OAAW,KAClB,OAAO,SAAS,WAAa,UAC7BE,EAAS,KAAK,kCAAkC,EAG7CA,CAAA,EACR,CAACH,EAAgBC,CAAM,CAAC,EAEpB,MAAA,CACH,QAAS/B,EACT,OAAQC,EACR,SAAAgC,EACA,MAAAJ,EAGA,UAAW5B,EAAa,OAAS,EACjC,YAAagC,EAAS,OAAS,EAC/B,aAAc,CAACH,GAAgB,WAAW,UAAU,EACpD,WAAYA,GAAgB,WAAW,UAAU,EAGjD,uBAAwB,IACfA,EACE,iCAAiC,KAAKA,CAAc,EAD/B,GAGhC,eAAgB,IAAM,CACd,GAAA,CAACC,EAAe,MAAA,GAChB,GAAA,CACA,WAAI,IAAIA,CAAM,EACP,EAAA,MACH,CACG,MAAA,EAAA,CAEf,EACA,iBAAkB,IACP,CAAC,WAAY,WAAY,UAAU,EAAE,SAASC,CAAQ,CAErE,CACJ"}