UNPKG

apphouse

Version:

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

286 lines (261 loc) 7.83 kB
import { toCSS, toJSON } from 'cssjson'; import { camelcaseify } from '../themes/utils/string.utils'; import { CSSProperties } from 'glamor'; import { camelcaseifyCssProperty } from '../themes/utils/styles.utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires // const beautify_css = require("js-beautify").css; import { css } from 'js-beautify'; const beautify_css = css; /** * Helper function to determine if a property key is a selector * @param styleKey * @returns */ export const isSelector = (property: string): boolean => { const selectorPrefixes = [':', '&:', '>', '.', '::', '@']; const found = selectorPrefixes.find((prefix) => property.startsWith(prefix)); return found !== undefined; }; export default class CSS { static parseCss = (css: string): object => { const cssObj: any = toJSON(css); const allStyles: { [selector: string]: CSSProperties } = {}; const parseChildren = (children: any) => { Object.keys(children).forEach((cssSelectorString) => { const styles = children[cssSelectorString].attributes; if (!styles) { parseChildren(children.children); } else { allStyles[cssSelectorString] = styles; } }); }; parseChildren(cssObj.children); return allStyles; }; static toJSONAttributes(cssString: string): object { return toJSON(cssString); } static getCssObjectWithCamelcaseProperties(values: any): object { const _values: any = {}; Object.keys(values).forEach((k) => { const _nKey = camelcaseify(k); _values[_nKey] = values[k]; }); return _values; } static getCssObjectWithDashedProperties(values: { [id: string]: any; }): object { const _values: any = {}; Object.keys(values).forEach((k) => { const _nKey = CSS.camelcaseToDashed(k); _values[_nKey] = values[k]; }); return _values; } static isMediaQuery(value: string): boolean { return value.startsWith('@media'); } static getSelectorValues(cssString: string): object { const json: any = CSS.parseCss(cssString); const _values: any = {}; Object.keys(json).forEach((key) => { const values = json[key]; const appentToRoot = () => { if (_values['root']) { _values['root'] = { ..._values['root'], ...CSS.getCssObjectWithCamelcaseProperties(values) }; } else { _values['root'] = CSS.getCssObjectWithCamelcaseProperties(values); } }; if (isSelector(key)) { let k = key; if (!CSS.isMediaQuery(key)) { const marker = '********'; const selectorKey = key.replace(':', marker); k = selectorKey.split(marker)[1]; } if (k !== undefined && !CSS.isMediaQuery(key)) { _values[`:${k}`] = CSS.getCssObjectWithCamelcaseProperties(values); } else if (CSS.isMediaQuery(key)) { _values[k] = CSS.getCssObjectWithCamelcaseProperties(values); } else { if (_values['root']) { _values['root'] = { ..._values['root'], ...CSS.getCssObjectWithCamelcaseProperties(values) }; } else { appentToRoot(); } } } else { appentToRoot(); } }); return _values; } static toCssInJs(cssString: string): object { const json: any = CSS.getSelectorValues(cssString); let cssInJs = {}; if (json.root) { cssInJs = json.root; } Object.keys(json).forEach((key) => { if (key !== 'root') { //@ts-ignore cssInJs[key] = json[key]; } }); return cssInJs; } static toCssInJsPrettified(value: string): string { const css = CSS.toCssInJs(value); const result2 = CSS.prettify(JSON.stringify(css)); return result2; } static toCssInJs2Prettified(value: string): string { const css = CSS.toCssInJs(value); const result = CSS.prettify(toCSS(css)); return result; } static fromCssInJsToJSONAttributes(value: { [id: string]: object | string; }): object { const tempSelector = '.container'; const jsonInAttributes: any = { children: {}, attributes: {} }; let json: any = { children: {}, attributes: {} }; Object.keys(value).forEach((key) => { let id = tempSelector; if (isSelector(key) && !CSS.isMediaQuery(key)) { id = `${tempSelector}${key}`; } else if (CSS.isMediaQuery(key)) { id = key; } const styles = value[key]; if (typeof styles === 'object') { // ONLY ACCEPTS ONE LEVEL if (CSS.isMediaQuery(key)) { jsonInAttributes.children[id] = { attributes: {}, children: { [tempSelector]: { //@ts-ignore attributes: CSS.getCssObjectWithDashedProperties(value[key]), children: {} } } }; } else { jsonInAttributes.children[id] = { children: {}, //@ts-ignore attributes: CSS.getCssObjectWithDashedProperties(value[key]) }; } } else { const id = CSS.camelcaseToDashed(key); if (!isSelector(id)) { json = { //@ts-ignore attributes: { ...json.attributes, [id]: value[key] } }; } } }); const jsonA = { children: { ...{ [tempSelector]: { attributes: json.attributes, children: {} } }, ...jsonInAttributes.children }, attributes: {} }; return jsonA; } static fromflatJSONToJSONAttributes(value: { [id: string]: object }): object { const tempSelector = '.container'; const jsonInAttributes: any = { children: {}, attributes: {} }; Object.keys(value).forEach((key) => { let id = tempSelector; if (isSelector(key) && !CSS.isMediaQuery(key)) { id = `${tempSelector}${key}`; } else if (CSS.isMediaQuery(key)) { id = key; } // ONLY ACCEPTS ONE LEVEL if (CSS.isMediaQuery(key)) { jsonInAttributes.children[id] = { attributes: {}, children: { [tempSelector]: { attributes: CSS.getCssObjectWithDashedProperties(value[key]), children: {} } } }; } else { jsonInAttributes.children[id] = { children: {}, attributes: CSS.getCssObjectWithDashedProperties(value[key]) }; } }); return jsonInAttributes; } /** * Convert JSON to CSS * @param value JSON in string or object format to be converted to CSS * @returns */ static fromCssInJstoCssString( value: { [id: string]: object | string }, prettify?: boolean ): string { try { const jsonAttributes = CSS.fromCssInJsToJSONAttributes(value); const css = toCSS(jsonAttributes); if (prettify) { return CSS.prettify(css); } return css; } catch (e) { // return `UNABLE TO CONVERT JSON TO CSS ${e}`; return `${value}`; } } static prettify(value: string): string { return beautify_css(value); } /** * Finds all uppercase letters, converts them to lowercase and the sufix - before them * @param str string in camelcase format */ static camelcaseToDashed(str: string): string { return str.replace(/[A-Z]/g, (match) => { return '-' + match.toLowerCase(); }); } static toCamelcase(css: CSSProperties): CSSProperties { const camel: CSSProperties = {}; Object.keys(css).forEach((key) => { camel[camelcaseifyCssProperty(key)] = css[key]; }); return camel; } }