UNPKG

apphouse

Version:

Component library for React that uses observable state management and theme-able components.

269 lines (244 loc) 7.09 kB
import { values } from '../../utils/obj/values'; import { isObject } from '../../utils/obj/isObject'; import { isEmpty } from '../../utils/obj/isEmpty'; import { Palette } from '../Palette'; import { Token } from '../Token'; import { ensureAllLowerCase } from './string.utils'; import ColorUtils from './color.utils'; import { ThemeTokens } from '../../styles/defaults/themes.interface'; import { ColorType } from './color.interface'; import { COLOR, StyleTokenReference, TOKEN } from '../style.interface'; import { TOKEN_KEY_SEPARATOR } from '../token.interface'; import { ThemeModeType } from '../palette.interface'; /** * Convert Tokens [Record<string, Token>] into object * @param value Record<string, Token> Tokens to be transformed * @returns object */ export const toTokensObject = (value: Record<string, Token>): object => { // TODO: update from any to ThemeTokens const obj: any = {}; values(value).forEach((token) => { if (!obj[token.type]) { obj[token.type] = {}; } if (!obj[token.type][token.key]) { obj[token.type][token.key] = token.value; } }); return obj; }; /** * Convert Tokens [Record<string, Token>] into Themes Things Tokens * @param value Record<string, Token> Tokens to be transformed * @returns object */ export const toApphouseTokens = (value: Record<string, Token>): ThemeTokens => { // TODO: update from any to ThemeTokens const obj: any = toTokensObject(value); return obj as ThemeTokens; }; const toUpperCaseifHex = (value: any) => { if (typeof value === 'string') { if (value.startsWith('#')) { return value.toLocaleUpperCase(); } } return value; }; /** * Find the first match for this value in the lookup table * @param value string value to be matched * @param lookup lookup table * @param namespace string if namespace is provided it will help * finding a value when there are multiple keys with the same value * in the lookup table * @returns */ export const getValueReferenceStringFromObject = ( value: string | number, lookup: { [value: string]: string }, namespace?: string ) => { let v = toUpperCaseifHex(value); const hasLookupValues = !isEmpty(lookup); if (!hasLookupValues) { return v; } if (hasLookupValues) { let found = v; Object.keys(lookup).forEach((key) => { if (namespace) { if (key.includes(namespace)) { if (toUpperCaseifHex(lookup[key]) === v) { found = key; return; } } } if (toUpperCaseifHex(lookup[key]) === v) { found = key; return; } }); return found; } }; /** * The reference here is key colors.onBase * @param obj object, usually referring to styles or tokens */ export const getReferenceTokenFromObject = ( obj: object, path?: string ): StyleTokenReference | undefined => { const keys = Object.keys(obj); if (keys.length > 1) { console.warn('only one key can be referenced at a time'); return undefined; } if (keys.length === 1) { const key = keys[0]; const value = Object.values(obj)[0]; const k = path ? `${path}.${key}` : key; const reference: StyleTokenReference | undefined = { type: getStyleTokenReferenceType(key), value: value, key: k }; return reference; } console.warn('no key was found in this object'); return undefined; }; /** * Discover is a key has the word 'color' in it * @param key string * @returns if the key contains 'color' it will return true, otherwise it will be false */ export const hasColorReference = (key: string): boolean => { return ( `${key}`.toLocaleLowerCase().indexOf('color') >= 0 || `${key}`.toLocaleLowerCase().indexOf('theme') >= 0 ); }; /** * * @param key string * @returns if the key contains 'color' it will return PALETTE, otherwise it will be TOKEN */ export const getStyleTokenReferenceType = (key: string): 'color' | 'token' => { return hasColorReference(key) ? COLOR : TOKEN; }; /** * Create lookup table for value reference * It only keeps unique objects * @param obj * @param root * @param lookup * @returns */ export const getLookupTable = ( obj: { [id: string]: any; }, lookup: { [id: string]: string } = {}, root?: string ): { [id: string]: string } => { const lookupCopy = lookup; if (!obj) { return {}; } Object.keys(obj).map((key) => { const value = obj[key]; const id = root ? `${root}.${key}` : key; // only create lookup values for unique values if (!isObject(value)) { if (!lookupCopy[id]) { lookupCopy[id] = value; } else { delete lookupCopy[id]; } } else { return getLookupTable(value, lookupCopy, id); } }); return lookupCopy; }; export const getTokenListId = (token: any) => { const type = token?.type; const key = token?.key; if (type && key && typeof key === 'string' && typeof type === 'string') { const nKey = ensureAllLowerCase(key).trim(); const ntype = type.trim(); return `${ntype}${TOKEN_KEY_SEPARATOR}${nKey}`.trim(); } console.warn('token is not valid when trying to get token list id'); return 'unknownTokenId'; }; export const getColorTokensLookupReferenceFromPalettes = ( palette: Record<string, Palette>, basePaletteId: string, colorPaletteId?: string | undefined ): { [id: string]: string } => { let baseColorsLookup; if (palette[basePaletteId]) { const baseColors = palette[basePaletteId].objectify.colors; baseColorsLookup = getLookupTableFromColorType( baseColors || [], palette[basePaletteId].mode ); } if (!colorPaletteId && baseColorsLookup) { return baseColorsLookup; } if (colorPaletteId) { if (palette[colorPaletteId] && palette[colorPaletteId].mode === 'theme') { const colors = palette[colorPaletteId].objectify.colors; const colorsLookup = getLookupTableFromColorType( colors || [], palette[colorPaletteId].mode, colorPaletteId ); return colorsLookup; } } return {}; }; export const getLookupTableFromColorType = ( colors: ColorType[], mode: ThemeModeType, paletteId?: string ) => { const lookup: { [id: string]: string } = {}; colors.forEach((color) => { if (!color) { return; } const id = paletteId ? `${mode}.${paletteId}.${color.id}` : `${mode}.${color.id}`; const hex = color.color.hex; if (!lookup[id]) { lookup[id] = hex; } const rgbaString = ColorUtils.toRgbaStringFromRgbaObject(color.color.rgb); if (rgbaString && !lookup[rgbaString]) { lookup[id] = rgbaString; } }); return lookup; }; export interface hashedObjectReturnType { lookup: { [id: string]: any }; hashedObject: { [id: string]: any }; } // Letter spacing export const toRemsLetterSpacing = (value: string | number): string => { return `${value}rem`; }; export const toEmLetterSpacing = () => { return 'em'; }; // eslint-disable-next-line @typescript-eslint/no-empty-function export const toPtLettersSpacing = () => {};