@slopmachine/react 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -12,6 +12,10 @@ yarn add @slopmachine/react
12
12
  pnpm add @slopmachine/react
13
13
  ```
14
14
 
15
+ ## Demo
16
+
17
+ https://slopmachine-dev.github.io/slopmachine-sdk/
18
+
15
19
  ## Usage
16
20
 
17
21
  ```tsx
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -25,7 +35,7 @@ __export(index_exports, {
25
35
  module.exports = __toCommonJS(index_exports);
26
36
 
27
37
  // src/components/SlopImage.tsx
28
- var import_react = require("react");
38
+ var import_react = __toESM(require("react"));
29
39
  var import_clsx = require("clsx");
30
40
  var import_tailwind_merge = require("tailwind-merge");
31
41
  var import_core = require("@slopmachine/core");
@@ -34,6 +44,7 @@ function cn(...inputs) {
34
44
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
35
45
  }
36
46
  var SlopImage = ({
47
+ bucketId,
37
48
  prompt,
38
49
  className,
39
50
  aspectRatio = "1:1",
@@ -42,10 +53,24 @@ var SlopImage = ({
42
53
  baseUrl,
43
54
  ...props
44
55
  }) => {
45
- const src = (0, import_react.useMemo)(
46
- () => (0, import_core.buildImageUrl)({ prompt, aspectRatio, variables, baseUrl, model }),
47
- [prompt, aspectRatio, variables, baseUrl, model]
56
+ const rawSrc = (0, import_react.useMemo)(
57
+ () => (0, import_core.buildImageUrl)({
58
+ bucketId,
59
+ prompt,
60
+ aspectRatio,
61
+ variables,
62
+ baseUrl,
63
+ model
64
+ }),
65
+ [bucketId, prompt, aspectRatio, variables, baseUrl, model]
48
66
  );
67
+ const [src, setSrc] = (0, import_react.useState)(rawSrc);
68
+ import_react.default.useEffect(() => {
69
+ const timer = setTimeout(() => {
70
+ setSrc(rawSrc);
71
+ }, 100);
72
+ return () => clearTimeout(timer);
73
+ }, [rawSrc]);
49
74
  const alt = (0, import_react.useMemo)(
50
75
  () => (0, import_core.interpolatePrompt)(prompt, variables) ?? "Generated image",
51
76
  [prompt, variables]
@@ -56,6 +81,23 @@ var SlopImage = ({
56
81
  setCurrentSrc(src);
57
82
  setIsLoading(true);
58
83
  }
84
+ import_react.default.useEffect(() => {
85
+ if (!src) return;
86
+ fetch(src, { method: "HEAD" }).then(async (res) => {
87
+ if (!res.ok) {
88
+ try {
89
+ const errRes = await fetch(src);
90
+ const errJson = await errRes.json();
91
+ console.error("SlopImage error:", res.status, errJson.error);
92
+ } catch (e) {
93
+ }
94
+ setIsLoading(false);
95
+ }
96
+ }).catch((err) => {
97
+ console.error(`Error fetching image from ${src}:`, err);
98
+ setIsLoading(false);
99
+ });
100
+ }, [src]);
59
101
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
60
102
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
61
103
  @keyframes slop-shimmer {
@@ -200,6 +242,7 @@ var SlopImage = ({
200
242
  src,
201
243
  alt,
202
244
  onLoad: () => setIsLoading(false),
245
+ onError: () => setIsLoading(false),
203
246
  className: cn(
204
247
  "h-full w-full object-cover transition-opacity duration-500",
205
248
  isLoading ? "opacity-0" : "opacity-100"
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/SlopImage.tsx
2
- import { useMemo, useState } from "react";
2
+ import React, { useMemo, useState } from "react";
3
3
  import { clsx } from "clsx";
4
4
  import { twMerge } from "tailwind-merge";
5
5
  import {
@@ -11,6 +11,7 @@ function cn(...inputs) {
11
11
  return twMerge(clsx(inputs));
12
12
  }
13
13
  var SlopImage = ({
14
+ bucketId,
14
15
  prompt,
15
16
  className,
16
17
  aspectRatio = "1:1",
@@ -19,10 +20,24 @@ var SlopImage = ({
19
20
  baseUrl,
20
21
  ...props
21
22
  }) => {
22
- const src = useMemo(
23
- () => buildImageUrl({ prompt, aspectRatio, variables, baseUrl, model }),
24
- [prompt, aspectRatio, variables, baseUrl, model]
23
+ const rawSrc = useMemo(
24
+ () => buildImageUrl({
25
+ bucketId,
26
+ prompt,
27
+ aspectRatio,
28
+ variables,
29
+ baseUrl,
30
+ model
31
+ }),
32
+ [bucketId, prompt, aspectRatio, variables, baseUrl, model]
25
33
  );
34
+ const [src, setSrc] = useState(rawSrc);
35
+ React.useEffect(() => {
36
+ const timer = setTimeout(() => {
37
+ setSrc(rawSrc);
38
+ }, 100);
39
+ return () => clearTimeout(timer);
40
+ }, [rawSrc]);
26
41
  const alt = useMemo(
27
42
  () => interpolatePrompt(prompt, variables) ?? "Generated image",
28
43
  [prompt, variables]
@@ -33,6 +48,23 @@ var SlopImage = ({
33
48
  setCurrentSrc(src);
34
49
  setIsLoading(true);
35
50
  }
51
+ React.useEffect(() => {
52
+ if (!src) return;
53
+ fetch(src, { method: "HEAD" }).then(async (res) => {
54
+ if (!res.ok) {
55
+ try {
56
+ const errRes = await fetch(src);
57
+ const errJson = await errRes.json();
58
+ console.error("SlopImage error:", res.status, errJson.error);
59
+ } catch (e) {
60
+ }
61
+ setIsLoading(false);
62
+ }
63
+ }).catch((err) => {
64
+ console.error(`Error fetching image from ${src}:`, err);
65
+ setIsLoading(false);
66
+ });
67
+ }, [src]);
36
68
  return /* @__PURE__ */ jsxs(Fragment, { children: [
37
69
  /* @__PURE__ */ jsx("style", { children: `
38
70
  @keyframes slop-shimmer {
@@ -177,6 +209,7 @@ var SlopImage = ({
177
209
  src,
178
210
  alt,
179
211
  onLoad: () => setIsLoading(false),
212
+ onError: () => setIsLoading(false),
180
213
  className: cn(
181
214
  "h-full w-full object-cover transition-opacity duration-500",
182
215
  isLoading ? "opacity-0" : "opacity-100"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slopmachine/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The official React SDK for Slop Machine",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -19,6 +19,7 @@ interface SlopImageProps
19
19
  SlopImageOptions {}
20
20
 
21
21
  export const SlopImage: React.FC<SlopImageProps> = ({
22
+ bucketId,
22
23
  prompt,
23
24
  className,
24
25
  aspectRatio = "1:1",
@@ -28,11 +29,28 @@ export const SlopImage: React.FC<SlopImageProps> = ({
28
29
  ...props
29
30
  }) => {
30
31
  // Construct API URL
31
- const src = useMemo(
32
- () => buildImageUrl({ prompt, aspectRatio, variables, baseUrl, model }),
33
- [prompt, aspectRatio, variables, baseUrl, model],
32
+ const rawSrc = useMemo(
33
+ () =>
34
+ buildImageUrl({
35
+ bucketId,
36
+ prompt,
37
+ aspectRatio,
38
+ variables,
39
+ baseUrl,
40
+ model,
41
+ }),
42
+ [bucketId, prompt, aspectRatio, variables, baseUrl, model],
34
43
  );
35
44
 
45
+ const [src, setSrc] = useState(rawSrc);
46
+
47
+ React.useEffect(() => {
48
+ const timer = setTimeout(() => {
49
+ setSrc(rawSrc);
50
+ }, 100);
51
+ return () => clearTimeout(timer);
52
+ }, [rawSrc]);
53
+
36
54
  const alt = useMemo(
37
55
  () => interpolatePrompt(prompt, variables) ?? "Generated image",
38
56
  [prompt, variables],
@@ -46,6 +64,31 @@ export const SlopImage: React.FC<SlopImageProps> = ({
46
64
  setIsLoading(true);
47
65
  }
48
66
 
67
+ React.useEffect(() => {
68
+ if (!src) return;
69
+
70
+ fetch(src, { method: "HEAD" })
71
+ .then(async (res) => {
72
+ if (!res.ok) {
73
+ // console.error(
74
+ // `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,
75
+ // );
76
+ try {
77
+ const errRes = await fetch(src);
78
+ const errJson = await errRes.json();
79
+ console.error("SlopImage error:", res.status, errJson.error);
80
+ } catch (e) {
81
+ // Failed to fetch or parse error details
82
+ }
83
+ setIsLoading(false);
84
+ }
85
+ })
86
+ .catch((err) => {
87
+ console.error(`Error fetching image from ${src}:`, err);
88
+ setIsLoading(false);
89
+ });
90
+ }, [src]);
91
+
49
92
  return (
50
93
  <>
51
94
  <style>{`
@@ -73,7 +116,8 @@ export const SlopImage: React.FC<SlopImageProps> = ({
73
116
  backgroundColor: "var(--muted, #f3f4f6)",
74
117
  position: "relative",
75
118
  overflow: "hidden",
76
- }}>
119
+ }}
120
+ >
77
121
  {/* Loading overlay */}
78
122
  <div
79
123
  className={cn(
@@ -94,7 +138,8 @@ export const SlopImage: React.FC<SlopImageProps> = ({
94
138
  opacity: isLoading ? 1 : 0,
95
139
  pointerEvents: isLoading ? "auto" : "none",
96
140
  transition: "opacity 300ms ease-in-out",
97
- }}>
141
+ }}
142
+ >
98
143
  <div
99
144
  className="flex flex-col items-center gap-2"
100
145
  style={{
@@ -102,7 +147,8 @@ export const SlopImage: React.FC<SlopImageProps> = ({
102
147
  flexDirection: "column",
103
148
  alignItems: "center",
104
149
  gap: "0.5rem",
105
- }}>
150
+ }}
151
+ >
106
152
  <svg
107
153
  className="spinner size-6 text-muted-foreground"
108
154
  xmlns="http://www.w3.org/2000/svg"
@@ -113,7 +159,8 @@ export const SlopImage: React.FC<SlopImageProps> = ({
113
159
  height: "24px",
114
160
  color: "var(--muted-foreground, #6b7280)",
115
161
  animation: "slop-spin 1s linear infinite",
116
- }}>
162
+ }}
163
+ >
117
164
  <circle
118
165
  className="opacity-25"
119
166
  cx="12"
@@ -135,7 +182,8 @@ export const SlopImage: React.FC<SlopImageProps> = ({
135
182
  style={{
136
183
  fontSize: "0.75rem",
137
184
  color: "var(--muted-foreground, #6b7280)",
138
- }}>
185
+ }}
186
+ >
139
187
  Loading...
140
188
  </span>
141
189
  </div>
@@ -168,6 +216,7 @@ export const SlopImage: React.FC<SlopImageProps> = ({
168
216
  src={src}
169
217
  alt={alt}
170
218
  onLoad={() => setIsLoading(false)}
219
+ onError={() => setIsLoading(false)}
171
220
  className={cn(
172
221
  "h-full w-full object-cover transition-opacity duration-500",
173
222
  isLoading ? "opacity-0" : "opacity-100",