@toriistudio/v0-playground 0.1.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.js ADDED
@@ -0,0 +1,631 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ Playground: () => Playground,
34
+ useControls: () => useControls
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/context/ResizableLayout.tsx
39
+ var import_react = require("react");
40
+ var import_lucide_react = require("lucide-react");
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var ResizableLayoutContext = (0, import_react.createContext)(
43
+ null
44
+ );
45
+ var useResizableLayout = () => {
46
+ const ctx = (0, import_react.useContext)(ResizableLayoutContext);
47
+ if (!ctx) throw new Error("ResizableLayoutContext not found");
48
+ return ctx;
49
+ };
50
+ var ResizableLayout = ({ children }) => {
51
+ const [leftPanelWidth, setLeftPanelWidth] = (0, import_react.useState)(25);
52
+ const [isDesktop, setIsDesktop] = (0, import_react.useState)(false);
53
+ const [isHydrated, setIsHydrated] = (0, import_react.useState)(false);
54
+ const [isDragging, setIsDragging] = (0, import_react.useState)(false);
55
+ const [sidebarNarrow, setSidebarNarrow] = (0, import_react.useState)(false);
56
+ const containerRef = (0, import_react.useRef)(null);
57
+ (0, import_react.useEffect)(() => {
58
+ setIsHydrated(true);
59
+ const handleResize = () => setIsDesktop(window.innerWidth >= 768);
60
+ handleResize();
61
+ window.addEventListener("resize", handleResize);
62
+ return () => window.removeEventListener("resize", handleResize);
63
+ }, []);
64
+ (0, import_react.useEffect)(() => {
65
+ if (!isHydrated || !isDesktop) return;
66
+ const checkSidebarWidth = () => {
67
+ if (containerRef.current) {
68
+ const containerWidth = containerRef.current.clientWidth;
69
+ const sidebarWidth = leftPanelWidth / 100 * containerWidth;
70
+ setSidebarNarrow(sidebarWidth < 350);
71
+ }
72
+ };
73
+ checkSidebarWidth();
74
+ window.addEventListener("resize", checkSidebarWidth);
75
+ return () => window.removeEventListener("resize", checkSidebarWidth);
76
+ }, [leftPanelWidth, isHydrated, isDesktop]);
77
+ (0, import_react.useEffect)(() => {
78
+ const handleMouseMove = (e) => {
79
+ if (isDragging && containerRef.current) {
80
+ const containerRect = containerRef.current.getBoundingClientRect();
81
+ const newLeftWidth = (e.clientX - containerRect.left) / containerRect.width * 100;
82
+ if (newLeftWidth >= 20 && newLeftWidth <= 80) {
83
+ setLeftPanelWidth(newLeftWidth);
84
+ }
85
+ }
86
+ };
87
+ const handleMouseUp = () => setIsDragging(false);
88
+ if (isDragging) {
89
+ document.addEventListener("mousemove", handleMouseMove);
90
+ document.addEventListener("mouseup", handleMouseUp);
91
+ }
92
+ return () => {
93
+ document.removeEventListener("mousemove", handleMouseMove);
94
+ document.removeEventListener("mouseup", handleMouseUp);
95
+ };
96
+ }, [isDragging]);
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ ResizableLayoutContext.Provider,
99
+ {
100
+ value: {
101
+ leftPanelWidth,
102
+ isHydrated,
103
+ isDesktop,
104
+ sidebarNarrow,
105
+ containerRef
106
+ },
107
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "min-h-screen w-full bg-black text-white", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
108
+ "div",
109
+ {
110
+ ref: containerRef,
111
+ className: "flex flex-col md:flex-row min-h-screen w-full overflow-hidden select-none",
112
+ children: [
113
+ children,
114
+ isHydrated && isDesktop && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
+ "div",
116
+ {
117
+ className: "order-3 w-2 bg-stone-800 hover:bg-stone-700 cursor-col-resize items-center justify-center z-10 transition-opacity duration-300",
118
+ onMouseDown: () => setIsDragging(true),
119
+ style: {
120
+ position: "absolute",
121
+ left: `${leftPanelWidth}%`,
122
+ top: 0,
123
+ bottom: 0,
124
+ display: "flex"
125
+ },
126
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.GripVertical, { className: "h-6 w-6 text-stone-500" })
127
+ }
128
+ )
129
+ ]
130
+ }
131
+ ) })
132
+ }
133
+ );
134
+ };
135
+
136
+ // src/context/ControlsContext.tsx
137
+ var import_react2 = require("react");
138
+ var import_jsx_runtime2 = require("react/jsx-runtime");
139
+ var ControlsContext = (0, import_react2.createContext)(null);
140
+ var useControlsContext = () => {
141
+ const ctx = (0, import_react2.useContext)(ControlsContext);
142
+ if (!ctx) throw new Error("useControls must be used within ControlsProvider");
143
+ return ctx;
144
+ };
145
+ var ControlsProvider = ({ children }) => {
146
+ const [schema, setSchema] = (0, import_react2.useState)({});
147
+ const [values, setValues] = (0, import_react2.useState)({});
148
+ const [componentName, setComponentName] = (0, import_react2.useState)();
149
+ const setValue = (key, value) => {
150
+ setValues((prev) => ({ ...prev, [key]: value }));
151
+ };
152
+ const registerSchema = (newSchema, opts) => {
153
+ if (opts?.componentName) {
154
+ setComponentName(opts.componentName);
155
+ }
156
+ setSchema((prevSchema) => ({ ...prevSchema, ...newSchema }));
157
+ setValues((prevValues) => {
158
+ const updated = { ...prevValues };
159
+ for (const key in newSchema) {
160
+ if (!(key in updated)) {
161
+ const control = newSchema[key];
162
+ if ("value" in control) {
163
+ updated[key] = control.value;
164
+ }
165
+ }
166
+ }
167
+ return updated;
168
+ });
169
+ };
170
+ const contextValue = (0, import_react2.useMemo)(
171
+ () => ({ schema, values, setValue, registerSchema, componentName }),
172
+ [schema, values, componentName]
173
+ );
174
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ControlsContext.Provider, { value: contextValue, children });
175
+ };
176
+ var useControls = (schema, options) => {
177
+ const ctx = (0, import_react2.useContext)(ControlsContext);
178
+ if (!ctx) throw new Error("useControls must be used within ControlsProvider");
179
+ (0, import_react2.useEffect)(() => {
180
+ ctx.registerSchema(schema, options);
181
+ }, [JSON.stringify(schema), JSON.stringify(options)]);
182
+ (0, import_react2.useEffect)(() => {
183
+ for (const key in schema) {
184
+ if (!(key in ctx.values) && "value" in schema[key]) {
185
+ ctx.setValue(key, schema[key].value);
186
+ }
187
+ }
188
+ }, [JSON.stringify(schema), JSON.stringify(ctx.values)]);
189
+ const typedValues = ctx.values;
190
+ const jsx11 = (0, import_react2.useCallback)(() => {
191
+ if (!options?.componentName) return "";
192
+ const props = Object.entries(typedValues).map(([key, val]) => {
193
+ if (typeof val === "string") return `${key}="${val}"`;
194
+ if (typeof val === "boolean") return `${key}={${val}}`;
195
+ return `${key}={${JSON.stringify(val)}}`;
196
+ }).join(" ");
197
+ return `<${options.componentName} ${props} />`;
198
+ }, [options?.componentName, JSON.stringify(typedValues)]);
199
+ return {
200
+ ...typedValues,
201
+ controls: ctx.values,
202
+ schema: ctx.schema,
203
+ setValue: ctx.setValue,
204
+ jsx: jsx11
205
+ };
206
+ };
207
+
208
+ // src/components/PreviewContainer/PreviewContainer.tsx
209
+ var import_react3 = require("react");
210
+ var import_jsx_runtime3 = require("react/jsx-runtime");
211
+ var PreviewContainer = ({ children }) => {
212
+ const { leftPanelWidth, isDesktop, isHydrated, containerRef } = useResizableLayout();
213
+ const previewRef = (0, import_react3.useRef)(null);
214
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
215
+ "div",
216
+ {
217
+ ref: previewRef,
218
+ className: "order-1 md:order-2 flex-1 bg-black overflow-auto flex items-center justify-center relative",
219
+ style: isHydrated && isDesktop ? {
220
+ width: `${100 - leftPanelWidth}%`,
221
+ marginLeft: `${leftPanelWidth}%`
222
+ } : {},
223
+ children
224
+ }
225
+ );
226
+ };
227
+ var PreviewContainer_default = PreviewContainer;
228
+
229
+ // src/components/ControlPanel/ControlPanel.tsx
230
+ var import_react4 = require("react");
231
+ var import_lucide_react3 = require("lucide-react");
232
+
233
+ // src/components/ui/switch.tsx
234
+ var React4 = __toESM(require("react"));
235
+ var SwitchPrimitives = __toESM(require("@radix-ui/react-switch"));
236
+
237
+ // src/lib/utils.ts
238
+ var import_clsx = require("clsx");
239
+ var import_tailwind_merge = require("tailwind-merge");
240
+ function cn(...inputs) {
241
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
242
+ }
243
+
244
+ // src/components/ui/switch.tsx
245
+ var import_jsx_runtime4 = require("react/jsx-runtime");
246
+ var Switch = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
247
+ SwitchPrimitives.Root,
248
+ {
249
+ className: cn(
250
+ "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
251
+ className
252
+ ),
253
+ ...props,
254
+ ref,
255
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
256
+ SwitchPrimitives.Thumb,
257
+ {
258
+ className: cn(
259
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
260
+ )
261
+ }
262
+ )
263
+ }
264
+ ));
265
+ Switch.displayName = SwitchPrimitives.Root.displayName;
266
+
267
+ // src/components/ui/label.tsx
268
+ var React5 = __toESM(require("react"));
269
+ var LabelPrimitive = __toESM(require("@radix-ui/react-label"));
270
+ var import_class_variance_authority = require("class-variance-authority");
271
+ var import_jsx_runtime5 = require("react/jsx-runtime");
272
+ var labelVariants = (0, import_class_variance_authority.cva)(
273
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
274
+ );
275
+ var Label = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
276
+ LabelPrimitive.Root,
277
+ {
278
+ ref,
279
+ className: cn(labelVariants(), className),
280
+ ...props
281
+ }
282
+ ));
283
+ Label.displayName = LabelPrimitive.Root.displayName;
284
+
285
+ // src/components/ui/slider.tsx
286
+ var React6 = __toESM(require("react"));
287
+ var SliderPrimitive = __toESM(require("@radix-ui/react-slider"));
288
+ var import_jsx_runtime6 = require("react/jsx-runtime");
289
+ var Slider = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
290
+ SliderPrimitive.Root,
291
+ {
292
+ ref,
293
+ className: cn(
294
+ "relative flex w-full touch-none select-none items-center",
295
+ className
296
+ ),
297
+ ...props,
298
+ children: [
299
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SliderPrimitive.Track, { className: "relative h-2 w-full grow overflow-hidden rounded-full bg-secondary", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SliderPrimitive.Range, { className: "absolute h-full bg-primary" }) }),
300
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SliderPrimitive.Thumb, { className: "block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" })
301
+ ]
302
+ }
303
+ ));
304
+ Slider.displayName = SliderPrimitive.Root.displayName;
305
+
306
+ // src/components/ui/input.tsx
307
+ var React7 = __toESM(require("react"));
308
+ var import_jsx_runtime7 = require("react/jsx-runtime");
309
+ var Input = React7.forwardRef(
310
+ ({ className, type, ...props }, ref) => {
311
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
312
+ "input",
313
+ {
314
+ type,
315
+ className: cn(
316
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
317
+ className
318
+ ),
319
+ ref,
320
+ ...props
321
+ }
322
+ );
323
+ }
324
+ );
325
+ Input.displayName = "Input";
326
+
327
+ // src/components/ui/select.tsx
328
+ var React8 = __toESM(require("react"));
329
+ var SelectPrimitive = __toESM(require("@radix-ui/react-select"));
330
+ var import_lucide_react2 = require("lucide-react");
331
+ var import_jsx_runtime8 = require("react/jsx-runtime");
332
+ var Select = SelectPrimitive.Root;
333
+ var SelectValue = SelectPrimitive.Value;
334
+ var SelectTrigger = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
335
+ SelectPrimitive.Trigger,
336
+ {
337
+ ref,
338
+ className: cn(
339
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
340
+ className
341
+ ),
342
+ ...props,
343
+ children: [
344
+ children,
345
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronDown, { className: "h-4 w-4 opacity-50" }) })
346
+ ]
347
+ }
348
+ ));
349
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
350
+ var SelectScrollUpButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
351
+ SelectPrimitive.ScrollUpButton,
352
+ {
353
+ ref,
354
+ className: cn(
355
+ "flex cursor-default items-center justify-center py-1",
356
+ className
357
+ ),
358
+ ...props,
359
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronUp, { className: "h-4 w-4" })
360
+ }
361
+ ));
362
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
363
+ var SelectScrollDownButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
364
+ SelectPrimitive.ScrollDownButton,
365
+ {
366
+ ref,
367
+ className: cn(
368
+ "flex cursor-default items-center justify-center py-1",
369
+ className
370
+ ),
371
+ ...props,
372
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronDown, { className: "h-4 w-4" })
373
+ }
374
+ ));
375
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
376
+ var SelectContent = React8.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
377
+ SelectPrimitive.Content,
378
+ {
379
+ ref,
380
+ className: cn(
381
+ "relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
382
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
383
+ className
384
+ ),
385
+ position,
386
+ ...props,
387
+ children: [
388
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectScrollUpButton, {}),
389
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
390
+ SelectPrimitive.Viewport,
391
+ {
392
+ className: cn(
393
+ "p-1",
394
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
395
+ ),
396
+ children
397
+ }
398
+ ),
399
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectScrollDownButton, {})
400
+ ]
401
+ }
402
+ ) }));
403
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
404
+ var SelectLabel = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
405
+ SelectPrimitive.Label,
406
+ {
407
+ ref,
408
+ className: cn("px-2 py-1.5 text-sm font-semibold", className),
409
+ ...props
410
+ }
411
+ ));
412
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
413
+ var SelectItem = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
414
+ SelectPrimitive.Item,
415
+ {
416
+ ref,
417
+ className: cn(
418
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
419
+ className
420
+ ),
421
+ ...props,
422
+ children: [
423
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Check, { className: "h-4 w-4" }) }) }),
424
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.ItemText, { children })
425
+ ]
426
+ }
427
+ ));
428
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
429
+ var SelectSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
430
+ SelectPrimitive.Separator,
431
+ {
432
+ ref,
433
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
434
+ ...props
435
+ }
436
+ ));
437
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
438
+
439
+ // src/components/ControlPanel/ControlPanel.tsx
440
+ var import_jsx_runtime9 = require("react/jsx-runtime");
441
+ var ControlPanel = () => {
442
+ const [copied, setCopied] = (0, import_react4.useState)(false);
443
+ const { leftPanelWidth, isDesktop, isHydrated, sidebarNarrow } = useResizableLayout();
444
+ const { schema, setValue, values, componentName } = useControlsContext();
445
+ const normalControls = Object.entries(schema).filter(
446
+ ([, control]) => control.type !== "button"
447
+ );
448
+ const buttonControls = Object.entries(schema).filter(
449
+ ([, control]) => control.type === "button"
450
+ );
451
+ const jsx11 = (0, import_react4.useMemo)(() => {
452
+ if (!componentName) return "";
453
+ const props = Object.entries(values).map(([key, val]) => {
454
+ if (typeof val === "string") return `${key}="${val}"`;
455
+ if (typeof val === "boolean") return `${key}={${val}}`;
456
+ return `${key}={${JSON.stringify(val)}}`;
457
+ }).join(" ");
458
+ return `<${componentName} ${props} />`;
459
+ }, [componentName, values]);
460
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
461
+ "div",
462
+ {
463
+ className: `order-2 md:order-1 w-full md:h-auto p-2 md:p-4 bg-stone-900 font-mono text-stone-300 transition-opacity duration-300 ${!isHydrated ? "opacity-0" : "opacity-100"}`,
464
+ style: {
465
+ width: "100%",
466
+ height: "auto",
467
+ flex: "0 0 auto",
468
+ ...isHydrated && isDesktop ? {
469
+ position: "absolute",
470
+ left: 0,
471
+ top: 0,
472
+ bottom: 0,
473
+ width: `${leftPanelWidth}%`,
474
+ overflowY: "auto"
475
+ } : {}
476
+ },
477
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
478
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "space-y-1", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { className: "text-lg text-stone-100 font-bold", children: "Controls" }) }),
479
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-4 pt-2", children: [
480
+ normalControls.map(([key, control]) => {
481
+ const value = values[key];
482
+ switch (control.type) {
483
+ case "boolean":
484
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
485
+ "div",
486
+ {
487
+ className: "flex items-center space-x-4 border-t border-stone-700 pt-4",
488
+ children: [
489
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
490
+ Switch,
491
+ {
492
+ id: key,
493
+ checked: value,
494
+ onCheckedChange: (v) => setValue(key, v),
495
+ className: "data-[state=checked]:bg-stone-700 data-[state=unchecked]:bg-stone-700/40"
496
+ }
497
+ ),
498
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Label, { htmlFor: key, className: "cursor-pointer", children: key })
499
+ ]
500
+ },
501
+ key
502
+ );
503
+ case "number":
504
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 w-full", children: [
505
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Label, { className: "text-stone-300", htmlFor: key, children: [
506
+ key,
507
+ ": ",
508
+ value
509
+ ] }) }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
511
+ Slider,
512
+ {
513
+ id: key,
514
+ min: control.min ?? 0,
515
+ max: control.max ?? 100,
516
+ step: control.step ?? 1,
517
+ value: [value],
518
+ onValueChange: ([v]) => setValue(key, v),
519
+ className: "[&>span]:border-none [&_.bg-primary]:bg-stone-800 [&>.bg-background]:bg-stone-500/30"
520
+ }
521
+ )
522
+ ] }, key);
523
+ case "string":
524
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
525
+ Input,
526
+ {
527
+ id: key,
528
+ value,
529
+ className: "bg-stone-900",
530
+ placeholder: key,
531
+ onChange: (e) => setValue(key, e.target.value)
532
+ },
533
+ key
534
+ );
535
+ case "color":
536
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 w-full", children: [
537
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Label, { className: "text-stone-300", htmlFor: key, children: key }) }),
538
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
539
+ "input",
540
+ {
541
+ type: "color",
542
+ id: key,
543
+ value,
544
+ onChange: (e) => setValue(key, e.target.value),
545
+ className: "w-full h-10 rounded border border-stone-600 bg-transparent"
546
+ }
547
+ )
548
+ ] }, key);
549
+ case "select":
550
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
551
+ "div",
552
+ {
553
+ className: "space-y-2 border-t border-stone-700 pt-4",
554
+ children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Label, { className: "text-stone-300", htmlFor: key, children: key }),
556
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
557
+ Select,
558
+ {
559
+ value,
560
+ onValueChange: (val) => setValue(key, val),
561
+ children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectValue, { placeholder: "Select option" }) }),
563
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectContent, { children: control.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectItem, { value: opt, children: opt }, opt)) })
564
+ ]
565
+ }
566
+ )
567
+ ]
568
+ },
569
+ key
570
+ );
571
+ default:
572
+ return null;
573
+ }
574
+ }),
575
+ (buttonControls.length > 0 || jsx11) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "border-t border-stone-700", children: [
576
+ jsx11 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
577
+ "button",
578
+ {
579
+ onClick: () => {
580
+ navigator.clipboard.writeText(jsx11);
581
+ setCopied(true);
582
+ setTimeout(() => setCopied(false), 5e3);
583
+ },
584
+ className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded flex items-center justify-center gap-2",
585
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
586
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Check, { className: "w-4 h-4" }),
587
+ "Copied"
588
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
589
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Copy, { className: "w-4 h-4" }),
590
+ "Copy to Clipboard"
591
+ ] })
592
+ }
593
+ ) }, "control-panel-jsx"),
594
+ buttonControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
595
+ ([key, control]) => control.type === "button" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
596
+ "div",
597
+ {
598
+ className: "flex-1",
599
+ children: control.render ? control.render() : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
600
+ "button",
601
+ {
602
+ onClick: control.onClick,
603
+ className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded",
604
+ children: control.label ?? key
605
+ }
606
+ )
607
+ },
608
+ `control-panel-custom-${key}`
609
+ ) : null
610
+ ) })
611
+ ] })
612
+ ] })
613
+ ] })
614
+ }
615
+ );
616
+ };
617
+ var ControlPanel_default = ControlPanel;
618
+
619
+ // src/components/Playground/Playground.tsx
620
+ var import_jsx_runtime10 = require("react/jsx-runtime");
621
+ function Playground({ children }) {
622
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ResizableLayout, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ControlsProvider, { children: [
623
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PreviewContainer_default, { children }),
624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ControlPanel_default, {})
625
+ ] }) });
626
+ }
627
+ // Annotate the CommonJS export names for ESM import in node:
628
+ 0 && (module.exports = {
629
+ Playground,
630
+ useControls
631
+ });