@toriistudio/v0-playground 0.2.6 → 0.2.8

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.d.mts CHANGED
@@ -5,37 +5,45 @@ declare function Playground({ children }: {
5
5
  children: ReactNode;
6
6
  }): react_jsx_runtime.JSX.Element | null;
7
7
 
8
- type ControlType = {
8
+ type BaseControl = {
9
+ hidden?: boolean;
10
+ };
11
+ type ControlType = ({
9
12
  type: "boolean";
10
13
  value: boolean;
11
- } | {
14
+ } & BaseControl) | ({
12
15
  type: "number";
13
16
  value: number;
14
17
  min?: number;
15
18
  max?: number;
16
19
  step?: number;
17
- } | {
20
+ } & BaseControl) | ({
18
21
  type: "string";
19
22
  value: string;
20
- } | {
23
+ } & BaseControl) | ({
21
24
  type: "color";
22
25
  value: string;
23
- } | {
26
+ } & BaseControl) | ({
24
27
  type: "select";
25
28
  value: string;
26
29
  options: string[];
27
- } | {
30
+ } & BaseControl) | ({
28
31
  type: "button";
29
32
  onClick?: () => void;
30
33
  label?: string;
31
34
  render?: () => React.ReactNode;
32
- };
35
+ } & BaseControl);
33
36
  type ControlsSchema = Record<string, ControlType>;
37
+ type ControlsConfig = {
38
+ showCopyButton?: boolean;
39
+ mainLabel?: string;
40
+ };
34
41
  declare const ControlsProvider: ({ children }: {
35
42
  children: ReactNode;
36
43
  }) => react_jsx_runtime.JSX.Element;
37
44
  declare const useControls: <T extends ControlsSchema>(schema: T, options?: {
38
45
  componentName?: string;
46
+ config?: ControlsConfig;
39
47
  }) => { [K in keyof T]: T[K] extends {
40
48
  value: infer V;
41
49
  } ? V : never; } & {
@@ -46,6 +54,7 @@ declare const useControls: <T extends ControlsSchema>(schema: T, options?: {
46
54
  };
47
55
  declare const useUrlSyncedControls: <T extends ControlsSchema>(schema: T, options?: {
48
56
  componentName?: string;
57
+ config?: ControlsConfig;
49
58
  }) => { [K in keyof T]: T[K] extends {
50
59
  value: infer V;
51
60
  } ? V : never; } & {
package/dist/index.d.ts CHANGED
@@ -5,37 +5,45 @@ declare function Playground({ children }: {
5
5
  children: ReactNode;
6
6
  }): react_jsx_runtime.JSX.Element | null;
7
7
 
8
- type ControlType = {
8
+ type BaseControl = {
9
+ hidden?: boolean;
10
+ };
11
+ type ControlType = ({
9
12
  type: "boolean";
10
13
  value: boolean;
11
- } | {
14
+ } & BaseControl) | ({
12
15
  type: "number";
13
16
  value: number;
14
17
  min?: number;
15
18
  max?: number;
16
19
  step?: number;
17
- } | {
20
+ } & BaseControl) | ({
18
21
  type: "string";
19
22
  value: string;
20
- } | {
23
+ } & BaseControl) | ({
21
24
  type: "color";
22
25
  value: string;
23
- } | {
26
+ } & BaseControl) | ({
24
27
  type: "select";
25
28
  value: string;
26
29
  options: string[];
27
- } | {
30
+ } & BaseControl) | ({
28
31
  type: "button";
29
32
  onClick?: () => void;
30
33
  label?: string;
31
34
  render?: () => React.ReactNode;
32
- };
35
+ } & BaseControl);
33
36
  type ControlsSchema = Record<string, ControlType>;
37
+ type ControlsConfig = {
38
+ showCopyButton?: boolean;
39
+ mainLabel?: string;
40
+ };
34
41
  declare const ControlsProvider: ({ children }: {
35
42
  children: ReactNode;
36
43
  }) => react_jsx_runtime.JSX.Element;
37
44
  declare const useControls: <T extends ControlsSchema>(schema: T, options?: {
38
45
  componentName?: string;
46
+ config?: ControlsConfig;
39
47
  }) => { [K in keyof T]: T[K] extends {
40
48
  value: infer V;
41
49
  } ? V : never; } & {
@@ -46,6 +54,7 @@ declare const useControls: <T extends ControlsSchema>(schema: T, options?: {
46
54
  };
47
55
  declare const useUrlSyncedControls: <T extends ControlsSchema>(schema: T, options?: {
48
56
  componentName?: string;
57
+ config?: ControlsConfig;
49
58
  }) => { [K in keyof T]: T[K] extends {
50
59
  value: infer V;
51
60
  } ? V : never; } & {
package/dist/index.js CHANGED
@@ -166,6 +166,9 @@ var useControlsContext = () => {
166
166
  var ControlsProvider = ({ children }) => {
167
167
  const [schema, setSchema] = (0, import_react2.useState)({});
168
168
  const [values, setValues] = (0, import_react2.useState)({});
169
+ const [config, setConfig] = (0, import_react2.useState)({
170
+ showCopyButton: true
171
+ });
169
172
  const [componentName, setComponentName] = (0, import_react2.useState)();
170
173
  const setValue = (key, value) => {
171
174
  setValues((prev) => ({ ...prev, [key]: value }));
@@ -174,12 +177,18 @@ var ControlsProvider = ({ children }) => {
174
177
  if (opts?.componentName) {
175
178
  setComponentName(opts.componentName);
176
179
  }
180
+ if (opts?.config) {
181
+ setConfig((prev) => ({
182
+ ...prev,
183
+ ...opts.config
184
+ }));
185
+ }
177
186
  setSchema((prevSchema) => ({ ...prevSchema, ...newSchema }));
178
187
  setValues((prevValues) => {
179
188
  const updated = { ...prevValues };
180
189
  for (const key in newSchema) {
190
+ const control = newSchema[key];
181
191
  if (!(key in updated)) {
182
- const control = newSchema[key];
183
192
  if ("value" in control) {
184
193
  updated[key] = control.value;
185
194
  }
@@ -189,8 +198,15 @@ var ControlsProvider = ({ children }) => {
189
198
  });
190
199
  };
191
200
  const contextValue = (0, import_react2.useMemo)(
192
- () => ({ schema, values, setValue, registerSchema, componentName }),
193
- [schema, values, componentName]
201
+ () => ({
202
+ schema,
203
+ values,
204
+ setValue,
205
+ registerSchema,
206
+ componentName,
207
+ config
208
+ }),
209
+ [schema, values, componentName, config]
194
210
  );
195
211
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ControlsContext.Provider, { value: contextValue, children });
196
212
  };
@@ -551,13 +567,13 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
551
567
  var ControlPanel = () => {
552
568
  const [copied, setCopied] = (0, import_react5.useState)(false);
553
569
  const { leftPanelWidth, isDesktop, isHydrated, sidebarNarrow } = useResizableLayout();
554
- const { schema, setValue, values, componentName } = useControlsContext();
570
+ const { schema, setValue, values, componentName, config } = useControlsContext();
555
571
  const previewUrl = usePreviewUrl(values);
556
572
  const normalControls = Object.entries(schema).filter(
557
- ([, control]) => control.type !== "button"
573
+ ([, control]) => control.type !== "button" && !control.hidden
558
574
  );
559
575
  const buttonControls = Object.entries(schema).filter(
560
- ([, control]) => control.type === "button"
576
+ ([, control]) => control.type === "button" && !control.hidden
561
577
  );
562
578
  const jsx12 = (0, import_react5.useMemo)(() => {
563
579
  if (!componentName) return "";
@@ -572,6 +588,8 @@ var ControlPanel = () => {
572
588
  "div",
573
589
  {
574
590
  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"}`,
591
+ onPointerDown: (e) => e.stopPropagation(),
592
+ onTouchStart: (e) => e.stopPropagation(),
575
593
  style: {
576
594
  width: "100%",
577
595
  height: "auto",
@@ -586,7 +604,7 @@ var ControlPanel = () => {
586
604
  } : {}
587
605
  },
588
606
  children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "mb-10 space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
589
- /* @__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" }) }),
607
+ /* @__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: config?.mainLabel ?? "Controls" }) }),
590
608
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-4 pt-2", children: [
591
609
  normalControls.map(([key, control]) => {
592
610
  const value = values[key];
@@ -683,43 +701,49 @@ var ControlPanel = () => {
683
701
  return null;
684
702
  }
685
703
  }),
686
- (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "border-t border-stone-700", children: [
687
- jsx12 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
688
- "button",
689
- {
690
- onClick: () => {
691
- navigator.clipboard.writeText(jsx12);
692
- setCopied(true);
693
- setTimeout(() => setCopied(false), 5e3);
694
- },
695
- 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",
696
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
697
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Check, { className: "w-4 h-4" }),
698
- "Copied"
699
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
700
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Copy, { className: "w-4 h-4" }),
701
- "Copy to Clipboard"
702
- ] })
703
- }
704
- ) }, "control-panel-jsx"),
705
- buttonControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
706
- ([key, control]) => control.type === "button" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
707
- "div",
708
- {
709
- className: "flex-1",
710
- children: control.render ? control.render() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
711
- "button",
704
+ (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
705
+ "div",
706
+ {
707
+ className: `${normalControls.length > 0 ? "border-t" : ""} border-stone-700`,
708
+ children: [
709
+ jsx12 && config?.showCopyButton !== false && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
710
+ "button",
711
+ {
712
+ onClick: () => {
713
+ navigator.clipboard.writeText(jsx12);
714
+ setCopied(true);
715
+ setTimeout(() => setCopied(false), 5e3);
716
+ },
717
+ 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",
718
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
719
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Check, { className: "w-4 h-4" }),
720
+ "Copied"
721
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Copy, { className: "w-4 h-4" }),
723
+ "Copy to Clipboard"
724
+ ] })
725
+ }
726
+ ) }, "control-panel-jsx"),
727
+ buttonControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
728
+ ([key, control]) => control.type === "button" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
729
+ "div",
712
730
  {
713
- onClick: control.onClick,
714
- className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded",
715
- children: control.label ?? key
716
- }
717
- )
718
- },
719
- `control-panel-custom-${key}`
720
- ) : null
721
- ) })
722
- ] })
731
+ className: "flex-1",
732
+ children: control.render ? control.render() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
733
+ "button",
734
+ {
735
+ onClick: control.onClick,
736
+ className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded",
737
+ children: control.label ?? key
738
+ }
739
+ )
740
+ },
741
+ `control-panel-custom-${key}`
742
+ ) : null
743
+ ) })
744
+ ]
745
+ }
746
+ )
723
747
  ] }),
724
748
  previewUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
725
749
  "a",
package/dist/index.mjs CHANGED
@@ -140,6 +140,9 @@ var useControlsContext = () => {
140
140
  var ControlsProvider = ({ children }) => {
141
141
  const [schema, setSchema] = useState2({});
142
142
  const [values, setValues] = useState2({});
143
+ const [config, setConfig] = useState2({
144
+ showCopyButton: true
145
+ });
143
146
  const [componentName, setComponentName] = useState2();
144
147
  const setValue = (key, value) => {
145
148
  setValues((prev) => ({ ...prev, [key]: value }));
@@ -148,12 +151,18 @@ var ControlsProvider = ({ children }) => {
148
151
  if (opts?.componentName) {
149
152
  setComponentName(opts.componentName);
150
153
  }
154
+ if (opts?.config) {
155
+ setConfig((prev) => ({
156
+ ...prev,
157
+ ...opts.config
158
+ }));
159
+ }
151
160
  setSchema((prevSchema) => ({ ...prevSchema, ...newSchema }));
152
161
  setValues((prevValues) => {
153
162
  const updated = { ...prevValues };
154
163
  for (const key in newSchema) {
164
+ const control = newSchema[key];
155
165
  if (!(key in updated)) {
156
- const control = newSchema[key];
157
166
  if ("value" in control) {
158
167
  updated[key] = control.value;
159
168
  }
@@ -163,8 +172,15 @@ var ControlsProvider = ({ children }) => {
163
172
  });
164
173
  };
165
174
  const contextValue = useMemo(
166
- () => ({ schema, values, setValue, registerSchema, componentName }),
167
- [schema, values, componentName]
175
+ () => ({
176
+ schema,
177
+ values,
178
+ setValue,
179
+ registerSchema,
180
+ componentName,
181
+ config
182
+ }),
183
+ [schema, values, componentName, config]
168
184
  );
169
185
  return /* @__PURE__ */ jsx2(ControlsContext.Provider, { value: contextValue, children });
170
186
  };
@@ -525,13 +541,13 @@ import { Fragment, jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
525
541
  var ControlPanel = () => {
526
542
  const [copied, setCopied] = useState4(false);
527
543
  const { leftPanelWidth, isDesktop, isHydrated, sidebarNarrow } = useResizableLayout();
528
- const { schema, setValue, values, componentName } = useControlsContext();
544
+ const { schema, setValue, values, componentName, config } = useControlsContext();
529
545
  const previewUrl = usePreviewUrl(values);
530
546
  const normalControls = Object.entries(schema).filter(
531
- ([, control]) => control.type !== "button"
547
+ ([, control]) => control.type !== "button" && !control.hidden
532
548
  );
533
549
  const buttonControls = Object.entries(schema).filter(
534
- ([, control]) => control.type === "button"
550
+ ([, control]) => control.type === "button" && !control.hidden
535
551
  );
536
552
  const jsx12 = useMemo2(() => {
537
553
  if (!componentName) return "";
@@ -546,6 +562,8 @@ var ControlPanel = () => {
546
562
  "div",
547
563
  {
548
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"}`,
565
+ onPointerDown: (e) => e.stopPropagation(),
566
+ onTouchStart: (e) => e.stopPropagation(),
549
567
  style: {
550
568
  width: "100%",
551
569
  height: "auto",
@@ -560,7 +578,7 @@ var ControlPanel = () => {
560
578
  } : {}
561
579
  },
562
580
  children: /* @__PURE__ */ jsxs4("div", { className: "mb-10 space-y-4 p-2 md:p-4 border border-stone-700 rounded-md", children: [
563
- /* @__PURE__ */ jsx10("div", { className: "space-y-1", children: /* @__PURE__ */ jsx10("h1", { className: "text-lg text-stone-100 font-bold", children: "Controls" }) }),
581
+ /* @__PURE__ */ jsx10("div", { className: "space-y-1", children: /* @__PURE__ */ jsx10("h1", { className: "text-lg text-stone-100 font-bold", children: config?.mainLabel ?? "Controls" }) }),
564
582
  /* @__PURE__ */ jsxs4("div", { className: "space-y-4 pt-2", children: [
565
583
  normalControls.map(([key, control]) => {
566
584
  const value = values[key];
@@ -657,43 +675,49 @@ var ControlPanel = () => {
657
675
  return null;
658
676
  }
659
677
  }),
660
- (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ jsxs4("div", { className: "border-t border-stone-700", children: [
661
- jsx12 && /* @__PURE__ */ jsx10("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ jsx10(
662
- "button",
663
- {
664
- onClick: () => {
665
- navigator.clipboard.writeText(jsx12);
666
- setCopied(true);
667
- setTimeout(() => setCopied(false), 5e3);
668
- },
669
- 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",
670
- children: copied ? /* @__PURE__ */ jsxs4(Fragment, { children: [
671
- /* @__PURE__ */ jsx10(Check2, { className: "w-4 h-4" }),
672
- "Copied"
673
- ] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
674
- /* @__PURE__ */ jsx10(Copy, { className: "w-4 h-4" }),
675
- "Copy to Clipboard"
676
- ] })
677
- }
678
- ) }, "control-panel-jsx"),
679
- buttonControls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
680
- ([key, control]) => control.type === "button" ? /* @__PURE__ */ jsx10(
681
- "div",
682
- {
683
- className: "flex-1",
684
- children: control.render ? control.render() : /* @__PURE__ */ jsx10(
685
- "button",
678
+ (buttonControls.length > 0 || jsx12) && /* @__PURE__ */ jsxs4(
679
+ "div",
680
+ {
681
+ className: `${normalControls.length > 0 ? "border-t" : ""} border-stone-700`,
682
+ children: [
683
+ jsx12 && config?.showCopyButton !== false && /* @__PURE__ */ jsx10("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ jsx10(
684
+ "button",
685
+ {
686
+ onClick: () => {
687
+ navigator.clipboard.writeText(jsx12);
688
+ setCopied(true);
689
+ setTimeout(() => setCopied(false), 5e3);
690
+ },
691
+ 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",
692
+ children: copied ? /* @__PURE__ */ jsxs4(Fragment, { children: [
693
+ /* @__PURE__ */ jsx10(Check2, { className: "w-4 h-4" }),
694
+ "Copied"
695
+ ] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
696
+ /* @__PURE__ */ jsx10(Copy, { className: "w-4 h-4" }),
697
+ "Copy to Clipboard"
698
+ ] })
699
+ }
700
+ ) }, "control-panel-jsx"),
701
+ buttonControls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-2 pt-4", children: buttonControls.map(
702
+ ([key, control]) => control.type === "button" ? /* @__PURE__ */ jsx10(
703
+ "div",
686
704
  {
687
- onClick: control.onClick,
688
- className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded",
689
- children: control.label ?? key
690
- }
691
- )
692
- },
693
- `control-panel-custom-${key}`
694
- ) : null
695
- ) })
696
- ] })
705
+ className: "flex-1",
706
+ children: control.render ? control.render() : /* @__PURE__ */ jsx10(
707
+ "button",
708
+ {
709
+ onClick: control.onClick,
710
+ className: "w-full px-4 py-2 text-sm bg-stone-700 hover:bg-stone-600 text-white rounded",
711
+ children: control.label ?? key
712
+ }
713
+ )
714
+ },
715
+ `control-panel-custom-${key}`
716
+ ) : null
717
+ ) })
718
+ ]
719
+ }
720
+ )
697
721
  ] }),
698
722
  previewUrl && /* @__PURE__ */ jsx10(Button, { asChild: true, children: /* @__PURE__ */ jsxs4(
699
723
  "a",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toriistudio/v0-playground",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "V0 Playground",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -30,7 +30,9 @@
30
30
  "scripts": {
31
31
  "build": "tsup",
32
32
  "local:push": "yarn build && yalc push",
33
- "prepublishOnly": "npm run build",
33
+ "release:patch": "npm version patch && git push --follow-tags && npm publish",
34
+ "release:minor": "npm version minor && git push --follow-tags && npm publish",
35
+ "release:major": "npm version major && git push --follow-tags && npm publish",
34
36
  "test": "echo \"Error: no test specified\" && exit 1"
35
37
  },
36
38
  "repository": {