@unicity/design-system
Version: 
A comprehensive React component library built on Material-UI with advanced theming capabilities including neumorphism design support
367 lines • 11.3 kB
JavaScript
/**
 * Theme Settings Utilities
 * Handles theme settings management, font scaling, and local storage
 */
// Font size scale mappings
export const FONT_SIZE_SCALES = {
    'small': 0.875, // 14px base
    'medium': 1, // 16px base (default)
    'large': 1.125, // 18px base
    'extra-large': 1.25, // 20px base
};
// Content density scale mappings
export const CONTENT_DENSITY_SCALES = {
    'compact': { spacing: 0.75, padding: 0.75 }, // 25% less space
    'comfortable': { spacing: 1, padding: 1 }, // Default
    'spacious': { spacing: 1.5, padding: 1.25 }, // 50% more spacing, 25% more padding
};
// Touch target size mappings
export const TOUCH_TARGET_SCALES = {
    'standard': 1, // 44px minimum (WCAG AA)
    'large': 1.25, // 55px (better for motor disabilities)
    'extra-large': 1.5, // 66px (best accessibility)
};
/**
 * System theme detection utilities
 */
export const SystemThemeUtils = {
    /**
     * Detect if user prefers dark mode from system settings
     */
    getSystemThemePreference: () => {
        if (typeof window === 'undefined')
            return 'light';
        return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    },
    /**
     * Listen for system theme changes
     */
    addSystemThemeListener: (callback) => {
        if (typeof window === 'undefined')
            return () => { };
        const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
        const listener = (e) => callback(e.matches);
        mediaQuery.addEventListener('change', listener);
        return () => mediaQuery.removeEventListener('change', listener);
    },
    /**
     * Resolve auto mode to actual theme mode
     */
    resolveAutoMode: (mode) => {
        if (mode === 'auto') {
            return SystemThemeUtils.getSystemThemePreference();
        }
        return mode;
    },
};
// Default settings
export const DEFAULT_THEME_SETTINGS = {
    mode: 'auto',
    accessibilityMode: 'default',
    fontSize: {
        level: 'medium',
        scale: FONT_SIZE_SCALES.medium,
    },
    contentDensity: {
        density: 'comfortable',
        spacing: CONTENT_DENSITY_SCALES.comfortable.spacing,
        padding: CONTENT_DENSITY_SCALES.comfortable.padding,
        touchTargetSize: 'standard',
    },
    motion: {
        reduceMotion: false,
        animationSpeed: 'normal',
        autoPlay: true,
    },
    focusNavigation: {
        showFocusRings: true,
        enhancedKeyboardNav: false,
        skipLinks: false,
        focusTimeout: 0,
    },
    reading: {
        readingMode: false,
        lineHeight: 1.5,
        letterSpacing: 0,
        wordSpacing: 0,
        readingGuide: false,
    },
    colorVisibility: {
        highContrast: false,
        colorBlindSupport: 'none',
        saturation: 1,
        brightness: 1,
    },
    audioAlerts: {
        soundEnabled: true,
        volume: 0.5,
        visualAlerts: false,
        vibration: false,
    },
};
// Local storage keys
const STORAGE_KEYS = {
    THEME_SETTINGS: 'unicity-theme-settings',
    LEGACY_THEME: 'unicity-theme', // For backward compatibility
};
/**
 * Font size utility functions
 */
export const FontSizeUtils = {
    /**
     * Get font size settings from level
     */
    getSettingsFromLevel: (level) => ({
        level,
        scale: FONT_SIZE_SCALES[level],
    }),
    /**
     * Get the next font size level
     */
    getNextLevel: (currentLevel) => {
        const levels = ['small', 'medium', 'large', 'extra-large'];
        const currentIndex = levels.indexOf(currentLevel);
        const nextIndex = Math.min(currentIndex + 1, levels.length - 1);
        return levels[nextIndex];
    },
    /**
     * Get the previous font size level
     */
    getPreviousLevel: (currentLevel) => {
        const levels = ['small', 'medium', 'large', 'extra-large'];
        const currentIndex = levels.indexOf(currentLevel);
        const prevIndex = Math.max(currentIndex - 1, 0);
        return levels[prevIndex];
    },
    /**
     * Get level index for slider (0-3)
     */
    getLevelIndex: (level) => {
        const levels = ['small', 'medium', 'large', 'extra-large'];
        return levels.indexOf(level);
    },
    /**
     * Get level from slider index (0-3)
     */
    getLevelFromIndex: (index) => {
        const levels = ['small', 'medium', 'large', 'extra-large'];
        return levels[Math.max(0, Math.min(index, levels.length - 1))];
    },
    /**
     * Apply font scale to CSS-in-JS styles
     */
    scaleFont: (baseSize, scale) => {
        return baseSize * scale;
    },
};
/**
 * Content density utility functions
 */
export const ContentDensityUtils = {
    /**
     * Get content density settings from density level
     */
    getSettingsFromDensity: (density, touchTargetSize = 'standard') => ({
        density,
        spacing: CONTENT_DENSITY_SCALES[density].spacing,
        padding: CONTENT_DENSITY_SCALES[density].padding,
        touchTargetSize,
    }),
    /**
     * Get density index for slider (0-2)
     */
    getDensityIndex: (density) => {
        const densities = ['compact', 'comfortable', 'spacious'];
        return densities.indexOf(density);
    },
    /**
     * Get density from slider index (0-2)
     */
    getDensityFromIndex: (index) => {
        const densities = ['compact', 'comfortable', 'spacious'];
        return densities[Math.max(0, Math.min(index, densities.length - 1))];
    },
    /**
     * Get touch target size index for slider (0-2)
     */
    getTouchTargetIndex: (size) => {
        const sizes = ['standard', 'large', 'extra-large'];
        return sizes.indexOf(size);
    },
    /**
     * Get touch target size from slider index (0-2)
     */
    getTouchTargetFromIndex: (index) => {
        const sizes = ['standard', 'large', 'extra-large'];
        return sizes[Math.max(0, Math.min(index, sizes.length - 1))];
    },
    /**
     * Apply spacing scale to CSS values
     */
    scaleSpacing: (baseSpacing, scale) => {
        return baseSpacing * scale;
    },
    /**
     * Apply padding scale to CSS values
     */
    scalePadding: (basePadding, scale) => {
        return basePadding * scale;
    },
    /**
     * Get minimum touch target size in pixels
     */
    getTouchTargetSize: (size) => {
        return 44 * TOUCH_TARGET_SCALES[size]; // Base 44px (WCAG AA minimum)
    },
};
/**
 * Local storage management
 */
export const ThemeStorageUtils = {
    /**
     * Get stored theme settings
     */
    getStoredSettings: () => {
        if (typeof window === 'undefined') {
            return DEFAULT_THEME_SETTINGS;
        }
        try {
            // Try new settings format first
            const stored = localStorage.getItem(STORAGE_KEYS.THEME_SETTINGS);
            if (stored) {
                const parsed = JSON.parse(stored);
                const result = {
                    ...DEFAULT_THEME_SETTINGS,
                    ...parsed,
                    fontSize: {
                        ...DEFAULT_THEME_SETTINGS.fontSize,
                        ...(parsed.fontSize || {}),
                    },
                    contentDensity: {
                        ...DEFAULT_THEME_SETTINGS.contentDensity,
                        ...(parsed.contentDensity || {}),
                    },
                    motion: {
                        ...DEFAULT_THEME_SETTINGS.motion,
                        ...(parsed.motion || {}),
                    },
                    focusNavigation: {
                        ...DEFAULT_THEME_SETTINGS.focusNavigation,
                        ...(parsed.focusNavigation || {}),
                    },
                    reading: {
                        ...DEFAULT_THEME_SETTINGS.reading,
                        ...(parsed.reading || {}),
                    },
                    colorVisibility: {
                        ...DEFAULT_THEME_SETTINGS.colorVisibility,
                        ...(parsed.colorVisibility || {}),
                    },
                    audioAlerts: {
                        ...DEFAULT_THEME_SETTINGS.audioAlerts,
                        ...(parsed.audioAlerts || {}),
                    },
                };
                return result;
            }
            // Fall back to legacy theme mode only
            const legacyTheme = localStorage.getItem(STORAGE_KEYS.LEGACY_THEME);
            if (legacyTheme && ['light', 'dark', 'neumorphism-light', 'neumorphism-dark', 'auto'].includes(legacyTheme)) {
                return {
                    ...DEFAULT_THEME_SETTINGS,
                    mode: legacyTheme,
                };
            }
        }
        catch (error) {
            console.warn('Failed to parse stored theme settings:', error);
        }
        return DEFAULT_THEME_SETTINGS;
    },
    /**
     * Store theme settings
     */
    setStoredSettings: (settings) => {
        if (typeof window === 'undefined')
            return;
        try {
            localStorage.setItem(STORAGE_KEYS.THEME_SETTINGS, JSON.stringify(settings));
            // Also update legacy key for backward compatibility
            localStorage.setItem(STORAGE_KEYS.LEGACY_THEME, settings.mode);
        }
        catch (error) {
            console.warn('Failed to store theme settings:', error);
        }
    },
    /**
     * Clear stored settings
     */
    clearStoredSettings: () => {
        if (typeof window === 'undefined')
            return;
        try {
            localStorage.removeItem(STORAGE_KEYS.THEME_SETTINGS);
            localStorage.removeItem(STORAGE_KEYS.LEGACY_THEME);
        }
        catch (error) {
            console.warn('Failed to clear stored theme settings:', error);
        }
    },
};
/**
 * High contrast utilities
 */
export const AccessibilityUtils = {
    /**
     * Get high contrast color overrides
     */
    getHighContrastOverrides: (baseMode) => {
        if (baseMode === 'dark') {
            return {
                background: {
                    default: '#000000',
                    paper: '#1a1a1a',
                    paper2: '#2d2d2d',
                },
                text: {
                    primary: '#ffffff',
                    secondary: '#cccccc',
                },
                primary: {
                    main: '#ffffff',
                    contrastText: '#000000',
                },
                secondary: {
                    main: '#ffff00',
                    contrastText: '#000000',
                },
            };
        }
        return {
            background: {
                default: '#ffffff',
                paper: '#ffffff',
                paper2: '#f8f8f8',
            },
            text: {
                primary: '#000000',
                secondary: '#333333',
            },
            primary: {
                main: '#000000',
                contrastText: '#ffffff',
            },
            secondary: {
                main: '#0000ff',
                contrastText: '#ffffff',
            },
        };
    },
    /**
     * Check if high contrast mode is enabled
     */
    isHighContrast: (mode) => {
        return mode === 'high-contrast';
    },
};
//# sourceMappingURL=themeSettings.js.map