diff --git a/.changeset/brave-beds-act.md b/.changeset/brave-beds-act.md
new file mode 100644
index 0000000000..4288967ceb
--- /dev/null
+++ b/.changeset/brave-beds-act.md
@@ -0,0 +1,5 @@
+---
+'@builder.io/mitosis': patch
+---
+
+Fix: properly handle innerHTML properties in react codegen
diff --git a/packages/core/src/__tests__/__snapshots__/builder.test.ts.snap b/packages/core/src/__tests__/__snapshots__/builder.test.ts.snap
index d94422bead..3f801630e6 100644
--- a/packages/core/src/__tests__/__snapshots__/builder.test.ts.snap
+++ b/packages/core/src/__tests__/__snapshots__/builder.test.ts.snap
@@ -3530,6 +3530,39 @@ exports[`Builder > Text with bindings 3`] = `
}
`;
+exports[`Builder > Valid Custom Code 1`] = `
+"
+
+
+
+"
+`;
+
+exports[`Builder > Valid Custom Code 2`] = `
+"import * as React from \\"react\\";
+
+function MyComponent(props) {
+ return (
+
+
\\",
+ }}
+ />
+
+ );
+}
+
+export default MyComponent;
+"
+`;
+
exports[`Builder > async bindings 1`] = `
{
"data": {
diff --git a/packages/core/src/__tests__/builder.test.ts b/packages/core/src/__tests__/builder.test.ts
index f19db5264d..98cf441b78 100644
--- a/packages/core/src/__tests__/builder.test.ts
+++ b/packages/core/src/__tests__/builder.test.ts
@@ -3,6 +3,7 @@ import { componentToHtml } from '@/generators/html';
import { componentToMitosis } from '@/generators/mitosis';
import { ToMitosisOptions } from '@/generators/mitosis/types';
import { componentToReact } from '@/generators/react';
+import { componentToVue } from '@/generators/vue';
import { dedent } from '@/helpers/dedent';
import {
builderContentToMitosisComponent,
@@ -322,6 +323,35 @@ describe('Builder', () => {
expect(html).toMatchSnapshot();
});
+ test('Valid Custom Code', async () => {
+ const builderJson: BuilderContent = {
+ data: {
+ blocks: [
+ {
+ '@type': '@builder.io/sdk:Element',
+ component: {
+ name: 'CustomCode',
+ options: {
+ code: `
`,
+ },
+ },
+ },
+ ],
+ },
+ } as BuilderContent;
+ const component = builderContentToMitosisComponent(builderJson);
+
+ const vue = componentToVue({
+ plugins: [compileAwayBuilderComponents()],
+ })({ component });
+ expect(vue).toMatchSnapshot();
+
+ const react = componentToReact({
+ plugins: [compileAwayBuilderComponents()],
+ })({ component });
+ expect(react).toMatchSnapshot();
+ });
+
test('Regenerate custom Hero', () => {
const code = dedent`
import { Hero } from "@components";
diff --git a/packages/core/src/generators/react/blocks.ts b/packages/core/src/generators/react/blocks.ts
index 40dc24b97d..04d2e7dcd6 100644
--- a/packages/core/src/generators/react/blocks.ts
+++ b/packages/core/src/generators/react/blocks.ts
@@ -145,7 +145,12 @@ const ATTTRIBUTE_MAPPERS: { [key: string]: string } = {
const BINDING_MAPPERS: {
[key: string]:
| string
- | ((key: string, value: string, options?: ToReactOptions) => [string, string]);
+ | ((
+ key: string,
+ value: string,
+ options?: ToReactOptions,
+ isProperty?: boolean,
+ ) => [string, string]);
} = {
ref(ref, value, options) {
if (options?.preact) {
@@ -161,8 +166,14 @@ const BINDING_MAPPERS: {
}
return [ref, value];
},
- innerHTML(_key, value) {
- return ['dangerouslySetInnerHTML', `{__html: ${value.replace(/\s+/g, ' ')}}`];
+ innerHTML(_key, value, _options, isProperty) {
+ const wrapChar = isProperty ? '"' : '';
+ let useValue = value.replace(/\s+/g, ' ');
+
+ if (isProperty) {
+ useValue = value.replace(/"/g, '\\"');
+ }
+ return ['dangerouslySetInnerHTML', `{__html: ${wrapChar}${useValue}${wrapChar}}`];
},
...ATTTRIBUTE_MAPPERS,
};
@@ -246,7 +257,7 @@ export const blockToReact = (
} else if (BINDING_MAPPERS[key]) {
const mapper = BINDING_MAPPERS[key];
if (typeof mapper === 'function') {
- const [newKey, newValue] = mapper(key, value, options);
+ const [newKey, newValue] = mapper(key, value, options, true);
str += ` ${newKey}={${newValue}} `;
} else {
str += ` ${BINDING_MAPPERS[key]}="${value}" `;
diff --git a/packages/core/src/plugins/compile-away-builder-components.ts b/packages/core/src/plugins/compile-away-builder-components.ts
index ef9fb881a7..162791fa9d 100644
--- a/packages/core/src/plugins/compile-away-builder-components.ts
+++ b/packages/core/src/plugins/compile-away-builder-components.ts
@@ -203,7 +203,10 @@ export const components: CompileAwayComponentsMap = {
bindings.innerHTML = node.bindings.code;
}
return wrapOutput(
- node,
+ {
+ ...node,
+ properties: omit(node.properties, 'code'),
+ },
createMitosisNode({
name: (node.properties.builderTag as string) || 'div',
properties: {