@toriistudio/v0-playground 0.1.2 → 0.2.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 CHANGED
@@ -208,7 +208,7 @@ var useControls = (schema, options) => {
208
208
  }
209
209
  }, [JSON.stringify(schema), JSON.stringify(ctx.values)]);
210
210
  const typedValues = ctx.values;
211
- const jsx11 = (0, import_react2.useCallback)(() => {
211
+ const jsx12 = (0, import_react2.useCallback)(() => {
212
212
  if (!options?.componentName) return "";
213
213
  const props = Object.entries(typedValues).map(([key, val]) => {
214
214
  if (typeof val === "string") return `${key}="${val}"`;
@@ -222,7 +222,7 @@ var useControls = (schema, options) => {
222
222
  controls: ctx.values,
223
223
  schema: ctx.schema,
224
224
  setValue: ctx.setValue,
225
- jsx: jsx11
225
+ jsx: jsx12
226
226
  };
227
227
  };
228
228
  var useUrlSyncedControls = (schema, options) => {
@@ -482,8 +482,53 @@ var SelectSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__
482
482
  ));
483
483
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
484
484
 
485
- // src/components/ControlPanel/ControlPanel.tsx
485
+ // src/components/ui/button.tsx
486
+ var React9 = __toESM(require("react"));
487
+ var import_react_slot = require("@radix-ui/react-slot");
488
+ var import_class_variance_authority2 = require("class-variance-authority");
486
489
  var import_jsx_runtime9 = require("react/jsx-runtime");
490
+ var buttonVariants = (0, import_class_variance_authority2.cva)(
491
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
492
+ {
493
+ variants: {
494
+ variant: {
495
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
496
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
497
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
498
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
499
+ ghost: "bg-gray-800 hover:bg-gray-900",
500
+ link: "text-primary underline-offset-4 hover:underline"
501
+ },
502
+ size: {
503
+ default: "h-9 px-4 py-2",
504
+ sm: "h-8 rounded-md px-3 text-xs",
505
+ lg: "h-10 rounded-md px-8",
506
+ icon: "h-9 w-9"
507
+ }
508
+ },
509
+ defaultVariants: {
510
+ variant: "default",
511
+ size: "default"
512
+ }
513
+ }
514
+ );
515
+ var Button = React9.forwardRef(
516
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
517
+ const Comp = asChild ? import_react_slot.Slot : "button";
518
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
519
+ Comp,
520
+ {
521
+ className: cn(buttonVariants({ variant, size, className })),
522
+ ref,
523
+ ...props
524
+ }
525
+ );
526
+ }
527
+ );
528
+ Button.displayName = "Button";
529
+
530
+ // src/components/ControlPanel/ControlPanel.tsx
531
+ var import_jsx_runtime10 = require("react/jsx-runtime");
487
532
  var ControlPanel = () => {
488
533
  const [copied, setCopied] = (0, import_react4.useState)(false);
489
534
  const { leftPanelWidth, isDesktop, isHydrated, sidebarNarrow } = useResizableLayout();
@@ -494,7 +539,17 @@ var ControlPanel = () => {
494
539
  const buttonControls = Object.entries(schema).filter(
495
540
  ([, control]) => control.type === "button"
496
541
  );
497
- const jsx11 = (0, import_react4.useMemo)(() => {
542
+ const previewUrl = (0, import_react4.useMemo)(() => {
543
+ const params = new URLSearchParams();
544
+ params.set("nocontrols", "true");
545
+ for (const [key, value] of Object.entries(values)) {
546
+ if (value !== void 0 && value !== null) {
547
+ params.set(key, value.toString());
548
+ }
549
+ }
550
+ return `${window.location.pathname}?${params.toString()}`;
551
+ }, [values]);
552
+ const jsx12 = (0, import_react4.useMemo)(() => {
498
553
  if (!componentName) return "";
499
554
  const props = Object.entries(values).map(([key, val]) => {
500
555
  if (typeof val === "string") return `${key}="${val}"`;
@@ -503,7 +558,7 @@ var ControlPanel = () => {
503
558
  }).join(" ");
504
559
  return `<${componentName} ${props} />`;
505
560
  }, [componentName, values]);
506
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
561
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
507
562
  "div",
508
563
  {
509
564
  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"}`,
@@ -520,19 +575,19 @@ var ControlPanel = () => {
520
575
  overflowY: "auto"
521
576
  } : {}
522
577
  },
523
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
524
- /* @__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" }) }),
525
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-4 pt-2", children: [
578
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { className: "text-lg text-stone-100 font-bold", children: "Controls" }) }),
580
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-4 pt-2", children: [
526
581
  normalControls.map(([key, control]) => {
527
582
  const value = values[key];
528
583
  switch (control.type) {
529
584
  case "boolean":
530
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
585
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
531
586
  "div",
532
587
  {
533
588
  className: "flex items-center space-x-4 border-t border-stone-700 pt-4",
534
589
  children: [
535
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
590
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
536
591
  Switch,
537
592
  {
538
593
  id: key,
@@ -541,19 +596,19 @@ var ControlPanel = () => {
541
596
  className: "data-[state=checked]:bg-stone-700 data-[state=unchecked]:bg-stone-700/40"
542
597
  }
543
598
  ),
544
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Label, { htmlFor: key, className: "cursor-pointer", children: key })
599
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Label, { htmlFor: key, className: "cursor-pointer", children: key })
545
600
  ]
546
601
  },
547
602
  key
548
603
  );
549
604
  case "number":
550
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 w-full", children: [
551
- /* @__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: [
605
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-2 w-full", children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Label, { className: "text-stone-300", htmlFor: key, children: [
552
607
  key,
553
608
  ": ",
554
609
  value
555
610
  ] }) }),
556
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
611
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
557
612
  Slider,
558
613
  {
559
614
  id: key,
@@ -567,7 +622,7 @@ var ControlPanel = () => {
567
622
  )
568
623
  ] }, key);
569
624
  case "string":
570
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
625
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
571
626
  Input,
572
627
  {
573
628
  id: key,
@@ -579,9 +634,9 @@ var ControlPanel = () => {
579
634
  key
580
635
  );
581
636
  case "color":
582
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 w-full", children: [
583
- /* @__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 }) }),
584
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
637
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-2 w-full", children: [
638
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Label, { className: "text-stone-300", htmlFor: key, children: key }) }),
639
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
585
640
  "input",
586
641
  {
587
642
  type: "color",
@@ -593,20 +648,20 @@ var ControlPanel = () => {
593
648
  )
594
649
  ] }, key);
595
650
  case "select":
596
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
651
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
597
652
  "div",
598
653
  {
599
654
  className: "space-y-2 border-t border-stone-700 pt-4",
600
655
  children: [
601
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Label, { className: "text-stone-300", htmlFor: key, children: key }),
602
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
656
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Label, { className: "text-stone-300", htmlFor: key, children: key }),
657
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
603
658
  Select,
604
659
  {
605
660
  value,
606
661
  onValueChange: (val) => setValue(key, val),
607
662
  children: [
608
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectValue, { placeholder: "Select option" }) }),
609
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectContent, { children: control.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectItem, { value: opt, children: opt }, opt)) })
663
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectValue, { placeholder: "Select option" }) }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectContent, { children: control.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectItem, { value: opt, children: opt }, opt)) })
610
665
  ]
611
666
  }
612
667
  )
@@ -618,31 +673,31 @@ var ControlPanel = () => {
618
673
  return null;
619
674
  }
620
675
  }),
621
- (buttonControls.length > 0 || jsx11) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "border-t border-stone-700", children: [
622
- jsx11 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
676
+ (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "border-t border-stone-700", children: [
677
+ jsx12 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
623
678
  "button",
624
679
  {
625
680
  onClick: () => {
626
- navigator.clipboard.writeText(jsx11);
681
+ navigator.clipboard.writeText(jsx12);
627
682
  setCopied(true);
628
683
  setTimeout(() => setCopied(false), 5e3);
629
684
  },
630
685
  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",
631
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
632
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Check, { className: "w-4 h-4" }),
686
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
687
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Check, { className: "w-4 h-4" }),
633
688
  "Copied"
634
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Copy, { className: "w-4 h-4" }),
689
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
690
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Copy, { className: "w-4 h-4" }),
636
691
  "Copy to Clipboard"
637
692
  ] })
638
693
  }
639
694
  ) }, "control-panel-jsx"),
640
- buttonControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
641
- ([key, control]) => control.type === "button" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
695
+ buttonControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
696
+ ([key, control]) => control.type === "button" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
642
697
  "div",
643
698
  {
644
699
  className: "flex-1",
645
- children: control.render ? control.render() : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
700
+ children: control.render ? control.render() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
646
701
  "button",
647
702
  {
648
703
  onClick: control.onClick,
@@ -655,7 +710,20 @@ var ControlPanel = () => {
655
710
  ) : null
656
711
  ) })
657
712
  ] })
658
- ] })
713
+ ] }),
714
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
715
+ "a",
716
+ {
717
+ href: previewUrl,
718
+ target: "_blank",
719
+ rel: "noopener noreferrer",
720
+ className: "w-full px-4 py-2 text-sm text-center bg-stone-800 hover:bg-stone-700 text-white rounded",
721
+ children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.SquareArrowOutUpRight, {}),
723
+ " Open in a New Tab"
724
+ ]
725
+ }
726
+ ) })
659
727
  ] })
660
728
  }
661
729
  );
@@ -663,16 +731,16 @@ var ControlPanel = () => {
663
731
  var ControlPanel_default = ControlPanel;
664
732
 
665
733
  // src/components/Playground/Playground.tsx
666
- var import_jsx_runtime10 = require("react/jsx-runtime");
734
+ var import_jsx_runtime11 = require("react/jsx-runtime");
667
735
  var NO_CONTROLS_PARAM = "nocontrols";
668
736
  function Playground({ children }) {
669
737
  const hideControls = (0, import_react5.useMemo)(() => {
670
738
  if (typeof window === "undefined") return false;
671
739
  return new URLSearchParams(window.location.search).get(NO_CONTROLS_PARAM) === "true";
672
740
  }, []);
673
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ResizableLayout, { hideControls, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ControlsProvider, { children: [
674
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PreviewContainer_default, { hideControls, children }),
675
- !hideControls && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ControlPanel_default, {})
741
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ResizableLayout, { hideControls, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(ControlsProvider, { children: [
742
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PreviewContainer_default, { hideControls, children }),
743
+ !hideControls && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ControlPanel_default, {})
676
744
  ] }) });
677
745
  }
678
746
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -182,7 +182,7 @@ var useControls = (schema, options) => {
182
182
  }
183
183
  }, [JSON.stringify(schema), JSON.stringify(ctx.values)]);
184
184
  const typedValues = ctx.values;
185
- const jsx11 = useCallback(() => {
185
+ const jsx12 = useCallback(() => {
186
186
  if (!options?.componentName) return "";
187
187
  const props = Object.entries(typedValues).map(([key, val]) => {
188
188
  if (typeof val === "string") return `${key}="${val}"`;
@@ -196,7 +196,7 @@ var useControls = (schema, options) => {
196
196
  controls: ctx.values,
197
197
  schema: ctx.schema,
198
198
  setValue: ctx.setValue,
199
- jsx: jsx11
199
+ jsx: jsx12
200
200
  };
201
201
  };
202
202
  var useUrlSyncedControls = (schema, options) => {
@@ -248,7 +248,7 @@ var PreviewContainer_default = PreviewContainer;
248
248
 
249
249
  // src/components/ControlPanel/ControlPanel.tsx
250
250
  import { useState as useState3, useMemo as useMemo2 } from "react";
251
- import { Check as Check2, Copy } from "lucide-react";
251
+ import { Check as Check2, Copy, SquareArrowOutUpRight } from "lucide-react";
252
252
 
253
253
  // src/components/ui/switch.tsx
254
254
  import * as React4 from "react";
@@ -456,8 +456,53 @@ var SelectSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__
456
456
  ));
457
457
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
458
458
 
459
+ // src/components/ui/button.tsx
460
+ import * as React9 from "react";
461
+ import { Slot } from "@radix-ui/react-slot";
462
+ import { cva as cva2 } from "class-variance-authority";
463
+ import { jsx as jsx9 } from "react/jsx-runtime";
464
+ var buttonVariants = cva2(
465
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
466
+ {
467
+ variants: {
468
+ variant: {
469
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
470
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
471
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
472
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
473
+ ghost: "bg-gray-800 hover:bg-gray-900",
474
+ link: "text-primary underline-offset-4 hover:underline"
475
+ },
476
+ size: {
477
+ default: "h-9 px-4 py-2",
478
+ sm: "h-8 rounded-md px-3 text-xs",
479
+ lg: "h-10 rounded-md px-8",
480
+ icon: "h-9 w-9"
481
+ }
482
+ },
483
+ defaultVariants: {
484
+ variant: "default",
485
+ size: "default"
486
+ }
487
+ }
488
+ );
489
+ var Button = React9.forwardRef(
490
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
491
+ const Comp = asChild ? Slot : "button";
492
+ return /* @__PURE__ */ jsx9(
493
+ Comp,
494
+ {
495
+ className: cn(buttonVariants({ variant, size, className })),
496
+ ref,
497
+ ...props
498
+ }
499
+ );
500
+ }
501
+ );
502
+ Button.displayName = "Button";
503
+
459
504
  // src/components/ControlPanel/ControlPanel.tsx
460
- import { Fragment, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
505
+ import { Fragment, jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
461
506
  var ControlPanel = () => {
462
507
  const [copied, setCopied] = useState3(false);
463
508
  const { leftPanelWidth, isDesktop, isHydrated, sidebarNarrow } = useResizableLayout();
@@ -468,7 +513,17 @@ var ControlPanel = () => {
468
513
  const buttonControls = Object.entries(schema).filter(
469
514
  ([, control]) => control.type === "button"
470
515
  );
471
- const jsx11 = useMemo2(() => {
516
+ const previewUrl = useMemo2(() => {
517
+ const params = new URLSearchParams();
518
+ params.set("nocontrols", "true");
519
+ for (const [key, value] of Object.entries(values)) {
520
+ if (value !== void 0 && value !== null) {
521
+ params.set(key, value.toString());
522
+ }
523
+ }
524
+ return `${window.location.pathname}?${params.toString()}`;
525
+ }, [values]);
526
+ const jsx12 = useMemo2(() => {
472
527
  if (!componentName) return "";
473
528
  const props = Object.entries(values).map(([key, val]) => {
474
529
  if (typeof val === "string") return `${key}="${val}"`;
@@ -477,7 +532,7 @@ var ControlPanel = () => {
477
532
  }).join(" ");
478
533
  return `<${componentName} ${props} />`;
479
534
  }, [componentName, values]);
480
- return /* @__PURE__ */ jsx9(
535
+ return /* @__PURE__ */ jsx10(
481
536
  "div",
482
537
  {
483
538
  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"}`,
@@ -495,7 +550,7 @@ var ControlPanel = () => {
495
550
  } : {}
496
551
  },
497
552
  children: /* @__PURE__ */ jsxs4("div", { className: "space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
498
- /* @__PURE__ */ jsx9("div", { className: "space-y-1", children: /* @__PURE__ */ jsx9("h1", { className: "text-lg text-stone-100 font-bold", children: "Controls" }) }),
553
+ /* @__PURE__ */ jsx10("div", { className: "space-y-1", children: /* @__PURE__ */ jsx10("h1", { className: "text-lg text-stone-100 font-bold", children: "Controls" }) }),
499
554
  /* @__PURE__ */ jsxs4("div", { className: "space-y-4 pt-2", children: [
500
555
  normalControls.map(([key, control]) => {
501
556
  const value = values[key];
@@ -506,7 +561,7 @@ var ControlPanel = () => {
506
561
  {
507
562
  className: "flex items-center space-x-4 border-t border-stone-700 pt-4",
508
563
  children: [
509
- /* @__PURE__ */ jsx9(
564
+ /* @__PURE__ */ jsx10(
510
565
  Switch,
511
566
  {
512
567
  id: key,
@@ -515,19 +570,19 @@ var ControlPanel = () => {
515
570
  className: "data-[state=checked]:bg-stone-700 data-[state=unchecked]:bg-stone-700/40"
516
571
  }
517
572
  ),
518
- /* @__PURE__ */ jsx9(Label, { htmlFor: key, className: "cursor-pointer", children: key })
573
+ /* @__PURE__ */ jsx10(Label, { htmlFor: key, className: "cursor-pointer", children: key })
519
574
  ]
520
575
  },
521
576
  key
522
577
  );
523
578
  case "number":
524
579
  return /* @__PURE__ */ jsxs4("div", { className: "space-y-2 w-full", children: [
525
- /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ jsxs4(Label, { className: "text-stone-300", htmlFor: key, children: [
580
+ /* @__PURE__ */ jsx10("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ jsxs4(Label, { className: "text-stone-300", htmlFor: key, children: [
526
581
  key,
527
582
  ": ",
528
583
  value
529
584
  ] }) }),
530
- /* @__PURE__ */ jsx9(
585
+ /* @__PURE__ */ jsx10(
531
586
  Slider,
532
587
  {
533
588
  id: key,
@@ -541,7 +596,7 @@ var ControlPanel = () => {
541
596
  )
542
597
  ] }, key);
543
598
  case "string":
544
- return /* @__PURE__ */ jsx9(
599
+ return /* @__PURE__ */ jsx10(
545
600
  Input,
546
601
  {
547
602
  id: key,
@@ -554,8 +609,8 @@ var ControlPanel = () => {
554
609
  );
555
610
  case "color":
556
611
  return /* @__PURE__ */ jsxs4("div", { className: "space-y-2 w-full", children: [
557
- /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ jsx9(Label, { className: "text-stone-300", htmlFor: key, children: key }) }),
558
- /* @__PURE__ */ jsx9(
612
+ /* @__PURE__ */ jsx10("div", { className: "flex items-center justify-between pb-1", children: /* @__PURE__ */ jsx10(Label, { className: "text-stone-300", htmlFor: key, children: key }) }),
613
+ /* @__PURE__ */ jsx10(
559
614
  "input",
560
615
  {
561
616
  type: "color",
@@ -572,15 +627,15 @@ var ControlPanel = () => {
572
627
  {
573
628
  className: "space-y-2 border-t border-stone-700 pt-4",
574
629
  children: [
575
- /* @__PURE__ */ jsx9(Label, { className: "text-stone-300", htmlFor: key, children: key }),
630
+ /* @__PURE__ */ jsx10(Label, { className: "text-stone-300", htmlFor: key, children: key }),
576
631
  /* @__PURE__ */ jsxs4(
577
632
  Select,
578
633
  {
579
634
  value,
580
635
  onValueChange: (val) => setValue(key, val),
581
636
  children: [
582
- /* @__PURE__ */ jsx9(SelectTrigger, { children: /* @__PURE__ */ jsx9(SelectValue, { placeholder: "Select option" }) }),
583
- /* @__PURE__ */ jsx9(SelectContent, { children: control.options.map((opt) => /* @__PURE__ */ jsx9(SelectItem, { value: opt, children: opt }, opt)) })
637
+ /* @__PURE__ */ jsx10(SelectTrigger, { children: /* @__PURE__ */ jsx10(SelectValue, { placeholder: "Select option" }) }),
638
+ /* @__PURE__ */ jsx10(SelectContent, { children: control.options.map((opt) => /* @__PURE__ */ jsx10(SelectItem, { value: opt, children: opt }, opt)) })
584
639
  ]
585
640
  }
586
641
  )
@@ -592,31 +647,31 @@ var ControlPanel = () => {
592
647
  return null;
593
648
  }
594
649
  }),
595
- (buttonControls.length > 0 || jsx11) && /* @__PURE__ */ jsxs4("div", { className: "border-t border-stone-700", children: [
596
- jsx11 && /* @__PURE__ */ jsx9("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ jsx9(
650
+ (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ jsxs4("div", { className: "border-t border-stone-700", children: [
651
+ jsx12 && /* @__PURE__ */ jsx10("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ jsx10(
597
652
  "button",
598
653
  {
599
654
  onClick: () => {
600
- navigator.clipboard.writeText(jsx11);
655
+ navigator.clipboard.writeText(jsx12);
601
656
  setCopied(true);
602
657
  setTimeout(() => setCopied(false), 5e3);
603
658
  },
604
659
  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",
605
660
  children: copied ? /* @__PURE__ */ jsxs4(Fragment, { children: [
606
- /* @__PURE__ */ jsx9(Check2, { className: "w-4 h-4" }),
661
+ /* @__PURE__ */ jsx10(Check2, { className: "w-4 h-4" }),
607
662
  "Copied"
608
663
  ] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
609
- /* @__PURE__ */ jsx9(Copy, { className: "w-4 h-4" }),
664
+ /* @__PURE__ */ jsx10(Copy, { className: "w-4 h-4" }),
610
665
  "Copy to Clipboard"
611
666
  ] })
612
667
  }
613
668
  ) }, "control-panel-jsx"),
614
- buttonControls.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
615
- ([key, control]) => control.type === "button" ? /* @__PURE__ */ jsx9(
669
+ buttonControls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
670
+ ([key, control]) => control.type === "button" ? /* @__PURE__ */ jsx10(
616
671
  "div",
617
672
  {
618
673
  className: "flex-1",
619
- children: control.render ? control.render() : /* @__PURE__ */ jsx9(
674
+ children: control.render ? control.render() : /* @__PURE__ */ jsx10(
620
675
  "button",
621
676
  {
622
677
  onClick: control.onClick,
@@ -629,7 +684,20 @@ var ControlPanel = () => {
629
684
  ) : null
630
685
  ) })
631
686
  ] })
632
- ] })
687
+ ] }),
688
+ /* @__PURE__ */ jsx10(Button, { asChild: true, children: /* @__PURE__ */ jsxs4(
689
+ "a",
690
+ {
691
+ href: previewUrl,
692
+ target: "_blank",
693
+ rel: "noopener noreferrer",
694
+ className: "w-full px-4 py-2 text-sm text-center bg-stone-800 hover:bg-stone-700 text-white rounded",
695
+ children: [
696
+ /* @__PURE__ */ jsx10(SquareArrowOutUpRight, {}),
697
+ " Open in a New Tab"
698
+ ]
699
+ }
700
+ ) })
633
701
  ] })
634
702
  }
635
703
  );
@@ -637,16 +705,16 @@ var ControlPanel = () => {
637
705
  var ControlPanel_default = ControlPanel;
638
706
 
639
707
  // src/components/Playground/Playground.tsx
640
- import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
708
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
641
709
  var NO_CONTROLS_PARAM = "nocontrols";
642
710
  function Playground({ children }) {
643
711
  const hideControls = useMemo3(() => {
644
712
  if (typeof window === "undefined") return false;
645
713
  return new URLSearchParams(window.location.search).get(NO_CONTROLS_PARAM) === "true";
646
714
  }, []);
647
- return /* @__PURE__ */ jsx10(ResizableLayout, { hideControls, children: /* @__PURE__ */ jsxs5(ControlsProvider, { children: [
648
- /* @__PURE__ */ jsx10(PreviewContainer_default, { hideControls, children }),
649
- !hideControls && /* @__PURE__ */ jsx10(ControlPanel_default, {})
715
+ return /* @__PURE__ */ jsx11(ResizableLayout, { hideControls, children: /* @__PURE__ */ jsxs5(ControlsProvider, { children: [
716
+ /* @__PURE__ */ jsx11(PreviewContainer_default, { hideControls, children }),
717
+ !hideControls && /* @__PURE__ */ jsx11(ControlPanel_default, {})
650
718
  ] }) });
651
719
  }
652
720
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toriistudio/v0-playground",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "V0 Playground",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",