+
Controls
+ {controls.length === 0 ? (
+
No adjustable props
+ ) : (
+
+ {controls.map((prop) => {
+ const { name, type } = prop;
+ const id = `ctrl-${name}`;
+ const checked = values[name] === 'true';
+
+ let control: JSX.Element;
+ if (isBooleanEnum(type) || type.name === 'boolean') {
+ control = (
+ onChange(name, e.target.checked ? 'true' : 'false')}
+ />
+ );
+ } else if (type.name === 'enum' && type.value) {
+ control = (
+
+ );
+ } else {
+ control = (
+ onChange(name, e.target.value)}
+ />
+ );
+ }
+
+ return (
+
+
+ {control}
+
+ );
+ })}
+
+ )}
+
+ );
+}
diff --git a/www/src/components/Playground/Playground.tsx b/www/src/components/Playground/Playground.tsx
new file mode 100644
index 00000000..a1d6547c
--- /dev/null
+++ b/www/src/components/Playground/Playground.tsx
@@ -0,0 +1,114 @@
+import { useMemo, useState } from 'react';
+import { LiveEditor, LiveError, LivePreview, LiveProvider } from 'react-live';
+
+import BrowserOnly from '@docusaurus/BrowserOnly';
+import { themes } from 'prism-react-renderer';
+
+import { ControlsPanel } from './ControlsPanel';
+import { generateCode, initialDefaults } from './generateCode';
+import { PropTable } from './PropTable';
+import { type ComponentRegistryKey, componentRegistry } from './registry';
+
+type PlaygroundProps = {
+ component: string;
+};
+
+type RegistryEntry = (typeof componentRegistry)[ComponentRegistryKey];
+
+const sectionLabel = 'px-4 py-2.5 text-sm font-medium text-gray-500';
+
+// A dark "stage" with a soft center spotlight and a faint dot grid, so the
+// component reads as placed on a surface rather than floating in a black void.
+const stageStyle: React.CSSProperties = {
+ backgroundColor: 'var(--side-color-background-base, #111111)',
+ backgroundImage:
+ 'radial-gradient(ellipse 70% 55% at 50% 42%, rgba(255,255,255,0.10), rgba(255,255,255,0) 70%), radial-gradient(rgba(255,255,255,0.06) 1px, transparent 1.5px)',
+ backgroundSize: '100% 100%, 18px 18px',
+};
+
+function CopyButton({ code }: { code: string }) {
+ const [copied, setCopied] = useState(false);
+ return (
+