{"id":25023973,"url":"https://github.com/vgulerianb/react-exe","last_synced_at":"2025-05-16T04:04:36.342Z","repository":{"id":275827020,"uuid":"927318039","full_name":"vgulerianb/react-exe","owner":"vgulerianb","description":"A powerful React component executor that renders code with external dependencies and custom styling","archived":false,"fork":false,"pushed_at":"2025-02-26T11:28:49.000Z","size":12749,"stargazers_count":164,"open_issues_count":3,"forks_count":12,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-17T12:32:08.549Z","etag":null,"topics":["artifacts","claude","javascript","nextjs","playground","react","runtime","v0"],"latest_commit_sha":null,"homepage":"https://react-exe-demo.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vgulerianb.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-04T18:59:56.000Z","updated_at":"2025-04-16T20:42:09.000Z","dependencies_parsed_at":"2025-02-04T20:18:54.527Z","dependency_job_id":"70a8ed59-a8e4-49c7-96d5-b2f2e0a8219d","html_url":"https://github.com/vgulerianb/react-exe","commit_stats":null,"previous_names":["vgulerianb/react-exe"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vgulerianb%2Freact-exe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vgulerianb%2Freact-exe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vgulerianb%2Freact-exe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vgulerianb%2Freact-exe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vgulerianb","download_url":"https://codeload.github.com/vgulerianb/react-exe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254464894,"owners_count":22075570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artifacts","claude","javascript","nextjs","playground","react","runtime","v0"],"created_at":"2025-02-05T15:38:25.857Z","updated_at":"2025-05-16T04:04:36.322Z","avatar_url":"https://github.com/vgulerianb.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# React-EXE\n\nExecute React components on the fly with external dependencies, custom styling, and TypeScript support. Perfect for creating live code previews, documentation, or interactive code playgrounds.\n\n\u003cimg width=\"1512\" alt=\"Screenshot 2025-02-26 at 00 23 34\" src=\"https://github.com/user-attachments/assets/bc690e07-3b7a-4719-8547-f21e08f50b65\" /\u003e\n\nTry the live demo [here](https://react-exe-demo.vercel.app/).\n\n## Features\n\n- 🚀 Execute React components from string code\n- 📦 Support for external dependencies\n- 🎨 Tailwind CSS support\n- 🔒 Built-in security checks\n- 💅 Customizable styling\n- 📝 TypeScript support\n- ⚡ Live rendering\n- 🐛 Error boundary protection\n- 📄 Multi-file support\n\n## Installation\n\n```bash\nnpm install react-exe\n# or\nyarn add react-exe\n# or\npnpm add react-exe\n```\n\n## Basic Usage\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\n\nconst code = `\nexport default function HelloWorld() {\n  return (\n    \u003cdiv className=\"p-4 bg-blue-100 rounded\"\u003e\n      \u003ch1 className=\"text-2xl font-bold\"\u003eHello World!\u003c/h1\u003e\n    \u003c/div\u003e\n  );\n}\n`;\n\nfunction App() {\n  return \u003cCodeExecutor code={code} config={{ enableTailwind: true }} /\u003e;\n}\n```\n\n## Advanced Usage\n\n### With External Dependencies\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\nimport * as echarts from \"echarts\";\nimport * as framerMotion from \"framer-motion\";\n\nconst code = `\nimport { motion } from 'framer-motion';\nimport { LineChart } from 'echarts';\n\nexport default function Dashboard() {\n  return (\n    \u003cmotion.div\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n      className=\"p-6 space-y-4\"\n    \u003e\n      \u003cLineChart \n        option={{\n          xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },\n          yAxis: { type: 'value' },\n          series: [{ data: [150, 230, 224], type: 'line' }]\n        }}\n        style={{ height: '300px' }}\n      /\u003e\n    \u003c/motion.div\u003e\n  );\n}\n`;\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={code}\n      config={{\n        dependencies: {\n          \"framer-motion\": framerMotion,\n          echarts: echarts,\n        },\n        enableTailwind: true,\n        containerClassName: \"min-h-[400px]\",\n        containerStyle: {\n          padding: \"20px\",\n          background: \"#f9fafb\",\n        },\n      }}\n    /\u003e\n  );\n}\n```\n\n### With absolute imports and wildcard patterns\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\nimport * as echarts from \"echarts\";\nimport * as framerMotion from \"framer-motion\";\nimport * as uiComponents from \"../ShadcnComps\";\n\nconst code = `\nimport { motion } from 'framer-motion';\nimport { LineChart } from 'echarts';\nimport { Button } from \"@/components/ui/button\"\n\nexport default function Dashboard() {\n  return (\n    \u003cmotion.div\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n      className=\"p-6 space-y-4\"\n    \u003e\n      \u003cLineChart \n        option={{\n          xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },\n          yAxis: { type: 'value' },\n          series: [{ data: [150, 230, 224], type: 'line' }]\n        }}\n        style={{ height: '300px' }}\n      /\u003e\n    \u003c/motion.div\u003e\n  );\n}\n`;\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={code}\n      config={{\n        dependencies: {\n          \"framer-motion\": framerMotion,\n          echarts: echarts,\n          \"@/components/ui/*\": uiComponents,\n        },\n        enableTailwind: true,\n        containerClassName: \"min-h-[400px]\",\n        containerStyle: {\n          padding: \"20px\",\n          background: \"#f9fafb\",\n        },\n      }}\n    /\u003e\n  );\n}\n```\n\n### With Multiple Files\n\nReact-EXE supports multiple files with cross-imports, allowing you to build more complex components and applications:\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\nimport * as framerMotion from \"framer-motion\";\n\n// Define multiple files as an array of code files\nconst files = [\n  {\n    name: \"App.tsx\", // Main entry file\n    content: `\nimport React from 'react';\nimport { motion } from 'framer-motion';\nimport Header from './Header';\nimport Counter from './Counter';\n\nconst App = () =\u003e {\n  return (\n    \u003cmotion.div \n      className=\"min-h-screen bg-gray-100 p-4\"\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n    \u003e\n      \u003cHeader title=\"Multi-File App Example\" /\u003e\n      \u003cCounter /\u003e\n    \u003c/motion.div\u003e\n  );\n};\n\nexport default App;\n    `,\n    isEntry: true, // Mark this as the entry point\n  },\n  {\n    name: \"Header.tsx\",\n    content: `\nimport React from 'react';\n\ninterface HeaderProps {\n  title: string;\n}\n\nconst Header = ({ title }: HeaderProps) =\u003e {\n  return (\n    \u003cheader className=\"bg-white p-4 mb-4 rounded-lg shadow-md\"\u003e\n      \u003ch1 className=\"text-2xl font-bold text-gray-800\"\u003e{title}\u003c/h1\u003e\n    \u003c/header\u003e\n  );\n};\n\nexport default Header;\n    `,\n  },\n  {\n    name: \"Counter.tsx\",\n    content: `\nimport React, { useState } from 'react';\nimport { motion } from 'framer-motion';\nimport CounterButton from './CounterButton';\n\nconst Counter = () =\u003e {\n  const [count, setCount] = useState(0);\n  \n  const increment = () =\u003e setCount(prev =\u003e prev + 1);\n  const decrement = () =\u003e setCount(prev =\u003e prev - 1);\n  \n  return (\n    \u003cdiv className=\"bg-white p-6 rounded-lg shadow-md\"\u003e\n      \u003ch2 className=\"text-xl font-semibold mb-4\"\u003eCounter Component\u003c/h2\u003e\n      \n      \u003cmotion.div \n        className=\"text-center text-3xl font-bold my-4\"\n        key={count}\n        initial={{ scale: 0.8, opacity: 0 }}\n        animate={{ scale: 1, opacity: 1 }}\n      \u003e\n        {count}\n      \u003c/motion.div\u003e\n      \n      \u003cdiv className=\"flex justify-center gap-4\"\u003e\n        \u003cCounterButton onClick={decrement} label=\"Decrease\" variant=\"danger\" /\u003e\n        \u003cCounterButton onClick={increment} label=\"Increase\" variant=\"success\" /\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default Counter;\n    `,\n  },\n  {\n    name: \"CounterButton.tsx\",\n    content: `\nimport React from 'react';\nimport { motion } from 'framer-motion';\n\ninterface CounterButtonProps {\n  onClick: () =\u003e void;\n  label: string;\n  variant?: 'primary' | 'success' | 'danger';\n}\n\nconst CounterButton = ({ \n  onClick, \n  label, \n  variant = 'primary' \n}: CounterButtonProps) =\u003e {\n  \n  const getButtonColor = () =\u003e {\n    switch(variant) {\n      case 'success': return 'bg-green-500 hover:bg-green-600';\n      case 'danger': return 'bg-red-500 hover:bg-red-600';\n      default: return 'bg-blue-500 hover:bg-blue-600';\n    }\n  };\n  \n  return (\n    \u003cmotion.button\n      className={\\`\\${getButtonColor()} text-white py-2 px-4 rounded\\`}\n      onClick={onClick}\n      whileHover={{ scale: 1.05 }}\n      whileTap={{ scale: 0.95 }}\n    \u003e\n      {label}\n    \u003c/motion.button\u003e\n  );\n};\n\nexport default CounterButton;\n    `,\n  },\n];\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={files}\n      config={{\n        dependencies: {\n          \"framer-motion\": framerMotion,\n        },\n        enableTailwind: true,\n        containerClassName: \"rounded-lg overflow-hidden\",\n      }}\n    /\u003e\n  );\n}\n```\n\n### Creating a Project Structure with Multiple Files\n\nFor more complex applications, you can organize your files in a project-like structure:\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\nimport * as reactRouter from \"react-router-dom\";\nimport * as framerMotion from \"framer-motion\";\n\nconst files = [\n  {\n    name: \"App.tsx\",\n    content: `\nimport React from 'react';\nimport { BrowserRouter, Routes, Route } from 'react-router-dom';\nimport Layout from './components/Layout';\nimport Home from './pages/Home';\nimport About from './pages/About';\nimport NotFound from './pages/NotFound';\n\nconst App = () =\u003e {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path=\"/\" element={\u003cLayout /\u003e}\u003e\n          \u003cRoute index element={\u003cHome /\u003e} /\u003e\n          \u003cRoute path=\"about\" element={\u003cAbout /\u003e} /\u003e\n          \u003cRoute path=\"*\" element={\u003cNotFound /\u003e} /\u003e\n        \u003c/Route\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n};\n\nexport default App;\n    `,\n    isEntry: true,\n  },\n  {\n    name: \"components/Layout.tsx\",\n    content: `\nimport React from 'react';\nimport { Outlet } from 'react-router-dom';\nimport Navbar from './Navbar';\nimport Footer from './Footer';\n\nconst Layout = () =\u003e {\n  return (\n    \u003cdiv className=\"min-h-screen flex flex-col\"\u003e\n      \u003cNavbar /\u003e\n      \u003cmain className=\"flex-grow container mx-auto px-4 py-8\"\u003e\n        \u003cOutlet /\u003e\n      \u003c/main\u003e\n      \u003cFooter /\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default Layout;\n    `,\n  },\n  {\n    name: \"components/Navbar.tsx\",\n    content: `\nimport React from 'react';\nimport { Link, useLocation } from 'react-router-dom';\n\nconst Navbar = () =\u003e {\n  const location = useLocation();\n  \n  const isActive = (path: string) =\u003e {\n    return location.pathname === path ? \n      'text-white bg-indigo-700' : \n      'text-indigo-200 hover:text-white hover:bg-indigo-600';\n  };\n  \n  return (\n    \u003cnav className=\"bg-indigo-800 text-white shadow-md\"\u003e\n      \u003cdiv className=\"container mx-auto px-4\"\u003e\n        \u003cdiv className=\"flex justify-between items-center h-16\"\u003e\n          \u003cLink to=\"/\" className=\"font-bold text-xl\"\u003eMulti-File App\u003c/Link\u003e\n          \n          \u003cdiv className=\"flex space-x-4\"\u003e\n            \u003cLink \n              to=\"/\" \n              className={\\`px-3 py-2 rounded-md \\${isActive('/')}\\`}\n            \u003e\n              Home\n            \u003c/Link\u003e\n            \u003cLink \n              to=\"/about\" \n              className={\\`px-3 py-2 rounded-md \\${isActive('/about')}\\`}\n            \u003e\n              About\n            \u003c/Link\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/nav\u003e\n  );\n};\n\nexport default Navbar;\n    `,\n  },\n  {\n    name: \"components/Footer.tsx\",\n    content: `\nimport React from 'react';\n\nconst Footer = () =\u003e {\n  return (\n    \u003cfooter className=\"bg-gray-800 text-white py-6\"\u003e\n      \u003cdiv className=\"container mx-auto px-4 text-center\"\u003e\n        \u003cp\u003e\u0026copy; {new Date().getFullYear()} React-EXE Demo\u003c/p\u003e\n        \u003cp className=\"text-gray-400 text-sm mt-1\"\u003eBuilt with multiple files\u003c/p\u003e\n      \u003c/div\u003e\n    \u003c/footer\u003e\n  );\n};\n\nexport default Footer;\n    `,\n  },\n  {\n    name: \"pages/Home.tsx\",\n    content: `\nimport React from 'react';\nimport { motion } from 'framer-motion';\n\nconst Home = () =\u003e {\n  return (\n    \u003cmotion.div\n      initial={{ opacity: 0, y: 20 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ duration: 0.5 }}\n    \u003e\n      \u003ch1 className=\"text-3xl font-bold mb-6\"\u003eWelcome to the Home Page\u003c/h1\u003e\n      \u003cp className=\"mb-4\"\u003eThis is a multi-file application example using React-EXE.\u003c/p\u003e\n      \u003cp className=\"mb-4\"\u003e\n        It demonstrates how you can create complex applications with multiple\n        components, pages, and even routing!\n      \u003c/p\u003e\n      \n      \u003cdiv className=\"mt-8 p-6 bg-indigo-50 rounded-lg shadow-sm\"\u003e\n        \u003ch2 className=\"text-xl font-semibold mb-4\"\u003eFeatures Demonstrated:\u003c/h2\u003e\n        \u003cul className=\"list-disc pl-5 space-y-2\"\u003e\n          \u003cli\u003eMultiple file structure\u003c/li\u003e\n          \u003cli\u003eReact Router integration\u003c/li\u003e\n          \u003cli\u003eAnimation with Framer Motion\u003c/li\u003e\n          \u003cli\u003eComponent composition\u003c/li\u003e\n          \u003cli\u003eStyling with Tailwind CSS\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/div\u003e\n    \u003c/motion.div\u003e\n  );\n};\n\nexport default Home;\n    `,\n  },\n  {\n    name: \"pages/About.tsx\",\n    content: `\nimport React from 'react';\nimport { motion } from 'framer-motion';\n\nconst About = () =\u003e {\n  return (\n    \u003cmotion.div\n      initial={{ opacity: 0, y: 20 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ duration: 0.5 }}\n    \u003e\n      \u003ch1 className=\"text-3xl font-bold mb-6\"\u003eAbout Page\u003c/h1\u003e\n      \u003cp className=\"mb-4\"\u003e\n        React-EXE is a powerful library for executing React components on the fly.\n        It supports multi-file applications like this one!\n      \u003c/p\u003e\n      \n      \u003cmotion.div \n        className=\"mt-8 grid grid-cols-1 md:grid-cols-3 gap-4\"\n        variants={{\n          hidden: { opacity: 0 },\n          show: {\n            opacity: 1,\n            transition: {\n              staggerChildren: 0.2\n            }\n          }\n        }}\n        initial=\"hidden\"\n        animate=\"show\"\n      \u003e\n        {[1, 2, 3].map((item) =\u003e (\n          \u003cmotion.div\n            key={item}\n            className=\"bg-white p-6 rounded-lg shadow-md\"\n            variants={{\n              hidden: { opacity: 0, y: 20 },\n              show: { opacity: 1, y: 0 }\n            }}\n          \u003e\n            \u003ch3 className=\"font-bold text-lg mb-2\"\u003eFeature {item}\u003c/h3\u003e\n            \u003cp className=\"text-gray-600\"\u003e\n              This is an example of a card that demonstrates Framer Motion animations\n              in a multi-file React component.\n            \u003c/p\u003e\n          \u003c/motion.div\u003e\n        ))}\n      \u003c/motion.div\u003e\n    \u003c/motion.div\u003e\n  );\n};\n\nexport default About;\n    `,\n  },\n  {\n    name: \"pages/NotFound.tsx\",\n    content: `\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { motion } from 'framer-motion';\n\nconst NotFound = () =\u003e {\n  return (\n    \u003cmotion.div \n      className=\"text-center py-12\"\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n      transition={{ duration: 0.5 }}\n    \u003e\n      \u003cmotion.div\n        initial={{ scale: 0.8 }}\n        animate={{ scale: 1 }}\n        transition={{ \n          type: \"spring\", \n          stiffness: 200, \n          damping: 10 \n        }}\n      \u003e\n        \u003ch1 className=\"text-9xl font-bold text-indigo-200\"\u003e404\u003c/h1\u003e\n      \u003c/motion.div\u003e\n      \n      \u003ch2 className=\"text-3xl font-bold mb-4\"\u003ePage Not Found\u003c/h2\u003e\n      \u003cp className=\"text-gray-600 mb-8\"\u003e\n        The page you're looking for doesn't exist or has been moved.\n      \u003c/p\u003e\n      \n      \u003cLink \n        to=\"/\" \n        className=\"bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition-colors\"\n      \u003e\n        Return Home\n      \u003c/Link\u003e\n    \u003c/motion.div\u003e\n  );\n};\n\nexport default NotFound;\n    `,\n  },\n];\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={files}\n      config={{\n        dependencies: {\n          \"react-router-dom\": reactRouter,\n          \"framer-motion\": framerMotion,\n        },\n        enableTailwind: true,\n      }}\n    /\u003e\n  );\n}\n```\n\n### Using Custom Hooks and Utilities in Multi-File Apps\n\nYou can also create and use custom hooks, utilities, and TypeScript types across multiple files:\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\n\nconst files = [\n  {\n    name: \"App.tsx\",\n    content: `\nimport React from 'react';\nimport ThemeProvider from './theme/ThemeProvider';\nimport ThemeSwitcher from './components/ThemeSwitcher';\nimport UserProfile from './components/UserProfile';\nimport { fetchUserData } from './utils/api';\n\nconst App = () =\u003e {\n  return (\n    \u003cThemeProvider\u003e\n      \u003cdiv className=\"min-h-screen p-6\"\u003e\n        \u003cdiv className=\"max-w-lg mx-auto\"\u003e\n          \u003cdiv className=\"flex justify-end mb-6\"\u003e\n            \u003cThemeSwitcher /\u003e\n          \u003c/div\u003e\n          \u003cUserProfile userId=\"1\" fetchUserData={fetchUserData} /\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/ThemeProvider\u003e\n  );\n};\n\nexport default App;\n    `,\n    isEntry: true,\n  },\n  {\n    name: \"types/index.ts\",\n    content: `\nexport interface User {\n  id: string;\n  name: string;\n  email: string;\n  avatar: string;\n}\n\nexport type Theme = 'light' | 'dark' | 'system';\n\nexport interface ThemeContextType {\n  theme: Theme;\n  setTheme: (theme: Theme) =\u003e void;\n}\n    `,\n  },\n  {\n    name: \"theme/ThemeProvider.tsx\",\n    content: `\nimport React, { createContext, useContext, useState, useEffect } from 'react';\nimport { Theme, ThemeContextType } from '../types';\n\nconst ThemeContext = createContext\u003cThemeContextType | undefined\u003e(undefined);\n\nconst ThemeProvider: React.FC\u003c{ children: React.ReactNode }\u003e = ({ children }) =\u003e {\n  const [theme, setTheme] = useState\u003cTheme\u003e('system');\n  \n  useEffect(() =\u003e {\n    const applyTheme = (newTheme: Theme) =\u003e {\n      const root = window.document.documentElement;\n      \n      // Remove any existing theme classes\n      root.classList.remove('light', 'dark');\n      \n      // Apply the appropriate theme\n      if (newTheme === 'system') {\n        const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n        root.classList.add(systemTheme);\n      } else {\n        root.classList.add(newTheme);\n      }\n    };\n    \n    applyTheme(theme);\n    \n    // Listen for system theme changes\n    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n    const handleChange = () =\u003e {\n      if (theme === 'system') {\n        applyTheme('system');\n      }\n    };\n    \n    mediaQuery.addEventListener('change', handleChange);\n    return () =\u003e mediaQuery.removeEventListener('change', handleChange);\n  }, [theme]);\n  \n  return (\n    \u003cThemeContext.Provider value={{ theme, setTheme }}\u003e\n      {children}\n    \u003c/ThemeContext.Provider\u003e\n  );\n};\n\nexport const useTheme = () =\u003e {\n  const context = useContext(ThemeContext);\n  if (context === undefined) {\n    throw new Error('useTheme must be used within a ThemeProvider');\n  }\n  return context;\n};\n\nexport default ThemeProvider;\n    `,\n  },\n  {\n    name: \"components/ThemeSwitcher.tsx\",\n    content: `\nimport React from 'react';\nimport { useTheme } from '../theme/ThemeProvider';\nimport { Theme } from '../types';\n\nconst ThemeSwitcher = () =\u003e {\n  const { theme, setTheme } = useTheme();\n  \n  const themes: { value: Theme; label: string }[] = [\n    { value: 'light', label: '☀️ Light' },\n    { value: 'dark', label: '🌙 Dark' },\n    { value: 'system', label: '🖥️ System' }\n  ];\n  \n  return (\n    \u003cdiv className=\"bg-white dark:bg-gray-800 p-3 rounded-lg shadow-md inline-block\"\u003e\n      \u003cdiv className=\"flex space-x-2\"\u003e\n        {themes.map(({ value, label }) =\u003e (\n          \u003cbutton\n            key={value}\n            onClick={() =\u003e setTheme(value)}\n            className={\\`px-3 py-1 rounded-md \\${\n              theme === value\n                ? 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200'\n                : 'hover:bg-gray-100 dark:hover:bg-gray-700'\n            }\\`}\n          \u003e\n            {label}\n          \u003c/button\u003e\n        ))}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default ThemeSwitcher;\n    `,\n  },\n  {\n    name: \"hooks/useUser.ts\",\n    content: `\nimport { useState, useEffect } from 'react';\nimport { User } from '../types';\n\nexport const useUser = (\n  userId: string,\n  fetchUserData: (id: string) =\u003e Promise\u003cUser\u003e\n) =\u003e {\n  const [user, setUser] = useState\u003cUser | null\u003e(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState\u003cstring | null\u003e(null);\n  \n  useEffect(() =\u003e {\n    let isMounted = true;\n    \n    const loadUser = async () =\u003e {\n      try {\n        setLoading(true);\n        const userData = await fetchUserData(userId);\n        \n        if (isMounted) {\n          setUser(userData);\n          setError(null);\n        }\n      } catch (err) {\n        if (isMounted) {\n          setError('Failed to load user');\n          setUser(null);\n        }\n      } finally {\n        if (isMounted) {\n          setLoading(false);\n        }\n      }\n    };\n    \n    loadUser();\n    \n    return () =\u003e {\n      isMounted = false;\n    };\n  }, [userId, fetchUserData]);\n  \n  return { user, loading, error };\n};\n    `,\n  },\n  {\n    name: \"utils/api.ts\",\n    content: `\nimport { User } from '../types';\n\n// Simulate API call with mock data\nexport const fetchUserData = async (userId: string): Promise\u003cUser\u003e =\u003e {\n  // Simulate network delay\n  await new Promise(resolve =\u003e setTimeout(resolve, 1000));\n  \n  // Mock data\n  const users: Record\u003cstring, User\u003e = {\n    '1': {\n      id: '1',\n      name: 'John Doe',\n      email: 'john@example.com',\n      avatar: 'https://randomuser.me/api/portraits/men/32.jpg'\n    },\n    '2': {\n      id: '2',\n      name: 'Jane Smith',\n      email: 'jane@example.com',\n      avatar: 'https://randomuser.me/api/portraits/women/44.jpg'\n    }\n  };\n  \n  const user = users[userId];\n  \n  if (!user) {\n    throw new Error(\\`User with ID \\${userId} not found\\`);\n  }\n  \n  return user;\n};\n    `,\n  },\n  {\n    name: \"components/UserProfile.tsx\",\n    content: `\nimport React from 'react';\nimport { useUser } from '../hooks/useUser';\nimport { User } from '../types';\n\ninterface UserProfileProps {\n  userId: string;\n  fetchUserData: (id: string) =\u003e Promise\u003cUser\u003e;\n}\n\nconst UserProfile = ({ userId, fetchUserData }: UserProfileProps) =\u003e {\n  const { user, loading, error } = useUser(userId, fetchUserData);\n  \n  if (loading) {\n    return (\n      \u003cdiv className=\"bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-pulse\"\u003e\n        \u003cdiv className=\"flex items-center space-x-4\"\u003e\n          \u003cdiv className=\"rounded-full bg-gray-300 dark:bg-gray-600 h-16 w-16\"\u003e\u003c/div\u003e\n          \u003cdiv className=\"flex-1 space-y-3\"\u003e\n            \u003cdiv className=\"h-4 bg-gray-300 dark:bg-gray-600 rounded w-3/4\"\u003e\u003c/div\u003e\n            \u003cdiv className=\"h-3 bg-gray-300 dark:bg-gray-600 rounded w-1/2\"\u003e\u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n  \n  if (error) {\n    return (\n      \u003cdiv className=\"bg-red-100 dark:bg-red-900 border-l-4 border-red-500 text-red-700 dark:text-red-200 p-4 rounded\"\u003e\n        \u003cp\u003e{error}\u003c/p\u003e\n      \u003c/div\u003e\n    );\n  }\n  \n  if (!user) {\n    return \u003cdiv\u003eNo user found\u003c/div\u003e;\n  }\n  \n  return (\n    \u003cdiv className=\"bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden\"\u003e\n      \u003cdiv className=\"p-6\"\u003e\n        \u003cdiv className=\"flex items-center space-x-4\"\u003e\n          \u003cimg \n            src={user.avatar} \n            alt={user.name} \n            className=\"h-16 w-16 rounded-full border-2 border-indigo-500\"\n          /\u003e\n          \u003cdiv\u003e\n            \u003ch2 className=\"text-xl font-bold text-gray-900 dark:text-white\"\u003e{user.name}\u003c/h2\u003e\n            \u003cp className=\"text-gray-600 dark:text-gray-300\"\u003e{user.email}\u003c/p\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv className=\"bg-gray-50 dark:bg-gray-900 px-6 py-4\"\u003e\n        \u003cp className=\"text-sm text-gray-500 dark:text-gray-400\"\u003e\n          User ID: {user.id}\n        \u003c/p\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default UserProfile;\n    `,\n  },\n];\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={files}\n      config={{\n        enableTailwind: true,\n      }}\n    /\u003e\n  );\n}\n```\n\n### With Custom Error Handling\n\n```tsx\nimport { CodeExecutor } from \"react-exe\";\n\nfunction App() {\n  return (\n    \u003cCodeExecutor\n      code={code}\n      config={{\n        enableTailwind: true,\n        errorClassName: \"my-error-class\",\n        errorStyle: {\n          background: \"#fee2e2\",\n          border: \"2px solid #ef4444\",\n        },\n        onError: (error) =\u003e {\n          console.error(\"Component error:\", error);\n          // Send to error tracking service\n          trackError(error);\n        },\n        // Custom security patterns\n        securityPatterns: [\n          /localStorage/i,\n          /sessionStorage/i,\n          /window\\.location/i,\n        ],\n      }}\n    /\u003e\n  );\n}\n```\n\n## Configuration Options\n\nThe `config` prop accepts the following options:\n\n```typescript\ninterface CodeExecutorConfig {\n  // External dependencies available to the rendered component\n  dependencies?: Record\u003cstring, any\u003e;\n\n  // Enable Tailwind CSS support\n  enableTailwind?: boolean;\n\n  // Custom className for the container\n  containerClassName?: string;\n\n  // Custom inline styles for the container\n  containerStyle?: React.CSSProperties;\n\n  // Custom className for error messages\n  errorClassName?: string;\n\n  // Custom inline styles for error messages\n  errorStyle?: React.CSSProperties;\n\n  // Custom security patterns to block potentially malicious code\n  securityPatterns?: RegExp[];\n\n  // Error callback function\n  onError?: (error: Error) =\u003e void;\n}\n```\n\n## Code Input Types\n\nReact-EXE accepts code in two formats:\n\n1. **Single File**: Pass a string containing the React component code\n\n   ```typescript\n   // Single file as a string\n   const code = `\n   export default function App() {\n     return \u003cdiv\u003eHello World\u003c/div\u003e;\n   }\n   `;\n   ```\n\n2. **Multiple Files**: Pass an array of CodeFile objects:\n\n   ```typescript\n   // Multiple files\n   const code = [\n     {\n       name: \"App.tsx\",\n       content:\n         \"import React from 'react';\\nimport Button from './Button';\\n...\",\n       isEntry: true, // Mark this as the entry point\n     },\n     {\n       name: \"Button.tsx\",\n       content:\n         \"export default function Button() { return \u003cbutton\u003eClick me\u003c/button\u003e; }\",\n     },\n   ];\n   ```\n\n   The `CodeFile` interface:\n\n   ```typescript\n   interface CodeFile {\n     name: string; // File name with extension (used for imports)\n     content: string; // File content\n     isEntry?: boolean; // Whether this is the entry point (defaults to first file if not specified)\n   }\n   ```\n\n## Security\n\nReact-EXE includes built-in security measures:\n\n- Default security patterns to block potentially harmful code\n- Custom security pattern support\n- Error boundary protection\n\nDefault blocked patterns include:\n\n```typescript\nconst defaultSecurityPatterns = [\n  /document\\.cookie/i,\n  /window\\.document\\.cookie/i,\n  /eval\\(/i,\n  /Function\\(/i,\n  /document\\.write/i,\n  /document\\.location/i,\n];\n```\n\n## TypeScript Support\n\nReact-EXE is written in TypeScript and includes type definitions. For the best development experience, use TypeScript in your project:\n\n```tsx\nimport { CodeExecutor, CodeExecutorConfig, CodeFile } from \"react-exe\";\n\nconst config: CodeExecutorConfig = {\n  enableTailwind: true,\n  dependencies: {\n    \"my-component\": MyComponent,\n  },\n};\n\nconst files: CodeFile[] = [\n  {\n    name: \"App.tsx\",\n    content: `export default function App() { return \u003cdiv\u003eHello\u003c/div\u003e; }`,\n    isEntry: true,\n  },\n];\n\nfunction App() {\n  return \u003cCodeExecutor code={files} config={config} /\u003e;\n}\n```\n\n## Used By [TuneChat](https://chat.tune.app/) to render Artifacts\n\n\u003cimg width=\"1512\" alt=\"Screenshot 2025-02-26 at 16 58 34\" src=\"https://github.com/user-attachments/assets/8b3d096f-1db3-47c3-be90-712c50bdd6d3\" /\u003e\n\n## License\n\nMIT © [Vikrant](https://www.linkedin.com/in/vikrant-guleria/)\n\n---\n\nMade with ❤️ by [Vikrant](https://www.linkedin.com/in/vikrant-guleria/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvgulerianb%2Freact-exe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvgulerianb%2Freact-exe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvgulerianb%2Freact-exe/lists"}