@builder.io/mitosis 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -342,7 +342,7 @@ const _componentToReact = (json, options, isSubComponent = false) => {
342
342
  // NOTE: `collectReactNativeStyles` must run before style generation in the component generation body, as it has
343
343
  // side effects that delete styles bindings from the JSON.
344
344
  const reactNativeStyles = options.stylesType === 'react-native' && componentHasStyles
345
- ? (0, react_native_1.collectReactNativeStyles)(json)
345
+ ? (0, react_native_1.collectReactNativeStyles)(json, options)
346
346
  : undefined;
347
347
  const propType = json.propsTypeRef || 'any';
348
348
  const componentArgs = [`props${options.typescript ? `:${propType}` : ''}`, options.forwardRef]
@@ -5,6 +5,7 @@ export interface ToReactOptions extends BaseTranspilerOptions {
5
5
  format?: 'lite' | 'safe';
6
6
  type: 'dom' | 'native' | 'taro';
7
7
  preact?: boolean;
8
+ sanitizeReactNative?: boolean;
8
9
  rsc?: boolean;
9
10
  forwardRef?: string;
10
11
  experimental?: any;
@@ -0,0 +1 @@
1
+ export declare function extractCssVarDefaultValue(value: string): string;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractCssVarDefaultValue = void 0;
4
+ function extractCssVarDefaultValue(value) {
5
+ // Regular expression to find var() expressions
6
+ const varRegex = /var\(--[^,]+?,\s*([^)]+)\)/;
7
+ // Function to replace var() with its fallback
8
+ let newValue = value;
9
+ let match;
10
+ while ((match = newValue.match(varRegex))) {
11
+ newValue = newValue.replace(match[0], match[1].trim());
12
+ }
13
+ return newValue;
14
+ }
15
+ exports.extractCssVarDefaultValue = extractCssVarDefaultValue;
@@ -0,0 +1,3 @@
1
+ type Styles = Record<string, string | number>;
2
+ export declare function cleanReactNativeBlockStyles(styles: Styles): Styles;
3
+ export {};
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cleanReactNativeBlockStyles = void 0;
4
+ const extract_css_var_default_value_1 = require("./extract-css-var-default-value");
5
+ const lengthPattern = /^-?\d*\.?\d+(px|%)?$/;
6
+ const pixelPattern = /^-?\d*\.?\d+(px)?$/;
7
+ const numberPattern = /^-?\d*\.?\d+$/;
8
+ const colorPattern = /^(#[0-9A-Fa-f]{3,8}|(rgb|hsl)a?\(.*\)|[a-zA-Z]+)$/;
9
+ // List of unsupported properties in React Native
10
+ const unsupportedProps = [
11
+ 'textShadow',
12
+ 'boxShadow',
13
+ 'transition',
14
+ 'cursor',
15
+ 'filter',
16
+ 'overflowX',
17
+ 'overflowY',
18
+ 'animation',
19
+ 'backgroundImage',
20
+ 'backgroundPosition',
21
+ 'backgroundSize',
22
+ 'backgroundRepeat',
23
+ 'whiteSpace',
24
+ ];
25
+ // Ensure CSS property value is valid for React Native
26
+ function validateReactNativeCssProperty(key, value) {
27
+ const cssProperties = {
28
+ width: (value) => lengthPattern.test(value),
29
+ height: (value) => lengthPattern.test(value),
30
+ backgroundColor: (value) => pixelPattern.test(value) || /^#[0-9A-Fa-f]{6}/.test(value),
31
+ minWidth: (value) => lengthPattern.test(value) || value === 'auto',
32
+ maxWidth: (value) => lengthPattern.test(value) || value === 'auto',
33
+ minHeight: (value) => lengthPattern.test(value) || value === 'auto',
34
+ maxHeight: (value) => lengthPattern.test(value) || value === 'auto',
35
+ aspectRatio: (value) => numberPattern.test(value) || /^\d+\/\d+$/.test(value),
36
+ // Flexbox Properties
37
+ flex: (value) => numberPattern.test(value),
38
+ flexBasis: (value) => lengthPattern.test(value) || value === 'auto',
39
+ flexDirection: (value) => ['row', 'row-reverse', 'column', 'column-reverse'].includes(value),
40
+ flexGrow: (value) => numberPattern.test(value),
41
+ flexShrink: (value) => numberPattern.test(value),
42
+ flexWrap: (value) => ['wrap', 'nowrap', 'wrap-reverse'].includes(value),
43
+ // Alignment Properties
44
+ alignContent: (value) => ['flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around'].includes(value),
45
+ alignItems: (value) => ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'].includes(value),
46
+ alignSelf: (value) => ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'].includes(value),
47
+ justifyContent: (value) => [
48
+ 'flex-start',
49
+ 'flex-end',
50
+ 'center',
51
+ 'space-between',
52
+ 'space-around',
53
+ 'space-evenly',
54
+ ].includes(value),
55
+ // Text Properties
56
+ color: (value) => colorPattern.test(value),
57
+ fontFamily: () => true, // Any string is valid
58
+ fontSize: (value) => pixelPattern.test(value),
59
+ fontStyle: (value) => ['normal', 'italic'].includes(value),
60
+ fontWeight: (value) => ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'].includes(value),
61
+ display: (value) => ['none', 'flex'].includes(value),
62
+ };
63
+ // If the property is not explicitly defined, consider it valid
64
+ if (!cssProperties[key])
65
+ return true;
66
+ // Convert number to string for validation
67
+ const stringValue = typeof value === 'number' ? value.toString() : value;
68
+ return cssProperties[key](stringValue);
69
+ }
70
+ // Clean up shorthand and unsupported styles for React Native
71
+ function cleanReactNativeBlockStyles(styles) {
72
+ return Object.entries(styles).reduce((acc, [key, value]) => {
73
+ var _a;
74
+ // Remove unsupported properties
75
+ if (unsupportedProps.includes(key))
76
+ return acc;
77
+ // Handle CSS variables
78
+ if (typeof value === 'string' && value.includes('var(')) {
79
+ value = (_a = (0, extract_css_var_default_value_1.extractCssVarDefaultValue)(value)) !== null && _a !== void 0 ? _a : value;
80
+ }
81
+ // Parse pixel units
82
+ if (typeof value === 'string') {
83
+ const pixelMatch = value.match(/^(-?\d+(\.\d+)?)px$/);
84
+ if (pixelMatch)
85
+ value = parseFloat(pixelMatch[1]);
86
+ }
87
+ // Handle shorthand properties
88
+ if (key === 'margin' || key === 'padding') {
89
+ return { ...acc, ...expandShorthand(key, value) };
90
+ }
91
+ // Convert 'background' to 'backgroundColor'
92
+ if (key === 'background' && typeof value === 'string') {
93
+ acc.backgroundColor = value;
94
+ return { ...acc, backgroundColor: value };
95
+ }
96
+ // Handle borderRadius
97
+ if (key === 'borderRadius' && typeof value === 'string') {
98
+ return { ...acc, ...expandBorderRadius(value) };
99
+ }
100
+ // Handle invalid display values
101
+ if (key === 'display' && value !== 'flex' && value !== 'none') {
102
+ return acc;
103
+ }
104
+ // Validate and add the property
105
+ if (validateReactNativeCssProperty(key, value)) {
106
+ acc[key] = value;
107
+ }
108
+ return acc;
109
+ }, {});
110
+ }
111
+ exports.cleanReactNativeBlockStyles = cleanReactNativeBlockStyles;
112
+ function expandShorthand(property, value) {
113
+ if (typeof value !== 'string')
114
+ return { [property]: value };
115
+ const values = value.split(' ').map((v) => parseFloat(v) || 0);
116
+ const [top, right = top, bottom = top, left = right] = values;
117
+ return {
118
+ [`${property}Top`]: top,
119
+ [`${property}Right`]: right,
120
+ [`${property}Bottom`]: bottom,
121
+ [`${property}Left`]: left,
122
+ };
123
+ }
124
+ function expandBorderRadius(value) {
125
+ const values = value.split(' ').map((v) => parseInt(v, 10));
126
+ const [topLeft, topRight = topLeft, bottomRight = topLeft, bottomLeft = topRight] = values;
127
+ return {
128
+ borderTopLeftRadius: topLeft,
129
+ borderTopRightRadius: topRight,
130
+ borderBottomRightRadius: bottomRight,
131
+ borderBottomLeftRadius: bottomLeft,
132
+ };
133
+ }
@@ -2,5 +2,6 @@ import { ToReactNativeOptions } from '../../generators/react-native/types';
2
2
  import { ClassStyleMap } from '../../helpers/styles/helpers';
3
3
  import { MitosisComponent } from '../../types/mitosis-component';
4
4
  import { TranspilerGenerator } from '../../types/transpiler';
5
- export declare const collectReactNativeStyles: (json: MitosisComponent) => ClassStyleMap;
5
+ import { ToReactOptions } from '../react';
6
+ export declare const collectReactNativeStyles: (json: MitosisComponent, options: ToReactOptions) => ClassStyleMap;
6
7
  export declare const componentToReactNative: TranspilerGenerator<Partial<ToReactNativeOptions>>;
@@ -25,7 +25,7 @@ const sanitizeStyle = (obj) => (key, value) => {
25
25
  return;
26
26
  }
27
27
  };
28
- const collectReactNativeStyles = (json) => {
28
+ const collectReactNativeStyles = (json, options) => {
29
29
  const styleMap = {};
30
30
  const componentIndexes = {};
31
31
  const getStyleSheetName = (item) => {
@@ -45,7 +45,7 @@ const collectReactNativeStyles = (json) => {
45
45
  // Style properties like `"20px"` need to be numbers like `20` for react native
46
46
  for (const key in cssValue) {
47
47
  sanitizeStyle(cssValue)(key, cssValue[key]);
48
- cssValue = (0, sanitize_react_native_block_styles_1.sanitizeReactNativeBlockStyles)(cssValue);
48
+ cssValue = (0, sanitize_react_native_block_styles_1.sanitizeReactNativeBlockStyles)(cssValue, options);
49
49
  }
50
50
  }
51
51
  try {
@@ -54,7 +54,7 @@ const collectReactNativeStyles = (json) => {
54
54
  // Style properties like `"20px"` need to be numbers like `20` for react native
55
55
  for (const key in styleValue) {
56
56
  sanitizeStyle(styleValue)(key, styleValue[key]);
57
- styleValue = (0, sanitize_react_native_block_styles_1.sanitizeReactNativeBlockStyles)(styleValue);
57
+ styleValue = (0, sanitize_react_native_block_styles_1.sanitizeReactNativeBlockStyles)(styleValue, options);
58
58
  }
59
59
  item.bindings.style.code = json5_1.default.stringify(styleValue);
60
60
  }
@@ -1,3 +1,4 @@
1
+ import { ToReactOptions } from '../react/types';
1
2
  type Styles = Record<string, string | number>;
2
- export declare const sanitizeReactNativeBlockStyles: (styles: Styles) => Styles;
3
+ export declare const sanitizeReactNativeBlockStyles: (styles: Styles, options: ToReactOptions) => Styles;
3
4
  export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sanitizeReactNativeBlockStyles = void 0;
4
+ const helpers_1 = require("./helpers");
4
5
  const propertiesThatMustBeNumber = new Set(['lineHeight']);
5
6
  const displayValues = new Set(['flex', 'none']);
6
7
  const normalizeNumber = (value) => {
@@ -15,10 +16,15 @@ const normalizeNumber = (value) => {
15
16
  return value;
16
17
  }
17
18
  };
18
- const sanitizeReactNativeBlockStyles = (styles) => {
19
+ const sanitizeReactNativeBlockStyles = (styles, options) => {
20
+ if (options.sanitizeReactNative) {
21
+ return (0, helpers_1.cleanReactNativeBlockStyles)(styles);
22
+ }
19
23
  return Object.keys(styles).reduce((acc, key) => {
20
24
  const propertyValue = styles[key];
21
- if (key === 'display' && !displayValues.has(propertyValue)) {
25
+ if (typeof propertyValue === 'string' &&
26
+ key === 'display' &&
27
+ !displayValues.has(propertyValue)) {
22
28
  console.warn(`Style value for key "display" must be "flex" or "none" but had ${propertyValue}`);
23
29
  return acc;
24
30
  }
@@ -1,5 +1,6 @@
1
1
  import { BaseTranspilerOptions } from '../../types/transpiler';
2
2
  export interface ToReactNativeOptions extends BaseTranspilerOptions {
3
+ sanitizeReactNative?: boolean;
3
4
  stylesType: 'emotion' | 'react-native' | 'twrnc' | 'native-wind';
4
5
  stateType: 'useState' | 'mobx' | 'valtio' | 'solid' | 'builder';
5
6
  }
@@ -101,7 +101,10 @@ function mapStateIdentifiers(json) {
101
101
  const plugin = (0, process_code_1.createCodeProcessorPlugin)(() => (code) => mapStateIdentifiersInExpression(code, stateProperties));
102
102
  plugin(json);
103
103
  (0, legacy_1.default)(json).forEach(function (item) {
104
- if ((0, is_mitosis_node_1.isMitosisNode)(item)) {
104
+ // only consolidate bindings for HTML tags, not custom components
105
+ // custom components are always PascalCase, e.g. MyComponent
106
+ // but HTML tags are lowercase, e.g. div
107
+ if ((0, is_mitosis_node_1.isMitosisNode)(item) && item.name.toLowerCase() === item.name) {
105
108
  consolidateClassBindings(item);
106
109
  }
107
110
  });
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "name": "Builder.io",
23
23
  "url": "https://www.builder.io"
24
24
  },
25
- "version": "0.5.0",
25
+ "version": "0.5.2",
26
26
  "homepage": "https://github.com/BuilderIO/mitosis",
27
27
  "main": "./dist/src/index.js",
28
28
  "exports": {
@@ -96,8 +96,6 @@
96
96
  "@types/rollup__plugin-virtual": "^2.0.1",
97
97
  "concurrently": "^8.2.2",
98
98
  "fs-extra-promise": "^1.0.1",
99
- "nx": "^19.0.8",
100
- "nx-cloud": "^19.0.0",
101
99
  "rimraf": "^5.0.5",
102
100
  "rollup": "^2.70.1",
103
101
  "strip-ansi": "^6.0.1",