@marianmeres/stuic 3.26.2 → 3.28.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.
@@ -173,6 +173,9 @@
173
173
  import { ItemCollection } from "@marianmeres/item-collection";
174
174
  import { twMerge } from "../../utils/tw-merge.js";
175
175
  import { preloadImgs, type PreloadImgOptions } from "../../utils/preload-img.js";
176
+ import { createClog } from "@marianmeres/clog";
177
+
178
+ const clog = createClog("Book", { color: "auto" });
176
179
 
177
180
  let {
178
181
  pages,
@@ -291,7 +294,7 @@
291
294
  toPreload.push({ src: page.src, srcset: page.srcset, sizes: page.sizes });
292
295
  }
293
296
  }
294
- if (toPreload.length) preloadImgs(toPreload);
297
+ if (toPreload.length) preloadImgs(toPreload).catch(() => {});
295
298
  });
296
299
 
297
300
  // ---- Z-index: track currently transitioning sheet ----
@@ -457,6 +460,17 @@
457
460
  }
458
461
  }
459
462
 
463
+ export function goToPage(pageId: BookPage["id"]) {
464
+ const idx = spreads.findIndex(
465
+ (s) => s.leftPage?.id == pageId || s.rightPage?.id == pageId
466
+ );
467
+ if (idx < 0) {
468
+ clog.warn(`goToPage: page "${pageId}" not found`);
469
+ return;
470
+ }
471
+ goTo(idx);
472
+ }
473
+
460
474
  export function getCollection() {
461
475
  return coll;
462
476
  }
@@ -637,6 +651,19 @@
637
651
  const y = (e.clientY - rect.top) / rect.height;
638
652
  onPageClick({ page, x, y });
639
653
  }
654
+
655
+ // ---- Image error tracking ----
656
+
657
+ let erroredSrcs = $state(new Set<string>());
658
+
659
+ $effect(() => {
660
+ pages; // reset errors when pages change
661
+ erroredSrcs = new Set();
662
+ });
663
+
664
+ function handleImgError(src: string) {
665
+ erroredSrcs = new Set([...erroredSrcs, src]);
666
+ }
640
667
  </script>
641
668
 
642
669
  {#if spreads.length}
@@ -702,6 +729,10 @@
702
729
  ? "cover"
703
730
  : "right",
704
731
  })}
732
+ {:else if erroredSrcs.has(sheet.frontPage.src)}
733
+ <div class={!unstyled ? "stuic-book-page-error" : undefined}>
734
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/><line x1="2" y1="2" x2="22" y2="22"/></svg>
735
+ </div>
705
736
  {:else}
706
737
  <img
707
738
  src={sheet.frontPage.src}
@@ -709,6 +740,7 @@
709
740
  sizes={sheet.frontPage.sizes}
710
741
  alt={sheet.frontPage.title ?? ""}
711
742
  draggable="false"
743
+ onerror={() => handleImgError(sheet.frontPage!.src)}
712
744
  />
713
745
  {/if}
714
746
  {#if onAreaClick && Math.abs(sheet.id - activeSpread) <= 1 && sheet.frontPage.areas?.length && sheet.frontPage.width && sheet.frontPage.height}
@@ -752,6 +784,10 @@
752
784
  page: sheet.backPage,
753
785
  position: isSinglePageMode ? "right" : "left",
754
786
  })}
787
+ {:else if erroredSrcs.has(sheet.backPage.src)}
788
+ <div class={!unstyled ? "stuic-book-page-error" : undefined}>
789
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/><line x1="2" y1="2" x2="22" y2="22"/></svg>
790
+ </div>
755
791
  {:else}
756
792
  <img
757
793
  src={sheet.backPage.src}
@@ -759,6 +795,7 @@
759
795
  sizes={sheet.backPage.sizes}
760
796
  alt={sheet.backPage.title ?? ""}
761
797
  draggable="false"
798
+ onerror={() => handleImgError(sheet.backPage!.src)}
762
799
  />
763
800
  {/if}
764
801
  {#if onAreaClick && Math.abs(sheet.id - activeSpread) <= 1 && sheet.backPage.areas?.length && sheet.backPage.width && sheet.backPage.height}
@@ -118,6 +118,7 @@ declare const Book: import("svelte").Component<Props, {
118
118
  next: () => void;
119
119
  previous: () => void;
120
120
  goTo: (spreadIndex: number) => void;
121
+ goToPage: (pageId: BookPage["id"]) => void;
121
122
  getCollection: () => BookCollection;
122
123
  }, "el" | "activeSpread">;
123
124
  type Book = ReturnType<typeof Book>;
@@ -8,7 +8,6 @@
8
8
  --stuic-book-radius: var(--radius-sm, 2px);
9
9
  --stuic-book-page-width: 300px;
10
10
  --stuic-book-page-height: 400px;
11
- --stuic-book-placeholder-bg: color-mix(in srgb, currentColor 5%, transparent);
12
11
  }
13
12
 
14
13
  @layer components {
@@ -117,7 +116,23 @@
117
116
  /* Placeholder: empty page face with content on the other side */
118
117
  .stuic-book-sheet-front[data-placeholder],
119
118
  .stuic-book-sheet-back[data-placeholder] {
120
- background: var(--stuic-book-placeholder-bg);
119
+ background: var(--stuic-color-muted);
120
+ }
121
+
122
+ /* Error placeholder: broken image */
123
+ .stuic-book-page-error {
124
+ width: 100%;
125
+ height: 100%;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ background: var(--stuic-color-muted);
130
+ color: var(--stuic-color-muted-foreground);
131
+ }
132
+
133
+ .stuic-book-page-error svg {
134
+ width: 48px;
135
+ height: 48px;
121
136
  }
122
137
 
123
138
  /* Flipped state */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.26.2",
3
+ "version": "3.28.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",