import merge from 'lodash.merge' import { betweenMediaWidthTemplates as betweenMediaWidth, fromMediaWidthTemplates as fromMediaWidth, mediaHeightTemplates as mediaHeight, mediaWidthTemplates as mediaWidth } from './styles/mediaQueries' import { ThemeTemplates } from './templates' import { BaseTheme } from './templates/base' import { AvailableThemeTemplate, BasicUserTheme, CustomThemeOrTemplate, Subset, ThemeByModes, ThemeMinimumRequired } from './types' interface CreateTheme { new ( args: T extends ThemeByModes ? T : K extends AvailableThemeTemplate ? never : ThemeMinimumRequired ): CustomThemeOrTemplate } /** * CreateTheme constructor function * Function REQUIRES at _least_ a theme Interface OR a template name as defined by the @type {ThemeTemplateKey} * @example * const SkillForgeTheme = CreateTheme() * const skilltreeTheme = new SkillForgeTheme() * skilltreeTheme.saltySwamys // <-- exists * @returns Constructed theme object consisting of the required parts + optionals */ function CreateTheme(): CreateTheme { return class { /* * MEDIA QUERIES */ mediaWidth = mediaWidth mediaHeight = mediaHeight fromMediaWidth = fromMediaWidth betweenMediaWidth = betweenMediaWidth constructor(args: T extends ThemeByModes ? T : K extends AvailableThemeTemplate ? never : ThemeMinimumRequired) { Object.assign(this, args) } } as CreateTheme } /** * createCustomTheme - create a "DefaultTheme" type + realdata object (TM) and pass to the creator fn * @example export const CUSTOM_THEME = { modes: { DEFAULT: { socks: { size: '200rem', colour: 'red', importanceColour: 'carrot' }, cartoons: { watchedColor: '#1234', soldColor: 'rgba(0,2,5,0.24)' } }, DARK: { // ... theme }, // ... rest theme mdoes } } as const type CustomTheme = typeof CUSTOM_THEME.modes.DEFAULT declare module 'styled-components' { export interface DefaultTheme extends ThemeBaseRequired, CustomTheme {} } const customTheme = createCustomTheme(CUSTOM_THEME) customTheme.cartoons.soldColor // <-- rgba(0,2,5,0.24) customTheme.mediaWidth.upToExtraLarge // <-- mediaWidth fn */ export function createCustomTheme( theme: T ): CustomThemeOrTemplate { const CustomThemeCreator = CreateTheme() const auxTheme = { ...BaseTheme, ...theme } as T extends ThemeByModes ? ThemeMinimumRequired & T : ThemeMinimumRequired return new CustomThemeCreator(auxTheme) } /** * createTemplateThemeFactory * @description Accepts a "themeTemplates" object which contains key/value pairs of theme names to themes * @example const appThemeCreators = createTemplateThemeFactory({ SALTY_BOI: { modes: { DEFAULT: { saltinessColour: 'pink', ...themeStuff }, DARK: { ...darkThemeStuff }, LIGHT: {} } } }) const saltyTheme = appThemeCreators("SALTY_BOI") saltyTheme.modes.DEFAULT.saltinessColour // string * @param templates * @returns */ export const createTemplateThemeFactory = (templates: TE) => function createTemplateTheme>(template: K, extension?: E) { const theme = templates[template] // if extension passed, deep merge // and set type accordingly if (extension) { const mergedThemeModes = merge({}, theme.modes, extension) theme.modes = mergedThemeModes } return createCustomTheme( theme as TE[K] & { modes: | ({ DEFAULT: BasicUserTheme } & { LIGHT: Subset DARK: Subset } & E) | undefined } ) } // Export pre-created PASTELLE (shop-ui) and SKILLFORGE (skilltree-ui) themes as syntactic sugar export const createPast3lleTemplateTheme = createTemplateThemeFactory(ThemeTemplates)