const kebabize = (str: string) => { return str.replace( /[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase() ); }; const formatCssValue = (value: string | number) => { return /^\d+$/.test(value.toString()) ? `${value}px` : value; }; interface NodeProperties { style?: Record; parent_id?: string; type?: string; tag?: string; breakpoints?: any[]; dataSources?: any[]; is_slider?: boolean; iteratingNode?: string; iteratorValue?: string; selectedDataSourceId?: string; order?: number; } interface Node { key: string; properties: NodeProperties; label?: string; data_type?: string; } const processNode = (node: Node, selector = '', styles: string[] = []) => { const { key, properties } = node; const { style } = properties; if (key && style) { const baseStyles: Record = {}; const breakpointStyles: Record> = {}; Object.entries(style).forEach(([prop, val]) => { if (typeof val === 'object') { breakpointStyles[prop] = val; } else { baseStyles[prop] = val; } }); const baseCssRules = Object.entries(baseStyles) .map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`) .join(' '); if (baseCssRules) { styles.push(`${selector} { ${baseCssRules} }`); } Object.keys(breakpointStyles) .map((bp) => parseInt(bp, 10)) .sort((a, b) => a - b) .forEach((bp) => { const bpCssRules = Object.entries(breakpointStyles[bp]) .map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`) .join(' '); if (bpCssRules) { styles.push( `@media only screen and (min-width: ${bp}px) { ${selector} { ${bpCssRules} } }` ); } }); } return styles; }; const componentToCss = (components: Record) => { const styles: string[] = []; const componentsById: Record = {}; Object.values(components).forEach((component) => { componentsById[component.key] = component; }); const addStylesForComponent = (component: Node) => { const selector = `[data-id="${component.key}"]`; processNode(component, selector, styles); Object.values(componentsById) .filter((child) => child.properties.parent_id === component.key) .forEach(addStylesForComponent); }; Object.values(componentsById) .filter((component) => !component.properties?.parent_id) .forEach(addStylesForComponent); return styles.join(' '); }; export const generateWidgetStyles = (widgetSchemas: Record[]) => { return widgetSchemas .filter((schema) => Object.keys(schema).length > 0) .map((data) => componentToCss(data)) .join('\n'); }; export type { Node, NodeProperties };