@builder.io/mitosis
Version:
Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io
134 lines (133 loc) • 5.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.cleanReactNativeBlockStyles = void 0;
const extract_css_var_default_value_1 = require("./extract-css-var-default-value");
const lengthPattern = /^-?\d*\.?\d+(px|%)?$/;
const pixelPattern = /^-?\d*\.?\d+(px)?$/;
const numberPattern = /^-?\d*\.?\d+$/;
const colorPattern = /^(#[0-9A-Fa-f]{3,8}|(rgb|hsl)a?\(.*\)|[a-zA-Z]+)$/;
// List of unsupported properties in React Native
const unsupportedProps = [
'textShadow',
'boxShadow',
'transition',
'cursor',
'filter',
'overflowX',
'overflowY',
'animation',
'backgroundImage',
'backgroundPosition',
'backgroundSize',
'backgroundRepeat',
'whiteSpace',
];
// Ensure CSS property value is valid for React Native
function validateReactNativeCssProperty(key, value) {
const cssProperties = {
width: (value) => lengthPattern.test(value),
height: (value) => lengthPattern.test(value),
backgroundColor: (value) => pixelPattern.test(value) || /^#[0-9A-Fa-f]{6}/.test(value),
minWidth: (value) => lengthPattern.test(value) || value === 'auto',
maxWidth: (value) => lengthPattern.test(value) || value === 'auto',
minHeight: (value) => lengthPattern.test(value) || value === 'auto',
maxHeight: (value) => lengthPattern.test(value) || value === 'auto',
aspectRatio: (value) => numberPattern.test(value) || /^\d+\/\d+$/.test(value),
// Flexbox Properties
flex: (value) => numberPattern.test(value),
flexBasis: (value) => lengthPattern.test(value) || value === 'auto',
flexDirection: (value) => ['row', 'row-reverse', 'column', 'column-reverse'].includes(value),
flexGrow: (value) => numberPattern.test(value),
flexShrink: (value) => numberPattern.test(value),
flexWrap: (value) => ['wrap', 'nowrap', 'wrap-reverse'].includes(value),
// Alignment Properties
alignContent: (value) => ['flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around'].includes(value),
alignItems: (value) => ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'].includes(value),
alignSelf: (value) => ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'].includes(value),
justifyContent: (value) => [
'flex-start',
'flex-end',
'center',
'space-between',
'space-around',
'space-evenly',
].includes(value),
// Text Properties
color: (value) => colorPattern.test(value),
fontFamily: () => true, // Any string is valid
fontSize: (value) => pixelPattern.test(value),
fontStyle: (value) => ['normal', 'italic'].includes(value),
fontWeight: (value) => ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'].includes(value),
display: (value) => ['none', 'flex'].includes(value),
};
// If the property is not explicitly defined, consider it valid
if (!cssProperties[key])
return true;
// Convert number to string for validation
const stringValue = typeof value === 'number' ? value.toString() : value;
return cssProperties[key](stringValue);
}
// Clean up shorthand and unsupported styles for React Native
function cleanReactNativeBlockStyles(styles) {
return Object.entries(styles).reduce((acc, [key, value]) => {
var _a;
// Remove unsupported properties
if (unsupportedProps.includes(key))
return acc;
// Handle CSS variables
if (typeof value === 'string' && value.includes('var(')) {
value = (_a = (0, extract_css_var_default_value_1.extractCssVarDefaultValue)(value)) !== null && _a !== void 0 ? _a : value;
}
// Parse pixel units
if (typeof value === 'string') {
const pixelMatch = value.match(/^(-?\d+(\.\d+)?)px$/);
if (pixelMatch)
value = parseFloat(pixelMatch[1]);
}
// Handle shorthand properties
if (key === 'margin' || key === 'padding') {
return { ...acc, ...expandShorthand(key, value) };
}
// Convert 'background' to 'backgroundColor'
if (key === 'background' && typeof value === 'string') {
acc.backgroundColor = value;
return { ...acc, backgroundColor: value };
}
// Handle borderRadius
if (key === 'borderRadius' && typeof value === 'string') {
return { ...acc, ...expandBorderRadius(value) };
}
// Handle invalid display values
if (key === 'display' && value !== 'flex' && value !== 'none') {
return acc;
}
// Validate and add the property
if (validateReactNativeCssProperty(key, value)) {
acc[key] = value;
}
return acc;
}, {});
}
exports.cleanReactNativeBlockStyles = cleanReactNativeBlockStyles;
function expandShorthand(property, value) {
if (typeof value !== 'string')
return { [property]: value };
const values = value.split(' ').map((v) => parseFloat(v) || 0);
const [top, right = top, bottom = top, left = right] = values;
return {
[`${property}Top`]: top,
[`${property}Right`]: right,
[`${property}Bottom`]: bottom,
[`${property}Left`]: left,
};
}
function expandBorderRadius(value) {
const values = value.split(' ').map((v) => parseInt(v, 10));
const [topLeft, topRight = topLeft, bottomRight = topLeft, bottomLeft = topRight] = values;
return {
borderTopLeftRadius: topLeft,
borderTopRightRadius: topRight,
borderBottomRightRadius: bottomRight,
borderBottomLeftRadius: bottomLeft,
};
}
;