import { useContext } from "react"; import { type ThemeContextStateType, type GapPropagationType, type ThemeContextType, type SharpnessType, type ThemesType } from "../types"; import NCoreContext, { type ConfigType } from "ncore-context"; import { mergeTypographyTokens, mergePalettes, mergeShapes } from "../helpers"; import _defaultPaletteData from "../variants/themes/default.json"; import { androidTypographyFixer } from "../utils"; const defaultPaletteData = androidTypographyFixer(_defaultPaletteData); class NCoreUIKitTheme extends NCoreContext> { projectThemes?: NCoreUIKit.Palette = defaultPaletteData; useContext = ({ gapPropagation, paletteKey, sharpness, themeKey }: { paletteKey?: keyof NCoreUIKit.PaletteKey; themeKey?: keyof NCoreUIKit.ThemeKey; gapPropagation?: GapPropagationType; sharpness?: SharpnessType; } = {}): ThemeContextType => { const currentState = useContext(this.stateContext); if( gapPropagation || paletteKey || sharpness || themeKey ) { const activeState = this.prepare({ activeGapPropagation: gapPropagation ? gapPropagation : currentState.activeGapPropagation, activeSharpness: sharpness ? sharpness : currentState.activeSharpness, activePalette: paletteKey ? paletteKey : currentState.activePalette, activeTheme: themeKey ? themeKey : currentState.activeTheme }); return { ...currentState, ...activeState }; } return currentState; }; constructor(initialState: T) { const { projectThemes, initialSelectedActiveSharpness, initialSelectedGapPropagation, initialSelectedPalette, initialSelectedTheme } = initialState; const initialPalette = defaultPaletteData.palettes.find(p => p.name === "nibgat"); if(!initialPalette) { throw new Error("Initial Theme error!."); } const initialTheme = initialPalette.themes[initialSelectedTheme as keyof typeof initialPalette.themes]; super({ activeGapPropagation: initialSelectedGapPropagation ?? "compact", activeSharpness: initialSelectedActiveSharpness ?? "soft", inlineSpaces: defaultPaletteData.shapes.inlineSpaces, typography: defaultPaletteData.typography.spacious, radiuses: defaultPaletteData.shapes.radiuses.soft, spaces: defaultPaletteData.shapes.spaces.spacious, activePalette: initialSelectedPalette ?? "nibgat", activeTheme: initialSelectedTheme ?? "dark", borders: defaultPaletteData.shapes.borders, colors: initialTheme }, { key: "NCoreUIKitTheme" }); this.projectThemes = projectThemes; const activeState = this.prepare({ activeGapPropagation: initialSelectedGapPropagation ?? "compact", activeSharpness: initialSelectedActiveSharpness ?? "soft", activePalette: initialSelectedPalette ?? "nibgat", activeTheme: initialSelectedTheme ?? "dark" }); this.state = activeState as ThemeContextType; } prepare = (props?: { activePalette?: keyof NCoreUIKit.PaletteKey; activeGapPropagation?: GapPropagationType; activeTheme?: keyof NCoreUIKit.ThemeKey; activeSharpness?: SharpnessType; }): ThemeContextStateType => { const gapPropagation = props && props.activeGapPropagation ? props.activeGapPropagation : this.state.activeGapPropagation; const sharpness = props && props.activeSharpness ? props.activeSharpness : this.state.activeSharpness; const palette = props && props.activePalette ? props.activePalette : this.state.activePalette; const theme = props && props.activeTheme ? props.activeTheme : this.state.activeTheme; const defaultPalette = defaultPaletteData.palettes.find(p => p.name === palette) ?? defaultPaletteData.palettes[0]!; const defaultTheme = defaultPalette.themes[theme as keyof typeof defaultPalette.themes] ?? defaultPalette.themes.dark; const defaultState: ThemeContextStateType = { typography: defaultPaletteData.typography[gapPropagation], spaces: defaultPaletteData.shapes.spaces[gapPropagation], radiuses: defaultPaletteData.shapes.radiuses[sharpness], inlineSpaces: defaultPaletteData.shapes.inlineSpaces, borders: defaultPaletteData.shapes.borders, activeGapPropagation: gapPropagation, activeSharpness: sharpness, activePalette: palette, colors: defaultTheme, activeTheme: theme }; if(!this.projectThemes || (this.projectThemes && !this.projectThemes.palettes.length)) { return defaultState; } const currentProjectPalette = this.projectThemes.palettes.find(p => p.name === palette); if(!currentProjectPalette) { return defaultState; } const currentProjectTheme = currentProjectPalette.themes[theme]; if(!currentProjectTheme) { return defaultState; } const shapes = mergeShapes({ projectShapes: this.projectThemes.shapes, defaultShapes: defaultPaletteData.shapes }); const typography = mergeTypographyTokens({ defaultTypographyTokens: defaultPaletteData.typography, projectTypographyTokens: this.projectThemes.typography }); const colors = mergePalettes( defaultPaletteData.palettes, this.projectThemes.palettes, palette, theme ); const newState: ThemeContextStateType = { typography: typography[gapPropagation], spaces: shapes.spaces[gapPropagation], activeGapPropagation: gapPropagation, radiuses: shapes.radiuses[sharpness], inlineSpaces: shapes.inlineSpaces, activeSharpness: sharpness, borders: shapes.borders, activePalette: palette, activeTheme: theme, colors: colors }; return newState; }; switch = ({ gapPropagation, paletteKey, sharpness, themeKey }: { paletteKey?: keyof NCoreUIKit.PaletteKey; themeKey?: keyof NCoreUIKit.ThemeKey; gapPropagation?: GapPropagationType; sharpness?: SharpnessType; }) => { const activeState = this.prepare({ activeGapPropagation: gapPropagation ?? this.state.activeGapPropagation, activeSharpness: sharpness ?? this.state.activeSharpness, activePalette: paletteKey ?? this.state.activePalette, activeTheme: themeKey ?? this.state.activeTheme }); this.setState(activeState); }; updateProjectTheme = (newProjectThemes: NCoreUIKit.Palette, newState?: { activePalette?: keyof NCoreUIKit.PaletteKey; activeGapPropagation?: GapPropagationType; activeTheme?: keyof NCoreUIKit.ThemeKey; activeSharpness?: SharpnessType; }) => { this.projectThemes = newProjectThemes; const activeState = this.prepare(newState); this.setState(activeState); }; } export default NCoreUIKitTheme;