@slopmachine/react 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,11 +1,87 @@
1
1
  // src/components/SlopImage.tsx
2
- import React, { useMemo, useState } from "react";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { clsx } from "clsx";
4
4
  import { twMerge } from "tailwind-merge";
5
5
  import {
6
- buildImageUrl
6
+ buildImageUrl,
7
+ createRenderUrlMonitor
7
8
  } from "@slopmachine/core";
8
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+
10
+ // src/components/ErrorOverlay.tsx
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ var overlayStyle = {
13
+ position: "absolute",
14
+ top: 0,
15
+ left: 0,
16
+ right: 0,
17
+ bottom: 0,
18
+ zIndex: 10,
19
+ display: "flex",
20
+ alignItems: "center",
21
+ justifyContent: "center"
22
+ };
23
+ var ErrorOverlay = ({
24
+ error,
25
+ errorFallback,
26
+ label
27
+ }) => {
28
+ if (errorFallback !== void 0) {
29
+ return /* @__PURE__ */ jsx(
30
+ "div",
31
+ {
32
+ className: "absolute inset-0 z-10 flex items-center justify-center",
33
+ style: overlayStyle,
34
+ children: typeof errorFallback === "function" ? errorFallback(error) : errorFallback
35
+ }
36
+ );
37
+ }
38
+ return /* @__PURE__ */ jsx(
39
+ "div",
40
+ {
41
+ className: "absolute inset-0 z-10 flex items-center justify-center bg-muted",
42
+ style: { ...overlayStyle, backgroundColor: "var(--muted, #f3f4f6)" },
43
+ title: error.message,
44
+ children: /* @__PURE__ */ jsxs(
45
+ "div",
46
+ {
47
+ className: "flex flex-col items-center gap-2 text-muted-foreground",
48
+ style: {
49
+ display: "flex",
50
+ flexDirection: "column",
51
+ alignItems: "center",
52
+ gap: "0.5rem",
53
+ color: "var(--muted-foreground, #6b7280)"
54
+ },
55
+ children: [
56
+ /* @__PURE__ */ jsxs(
57
+ "svg",
58
+ {
59
+ xmlns: "http://www.w3.org/2000/svg",
60
+ viewBox: "0 0 24 24",
61
+ fill: "none",
62
+ stroke: "currentColor",
63
+ strokeWidth: "2",
64
+ strokeLinecap: "round",
65
+ strokeLinejoin: "round",
66
+ "aria-hidden": "true",
67
+ style: { width: "24px", height: "24px" },
68
+ children: [
69
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
70
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
71
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
72
+ ]
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { fontSize: "0.75rem" }, children: label })
76
+ ]
77
+ }
78
+ )
79
+ }
80
+ );
81
+ };
82
+
83
+ // src/components/SlopImage.tsx
84
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
9
85
  function cn(...inputs) {
10
86
  return twMerge(clsx(inputs));
11
87
  }
@@ -25,6 +101,8 @@ var SlopImage = ({
25
101
  original,
26
102
  attachments,
27
103
  loader,
104
+ errorFallback,
105
+ onGenerationError,
28
106
  objectFit = "cover",
29
107
  imageClassName,
30
108
  style,
@@ -65,7 +143,7 @@ var SlopImage = ({
65
143
  ]
66
144
  );
67
145
  const [src, setSrc] = useState(rawSrc);
68
- React.useEffect(() => {
146
+ useEffect(() => {
69
147
  const timer = setTimeout(() => {
70
148
  setSrc(rawSrc);
71
149
  }, 100);
@@ -73,35 +151,33 @@ var SlopImage = ({
73
151
  }, [rawSrc]);
74
152
  const alt = "Image produced by Slop Machine (slopmachine.dev)";
75
153
  const [isLoading, setIsLoading] = useState(true);
154
+ const [error, setError] = useState(null);
76
155
  const [currentSrc, setCurrentSrc] = useState(src);
77
156
  if (src !== currentSrc) {
78
157
  setCurrentSrc(src);
79
158
  setIsLoading(true);
159
+ setError(null);
80
160
  }
81
- React.useEffect(() => {
82
- if (!src) return;
83
- fetch(src, { method: "HEAD" }).then(async (res) => {
84
- if (!res.ok) {
85
- let errorMessage = res.statusText;
86
- try {
87
- const errRes = await fetch(src);
88
- const errorText = await errRes.text();
89
- const errorData = JSON.parse(errorText);
90
- if (errorData.error) {
91
- errorMessage = errorData.error;
92
- }
93
- } catch (e) {
94
- }
95
- console.error("SlopImage error:", res.status, errorMessage);
96
- setIsLoading(false);
97
- }
98
- }).catch((err) => {
99
- console.error(`Error fetching image from ${src}:`, err);
161
+ const onGenerationErrorRef = useRef(onGenerationError);
162
+ useEffect(() => {
163
+ onGenerationErrorRef.current = onGenerationError;
164
+ });
165
+ const monitor = useMemo(
166
+ () => createRenderUrlMonitor((err) => {
167
+ console.error("SlopImage error:", err.status ?? "", err.message);
100
168
  setIsLoading(false);
101
- });
102
- }, [src]);
103
- return /* @__PURE__ */ jsxs(Fragment, { children: [
104
- /* @__PURE__ */ jsx("style", { children: `
169
+ setError(err);
170
+ onGenerationErrorRef.current?.(err);
171
+ }),
172
+ []
173
+ );
174
+ useEffect(() => {
175
+ if (!src) return;
176
+ monitor.watch(src);
177
+ return () => monitor.stop();
178
+ }, [src, monitor]);
179
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
180
+ /* @__PURE__ */ jsx2("style", { children: `
105
181
  @keyframes slop-shimmer {
106
182
  0% {
107
183
  background-position: 200% 0;
@@ -119,7 +195,7 @@ var SlopImage = ({
119
195
  }
120
196
  }
121
197
  ` }),
122
- /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsxs(
198
+ /* @__PURE__ */ jsx2("div", { className, style, children: /* @__PURE__ */ jsxs2(
123
199
  "div",
124
200
  {
125
201
  className: "slop-wrapper relative overflow-hidden w-full h-full",
@@ -131,7 +207,7 @@ var SlopImage = ({
131
207
  height: "100%"
132
208
  },
133
209
  children: [
134
- loader ? /* @__PURE__ */ jsx(
210
+ loader ? /* @__PURE__ */ jsx2(
135
211
  "div",
136
212
  {
137
213
  className: cn(
@@ -154,8 +230,8 @@ var SlopImage = ({
154
230
  },
155
231
  children: loader
156
232
  }
157
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
158
- /* @__PURE__ */ jsx(
233
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
234
+ /* @__PURE__ */ jsx2(
159
235
  "div",
160
236
  {
161
237
  className: cn(
@@ -177,7 +253,7 @@ var SlopImage = ({
177
253
  pointerEvents: isLoading ? "auto" : "none",
178
254
  transition: "opacity 300ms ease-in-out"
179
255
  },
180
- children: /* @__PURE__ */ jsxs(
256
+ children: /* @__PURE__ */ jsxs2(
181
257
  "div",
182
258
  {
183
259
  className: "flex flex-col items-center gap-2",
@@ -188,7 +264,7 @@ var SlopImage = ({
188
264
  gap: "0.5rem"
189
265
  },
190
266
  children: [
191
- /* @__PURE__ */ jsxs(
267
+ /* @__PURE__ */ jsxs2(
192
268
  "svg",
193
269
  {
194
270
  className: "spinner size-6 text-muted-foreground",
@@ -202,7 +278,7 @@ var SlopImage = ({
202
278
  animation: "slop-spin 1s linear infinite"
203
279
  },
204
280
  children: [
205
- /* @__PURE__ */ jsx(
281
+ /* @__PURE__ */ jsx2(
206
282
  "circle",
207
283
  {
208
284
  className: "opacity-25",
@@ -214,7 +290,7 @@ var SlopImage = ({
214
290
  style: { opacity: 0.25 }
215
291
  }
216
292
  ),
217
- /* @__PURE__ */ jsx(
293
+ /* @__PURE__ */ jsx2(
218
294
  "path",
219
295
  {
220
296
  className: "opacity-75",
@@ -226,7 +302,7 @@ var SlopImage = ({
226
302
  ]
227
303
  }
228
304
  ),
229
- /* @__PURE__ */ jsx(
305
+ /* @__PURE__ */ jsx2(
230
306
  "span",
231
307
  {
232
308
  className: "text-xs text-muted-foreground",
@@ -242,7 +318,7 @@ var SlopImage = ({
242
318
  )
243
319
  }
244
320
  ),
245
- /* @__PURE__ */ jsx(
321
+ /* @__PURE__ */ jsx2(
246
322
  "div",
247
323
  {
248
324
  className: cn(
@@ -264,7 +340,15 @@ var SlopImage = ({
264
340
  }
265
341
  )
266
342
  ] }),
267
- /* @__PURE__ */ jsx(
343
+ error && /* @__PURE__ */ jsx2(
344
+ ErrorOverlay,
345
+ {
346
+ error,
347
+ errorFallback,
348
+ label: "Failed to load image"
349
+ }
350
+ ),
351
+ /* @__PURE__ */ jsx2(
268
352
  "img",
269
353
  {
270
354
  src,
@@ -275,12 +359,13 @@ var SlopImage = ({
275
359
  onLoad?.(e);
276
360
  },
277
361
  onError: (e) => {
278
- setIsLoading(false);
362
+ monitor.mediaFailed(src, "Failed to load image");
279
363
  onError?.(e);
280
364
  },
365
+ "aria-hidden": error ? true : props["aria-hidden"],
281
366
  className: cn(
282
367
  "h-full w-full transition-opacity duration-500",
283
- isLoading ? "opacity-0" : "opacity-100",
368
+ isLoading || error ? "opacity-0" : "opacity-100",
284
369
  imageClassName
285
370
  ),
286
371
  style: {
@@ -288,7 +373,7 @@ var SlopImage = ({
288
373
  width: "100%",
289
374
  objectFit,
290
375
  transition: "opacity 500ms",
291
- opacity: isLoading ? 0 : 1
376
+ opacity: isLoading || error ? 0 : 1
292
377
  }
293
378
  },
294
379
  src
@@ -300,13 +385,14 @@ var SlopImage = ({
300
385
  };
301
386
 
302
387
  // src/components/SlopVideo.tsx
303
- import { useMemo as useMemo2, useState as useState2, useRef, useEffect } from "react";
388
+ import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
304
389
  import { clsx as clsx2 } from "clsx";
305
390
  import { twMerge as twMerge2 } from "tailwind-merge";
306
391
  import {
307
- buildVideoUrl
392
+ buildVideoUrl,
393
+ createRenderUrlMonitor as createRenderUrlMonitor2
308
394
  } from "@slopmachine/core";
309
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
395
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
310
396
  function cn2(...inputs) {
311
397
  return twMerge2(clsx2(inputs));
312
398
  }
@@ -326,6 +412,8 @@ var SlopVideo = ({
326
412
  original,
327
413
  attachments,
328
414
  loader,
415
+ errorFallback,
416
+ onGenerationError,
329
417
  autoPlay = true,
330
418
  loop = true,
331
419
  muted = true,
@@ -367,43 +455,41 @@ var SlopVideo = ({
367
455
  ]
368
456
  );
369
457
  const [src, setSrc] = useState2(rawSrc);
370
- useEffect(() => {
458
+ useEffect2(() => {
371
459
  const timer = setTimeout(() => {
372
460
  setSrc(rawSrc);
373
461
  }, 100);
374
462
  return () => clearTimeout(timer);
375
463
  }, [rawSrc]);
376
464
  const [isLoading, setIsLoading] = useState2(true);
465
+ const [error, setError] = useState2(null);
377
466
  const [currentSrc, setCurrentSrc] = useState2(src);
378
- const videoRef = useRef(null);
467
+ const videoRef = useRef2(null);
379
468
  if (src !== currentSrc) {
380
469
  setCurrentSrc(src);
381
470
  setIsLoading(true);
471
+ setError(null);
382
472
  }
383
- useEffect(() => {
384
- if (!src) return;
385
- fetch(src, { method: "HEAD" }).then(async (res) => {
386
- if (!res.ok) {
387
- let errorMessage = res.statusText;
388
- try {
389
- const errRes = await fetch(src);
390
- const errorText = await errRes.text();
391
- const errorData = JSON.parse(errorText);
392
- if (errorData.error) {
393
- errorMessage = errorData.error;
394
- }
395
- } catch (e) {
396
- }
397
- console.error("SlopVideo error:", res.status, errorMessage);
398
- setIsLoading(false);
399
- }
400
- }).catch((err) => {
401
- console.error(`Error fetching video from ${src}:`, err);
473
+ const onGenerationErrorRef = useRef2(onGenerationError);
474
+ useEffect2(() => {
475
+ onGenerationErrorRef.current = onGenerationError;
476
+ });
477
+ const monitor = useMemo2(
478
+ () => createRenderUrlMonitor2((err) => {
479
+ console.error("SlopVideo error:", err.status ?? "", err.message);
402
480
  setIsLoading(false);
403
- });
404
- }, [src]);
405
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
406
- /* @__PURE__ */ jsx2("style", { children: `
481
+ setError(err);
482
+ onGenerationErrorRef.current?.(err);
483
+ }),
484
+ []
485
+ );
486
+ useEffect2(() => {
487
+ if (!src) return;
488
+ monitor.watch(src);
489
+ return () => monitor.stop();
490
+ }, [src, monitor]);
491
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
492
+ /* @__PURE__ */ jsx3("style", { children: `
407
493
  @keyframes slop-shimmer {
408
494
  0% {
409
495
  background-position: 200% 0;
@@ -421,7 +507,7 @@ var SlopVideo = ({
421
507
  }
422
508
  }
423
509
  ` }),
424
- /* @__PURE__ */ jsx2("div", { className, style: props.style, children: /* @__PURE__ */ jsxs2(
510
+ /* @__PURE__ */ jsx3("div", { className, style: props.style, children: /* @__PURE__ */ jsxs3(
425
511
  "div",
426
512
  {
427
513
  className: "slop-wrapper relative overflow-hidden w-full h-full",
@@ -433,7 +519,7 @@ var SlopVideo = ({
433
519
  height: "100%"
434
520
  },
435
521
  children: [
436
- loader ? /* @__PURE__ */ jsx2(
522
+ loader ? /* @__PURE__ */ jsx3(
437
523
  "div",
438
524
  {
439
525
  className: cn2(
@@ -456,8 +542,8 @@ var SlopVideo = ({
456
542
  },
457
543
  children: loader
458
544
  }
459
- ) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
460
- /* @__PURE__ */ jsx2(
545
+ ) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
546
+ /* @__PURE__ */ jsx3(
461
547
  "div",
462
548
  {
463
549
  className: cn2(
@@ -479,7 +565,7 @@ var SlopVideo = ({
479
565
  pointerEvents: isLoading ? "auto" : "none",
480
566
  transition: "opacity 300ms ease-in-out"
481
567
  },
482
- children: /* @__PURE__ */ jsxs2(
568
+ children: /* @__PURE__ */ jsxs3(
483
569
  "div",
484
570
  {
485
571
  className: "flex flex-col items-center gap-2",
@@ -490,7 +576,7 @@ var SlopVideo = ({
490
576
  gap: "0.5rem"
491
577
  },
492
578
  children: [
493
- /* @__PURE__ */ jsxs2(
579
+ /* @__PURE__ */ jsxs3(
494
580
  "svg",
495
581
  {
496
582
  className: "spinner size-6 text-muted-foreground",
@@ -504,7 +590,7 @@ var SlopVideo = ({
504
590
  animation: "slop-spin 1s linear infinite"
505
591
  },
506
592
  children: [
507
- /* @__PURE__ */ jsx2(
593
+ /* @__PURE__ */ jsx3(
508
594
  "circle",
509
595
  {
510
596
  className: "opacity-25",
@@ -516,7 +602,7 @@ var SlopVideo = ({
516
602
  style: { opacity: 0.25 }
517
603
  }
518
604
  ),
519
- /* @__PURE__ */ jsx2(
605
+ /* @__PURE__ */ jsx3(
520
606
  "path",
521
607
  {
522
608
  className: "opacity-75",
@@ -528,7 +614,7 @@ var SlopVideo = ({
528
614
  ]
529
615
  }
530
616
  ),
531
- /* @__PURE__ */ jsx2(
617
+ /* @__PURE__ */ jsx3(
532
618
  "span",
533
619
  {
534
620
  className: "text-xs text-muted-foreground",
@@ -544,7 +630,7 @@ var SlopVideo = ({
544
630
  )
545
631
  }
546
632
  ),
547
- /* @__PURE__ */ jsx2(
633
+ /* @__PURE__ */ jsx3(
548
634
  "div",
549
635
  {
550
636
  className: cn2(
@@ -566,7 +652,15 @@ var SlopVideo = ({
566
652
  }
567
653
  )
568
654
  ] }),
569
- /* @__PURE__ */ jsx2(
655
+ error && /* @__PURE__ */ jsx3(
656
+ ErrorOverlay,
657
+ {
658
+ error,
659
+ errorFallback,
660
+ label: "Failed to load video"
661
+ }
662
+ ),
663
+ /* @__PURE__ */ jsx3(
570
664
  "video",
571
665
  {
572
666
  ref: videoRef,
@@ -581,19 +675,20 @@ var SlopVideo = ({
581
675
  onLoadedData?.(e);
582
676
  },
583
677
  onError: (e) => {
584
- setIsLoading(false);
678
+ monitor.mediaFailed(src, "Failed to load video");
585
679
  onError?.(e);
586
680
  },
681
+ "aria-hidden": error ? true : props["aria-hidden"],
587
682
  className: cn2(
588
683
  "h-full w-full object-cover transition-opacity duration-500",
589
- isLoading ? "opacity-0" : "opacity-100"
684
+ isLoading || error ? "opacity-0" : "opacity-100"
590
685
  ),
591
686
  style: {
592
687
  height: "100%",
593
688
  width: "100%",
594
689
  objectFit: "cover",
595
690
  transition: "opacity 500ms",
596
- opacity: isLoading ? 0 : 1
691
+ opacity: isLoading || error ? 0 : 1
597
692
  }
598
693
  },
599
694
  src
@@ -605,12 +700,12 @@ var SlopVideo = ({
605
700
  };
606
701
 
607
702
  // src/components/SlopText.tsx
608
- import React3, { useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
703
+ import React3, { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
609
704
  import {
610
705
  buildTextUrl,
611
706
  renderMarkdown
612
707
  } from "@slopmachine/core";
613
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
708
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
614
709
  var SlopText = React3.forwardRef(
615
710
  ({
616
711
  bucketId,
@@ -659,7 +754,7 @@ var SlopText = React3.forwardRef(
659
754
  JSON.stringify(attachments)
660
755
  ]
661
756
  );
662
- useEffect2(() => {
757
+ useEffect3(() => {
663
758
  let isMounted = true;
664
759
  const fetchText = async () => {
665
760
  try {
@@ -700,14 +795,14 @@ var SlopText = React3.forwardRef(
700
795
  };
701
796
  }, [rawUrl]);
702
797
  if (error && errorFallback) {
703
- return /* @__PURE__ */ jsx3(Fragment3, { children: errorFallback });
798
+ return /* @__PURE__ */ jsx4(Fragment3, { children: errorFallback });
704
799
  }
705
800
  if (loading) {
706
801
  if (fallback) {
707
- return /* @__PURE__ */ jsx3(Fragment3, { children: fallback });
802
+ return /* @__PURE__ */ jsx4(Fragment3, { children: fallback });
708
803
  }
709
- return /* @__PURE__ */ jsxs3("div", { className: props.className, style: props.style, children: [
710
- /* @__PURE__ */ jsx3("style", { children: `
804
+ return /* @__PURE__ */ jsxs4("div", { className: props.className, style: props.style, children: [
805
+ /* @__PURE__ */ jsx4("style", { children: `
711
806
  @keyframes slop-shimmer {
712
807
  0% { background-position: 200% 0; }
713
808
  100% { background-position: -200% 0; }
@@ -717,7 +812,7 @@ var SlopText = React3.forwardRef(
717
812
  to { transform: rotate(360deg); }
718
813
  }
719
814
  ` }),
720
- /* @__PURE__ */ jsxs3(
815
+ /* @__PURE__ */ jsxs4(
721
816
  "div",
722
817
  {
723
818
  className: "slop-wrapper relative overflow-hidden w-full",
@@ -728,7 +823,7 @@ var SlopText = React3.forwardRef(
728
823
  minHeight: "100px"
729
824
  },
730
825
  children: [
731
- /* @__PURE__ */ jsx3(
826
+ /* @__PURE__ */ jsx4(
732
827
  "div",
733
828
  {
734
829
  className: "absolute inset-0 z-10 flex items-center justify-center bg-muted transition-opacity duration-300",
@@ -744,7 +839,7 @@ var SlopText = React3.forwardRef(
744
839
  justifyContent: "center",
745
840
  backgroundColor: "var(--muted, #f3f4f6)"
746
841
  },
747
- children: /* @__PURE__ */ jsxs3(
842
+ children: /* @__PURE__ */ jsxs4(
748
843
  "div",
749
844
  {
750
845
  className: "flex flex-col items-center gap-2",
@@ -755,7 +850,7 @@ var SlopText = React3.forwardRef(
755
850
  gap: "0.5rem"
756
851
  },
757
852
  children: [
758
- /* @__PURE__ */ jsxs3(
853
+ /* @__PURE__ */ jsxs4(
759
854
  "svg",
760
855
  {
761
856
  className: "spinner size-6 text-muted-foreground",
@@ -769,7 +864,7 @@ var SlopText = React3.forwardRef(
769
864
  animation: "slop-spin 1s linear infinite"
770
865
  },
771
866
  children: [
772
- /* @__PURE__ */ jsx3(
867
+ /* @__PURE__ */ jsx4(
773
868
  "circle",
774
869
  {
775
870
  className: "opacity-25",
@@ -781,7 +876,7 @@ var SlopText = React3.forwardRef(
781
876
  style: { opacity: 0.25 }
782
877
  }
783
878
  ),
784
- /* @__PURE__ */ jsx3(
879
+ /* @__PURE__ */ jsx4(
785
880
  "path",
786
881
  {
787
882
  className: "opacity-75",
@@ -793,7 +888,7 @@ var SlopText = React3.forwardRef(
793
888
  ]
794
889
  }
795
890
  ),
796
- /* @__PURE__ */ jsx3(
891
+ /* @__PURE__ */ jsx4(
797
892
  "span",
798
893
  {
799
894
  className: "text-xs text-muted-foreground",
@@ -809,7 +904,7 @@ var SlopText = React3.forwardRef(
809
904
  )
810
905
  }
811
906
  ),
812
- /* @__PURE__ */ jsx3(
907
+ /* @__PURE__ */ jsx4(
813
908
  "div",
814
909
  {
815
910
  className: "shimmer-effect absolute inset-0 bg-gradient-to-r from-muted via-muted/50 to-muted",
@@ -830,7 +925,7 @@ var SlopText = React3.forwardRef(
830
925
  )
831
926
  ] });
832
927
  }
833
- return /* @__PURE__ */ jsx3(
928
+ return /* @__PURE__ */ jsx4(
834
929
  "div",
835
930
  {
836
931
  ref,
@@ -849,10 +944,12 @@ import {
849
944
  preloadImage,
850
945
  preloadVideo,
851
946
  preloadText,
852
- rateResult
947
+ rateResult,
948
+ SlopMachineError
853
949
  } from "@slopmachine/core";
854
950
  export {
855
951
  SlopImage,
952
+ SlopMachineError,
856
953
  SlopText,
857
954
  SlopVideo,
858
955
  preloadImage,