@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
1 lines • 21.5 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../../../src/config/index.ts"],"sourcesContent":["/**\n * @frank-auth/react - Configuration System\n *\n * Unified entry point for the Frank Auth React UI configuration system.\n * Provides comprehensive configuration management for themes, appearance,\n * localization, and organization-specific settings.\n *\n * @example Basic Usage\n * ```typescript\n * import { createFrankAuthConfig } from '@frank-auth/react/config';\n *\n * const config = createFrankAuthConfig({\n * publishableKey: 'pk_test_...',\n * userType: 'external',\n * theme: {\n * mode: 'dark',\n * colors: {\n * primary: '#3b82f6',\n * },\n * },\n * });\n * ```\n *\n * @example Advanced Usage\n * ```typescript\n * import { \n * ConfigManager,\n * ThemeManager,\n * AppearanceManager,\n * LocalizationManager,\n * OrganizationConfigManager\n * } from '@frank-auth/react/config';\n *\n * const configManager = new ConfigManager({\n * publishableKey: 'pk_test_...',\n * userType: 'external',\n * organizationId: 'org_123',\n * });\n *\n * // Listen for configuration changes\n * configManager.subscribe((config) => {\n * console.log('Configuration updated:', config);\n * });\n * ```\n */\n\nimport {AppearanceManager} from './appearance';\nimport {LocalizationManager} from './localization';\nimport {OrganizationConfigManager, transformOrganizationSettings} from './organization';\nimport {ThemeManager} from './theme';\nimport type {ConfigValidationResult, FrankAuthUIConfig, OrganizationConfig, UserType} from './types';\nimport {CONFIG_PRESETS, DEFAULT_FRANK_AUTH_CONFIG,} from './defaults';\nimport {\n assertValidConfig,\n getConfigErrors,\n getConfigWarnings,\n isValidConfig,\n validateApiUrl,\n validateAppearanceConfig,\n validateComponentOverrides,\n validateFrankAuthConfig,\n validateLocale,\n validateLocalizationConfig,\n validateOrganizationConfig,\n validatePublishableKey,\n validateThemeConfig,\n validateUserType,\n} from './validators';\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\n// Core configuration types\nexport type {\n FrankAuthUIConfig,\n ConfigValidationError,\n ConfigValidationResult,\n} from './types';\n\n// Theme types\nexport type {\n ThemeMode,\n Typography,\n} from './types';\n\n// Appearance types\nexport type {\n AppearanceConfig,\n AppearanceMode,\n ComponentAppearance,\n BrandingConfig,\n ComponentSize,\n ColorVariant,\n} from './types';\n\n// Localization types\nexport type {\n LocalizationConfig,\n Locale,\n LocaleDirection,\n} from './types';\n\n// Organization types\nexport type {\n OrganizationConfig,\n OrganizationSettings,\n UserType,\n ComponentOverrides,\n} from './types';\n\n// Extended organization types\nexport type {\n OrganizationFeatureFlags,\n OrganizationLimits,\n OrganizationCompliance,\n ExtendedOrganizationConfig,\n} from './organization';\n\n// ============================================================================\n// Default Configuration Exports\n// ============================================================================\n\nexport {\n // Main defaults\n DEFAULT_FRANK_AUTH_CONFIG as defaultConfig,\n CONFIG_PRESETS as configPresets,\n\n // Theme defaults\n DEFAULT_THEME_CONFIG as defaultTheme,\n DEFAULT_COLOR_PALETTE as defaultColors,\n DEFAULT_TYPOGRAPHY as defaultTypography,\n DEFAULT_SPACING as defaultSpacing,\n DEFAULT_BORDER_RADIUS as defaultBorderRadius,\n DEFAULT_SHADOWS as defaultShadows,\n DEFAULT_ANIMATIONS as defaultAnimations,\n\n // Appearance defaults\n DEFAULT_APPEARANCE_CONFIG as defaultAppearance,\n DEFAULT_COMPONENT_APPEARANCE as defaultComponentAppearance,\n DEFAULT_LAYOUT_CONFIG as defaultLayout,\n DEFAULT_BRANDING_CONFIG as defaultBranding,\n\n // Localization defaults\n DEFAULT_LOCALIZATION_CONFIG as defaultLocalization,\n DEFAULT_LOCALE_MESSAGES as defaultMessages,\n\n // Organization defaults\n DEFAULT_ORGANIZATION_CONFIG as defaultOrganization,\n} from './defaults';\n\n// ============================================================================\n// Manager Class Exports\n// ============================================================================\n\nexport {\n ThemeManager,\n THEME_PRESETS as themePresets,\n createThemeManager,\n createDarkTheme,\n getThemeCSS,\n validateTheme,\n} from './theme';\n\nexport {\n AppearanceManager,\n INPUT_VARIANTS as inputVariants,\n BUTTON_VARIANTS as buttonVariants,\n CARD_VARIANTS as cardVariants,\n SIZE_CONFIGS as sizeConfigs,\n MODAL_SIZES as modalSizes,\n BREAKPOINTS as breakpoints,\n RESPONSIVE_UTILITIES as responsiveUtils,\n createAppearanceManager,\n getComponentClassNames,\n appearanceConfigToTailwind,\n createResponsiveProps,\n} from './appearance';\n\nexport {\n LocalizationManager,\n createLocalizationManager,\n detectBrowserLocale,\n getLocaleDirection,\n isRTL,\n createTranslationNamespace,\n} from './localization';\n\nexport {\n OrganizationConfigManager,\n createOrganizationConfigManager,\n transformOrganizationSettings,\n getFeaturesByTier,\n} from './organization';\n\n// ============================================================================\n// Validation Exports\n// ============================================================================\nexport {\n validateFrankAuthConfig,\n validateThemeConfig,\n validateAppearanceConfig,\n validateLocalizationConfig,\n validateOrganizationConfig,\n validateComponentOverrides,\n validatePublishableKey,\n validateApiUrl,\n validateUserType,\n validateLocale,\n assertValidConfig,\n isValidConfig,\n getConfigErrors,\n getConfigWarnings,\n} from './validators';\n\n// ============================================================================\n// Main Configuration Manager\n// ============================================================================\n\n/**\n * Comprehensive configuration manager that orchestrates all configuration aspects\n */\nexport class ConfigManager {\n private config: FrankAuthUIConfig;\n private themeManager: ThemeManager;\n private appearanceManager: AppearanceManager;\n private localizationManager: LocalizationManager;\n private organizationManager?: OrganizationConfigManager;\n private listeners: Set<(config: FrankAuthUIConfig) => void> = new Set();\n\n constructor(initialConfig: Partial<FrankAuthUIConfig>) {\n // Validate and merge with defaults\n this.config = { ...DEFAULT_FRANK_AUTH_CONFIG, ...initialConfig } as FrankAuthUIConfig;\n\n // Initialize managers\n this.themeManager = new ThemeManager(this.config.theme);\n this.appearanceManager = new AppearanceManager(this.config.appearance);\n this.localizationManager = new LocalizationManager(this.config.localization);\n\n // Initialize organization manager if organization config is provided\n if (this.config.organization) {\n this.organizationManager = new OrganizationConfigManager(\n this.config.organization,\n this.themeManager,\n this.appearanceManager\n );\n }\n\n this.setupManagerListeners();\n this.applyInitialConfiguration();\n }\n\n /**\n * Get current configuration\n */\n getConfig(): FrankAuthUIConfig {\n return { ...this.config };\n }\n\n /**\n * Update configuration\n */\n updateConfig(updates: Partial<FrankAuthUIConfig>): void {\n this.config = { ...this.config, ...updates };\n\n // Update individual managers\n if (updates.theme) {\n this.themeManager.setTheme(updates.theme);\n }\n\n if (updates.appearance) {\n this.appearanceManager.updateConfig(updates.appearance);\n }\n\n if (updates.localization) {\n this.localizationManager.updateConfig(updates.localization);\n }\n\n if (updates.organization && this.organizationManager) {\n this.organizationManager.updateConfig(updates.organization);\n }\n\n this.notifyListeners();\n }\n\n /**\n * Set organization configuration\n */\n setOrganization(organization: OrganizationConfig): void {\n this.config.organization = organization;\n this.config.projectId = organization.id;\n\n // Create or update organization manager\n if (!this.organizationManager) {\n this.organizationManager = new OrganizationConfigManager(\n organization,\n this.themeManager,\n this.appearanceManager\n );\n\n // Subscribe to organization changes\n this.organizationManager.subscribe((orgConfig) => {\n this.config.organization = orgConfig;\n this.notifyListeners();\n });\n } else {\n this.organizationManager.updateConfig(organization);\n }\n\n // Apply organization-specific UI configuration\n const orgUIConfig = this.organizationManager.generateUIConfig();\n this.updateConfig(orgUIConfig);\n }\n\n /**\n * Get theme manager\n */\n getThemeManager(): ThemeManager {\n return this.themeManager;\n }\n\n /**\n * Get appearance manager\n */\n getAppearanceManager(): AppearanceManager {\n return this.appearanceManager;\n }\n\n /**\n * Get localization manager\n */\n getLocalizationManager(): LocalizationManager {\n return this.localizationManager;\n }\n\n /**\n * Get organization manager\n */\n getOrganizationManager(): OrganizationConfigManager | undefined {\n return this.organizationManager;\n }\n\n /**\n * Apply configuration to DOM\n */\n applyToDOM(): void {\n this.themeManager.applyToDOM();\n this.appearanceManager.applyToDOM();\n\n // Apply locale direction\n const direction = this.localizationManager.getCurrentLocaleMetadata().direction;\n if (typeof document !== 'undefined') {\n document.documentElement.dir = direction;\n document.documentElement.lang = this.localizationManager.getCurrentLocale();\n }\n }\n\n /**\n * Generate complete CSS for server-side rendering\n */\n generateCSS(): string {\n let css = '';\n\n // Theme CSS\n css += this.themeManager.generateCSSVariables();\n css += '\\n';\n\n // Appearance CSS\n css += this.appearanceManager.generateCSS();\n css += '\\n';\n\n return css;\n }\n\n /**\n * Validate current configuration\n */\n validateConfig(): ConfigValidationResult {\n return validateFrankAuthConfig(this.config);\n }\n\n /**\n * Subscribe to configuration changes\n */\n subscribe(callback: (config: FrankAuthUIConfig) => void): () => void {\n this.listeners.add(callback);\n return () => {\n this.listeners.delete(callback);\n };\n }\n\n /**\n * Reset to default configuration\n */\n reset(): void {\n this.config = { ...DEFAULT_FRANK_AUTH_CONFIG } as any;\n\n this.themeManager.setTheme(this.config.theme || {});\n this.appearanceManager.updateConfig(this.config.appearance || {});\n this.localizationManager.updateConfig(this.config.localization || {});\n\n this.notifyListeners();\n }\n\n /**\n * Destroy and cleanup\n */\n destroy(): void {\n this.listeners.clear();\n }\n\n // Private methods\n\n private setupManagerListeners(): void {\n // Listen to theme changes\n this.themeManager.subscribe((theme) => {\n this.config.theme = theme;\n this.notifyListeners();\n });\n\n // Listen to appearance changes\n this.appearanceManager.subscribe((appearance) => {\n this.config.appearance = appearance;\n this.notifyListeners();\n });\n\n // Listen to localization changes\n this.localizationManager.subscribe((locale) => {\n if (this.config.localization) {\n this.config.localization.defaultLocale = locale;\n }\n this.notifyListeners();\n });\n }\n\n private applyInitialConfiguration(): void {\n // Apply organization branding if available\n if (this.config.organization?.settings.branding) {\n this.themeManager.applyBranding({\n logo: {\n url: this.config.organization.settings.branding.logo,\n alt: this.config.organization.name,\n },\n colors: {\n primary: this.config.organization.settings.branding.primaryColor || '#3b82f6',\n secondary: this.config.organization.settings.branding.secondaryColor || '#64748b',\n },\n fonts: {\n primary: 'Inter, ui-sans-serif, system-ui, sans-serif',\n },\n customCSS: this.config.organization.settings.branding.customCSS,\n });\n }\n\n // Apply to DOM if in browser environment\n if (typeof window !== 'undefined') {\n this.applyToDOM();\n }\n }\n\n private notifyListeners(): void {\n this.listeners.forEach(callback => callback(this.config));\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Create a complete Frank Auth configuration with validation\n */\nexport function createFrankAuthConfig(config: Partial<FrankAuthUIConfig>): FrankAuthUIConfig {\n const validate = validateFrankAuthConfig;\n\n // Validate configuration\n const validation = validate(config);\n if (!validation.isValid) {\n throw new Error(`Invalid configuration: ${validation.errors.map(e => e.message).join(', ')}`);\n }\n\n // Merge with defaults\n return { ...DEFAULT_FRANK_AUTH_CONFIG, ...config } as FrankAuthUIConfig;\n}\n\n/**\n * Create a configuration manager instance\n */\nexport function createConfigManager(config: Partial<FrankAuthUIConfig>): ConfigManager {\n return new ConfigManager(config);\n}\n\n/**\n * Create configuration from organization settings (useful for server-side setup)\n */\nexport function createConfigFromOrganization(\n publishableKey: string,\n userType: UserType,\n organizationSettings: any\n): FrankAuthUIConfig {\n const organization = transformOrganizationSettings(organizationSettings);\n\n return createFrankAuthConfig({\n publishableKey,\n userType,\n organization,\n });\n}\n\n/**\n * Merge multiple configuration objects with proper type safety\n */\nexport function mergeConfigs(...configs: Partial<FrankAuthUIConfig>[]): FrankAuthUIConfig {\n let merged = { ...DEFAULT_FRANK_AUTH_CONFIG };\n\n for (const config of configs) {\n merged = {\n ...merged,\n ...config,\n theme: { ...merged.theme, ...config.theme },\n appearance: {\n ...merged.appearance,\n ...config.appearance,\n layout: { ...merged.appearance?.layout, ...config.appearance?.layout },\n components: { ...merged.appearance?.components, ...config.appearance?.components },\n branding: { ...merged.appearance?.branding, ...config.appearance?.branding },\n },\n localization: { ...merged.localization, ...config.localization },\n organization: { ...merged.organization, ...config.organization },\n features: { ...merged.features, ...config.features },\n components: { ...merged.components, ...config.components },\n };\n }\n\n return merged as FrankAuthUIConfig;\n}\n\n/**\n * Create a configuration preset\n */\nexport function createConfigPreset(\n presetName: 'minimal' | 'enterprise' | 'b2b' | 'consumer',\n overrides?: Partial<FrankAuthUIConfig>\n): Partial<FrankAuthUIConfig> {\n const preset = CONFIG_PRESETS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset: ${presetName}`);\n }\n\n return overrides ? mergeConfigs(preset, overrides) : preset;\n}\n\n// ============================================================================\n// Re-export everything for convenience\n// ============================================================================\n\n// Export all types\nexport * from './types';\n\n// Export main manager as default\nexport { ConfigManager as default };"],"names":["ConfigManager","initialConfig","__publicField","DEFAULT_FRANK_AUTH_CONFIG","ThemeManager","AppearanceManager","LocalizationManager","OrganizationConfigManager","updates","organization","orgConfig","orgUIConfig","direction","css","validateFrankAuthConfig","callback","theme","appearance","locale","createFrankAuthConfig","config","validate","validation","e","createConfigManager","createConfigFromOrganization","publishableKey","userType","organizationSettings","transformOrganizationSettings","mergeConfigs","configs","merged","createConfigPreset","presetName","overrides","preset","CONFIG_PRESETS"],"mappings":"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"}