@slopmachine/react 0.1.14 → 0.1.15

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
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SlopImageOptions, ImageAspectRatio, SlopVideoOptions, VideoAspectRatio } from '@slopmachine/core';
2
+ import { SlopImageOptions, ImageAspectRatio, SlopVideoOptions, VideoAspectRatio, SlopTextOptions } from '@slopmachine/core';
3
3
  export { ImageAspectRatio, SlopImageOptions, SlopVideoOptions, VideoAspectRatio } from '@slopmachine/core';
4
4
 
5
5
  interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">, Omit<SlopImageOptions, "aspectRatio"> {
@@ -29,7 +29,7 @@ interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>,
29
29
  * />
30
30
  * ```
31
31
  *
32
- * @version 0.1.14
32
+ * @version 0.1.15
33
33
  */
34
34
  declare const SlopImage: React.FC<SlopImageProps>;
35
35
 
@@ -62,7 +62,39 @@ interface SlopVideoProps extends Omit<React.VideoHTMLAttributes<HTMLVideoElement
62
62
  * muted
63
63
  * />
64
64
  * ```
65
+ *
66
+ * @version 0.1.15
65
67
  */
66
68
  declare const SlopVideo: React.FC<SlopVideoProps>;
67
69
 
68
- export { SlopImage, type SlopImageProps, SlopVideo, type SlopVideoProps };
70
+ interface SlopTextProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children">, SlopTextOptions {
71
+ /**
72
+ * Optional loading component to show while the text is being generated
73
+ */
74
+ fallback?: React.ReactNode;
75
+ /**
76
+ * Optional error component to show if the text generation fails
77
+ */
78
+ errorFallback?: React.ReactNode;
79
+ }
80
+ /**
81
+ * Renders text generated by Slop Machine.
82
+ *
83
+ * This component automatically constructs the correct URL for the Slop Machine API,
84
+ * fetches the generated text, and displays it with optional loading and error states.
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * <SlopText
89
+ * bucketId="my-text-bucket"
90
+ * fallback={<div>Loading story...</div>}
91
+ * errorFallback={<div>Failed to load story</div>}
92
+ * className="text-lg text-gray-800"
93
+ * />
94
+ * ```
95
+ *
96
+ * @version 0.1.15
97
+ */
98
+ declare const SlopText: React.ForwardRefExoticComponent<SlopTextProps & React.RefAttributes<HTMLDivElement>>;
99
+
100
+ export { SlopImage, type SlopImageProps, SlopText, type SlopTextProps, SlopVideo, type SlopVideoProps };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SlopImageOptions, ImageAspectRatio, SlopVideoOptions, VideoAspectRatio } from '@slopmachine/core';
2
+ import { SlopImageOptions, ImageAspectRatio, SlopVideoOptions, VideoAspectRatio, SlopTextOptions } from '@slopmachine/core';
3
3
  export { ImageAspectRatio, SlopImageOptions, SlopVideoOptions, VideoAspectRatio } from '@slopmachine/core';
4
4
 
5
5
  interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">, Omit<SlopImageOptions, "aspectRatio"> {
@@ -29,7 +29,7 @@ interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>,
29
29
  * />
30
30
  * ```
31
31
  *
32
- * @version 0.1.14
32
+ * @version 0.1.15
33
33
  */
34
34
  declare const SlopImage: React.FC<SlopImageProps>;
35
35
 
@@ -62,7 +62,39 @@ interface SlopVideoProps extends Omit<React.VideoHTMLAttributes<HTMLVideoElement
62
62
  * muted
63
63
  * />
64
64
  * ```
65
+ *
66
+ * @version 0.1.15
65
67
  */
66
68
  declare const SlopVideo: React.FC<SlopVideoProps>;
67
69
 
68
- export { SlopImage, type SlopImageProps, SlopVideo, type SlopVideoProps };
70
+ interface SlopTextProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children">, SlopTextOptions {
71
+ /**
72
+ * Optional loading component to show while the text is being generated
73
+ */
74
+ fallback?: React.ReactNode;
75
+ /**
76
+ * Optional error component to show if the text generation fails
77
+ */
78
+ errorFallback?: React.ReactNode;
79
+ }
80
+ /**
81
+ * Renders text generated by Slop Machine.
82
+ *
83
+ * This component automatically constructs the correct URL for the Slop Machine API,
84
+ * fetches the generated text, and displays it with optional loading and error states.
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * <SlopText
89
+ * bucketId="my-text-bucket"
90
+ * fallback={<div>Loading story...</div>}
91
+ * errorFallback={<div>Failed to load story</div>}
92
+ * className="text-lg text-gray-800"
93
+ * />
94
+ * ```
95
+ *
96
+ * @version 0.1.15
97
+ */
98
+ declare const SlopText: React.ForwardRefExoticComponent<SlopTextProps & React.RefAttributes<HTMLDivElement>>;
99
+
100
+ export { SlopImage, type SlopImageProps, SlopText, type SlopTextProps, SlopVideo, type SlopVideoProps };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  SlopImage: () => SlopImage,
34
+ SlopText: () => SlopText,
34
35
  SlopVideo: () => SlopVideo
35
36
  });
36
37
  module.exports = __toCommonJS(index_exports);
@@ -581,9 +582,223 @@ var SlopVideo = ({
581
582
  ) })
582
583
  ] });
583
584
  };
585
+
586
+ // src/components/SlopText.tsx
587
+ var import_react3 = __toESM(require("react"));
588
+ var import_core3 = require("@slopmachine/core");
589
+ var import_marked = require("marked");
590
+ var import_jsx_runtime3 = require("react/jsx-runtime");
591
+ var SlopText = import_react3.default.forwardRef(
592
+ ({
593
+ bucketId,
594
+ version,
595
+ resultId,
596
+ model,
597
+ variables,
598
+ baseUrl,
599
+ fallback,
600
+ errorFallback,
601
+ ...props
602
+ }, ref) => {
603
+ const [text, setText] = (0, import_react3.useState)(null);
604
+ const [loading, setLoading] = (0, import_react3.useState)(true);
605
+ const [error, setError] = (0, import_react3.useState)(null);
606
+ (0, import_react3.useEffect)(() => {
607
+ let isMounted = true;
608
+ const fetchText = async () => {
609
+ try {
610
+ setLoading(true);
611
+ setError(null);
612
+ const url = (0, import_core3.buildTextUrl)({
613
+ bucketId,
614
+ version,
615
+ resultId,
616
+ model,
617
+ variables,
618
+ baseUrl
619
+ });
620
+ const response = await fetch(url);
621
+ if (!response.ok) {
622
+ throw new Error(`Failed to fetch text: ${response.statusText}`);
623
+ }
624
+ const content = await response.text();
625
+ if (isMounted) {
626
+ setText(content);
627
+ }
628
+ } catch (err) {
629
+ if (isMounted) {
630
+ setError(
631
+ err instanceof Error ? err : new Error("Failed to generate text")
632
+ );
633
+ }
634
+ } finally {
635
+ if (isMounted) {
636
+ setLoading(false);
637
+ }
638
+ }
639
+ };
640
+ fetchText();
641
+ return () => {
642
+ isMounted = false;
643
+ };
644
+ }, [
645
+ bucketId,
646
+ version,
647
+ resultId,
648
+ model,
649
+ JSON.stringify(variables),
650
+ baseUrl
651
+ ]);
652
+ if (error && errorFallback) {
653
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: errorFallback });
654
+ }
655
+ if (loading) {
656
+ if (fallback) {
657
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: fallback });
658
+ }
659
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: props.className, style: props.style, children: [
660
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
661
+ @keyframes slop-shimmer {
662
+ 0% { background-position: 200% 0; }
663
+ 100% { background-position: -200% 0; }
664
+ }
665
+ @keyframes slop-spin {
666
+ from { transform: rotate(0deg); }
667
+ to { transform: rotate(360deg); }
668
+ }
669
+ ` }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
671
+ "div",
672
+ {
673
+ className: "slop-wrapper relative overflow-hidden w-full",
674
+ style: {
675
+ position: "relative",
676
+ overflow: "hidden",
677
+ width: "100%",
678
+ minHeight: "100px",
679
+ backgroundColor: "var(--muted, #f3f4f6)",
680
+ borderRadius: "0.375rem"
681
+ },
682
+ children: [
683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
684
+ "div",
685
+ {
686
+ className: "absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
687
+ style: {
688
+ position: "absolute",
689
+ top: 0,
690
+ left: 0,
691
+ right: 0,
692
+ bottom: 0,
693
+ zIndex: 10,
694
+ display: "flex",
695
+ alignItems: "center",
696
+ justifyContent: "center",
697
+ backgroundColor: "var(--muted, #f3f4f6)"
698
+ },
699
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
700
+ "div",
701
+ {
702
+ className: "flex flex-col items-center gap-2",
703
+ style: {
704
+ display: "flex",
705
+ flexDirection: "column",
706
+ alignItems: "center",
707
+ gap: "0.5rem"
708
+ },
709
+ children: [
710
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
711
+ "svg",
712
+ {
713
+ className: "spinner size-6 text-muted-foreground",
714
+ xmlns: "http://www.w3.org/2000/svg",
715
+ fill: "none",
716
+ viewBox: "0 0 24 24",
717
+ style: {
718
+ width: "24px",
719
+ height: "24px",
720
+ color: "var(--muted-foreground, #6b7280)",
721
+ animation: "slop-spin 1s linear infinite"
722
+ },
723
+ children: [
724
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
725
+ "circle",
726
+ {
727
+ className: "opacity-25",
728
+ cx: "12",
729
+ cy: "12",
730
+ r: "10",
731
+ stroke: "currentColor",
732
+ strokeWidth: "4",
733
+ style: { opacity: 0.25 }
734
+ }
735
+ ),
736
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
737
+ "path",
738
+ {
739
+ className: "opacity-75",
740
+ fill: "currentColor",
741
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z",
742
+ style: { opacity: 0.75 }
743
+ }
744
+ )
745
+ ]
746
+ }
747
+ ),
748
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
749
+ "span",
750
+ {
751
+ className: "text-xs text-muted-foreground",
752
+ style: {
753
+ fontSize: "0.75rem",
754
+ color: "var(--muted-foreground, #6b7280)"
755
+ },
756
+ children: "Loading..."
757
+ }
758
+ )
759
+ ]
760
+ }
761
+ )
762
+ }
763
+ ),
764
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
765
+ "div",
766
+ {
767
+ className: "shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
768
+ style: {
769
+ position: "absolute",
770
+ top: 0,
771
+ left: 0,
772
+ right: 0,
773
+ bottom: 0,
774
+ background: "linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
775
+ backgroundSize: "200% 100%",
776
+ animation: "slop-shimmer 2s ease-in-out infinite"
777
+ }
778
+ }
779
+ )
780
+ ]
781
+ }
782
+ )
783
+ ] });
784
+ }
785
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
786
+ "div",
787
+ {
788
+ ref,
789
+ ...props,
790
+ dangerouslySetInnerHTML: {
791
+ __html: text ? import_marked.marked.parse(text) : ""
792
+ }
793
+ }
794
+ );
795
+ }
796
+ );
797
+ SlopText.displayName = "SlopText";
584
798
  // Annotate the CommonJS export names for ESM import in node:
585
799
  0 && (module.exports = {
586
800
  SlopImage,
801
+ SlopText,
587
802
  SlopVideo
588
803
  });
589
804
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/SlopImage.tsx","../src/components/SlopVideo.tsx"],"sourcesContent":["export { SlopImage, type SlopImageProps } from \"./components/SlopImage\";\nexport { SlopVideo, type SlopVideoProps } from \"./components/SlopVideo\";\nexport type {\n ImageAspectRatio,\n VideoAspectRatio,\n SlopImageOptions,\n SlopVideoOptions,\n} from \"@slopmachine/core\";\n","import React, { useMemo, useState } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildImageUrl,\n type SlopImageOptions,\n type ImageAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopImageProps\n extends\n Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\">,\n Omit<SlopImageOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated image. Defaults to \"1:1\".\n */\n aspectRatio?: ImageAspectRatio;\n /**\n * Custom React node to display while the image is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders an image generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopImage\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * />\n * ```\n *\n * @version 0.1.14\n */\nexport const SlopImage: React.FC<SlopImageProps> = ({\n bucketId,\n className,\n aspectRatio = \"1:1\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n baseUrl,\n loader,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildImageUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n React.useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const alt = \"Generated image\";\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n React.useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n // console.error(\n // `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,\n // );\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopImage error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching image from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Image */}\n <img\n key={src}\n src={src}\n alt={alt}\n onLoad={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useMemo, useState, useRef, useEffect } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildVideoUrl,\n type SlopVideoOptions,\n type VideoAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopVideoProps\n extends\n Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"src\">,\n Omit<SlopVideoOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated video. Defaults to \"16:9\".\n */\n aspectRatio?: VideoAspectRatio;\n /**\n * Custom React node to display while the video is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders a video generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopVideo\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * autoPlay\n * loop\n * muted\n * />\n * ```\n */\nexport const SlopVideo: React.FC<SlopVideoProps> = ({\n bucketId,\n className,\n aspectRatio = \"16:9\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n duration,\n baseUrl,\n loader,\n autoPlay = true,\n loop = true,\n muted = true,\n playsInline = true,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildVideoUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n const videoRef = useRef<HTMLVideoElement>(null);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopVideo error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching video from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Video */}\n <video\n key={src}\n ref={videoRef}\n src={src}\n autoPlay={autoPlay}\n loop={loop}\n muted={muted}\n playsInline={playsInline}\n onLoadedData={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n"],"mappings":"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","names":["React","import_react","import_clsx","import_tailwind_merge","import_core","import_jsx_runtime","cn"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/SlopImage.tsx","../src/components/SlopVideo.tsx","../src/components/SlopText.tsx"],"sourcesContent":["export { SlopImage, type SlopImageProps } from \"./components/SlopImage\";\nexport { SlopVideo, type SlopVideoProps } from \"./components/SlopVideo\";\nexport { SlopText, type SlopTextProps } from \"./components/SlopText\";\n\nexport type {\n ImageAspectRatio,\n VideoAspectRatio,\n SlopImageOptions,\n SlopVideoOptions,\n} from \"@slopmachine/core\";\n","import React, { useMemo, useState } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildImageUrl,\n type SlopImageOptions,\n type ImageAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopImageProps\n extends\n Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\">,\n Omit<SlopImageOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated image. Defaults to \"1:1\".\n */\n aspectRatio?: ImageAspectRatio;\n /**\n * Custom React node to display while the image is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders an image generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopImage\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopImage: React.FC<SlopImageProps> = ({\n bucketId,\n className,\n aspectRatio = \"1:1\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n baseUrl,\n loader,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildImageUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n React.useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const alt = \"Generated image\";\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n React.useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n // console.error(\n // `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,\n // );\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopImage error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching image from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Image */}\n <img\n key={src}\n src={src}\n alt={alt}\n onLoad={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useMemo, useState, useRef, useEffect } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildVideoUrl,\n type SlopVideoOptions,\n type VideoAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopVideoProps\n extends\n Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"src\">,\n Omit<SlopVideoOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated video. Defaults to \"16:9\".\n */\n aspectRatio?: VideoAspectRatio;\n /**\n * Custom React node to display while the video is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders a video generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopVideo\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * autoPlay\n * loop\n * muted\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopVideo: React.FC<SlopVideoProps> = ({\n bucketId,\n className,\n aspectRatio = \"16:9\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n duration,\n baseUrl,\n loader,\n autoPlay = true,\n loop = true,\n muted = true,\n playsInline = true,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildVideoUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n const videoRef = useRef<HTMLVideoElement>(null);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopVideo error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching video from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Video */}\n <video\n key={src}\n ref={videoRef}\n src={src}\n autoPlay={autoPlay}\n loop={loop}\n muted={muted}\n playsInline={playsInline}\n onLoadedData={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useEffect, useState } from \"react\";\nimport { buildTextUrl, type SlopTextOptions } from \"@slopmachine/core\";\nimport { marked } from \"marked\";\n\nexport interface SlopTextProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, \"children\">,\n SlopTextOptions {\n /**\n * Optional loading component to show while the text is being generated\n */\n fallback?: React.ReactNode;\n /**\n * Optional error component to show if the text generation fails\n */\n errorFallback?: React.ReactNode;\n}\n\n/**\n * Renders text generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * fetches the generated text, and displays it with optional loading and error states.\n *\n * @example\n * ```tsx\n * <SlopText\n * bucketId=\"my-text-bucket\"\n * fallback={<div>Loading story...</div>}\n * errorFallback={<div>Failed to load story</div>}\n * className=\"text-lg text-gray-800\"\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopText = React.forwardRef<HTMLDivElement, SlopTextProps>(\n (\n {\n bucketId,\n version,\n resultId,\n model,\n variables,\n baseUrl,\n fallback,\n errorFallback,\n ...props\n },\n ref,\n ) => {\n const [text, setText] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let isMounted = true;\n\n const fetchText = async () => {\n try {\n setLoading(true);\n setError(null);\n\n const url = buildTextUrl({\n bucketId,\n version,\n resultId,\n model,\n variables,\n baseUrl,\n });\n\n // Fetch the URL to get the content, following redirects automatically\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch text: ${response.statusText}`);\n }\n const content = await response.text();\n if (isMounted) {\n setText(content);\n }\n } catch (err) {\n if (isMounted) {\n setError(\n err instanceof Error ? err : new Error(\"Failed to generate text\"),\n );\n }\n } finally {\n if (isMounted) {\n setLoading(false);\n }\n }\n };\n\n fetchText();\n\n return () => {\n isMounted = false;\n };\n }, [\n bucketId,\n version,\n resultId,\n model,\n JSON.stringify(variables),\n baseUrl,\n ]);\n\n if (error && errorFallback) {\n return <>{errorFallback}</>;\n }\n\n if (loading) {\n if (fallback) {\n return <>{fallback}</>;\n }\n return (\n <div className={props.className} style={props.style}>\n <style>{`\n @keyframes slop-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n }\n @keyframes slop-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full\"\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n minHeight: \"100px\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n borderRadius: \"0.375rem\",\n }}\n >\n {/* Loading overlay */}\n <div\n className=\"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\"\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className=\"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\"\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n }}\n />\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n {...props}\n dangerouslySetInnerHTML={{\n __html: text ? (marked.parse(text) as string) : \"\",\n }}\n />\n );\n },\n);\n\nSlopText.displayName = \"SlopText\";\n"],"mappings":"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","names":["React","import_react","import_clsx","import_tailwind_merge","import_core","import_jsx_runtime","cn","import_react","import_core","import_jsx_runtime","React"]}
package/dist/index.mjs CHANGED
@@ -548,8 +548,222 @@ var SlopVideo = ({
548
548
  ) })
549
549
  ] });
550
550
  };
551
+
552
+ // src/components/SlopText.tsx
553
+ import React3, { useEffect as useEffect2, useState as useState3 } from "react";
554
+ import { buildTextUrl } from "@slopmachine/core";
555
+ import { marked } from "marked";
556
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
557
+ var SlopText = React3.forwardRef(
558
+ ({
559
+ bucketId,
560
+ version,
561
+ resultId,
562
+ model,
563
+ variables,
564
+ baseUrl,
565
+ fallback,
566
+ errorFallback,
567
+ ...props
568
+ }, ref) => {
569
+ const [text, setText] = useState3(null);
570
+ const [loading, setLoading] = useState3(true);
571
+ const [error, setError] = useState3(null);
572
+ useEffect2(() => {
573
+ let isMounted = true;
574
+ const fetchText = async () => {
575
+ try {
576
+ setLoading(true);
577
+ setError(null);
578
+ const url = buildTextUrl({
579
+ bucketId,
580
+ version,
581
+ resultId,
582
+ model,
583
+ variables,
584
+ baseUrl
585
+ });
586
+ const response = await fetch(url);
587
+ if (!response.ok) {
588
+ throw new Error(`Failed to fetch text: ${response.statusText}`);
589
+ }
590
+ const content = await response.text();
591
+ if (isMounted) {
592
+ setText(content);
593
+ }
594
+ } catch (err) {
595
+ if (isMounted) {
596
+ setError(
597
+ err instanceof Error ? err : new Error("Failed to generate text")
598
+ );
599
+ }
600
+ } finally {
601
+ if (isMounted) {
602
+ setLoading(false);
603
+ }
604
+ }
605
+ };
606
+ fetchText();
607
+ return () => {
608
+ isMounted = false;
609
+ };
610
+ }, [
611
+ bucketId,
612
+ version,
613
+ resultId,
614
+ model,
615
+ JSON.stringify(variables),
616
+ baseUrl
617
+ ]);
618
+ if (error && errorFallback) {
619
+ return /* @__PURE__ */ jsx3(Fragment3, { children: errorFallback });
620
+ }
621
+ if (loading) {
622
+ if (fallback) {
623
+ return /* @__PURE__ */ jsx3(Fragment3, { children: fallback });
624
+ }
625
+ return /* @__PURE__ */ jsxs3("div", { className: props.className, style: props.style, children: [
626
+ /* @__PURE__ */ jsx3("style", { children: `
627
+ @keyframes slop-shimmer {
628
+ 0% { background-position: 200% 0; }
629
+ 100% { background-position: -200% 0; }
630
+ }
631
+ @keyframes slop-spin {
632
+ from { transform: rotate(0deg); }
633
+ to { transform: rotate(360deg); }
634
+ }
635
+ ` }),
636
+ /* @__PURE__ */ jsxs3(
637
+ "div",
638
+ {
639
+ className: "slop-wrapper relative overflow-hidden w-full",
640
+ style: {
641
+ position: "relative",
642
+ overflow: "hidden",
643
+ width: "100%",
644
+ minHeight: "100px",
645
+ backgroundColor: "var(--muted, #f3f4f6)",
646
+ borderRadius: "0.375rem"
647
+ },
648
+ children: [
649
+ /* @__PURE__ */ jsx3(
650
+ "div",
651
+ {
652
+ className: "absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
653
+ style: {
654
+ position: "absolute",
655
+ top: 0,
656
+ left: 0,
657
+ right: 0,
658
+ bottom: 0,
659
+ zIndex: 10,
660
+ display: "flex",
661
+ alignItems: "center",
662
+ justifyContent: "center",
663
+ backgroundColor: "var(--muted, #f3f4f6)"
664
+ },
665
+ children: /* @__PURE__ */ jsxs3(
666
+ "div",
667
+ {
668
+ className: "flex flex-col items-center gap-2",
669
+ style: {
670
+ display: "flex",
671
+ flexDirection: "column",
672
+ alignItems: "center",
673
+ gap: "0.5rem"
674
+ },
675
+ children: [
676
+ /* @__PURE__ */ jsxs3(
677
+ "svg",
678
+ {
679
+ className: "spinner size-6 text-muted-foreground",
680
+ xmlns: "http://www.w3.org/2000/svg",
681
+ fill: "none",
682
+ viewBox: "0 0 24 24",
683
+ style: {
684
+ width: "24px",
685
+ height: "24px",
686
+ color: "var(--muted-foreground, #6b7280)",
687
+ animation: "slop-spin 1s linear infinite"
688
+ },
689
+ children: [
690
+ /* @__PURE__ */ jsx3(
691
+ "circle",
692
+ {
693
+ className: "opacity-25",
694
+ cx: "12",
695
+ cy: "12",
696
+ r: "10",
697
+ stroke: "currentColor",
698
+ strokeWidth: "4",
699
+ style: { opacity: 0.25 }
700
+ }
701
+ ),
702
+ /* @__PURE__ */ jsx3(
703
+ "path",
704
+ {
705
+ className: "opacity-75",
706
+ fill: "currentColor",
707
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z",
708
+ style: { opacity: 0.75 }
709
+ }
710
+ )
711
+ ]
712
+ }
713
+ ),
714
+ /* @__PURE__ */ jsx3(
715
+ "span",
716
+ {
717
+ className: "text-xs text-muted-foreground",
718
+ style: {
719
+ fontSize: "0.75rem",
720
+ color: "var(--muted-foreground, #6b7280)"
721
+ },
722
+ children: "Loading..."
723
+ }
724
+ )
725
+ ]
726
+ }
727
+ )
728
+ }
729
+ ),
730
+ /* @__PURE__ */ jsx3(
731
+ "div",
732
+ {
733
+ className: "shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
734
+ style: {
735
+ position: "absolute",
736
+ top: 0,
737
+ left: 0,
738
+ right: 0,
739
+ bottom: 0,
740
+ background: "linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
741
+ backgroundSize: "200% 100%",
742
+ animation: "slop-shimmer 2s ease-in-out infinite"
743
+ }
744
+ }
745
+ )
746
+ ]
747
+ }
748
+ )
749
+ ] });
750
+ }
751
+ return /* @__PURE__ */ jsx3(
752
+ "div",
753
+ {
754
+ ref,
755
+ ...props,
756
+ dangerouslySetInnerHTML: {
757
+ __html: text ? marked.parse(text) : ""
758
+ }
759
+ }
760
+ );
761
+ }
762
+ );
763
+ SlopText.displayName = "SlopText";
551
764
  export {
552
765
  SlopImage,
766
+ SlopText,
553
767
  SlopVideo
554
768
  };
555
769
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/SlopImage.tsx","../src/components/SlopVideo.tsx"],"sourcesContent":["import React, { useMemo, useState } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildImageUrl,\n type SlopImageOptions,\n type ImageAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopImageProps\n extends\n Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\">,\n Omit<SlopImageOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated image. Defaults to \"1:1\".\n */\n aspectRatio?: ImageAspectRatio;\n /**\n * Custom React node to display while the image is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders an image generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopImage\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * />\n * ```\n *\n * @version 0.1.14\n */\nexport const SlopImage: React.FC<SlopImageProps> = ({\n bucketId,\n className,\n aspectRatio = \"1:1\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n baseUrl,\n loader,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildImageUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n React.useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const alt = \"Generated image\";\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n React.useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n // console.error(\n // `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,\n // );\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopImage error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching image from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Image */}\n <img\n key={src}\n src={src}\n alt={alt}\n onLoad={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useMemo, useState, useRef, useEffect } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildVideoUrl,\n type SlopVideoOptions,\n type VideoAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopVideoProps\n extends\n Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"src\">,\n Omit<SlopVideoOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated video. Defaults to \"16:9\".\n */\n aspectRatio?: VideoAspectRatio;\n /**\n * Custom React node to display while the video is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders a video generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopVideo\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * autoPlay\n * loop\n * muted\n * />\n * ```\n */\nexport const SlopVideo: React.FC<SlopVideoProps> = ({\n bucketId,\n className,\n aspectRatio = \"16:9\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n duration,\n baseUrl,\n loader,\n autoPlay = true,\n loop = true,\n muted = true,\n playsInline = true,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildVideoUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n const videoRef = useRef<HTMLVideoElement>(null);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopVideo error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching video from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Video */}\n <video\n key={src}\n ref={videoRef}\n src={src}\n autoPlay={autoPlay}\n loop={loop}\n muted={muted}\n playsInline={playsInline}\n onLoadedData={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n"],"mappings":"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","names":["useMemo","useState","clsx","twMerge","Fragment","jsx","jsxs","cn"]}
1
+ {"version":3,"sources":["../src/components/SlopImage.tsx","../src/components/SlopVideo.tsx","../src/components/SlopText.tsx"],"sourcesContent":["import React, { useMemo, useState } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildImageUrl,\n type SlopImageOptions,\n type ImageAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopImageProps\n extends\n Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\">,\n Omit<SlopImageOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated image. Defaults to \"1:1\".\n */\n aspectRatio?: ImageAspectRatio;\n /**\n * Custom React node to display while the image is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders an image generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopImage\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopImage: React.FC<SlopImageProps> = ({\n bucketId,\n className,\n aspectRatio = \"1:1\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n baseUrl,\n loader,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildImageUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n React.useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const alt = \"Generated image\";\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n React.useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n // console.error(\n // `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,\n // );\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopImage error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching image from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Image */}\n <img\n key={src}\n src={src}\n alt={alt}\n onLoad={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useMemo, useState, useRef, useEffect } from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nimport {\n buildVideoUrl,\n type SlopVideoOptions,\n type VideoAspectRatio,\n} from \"@slopmachine/core\";\n\n// Utility for Tailwind classes\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport interface SlopVideoProps\n extends\n Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"src\">,\n Omit<SlopVideoOptions, \"aspectRatio\"> {\n /**\n * The aspect ratio of the generated video. Defaults to \"16:9\".\n */\n aspectRatio?: VideoAspectRatio;\n /**\n * Custom React node to display while the video is loading.\n * If not provided, a default spinner and shimmer effect will be shown.\n */\n loader?: React.ReactNode;\n}\n\n/**\n * Renders a video generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * displays a loading skeleton or custom loader while fetching, and handles errors.\n *\n * @example\n * ```tsx\n * <SlopVideo\n * bucketId=\"my-bucket\"\n * resultId=\"some-result\"\n * aspectRatio=\"16:9\"\n * className=\"rounded-lg\"\n * autoPlay\n * loop\n * muted\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopVideo: React.FC<SlopVideoProps> = ({\n bucketId,\n className,\n aspectRatio = \"16:9\",\n version,\n resultId,\n model,\n quality = \"fast\",\n variables = {},\n duration,\n baseUrl,\n loader,\n autoPlay = true,\n loop = true,\n muted = true,\n playsInline = true,\n ...props\n}) => {\n // Construct API URL\n const rawSrc = useMemo(\n () =>\n buildVideoUrl({\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n }),\n [\n bucketId,\n aspectRatio,\n version,\n resultId,\n variables,\n duration,\n baseUrl,\n model,\n quality,\n ],\n );\n\n const [src, setSrc] = useState(rawSrc);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setSrc(rawSrc);\n }, 100);\n return () => clearTimeout(timer);\n }, [rawSrc]);\n\n const [isLoading, setIsLoading] = useState(true);\n const [currentSrc, setCurrentSrc] = useState(src);\n const videoRef = useRef<HTMLVideoElement>(null);\n\n if (src !== currentSrc) {\n setCurrentSrc(src);\n setIsLoading(true);\n }\n\n useEffect(() => {\n if (!src) return;\n\n fetch(src, { method: \"HEAD\" })\n .then(async (res) => {\n if (!res.ok) {\n try {\n const errRes = await fetch(src);\n const errJson = await errRes.json();\n console.error(\"SlopVideo error:\", res.status, errJson.error);\n } catch (e) {\n // Failed to fetch or parse error details\n }\n setIsLoading(false);\n }\n })\n .catch((err) => {\n console.error(`Error fetching video from ${src}:`, err);\n setIsLoading(false);\n });\n }, [src]);\n\n return (\n <>\n <style>{`\n @keyframes slop-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n }\n @keyframes slop-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n `}</style>\n <div className={className} style={props.style}>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full h-full\"\n style={{\n aspectRatio: String(aspectRatio).replace(\":\", \"/\"),\n backgroundColor: \"var(--muted, #f3f4f6)\",\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n }}\n >\n {/* Loading UI */}\n {loader ? (\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n {loader}\n </div>\n ) : (\n <>\n {/* Loading overlay */}\n <div\n className={cn(\n \"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\",\n isLoading ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n opacity: isLoading ? 1 : 0,\n pointerEvents: isLoading ? \"auto\" : \"none\",\n transition: \"opacity 300ms ease-in-out\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className={cn(\n \"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\",\n isLoading ? \"opacity-100\" : \"opacity-0\",\n )}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n opacity: isLoading ? 1 : 0,\n transition: \"opacity 300ms\",\n }}\n />\n </>\n )}\n\n {/* Video */}\n <video\n key={src}\n ref={videoRef}\n src={src}\n autoPlay={autoPlay}\n loop={loop}\n muted={muted}\n playsInline={playsInline}\n onLoadedData={() => setIsLoading(false)}\n onError={() => setIsLoading(false)}\n className={cn(\n \"h-full w-full object-cover transition-opacity duration-500\",\n isLoading ? \"opacity-0\" : \"opacity-100\",\n )}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\",\n transition: \"opacity 500ms\",\n opacity: isLoading ? 0 : 1,\n }}\n {...props}\n />\n </div>\n </div>\n </>\n );\n};\n","import React, { useEffect, useState } from \"react\";\nimport { buildTextUrl, type SlopTextOptions } from \"@slopmachine/core\";\nimport { marked } from \"marked\";\n\nexport interface SlopTextProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, \"children\">,\n SlopTextOptions {\n /**\n * Optional loading component to show while the text is being generated\n */\n fallback?: React.ReactNode;\n /**\n * Optional error component to show if the text generation fails\n */\n errorFallback?: React.ReactNode;\n}\n\n/**\n * Renders text generated by Slop Machine.\n *\n * This component automatically constructs the correct URL for the Slop Machine API,\n * fetches the generated text, and displays it with optional loading and error states.\n *\n * @example\n * ```tsx\n * <SlopText\n * bucketId=\"my-text-bucket\"\n * fallback={<div>Loading story...</div>}\n * errorFallback={<div>Failed to load story</div>}\n * className=\"text-lg text-gray-800\"\n * />\n * ```\n *\n * @version 0.1.15\n */\nexport const SlopText = React.forwardRef<HTMLDivElement, SlopTextProps>(\n (\n {\n bucketId,\n version,\n resultId,\n model,\n variables,\n baseUrl,\n fallback,\n errorFallback,\n ...props\n },\n ref,\n ) => {\n const [text, setText] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let isMounted = true;\n\n const fetchText = async () => {\n try {\n setLoading(true);\n setError(null);\n\n const url = buildTextUrl({\n bucketId,\n version,\n resultId,\n model,\n variables,\n baseUrl,\n });\n\n // Fetch the URL to get the content, following redirects automatically\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch text: ${response.statusText}`);\n }\n const content = await response.text();\n if (isMounted) {\n setText(content);\n }\n } catch (err) {\n if (isMounted) {\n setError(\n err instanceof Error ? err : new Error(\"Failed to generate text\"),\n );\n }\n } finally {\n if (isMounted) {\n setLoading(false);\n }\n }\n };\n\n fetchText();\n\n return () => {\n isMounted = false;\n };\n }, [\n bucketId,\n version,\n resultId,\n model,\n JSON.stringify(variables),\n baseUrl,\n ]);\n\n if (error && errorFallback) {\n return <>{errorFallback}</>;\n }\n\n if (loading) {\n if (fallback) {\n return <>{fallback}</>;\n }\n return (\n <div className={props.className} style={props.style}>\n <style>{`\n @keyframes slop-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n }\n @keyframes slop-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n <div\n className=\"slop-wrapper relative overflow-hidden w-full\"\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n width: \"100%\",\n minHeight: \"100px\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n borderRadius: \"0.375rem\",\n }}\n >\n {/* Loading overlay */}\n <div\n className=\"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300\"\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"var(--muted, #f3f4f6)\",\n }}\n >\n <div\n className=\"flex flex-col items-center gap-2\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n className=\"spinner size-6 text-muted-foreground\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{\n width: \"24px\",\n height: \"24px\",\n color: \"var(--muted-foreground, #6b7280)\",\n animation: \"slop-spin 1s linear infinite\",\n }}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n style={{ opacity: 0.25 }}\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n style={{ opacity: 0.75 }}\n />\n </svg>\n <span\n className=\"text-xs text-muted-foreground\"\n style={{\n fontSize: \"0.75rem\",\n color: \"var(--muted-foreground, #6b7280)\",\n }}\n >\n Loading...\n </span>\n </div>\n </div>\n\n {/* Shimmer effect underneath */}\n <div\n className=\"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted\"\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background:\n \"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)\",\n backgroundSize: \"200% 100%\",\n animation: \"slop-shimmer 2s ease-in-out infinite\",\n }}\n />\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n {...props}\n dangerouslySetInnerHTML={{\n __html: text ? (marked.parse(text) as string) : \"\",\n }}\n />\n );\n },\n);\n\nSlopText.displayName = \"SlopText\";\n"],"mappings":"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","names":["useMemo","useState","clsx","twMerge","Fragment","jsx","jsxs","cn","React","useEffect","useState","Fragment","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@slopmachine/react",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
+ "llms": "https://slopmachine-dev.github.io/slopmachine-sdk/llms.txt",
5
+ "llmsFull": "https://slopmachine-dev.github.io/slopmachine-sdk/llms-full.txt",
4
6
  "description": "The official React SDK for Slop Machine",
5
7
  "main": "dist/index.js",
6
8
  "module": "dist/index.mjs",
@@ -48,9 +50,11 @@
48
50
  "@slopmachine/core": "*",
49
51
  "@tailwindcss/postcss": "^4.1.18",
50
52
  "@tailwindcss/vite": "^4.1.18",
53
+ "@types/marked": "^5.0.2",
51
54
  "class-variance-authority": "^0.7.1",
52
55
  "clsx": "^2.1.1",
53
56
  "lucide-react": "^0.563.0",
57
+ "marked": "^17.0.4",
54
58
  "shiki": "^3.21.0",
55
59
  "tailwind-merge": "^3.4.0",
56
60
  "tailwindcss-animate": "^1.0.7"
@@ -44,7 +44,7 @@ export interface SlopImageProps
44
44
  * />
45
45
  * ```
46
46
  *
47
- * @version 0.1.14
47
+ * @version 0.1.15
48
48
  */
49
49
  export const SlopImage: React.FC<SlopImageProps> = ({
50
50
  bucketId,
@@ -0,0 +1,237 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { buildTextUrl, type SlopTextOptions } from "@slopmachine/core";
3
+ import { marked } from "marked";
4
+
5
+ export interface SlopTextProps
6
+ extends
7
+ Omit<React.HTMLAttributes<HTMLDivElement>, "children">,
8
+ SlopTextOptions {
9
+ /**
10
+ * Optional loading component to show while the text is being generated
11
+ */
12
+ fallback?: React.ReactNode;
13
+ /**
14
+ * Optional error component to show if the text generation fails
15
+ */
16
+ errorFallback?: React.ReactNode;
17
+ }
18
+
19
+ /**
20
+ * Renders text generated by Slop Machine.
21
+ *
22
+ * This component automatically constructs the correct URL for the Slop Machine API,
23
+ * fetches the generated text, and displays it with optional loading and error states.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * <SlopText
28
+ * bucketId="my-text-bucket"
29
+ * fallback={<div>Loading story...</div>}
30
+ * errorFallback={<div>Failed to load story</div>}
31
+ * className="text-lg text-gray-800"
32
+ * />
33
+ * ```
34
+ *
35
+ * @version 0.1.15
36
+ */
37
+ export const SlopText = React.forwardRef<HTMLDivElement, SlopTextProps>(
38
+ (
39
+ {
40
+ bucketId,
41
+ version,
42
+ resultId,
43
+ model,
44
+ variables,
45
+ baseUrl,
46
+ fallback,
47
+ errorFallback,
48
+ ...props
49
+ },
50
+ ref,
51
+ ) => {
52
+ const [text, setText] = useState<string | null>(null);
53
+ const [loading, setLoading] = useState(true);
54
+ const [error, setError] = useState<Error | null>(null);
55
+
56
+ useEffect(() => {
57
+ let isMounted = true;
58
+
59
+ const fetchText = async () => {
60
+ try {
61
+ setLoading(true);
62
+ setError(null);
63
+
64
+ const url = buildTextUrl({
65
+ bucketId,
66
+ version,
67
+ resultId,
68
+ model,
69
+ variables,
70
+ baseUrl,
71
+ });
72
+
73
+ // Fetch the URL to get the content, following redirects automatically
74
+ const response = await fetch(url);
75
+ if (!response.ok) {
76
+ throw new Error(`Failed to fetch text: ${response.statusText}`);
77
+ }
78
+ const content = await response.text();
79
+ if (isMounted) {
80
+ setText(content);
81
+ }
82
+ } catch (err) {
83
+ if (isMounted) {
84
+ setError(
85
+ err instanceof Error ? err : new Error("Failed to generate text"),
86
+ );
87
+ }
88
+ } finally {
89
+ if (isMounted) {
90
+ setLoading(false);
91
+ }
92
+ }
93
+ };
94
+
95
+ fetchText();
96
+
97
+ return () => {
98
+ isMounted = false;
99
+ };
100
+ }, [
101
+ bucketId,
102
+ version,
103
+ resultId,
104
+ model,
105
+ JSON.stringify(variables),
106
+ baseUrl,
107
+ ]);
108
+
109
+ if (error && errorFallback) {
110
+ return <>{errorFallback}</>;
111
+ }
112
+
113
+ if (loading) {
114
+ if (fallback) {
115
+ return <>{fallback}</>;
116
+ }
117
+ return (
118
+ <div className={props.className} style={props.style}>
119
+ <style>{`
120
+ @keyframes slop-shimmer {
121
+ 0% { background-position: 200% 0; }
122
+ 100% { background-position: -200% 0; }
123
+ }
124
+ @keyframes slop-spin {
125
+ from { transform: rotate(0deg); }
126
+ to { transform: rotate(360deg); }
127
+ }
128
+ `}</style>
129
+ <div
130
+ className="slop-wrapper relative overflow-hidden w-full"
131
+ style={{
132
+ position: "relative",
133
+ overflow: "hidden",
134
+ width: "100%",
135
+ minHeight: "100px",
136
+ backgroundColor: "var(--muted, #f3f4f6)",
137
+ borderRadius: "0.375rem",
138
+ }}
139
+ >
140
+ {/* Loading overlay */}
141
+ <div
142
+ className="absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300"
143
+ style={{
144
+ position: "absolute",
145
+ top: 0,
146
+ left: 0,
147
+ right: 0,
148
+ bottom: 0,
149
+ zIndex: 10,
150
+ display: "flex",
151
+ alignItems: "center",
152
+ justifyContent: "center",
153
+ backgroundColor: "var(--muted, #f3f4f6)",
154
+ }}
155
+ >
156
+ <div
157
+ className="flex flex-col items-center gap-2"
158
+ style={{
159
+ display: "flex",
160
+ flexDirection: "column",
161
+ alignItems: "center",
162
+ gap: "0.5rem",
163
+ }}
164
+ >
165
+ <svg
166
+ className="spinner size-6 text-muted-foreground"
167
+ xmlns="http://www.w3.org/2000/svg"
168
+ fill="none"
169
+ viewBox="0 0 24 24"
170
+ style={{
171
+ width: "24px",
172
+ height: "24px",
173
+ color: "var(--muted-foreground, #6b7280)",
174
+ animation: "slop-spin 1s linear infinite",
175
+ }}
176
+ >
177
+ <circle
178
+ className="opacity-25"
179
+ cx="12"
180
+ cy="12"
181
+ r="10"
182
+ stroke="currentColor"
183
+ strokeWidth="4"
184
+ style={{ opacity: 0.25 }}
185
+ />
186
+ <path
187
+ className="opacity-75"
188
+ fill="currentColor"
189
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
190
+ style={{ opacity: 0.75 }}
191
+ />
192
+ </svg>
193
+ <span
194
+ className="text-xs text-muted-foreground"
195
+ style={{
196
+ fontSize: "0.75rem",
197
+ color: "var(--muted-foreground, #6b7280)",
198
+ }}
199
+ >
200
+ Loading...
201
+ </span>
202
+ </div>
203
+ </div>
204
+
205
+ {/* Shimmer effect underneath */}
206
+ <div
207
+ className="shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted"
208
+ style={{
209
+ position: "absolute",
210
+ top: 0,
211
+ left: 0,
212
+ right: 0,
213
+ bottom: 0,
214
+ background:
215
+ "linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
216
+ backgroundSize: "200% 100%",
217
+ animation: "slop-shimmer 2s ease-in-out infinite",
218
+ }}
219
+ />
220
+ </div>
221
+ </div>
222
+ );
223
+ }
224
+
225
+ return (
226
+ <div
227
+ ref={ref}
228
+ {...props}
229
+ dangerouslySetInnerHTML={{
230
+ __html: text ? (marked.parse(text) as string) : "",
231
+ }}
232
+ />
233
+ );
234
+ },
235
+ );
236
+
237
+ SlopText.displayName = "SlopText";
@@ -46,6 +46,8 @@ export interface SlopVideoProps
46
46
  * muted
47
47
  * />
48
48
  * ```
49
+ *
50
+ * @version 0.1.15
49
51
  */
50
52
  export const SlopVideo: React.FC<SlopVideoProps> = ({
51
53
  bucketId,
package/src/index.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { SlopImage, type SlopImageProps } from "./components/SlopImage";
2
2
  export { SlopVideo, type SlopVideoProps } from "./components/SlopVideo";
3
+ export { SlopText, type SlopTextProps } from "./components/SlopText";
4
+
3
5
  export type {
4
6
  ImageAspectRatio,
5
7
  VideoAspectRatio,
File without changes