UNPKG

apphouse

Version:

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

404 lines (351 loc) 10.5 kB
import { Style } from '../Style'; import { getCssWithThemedTokens } from './theme.utils'; import { Token } from '../Token'; import { ThemeStyles } from '../../styles/defaults/themes.interface'; import { htmlTags } from '../style.interface'; /** * 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; }; /** * Force first letter uppercase on a word * @param string string * @returns */ export const makeFirstLetterUppercase = (string: string) => { if (string.length === 0) { return string; } return string[0].toUpperCase() + string.substring(1); }; export const createStylesFromObject = ( objectStyles: any ): Record<string, Style> => { const styles: any = {}; // use default styles const keys = Object.keys(objectStyles); keys.forEach((key) => { const value = objectStyles[key]; const values = []; if (Array.isArray(value)) { value.forEach((entry: any) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore styles[key] = values.push(createStylesFromObject(entry)); }); } else { styles[key] = new Style({ id: key, value, baseComponent: '', variant: 'default' }); } }); return styles; }; export const getStyleValue = () => {}; export const toStylesObject = ({ value, withColorsFromPaletteId, lookup }: { value: Record<string, Style>; withColorsFromPaletteId?: string; // this is actually the paletteId ('dark' or 'light') lookup: { [id: string]: string }; }): object => { const obj: any = {}; Object.keys(value).forEach((key) => { const style = value[key]; if (style.baseComponent) { if (!obj[style.baseComponent]) { obj[style.baseComponent] = {}; } } }); Object.keys(value).forEach((key) => { const style = value[key]; if (style.baseComponent) { obj[style.baseComponent][style.variant] = getCssWithThemedTokens({ value: style.value, lookup, withColorsFromPaletteId, withRawValue: true }); } }); return obj; }; export const toApphouseStyles = ({ value, withColorsFromPaletteId, lookup }: { value: Record<string, Style>; withColorsFromPaletteId?: string; lookup: { [id: string]: string }; }): ThemeStyles => { const baseStyles: any = toStylesObject({ value, withColorsFromPaletteId, lookup }); let styles = JSON.stringify(baseStyles); Object.keys(lookup).forEach((key) => { styles = styles.replaceAll(`${key}"`, `${lookup[key]}"`); }); return JSON.parse(styles) as ThemeStyles; }; export const objectifyStylesWithBaseColors = ({ value }: { value: Record<string, Style>; theme?: 'dark' | 'light'; colors: { [colorId: string]: string }; tokens: Record<string, Token>; }): object => { const obj: any = {}; Object.keys(value).forEach((key) => { const style = value[key]; if (style.baseComponent) { if (!obj[style.baseComponent]) { obj[style.baseComponent] = {}; } } }); Object.keys(value).forEach((key) => { const style = value[key]; if (style.baseComponent) { obj[style.baseComponent][style.variant] = {}; } }); return obj; }; export const camelcaseifyCssProperty = (property: string): string => { const words = property.replaceAll('_', '-').split('-'); let camelcaseProperty = ''; words.forEach((word: string, i: number) => { if (i === 0) { camelcaseProperty = word; } else { camelcaseProperty = camelcaseProperty + makeFirstLetterUppercase(word); } }); return camelcaseProperty; }; // import { CSSProperties } from "glamor"; // import { CssPropertyStyle, Style } from "./Style"; // export const getPropertyValue = (value: any) => { // try { // const localStyles: any = {}; // if (typeof value !== "object") { // return value; // } // Object.keys(value).forEach((key) => { // const it = value[key]; // if (!it && it !== 0) { // return; // } // if (it === 0) { // //console.warn("x342", { it, itKey: key }); // localStyles[key] = 0; // return; // } // const stylePropertyValues = getPropertyValue(value[key]); // const hasChildren = Object.keys(stylePropertyValues)?.length > 0; // if (!hasChildren) { // // accumulate styles // localStyles[key] = stylePropertyValues; // } // if (hasChildren) { // localStyles[key] = {}; // localStyles[key] = getPropertyValue(stylePropertyValues); // } // }); // return localStyles; // } catch (error) { // console.log({ Error: "Error getting property values", error }); // return {}; // } // }; // export const isSelector = (styleKey: string): boolean => { // let selector = false; // if (styleKey.startsWith(":") || styleKey.startsWith("&:")) { // selector = true; // } // return selector; // }; // export const getPropertyValuePairs = ( // cssStyles: CSSProperties // ): CssPropertyStyle[] => { // let propertyStyles: CssPropertyStyle[] = []; // Object.keys(cssStyles).forEach((key: string) => { // const selector = isSelector(key); // const ps: CssPropertyStyle = { // isSelector: selector, // property: key, // value: selector ? cssStyles[key] : cssStyles[key], // }; // propertyStyles = [...propertyStyles, ps]; // }); // return propertyStyles; // }; // export const makeFirstLetterUppercase = (string: string) => { // if (string.length === 0) { // return string; // } // return string[0].toUpperCase() + string.substring(1); // }; // export const depthOf = (object: any) => { // let level = 1; // for (let key in object) { // if (!object.hasOwnProperty(key)) continue; // if (typeof object[key] == "object") { // const depth = depthOf(object[key]) + 1; // level = Math.max(depth, level); // } // } // return level; // }; // const getHtmlFromId = (id: string) => { // if (id.indexOf("button") >= 0) { // return "button"; // } // if (id.indexOf("heading") >= 0) { // return "h1"; // } // if (id.indexOf("text") >= 0) { // return "p"; // } // if (id.indexOf("input") >= 0) { // return "input"; // } // if (id.indexOf("label") >= 0) { // return "label"; // } // return "div"; // }; // export const getFlattenedStyles = (cssStyles: any): Record<string, Style[]> => { // let localStyles: Record<string, Style[]> = {}; // const getStyles = ( // current: any, // level: number, // currentPath?: string // ): Style[] => { // let localStyle: Style[] = []; // const keys = Object.keys(current); // keys?.forEach((key) => { // const currentStyles = current[key]; // const variant = level === 0 ? "default" : key; // const localDepth = depthOf(localStyle); // let id = key; // if (currentPath && level !== 0) { // id = `${currentPath}${makeFirstLetterUppercase(key)}`; // } // const childDepth = depthOf(currentStyles); // if (childDepth > 1) { // const s = getPropertyValuePairs(currentStyles); // const hasSelectors = s.find((item) => item.isSelector); // if (!hasSelectors) { // return mergeStyles(currentStyles, level + 1, key); // } // } // if (localDepth === 1) { // const style = new Style( // id, // getPropertyValuePairs(currentStyles), // currentPath || key, // variant, // undefined, // undefined, // getHtmlFromId(id) // ); // if (localStyles[id]) { // localStyles[id] = [...localStyles[id], style]; // } else { // localStyles[id] = [style]; // } // } // }); // return localStyle; // }; // mergeStyles(cssStyles, 0); // return localStyles; // }; // const cssStyles = toJS(styles); // export const defaultsStylesRaw = getPropertyValue(cssStyles); // export const defaultsStyles = getFlattenedStyles(defaultsStylesRaw); /** * Attempt to get a preview tag based on an item from the base component list * @param baseComponent string from baseComponent list * @returns an html tag (it will default to div if no match is found) */ export const getPreviewWithTagFromBaseComponent = (baseComponent: string) => { let previewWithTag = htmlTags.includes(baseComponent) ? baseComponent : undefined; if (!previewWithTag) { if (baseComponent === 'button') { previewWithTag = 'button'; } else if (baseComponent === 'list') { previewWithTag = 'ul'; } else if (baseComponent === 'link') { previewWithTag = 'a'; } else if (baseComponent === 'typography') { previewWithTag = 'p'; } else if (baseComponent === 'custom') { previewWithTag = 'SearchInput'; } else { previewWithTag = 'div'; } } return previewWithTag; }; /** * Attempt to get a preview tag based on the property keys on a object * @param cssObj object representing the styles * @returns an html tag (it will default to div if no match is found) */ export const getPreviewWithTagBasedOnObjectProperties = ( obj: { [id: string]: any; }, k?: string ): string => { if (k && k.toLocaleLowerCase().includes('button')) { return 'button'; } let previewWithTag = 'div'; Object.keys(obj).forEach((property) => { const value = obj[property]; if (typeof value === 'string') { const key = property.toLocaleLowerCase(); if ( key.indexOf('font') >= 0 || key.indexOf('typography') >= 0 || key.indexOf('text') >= 0 ) { previewWithTag = 'p'; } if (key.indexOf('input') >= 0) { previewWithTag = 'input'; } if (key.indexOf('button') >= 0) { previewWithTag = 'button'; } } if (typeof value === 'object') { // if we have not found a matching at the upper object keys, let's look at the children if (previewWithTag === 'div') { previewWithTag = getPreviewWithTagBasedOnObjectProperties(value); } } }); return previewWithTag; };