apphouse
Version:
Component library for React that uses observable state management and theme-able components.
152 lines (132 loc) • 3.69 kB
text/typescript
import { ThemeStyles, ThemeTokens } from '../styles/defaults/themes.interface';
import { Style } from './Style';
import { Token } from './Token';
import { getLookupTableForThisApp } from './Theme';
import { StyleUtils } from '../utils/style.utils';
import { THEMES } from './presets';
import { htmlTags } from './style.interface';
import { TOKEN_KEY_SEPARATOR, TokenType } from './token.interface';
export interface BaseThemeSettings {
tokens: Record<string, Token>;
styles: Record<string, Style>;
}
/**
* Get theme settings for this app
* @param theme
* @returns
*/
export const getDefaultThemeSettings = (
theme: 'dark' | 'light'
): BaseThemeSettings => {
let tokens = THEMES.APPHOUSE_DARK.tokens;
if (theme === 'light') {
tokens = THEMES.APPHOUSE_LIGHT.tokens;
}
return {
tokens: tokenize(tokens),
styles: parsetheme(theme)
};
};
/**
* Convert object to Record<string, Token>
* @param tokens ThemeTokens tokens in object format
* @returns Record<string, Token>
*/
export const tokenize = (tokens: ThemeTokens): Record<string, Token> => {
const hashedTokens: Record<string, Token> = {};
const getTokens = (dTokens: ThemeTokens) => {
Object.keys(dTokens).forEach((type: string) => {
//@ts-ignore
const tKeys = dTokens[type];
Object.keys(tKeys).forEach((key: string) => {
const hashedTokenId = `${type}${TOKEN_KEY_SEPARATOR}${key}`;
const tokn: TokenType = {
key,
value: tKeys[key],
type
};
hashedTokens[hashedTokenId] = new Token(tokn);
});
});
};
getTokens(tokens);
return hashedTokens;
};
const getPreviewWithTagFromKey = (key: string) => {
if (key.indexOf('custom') >= 0) {
return 'SearchInput';
}
if (key.indexOf('button') >= 0) {
return 'button';
}
if (key.indexOf('input') >= 0) {
return 'input';
}
if (key.indexOf('layout') >= 0) {
return 'div';
}
if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'].includes(key)) {
return 'p';
}
if (key.indexOf('typography') >= 0) {
return 'p';
}
if (key.indexOf('text') >= 0) {
return 'p';
}
if (key.indexOf('label') >= 0) {
return 'label';
}
if (htmlTags.find((tag) => tag.indexOf(key) >= 0)) {
return key;
} else {
return 'div';
}
};
/**
* Parse styles of this app
* @param theme
* @returns
*/
export const parsetheme = (theme: 'dark' | 'light'): Record<string, Style> => {
const hashedStyles: Record<string, Style> = {};
const getStyles = (styles: ThemeStyles) => {
styles &&
Object.keys(styles).forEach((key) => {
//@ts-ignore
const s = styles[key];
Object.keys(s).forEach((p) => {
const hashedStyleId = `${key}.${p}`;
let previewWithTag = getPreviewWithTagFromKey(key);
if (key === 'button' && p === 'select') {
previewWithTag = 'select';
}
if (key === 'input' && p === 'label') {
previewWithTag = 'label';
}
const namespace = `${key}${TOKEN_KEY_SEPARATOR}${p}`;
const value = StyleUtils.toCssPropertyStyle(
s[p],
getLookupTableForThisApp(),
namespace
);
const style = {
id: hashedStyleId,
value,
baseComponent: key,
variant: p,
state: 'active',
previewWithTag
};
hashedStyles[hashedStyleId] = new Style(style);
});
});
};
if (theme === 'light') {
getStyles(THEMES.APPHOUSE_LIGHT.styles);
}
if (theme === 'dark') {
getStyles(THEMES.APPHOUSE_DARK.styles);
}
return hashedStyles;
};