@aquiles-ai/renderize 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Renderize: () => Renderize
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/Renderize.tsx
28
+ var import_react = require("react");
29
+
30
+ // src/template.ts
31
+ function buildTemplate(code) {
32
+ return (
33
+ /* html */
34
+ `
35
+ <!DOCTYPE html>
36
+ <html lang="en">
37
+ <head>
38
+ <meta charset="UTF-8" />
39
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
40
+
41
+ <!-- Tailwind CSS Play CDN -->
42
+ <script src="https://cdn.tailwindcss.com"></script>
43
+
44
+ <!-- Babel standalone: transpiles JSX at runtime -->
45
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
46
+
47
+ <!-- Import map: React + Radix UI + Lucide -->
48
+ <script type="importmap">
49
+ {
50
+ "imports": {
51
+ "react": "https://esm.sh/react@18",
52
+ "react/jsx-runtime": "https://esm.sh/react@18/jsx-runtime",
53
+ "react-dom": "https://esm.sh/react-dom@18",
54
+ "react-dom/client": "https://esm.sh/react-dom@18/client",
55
+ "lucide-react": "https://esm.sh/lucide-react@latest",
56
+ "clsx": "https://esm.sh/clsx",
57
+ "class-variance-authority": "https://esm.sh/class-variance-authority",
58
+ "tailwind-merge": "https://esm.sh/tailwind-merge",
59
+ "@radix-ui/react-accordion": "https://esm.sh/@radix-ui/react-accordion",
60
+ "@radix-ui/react-alert-dialog": "https://esm.sh/@radix-ui/react-alert-dialog",
61
+ "@radix-ui/react-avatar": "https://esm.sh/@radix-ui/react-avatar",
62
+ "@radix-ui/react-checkbox": "https://esm.sh/@radix-ui/react-checkbox",
63
+ "@radix-ui/react-collapsible": "https://esm.sh/@radix-ui/react-collapsible",
64
+ "@radix-ui/react-context-menu": "https://esm.sh/@radix-ui/react-context-menu",
65
+ "@radix-ui/react-dialog": "https://esm.sh/@radix-ui/react-dialog",
66
+ "@radix-ui/react-dropdown-menu": "https://esm.sh/@radix-ui/react-dropdown-menu",
67
+ "@radix-ui/react-hover-card": "https://esm.sh/@radix-ui/react-hover-card",
68
+ "@radix-ui/react-label": "https://esm.sh/@radix-ui/react-label",
69
+ "@radix-ui/react-menubar": "https://esm.sh/@radix-ui/react-menubar",
70
+ "@radix-ui/react-navigation-menu": "https://esm.sh/@radix-ui/react-navigation-menu",
71
+ "@radix-ui/react-popover": "https://esm.sh/@radix-ui/react-popover",
72
+ "@radix-ui/react-progress": "https://esm.sh/@radix-ui/react-progress",
73
+ "@radix-ui/react-radio-group": "https://esm.sh/@radix-ui/react-radio-group",
74
+ "@radix-ui/react-scroll-area": "https://esm.sh/@radix-ui/react-scroll-area",
75
+ "@radix-ui/react-select": "https://esm.sh/@radix-ui/react-select",
76
+ "@radix-ui/react-separator": "https://esm.sh/@radix-ui/react-separator",
77
+ "@radix-ui/react-slider": "https://esm.sh/@radix-ui/react-slider",
78
+ "@radix-ui/react-slot": "https://esm.sh/@radix-ui/react-slot",
79
+ "@radix-ui/react-switch": "https://esm.sh/@radix-ui/react-switch",
80
+ "@radix-ui/react-tabs": "https://esm.sh/@radix-ui/react-tabs",
81
+ "@radix-ui/react-toast": "https://esm.sh/@radix-ui/react-toast",
82
+ "@radix-ui/react-toggle": "https://esm.sh/@radix-ui/react-toggle",
83
+ "@radix-ui/react-toggle-group": "https://esm.sh/@radix-ui/react-toggle-group",
84
+ "@radix-ui/react-toolbar": "https://esm.sh/@radix-ui/react-toolbar",
85
+ "@radix-ui/react-tooltip": "https://esm.sh/@radix-ui/react-tooltip"
86
+ }
87
+ }
88
+ </script>
89
+
90
+ <style>
91
+ * { box-sizing: border-box; }
92
+ body { margin: 0; padding: 0; }
93
+ </style>
94
+ </head>
95
+ <body>
96
+ <div id="root"></div>
97
+
98
+ <script type="text/babel" data-type="module">
99
+ import { createRoot } from "react-dom/client";
100
+
101
+ // \u2500\u2500 USER CODE START \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
102
+ ${code}
103
+ // \u2500\u2500 USER CODE END \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
104
+
105
+ const container = document.getElementById("root");
106
+ createRoot(container).render(<App />);
107
+ </script>
108
+ </body>
109
+ </html>
110
+ `.trim()
111
+ );
112
+ }
113
+
114
+ // src/Renderize.tsx
115
+ var import_jsx_runtime = require("react/jsx-runtime");
116
+ function Renderize({
117
+ code,
118
+ height = "100%",
119
+ width = "100%",
120
+ className,
121
+ style,
122
+ onError
123
+ }) {
124
+ const prevUrlRef = (0, import_react.useRef)(null);
125
+ const [blobUrl, setBlobUrl] = (0, import_react.useState)(null);
126
+ (0, import_react.useEffect)(() => {
127
+ if (!code?.trim()) return;
128
+ if (prevUrlRef.current) {
129
+ URL.revokeObjectURL(prevUrlRef.current);
130
+ }
131
+ const html = buildTemplate(code);
132
+ const blob = new Blob([html], { type: "text/html" });
133
+ const url = URL.createObjectURL(blob);
134
+ prevUrlRef.current = url;
135
+ setBlobUrl(url);
136
+ return () => {
137
+ if (prevUrlRef.current) {
138
+ URL.revokeObjectURL(prevUrlRef.current);
139
+ prevUrlRef.current = null;
140
+ }
141
+ };
142
+ }, [code]);
143
+ (0, import_react.useEffect)(() => {
144
+ const handler = (event) => {
145
+ if (event.data?.source === "renderize" && event.data?.type === "error" && onError) {
146
+ onError(event.data.message);
147
+ }
148
+ };
149
+ window.addEventListener("message", handler);
150
+ return () => window.removeEventListener("message", handler);
151
+ }, [onError]);
152
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
153
+ "div",
154
+ {
155
+ className,
156
+ style: { width, height, overflow: "hidden", ...style },
157
+ children: blobUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
158
+ "iframe",
159
+ {
160
+ src: blobUrl,
161
+ title: "Renderize Sandbox",
162
+ sandbox: "allow-scripts",
163
+ style: {
164
+ width: "100%",
165
+ height: "100%",
166
+ border: "none",
167
+ display: "block"
168
+ }
169
+ },
170
+ blobUrl
171
+ )
172
+ }
173
+ );
174
+ }
175
+ // Annotate the CommonJS export names for ESM import in node:
176
+ 0 && (module.exports = {
177
+ Renderize
178
+ });
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface RenderizeProps {
5
+ /** React code generated by the LLM. Must export a default `App` function component. */
6
+ code: string;
7
+ /** Height of the sandbox iframe. Defaults to "100%" */
8
+ height?: string | number;
9
+ /** Width of the sandbox iframe. Defaults to "100%" */
10
+ width?: string | number;
11
+ /** Custom class name for the wrapper element */
12
+ className?: string;
13
+ /** Custom inline styles for the wrapper element */
14
+ style?: React.CSSProperties;
15
+ /** Called when the sandbox encounters a runtime error */
16
+ onError?: (error: string) => void;
17
+ }
18
+ declare function Renderize({ code, height, width, className, style, onError, }: RenderizeProps): react_jsx_runtime.JSX.Element;
19
+
20
+ export { Renderize, type RenderizeProps };
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface RenderizeProps {
5
+ /** React code generated by the LLM. Must export a default `App` function component. */
6
+ code: string;
7
+ /** Height of the sandbox iframe. Defaults to "100%" */
8
+ height?: string | number;
9
+ /** Width of the sandbox iframe. Defaults to "100%" */
10
+ width?: string | number;
11
+ /** Custom class name for the wrapper element */
12
+ className?: string;
13
+ /** Custom inline styles for the wrapper element */
14
+ style?: React.CSSProperties;
15
+ /** Called when the sandbox encounters a runtime error */
16
+ onError?: (error: string) => void;
17
+ }
18
+ declare function Renderize({ code, height, width, className, style, onError, }: RenderizeProps): react_jsx_runtime.JSX.Element;
19
+
20
+ export { Renderize, type RenderizeProps };
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ // src/Renderize.tsx
2
+ import { useEffect, useRef, useState } from "react";
3
+
4
+ // src/template.ts
5
+ function buildTemplate(code) {
6
+ return (
7
+ /* html */
8
+ `
9
+ <!DOCTYPE html>
10
+ <html lang="en">
11
+ <head>
12
+ <meta charset="UTF-8" />
13
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
14
+
15
+ <!-- Tailwind CSS Play CDN -->
16
+ <script src="https://cdn.tailwindcss.com"></script>
17
+
18
+ <!-- Babel standalone: transpiles JSX at runtime -->
19
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
20
+
21
+ <!-- Import map: React + Radix UI + Lucide -->
22
+ <script type="importmap">
23
+ {
24
+ "imports": {
25
+ "react": "https://esm.sh/react@18",
26
+ "react/jsx-runtime": "https://esm.sh/react@18/jsx-runtime",
27
+ "react-dom": "https://esm.sh/react-dom@18",
28
+ "react-dom/client": "https://esm.sh/react-dom@18/client",
29
+ "lucide-react": "https://esm.sh/lucide-react@latest",
30
+ "clsx": "https://esm.sh/clsx",
31
+ "class-variance-authority": "https://esm.sh/class-variance-authority",
32
+ "tailwind-merge": "https://esm.sh/tailwind-merge",
33
+ "@radix-ui/react-accordion": "https://esm.sh/@radix-ui/react-accordion",
34
+ "@radix-ui/react-alert-dialog": "https://esm.sh/@radix-ui/react-alert-dialog",
35
+ "@radix-ui/react-avatar": "https://esm.sh/@radix-ui/react-avatar",
36
+ "@radix-ui/react-checkbox": "https://esm.sh/@radix-ui/react-checkbox",
37
+ "@radix-ui/react-collapsible": "https://esm.sh/@radix-ui/react-collapsible",
38
+ "@radix-ui/react-context-menu": "https://esm.sh/@radix-ui/react-context-menu",
39
+ "@radix-ui/react-dialog": "https://esm.sh/@radix-ui/react-dialog",
40
+ "@radix-ui/react-dropdown-menu": "https://esm.sh/@radix-ui/react-dropdown-menu",
41
+ "@radix-ui/react-hover-card": "https://esm.sh/@radix-ui/react-hover-card",
42
+ "@radix-ui/react-label": "https://esm.sh/@radix-ui/react-label",
43
+ "@radix-ui/react-menubar": "https://esm.sh/@radix-ui/react-menubar",
44
+ "@radix-ui/react-navigation-menu": "https://esm.sh/@radix-ui/react-navigation-menu",
45
+ "@radix-ui/react-popover": "https://esm.sh/@radix-ui/react-popover",
46
+ "@radix-ui/react-progress": "https://esm.sh/@radix-ui/react-progress",
47
+ "@radix-ui/react-radio-group": "https://esm.sh/@radix-ui/react-radio-group",
48
+ "@radix-ui/react-scroll-area": "https://esm.sh/@radix-ui/react-scroll-area",
49
+ "@radix-ui/react-select": "https://esm.sh/@radix-ui/react-select",
50
+ "@radix-ui/react-separator": "https://esm.sh/@radix-ui/react-separator",
51
+ "@radix-ui/react-slider": "https://esm.sh/@radix-ui/react-slider",
52
+ "@radix-ui/react-slot": "https://esm.sh/@radix-ui/react-slot",
53
+ "@radix-ui/react-switch": "https://esm.sh/@radix-ui/react-switch",
54
+ "@radix-ui/react-tabs": "https://esm.sh/@radix-ui/react-tabs",
55
+ "@radix-ui/react-toast": "https://esm.sh/@radix-ui/react-toast",
56
+ "@radix-ui/react-toggle": "https://esm.sh/@radix-ui/react-toggle",
57
+ "@radix-ui/react-toggle-group": "https://esm.sh/@radix-ui/react-toggle-group",
58
+ "@radix-ui/react-toolbar": "https://esm.sh/@radix-ui/react-toolbar",
59
+ "@radix-ui/react-tooltip": "https://esm.sh/@radix-ui/react-tooltip"
60
+ }
61
+ }
62
+ </script>
63
+
64
+ <style>
65
+ * { box-sizing: border-box; }
66
+ body { margin: 0; padding: 0; }
67
+ </style>
68
+ </head>
69
+ <body>
70
+ <div id="root"></div>
71
+
72
+ <script type="text/babel" data-type="module">
73
+ import { createRoot } from "react-dom/client";
74
+
75
+ // \u2500\u2500 USER CODE START \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
76
+ ${code}
77
+ // \u2500\u2500 USER CODE END \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
78
+
79
+ const container = document.getElementById("root");
80
+ createRoot(container).render(<App />);
81
+ </script>
82
+ </body>
83
+ </html>
84
+ `.trim()
85
+ );
86
+ }
87
+
88
+ // src/Renderize.tsx
89
+ import { jsx } from "react/jsx-runtime";
90
+ function Renderize({
91
+ code,
92
+ height = "100%",
93
+ width = "100%",
94
+ className,
95
+ style,
96
+ onError
97
+ }) {
98
+ const prevUrlRef = useRef(null);
99
+ const [blobUrl, setBlobUrl] = useState(null);
100
+ useEffect(() => {
101
+ if (!code?.trim()) return;
102
+ if (prevUrlRef.current) {
103
+ URL.revokeObjectURL(prevUrlRef.current);
104
+ }
105
+ const html = buildTemplate(code);
106
+ const blob = new Blob([html], { type: "text/html" });
107
+ const url = URL.createObjectURL(blob);
108
+ prevUrlRef.current = url;
109
+ setBlobUrl(url);
110
+ return () => {
111
+ if (prevUrlRef.current) {
112
+ URL.revokeObjectURL(prevUrlRef.current);
113
+ prevUrlRef.current = null;
114
+ }
115
+ };
116
+ }, [code]);
117
+ useEffect(() => {
118
+ const handler = (event) => {
119
+ if (event.data?.source === "renderize" && event.data?.type === "error" && onError) {
120
+ onError(event.data.message);
121
+ }
122
+ };
123
+ window.addEventListener("message", handler);
124
+ return () => window.removeEventListener("message", handler);
125
+ }, [onError]);
126
+ return /* @__PURE__ */ jsx(
127
+ "div",
128
+ {
129
+ className,
130
+ style: { width, height, overflow: "hidden", ...style },
131
+ children: blobUrl && /* @__PURE__ */ jsx(
132
+ "iframe",
133
+ {
134
+ src: blobUrl,
135
+ title: "Renderize Sandbox",
136
+ sandbox: "allow-scripts",
137
+ style: {
138
+ width: "100%",
139
+ height: "100%",
140
+ border: "none",
141
+ display: "block"
142
+ }
143
+ },
144
+ blobUrl
145
+ )
146
+ }
147
+ );
148
+ }
149
+ export {
150
+ Renderize
151
+ };
package/package.json CHANGED
@@ -1,8 +1,10 @@
1
1
  {
2
2
  "name": "@aquiles-ai/renderize",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "Drop-in sandbox component that executes AI-generated React code with zero configuration.",
5
- "main": "index.js",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
6
8
  "scripts": {
7
9
  "build": "tsup src/index.ts --format cjs,esm --dts --external react react-dom",
8
10
  "dev": "tsup src/index.ts --format cjs,esm --dts --external react react-dom --watch"
@@ -35,6 +37,7 @@
35
37
  },
36
38
  "dependencies": {
37
39
  "react": "^19.2.4",
38
- "react-dom": "^19.2.4"
40
+ "react-dom": "^19.2.4",
41
+ "tsup": "^8.5.1"
39
42
  }
40
43
  }
package/src/Renderize.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference lib="dom" />
1
2
  import React, { useEffect, useRef, useState } from "react";
2
3
  import { buildTemplate } from "./template.js";
3
4
 
@@ -24,35 +25,30 @@ export function Renderize({
24
25
  style,
25
26
  onError,
26
27
  }: RenderizeProps) {
27
- const iframeRef = useRef<HTMLIFrameElement>(null);
28
- const blobUrlRef = useRef<string | null>(null);
29
- const [key, setKey] = useState(0);
28
+ const prevUrlRef = useRef<string | null>(null);
29
+ const [blobUrl, setBlobUrl] = useState<string | null>(null);
30
30
 
31
31
  useEffect(() => {
32
32
  if (!code?.trim()) return;
33
33
 
34
34
  // Revoke previous blob URL to free memory
35
- if (blobUrlRef.current) {
36
- URL.revokeObjectURL(blobUrlRef.current);
35
+ if (prevUrlRef.current) {
36
+ URL.revokeObjectURL(prevUrlRef.current);
37
37
  }
38
38
 
39
39
  const html = buildTemplate(code);
40
40
  const blob = new Blob([html], { type: "text/html" });
41
41
  const url = URL.createObjectURL(blob);
42
42
 
43
- blobUrlRef.current = url;
44
-
45
- if (iframeRef.current) {
46
- iframeRef.current.src = url;
47
- }
48
-
49
- // Force iframe remount when code changes to ensure clean state
50
- setKey((prev) => prev + 1);
43
+ prevUrlRef.current = url;
44
+ // Storing the URL in state ensures the iframe src prop
45
+ // and the actual DOM element are always in sync
46
+ setBlobUrl(url);
51
47
 
52
48
  return () => {
53
- if (blobUrlRef.current) {
54
- URL.revokeObjectURL(blobUrlRef.current);
55
- blobUrlRef.current = null;
49
+ if (prevUrlRef.current) {
50
+ URL.revokeObjectURL(prevUrlRef.current);
51
+ prevUrlRef.current = null;
56
52
  }
57
53
  };
58
54
  }, [code]);
@@ -77,18 +73,22 @@ export function Renderize({
77
73
  className={className}
78
74
  style={{ width, height, overflow: "hidden", ...style }}
79
75
  >
80
- <iframe
81
- key={key}
82
- ref={iframeRef}
83
- title="Renderize Sandbox"
84
- sandbox="allow-scripts"
85
- style={{
86
- width: "100%",
87
- height: "100%",
88
- border: "none",
89
- display: "block",
90
- }}
91
- />
76
+ {blobUrl && (
77
+ <iframe
78
+ // key forces a full remount when the URL changes,
79
+ // guaranteeing a clean JS context on every new code
80
+ key={blobUrl}
81
+ src={blobUrl}
82
+ title="Renderize Sandbox"
83
+ sandbox="allow-scripts"
84
+ style={{
85
+ width: "100%",
86
+ height: "100%",
87
+ border: "none",
88
+ display: "block",
89
+ }}
90
+ />
91
+ )}
92
92
  </div>
93
93
  );
94
94
  }