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