@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/LICENSE.md +21 -0
- package/README.md +79 -0
- package/dist/index.d.mts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +631 -0
- package/dist/index.mjs +606 -0
- package/dist/preset.d.mts +5 -0
- package/dist/preset.d.ts +5 -0
- package/dist/preset.js +219 -0
- package/dist/preset.mjs +186 -0
- package/package.json +89 -0
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
|
+
});
|