From 2ba144f171ba4853636b306c48ef1a50dd97d414 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Thu, 18 Jan 2024 23:13:32 +0200
Subject: [PATCH 01/30] feat(compilers): render React component if it is the
 default export

---
 src/livecodes/languages/jsx/jsx-runtime.ts    | 11 +++++++++
 .../languages/typescript/lang-typescript.ts   | 14 +++++++----
 src/livecodes/result/result-page.ts           | 24 ++++++++++++++++---
 3 files changed, 42 insertions(+), 7 deletions(-)
 create mode 100644 src/livecodes/languages/jsx/jsx-runtime.ts

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
new file mode 100644
index 000000000..fdcf8130b
--- /dev/null
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -0,0 +1,11 @@
+export const reactRuntime = `
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from './script';
+const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')));
+root.render(React.createElement(App, null));
+`;
+
+export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
+
+export const hasDefaultExport = (code: string) => new RegExp(/export\s*default\s/).test(code);
diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index e6c826dcd..7a6464900 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -2,6 +2,8 @@ import type { LanguageSpecs } from '../../models';
 import { typescriptUrl } from '../../vendors';
 import { getLanguageCustomSettings } from '../../utils';
 import { parserPlugins } from '../prettier';
+// eslint-disable-next-line import/no-internal-modules
+import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
@@ -22,12 +24,16 @@ export const typescript: LanguageSpecs = {
     url: typescriptUrl,
     factory:
       () =>
-      async (code, { config, language }) =>
-        (window as any).ts.transpile(code, {
+      async (code, { config }) => {
+        if (['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)) {
+          code = `import React from 'react';\n${code}`;
+        }
+        return (window as any).ts.transpile(code, {
           ...typescriptOptions,
           ...getLanguageCustomSettings('typescript', config),
-          ...getLanguageCustomSettings(language, config),
-        }),
+          ...getLanguageCustomSettings(config.script.language, config),
+        });
+      },
   },
   extensions: ['ts', 'typescript'],
   editor: 'script',
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 5ca39a638..c13d70e76 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -1,3 +1,4 @@
+/* eslint-disable import/no-internal-modules */
 import {
   createImportMap,
   createCSSModulesImportMap,
@@ -7,9 +8,9 @@ import {
   removeImports,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
+import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
 import type { Cache, EditorId, Config, CompileInfo } from '../models';
 import { getAppCDN, modulesService } from '../services';
-// eslint-disable-next-line import/no-internal-modules
 import { testImports } from '../toolspane/test-imports';
 import {
   addAttrs,
@@ -156,6 +157,12 @@ export const createResultPage = async ({
     getImports(markup).includes('./script') ||
     (runTests && !forExport && getImports(compiledTests).includes('./script'));
 
+  const shouldInsertReactJsxRuntime =
+    ['jsx', 'tsx'].includes(code.script.language) &&
+    hasDefaultExport(code.script.compiled) &&
+    !hasCustomJsxRuntime(code.script.content || '') &&
+    !importFromScript;
+
   let compilerImports = {};
 
   for (const { language, compiled } of runtimeDependencies) {
@@ -218,10 +225,13 @@ export const createResultPage = async ({
           ...(hasImports(code.markup.compiled)
             ? createImportMap(code.markup.compiled, config)
             : {}),
+          ...(shouldInsertReactJsxRuntime ? createImportMap(reactRuntime, config) : {}),
           ...(runTests && !forExport && hasImports(compiledTests)
             ? createImportMap(compiledTests, config)
             : {}),
-          ...(importFromScript ? { './script': toDataUrl(code.script.compiled) } : {}),
+          ...(importFromScript || shouldInsertReactJsxRuntime
+            ? { './script': toDataUrl(code.script.compiled) }
+            : {}),
           ...createCSSModulesImportMap(
             code.script.compiled,
             code.style.compiled,
@@ -263,7 +273,7 @@ export const createResultPage = async ({
     dom.head.appendChild(externalScript);
   });
 
-  if (!importFromScript) {
+  if (!importFromScript && !shouldInsertReactJsxRuntime) {
     // editor script
     const script = code.script.compiled;
     const scriptElement = dom.createElement('script');
@@ -288,6 +298,14 @@ export const createResultPage = async ({
     }
   }
 
+  // React JSX runtime
+  if (shouldInsertReactJsxRuntime) {
+    const jsxRuntimeScript = dom.createElement('script');
+    jsxRuntimeScript.type = 'module';
+    jsxRuntimeScript.innerHTML = reactRuntime;
+    dom.body.appendChild(jsxRuntimeScript);
+  }
+
   // spacing
   if (config.showSpacing && !forExport) {
     const spacingScript = dom.createElement('script');

From 87936277aae60e3d5d3d6ebb2f82d966eca5c709 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 19 Jan 2024 07:49:24 +0200
Subject: [PATCH 02/30] feat(compilers): set typescript option { jsx:
 'react-jsx' }

---
 src/livecodes/languages/jsx/jsx-runtime.ts          |  4 ++--
 .../languages/typescript/lang-typescript.ts         | 13 +++++--------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
index fdcf8130b..33cee2a7d 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -1,9 +1,9 @@
 export const reactRuntime = `
-import React from "react";
+import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
 import App from './script';
 const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')));
-root.render(React.createElement(App, null));
+root.render(_jsx(App, {}));
 `;
 
 export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index 7a6464900..bb8c578c6 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -7,7 +7,7 @@ import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
-  jsx: 'react',
+  jsx: 'react-jsx',
   allowUmdGlobalAccess: true,
   esModuleInterop: true,
 };
@@ -24,16 +24,13 @@ export const typescript: LanguageSpecs = {
     url: typescriptUrl,
     factory:
       () =>
-      async (code, { config }) => {
-        if (['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)) {
-          code = `import React from 'react';\n${code}`;
-        }
-        return (window as any).ts.transpile(code, {
+      async (code, { config }) =>
+        (window as any).ts.transpile(code, {
           ...typescriptOptions,
+          ...(hasCustomJsxRuntime(code) ? { jsx: 'react' } : {}),
           ...getLanguageCustomSettings('typescript', config),
           ...getLanguageCustomSettings(config.script.language, config),
-        });
-      },
+        }),
   },
   extensions: ['ts', 'typescript'],
   editor: 'script',

From 4a287aeddc20fe70ce2ad1eefdc38a860c0dd57b Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 19 Jan 2024 08:31:02 +0200
Subject: [PATCH 03/30] only apply {jsx: 'react-jsx'} if language is JSX or TSX
 this avoids interfering with other languages (e.g. Vue with JSX)

---
 src/livecodes/languages/typescript/lang-typescript.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index bb8c578c6..16ac76dda 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -7,7 +7,7 @@ import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
-  jsx: 'react-jsx',
+  jsx: 'react',
   allowUmdGlobalAccess: true,
   esModuleInterop: true,
 };
@@ -27,7 +27,9 @@ export const typescript: LanguageSpecs = {
       async (code, { config }) =>
         (window as any).ts.transpile(code, {
           ...typescriptOptions,
-          ...(hasCustomJsxRuntime(code) ? { jsx: 'react' } : {}),
+          ...(['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)
+            ? { jsx: 'react-jsx' }
+            : {}),
           ...getLanguageCustomSettings('typescript', config),
           ...getLanguageCustomSettings(config.script.language, config),
         }),

From 6daace7f4196e05b9704adfedadedae39cd69187 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Sun, 21 Jan 2024 17:48:32 +0200
Subject: [PATCH 04/30] feat(compilers): render React component if it is the
 default export

---
 src/livecodes/languages/jsx/jsx-runtime.ts    | 11 +++++++++
 .../languages/typescript/lang-typescript.ts   | 14 +++++++----
 src/livecodes/result/result-page.ts           | 24 ++++++++++++++++---
 3 files changed, 42 insertions(+), 7 deletions(-)
 create mode 100644 src/livecodes/languages/jsx/jsx-runtime.ts

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
new file mode 100644
index 000000000..fdcf8130b
--- /dev/null
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -0,0 +1,11 @@
+export const reactRuntime = `
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from './script';
+const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')));
+root.render(React.createElement(App, null));
+`;
+
+export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
+
+export const hasDefaultExport = (code: string) => new RegExp(/export\s*default\s/).test(code);
diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index e6c826dcd..7a6464900 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -2,6 +2,8 @@ import type { LanguageSpecs } from '../../models';
 import { typescriptUrl } from '../../vendors';
 import { getLanguageCustomSettings } from '../../utils';
 import { parserPlugins } from '../prettier';
+// eslint-disable-next-line import/no-internal-modules
+import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
@@ -22,12 +24,16 @@ export const typescript: LanguageSpecs = {
     url: typescriptUrl,
     factory:
       () =>
-      async (code, { config, language }) =>
-        (window as any).ts.transpile(code, {
+      async (code, { config }) => {
+        if (['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)) {
+          code = `import React from 'react';\n${code}`;
+        }
+        return (window as any).ts.transpile(code, {
           ...typescriptOptions,
           ...getLanguageCustomSettings('typescript', config),
-          ...getLanguageCustomSettings(language, config),
-        }),
+          ...getLanguageCustomSettings(config.script.language, config),
+        });
+      },
   },
   extensions: ['ts', 'typescript'],
   editor: 'script',
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 5ca39a638..c13d70e76 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -1,3 +1,4 @@
+/* eslint-disable import/no-internal-modules */
 import {
   createImportMap,
   createCSSModulesImportMap,
@@ -7,9 +8,9 @@ import {
   removeImports,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
+import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
 import type { Cache, EditorId, Config, CompileInfo } from '../models';
 import { getAppCDN, modulesService } from '../services';
-// eslint-disable-next-line import/no-internal-modules
 import { testImports } from '../toolspane/test-imports';
 import {
   addAttrs,
@@ -156,6 +157,12 @@ export const createResultPage = async ({
     getImports(markup).includes('./script') ||
     (runTests && !forExport && getImports(compiledTests).includes('./script'));
 
+  const shouldInsertReactJsxRuntime =
+    ['jsx', 'tsx'].includes(code.script.language) &&
+    hasDefaultExport(code.script.compiled) &&
+    !hasCustomJsxRuntime(code.script.content || '') &&
+    !importFromScript;
+
   let compilerImports = {};
 
   for (const { language, compiled } of runtimeDependencies) {
@@ -218,10 +225,13 @@ export const createResultPage = async ({
           ...(hasImports(code.markup.compiled)
             ? createImportMap(code.markup.compiled, config)
             : {}),
+          ...(shouldInsertReactJsxRuntime ? createImportMap(reactRuntime, config) : {}),
           ...(runTests && !forExport && hasImports(compiledTests)
             ? createImportMap(compiledTests, config)
             : {}),
-          ...(importFromScript ? { './script': toDataUrl(code.script.compiled) } : {}),
+          ...(importFromScript || shouldInsertReactJsxRuntime
+            ? { './script': toDataUrl(code.script.compiled) }
+            : {}),
           ...createCSSModulesImportMap(
             code.script.compiled,
             code.style.compiled,
@@ -263,7 +273,7 @@ export const createResultPage = async ({
     dom.head.appendChild(externalScript);
   });
 
-  if (!importFromScript) {
+  if (!importFromScript && !shouldInsertReactJsxRuntime) {
     // editor script
     const script = code.script.compiled;
     const scriptElement = dom.createElement('script');
@@ -288,6 +298,14 @@ export const createResultPage = async ({
     }
   }
 
+  // React JSX runtime
+  if (shouldInsertReactJsxRuntime) {
+    const jsxRuntimeScript = dom.createElement('script');
+    jsxRuntimeScript.type = 'module';
+    jsxRuntimeScript.innerHTML = reactRuntime;
+    dom.body.appendChild(jsxRuntimeScript);
+  }
+
   // spacing
   if (config.showSpacing && !forExport) {
     const spacingScript = dom.createElement('script');

From e46450dd39919415e48896d27dd27ab66a69a417 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Sun, 21 Jan 2024 17:48:32 +0200
Subject: [PATCH 05/30] feat(compilers): set typescript option { jsx:
 'react-jsx' }

---
 src/livecodes/languages/jsx/jsx-runtime.ts          |  4 ++--
 .../languages/typescript/lang-typescript.ts         | 13 +++++--------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
index fdcf8130b..33cee2a7d 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -1,9 +1,9 @@
 export const reactRuntime = `
-import React from "react";
+import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
 import App from './script';
 const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')));
-root.render(React.createElement(App, null));
+root.render(_jsx(App, {}));
 `;
 
 export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index 7a6464900..bb8c578c6 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -7,7 +7,7 @@ import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
-  jsx: 'react',
+  jsx: 'react-jsx',
   allowUmdGlobalAccess: true,
   esModuleInterop: true,
 };
@@ -24,16 +24,13 @@ export const typescript: LanguageSpecs = {
     url: typescriptUrl,
     factory:
       () =>
-      async (code, { config }) => {
-        if (['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)) {
-          code = `import React from 'react';\n${code}`;
-        }
-        return (window as any).ts.transpile(code, {
+      async (code, { config }) =>
+        (window as any).ts.transpile(code, {
           ...typescriptOptions,
+          ...(hasCustomJsxRuntime(code) ? { jsx: 'react' } : {}),
           ...getLanguageCustomSettings('typescript', config),
           ...getLanguageCustomSettings(config.script.language, config),
-        });
-      },
+        }),
   },
   extensions: ['ts', 'typescript'],
   editor: 'script',

From d83c668f600c140cf04843beaea7b9727af78a72 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Sun, 21 Jan 2024 17:48:32 +0200
Subject: [PATCH 06/30] only apply {jsx: 'react-jsx'} if language is JSX or TSX
 this avoids interfering with other languages (e.g. Vue with JSX)

---
 src/livecodes/languages/typescript/lang-typescript.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index bb8c578c6..16ac76dda 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -7,7 +7,7 @@ import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
 
 export const typescriptOptions = {
   target: 'es2015',
-  jsx: 'react-jsx',
+  jsx: 'react',
   allowUmdGlobalAccess: true,
   esModuleInterop: true,
 };
@@ -27,7 +27,9 @@ export const typescript: LanguageSpecs = {
       async (code, { config }) =>
         (window as any).ts.transpile(code, {
           ...typescriptOptions,
-          ...(hasCustomJsxRuntime(code) ? { jsx: 'react' } : {}),
+          ...(['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)
+            ? { jsx: 'react-jsx' }
+            : {}),
           ...getLanguageCustomSettings('typescript', config),
           ...getLanguageCustomSettings(config.script.language, config),
         }),

From 2e5b9d1d2e8af0c150426d57b249c8112477d5dc Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Sun, 21 Jan 2024 20:22:09 +0200
Subject: [PATCH 07/30] feat(Templates): update react and jest-react starter
 templates to use the new jsx runtime

---
 .../templates/starter/jest-react-starter.ts        | 14 ++++++--------
 src/livecodes/templates/starter/react-starter.ts   | 12 ++++++------
 2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/src/livecodes/templates/starter/jest-react-starter.ts b/src/livecodes/templates/starter/jest-react-starter.ts
index 9eb5e9619..c82c70b23 100644
--- a/src/livecodes/templates/starter/jest-react-starter.ts
+++ b/src/livecodes/templates/starter/jest-react-starter.ts
@@ -8,9 +8,7 @@ export const jestReactStarter: Template = {
   autotest: true,
   markup: {
     language: 'html',
-    content: `
-<div id="app">Loading...</div>
-`.trimStart(),
+    content: '',
   },
   style: {
     language: 'css',
@@ -33,12 +31,11 @@ export const jestReactStarter: Template = {
   script: {
     language: 'jsx',
     content: `
-import React, { useState } from "react";
-import { createRoot } from "react-dom/client";
+import { useState } from "react";
 
 export const increment = (count) => (count ?? 0) + 1;
 
-export default function App(props) {
+function Counter(props) {
   const [count, setCount] = useState(0);
   return (
     <div className="container">
@@ -51,8 +48,9 @@ export default function App(props) {
   );
 }
 
-const root = createRoot(document.querySelector("#app"));
-root.render(<App name="Jest with React" />);
+export default function App() {
+  return <Counter name="Jest with React" />;
+}
 `.trimStart(),
   },
   tests: {
diff --git a/src/livecodes/templates/starter/react-starter.ts b/src/livecodes/templates/starter/react-starter.ts
index fd2b0fa2a..db497a1c3 100644
--- a/src/livecodes/templates/starter/react-starter.ts
+++ b/src/livecodes/templates/starter/react-starter.ts
@@ -7,7 +7,7 @@ export const reactStarter: Template = {
   activeEditor: 'script',
   markup: {
     language: 'html',
-    content: '<div id="app">Loading...</div>\n',
+    content: '',
   },
   style: {
     language: 'css',
@@ -25,10 +25,9 @@ export const reactStarter: Template = {
   script: {
     language: 'jsx',
     content: `
-import React, { useState } from "react";
-import { createRoot } from "react-dom/client";
+import { useState } from "react";
 
-function App(props) {
+function Counter(props) {
   const [count, setCount] = useState(0);
   return (
     <div className="container">
@@ -40,8 +39,9 @@ function App(props) {
   );
 }
 
-const root = createRoot(document.querySelector("#app"));
-root.render(<App name="React" />);
+export default function App() {
+  return <Counter name="React" />;
+}
 `.trimStart(),
   },
   stylesheets: [],

From 40a96c7148d5a41e029442e408142aa9b3d7772b Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Mon, 22 Jan 2024 01:14:04 +0200
Subject: [PATCH 08/30] only render jsx default export if it is a react
 component

---
 src/livecodes/languages/jsx/jsx-runtime.ts | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
index 33cee2a7d..0287dd57c 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -1,9 +1,13 @@
 export const reactRuntime = `
 import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
-import App from './script';
-const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')));
-root.render(_jsx(App, {}));
+import App from "./script";
+(() => {
+  const isReactComponent = (c) => typeof c === "function" && (/return\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype.isReactComponent));
+  if (!isReactComponent(App)) return;
+  const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
+  root.render(_jsx(App, {}));
+})();
 `;
 
 export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);

From 7db03f6e39a05beb56d51c8d1798564b0f52536f Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 01:12:43 +0200
Subject: [PATCH 09/30] feat(compilers): render react-native component if it is
 the default export

---
 .../languages/react-native/jsx-runtime.ts     | 11 ++++++++
 .../react-native/lang-react-native-tsx.ts     | 21 ++-------------
 .../react-native/lang-react-native.ts         |  3 ++-
 src/livecodes/result/result-page.ts           | 26 +++++++++++++------
 .../templates/starter/react-native-starter.ts | 14 +++-------
 5 files changed, 37 insertions(+), 38 deletions(-)
 create mode 100644 src/livecodes/languages/react-native/jsx-runtime.ts

diff --git a/src/livecodes/languages/react-native/jsx-runtime.ts b/src/livecodes/languages/react-native/jsx-runtime.ts
new file mode 100644
index 000000000..6f0794030
--- /dev/null
+++ b/src/livecodes/languages/react-native/jsx-runtime.ts
@@ -0,0 +1,11 @@
+export const reactNativeRuntime = `
+import { AppRegistry } from "react-native";
+import App from "./script";
+(() => {
+  const isReactComponent = (c) => typeof c === "function" && (/return\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype.isReactComponent));
+  if (!isReactComponent(App)) return;
+  const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
+  AppRegistry.registerComponent("App", () => App);
+  AppRegistry.runApplication("App", { rootTag });
+})();
+`;
diff --git a/src/livecodes/languages/react-native/lang-react-native-tsx.ts b/src/livecodes/languages/react-native/lang-react-native-tsx.ts
index fe008dbef..8e55b94df 100644
--- a/src/livecodes/languages/react-native/lang-react-native-tsx.ts
+++ b/src/livecodes/languages/react-native/lang-react-native-tsx.ts
@@ -1,32 +1,15 @@
 import type { LanguageSpecs } from '../../models';
-import { typescriptOptions } from '../typescript';
-import { getLanguageCustomSettings } from '../utils';
 import { parserPlugins } from '../prettier';
-import { reactNativeWebUrl } from './lang-react-native';
 
 export const reactNativeTsx: LanguageSpecs = {
   name: 'react-native-tsx',
   title: 'RN (TSX)',
   longTitle: 'React Native (TSX)',
   parser: {
-    name: 'babel',
+    name: 'babel-ts',
     pluginUrls: [parserPlugins.babel, parserPlugins.html],
   },
-  compiler: {
-    dependencies: ['typescript'],
-    factory:
-      () =>
-      async (code, { config, language }) =>
-        (window as any).ts.transpile(code, {
-          ...typescriptOptions,
-          ...getLanguageCustomSettings('typescript', config),
-          ...getLanguageCustomSettings(language, config),
-        }),
-    imports: {
-      react: reactNativeWebUrl,
-      'react-native': reactNativeWebUrl,
-    },
-  },
+  compiler: 'react-native',
   extensions: ['react-native.tsx'],
   editor: 'script',
   editorLanguage: 'typescript',
diff --git a/src/livecodes/languages/react-native/lang-react-native.ts b/src/livecodes/languages/react-native/lang-react-native.ts
index 3ca25ff2b..c345b8820 100644
--- a/src/livecodes/languages/react-native/lang-react-native.ts
+++ b/src/livecodes/languages/react-native/lang-react-native.ts
@@ -4,7 +4,7 @@ import { typescriptOptions } from '../typescript';
 import { getLanguageCustomSettings } from '../utils';
 import { parserPlugins } from '../prettier';
 
-export const reactNativeWebUrl = vendorsBaseUrl + 'react-native-web/react-native-web.js';
+const reactNativeWebUrl = vendorsBaseUrl + 'react-native-web/react-native-web.js';
 
 export const reactNative: LanguageSpecs = {
   name: 'react-native',
@@ -21,6 +21,7 @@ export const reactNative: LanguageSpecs = {
       async (code, { config, language }) =>
         (window as any).ts.transpile(code, {
           ...typescriptOptions,
+          ...{ jsx: 'react-jsx' },
           ...getLanguageCustomSettings('typescript', config),
           ...getLanguageCustomSettings(language, config),
         }),
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index c13d70e76..bf559d4cc 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -9,7 +9,8 @@ import {
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
 import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
-import type { Cache, EditorId, Config, CompileInfo } from '../models';
+import { reactNativeRuntime } from '../languages/react-native/jsx-runtime';
+import type { Cache, EditorId, Config, CompileInfo, Language } from '../models';
 import { getAppCDN, modulesService } from '../services';
 import { testImports } from '../toolspane/test-imports';
 import {
@@ -157,8 +158,17 @@ export const createResultPage = async ({
     getImports(markup).includes('./script') ||
     (runTests && !forExport && getImports(compiledTests).includes('./script'));
 
-  const shouldInsertReactJsxRuntime =
-    ['jsx', 'tsx'].includes(code.script.language) &&
+  const jsxRuntimes: Partial<Record<Language, string>> = {
+    jsx: reactRuntime,
+    tsx: reactRuntime,
+    'react-native': reactNativeRuntime,
+    'react-native-tsx': reactNativeRuntime,
+    solid: '',
+    'solid.tsx': '',
+  };
+  const jsxRuntime = jsxRuntimes[code.script.language] || '';
+  const shouldInsertJsxRuntime =
+    Object.keys(jsxRuntimes).includes(code.script.language) &&
     hasDefaultExport(code.script.compiled) &&
     !hasCustomJsxRuntime(code.script.content || '') &&
     !importFromScript;
@@ -225,11 +235,11 @@ export const createResultPage = async ({
           ...(hasImports(code.markup.compiled)
             ? createImportMap(code.markup.compiled, config)
             : {}),
-          ...(shouldInsertReactJsxRuntime ? createImportMap(reactRuntime, config) : {}),
+          ...(shouldInsertJsxRuntime ? createImportMap(jsxRuntime, config) : {}),
           ...(runTests && !forExport && hasImports(compiledTests)
             ? createImportMap(compiledTests, config)
             : {}),
-          ...(importFromScript || shouldInsertReactJsxRuntime
+          ...(importFromScript || shouldInsertJsxRuntime
             ? { './script': toDataUrl(code.script.compiled) }
             : {}),
           ...createCSSModulesImportMap(
@@ -273,7 +283,7 @@ export const createResultPage = async ({
     dom.head.appendChild(externalScript);
   });
 
-  if (!importFromScript && !shouldInsertReactJsxRuntime) {
+  if (!importFromScript && !shouldInsertJsxRuntime) {
     // editor script
     const script = code.script.compiled;
     const scriptElement = dom.createElement('script');
@@ -299,10 +309,10 @@ export const createResultPage = async ({
   }
 
   // React JSX runtime
-  if (shouldInsertReactJsxRuntime) {
+  if (shouldInsertJsxRuntime) {
     const jsxRuntimeScript = dom.createElement('script');
     jsxRuntimeScript.type = 'module';
-    jsxRuntimeScript.innerHTML = reactRuntime;
+    jsxRuntimeScript.innerHTML = jsxRuntime;
     dom.body.appendChild(jsxRuntimeScript);
   }
 
diff --git a/src/livecodes/templates/starter/react-native-starter.ts b/src/livecodes/templates/starter/react-native-starter.ts
index f22e097d8..7d56f3d78 100644
--- a/src/livecodes/templates/starter/react-native-starter.ts
+++ b/src/livecodes/templates/starter/react-native-starter.ts
@@ -7,7 +7,7 @@ export const reactNativeStarter: Template = {
   activeEditor: 'script',
   markup: {
     language: 'html',
-    content: '<div id="app">Loading...</div>\n',
+    content: '',
   },
   style: {
     language: 'css',
@@ -16,8 +16,8 @@ export const reactNativeStarter: Template = {
   script: {
     language: 'react-native',
     content: `
-import React, { useState } from "react";
-import { AppRegistry, Button, Image, StyleSheet, Text, View } from "react-native";
+import { useState } from "react";
+import { Button, Image, StyleSheet, Text, View } from "react-native";
 
 const logoUri = \`data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z" /><circle cx="420.9" cy="296.5" r="45.7" /><path d="M520.5 78.1z" /></g></svg>\`;
 
@@ -41,7 +41,7 @@ function Counter(props) {
   );
 }
 
-function App() {
+export default function App() {
   return (
     <View style={styles.app}>
       <View style={styles.header}>
@@ -92,12 +92,6 @@ const styles = StyleSheet.create({
     color: "#1B95E0",
   },
 });
-
-AppRegistry.registerComponent("App", () => App);
-
-AppRegistry.runApplication("App", {
-  rootTag: document.getElementById("app"),
-});
 `.trimStart(),
   },
   stylesheets: [],

From 4968f036b6062293d6580eab593f4a99cc83ea14 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 02:04:34 +0200
Subject: [PATCH 10/30] feat(compilers): render Solid component if it is the
 default export

---
 src/livecodes/languages/solid/jsx-runtime.ts  | 10 +++++++
 .../languages/solid/lang-solid-tsx.ts         |  2 +-
 src/livecodes/result/result-page.ts           |  5 ++--
 .../templates/starter/solid-starter.ts        | 30 ++++++++++++-------
 4 files changed, 33 insertions(+), 14 deletions(-)
 create mode 100644 src/livecodes/languages/solid/jsx-runtime.ts

diff --git a/src/livecodes/languages/solid/jsx-runtime.ts b/src/livecodes/languages/solid/jsx-runtime.ts
new file mode 100644
index 000000000..05f5f7fa9
--- /dev/null
+++ b/src/livecodes/languages/solid/jsx-runtime.ts
@@ -0,0 +1,10 @@
+export const solidRuntime = `
+import { render, createComponent } from "solid-js/web";
+import App from "./script";
+(() => {
+  const isSolidComponent = (c) => typeof c === "function" && /return\\s+\\(?\\s*function\\s+\\(\\)\\s+{/g.test(String(c));
+  if (!isSolidComponent(App)) return;
+  const root = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
+  render(() => createComponent(App, {}), root);
+})();
+`;
diff --git a/src/livecodes/languages/solid/lang-solid-tsx.ts b/src/livecodes/languages/solid/lang-solid-tsx.ts
index d07af1c3d..bde8639ca 100644
--- a/src/livecodes/languages/solid/lang-solid-tsx.ts
+++ b/src/livecodes/languages/solid/lang-solid-tsx.ts
@@ -5,7 +5,7 @@ export const solidTsx: LanguageSpecs = {
   name: 'solid.tsx',
   title: 'Solid (TS)',
   parser: {
-    name: 'babel',
+    name: 'babel-ts',
     pluginUrls: [parserPlugins.babel, parserPlugins.html],
   },
   compiler: 'solid',
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index bf559d4cc..4f163f5a8 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -10,6 +10,7 @@ import {
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
 import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
 import { reactNativeRuntime } from '../languages/react-native/jsx-runtime';
+import { solidRuntime } from '../languages/solid/jsx-runtime';
 import type { Cache, EditorId, Config, CompileInfo, Language } from '../models';
 import { getAppCDN, modulesService } from '../services';
 import { testImports } from '../toolspane/test-imports';
@@ -163,8 +164,8 @@ export const createResultPage = async ({
     tsx: reactRuntime,
     'react-native': reactNativeRuntime,
     'react-native-tsx': reactNativeRuntime,
-    solid: '',
-    'solid.tsx': '',
+    solid: solidRuntime,
+    'solid.tsx': solidRuntime,
   };
   const jsxRuntime = jsxRuntimes[code.script.language] || '';
   const shouldInsertJsxRuntime =
diff --git a/src/livecodes/templates/starter/solid-starter.ts b/src/livecodes/templates/starter/solid-starter.ts
index 257a3c369..d2f33e09a 100644
--- a/src/livecodes/templates/starter/solid-starter.ts
+++ b/src/livecodes/templates/starter/solid-starter.ts
@@ -7,7 +7,7 @@ export const solidStarter: Template = {
   activeEditor: 'script',
   markup: {
     language: 'html',
-    content: '<div id="app"></div>\n',
+    content: '',
   },
   style: {
     language: 'css',
@@ -25,28 +25,36 @@ export const solidStarter: Template = {
   script: {
     language: 'solid.tsx',
     content: `
-import { render } from "solid-js/web";
 import { createSignal } from "solid-js";
 
-type Props = {
-  title: string;
+function Greeting(props: { name: string }) {
+  return (
+    <>
+      <h1>Hello, {props.name}!</h1>
+      <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/solid.svg" />
+    </>
+  );
 }
 
-function App(props: Props) {
+function Counter() {
   const [count, setCount] = createSignal(0);
   const increment = () => setCount(count() + 1);
-
   return (
-    <div className="container">
-      <h1>Hello, {props.title}!</h1>
-      <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/solid.svg" />
+    <>
       <p>You clicked {count()} times.</p>
       <button onClick={increment}>Click me</button>
-    </div>
+    </>
   );
 }
 
-render(() => <App title="Solid" />, document.getElementById("app"));
+export default function App() {
+  return (
+    <div className="container">
+      <Greeting name="Solid" />
+      <Counter />
+    </div>
+  );
+}
 `.trimStart(),
   },
   stylesheets: [],

From 32270d801683dd556412e8396de6e56f19702431 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 02:56:20 +0200
Subject: [PATCH 11/30] feat(compilers): allow using JSX fragments in Vue SFC

---
 src/livecodes/languages/vue/lang-vue-compiler.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/livecodes/languages/vue/lang-vue-compiler.ts b/src/livecodes/languages/vue/lang-vue-compiler.ts
index a3aa970a6..b3dee4bd4 100644
--- a/src/livecodes/languages/vue/lang-vue-compiler.ts
+++ b/src/livecodes/languages/vue/lang-vue-compiler.ts
@@ -246,7 +246,7 @@ import { getLanguageByAlias } from '../utils';
           attrs.toLowerCase().includes("'jsx'") ||
           attrs.toLowerCase().includes("'tsx'")
         ) {
-          scriptContent = 'import { h } from "vue";\n' + scriptContent;
+          scriptContent = 'import { h, Fragment } from "vue";\n' + scriptContent;
         }
         return `<script ${attrs}>${scriptContent}</script>`;
       });
@@ -254,6 +254,7 @@ import { getLanguageByAlias } from '../utils';
     config.customSettings.typescript = {
       ...config.customSettings.typescript,
       jsxFactory: 'h',
+      jsxFragmentFactory: 'Fragment',
     };
 
     content = await compileAllBlocks(content, config, { prepareFn });

From 6f630c2d723c2a9d9d09044cdba368820c7536f4 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 02:56:53 +0200
Subject: [PATCH 12/30] edit starter templates

---
 .../templates/starter/mdx-starter.ts          | 10 ++++-----
 .../templates/starter/react-starter.ts        | 22 ++++++++++++++-----
 .../templates/starter/vue-sfc-starter.ts      | 10 +++++++--
 3 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/livecodes/templates/starter/mdx-starter.ts b/src/livecodes/templates/starter/mdx-starter.ts
index 11b446d6f..cad5da47b 100644
--- a/src/livecodes/templates/starter/mdx-starter.ts
+++ b/src/livecodes/templates/starter/mdx-starter.ts
@@ -8,9 +8,9 @@ export const mdxStarter: Template = {
   markup: {
     language: 'mdx',
     content: `
-import { Hello, Counter } from './script';
+import { Greeting, Counter } from './script';
 
-<Hello title="MDX" />
+<Greeting name="MDX" />
 
 ![MDX Logo]({{ __livecodes_baseUrl__ }}assets/templates/mdx.svg)
 
@@ -33,11 +33,11 @@ img {
   script: {
     language: 'jsx',
     content: `
-import React, { useState } from "react";
+import { useState } from "react";
 
-export const Hello = (props) => <h1>Hello, {props.title || "World"}!</h1>;
+export const Greeting = (props) => <h1>Hello, {props.name || "World"}!</h1>;
 
-export function Counter(props) {
+export function Counter() {
   const [count, setCount] = useState(0);
   return (
     <div>
diff --git a/src/livecodes/templates/starter/react-starter.ts b/src/livecodes/templates/starter/react-starter.ts
index db497a1c3..43fc1bca1 100644
--- a/src/livecodes/templates/starter/react-starter.ts
+++ b/src/livecodes/templates/starter/react-starter.ts
@@ -27,20 +27,32 @@ export const reactStarter: Template = {
     content: `
 import { useState } from "react";
 
-function Counter(props) {
-  const [count, setCount] = useState(0);
+function Greeting(props) {
   return (
-    <div className="container">
+    <>
       <h1>Hello, {props.name}!</h1>
       <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/react.svg" />
+    </>
+  );
+}
+
+function Counter() {
+  const [count, setCount] = useState(0);
+  return (
+    <>
       <p>You clicked {count} times.</p>
       <button onClick={() => setCount(count + 1)}>Click me</button>
-    </div>
+    </>
   );
 }
 
 export default function App() {
-  return <Counter name="React" />;
+  return (
+    <div className="container">
+      <Greeting name="React" />
+      <Counter />
+    </div>
+  );
 }
 `.trimStart(),
   },
diff --git a/src/livecodes/templates/starter/vue-sfc-starter.ts b/src/livecodes/templates/starter/vue-sfc-starter.ts
index 6dd83bdf6..caf750437 100644
--- a/src/livecodes/templates/starter/vue-sfc-starter.ts
+++ b/src/livecodes/templates/starter/vue-sfc-starter.ts
@@ -16,16 +16,22 @@ export const vueSfcStarter: Template = {
   script: {
     language: 'vue',
     content: `
-<script setup>
+<script setup lang="tsx">
   import { ref } from 'vue';
 
+  const name = 'Vue';
   const count = ref(0);
   const align = 'center';
+
+  // define inline component
+  function Greeting(props: {name: string}) {
+    return <h1>Hello, { props.name }!</h1>
+  }
 </script>
 
 <template>
   <div class="container">
-    <h1>Hello, Vue!</h1>
+    <Greeting :name="name" />
     <img class="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/vue.svg" />
     <p>You clicked {{ count }} times.</p>
     <button @click="count++">Click me</button>

From c853df67a07e5954f5e8f138f385ef02d0e82e95 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 03:20:17 +0200
Subject: [PATCH 13/30] fix jsx runtime code

---
 src/livecodes/languages/jsx/jsx-runtime.ts          | 2 +-
 src/livecodes/languages/react-native/jsx-runtime.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
index 0287dd57c..5de841c97 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
 import App from "./script";
 (() => {
-  const isReactComponent = (c) => typeof c === "function" && (/return\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype.isReactComponent));
+  const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype?.isReactComponent));
   if (!isReactComponent(App)) return;
   const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
   root.render(_jsx(App, {}));
diff --git a/src/livecodes/languages/react-native/jsx-runtime.ts b/src/livecodes/languages/react-native/jsx-runtime.ts
index 6f0794030..b02593671 100644
--- a/src/livecodes/languages/react-native/jsx-runtime.ts
+++ b/src/livecodes/languages/react-native/jsx-runtime.ts
@@ -2,7 +2,7 @@ export const reactNativeRuntime = `
 import { AppRegistry } from "react-native";
 import App from "./script";
 (() => {
-  const isReactComponent = (c) => typeof c === "function" && (/return\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype.isReactComponent));
+  const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype?.isReactComponent));
   if (!isReactComponent(App)) return;
   const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
   AppRegistry.registerComponent("App", () => App);

From 89111d00290f2b562ae893d651973aba12c2a508 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 04:20:36 +0200
Subject: [PATCH 14/30] remove `import './styles.css'` from script

---
 src/livecodes/compiler/import-map.ts | 3 +++
 src/livecodes/result/result-page.ts  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/src/livecodes/compiler/import-map.ts b/src/livecodes/compiler/import-map.ts
index ed07b62dc..571c68070 100644
--- a/src/livecodes/compiler/import-map.ts
+++ b/src/livecodes/compiler/import-map.ts
@@ -199,6 +199,9 @@ export const removeImports = (code: string, mods: string[]) =>
     return mods.includes(libName) ? '' : statement;
   });
 
+export const removeSideEffectStyleImports = (code: string) =>
+  code.replace(/import\s+["']\.\/style(s)?\.(css|less|sass|scss)["'];?/g, '');
+
 export const styleimportsPattern =
   /(?:@import\s+?)((?:".*?")|(?:'.*?')|(?:url\('.*?'\))|(?:url\(".*?"\)))(.*)?;/g;
 
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 4f163f5a8..83fc9208c 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -6,6 +6,7 @@ import {
   hasImports,
   isModuleScript,
   removeImports,
+  removeSideEffectStyleImports,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
 import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
@@ -118,6 +119,7 @@ export const createResultPage = async ({
     dom.head.appendChild(stylesheet);
   });
   code.script.compiled = removeImports(code.script.compiled, stylesheetImports);
+  code.script.compiled = removeSideEffectStyleImports(code.script.compiled);
 
   // editor styles
   if (singleFile) {

From d6a1803a7825d31af6c2ed9b0727cd8537c9a691 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 05:20:37 +0200
Subject: [PATCH 15/30] fix

---
 src/livecodes/compiler/import-map.ts       |  4 +++-
 src/livecodes/languages/jsx/jsx-runtime.ts |  2 --
 src/livecodes/result/result-page.ts        | 11 ++++++++---
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/livecodes/compiler/import-map.ts b/src/livecodes/compiler/import-map.ts
index 571c68070..0ae45311f 100644
--- a/src/livecodes/compiler/import-map.ts
+++ b/src/livecodes/compiler/import-map.ts
@@ -90,6 +90,8 @@ export const hasImports = (code: string) => getImports(code).length > 0;
 export const hasExports = (code: string) =>
   new RegExp(/(^export\s)|([\s|;]export\s)/).test(removeCommentsAndStrings(code));
 
+export const hasDefaultExport = (code: string) => new RegExp(/export\s*default\s/).test(code);
+
 export const hasUrlImportsOrExports = (code: string) =>
   new RegExp(
     /((?:import|export)\s+?(?:(?:(?:[\w*\s{},\$]*)\s+from\s+?)|))((?:"(?:\.|http|\/).*?")|(?:'(?:\.|http|\/).*?'))([\s]*?(?:;|$|))/,
@@ -199,7 +201,7 @@ export const removeImports = (code: string, mods: string[]) =>
     return mods.includes(libName) ? '' : statement;
   });
 
-export const removeSideEffectStyleImports = (code: string) =>
+export const removeEditorStylesImport = (code: string) =>
   code.replace(/import\s+["']\.\/style(s)?\.(css|less|sass|scss)["'];?/g, '');
 
 export const styleimportsPattern =
diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/jsx-runtime.ts
index 5de841c97..a8f103ebf 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/jsx-runtime.ts
@@ -11,5 +11,3 @@ import App from "./script";
 `;
 
 export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
-
-export const hasDefaultExport = (code: string) => new RegExp(/export\s*default\s/).test(code);
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 83fc9208c..e56f32fa4 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -6,10 +6,12 @@ import {
   hasImports,
   isModuleScript,
   removeImports,
-  removeSideEffectStyleImports,
+  // avoid default exports conflict
+  removeEditorStylesImport,
+  hasDefaultExport,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
-import { hasCustomJsxRuntime, hasDefaultExport, reactRuntime } from '../languages/jsx/jsx-runtime';
+import { hasCustomJsxRuntime, reactRuntime } from '../languages/jsx/jsx-runtime';
 import { reactNativeRuntime } from '../languages/react-native/jsx-runtime';
 import { solidRuntime } from '../languages/solid/jsx-runtime';
 import type { Cache, EditorId, Config, CompileInfo, Language } from '../models';
@@ -119,7 +121,10 @@ export const createResultPage = async ({
     dom.head.appendChild(stylesheet);
   });
   code.script.compiled = removeImports(code.script.compiled, stylesheetImports);
-  code.script.compiled = removeSideEffectStyleImports(code.script.compiled);
+  if (hasDefaultExport(code.script.compiled)) {
+    // avoid default exports conflict
+    code.script.compiled = removeEditorStylesImport(code.script.compiled);
+  }
 
   // editor styles
   if (singleFile) {

From dd5167d4945679cf04c48932ca9356ec0d236fd5 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Tue, 23 Jan 2024 13:46:46 +0200
Subject: [PATCH 16/30] improve detecting custom JSX runtime

---
 .../jsx/{jsx-runtime.ts => react-runtime.ts}   |  2 --
 ...{jsx-runtime.ts => react-native-runtime.ts} |  0
 .../solid/{jsx-runtime.ts => solid-runtime.ts} |  0
 .../languages/typescript/lang-typescript.ts    | 18 ++++++++++++++----
 src/livecodes/result/result-page.ts            |  9 +++++----
 5 files changed, 19 insertions(+), 10 deletions(-)
 rename src/livecodes/languages/jsx/{jsx-runtime.ts => react-runtime.ts} (84%)
 rename src/livecodes/languages/react-native/{jsx-runtime.ts => react-native-runtime.ts} (100%)
 rename src/livecodes/languages/solid/{jsx-runtime.ts => solid-runtime.ts} (100%)

diff --git a/src/livecodes/languages/jsx/jsx-runtime.ts b/src/livecodes/languages/jsx/react-runtime.ts
similarity index 84%
rename from src/livecodes/languages/jsx/jsx-runtime.ts
rename to src/livecodes/languages/jsx/react-runtime.ts
index a8f103ebf..75eda3f5e 100644
--- a/src/livecodes/languages/jsx/jsx-runtime.ts
+++ b/src/livecodes/languages/jsx/react-runtime.ts
@@ -9,5 +9,3 @@ import App from "./script";
   root.render(_jsx(App, {}));
 })();
 `;
-
-export const hasCustomJsxRuntime = (code: string) => new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code);
diff --git a/src/livecodes/languages/react-native/jsx-runtime.ts b/src/livecodes/languages/react-native/react-native-runtime.ts
similarity index 100%
rename from src/livecodes/languages/react-native/jsx-runtime.ts
rename to src/livecodes/languages/react-native/react-native-runtime.ts
diff --git a/src/livecodes/languages/solid/jsx-runtime.ts b/src/livecodes/languages/solid/solid-runtime.ts
similarity index 100%
rename from src/livecodes/languages/solid/jsx-runtime.ts
rename to src/livecodes/languages/solid/solid-runtime.ts
diff --git a/src/livecodes/languages/typescript/lang-typescript.ts b/src/livecodes/languages/typescript/lang-typescript.ts
index 16ac76dda..b00e3f30c 100644
--- a/src/livecodes/languages/typescript/lang-typescript.ts
+++ b/src/livecodes/languages/typescript/lang-typescript.ts
@@ -1,9 +1,19 @@
-import type { LanguageSpecs } from '../../models';
+import type { Config, LanguageSpecs } from '../../models';
 import { typescriptUrl } from '../../vendors';
 import { getLanguageCustomSettings } from '../../utils';
 import { parserPlugins } from '../prettier';
-// eslint-disable-next-line import/no-internal-modules
-import { hasCustomJsxRuntime } from '../jsx/jsx-runtime';
+
+export const hasCustomJsxRuntime = (code: string, config: Config) => {
+  const customTSConfig = {
+    ...getLanguageCustomSettings('typescript', config),
+    ...getLanguageCustomSettings(config.script.language, config),
+  };
+  return Boolean(
+    customTSConfig.jsx ||
+      customTSConfig.jsxFactory ||
+      new RegExp(/\/\*\*[\s\*]*@jsx\s/g).test(code),
+  );
+};
 
 export const typescriptOptions = {
   target: 'es2015',
@@ -27,7 +37,7 @@ export const typescript: LanguageSpecs = {
       async (code, { config }) =>
         (window as any).ts.transpile(code, {
           ...typescriptOptions,
-          ...(['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code)
+          ...(['jsx', 'tsx'].includes(config.script.language) && !hasCustomJsxRuntime(code, config)
             ? { jsx: 'react-jsx' }
             : {}),
           ...getLanguageCustomSettings('typescript', config),
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index e56f32fa4..552816572 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -11,9 +11,10 @@ import {
   hasDefaultExport,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
-import { hasCustomJsxRuntime, reactRuntime } from '../languages/jsx/jsx-runtime';
-import { reactNativeRuntime } from '../languages/react-native/jsx-runtime';
-import { solidRuntime } from '../languages/solid/jsx-runtime';
+import { hasCustomJsxRuntime } from '../languages/typescript';
+import { reactRuntime } from '../languages/jsx/react-runtime';
+import { reactNativeRuntime } from '../languages/react-native/react-native-runtime';
+import { solidRuntime } from '../languages/solid/solid-runtime';
 import type { Cache, EditorId, Config, CompileInfo, Language } from '../models';
 import { getAppCDN, modulesService } from '../services';
 import { testImports } from '../toolspane/test-imports';
@@ -178,7 +179,7 @@ export const createResultPage = async ({
   const shouldInsertJsxRuntime =
     Object.keys(jsxRuntimes).includes(code.script.language) &&
     hasDefaultExport(code.script.compiled) &&
-    !hasCustomJsxRuntime(code.script.content || '') &&
+    !hasCustomJsxRuntime(code.script.content || '', config) &&
     !importFromScript;
 
   let compilerImports = {};

From 3397a659c12349ea772d745db93501b62a257970 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 24 Jan 2024 00:05:35 +0200
Subject: [PATCH 17/30] test(compilers): add e2e tests for jsx

---
 docs/docs/languages/jsx.md           |  54 +++++++++-
 e2e/specs/jsx.spec.ts                | 156 +++++++++++++++++++++++++++
 src/livecodes/compiler/import-map.ts |   3 -
 src/livecodes/result/result-page.ts  |  24 +++--
 4 files changed, 225 insertions(+), 12 deletions(-)
 create mode 100644 e2e/specs/jsx.spec.ts

diff --git a/docs/docs/languages/jsx.md b/docs/docs/languages/jsx.md
index 8ebdc62bb..da26944d4 100644
--- a/docs/docs/languages/jsx.md
+++ b/docs/docs/languages/jsx.md
@@ -1,3 +1,55 @@
 # JSX
 
-TODO...
+## Usage
+
+## Language Info
+
+### Name
+
+`name`
+
+### Aliases
+
+### Extensions
+
+### Editor
+
+`script`
+
+## Compiler
+
+### Version
+
+## Code Formatting
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `name` are passed as a JSON object to the `compiler` during compile. Please check the [documentation](#) for full reference.
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "name": {}
+}
+```
+
+## Helper Methods
+
+## Live Reload
+
+## Limitations
+
+## Example Usage
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const params = {};
+
+<LiveCodes template="react"></LiveCodes>
+
+## Starter Template
+
+## Links
diff --git a/e2e/specs/jsx.spec.ts b/e2e/specs/jsx.spec.ts
new file mode 100644
index 000000000..cdd206037
--- /dev/null
+++ b/e2e/specs/jsx.spec.ts
@@ -0,0 +1,156 @@
+import { expect } from '@playwright/test';
+import { test } from '../test-fixtures';
+import { getLoadedApp } from '../helpers';
+
+test.describe('JSX', () => {
+  test('default export', async ({ page, getTestUrl }) => {
+    const jsx = `export default () => <h1>Hello, World!</h1>`;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('default export with named exports', async ({ page, getTestUrl }) => {
+    const jsx = `
+    export const name = 'World'
+    const App = () => <h1>Hello, \{name\}!</h1>
+    export default App
+    `;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('default export with style import', async ({ page, getTestUrl }) => {
+    const jsx = `
+    import "./style.css"
+    const App = () => <h1>Hello, World!</h1>
+    export default App
+    `;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('default export with style default import', async ({ page, getTestUrl }) => {
+    const jsx = `
+    import styles from "./style.css"
+    const App = () => <h1>{styles}</h1>
+    export default App
+    `;
+    const css = `h1 { color: red; }`;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), css: encodeURIComponent(css) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('red');
+  });
+
+  test('no default export', async ({ page, getTestUrl }) => {
+    const jsx = `
+    import React from "react";
+    import { createRoot } from "react-dom/client";
+
+    function App(props) {
+      return <h1>Hello, {props.name}!</h1>;
+    }
+
+    const root = createRoot(document.querySelector("#app"));
+    root.render(<App name="World" />);
+    `;
+    const html = '<div id="app"></div>';
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), html: encodeURIComponent(html) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('no default export & no react import', async ({ page, getTestUrl }) => {
+    const jsx = `
+    import { createRoot } from "react-dom/client";
+
+    function App(props) {
+      return <h1>Hello, {props.name}!</h1>;
+    }
+
+    const root = createRoot(document.querySelector("#app"));
+    root.render(<App name="World" />);
+    `;
+    const html = '<div id="app"></div>';
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), html: encodeURIComponent(html) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('add to markup', async ({ page, getTestUrl }) => {
+    const jsx = `export default () => <h1>Hello, World!</h1>`;
+    const html = '<div>hi</div>';
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), html: encodeURIComponent(html) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('add to specific element', async ({ page, getTestUrl }) => {
+    const jsx = `export default () => <h1>Hello, World!</h1>`;
+    const html = '<div id="livecodes-app"></div>';
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), html: encodeURIComponent(html) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    await getResult().waitForSelector('h1');
+    expect(await getResult().innerText('#livecodes-app')).toContain('Hello, World!');
+  });
+
+  test('import default export in markup', async ({ page, getTestUrl }) => {
+    const jsx = `export default \`Hello, World!\``;
+    const html = `
+    <script type="module">
+    import text from './script';
+    const h1 = document.createElement('h1');
+    h1.textContent = text;
+    document.body.appendChild(h1);
+    </script>
+    `;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx), html: encodeURIComponent(html) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+
+  test('custom runtime', async ({ page, getTestUrl }) => {
+    const jsx = `/** @jsx h */
+    import { h, render } from 'preact';
+    function App(props) {
+      return <h1>Hello, {props.name}!</h1>;
+    }
+    render(<App name="World" />, document.body);
+    `;
+
+    await page.goto(getTestUrl({ jsx: encodeURIComponent(jsx) }));
+    const { getResult, waitForResultUpdate } = await getLoadedApp(page);
+    await waitForResultUpdate();
+
+    expect(await getResult().innerText('h1')).toContain('Hello, World!');
+  });
+});
diff --git a/src/livecodes/compiler/import-map.ts b/src/livecodes/compiler/import-map.ts
index 0ae45311f..f4286e2cd 100644
--- a/src/livecodes/compiler/import-map.ts
+++ b/src/livecodes/compiler/import-map.ts
@@ -201,9 +201,6 @@ export const removeImports = (code: string, mods: string[]) =>
     return mods.includes(libName) ? '' : statement;
   });
 
-export const removeEditorStylesImport = (code: string) =>
-  code.replace(/import\s+["']\.\/style(s)?\.(css|less|sass|scss)["'];?/g, '');
-
 export const styleimportsPattern =
   /(?:@import\s+?)((?:".*?")|(?:'.*?')|(?:url\('.*?'\))|(?:url\(".*?"\)))(.*)?;/g;
 
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 552816572..7ce909fc7 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -7,8 +7,8 @@ import {
   isModuleScript,
   removeImports,
   // avoid default exports conflict
-  removeEditorStylesImport,
   hasDefaultExport,
+  replaceImports,
 } from '../compiler';
 import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages';
 import { hasCustomJsxRuntime } from '../languages/typescript';
@@ -23,6 +23,7 @@ import {
   escapeScript,
   getAbsoluteUrl,
   isRelativeUrl,
+  objectFilter,
   objectMap,
   toDataUrl,
 } from '../utils';
@@ -122,10 +123,6 @@ export const createResultPage = async ({
     dom.head.appendChild(stylesheet);
   });
   code.script.compiled = removeImports(code.script.compiled, stylesheetImports);
-  if (hasDefaultExport(code.script.compiled)) {
-    // avoid default exports conflict
-    code.script.compiled = removeEditorStylesImport(code.script.compiled);
-  }
 
   // editor styles
   if (singleFile) {
@@ -248,9 +245,6 @@ export const createResultPage = async ({
           ...(runTests && !forExport && hasImports(compiledTests)
             ? createImportMap(compiledTests, config)
             : {}),
-          ...(importFromScript || shouldInsertJsxRuntime
-            ? { './script': toDataUrl(code.script.compiled) }
-            : {}),
           ...createCSSModulesImportMap(
             code.script.compiled,
             code.style.compiled,
@@ -266,8 +260,22 @@ export const createResultPage = async ({
           ...compileInfo.imports,
         };
 
+  const scriptImport =
+    importFromScript || shouldInsertJsxRuntime
+      ? {
+          './script': toDataUrl(
+            replaceImports(
+              code.script.compiled,
+              config,
+              objectFilter(userImports, (_value, key) => key.startsWith('./')),
+            ),
+          ),
+        }
+      : {};
+
   const importMaps = {
     ...userImports,
+    ...scriptImport,
     ...compilerImports,
     ...(runTests ? testImports : {}),
     ...config.imports,

From aabfdee22aa72dac42b864cd12854a8ce64b2765 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 24 Jan 2024 12:04:17 +0200
Subject: [PATCH 18/30] improve detecting react jsx

---
 src/livecodes/languages/jsx/react-runtime.ts       | 14 ++++++++++----
 .../languages/react-native/react-native-runtime.ts | 12 +++++++-----
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/src/livecodes/languages/jsx/react-runtime.ts b/src/livecodes/languages/jsx/react-runtime.ts
index 75eda3f5e..9c358c6a7 100644
--- a/src/livecodes/languages/jsx/react-runtime.ts
+++ b/src/livecodes/languages/jsx/react-runtime.ts
@@ -1,11 +1,17 @@
+export const checkIsReact = (App: string) =>
+  `
+const removeComments = (src) => src.replace(/\\/\\*[\\s\\S]*?\\*\\/|([^\\\\:]|^)\\/\\/.*$/gm, '$1');
+const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(removeComments(String(c))) || Boolean(c.prototype?.isReactComponent));
+if (!isReactComponent(${App})) return;
+`.trim();
+
 export const reactRuntime = `
 import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
 import App from "./script";
 (() => {
-  const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype?.isReactComponent));
-  if (!isReactComponent(App)) return;
-  const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
-  root.render(_jsx(App, {}));
+${checkIsReact('App')}
+const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
+root.render(_jsx(App, {}));
 })();
 `;
diff --git a/src/livecodes/languages/react-native/react-native-runtime.ts b/src/livecodes/languages/react-native/react-native-runtime.ts
index b02593671..184971c0b 100644
--- a/src/livecodes/languages/react-native/react-native-runtime.ts
+++ b/src/livecodes/languages/react-native/react-native-runtime.ts
@@ -1,11 +1,13 @@
+// eslint-disable-next-line import/no-internal-modules
+import { checkIsReact } from '../jsx/react-runtime';
+
 export const reactNativeRuntime = `
 import { AppRegistry } from "react-native";
 import App from "./script";
 (() => {
-  const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(String(c)) || Boolean(c.prototype?.isReactComponent));
-  if (!isReactComponent(App)) return;
-  const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
-  AppRegistry.registerComponent("App", () => App);
-  AppRegistry.runApplication("App", { rootTag });
+${checkIsReact('App')}
+const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
+AppRegistry.registerComponent("App", () => App);
+AppRegistry.runApplication("App", { rootTag });
 })();
 `;

From e0c0fd917d8e6d86b1f6da3a342b242321e50b1f Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 24 Jan 2024 12:14:47 +0200
Subject: [PATCH 19/30] fix incorrect URLs in type bundling

---
 src/livecodes/types/bundle-types.ts | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/src/livecodes/types/bundle-types.ts b/src/livecodes/types/bundle-types.ts
index 641eb2f42..c3295a9c5 100644
--- a/src/livecodes/types/bundle-types.ts
+++ b/src/livecodes/types/bundle-types.ts
@@ -95,10 +95,6 @@ export async function bundle(options: Options): Promise<string> {
   assert(typeof prefix === 'string', 'option "prefix" must be a string');
   assert(separator.length > 0, 'option "separator" must have non-zero length');
 
-  // turn relative paths into absolute paths
-  const mainFile = main;
-  // const outFile = calcOutFilePath(out, baseDir);
-
   trace('### settings object passed ###');
   traceObject(options);
 
@@ -106,7 +102,7 @@ export async function bundle(options: Options): Promise<string> {
   trace('main:         %s', main);
   trace('name:         %s', exportName);
   trace('baseDir:      %s', baseDir);
-  trace('mainFile:     %s', mainFile);
+  trace('mainFile:     %s', main);
   trace('externals:    %s', externals ? 'yes' : 'no');
   trace('exclude:      %s', exclude);
   trace('comments:     %s', comments ? 'yes' : 'no');
@@ -133,9 +129,6 @@ export async function bundle(options: Options): Promise<string> {
   const inSourceTypings = (file: string) => file.startsWith(sourceRoot); // if file reference is a directory assume commonjs index.d.ts
 
   trace('source typings (will be included in output if actually used)');
-
-  // sourceTypings.forEach(file => trace(' - %s ', file));
-
   trace('excluded typings (will always be excluded from output)');
 
   const fileMap: { [name: string]: Result } = Object.create(null);
@@ -148,7 +141,7 @@ export async function bundle(options: Options): Promise<string> {
     // following all references and imports
     trace('\n### parse files ###');
 
-    const queue: string[] = [mainFile];
+    const queue: string[] = [main];
     const queueSeen: { [name: string]: boolean } = Object.create(null);
 
     while (queue.length > 0) {
@@ -436,7 +429,7 @@ export async function bundle(options: Options): Promise<string> {
   }
 
   function getExpName(file: string) {
-    if (file === mainFile) {
+    if (file === main) {
       return exportName;
     }
     return getExpNameRaw(file);
@@ -447,7 +440,7 @@ export async function bundle(options: Options): Promise<string> {
   }
 
   function getLibName(ref: string) {
-    return getExpNameRaw(mainFile) + separator + prefix + separator + ref;
+    return getExpNameRaw(main) + separator + prefix + separator + ref;
   }
 
   function cleanupName(name: string) {
@@ -489,6 +482,16 @@ export async function bundle(options: Options): Promise<string> {
       importLineRef: [],
       relativeRef: [],
     };
+    try {
+      const url = new URL(file);
+      const mainUrl = new URL(main);
+      if (url.origin !== mainUrl.origin && url.origin === window.location.origin) {
+        trace(' X - Invalid URL: %s', file);
+        throw new Error();
+      }
+    } catch {
+      return res;
+    }
     let response = await fetch(file);
     if (!response.ok) {
       // if file is a directory then lets assume commonjs convention of an index file in the given folder

From 104777fc245d1e9a298187c43575e01ceb79521d Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 24 Jan 2024 12:15:08 +0200
Subject: [PATCH 20/30] start jsx docs

---
 docs/docs/languages/jsx.md                    | 58 +++++++++++++------
 .../templates/starter/jest-react-starter.ts   |  4 +-
 .../templates/starter/react-starter.ts        |  4 +-
 3 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/docs/docs/languages/jsx.md b/docs/docs/languages/jsx.md
index da26944d4..d9b45bdc9 100644
--- a/docs/docs/languages/jsx.md
+++ b/docs/docs/languages/jsx.md
@@ -2,15 +2,43 @@
 
 ## Usage
 
+### Importing Modules
+
+### Exports
+
+### Styles
+
+#### CSS Processors
+
+#### Importing Styles
+
+#### CSS Modules
+
+#### CSS Frameworks
+
+[CSS Frameworks](../features/css.md#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.md), [UnoCSS](./unocss.md), [WindiCSS](./windicss.md)) are available for use in JSX. Make sure that the required utility is enabled (Style menu or `processors` property of [configuration object](../configuration/configuration-object.md#processors)) and required [directives](https://tailwindcss.com/docs/functions-and-directives#tailwind) are added to the style editor.
+
+Example:
+
+#### CSS-in-JS
+
+### Root Element
+
+To render the React components to a specific [root](https://react.dev/reference/react-dom/client/createRoot) DOM element use `livecodes-app` as the element ID. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used as the root.
+
+### Custom JSX Runtimes
+
+To [mount](https://vuejs.org/api/application.html#app-mount) the application instance to a specific DOM element use `livecodes-app` as the element ID. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance.
+
 ## Language Info
 
 ### Name
 
-`name`
+`jsx`
 
-### Aliases
+### Extension
 
-### Extensions
+`.jsx`
 
 ### Editor
 
@@ -18,10 +46,14 @@
 
 ## Compiler
 
+[TypeScript compiler](./typescript.md)
+
 ### Version
 
 ## Code Formatting
 
+Using [Prettier](https://prettier.io/).
+
 ## Custom Settings
 
 [Custom settings](../advanced/custom-settings.md) added to the property `name` are passed as a JSON object to the `compiler` during compile. Please check the [documentation](#) for full reference.
@@ -36,20 +68,12 @@ Please note that custom settings should be valid JSON (i.e. functions are not al
 }
 ```
 
-## Helper Methods
-
-## Live Reload
-
-## Limitations
-
-## Example Usage
-
-import LiveCodes from '../../src/components/LiveCodes.tsx';
-
-export const params = {};
-
-<LiveCodes template="react"></LiveCodes>
-
 ## Starter Template
 
+https://livecodes.io/?template=react
+
 ## Links
+
+- [React](https://react.dev/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [CSS Modules](https://github.com/css-modules/css-modules)
diff --git a/src/livecodes/templates/starter/jest-react-starter.ts b/src/livecodes/templates/starter/jest-react-starter.ts
index c82c70b23..467e31e24 100644
--- a/src/livecodes/templates/starter/jest-react-starter.ts
+++ b/src/livecodes/templates/starter/jest-react-starter.ts
@@ -48,9 +48,11 @@ function Counter(props) {
   );
 }
 
-export default function App() {
+function App() {
   return <Counter name="Jest with React" />;
 }
+
+export default App;
 `.trimStart(),
   },
   tests: {
diff --git a/src/livecodes/templates/starter/react-starter.ts b/src/livecodes/templates/starter/react-starter.ts
index 43fc1bca1..2fcdc82ff 100644
--- a/src/livecodes/templates/starter/react-starter.ts
+++ b/src/livecodes/templates/starter/react-starter.ts
@@ -46,7 +46,7 @@ function Counter() {
   );
 }
 
-export default function App() {
+function App() {
   return (
     <div className="container">
       <Greeting name="React" />
@@ -54,6 +54,8 @@ export default function App() {
     </div>
   );
 }
+
+export default App;
 `.trimStart(),
   },
   stylesheets: [],

From 0120bc36a80287ae403502039fa4a1d5ef446948 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 24 Jan 2024 23:14:30 +0200
Subject: [PATCH 21/30] simplify jsx runtime code

---
 src/livecodes/languages/jsx/react-runtime.ts  | 13 ++-------
 .../react-native/react-native-runtime.ts      | 11 +++-----
 .../languages/solid/solid-runtime.ts          |  3 +-
 .../templates/starter/jest-react-starter.ts   |  4 +--
 .../templates/starter/react-starter.ts        | 28 +++++--------------
 .../templates/starter/solid-starter.ts        | 24 ++++------------
 6 files changed, 22 insertions(+), 61 deletions(-)

diff --git a/src/livecodes/languages/jsx/react-runtime.ts b/src/livecodes/languages/jsx/react-runtime.ts
index 9c358c6a7..a0795498e 100644
--- a/src/livecodes/languages/jsx/react-runtime.ts
+++ b/src/livecodes/languages/jsx/react-runtime.ts
@@ -1,17 +1,10 @@
-export const checkIsReact = (App: string) =>
-  `
-const removeComments = (src) => src.replace(/\\/\\*[\\s\\S]*?\\*\\/|([^\\\\:]|^)\\/\\/.*$/gm, '$1');
-const isReactComponent = (c) => typeof c === "function" && (/(return|=>)\\s+\\(?\\s*(_jsx|React\\.createElement)/g.test(removeComments(String(c))) || Boolean(c.prototype?.isReactComponent));
-if (!isReactComponent(${App})) return;
-`.trim();
-
 export const reactRuntime = `
 import { jsx as _jsx } from "react/jsx-runtime";
 import { createRoot } from "react-dom/client";
 import App from "./script";
 (() => {
-${checkIsReact('App')}
-const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
-root.render(_jsx(App, {}));
+  if (typeof App !== "function") return;
+  const root = createRoot(document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div")));
+  root.render(_jsx(App, {}));
 })();
 `;
diff --git a/src/livecodes/languages/react-native/react-native-runtime.ts b/src/livecodes/languages/react-native/react-native-runtime.ts
index 184971c0b..2949bf314 100644
--- a/src/livecodes/languages/react-native/react-native-runtime.ts
+++ b/src/livecodes/languages/react-native/react-native-runtime.ts
@@ -1,13 +1,10 @@
-// eslint-disable-next-line import/no-internal-modules
-import { checkIsReact } from '../jsx/react-runtime';
-
 export const reactNativeRuntime = `
 import { AppRegistry } from "react-native";
 import App from "./script";
 (() => {
-${checkIsReact('App')}
-const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
-AppRegistry.registerComponent("App", () => App);
-AppRegistry.runApplication("App", { rootTag });
+  if (typeof App !== "function") return;
+  const rootTag = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
+  AppRegistry.registerComponent("App", () => App);
+  AppRegistry.runApplication("App", { rootTag });
 })();
 `;
diff --git a/src/livecodes/languages/solid/solid-runtime.ts b/src/livecodes/languages/solid/solid-runtime.ts
index 05f5f7fa9..ac75363b6 100644
--- a/src/livecodes/languages/solid/solid-runtime.ts
+++ b/src/livecodes/languages/solid/solid-runtime.ts
@@ -2,8 +2,7 @@ export const solidRuntime = `
 import { render, createComponent } from "solid-js/web";
 import App from "./script";
 (() => {
-  const isSolidComponent = (c) => typeof c === "function" && /return\\s+\\(?\\s*function\\s+\\(\\)\\s+{/g.test(String(c));
-  if (!isSolidComponent(App)) return;
+  if (typeof App !== "function") return;
   const root = document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement("div"));
   render(() => createComponent(App, {}), root);
 })();
diff --git a/src/livecodes/templates/starter/jest-react-starter.ts b/src/livecodes/templates/starter/jest-react-starter.ts
index 467e31e24..c82c70b23 100644
--- a/src/livecodes/templates/starter/jest-react-starter.ts
+++ b/src/livecodes/templates/starter/jest-react-starter.ts
@@ -48,11 +48,9 @@ function Counter(props) {
   );
 }
 
-function App() {
+export default function App() {
   return <Counter name="Jest with React" />;
 }
-
-export default App;
 `.trimStart(),
   },
   tests: {
diff --git a/src/livecodes/templates/starter/react-starter.ts b/src/livecodes/templates/starter/react-starter.ts
index 2fcdc82ff..54dd1f605 100644
--- a/src/livecodes/templates/starter/react-starter.ts
+++ b/src/livecodes/templates/starter/react-starter.ts
@@ -25,37 +25,23 @@ export const reactStarter: Template = {
   script: {
     language: 'jsx',
     content: `
-import { useState } from "react";
+import { useState } from "react"
 
-function Greeting(props) {
+function Counter(props) {
+  const [count, setCount] = useState(0);
   return (
-    <>
+    <div className="container">
       <h1>Hello, {props.name}!</h1>
       <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/react.svg" />
-    </>
-  );
-}
-
-function Counter() {
-  const [count, setCount] = useState(0);
-  return (
-    <>
       <p>You clicked {count} times.</p>
       <button onClick={() => setCount(count + 1)}>Click me</button>
-    </>
-  );
-}
-
-function App() {
-  return (
-    <div className="container">
-      <Greeting name="React" />
-      <Counter />
     </div>
   );
 }
 
-export default App;
+export default function App() {
+  return <Counter name="React" />;
+}
 `.trimStart(),
   },
   stylesheets: [],
diff --git a/src/livecodes/templates/starter/solid-starter.ts b/src/livecodes/templates/starter/solid-starter.ts
index d2f33e09a..21fcf0f3b 100644
--- a/src/livecodes/templates/starter/solid-starter.ts
+++ b/src/livecodes/templates/starter/solid-starter.ts
@@ -27,33 +27,21 @@ export const solidStarter: Template = {
     content: `
 import { createSignal } from "solid-js";
 
-function Greeting(props: { name: string }) {
-  return (
-    <>
-      <h1>Hello, {props.name}!</h1>
-      <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/solid.svg" />
-    </>
-  );
-}
-
-function Counter() {
+function Counter(props: { name: string }) {
   const [count, setCount] = createSignal(0);
   const increment = () => setCount(count() + 1);
   return (
-    <>
+    <div className="container">
+      <h1>Hello, {props.name}!</h1>
+      <img className="logo" alt="logo" src="{{ __livecodes_baseUrl__ }}assets/templates/solid.svg" />
       <p>You clicked {count()} times.</p>
       <button onClick={increment}>Click me</button>
-    </>
+    </div>
   );
 }
 
 export default function App() {
-  return (
-    <div className="container">
-      <Greeting name="Solid" />
-      <Counter />
-    </div>
-  );
+  return <Counter name="Solid" />;
 }
 `.trimStart(),
   },

From 20d5b5b768a0c60c259afb21b62c42c762cdb4d6 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Thu, 25 Jan 2024 15:23:52 +0200
Subject: [PATCH 22/30] feat(Config): allow disabling JSX auto-render from
 custom settings

---
 src/livecodes/result/result-page.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index 7ce909fc7..c3cd72016 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -175,6 +175,7 @@ export const createResultPage = async ({
   const jsxRuntime = jsxRuntimes[code.script.language] || '';
   const shouldInsertJsxRuntime =
     Object.keys(jsxRuntimes).includes(code.script.language) &&
+    !config.customSettings[code.script.language]?.disableAutoRender &&
     hasDefaultExport(code.script.compiled) &&
     !hasCustomJsxRuntime(code.script.content || '', config) &&
     !importFromScript;

From 3d2e5c383bc7efbb290d64ba98b89b3377554d4f Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Thu, 25 Jan 2024 17:27:48 +0200
Subject: [PATCH 23/30] docs: use SDK `getPlaygroundUrl` in docs
 `RunInLiveCodes` component

---
 docs/src/components/RunInLiveCodes.tsx | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/docs/src/components/RunInLiveCodes.tsx b/docs/src/components/RunInLiveCodes.tsx
index 75c3e9de6..f850a99fc 100644
--- a/docs/src/components/RunInLiveCodes.tsx
+++ b/docs/src/components/RunInLiveCodes.tsx
@@ -3,11 +3,12 @@ import React from 'react';
 import BrowserOnly from '@docusaurus/BrowserOnly';
 import CodeBlock from '@theme/CodeBlock';
 /* eslint-disable import/no-internal-modules */
-import type { EmbedOptions } from '../../../src/sdk';
+import { getPlaygroundUrl, type EmbedOptions } from '../../../src/sdk';
 import { appUrl } from '../utils';
 
 export default function RunInLiveCodes(props: {
-  params: EmbedOptions['params'];
+  params?: EmbedOptions['params'];
+  config?: EmbedOptions['config'];
   code?: string;
   language?: string;
   codeTitle?: string;
@@ -19,6 +20,7 @@ export default function RunInLiveCodes(props: {
 }): JSX.Element {
   const {
     params,
+    config,
     code,
     language = 'js',
     codeTitle = '',
@@ -28,12 +30,8 @@ export default function RunInLiveCodes(props: {
     style = {},
     className = '',
   } = props;
-  const url = new URL(appUrl);
-  if (typeof params === 'object') {
-    (Object.keys(params) as string[]).forEach((param) => {
-      url.searchParams.set(param, String(params[param]));
-    });
-  }
+  const url = getPlaygroundUrl({ appUrl, params, config });
+
   return (
     <div style={{ marginBottom: '30px', ...style }} className={className}>
       {code && (
@@ -53,7 +51,7 @@ export default function RunInLiveCodes(props: {
           }}
         </BrowserOnly>
       )}
-      <a href={url.href} target="_blank" rel="noreferrer">
+      <a href={url} target="_blank" rel="noreferrer">
         {linkText}
         <svg
           width="12"

From c63a32ff69b0e4e52a49c18aedc444d8dc3c71d7 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Thu, 25 Jan 2024 22:12:14 +0200
Subject: [PATCH 24/30] fix(Result): remove extra scripts added to detect
 classes for CSS processors

---
 src/livecodes/core.ts               | 3 ++-
 src/livecodes/result/result-page.ts | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/livecodes/core.ts b/src/livecodes/core.ts
index 27dcc3ae2..01b19faff 100644
--- a/src/livecodes/core.ts
+++ b/src/livecodes/core.ts
@@ -866,7 +866,8 @@ const getResultPage = async ({
 
   const compileResults = await Promise.all([
     compiler.compile(styleContent, styleLanguage, config, {
-      html: `${compiledMarkup}<script>${compiledScript}</script><script>${compileInfo.importedContent}</script>`,
+      html: `${compiledMarkup}<script type="script-for-styles">${compiledScript}</script>
+        <script type="script-for-styles">${compileInfo.importedContent}</script>`,
       forceCompile: forceCompileStyles,
     }),
     runTests
diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index c3cd72016..cbeebb50a 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -142,6 +142,10 @@ export const createResultPage = async ({
   const markup = code.markup.compiled;
   dom.body.innerHTML += markup;
 
+  // cleanup extra scripts added to detect classes for CSS processors
+  const extra = dom.querySelectorAll('script[type="script-for-styles"]');
+  extra.forEach((el) => el.remove());
+
   // cleanup custom configurations and scripts
   if (code.script.language === 'blockly') {
     const extra = dom.querySelectorAll(

From c77980a1079f09827c8cde44cbf38cf1c3199d58 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Thu, 25 Jan 2024 22:44:29 +0200
Subject: [PATCH 25/30] fix(Result): fix removing/ignoring stylesheet imports
 in scripts

---
 src/livecodes/result/result-page.ts | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts
index cbeebb50a..fb9dde7d6 100644
--- a/src/livecodes/result/result-page.ts
+++ b/src/livecodes/result/result-page.ts
@@ -5,8 +5,6 @@ import {
   getImports,
   hasImports,
   isModuleScript,
-  removeImports,
-  // avoid default exports conflict
   hasDefaultExport,
   replaceImports,
 } from '../compiler';
@@ -122,7 +120,6 @@ export const createResultPage = async ({
     stylesheet.href = url;
     dom.head.appendChild(stylesheet);
   });
-  code.script.compiled = removeImports(code.script.compiled, stylesheetImports);
 
   // editor styles
   if (singleFile) {
@@ -250,6 +247,13 @@ export const createResultPage = async ({
           ...(runTests && !forExport && hasImports(compiledTests)
             ? createImportMap(compiledTests, config)
             : {}),
+          ...stylesheetImports.reduce(
+            (acc, url) => ({
+              ...acc,
+              [url]: toDataUrl(''),
+            }),
+            {},
+          ),
           ...createCSSModulesImportMap(
             code.script.compiled,
             code.style.compiled,

From e87fbf85aa9fa165d1d455e71f7122be7d8fb3c0 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 26 Jan 2024 08:03:31 +0200
Subject: [PATCH 26/30] docs(compilers): add docs for JSX support

---
 docs/docs/languages/jsx.md | 178 ++++++++++++++++++++++++++++++++++---
 docs/docs/languages/vue.md |   6 +-
 2 files changed, 169 insertions(+), 15 deletions(-)

diff --git a/docs/docs/languages/jsx.md b/docs/docs/languages/jsx.md
index d9b45bdc9..a80a4a104 100644
--- a/docs/docs/languages/jsx.md
+++ b/docs/docs/languages/jsx.md
@@ -1,34 +1,186 @@
 # JSX
 
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx';
+
+[JSX](https://react.dev/learn/writing-markup-with-jsx) is a syntax extension for JavaScript that allows writing HTML-like markup inside JavaScript.
+It has been popularized by [React](https://react.dev/), and then adopted by many other libraries/frameworks.
+
+By default, when running JSX in LiveCodes, [React](https://react.dev/) runtime is used.
+However, other libraries like [Preact](https://preactjs.com/), [nano JSX](https://nanojsx.io/) and others can be used as well (see [Custom JSX Runtimes](#custom-jsx-runtimes)).
+
+Please note that TSX is also supported in LiveCodes and is [documented here](./tsx.md).
+
+## Demo:
+
+<LiveCodes template="react" height="400px"></LiveCodes>
+
 ## Usage
 
+The easiest way is to [auto-render](#auto-rendering) a component by exporting it as the [default export](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#using_the_default_export):
+
+export const basicJsxDemo = { jsx: `export default function App() {\n  return <h1>Hello World!</h1>;\n}`}
+
+<RunInLiveCodes params={basicJsxDemo} code={basicJsxDemo.jsx} language="jsx" formatCode={false}></RunInLiveCodes>
+
+You may, however, be more explicit and render the component yourself using [React DOM](https://react.dev/reference/react-dom/client):
+
+export const reactDomDemo = { jsx: `import { createRoot } from "react-dom/client";\n\nfunction App() {\n  return <h1>Hello World!</h1>;\n}\n\nconst root = createRoot(document.querySelector("#root"));\nroot.render(<App />);`, html: `<div id="root"></div>`}
+
+<RunInLiveCodes params={reactDomDemo} code={reactDomDemo.jsx} language="jsx" formatCode={false}></RunInLiveCodes>
+
+:::info note
+
+React's [new JSX transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) is utilized. So there is no need to import React.
+
+```jsx
+// this is not needed:
+// import React from 'react';
+
+export default function App() {
+  return <h1>Hello World!</h1>;
+}
+```
+
+:::
+
+### Auto-rendering
+
+A component is rendered automatically as a React component (without having to manually use React Dom to render it) if the following conditions are met:
+
+- The component is exported as the default export.
+- No custom JSX runtime is used (see [Custom JSX Runtimes](#custom-jsx-runtimes)).
+- No [imports from `"./script"`](#exports) in markup editor.
+- Auto-rendering is not [disabled](#disabling-auto-rendering).
+
+#### Root Element
+
+To render the React components to a specific [root](https://react.dev/reference/react-dom/client/createRoot) DOM element use `"livecodes-app"` as the element `id`. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used as the root.
+
+Example:
+
+export const rootDemo = { html: `<div id="livecodes-app">Loading...</div>`, jsx: `export default function App() {\n  return <h1>Hello World!</h1>;\n}`}
+
+<RunInLiveCodes params={rootDemo} code={rootDemo.html} language="html" formatCode={false}></RunInLiveCodes>
+
+#### Disabling Auto-rendering
+
+To disable auto-rendering, set the [custom settings](#custom-settings) `disableAutoRender` property to `true`.
+
+export const disableAutoRenderDemo = {markup: {language: "html", content: `JSX auto-rendering is disabled. Set from app menu → Custom Settings.`}, script: {language: "jsx", content: `export default function App() {\n  return <h1>Hello World!</h1>;\n}`}, customSettings: {"jsx": {"disableAutoRender": true}}}
+
+<RunInLiveCodes config={disableAutoRenderDemo} code={JSON.stringify(disableAutoRenderDemo.customSettings, null, 2)} language="json" codeTitle="Custom Settings" formatCode={false}></RunInLiveCodes>
+
 ### Importing Modules
 
+npm modules can be imported as described in the section about [module resolution](../features/module-resolution.md), including bare module imports and importing from different CDNs. Stylesheet imports are added as `<link rel="stylesheet">` tags in the page `head`.
+
+Example:
+
+export const importsDemo = { jsx: `import { useState, useEffect } from "react";\nimport confetti from "canvas-confetti";\nimport "bootstrap/dist/css/bootstrap.css";\n\nexport default function App() {\n  const [count, setCount] = useState(0);\n\n  useEffect(() => {\n    if (count > 0) {\n      confetti();\n    }\n  }, [count]);\n\n  return (\n    <div className="m-5 text-center">\n      <p>You clicked {count} times.</p>\n      <button onClick={() => setCount(count + 1)}>Click me</button>\n    </div>\n  );\n}\n` }
+
+<RunInLiveCodes params={importsDemo} code={importsDemo.jsx} language="jsx" formatCode={false}></RunInLiveCodes>
+
+Module imports can be customized using import maps as described in [module resolution](../features/module-resolution.md#custom-module-resolution) documentations.
+
+#### Types for Imported Modules
+
+Types for imported modules are loaded automatically (if available) to provide [Intellisense](../features/intellisense.md), auto-completion and type information.
+
+![LiveCodes Intellisense](../../static/img/screenshots/intellisense1.jpg)
+
+![LiveCodes Intellisense](../../static/img/screenshots/intellisense2.jpg)
+
+Moreover, you can provide custom type definitions for modules that do not have types available on npm. See [Custom Types](../features/intellisense.md#custom-types) for details.
+
 ### Exports
 
+Values exported from script editor (default or named) can be imported in the markup editor by importing from `"./script"` (with no extension).
+
+This can be useful, for example, when using [MDX](./mdx.md) to import components exported form JSX.
+
+Demo:
+
+export const exportsDemo = { mdx: `import Greeting from "./script";\n\n<Greeting name="MDX" />\n`, jsx: `export default function(props) {\n  return <h1>Greeting from {props.name}!</h1>;\n}\n` }
+
+<LiveCodes params={exportsDemo}></LiveCodes>
+
+:::info note
+
+When values are imported from `"./script"`, [auto-rendering](#auto-rendering) is disabled, because it is assumed that you want to take control over component rendering.
+
+:::
+
 ### Styles
 
-#### CSS Processors
+CSS can be applied to the component using various ways:
+
+#### Style Editor
+
+Styles added in the style editor is applied globally to the [result page](../features/result.md). This can use different **languages/processors** supported in LiveCodes including CSS, SCSS, Less, Stylus, ..etc. See [style documentation](../features/css.md) for more details.
+
+And of course, styles and stylesheets added in markup editor are also applied globally.
+
+#### Importing Stylesheets
+
+Stylesheets imported in script editor are added as `<link rel="stylesheet">` tags in the page `head`.
+The stylesheet URL can be an absolute URL or a path in the npm package. The URL has to end with `".css"`.
+
+example:
 
-#### Importing Styles
+export const stylesDemo = { jsx: `import "bootstrap/dist/css/bootstrap.css";\n\nexport default () => <h1 className="m-5 text-center">Hello World!</h1>;\n` }
+
+<RunInLiveCodes params={stylesDemo} code={stylesDemo.jsx} language="jsx" formatCode={false}></RunInLiveCodes>
 
 #### CSS Modules
 
+CSS modules are supported and are [documented separately](./cssmodules.md). Make sure to enable CSS modules (from style editor menu or in [`processors`](../configuration/configuration-object.md#processors) property of [configuration object](../configuration/configuration-object.md)).
+
+Demo:
+
+export const cssModulesDemo = { activeEditor: 'script' , style: {language: 'css', content: `.title {\n  color: green;\n  font-family: sans-serif;\n}\n`}, script: {language: 'jsx', content: `import classes from './style.module.css';\n\nexport default function() {\n  return <h1 className={classes.title}>Hello, CSS Modules!</h1>;\n}\n`}, processors: ['cssmodules'] }
+
+<LiveCodes config={cssModulesDemo}></LiveCodes>
+
 #### CSS Frameworks
 
-[CSS Frameworks](../features/css.md#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.md), [UnoCSS](./unocss.md), [WindiCSS](./windicss.md)) are available for use in JSX. Make sure that the required utility is enabled (Style menu or `processors` property of [configuration object](../configuration/configuration-object.md#processors)) and required [directives](https://tailwindcss.com/docs/functions-and-directives#tailwind) are added to the style editor.
+[CSS Frameworks](../features/css.md#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.md), [UnoCSS](./unocss.md), [WindiCSS](./windicss.md)) can detect class names added in JSX. Make sure that the required utility is enabled (from style editor menu or in [`processors`](../configuration/configuration-object.md#processors) property of [configuration object](../configuration/configuration-object.md)) and that required [directives](https://tailwindcss.com/docs/functions-and-directives#tailwind) are added to the style editor.
 
-Example:
+Demo:
+
+export const tailwindcssDemo = { activeEditor: 'script' , style: {language: 'css', content: `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`}, script: {language: 'jsx', content: `export default function() {\n  return <h1 className="text-3xl font-bold text-gray-500 text-center m-4">Hello, Tailwind CSS!</h1>;\n}\n`}, processors: ['tailwindcss'] }
+
+<LiveCodes config={tailwindcssDemo}></LiveCodes>
 
 #### CSS-in-JS
 
-### Root Element
+CSS-in-JS libraries can be imported and used as usual.
+
+Demo:
+
+export const styledComponentsDemo = { jsx: `import styled from 'styled-components';\n\nconst Title = styled.h1\`\n text-align: center;\n font-family: sans-serif;\n color: palevioletred;\n\`;\n\nexport default function () {\n return <Title>Hello, styled-components!</Title>;\n}\n` }
 
-To render the React components to a specific [root](https://react.dev/reference/react-dom/client/createRoot) DOM element use `livecodes-app` as the element ID. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used as the root.
+<LiveCodes params={styledComponentsDemo}></LiveCodes>
 
 ### Custom JSX Runtimes
 
-To [mount](https://vuejs.org/api/application.html#app-mount) the application instance to a specific DOM element use `livecodes-app` as the element ID. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance.
+LiveCodes allows using other libraries (like [Preact](https://preactjs.com/) and [nano JSX](https://nanojsx.io/)) as the JSX runtime.
+
+JSX is compiled to JavaScript using the TypeScript compiler, which allows multiple configuration options for JSX, including [`jsx`](https://www.typescriptlang.org/tsconfig#jsx), [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory), [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory) and [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource).
+
+These can be configured using in-code pragmas or in [custom settings](#custom-settings).
+
+Example for using Preact:
+
+export const preactDemo = { jsx: `/** @jsx h */\nimport { h, render } from 'preact';\n\nconst App = (props) => <h1>Hello, {props.name}</h1>;\n\nrender(<App name="Preact" />, document.body);\n` }
+
+<RunInLiveCodes params={preactDemo} code={'//highlight-next-line\n' + preactDemo.jsx} language="jsx" formatCode={false} showLineNumbers={true}></RunInLiveCodes>
+
+:::info note
+
+[Auto-rendering](#auto-rendering) is disabled for custom JSX runtimes.
+
+:::
 
 ## Language Info
 
@@ -48,15 +200,14 @@ To [mount](https://vuejs.org/api/application.html#app-mount) the application ins
 
 [TypeScript compiler](./typescript.md)
 
-### Version
-
 ## Code Formatting
 
 Using [Prettier](https://prettier.io/).
 
 ## Custom Settings
 
-[Custom settings](../advanced/custom-settings.md) added to the property `name` are passed as a JSON object to the `compiler` during compile. Please check the [documentation](#) for full reference.
+[Custom settings](../advanced/custom-settings.md) added to the property `jsx` are passed to the TypeScript compiler as [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions) while compiling JSX.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](#auto-rendering).
 
 Please note that custom settings should be valid JSON (i.e. functions are not allowed).
 
@@ -64,7 +215,11 @@ Please note that custom settings should be valid JSON (i.e. functions are not al
 
 ```json title="Custom Settings"
 {
-  "name": {}
+  "jsx": {
+    "disableAutoRender": true,
+    "jsxFactory": "h",
+    "jsxFragmentFactory": "Fragment"
+  }
 }
 ```
 
@@ -76,4 +231,3 @@ https://livecodes.io/?template=react
 
 - [React](https://react.dev/)
 - [JSX](https://react.dev/learn/writing-markup-with-jsx)
-- [CSS Modules](https://github.com/css-modules/css-modules)
diff --git a/docs/docs/languages/vue.md b/docs/docs/languages/vue.md
index 759e1904b..64ae100d5 100644
--- a/docs/docs/languages/vue.md
+++ b/docs/docs/languages/vue.md
@@ -37,7 +37,7 @@ export const cssModulesDemo = { vue: `<template>\n  <p :class="$style.red">This
 
 ### CSS Frameworks
 
-[CSS Frameworks](../features/css.md#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.md), [UnoCSS](./unocss.md), [WindiCSS](./windicss.md)) are available for use in Vue SFCs. Make sure that the required utility is enabled (Style menu or `processors` property of [configuration object](../configuration/configuration-object.md#processors)) and required [directives](https://tailwindcss.com/docs/functions-and-directives#tailwind) are added to the style editor.
+[CSS Frameworks](../features/css.md#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.md), [UnoCSS](./unocss.md), [WindiCSS](./windicss.md)) can detect class names added in Vue SFCs. Make sure that the required utility is enabled (from style editor menu or in `processors` property of [configuration object](../configuration/configuration-object.md#processors)) and that required [directives](https://tailwindcss.com/docs/functions-and-directives#tailwind) are added to the style editor.
 
 See [example below](#importing-vue-sfcs).
 
@@ -82,7 +82,7 @@ The imported sources can use any of the supported languages/pre-processors (iden
 
 ### Module Imports
 
-Modules can be imported as described in the section about [module resolution](../features/module-resolution.md), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `<link rel="stylesheet">` tags in the page `head`.
+npm modules can be imported as described in the section about [module resolution](../features/module-resolution.md), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `<link rel="stylesheet">` tags in the page `head`.
 
 Example:
 
@@ -121,7 +121,7 @@ This is an example of importing a Vue SFC, which in turn imports other Vue SFCs
 
 ### Root Element
 
-To [mount](https://vuejs.org/api/application.html#app-mount) the application instance to a specific DOM element use `livecodes-app` as the element ID. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance.
+To [mount](https://vuejs.org/api/application.html#app-mount) the application instance to a specific DOM element use `"livecodes-app"` as the element `id`. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance.
 
 ## Language Info
 

From 9fa8998902128b5f3e0658b6954ed6ea28f739cd Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 26 Jan 2024 08:13:53 +0200
Subject: [PATCH 27/30] docs(compilers): add docs for TSX support

---
 docs/docs/languages/tsx.md | 61 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/docs/docs/languages/tsx.md b/docs/docs/languages/tsx.md
index 4daabfaf2..0fc6f7fe7 100644
--- a/docs/docs/languages/tsx.md
+++ b/docs/docs/languages/tsx.md
@@ -1,3 +1,62 @@
 # TSX
 
-TODO...
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx';
+
+TSX is a syntax that allows using TypeScript in JSX.
+[JSX](https://react.dev/learn/writing-markup-with-jsx) is a syntax extension for JavaScript that allows writing HTML-like markup inside JavaScript.
+It has been popularized by [React](https://react.dev/), and then adopted by many other libraries/frameworks.
+
+By default, when running JSX/TSX in LiveCodes, [React](https://react.dev/) runtime is used.
+However, other libraries like [Preact](https://preactjs.com/), [nano JSX](https://nanojsx.io/) and others can be used as well (see [Custom JSX Runtimes](./jsx.md#custom-jsx-runtimes)).
+
+## Usage
+
+For usage and examples, see documentation for [JSX](./jsx.md) and [TypeScript](./typescript.md) support in LiveCodes.
+
+## Language Info
+
+### Name
+
+`tsx`
+
+### Extension
+
+`.tsx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[TypeScript compiler](./typescript.md)
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `tsx` are passed to the TypeScript compiler as [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions) while compiling TSX.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](#auto-rendering).
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "tsx": {
+    "disableAutoRender": true,
+    "jsxFactory": "h",
+    "jsxFragmentFactory": "Fragment"
+  }
+}
+```
+
+## Links
+
+- [React](https://react.dev/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [TypeScript](https://www.typescriptlang.org/)

From dfe7c4298c672b36e20da174cd468fadc053a76f Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 26 Jan 2024 08:46:33 +0200
Subject: [PATCH 28/30] docs(compilers): add docs for SolidJS

---
 docs/docs/languages/solid.md     | 68 +++++++++++++++++++++++++++++++-
 docs/docs/languages/solid.tsx.md | 68 +++++++++++++++++++++++++++++++-
 docs/docs/languages/tsx.md       |  9 +++--
 3 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/docs/docs/languages/solid.md b/docs/docs/languages/solid.md
index 6d7b6cfbb..012939ed3 100644
--- a/docs/docs/languages/solid.md
+++ b/docs/docs/languages/solid.md
@@ -1,3 +1,69 @@
 # Solid
 
-TODO...
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx';
+
+[Solid](https://www.solidjs.com/) is a JavaScript framework for making interactive web applications.
+
+Solid offers very similar syntax to [React](https://react.dev/), with strong focus on [reactivity](https://www.solidjs.com/guides/reactivity) using signals. Solid supports templating in 3 forms [JSX](./jsx.md), Tagged Template Literals and Solid's HyperScript variant, although JSX is the predominate form. Solid also supports [TypeScript](./typescript.md) (See [Solid-TS](./solid.tsx.md)).
+
+## Demo
+
+<LiveCodes template="solid" height="400px"></LiveCodes>
+
+## Usage
+
+For usage, see documentation for [JSX](./jsx.md) and [TypeScript](./typescript.md) support in LiveCodes.
+
+## Language Info
+
+### Name
+
+`solid`
+
+### Extension
+
+`solid.jsx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[Official Solid JSX compiler](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions) (`babel-preset-solid`)
+
+### Version
+
+`babel-preset-solid` version 1.7.4
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `solid` are passed to the Babel compiler during compile. Please check the [documentation](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions#plugin-options) for full reference.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](./jsx#auto-rendering).
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "solid": {
+    "disableAutoRender": true
+  }
+}
+```
+
+## Starter Template
+
+https://livecodes.io/?template=solid (uses TSX)
+
+## Links
+
+- [Solid](https://www.solidjs.com/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [TypeScript](https://www.typescriptlang.org/)
diff --git a/docs/docs/languages/solid.tsx.md b/docs/docs/languages/solid.tsx.md
index b5b063978..d3ae327ca 100644
--- a/docs/docs/languages/solid.tsx.md
+++ b/docs/docs/languages/solid.tsx.md
@@ -1,3 +1,69 @@
 # Solid (TS)
 
-TODO...
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx';
+
+[Solid](https://www.solidjs.com/) is a JavaScript framework for making interactive web applications.
+
+Solid offers very similar syntax to [React](https://react.dev/), with strong focus on [reactivity](https://www.solidjs.com/guides/reactivity) using signals. Solid supports templating in 3 forms [JSX](./jsx.md), Tagged Template Literals and Solid's HyperScript variant, although JSX is the predominate form. Solid also supports [TypeScript](./typescript.md).
+
+## Demo
+
+<LiveCodes template="solid" height="400px"></LiveCodes>
+
+## Usage
+
+For usage, see documentation for [JSX](./jsx.md) and [TypeScript](./typescript.md) support in LiveCodes.
+
+## Language Info
+
+### Name
+
+`solid.tsx`
+
+### Extension
+
+`solid.tsx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[Official Solid JSX compiler](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions) (`babel-preset-solid`)
+
+### Version
+
+`babel-preset-solid` version 1.7.4
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `solid.tsx` are passed to the Babel compiler during compile. Please check the [documentation](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions#plugin-options) for full reference.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](./jsx#auto-rendering).
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "solid": {
+    "disableAutoRender": true
+  }
+}
+```
+
+## Starter Template
+
+https://livecodes.io/?template=solid
+
+## Links
+
+- [Solid](https://www.solidjs.com/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [TypeScript](https://www.typescriptlang.org/)
diff --git a/docs/docs/languages/tsx.md b/docs/docs/languages/tsx.md
index 0fc6f7fe7..7682f6725 100644
--- a/docs/docs/languages/tsx.md
+++ b/docs/docs/languages/tsx.md
@@ -1,8 +1,5 @@
 # TSX
 
-import LiveCodes from '../../src/components/LiveCodes.tsx';
-import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx';
-
 TSX is a syntax that allows using TypeScript in JSX.
 [JSX](https://react.dev/learn/writing-markup-with-jsx) is a syntax extension for JavaScript that allows writing HTML-like markup inside JavaScript.
 It has been popularized by [React](https://react.dev/), and then adopted by many other libraries/frameworks.
@@ -39,7 +36,7 @@ Using [Prettier](https://prettier.io/).
 ## Custom Settings
 
 [Custom settings](../advanced/custom-settings.md) added to the property `tsx` are passed to the TypeScript compiler as [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions) while compiling TSX.
-In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](#auto-rendering).
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](./jsx#auto-rendering).
 
 Please note that custom settings should be valid JSON (i.e. functions are not allowed).
 
@@ -55,6 +52,10 @@ Please note that custom settings should be valid JSON (i.e. functions are not al
 }
 ```
 
+## Starter Template
+
+https://livecodes.io/?template=react (uses JSX)
+
 ## Links
 
 - [React](https://react.dev/)

From 0bf80a5d8576862ebac93c2c53471837ee1045f5 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 26 Jan 2024 09:14:11 +0200
Subject: [PATCH 29/30] feat(UI): add links to docs in language info

---
 src/livecodes/html/language-info.html | 203 +++++++++++++++++++-------
 1 file changed, 154 insertions(+), 49 deletions(-)

diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html
index 14a55da1e..475075609 100644
--- a/src/livecodes/html/language-info.html
+++ b/src/livecodes/html/language-info.html
@@ -332,6 +332,11 @@ <h3>doT.js</h3>
     <li>
       <a href="https://olado.github.io/doT/" target="_blank" rel="noopener">Official website</a>
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/dot" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="ejs">
@@ -339,6 +344,11 @@ <h3>EJS</h3>
   <div>Embedded JavaScript templating.</div>
   <ul>
     <li><a href="https://ejs.co/" target="_blank" rel="noopener">Official website</a></li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/ejs" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="eta">
@@ -352,6 +362,11 @@ <h3>Eta</h3>
     <li>
       <a href="https://eta.js.org/docs/learn" target="_blank" rel="noopener">Documentation</a>
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/eta" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="fennel">
@@ -369,6 +384,11 @@ <h3>Fennel</h3>
         >Getting Started with Fennel</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/fennel" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=fennel" target="_parent" data-template="fennel">Load starter template</a>
     </li>
@@ -409,29 +429,6 @@ <h3>Go</h3>
     <li><a href="?template=go" target="_parent" data-template="go">Load starter template</a></li>
   </ul>
 </section>
-<section data-lang="gnuplot">
-  <h3>Gnuplot</h3>
-  <div>Gnuplot is a portable command-line driven graphing utility.</div>
-  <div>Here, it is running in the browser using gnuplot-JS.</div>
-  <ul>
-    <li>
-      <a href="http://www.gnuplot.info/" target="_blank" rel="noopener">Gnuplot official website</a>
-    </li>
-    <li>
-      <a href="http://www.gnuplot.info/documentation.html" target="_blank" rel="noopener"
-        >Gnuplot documentation</a
-      >
-    </li>
-    <li>
-      <a href="https://github.com/chhu/gnuplot-JS" target="_blank" rel="noopener"
-        >gnuplot-JS repo</a
-      >
-    </li>
-    <li>
-      <a href="?template=gnuplot" target="_parent" data-template="gnuplot">Load starter template</a>
-    </li>
-  </ul>
-</section>
 <section data-lang="haml">
   <h3>Haml</h3>
   <div>Haml compiler for client side javascript view templates using clientside-haml-js.</div>
@@ -450,6 +447,11 @@ <h3>Haml</h3>
         >Learn X in Y minutes, where X=haml</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/haml" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="handlebars">
@@ -457,6 +459,11 @@ <h3>Handlebars</h3>
   <div>Minimal templating on steroids.</div>
   <ul>
     <li><a href="https://handlebarsjs.com/" target="_blank" rel="noopener">Official website</a></li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/handlebars" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="imba">
@@ -470,20 +477,20 @@ <h3>Imba</h3>
   <h3>JSX</h3>
   <div>
     JSX is compiled to JavaScript in LiveCodes using the TypeScript Compiler. <br />
-    By default it uses <code>React.createElement</code>
+    By default it uses React as the JSX runtime.
   </div>
   <ul>
     <li>
-      <a href="https://reactjs.org/" target="_blank" rel="noopener">React official website</a>
+      <a href="https://react.dev/" target="_blank" rel="noopener">React official website</a>
     </li>
     <li>
-      <a href="https://reactjs.org/docs/getting-started.html" target="_blank" rel="noopener"
-        >React documentation</a
+      <a href="https://react.dev/learn/writing-markup-with-jsx" target="_blank" rel="noopener"
+        >JSX in React documentation</a
       >
     </li>
     <li>
-      <a href="https://reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noopener"
-        >JSX in React documentation</a
+      <a href="{{DOCS_BASE_URL}}languages/jsx" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
       >
     </li>
     <li>
@@ -545,6 +552,11 @@ <h3>LiquidJS</h3>
         >LiquidJS documentation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/liquid" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="livescript">
@@ -591,6 +603,11 @@ <h3>Lua</h3>
         >Learn X in Y minutes, where X=Lua</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/lua" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li><a href="?template=lua" target="_parent" data-template="lua">Load starter template</a></li>
   </ul>
 </section>
@@ -617,6 +634,11 @@ <h3>Lua (Wasm)</h3>
         >Learn X in Y minutes, where X=Lua</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/lua-wasm" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=lua-wasm" target="_parent" data-template="lua-wasm"
         >Load starter template</a
@@ -689,6 +711,11 @@ <h3>MJML</h3>
     <li>
       <a href="https://mjml.io/templates" target="_blank" rel="noopener">MJML official templates</a>
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/mjml" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="mustache">
@@ -708,6 +735,11 @@ <h3>Mustache</h3>
         >JavaScript implementation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/mustache" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="nunjucks">
@@ -722,6 +754,11 @@ <h3>Nunjucks</h3>
         >Official website</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/nunjucks" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="twig">
@@ -749,6 +786,11 @@ <h3>Twig</h3>
         >Twig.js Documentation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/twig" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="ocaml">
@@ -822,6 +864,11 @@ <h3>PHP</h3>
         >Learn X in Y minutes, where X=PHP</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/php" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li><a href="?template=php" target="_parent" data-template="php">Load starter template</a></li>
   </ul>
 </section>
@@ -843,6 +890,11 @@ <h3>PHP (Wasm)</h3>
         >Learn X in Y minutes, where X=PHP</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/php-wasm" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=php-wasm" target="_parent" data-template="php-wasm"
         >Load starter template</a
@@ -891,6 +943,11 @@ <h3>Pug</h3>
         >Learn X in Y minutes, where X=Pug</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/pug" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="python-wasm">
@@ -913,6 +970,11 @@ <h3>Python (Wasm)</h3>
         >Learn X in Y minutes, where X=Python</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/python-wasm" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=python-wasm" target="_parent" data-template="python-wasm"
         >Load starter template</a
@@ -938,6 +1000,11 @@ <h3>Python</h3>
         >Learn X in Y minutes, where X=Python</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/python" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=python" target="_parent" data-template="python">Load starter template</a>
     </li>
@@ -945,7 +1012,6 @@ <h3>Python</h3>
 </section>
 <section data-lang="r">
   <h3>R</h3>
-  <div class="description">(R language support in LiveCodes is still experimental)</div>
   <div>R running in the browser using WebR.</div>
   <ul>
     <li>
@@ -971,6 +1037,11 @@ <h3>R</h3>
         >Learn X in Y minutes, where X=R</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/r" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=r" target="_parent" data-template="r">Load starter template</a>
     </li>
@@ -1154,6 +1225,11 @@ <h3>Ruby</h3>
         >Learn X in Y minutes, where X=ruby</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/ruby" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=ruby" target="_parent" data-template="ruby">Load starter template</a>
     </li>
@@ -1186,6 +1262,11 @@ <h3>Ruby (WASM)</h3>
         >Learn X in Y minutes, where X=ruby</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/ruby-wasm" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=ruby-wasm" target="_parent" data-template="ruby-wasm"
         >Load starter template</a
@@ -1287,10 +1368,13 @@ <h3>Solid (with TypeScript)</h3>
       >
     </li>
     <li>
-      <a href="?template=solid" target="_parent" data-template="solid"
-        >Load starter template (JSX)</a
+      <a href="{{DOCS_BASE_URL}}languages/solid.tsx" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
       >
     </li>
+    <li>
+      <a href="?template=solid" target="_parent" data-template="solid">Load starter template</a>
+    </li>
   </ul>
 </section>
 <section data-lang="solid">
@@ -1300,7 +1384,14 @@ <h3>Solid</h3>
     <li><a href="https://www.solidjs.com/" target="_blank" rel="noopener">Official website</a></li>
     <li><a href="https://www.solidjs.com/docs" target="_blank" rel="noopener">Documentation</a></li>
     <li>
-      <a href="?template=solid" target="_parent" data-template="solid">Load starter template</a>
+      <a href="{{DOCS_BASE_URL}}languages/solid" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
+    <li>
+      <a href="?template=solid" target="_parent" data-template="solid"
+        >Load starter template (TSX)</a
+      >
     </li>
   </ul>
 </section>
@@ -1386,6 +1477,11 @@ <h3>Sucrase</h3>
         >Sucrase GitHub Repo</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/sucrase" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="svelte">
@@ -1448,6 +1544,11 @@ <h3>Teal</h3>
         >Teal tutorial</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/teal" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=teal" target="_parent" data-template="teal">Load starter template</a>
     </li>
@@ -1457,19 +1558,14 @@ <h3>Teal</h3>
   <h3>TSX</h3>
   <div>
     TypeScript in JSX. TSX is compiled to JavaScript in LiveCodes using the TypeScript Compiler.<br />
-    By default it uses <code>React.createElement</code>
+    By default it uses React as the JSX runtime.
   </div>
   <ul>
     <li>
-      <a href="https://reactjs.org/" target="_blank" rel="noopener">React official website</a>
-    </li>
-    <li>
-      <a href="https://reactjs.org/docs/getting-started.html" target="_blank" rel="noopener"
-        >React documentation</a
-      >
+      <a href="https://react.dev/" target="_blank" rel="noopener">React official website</a>
     </li>
     <li>
-      <a href="https://reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noopener"
+      <a href="https://react.dev/learn/writing-markup-with-jsx" target="_blank" rel="noopener"
         >JSX in React documentation</a
       >
     </li>
@@ -1478,6 +1574,11 @@ <h3>TSX</h3>
         >Typescript documentation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/tsx" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="typescript">
@@ -1506,24 +1607,23 @@ <h3>TypeScript</h3>
 </section>
 <section data-lang="vue">
   <h3>Vue3 Single File Components</h3>
-  <div>Loaded using vue3-sfc-loader.</div>
   <ul>
     <li>
-      <a href="https://v3.vuejs.org/" target="_blank" rel="noopener">Vue.js v3 official website</a>
+      <a href="https://vuejs.org/" target="_blank" rel="noopener">Vue.js v3 official website</a>
     </li>
     <li>
-      <a href="https://v3.vuejs.org/guide/introduction.html" target="_blank" rel="noopener"
+      <a href="https://vuejs.org/guide/introduction.html" target="_blank" rel="noopener"
         >Vue3 documentation</a
       >
     </li>
     <li>
-      <a href="https://v3.vuejs.org/guide/single-file-component.html" target="_blank" rel="noopener"
+      <a href="https://vuejs.org/api/sfc-spec.html" target="_blank" rel="noopener"
         >Vue3 single file components</a
       >
     </li>
     <li>
-      <a href="https://github.com/FranckFreiburger/vue3-sfc-loader" target="_blank" rel="noopener"
-        >vue3-sfc-loader GitHub repo</a
+      <a href="{{DOCS_BASE_URL}}languages/vue" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
       >
     </li>
     <li><a href="?template=vue" target="_parent" data-template="vue">Load starter template</a></li>
@@ -1535,11 +1635,11 @@ <h3>Vue2 Single File Components</h3>
   <ul>
     <li><a href="https://vuejs.org/" target="_blank" rel="noopener">Vue.js official website</a></li>
     <li>
-      <a href="https://vuejs.org/v2/guide/" target="_blank" rel="noopener">Vue2 documentation</a>
+      <a href="https://v2.vuejs.org/v2/guide/" target="_blank" rel="noopener">Vue2 documentation</a>
     </li>
     <li>
       <a
-        href="https://vuejs.org/v2/guide/single-file-components.html"
+        href="https://v2.vuejs.org/v2/guide/single-file-components.html"
         target="_blank"
         rel="noopener"
         >Vue2 single file components</a
@@ -1550,6 +1650,11 @@ <h3>Vue2 Single File Components</h3>
         >vue3-sfc-loader GitHub repo</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/vue2" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
   </ul>
 </section>
 <section data-lang="wat">

From 35f644d5e064303877fabed796792e06c8942c17 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Fri, 26 Jan 2024 09:52:05 +0200
Subject: [PATCH 30/30] docs(compilers): add docs for react-native

---
 docs/docs/languages/react-native-tsx.md | 63 +++++++++++++++++++++++-
 docs/docs/languages/react-native.md     | 65 ++++++++++++++++++++++++-
 src/livecodes/html/language-info.html   | 10 ++++
 3 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/docs/docs/languages/react-native-tsx.md b/docs/docs/languages/react-native-tsx.md
index 6ab61d298..3cb6e5dc1 100644
--- a/docs/docs/languages/react-native-tsx.md
+++ b/docs/docs/languages/react-native-tsx.md
@@ -1,3 +1,64 @@
 # React Native (TSX)
 
-TODO...
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+[React Native](https://reactnative.dev/) is a framework for building mobile apps using React and React Native. React Native support in LiveCodes is achieved by using [React Native for Web](https://necolas.github.io/react-native-web/) (an accessible implementation of React Native's Components and APIs that is interoperable with React DOM).
+
+## Demo
+
+<LiveCodes template="react-native" height="400px"></LiveCodes>
+
+## Usage
+
+For usage and examples, see documentation for [JSX](./jsx.md).
+
+## Language Info
+
+### Name
+
+`react-native-tsx`
+
+### Extension
+
+`.react-native.tsx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[TypeScript compiler](./typescript.md) and [React Native for Web](https://necolas.github.io/react-native-web/)
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `react-native-tsx` are passed to the TypeScript compiler as [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions) while compiling TSX.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](./jsx#auto-rendering).
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "react-native-tsx": {
+    "disableAutoRender": true
+  }
+}
+```
+
+## Starter Template
+
+https://livecodes.io/?template=react-native (uses JSX)
+
+## Links
+
+- [React Native](https://reactnative.dev/)
+- [React Native for Web](https://necolas.github.io/react-native-web/)
+- [React](https://react.dev/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [TypeScript](https://www.typescriptlang.org/)
diff --git a/docs/docs/languages/react-native.md b/docs/docs/languages/react-native.md
index a38482129..fbb231622 100644
--- a/docs/docs/languages/react-native.md
+++ b/docs/docs/languages/react-native.md
@@ -1,3 +1,66 @@
 # React Native
 
-TODO...
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+[React Native](https://reactnative.dev/) is a framework for building mobile apps using React and React Native. React Native support in LiveCodes is achieved by using [React Native for Web](https://necolas.github.io/react-native-web/) (an accessible implementation of React Native's Components and APIs that is interoperable with React DOM).
+
+TypeScript is also supported in React Native (TSX) and is [documented here](./react-native-tsx.md).
+
+## Demo
+
+<LiveCodes template="react-native" height="400px"></LiveCodes>
+
+## Usage
+
+For usage and examples, see documentation for [JSX](./jsx.md).
+
+## Language Info
+
+### Name
+
+`react-native`
+
+### Extension
+
+`.react-native.jsx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[TypeScript compiler](./typescript.md) and [React Native for Web](https://necolas.github.io/react-native-web/)
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.md) added to the property `react-native` are passed to the TypeScript compiler as [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions) while compiling JSX.
+In addition, the option `disableAutoRender` can be set to `true` to disable [auto-rendering](./jsx#auto-rendering).
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+  "react-native": {
+    "disableAutoRender": true
+  }
+}
+```
+
+## Starter Template
+
+https://livecodes.io/?template=react-native
+
+## Links
+
+- [React Native](https://reactnative.dev/)
+- [React Native for Web](https://necolas.github.io/react-native-web/)
+- [React](https://react.dev/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [TypeScript](https://www.typescriptlang.org/)
diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html
index 475075609..0baf2767e 100644
--- a/src/livecodes/html/language-info.html
+++ b/src/livecodes/html/language-info.html
@@ -1080,6 +1080,11 @@ <h3>React Native for Web (with TypeScript)</h3>
         >TypeScript documentation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/react-native-tsx" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=react-native" target="_parent" data-template="react-native"
         >Load starter template (JSX)</a
@@ -1110,6 +1115,11 @@ <h3>React Native for Web</h3>
         >React Native documentation</a
       >
     </li>
+    <li>
+      <a href="{{DOCS_BASE_URL}}languages/react-native" target="_blank" rel="noopener"
+        >LiveCodes Documentations</a
+      >
+    </li>
     <li>
       <a href="?template=react-native" target="_parent" data-template="react-native"
         >Load starter template</a