UNPKG

@builder.io/mitosis

Version:

Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io

114 lines (113 loc) 5.17 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.collectCss = exports.normalizeName = void 0; const legacy_1 = __importDefault(require("neotraverse/legacy")); const object_hash_1 = __importDefault(require("object-hash")); const dash_case_1 = require("../dash-case"); const is_mitosis_node_1 = require("../is-mitosis-node"); const helpers_1 = require("./helpers"); const trimClassStr = (classStr) => classStr.trim().replace(/\s{2,}/g, ' '); const updateClassForNode = (item, className) => { if (item.bindings.class) { // combine className with existing binding. We use single quotes because in Vue, bindings are wrapped in double quotes // e.g. <div :class="_classStringToObject(this.className + ' div-21azgz5avex')" /> item.bindings.class.code = trimClassStr(`${item.bindings.class.code} + ' ${className}'`); } else { item.properties.class = trimClassStr(`${item.properties.class || ''} ${className}`); } }; function normalizeName(name) { if (!name || name.trim() === '' || name.match(/^[^a-zA-Z0-9]*$/)) { return ''; } // Clean the name first const cleaned = name.replace(/[^a-zA-Z0-9\-_]/g, ''); // If pure numeric or only contains numbers and dashes if (cleaned.match(/^[0-9-]+$/)) { // Extract just the numbers and format as css{number} const numbers = cleaned.replace(/[^0-9]/g, ''); return `css${numbers}`; } // Remove leading numbers and dashes for other cases const normalized = cleaned.replace(/^[0-9-]+(?=[a-zA-Z])/, ''); return normalized || ''; } exports.normalizeName = normalizeName; const collectStyles = (json, options = {}) => { const styleMap = {}; const componentIndexes = {}; const componentHashes = {}; (0, legacy_1.default)(json).forEach(function (item) { var _a; if ((0, is_mitosis_node_1.isMitosisNode)(item)) { if ((0, helpers_1.nodeHasCss)(item)) { const value = (0, helpers_1.parseCssObject)((_a = item.bindings.css) === null || _a === void 0 ? void 0 : _a.code); delete item.bindings.css; const normalizedName = normalizeName(item.properties.$name); const componentName = normalizedName ? (0, dash_case_1.dashCase)(normalizedName) : /^h\d$/.test(item.name || '') // don't dashcase h1 into h-1 ? item.name : (0, dash_case_1.dashCase)(normalizeName(item.name) || 'div'); const classNameWPrefix = `${componentName}${options.prefix ? `-${options.prefix}` : ''}`; const stylesHash = (0, object_hash_1.default)(value); if (componentHashes[componentName] === stylesHash) { const className = classNameWPrefix; updateClassForNode(item, className); return; } if (!componentHashes[componentName]) { componentHashes[componentName] = stylesHash; } const index = (componentIndexes[componentName] = (componentIndexes[componentName] || 0) + 1); const className = `${classNameWPrefix}${index === 1 ? '' : `-${index}`}`; updateClassForNode(item, className); styleMap[className] = value; } delete item.bindings.css; } }); return styleMap; }; const collectCss = (json, options = {}) => { var _a; const styles = collectStyles(json, options); // TODO create and use a root selector let css = ''; css += !!((_a = json.style) === null || _a === void 0 ? void 0 : _a.length) ? `${json.style}\n` : ''; css += classStyleMapToCss(styles); return css; }; exports.collectCss = collectCss; const classStyleMapToCss = (map) => { let str = ''; for (const key in map) { const styles = (0, helpers_1.getStylesOnly)(map[key]); str += `.${key} {\n${(0, helpers_1.styleMapToCss)(styles)}\n}`; const nestedSelectors = (0, helpers_1.getNestedSelectors)(map[key]); for (const nestedSelector in nestedSelectors) { const value = nestedSelectors[nestedSelector]; if (nestedSelector.startsWith('@')) { str += `${nestedSelector} { .${key} { ${(0, helpers_1.styleMapToCss)(value)} } }`; } else { const getSelector = (nestedSelector) => { if (nestedSelector.startsWith(':')) { return `.${key}${nestedSelector}`; } if (nestedSelector.includes('&')) { return nestedSelector.replace(/&/g, `.${key}`); } return `.${key} ${nestedSelector}`; }; str += `${getSelector(nestedSelector)} {\n${(0, helpers_1.styleMapToCss)(value)}\n}`; } } } return str; };