@slopmachine/react 0.1.8 → 0.1.10
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 +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +113 -87
- package/dist/index.mjs +113 -87
- package/package.json +8 -17
- package/src/components/SlopImage.tsx +262 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +28 -0
- package/tsup.config.ts +9 -0
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { SlopImageOptions } from '@slopmachine/core';
|
|
3
3
|
|
|
4
4
|
interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">, SlopImageOptions {
|
|
5
|
+
loader?: React.ReactNode;
|
|
5
6
|
}
|
|
6
7
|
declare const SlopImage: React.FC<SlopImageProps>;
|
|
7
8
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { SlopImageOptions } from '@slopmachine/core';
|
|
3
3
|
|
|
4
4
|
interface SlopImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">, SlopImageOptions {
|
|
5
|
+
loader?: React.ReactNode;
|
|
5
6
|
}
|
|
6
7
|
declare const SlopImage: React.FC<SlopImageProps>;
|
|
7
8
|
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ var SlopImage = ({
|
|
|
52
52
|
model,
|
|
53
53
|
variables = {},
|
|
54
54
|
baseUrl,
|
|
55
|
+
loader,
|
|
55
56
|
...props
|
|
56
57
|
}) => {
|
|
57
58
|
const rawSrc = (0, import_react.useMemo)(
|
|
@@ -127,11 +128,11 @@ var SlopImage = ({
|
|
|
127
128
|
overflow: "hidden"
|
|
128
129
|
},
|
|
129
130
|
children: [
|
|
130
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
loader ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
132
|
"div",
|
|
132
133
|
{
|
|
133
134
|
className: cn(
|
|
134
|
-
"absolute inset-0 z-10 flex items-center justify-center
|
|
135
|
+
"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300",
|
|
135
136
|
isLoading ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
136
137
|
),
|
|
137
138
|
style: {
|
|
@@ -144,97 +145,122 @@ var SlopImage = ({
|
|
|
144
145
|
display: "flex",
|
|
145
146
|
alignItems: "center",
|
|
146
147
|
justifyContent: "center",
|
|
147
|
-
backgroundColor: "var(--muted, #f3f4f6)",
|
|
148
148
|
opacity: isLoading ? 1 : 0,
|
|
149
149
|
pointerEvents: isLoading ? "auto" : "none",
|
|
150
150
|
transition: "opacity 300ms ease-in-out"
|
|
151
151
|
},
|
|
152
|
-
children:
|
|
153
|
-
"div",
|
|
154
|
-
{
|
|
155
|
-
className: "flex flex-col items-center gap-2",
|
|
156
|
-
style: {
|
|
157
|
-
display: "flex",
|
|
158
|
-
flexDirection: "column",
|
|
159
|
-
alignItems: "center",
|
|
160
|
-
gap: "0.5rem"
|
|
161
|
-
},
|
|
162
|
-
children: [
|
|
163
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
164
|
-
"svg",
|
|
165
|
-
{
|
|
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
|
-
children: [
|
|
177
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
178
|
-
"circle",
|
|
179
|
-
{
|
|
180
|
-
className: "opacity-25",
|
|
181
|
-
cx: "12",
|
|
182
|
-
cy: "12",
|
|
183
|
-
r: "10",
|
|
184
|
-
stroke: "currentColor",
|
|
185
|
-
strokeWidth: "4",
|
|
186
|
-
style: { opacity: 0.25 }
|
|
187
|
-
}
|
|
188
|
-
),
|
|
189
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
190
|
-
"path",
|
|
191
|
-
{
|
|
192
|
-
className: "opacity-75",
|
|
193
|
-
fill: "currentColor",
|
|
194
|
-
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",
|
|
195
|
-
style: { opacity: 0.75 }
|
|
196
|
-
}
|
|
197
|
-
)
|
|
198
|
-
]
|
|
199
|
-
}
|
|
200
|
-
),
|
|
201
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
202
|
-
"span",
|
|
203
|
-
{
|
|
204
|
-
className: "text-xs text-muted-foreground",
|
|
205
|
-
style: {
|
|
206
|
-
fontSize: "0.75rem",
|
|
207
|
-
color: "var(--muted-foreground, #6b7280)"
|
|
208
|
-
},
|
|
209
|
-
children: "Loading..."
|
|
210
|
-
}
|
|
211
|
-
)
|
|
212
|
-
]
|
|
213
|
-
}
|
|
214
|
-
)
|
|
152
|
+
children: loader
|
|
215
153
|
}
|
|
216
|
-
),
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
154
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
156
|
+
"div",
|
|
157
|
+
{
|
|
158
|
+
className: cn(
|
|
159
|
+
"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
|
|
160
|
+
isLoading ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
161
|
+
),
|
|
162
|
+
style: {
|
|
163
|
+
position: "absolute",
|
|
164
|
+
top: 0,
|
|
165
|
+
left: 0,
|
|
166
|
+
right: 0,
|
|
167
|
+
bottom: 0,
|
|
168
|
+
zIndex: 10,
|
|
169
|
+
display: "flex",
|
|
170
|
+
alignItems: "center",
|
|
171
|
+
justifyContent: "center",
|
|
172
|
+
backgroundColor: "var(--muted, #f3f4f6)",
|
|
173
|
+
opacity: isLoading ? 1 : 0,
|
|
174
|
+
pointerEvents: isLoading ? "auto" : "none",
|
|
175
|
+
transition: "opacity 300ms ease-in-out"
|
|
176
|
+
},
|
|
177
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
178
|
+
"div",
|
|
179
|
+
{
|
|
180
|
+
className: "flex flex-col items-center gap-2",
|
|
181
|
+
style: {
|
|
182
|
+
display: "flex",
|
|
183
|
+
flexDirection: "column",
|
|
184
|
+
alignItems: "center",
|
|
185
|
+
gap: "0.5rem"
|
|
186
|
+
},
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
189
|
+
"svg",
|
|
190
|
+
{
|
|
191
|
+
className: "spinner size-6 text-muted-foreground",
|
|
192
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
193
|
+
fill: "none",
|
|
194
|
+
viewBox: "0 0 24 24",
|
|
195
|
+
style: {
|
|
196
|
+
width: "24px",
|
|
197
|
+
height: "24px",
|
|
198
|
+
color: "var(--muted-foreground, #6b7280)",
|
|
199
|
+
animation: "slop-spin 1s linear infinite"
|
|
200
|
+
},
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
203
|
+
"circle",
|
|
204
|
+
{
|
|
205
|
+
className: "opacity-25",
|
|
206
|
+
cx: "12",
|
|
207
|
+
cy: "12",
|
|
208
|
+
r: "10",
|
|
209
|
+
stroke: "currentColor",
|
|
210
|
+
strokeWidth: "4",
|
|
211
|
+
style: { opacity: 0.25 }
|
|
212
|
+
}
|
|
213
|
+
),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
215
|
+
"path",
|
|
216
|
+
{
|
|
217
|
+
className: "opacity-75",
|
|
218
|
+
fill: "currentColor",
|
|
219
|
+
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",
|
|
220
|
+
style: { opacity: 0.75 }
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
227
|
+
"span",
|
|
228
|
+
{
|
|
229
|
+
className: "text-xs text-muted-foreground",
|
|
230
|
+
style: {
|
|
231
|
+
fontSize: "0.75rem",
|
|
232
|
+
color: "var(--muted-foreground, #6b7280)"
|
|
233
|
+
},
|
|
234
|
+
children: "Loading..."
|
|
235
|
+
}
|
|
236
|
+
)
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
)
|
|
235
240
|
}
|
|
236
|
-
|
|
237
|
-
|
|
241
|
+
),
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
243
|
+
"div",
|
|
244
|
+
{
|
|
245
|
+
className: cn(
|
|
246
|
+
"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
|
|
247
|
+
isLoading ? "opacity-100" : "opacity-0"
|
|
248
|
+
),
|
|
249
|
+
style: {
|
|
250
|
+
position: "absolute",
|
|
251
|
+
top: 0,
|
|
252
|
+
left: 0,
|
|
253
|
+
right: 0,
|
|
254
|
+
bottom: 0,
|
|
255
|
+
background: "linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
|
|
256
|
+
backgroundSize: "200% 100%",
|
|
257
|
+
animation: "slop-shimmer 2s ease-in-out infinite",
|
|
258
|
+
opacity: isLoading ? 1 : 0,
|
|
259
|
+
transition: "opacity 300ms"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
] }),
|
|
238
264
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
239
265
|
"img",
|
|
240
266
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -16,6 +16,7 @@ var SlopImage = ({
|
|
|
16
16
|
model,
|
|
17
17
|
variables = {},
|
|
18
18
|
baseUrl,
|
|
19
|
+
loader,
|
|
19
20
|
...props
|
|
20
21
|
}) => {
|
|
21
22
|
const rawSrc = useMemo(
|
|
@@ -91,11 +92,11 @@ var SlopImage = ({
|
|
|
91
92
|
overflow: "hidden"
|
|
92
93
|
},
|
|
93
94
|
children: [
|
|
94
|
-
/* @__PURE__ */ jsx(
|
|
95
|
+
loader ? /* @__PURE__ */ jsx(
|
|
95
96
|
"div",
|
|
96
97
|
{
|
|
97
98
|
className: cn(
|
|
98
|
-
"absolute inset-0 z-10 flex items-center justify-center
|
|
99
|
+
"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300",
|
|
99
100
|
isLoading ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
100
101
|
),
|
|
101
102
|
style: {
|
|
@@ -108,97 +109,122 @@ var SlopImage = ({
|
|
|
108
109
|
display: "flex",
|
|
109
110
|
alignItems: "center",
|
|
110
111
|
justifyContent: "center",
|
|
111
|
-
backgroundColor: "var(--muted, #f3f4f6)",
|
|
112
112
|
opacity: isLoading ? 1 : 0,
|
|
113
113
|
pointerEvents: isLoading ? "auto" : "none",
|
|
114
114
|
transition: "opacity 300ms ease-in-out"
|
|
115
115
|
},
|
|
116
|
-
children:
|
|
117
|
-
"div",
|
|
118
|
-
{
|
|
119
|
-
className: "flex flex-col items-center gap-2",
|
|
120
|
-
style: {
|
|
121
|
-
display: "flex",
|
|
122
|
-
flexDirection: "column",
|
|
123
|
-
alignItems: "center",
|
|
124
|
-
gap: "0.5rem"
|
|
125
|
-
},
|
|
126
|
-
children: [
|
|
127
|
-
/* @__PURE__ */ jsxs(
|
|
128
|
-
"svg",
|
|
129
|
-
{
|
|
130
|
-
className: "spinner size-6 text-muted-foreground",
|
|
131
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
132
|
-
fill: "none",
|
|
133
|
-
viewBox: "0 0 24 24",
|
|
134
|
-
style: {
|
|
135
|
-
width: "24px",
|
|
136
|
-
height: "24px",
|
|
137
|
-
color: "var(--muted-foreground, #6b7280)",
|
|
138
|
-
animation: "slop-spin 1s linear infinite"
|
|
139
|
-
},
|
|
140
|
-
children: [
|
|
141
|
-
/* @__PURE__ */ jsx(
|
|
142
|
-
"circle",
|
|
143
|
-
{
|
|
144
|
-
className: "opacity-25",
|
|
145
|
-
cx: "12",
|
|
146
|
-
cy: "12",
|
|
147
|
-
r: "10",
|
|
148
|
-
stroke: "currentColor",
|
|
149
|
-
strokeWidth: "4",
|
|
150
|
-
style: { opacity: 0.25 }
|
|
151
|
-
}
|
|
152
|
-
),
|
|
153
|
-
/* @__PURE__ */ jsx(
|
|
154
|
-
"path",
|
|
155
|
-
{
|
|
156
|
-
className: "opacity-75",
|
|
157
|
-
fill: "currentColor",
|
|
158
|
-
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",
|
|
159
|
-
style: { opacity: 0.75 }
|
|
160
|
-
}
|
|
161
|
-
)
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
),
|
|
165
|
-
/* @__PURE__ */ jsx(
|
|
166
|
-
"span",
|
|
167
|
-
{
|
|
168
|
-
className: "text-xs text-muted-foreground",
|
|
169
|
-
style: {
|
|
170
|
-
fontSize: "0.75rem",
|
|
171
|
-
color: "var(--muted-foreground, #6b7280)"
|
|
172
|
-
},
|
|
173
|
-
children: "Loading..."
|
|
174
|
-
}
|
|
175
|
-
)
|
|
176
|
-
]
|
|
177
|
-
}
|
|
178
|
-
)
|
|
116
|
+
children: loader
|
|
179
117
|
}
|
|
180
|
-
),
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
118
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
className: cn(
|
|
123
|
+
"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
|
|
124
|
+
isLoading ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
125
|
+
),
|
|
126
|
+
style: {
|
|
127
|
+
position: "absolute",
|
|
128
|
+
top: 0,
|
|
129
|
+
left: 0,
|
|
130
|
+
right: 0,
|
|
131
|
+
bottom: 0,
|
|
132
|
+
zIndex: 10,
|
|
133
|
+
display: "flex",
|
|
134
|
+
alignItems: "center",
|
|
135
|
+
justifyContent: "center",
|
|
136
|
+
backgroundColor: "var(--muted, #f3f4f6)",
|
|
137
|
+
opacity: isLoading ? 1 : 0,
|
|
138
|
+
pointerEvents: isLoading ? "auto" : "none",
|
|
139
|
+
transition: "opacity 300ms ease-in-out"
|
|
140
|
+
},
|
|
141
|
+
children: /* @__PURE__ */ jsxs(
|
|
142
|
+
"div",
|
|
143
|
+
{
|
|
144
|
+
className: "flex flex-col items-center gap-2",
|
|
145
|
+
style: {
|
|
146
|
+
display: "flex",
|
|
147
|
+
flexDirection: "column",
|
|
148
|
+
alignItems: "center",
|
|
149
|
+
gap: "0.5rem"
|
|
150
|
+
},
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsxs(
|
|
153
|
+
"svg",
|
|
154
|
+
{
|
|
155
|
+
className: "spinner size-6 text-muted-foreground",
|
|
156
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
157
|
+
fill: "none",
|
|
158
|
+
viewBox: "0 0 24 24",
|
|
159
|
+
style: {
|
|
160
|
+
width: "24px",
|
|
161
|
+
height: "24px",
|
|
162
|
+
color: "var(--muted-foreground, #6b7280)",
|
|
163
|
+
animation: "slop-spin 1s linear infinite"
|
|
164
|
+
},
|
|
165
|
+
children: [
|
|
166
|
+
/* @__PURE__ */ jsx(
|
|
167
|
+
"circle",
|
|
168
|
+
{
|
|
169
|
+
className: "opacity-25",
|
|
170
|
+
cx: "12",
|
|
171
|
+
cy: "12",
|
|
172
|
+
r: "10",
|
|
173
|
+
stroke: "currentColor",
|
|
174
|
+
strokeWidth: "4",
|
|
175
|
+
style: { opacity: 0.25 }
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
"path",
|
|
180
|
+
{
|
|
181
|
+
className: "opacity-75",
|
|
182
|
+
fill: "currentColor",
|
|
183
|
+
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",
|
|
184
|
+
style: { opacity: 0.75 }
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
"span",
|
|
192
|
+
{
|
|
193
|
+
className: "text-xs text-muted-foreground",
|
|
194
|
+
style: {
|
|
195
|
+
fontSize: "0.75rem",
|
|
196
|
+
color: "var(--muted-foreground, #6b7280)"
|
|
197
|
+
},
|
|
198
|
+
children: "Loading..."
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
)
|
|
199
204
|
}
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
),
|
|
206
|
+
/* @__PURE__ */ jsx(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
className: cn(
|
|
210
|
+
"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
|
|
211
|
+
isLoading ? "opacity-100" : "opacity-0"
|
|
212
|
+
),
|
|
213
|
+
style: {
|
|
214
|
+
position: "absolute",
|
|
215
|
+
top: 0,
|
|
216
|
+
left: 0,
|
|
217
|
+
right: 0,
|
|
218
|
+
bottom: 0,
|
|
219
|
+
background: "linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
|
|
220
|
+
backgroundSize: "200% 100%",
|
|
221
|
+
animation: "slop-shimmer 2s ease-in-out infinite",
|
|
222
|
+
opacity: isLoading ? 1 : 0,
|
|
223
|
+
transition: "opacity 300ms"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
] }),
|
|
202
228
|
/* @__PURE__ */ jsx(
|
|
203
229
|
"img",
|
|
204
230
|
{
|
package/package.json
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slopmachine/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "The official React SDK for Slop Machine",
|
|
5
|
-
"main": "
|
|
6
|
-
"module": "
|
|
7
|
-
"types": "
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
"require": {
|
|
15
|
-
"types": "./dist/index.d.ts",
|
|
16
|
-
"default": "./dist/index.js"
|
|
17
|
-
}
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
18
13
|
}
|
|
19
14
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
],
|
|
23
15
|
"scripts": {
|
|
24
16
|
"build": "tsup",
|
|
25
|
-
"dev": "tsup --watch"
|
|
26
|
-
"prepublishOnly": "npm run build"
|
|
17
|
+
"dev": "tsup --watch"
|
|
27
18
|
},
|
|
28
19
|
"repository": {
|
|
29
20
|
"type": "git",
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { clsx, type ClassValue } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
|
|
5
|
+
import { buildImageUrl, type SlopImageOptions } from "@slopmachine/core";
|
|
6
|
+
|
|
7
|
+
// Utility for Tailwind classes
|
|
8
|
+
function cn(...inputs: ClassValue[]) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SlopImageProps
|
|
13
|
+
extends
|
|
14
|
+
Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">,
|
|
15
|
+
SlopImageOptions {
|
|
16
|
+
loader?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const SlopImage: React.FC<SlopImageProps> = ({
|
|
20
|
+
bucketId,
|
|
21
|
+
className,
|
|
22
|
+
aspectRatio = "1:1",
|
|
23
|
+
version,
|
|
24
|
+
resultId,
|
|
25
|
+
model,
|
|
26
|
+
variables = {},
|
|
27
|
+
baseUrl,
|
|
28
|
+
loader,
|
|
29
|
+
...props
|
|
30
|
+
}) => {
|
|
31
|
+
// Construct API URL
|
|
32
|
+
const rawSrc = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
buildImageUrl({
|
|
35
|
+
bucketId,
|
|
36
|
+
aspectRatio,
|
|
37
|
+
version,
|
|
38
|
+
resultId,
|
|
39
|
+
variables,
|
|
40
|
+
baseUrl,
|
|
41
|
+
model,
|
|
42
|
+
}),
|
|
43
|
+
[bucketId, aspectRatio, version, resultId, variables, baseUrl, model],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const [src, setSrc] = useState(rawSrc);
|
|
47
|
+
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
const timer = setTimeout(() => {
|
|
50
|
+
setSrc(rawSrc);
|
|
51
|
+
}, 100);
|
|
52
|
+
return () => clearTimeout(timer);
|
|
53
|
+
}, [rawSrc]);
|
|
54
|
+
|
|
55
|
+
const alt = "Generated image";
|
|
56
|
+
|
|
57
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
58
|
+
const [currentSrc, setCurrentSrc] = useState(src);
|
|
59
|
+
|
|
60
|
+
if (src !== currentSrc) {
|
|
61
|
+
setCurrentSrc(src);
|
|
62
|
+
setIsLoading(true);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
React.useEffect(() => {
|
|
66
|
+
if (!src) return;
|
|
67
|
+
|
|
68
|
+
fetch(src, { method: "HEAD" })
|
|
69
|
+
.then(async (res) => {
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
// console.error(
|
|
72
|
+
// `Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`,
|
|
73
|
+
// );
|
|
74
|
+
try {
|
|
75
|
+
const errRes = await fetch(src);
|
|
76
|
+
const errJson = await errRes.json();
|
|
77
|
+
console.error("SlopImage error:", res.status, errJson.error);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
// Failed to fetch or parse error details
|
|
80
|
+
}
|
|
81
|
+
setIsLoading(false);
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.catch((err) => {
|
|
85
|
+
console.error(`Error fetching image from ${src}:`, err);
|
|
86
|
+
setIsLoading(false);
|
|
87
|
+
});
|
|
88
|
+
}, [src]);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<>
|
|
92
|
+
<style>{`
|
|
93
|
+
@keyframes slop-shimmer {
|
|
94
|
+
0% {
|
|
95
|
+
background-position: 200% 0;
|
|
96
|
+
}
|
|
97
|
+
100% {
|
|
98
|
+
background-position: -200% 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
@keyframes slop-spin {
|
|
102
|
+
from {
|
|
103
|
+
transform: rotate(0deg);
|
|
104
|
+
}
|
|
105
|
+
to {
|
|
106
|
+
transform: rotate(360deg);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
`}</style>
|
|
110
|
+
<div
|
|
111
|
+
className={cn("relative overflow-hidden", className)}
|
|
112
|
+
style={{
|
|
113
|
+
aspectRatio: String(aspectRatio).replace(":", "/"),
|
|
114
|
+
backgroundColor: "var(--muted, #f3f4f6)",
|
|
115
|
+
position: "relative",
|
|
116
|
+
overflow: "hidden",
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
{/* Loading UI */}
|
|
120
|
+
{loader ? (
|
|
121
|
+
<div
|
|
122
|
+
className={cn(
|
|
123
|
+
"absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300",
|
|
124
|
+
isLoading ? "opacity-100" : "opacity-0 pointer-events-none",
|
|
125
|
+
)}
|
|
126
|
+
style={{
|
|
127
|
+
position: "absolute",
|
|
128
|
+
top: 0,
|
|
129
|
+
left: 0,
|
|
130
|
+
right: 0,
|
|
131
|
+
bottom: 0,
|
|
132
|
+
zIndex: 10,
|
|
133
|
+
display: "flex",
|
|
134
|
+
alignItems: "center",
|
|
135
|
+
justifyContent: "center",
|
|
136
|
+
opacity: isLoading ? 1 : 0,
|
|
137
|
+
pointerEvents: isLoading ? "auto" : "none",
|
|
138
|
+
transition: "opacity 300ms ease-in-out",
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
{loader}
|
|
142
|
+
</div>
|
|
143
|
+
) : (
|
|
144
|
+
<>
|
|
145
|
+
{/* Loading overlay */}
|
|
146
|
+
<div
|
|
147
|
+
className={cn(
|
|
148
|
+
"absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
|
|
149
|
+
isLoading ? "opacity-100" : "opacity-0 pointer-events-none",
|
|
150
|
+
)}
|
|
151
|
+
style={{
|
|
152
|
+
position: "absolute",
|
|
153
|
+
top: 0,
|
|
154
|
+
left: 0,
|
|
155
|
+
right: 0,
|
|
156
|
+
bottom: 0,
|
|
157
|
+
zIndex: 10,
|
|
158
|
+
display: "flex",
|
|
159
|
+
alignItems: "center",
|
|
160
|
+
justifyContent: "center",
|
|
161
|
+
backgroundColor: "var(--muted, #f3f4f6)",
|
|
162
|
+
opacity: isLoading ? 1 : 0,
|
|
163
|
+
pointerEvents: isLoading ? "auto" : "none",
|
|
164
|
+
transition: "opacity 300ms ease-in-out",
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
<div
|
|
168
|
+
className="flex flex-col items-center gap-2"
|
|
169
|
+
style={{
|
|
170
|
+
display: "flex",
|
|
171
|
+
flexDirection: "column",
|
|
172
|
+
alignItems: "center",
|
|
173
|
+
gap: "0.5rem",
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
<svg
|
|
177
|
+
className="spinner size-6 text-muted-foreground"
|
|
178
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
179
|
+
fill="none"
|
|
180
|
+
viewBox="0 0 24 24"
|
|
181
|
+
style={{
|
|
182
|
+
width: "24px",
|
|
183
|
+
height: "24px",
|
|
184
|
+
color: "var(--muted-foreground, #6b7280)",
|
|
185
|
+
animation: "slop-spin 1s linear infinite",
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
<circle
|
|
189
|
+
className="opacity-25"
|
|
190
|
+
cx="12"
|
|
191
|
+
cy="12"
|
|
192
|
+
r="10"
|
|
193
|
+
stroke="currentColor"
|
|
194
|
+
strokeWidth="4"
|
|
195
|
+
style={{ opacity: 0.25 }}
|
|
196
|
+
/>
|
|
197
|
+
<path
|
|
198
|
+
className="opacity-75"
|
|
199
|
+
fill="currentColor"
|
|
200
|
+
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"
|
|
201
|
+
style={{ opacity: 0.75 }}
|
|
202
|
+
/>
|
|
203
|
+
</svg>
|
|
204
|
+
<span
|
|
205
|
+
className="text-xs text-muted-foreground"
|
|
206
|
+
style={{
|
|
207
|
+
fontSize: "0.75rem",
|
|
208
|
+
color: "var(--muted-foreground, #6b7280)",
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
Loading...
|
|
212
|
+
</span>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
{/* Shimmer effect underneath */}
|
|
217
|
+
<div
|
|
218
|
+
className={cn(
|
|
219
|
+
"shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
|
|
220
|
+
isLoading ? "opacity-100" : "opacity-0",
|
|
221
|
+
)}
|
|
222
|
+
style={{
|
|
223
|
+
position: "absolute",
|
|
224
|
+
top: 0,
|
|
225
|
+
left: 0,
|
|
226
|
+
right: 0,
|
|
227
|
+
bottom: 0,
|
|
228
|
+
background:
|
|
229
|
+
"linear-gradient(90deg, var(--muted, #f3f4f6) 0%, var(--muted-foreground, #e5e7eb) 50%, var(--muted, #f3f4f6) 100%)",
|
|
230
|
+
backgroundSize: "200% 100%",
|
|
231
|
+
animation: "slop-shimmer 2s ease-in-out infinite",
|
|
232
|
+
opacity: isLoading ? 1 : 0,
|
|
233
|
+
transition: "opacity 300ms",
|
|
234
|
+
}}
|
|
235
|
+
/>
|
|
236
|
+
</>
|
|
237
|
+
)}
|
|
238
|
+
|
|
239
|
+
{/* Image */}
|
|
240
|
+
<img
|
|
241
|
+
key={src}
|
|
242
|
+
src={src}
|
|
243
|
+
alt={alt}
|
|
244
|
+
onLoad={() => setIsLoading(false)}
|
|
245
|
+
onError={() => setIsLoading(false)}
|
|
246
|
+
className={cn(
|
|
247
|
+
"h-full w-full object-cover transition-opacity duration-500",
|
|
248
|
+
isLoading ? "opacity-0" : "opacity-100",
|
|
249
|
+
)}
|
|
250
|
+
style={{
|
|
251
|
+
height: "100%",
|
|
252
|
+
width: "100%",
|
|
253
|
+
objectFit: "cover",
|
|
254
|
+
transition: "opacity 500ms",
|
|
255
|
+
opacity: isLoading ? 0 : 1,
|
|
256
|
+
}}
|
|
257
|
+
{...props}
|
|
258
|
+
/>
|
|
259
|
+
</div>
|
|
260
|
+
</>
|
|
261
|
+
);
|
|
262
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SlopImage } from './components/SlopImage';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
"declaration": true,
|
|
24
|
+
"baseUrl": "."
|
|
25
|
+
},
|
|
26
|
+
"include": ["src"],
|
|
27
|
+
"exclude": ["node_modules", "dist"]
|
|
28
|
+
}
|