UNPKG

@whitemordred/react-native-bootstrap5

Version:

A complete React Native library that replicates Bootstrap 5.3 with 100% feature parity, full theming support, CSS variables, and dark/light mode

186 lines (185 loc) 9.39 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.useTheme = exports.BootstrapProvider = void 0; const react_1 = __importStar(require("react")); const react_native_1 = require("react-native"); const defaultTheme_1 = require("./defaultTheme"); const themeUtils_1 = require("./themeUtils"); const ThemeContext = (0, react_1.createContext)(undefined); const BootstrapProvider = ({ children, theme: customTheme, mode: initialMode, followSystemTheme = true, enableAnimations = true, persistTheme = true, }) => { const [mode, setModeState] = (0, react_1.useState)('light'); const [isLoading, setIsLoading] = (0, react_1.useState)(true); const [preferences, setPreferences] = (0, react_1.useState)(null); const [isFollowingSystem, setIsFollowingSystem] = (0, react_1.useState)(followSystemTheme); const [systemTheme, setSystemTheme] = (0, react_1.useState)(() => { if (react_native_1.Platform.OS === 'web') { return themeUtils_1.SystemTheme.getSystemTheme(); } return react_native_1.Appearance.getColorScheme() === 'dark' ? 'dark' : 'light'; }); const initialized = (0, react_1.useRef)(false); // Merge custom theme with default theme const theme = react_1.default.useMemo(() => { var _a, _b, _c; if (!customTheme) return defaultTheme_1.defaultTheme; return Object.assign(Object.assign(Object.assign({}, defaultTheme_1.defaultTheme), customTheme), { colors: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.colors), customTheme.colors), darkColors: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.darkColors), customTheme.darkColors), spacing: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.spacing), customTheme.spacing), typography: Object.assign(Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.typography), customTheme.typography), { fontSizes: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.typography.fontSizes), (_a = customTheme.typography) === null || _a === void 0 ? void 0 : _a.fontSizes), fontWeights: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.typography.fontWeights), (_b = customTheme.typography) === null || _b === void 0 ? void 0 : _b.fontWeights), lineHeights: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.typography.lineHeights), (_c = customTheme.typography) === null || _c === void 0 ? void 0 : _c.lineHeights) }), borderRadius: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.borderRadius), customTheme.borderRadius), shadows: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.shadows), customTheme.shadows), breakpoints: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.breakpoints), customTheme.breakpoints), zIndex: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.zIndex), customTheme.zIndex), animation: Object.assign(Object.assign({}, defaultTheme_1.defaultTheme.animation), customTheme.animation) }); }, [customTheme]); // Get current colors based on mode const currentColors = react_1.default.useMemo(() => { return mode === 'dark' ? theme.darkColors : theme.colors; }, [theme, mode]); // Initialize theme system (0, react_1.useEffect)(() => { if (initialized.current) return; initialized.current = true; const initializeTheme = async () => { try { // Initialize theme manager let finalMode = mode; if (persistTheme) { const savedMode = await themeUtils_1.ThemeStorage.loadThemeMode(); const savedPreferences = await themeUtils_1.ThemeStorage.loadPreferences(); if (savedMode) { finalMode = savedMode; } else if (followSystemTheme && !initialMode) { finalMode = systemTheme; } else if (initialMode) { finalMode = initialMode; } setPreferences(savedPreferences); } else if (initialMode) { finalMode = initialMode; } else if (followSystemTheme) { finalMode = systemTheme; } // Initialize theme manager await themeUtils_1.ThemeManager.initialize(followSystemTheme); themeUtils_1.ThemeManager.setMode(finalMode, persistTheme); setModeState(finalMode); setIsFollowingSystem(themeUtils_1.ThemeManager.isFollowingSystem()); // Apply animations preferences if (enableAnimations) { themeUtils_1.ThemeAnimationUtils.respectReducedMotion(); } } catch (error) { console.warn('Failed to initialize theme:', error); } finally { setIsLoading(false); } }; initializeTheme(); }, []); // Listen to theme manager changes (0, react_1.useEffect)(() => { const removeListener = themeUtils_1.ThemeManager.addListener((newMode) => { setModeState(newMode); setIsFollowingSystem(themeUtils_1.ThemeManager.isFollowingSystem()); }); return removeListener; }, []); // Listen to system theme changes (React Native) (0, react_1.useEffect)(() => { if (react_native_1.Platform.OS !== 'web') { const subscription = react_native_1.Appearance.addChangeListener((preferences) => { const newSystemTheme = preferences.colorScheme === 'dark' ? 'dark' : 'light'; setSystemTheme(newSystemTheme); if (isFollowingSystem && followSystemTheme) { themeUtils_1.ThemeManager.setMode(newSystemTheme, false); } }); return () => subscription === null || subscription === void 0 ? void 0 : subscription.remove(); } return undefined; }, [isFollowingSystem, followSystemTheme]); // Listen to system theme changes (Web) (0, react_1.useEffect)(() => { if (react_native_1.Platform.OS === 'web') { const removeListener = themeUtils_1.SystemTheme.addSystemThemeListener((newSystemTheme) => { setSystemTheme(newSystemTheme); if (isFollowingSystem && followSystemTheme) { themeUtils_1.ThemeManager.setMode(newSystemTheme, false); } }); return removeListener || undefined; } return undefined; }, [isFollowingSystem, followSystemTheme]); // Enhanced setMode function const setMode = react_1.default.useCallback(async (newMode) => { if (enableAnimations) { themeUtils_1.ThemeAnimationUtils.createThemeTransition(); } await themeUtils_1.ThemeManager.setMode(newMode, persistTheme); }, [enableAnimations, persistTheme]); // Enhanced toggle function const toggleMode = react_1.default.useCallback(async () => { if (enableAnimations) { themeUtils_1.ThemeAnimationUtils.createThemeTransition(); } await themeUtils_1.ThemeManager.toggleMode(); }, [enableAnimations]); const contextValue = { theme, mode, setMode, toggleMode, currentColors, isLoading, preferences, isFollowingSystem, systemTheme, }; return (<ThemeContext.Provider value={contextValue}> {children} </ThemeContext.Provider>); }; exports.BootstrapProvider = BootstrapProvider; const useTheme = () => { const context = (0, react_1.useContext)(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a BootstrapProvider'); } return context; }; exports.useTheme = useTheme;