@canopy-iiif/app 0.8.6 → 0.9.1

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.
@@ -1,41 +1,8 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
9
5
  };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
- // If the importer is in node compatibility mode or this is not an ESM
20
- // file that has been converted to a CommonJS file using a Babel-
21
- // compatible transform (i.e. "__esModule" has not been set), then set
22
- // "default" to the CommonJS "module.exports" for node compatibility.
23
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
- mod
25
- ));
26
-
27
- // ui/src/iiif/hero-utils.js
28
- var require_hero_utils = __commonJS({
29
- "ui/src/iiif/hero-utils.js"(exports, module) {
30
- "use strict";
31
- function computeHeroHeightStyle2(height) {
32
- const h = typeof height === "number" ? `${height}px` : String(height || "").trim();
33
- const val = h || "360px";
34
- return { width: "100%", height: val };
35
- }
36
- module.exports = { computeHeroHeightStyle: computeHeroHeightStyle2 };
37
- }
38
- });
39
6
 
40
7
  // ui/src/HelloWorld.jsx
41
8
  import React from "react";
@@ -198,10 +165,25 @@ function MdxRelatedItems(props) {
198
165
  return /* @__PURE__ */ React5.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React5.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
199
166
  }
200
167
 
201
- // ui/src/iiif/Hero.jsx
202
- var import_hero_utils = __toESM(require_hero_utils());
168
+ // ui/src/interstitials/index.js
169
+ var interstitials_exports = {};
170
+ __export(interstitials_exports, {
171
+ Hero: () => Hero,
172
+ computeHeroHeightStyle: () => computeHeroHeightStyle
173
+ });
174
+
175
+ // ui/src/interstitials/Hero.jsx
203
176
  import React6 from "react";
204
177
  import helpers from "@canopy-iiif/app/lib/components/featured.js";
178
+
179
+ // ui/src/interstitials/hero-utils.js
180
+ function computeHeroHeightStyle(height) {
181
+ const h = typeof height === "number" ? `${height}px` : String(height || "").trim();
182
+ const val = h || "360px";
183
+ return { width: "100%", height: val };
184
+ }
185
+
186
+ // ui/src/interstitials/Hero.jsx
205
187
  var basePath = (() => {
206
188
  try {
207
189
  const raw = typeof process !== "undefined" && process && process.env ? String(process.env.CANOPY_BASE_PATH || "") : "";
@@ -221,68 +203,196 @@ function applyBasePath(href) {
221
203
  }
222
204
  return href;
223
205
  }
206
+ function resolveFeaturedItem({ item, index, random }) {
207
+ if (item) return item;
208
+ const list = helpers && helpers.readFeaturedFromCacheSync ? helpers.readFeaturedFromCacheSync() : [];
209
+ if (!list.length) return null;
210
+ if (typeof index === "number") {
211
+ const idx = Math.max(0, Math.min(list.length - 1, Math.floor(index)));
212
+ return list[idx];
213
+ }
214
+ if (random === true || random === "true") {
215
+ const idx = Math.floor(Math.random() * Math.max(1, list.length));
216
+ return list[idx];
217
+ }
218
+ return list[0];
219
+ }
220
+ function normalizeLinks(links) {
221
+ if (!Array.isArray(links)) return [];
222
+ return links.map((link) => {
223
+ if (!link) return null;
224
+ const href = applyBasePath(link.href || "");
225
+ const title = link.title ? String(link.title) : "";
226
+ if (!href || !title) return null;
227
+ const type = link.type === "secondary" ? "secondary" : "primary";
228
+ return { href, title, type };
229
+ }).filter(Boolean);
230
+ }
231
+ function sanitizeRest(rest) {
232
+ const clone = { ...rest };
233
+ try {
234
+ delete clone.random;
235
+ delete clone.index;
236
+ delete clone.item;
237
+ delete clone.links;
238
+ delete clone.overlay;
239
+ delete clone.variant;
240
+ delete clone.background;
241
+ } catch (_) {
242
+ }
243
+ return clone;
244
+ }
245
+ function normalizeBackground(value) {
246
+ try {
247
+ const allowed = /* @__PURE__ */ new Set(["theme", "transparent"]);
248
+ const raw = value == null ? "" : String(value);
249
+ const normalized = raw.trim().toLowerCase();
250
+ return allowed.has(normalized) ? normalized : "theme";
251
+ } catch (_) {
252
+ return "theme";
253
+ }
254
+ }
224
255
  function Hero({
225
- height = 360,
256
+ height = 520,
226
257
  item,
227
258
  index,
228
- random,
259
+ random = true,
260
+ headline,
261
+ description,
262
+ links = [],
229
263
  className = "",
230
264
  style = {},
265
+ background = "theme",
231
266
  ...rest
232
267
  }) {
233
- let resolved = item;
234
- if (!resolved) {
235
- const list = helpers && helpers.readFeaturedFromCacheSync ? helpers.readFeaturedFromCacheSync() : [];
236
- let idx = 0;
237
- if (typeof index === "number") {
238
- idx = Math.max(0, Math.min(list.length - 1, Math.floor(index)));
239
- } else if (random === true || random === "true") {
240
- idx = Math.floor(Math.random() * Math.max(1, list.length));
268
+ const resolved = resolveFeaturedItem({ item, index, random });
269
+ const helpersList = helpers && helpers.readFeaturedFromCacheSync ? helpers.readFeaturedFromCacheSync() : [];
270
+ const slides = [];
271
+ const pushUnique = (entry) => {
272
+ if (!entry) return;
273
+ const key = String(entry.href || entry.id || entry.title || "");
274
+ const hasKey = slides.some(
275
+ (item2) => String(item2 && (item2.href || item2.id || item2.title || "")) === key
276
+ );
277
+ if (!hasKey) {
278
+ slides.push(entry);
241
279
  }
242
- resolved = list[idx] || list[0] || null;
243
- }
244
- const hStyle = (0, import_hero_utils.computeHeroHeightStyle)(height);
245
- const title = resolved && resolved.title || "";
246
- const href = resolved && resolved.href || "#";
247
- const thumbnail = resolved && resolved.thumbnail || "";
248
- const mediaStyles = {
249
- position: "relative",
250
- ...hStyle,
251
- overflow: "hidden",
252
- backgroundColor: "var(--color-gray-muted)"
253
280
  };
254
- const imgStyles = {
255
- position: "absolute",
256
- inset: 0,
257
- width: "100%",
258
- height: "100%",
259
- objectFit: "cover",
260
- objectPosition: "center",
261
- filter: "none"
281
+ if (resolved) pushUnique(resolved);
282
+ helpersList.forEach(pushUnique);
283
+ if (!slides.length) return null;
284
+ let orderedSlides = slides.slice();
285
+ if (typeof index === "number" && orderedSlides.length > 1) {
286
+ const clamp = Math.max(
287
+ 0,
288
+ Math.min(orderedSlides.length - 1, Math.floor(index))
289
+ );
290
+ if (clamp > 0) {
291
+ orderedSlides = orderedSlides.slice(clamp).concat(orderedSlides.slice(0, clamp));
292
+ }
293
+ } else if (random === true || random === "true") {
294
+ const rand = Math.floor(Math.random() * orderedSlides.length);
295
+ if (rand > 0) {
296
+ orderedSlides = orderedSlides.slice(rand).concat(orderedSlides.slice(0, rand));
297
+ }
298
+ }
299
+ const heroHeight = computeHeroHeightStyle(height);
300
+ const heroStyles = { ...style || {} };
301
+ if (heroHeight && heroHeight.height) {
302
+ heroStyles["--hero-height"] = heroHeight.height;
303
+ }
304
+ const derivedDescription = description ? String(description) : "";
305
+ const normalizedLinks = normalizeLinks(links);
306
+ const primarySlide = orderedSlides[0] || null;
307
+ const overlayTitle = headline || primarySlide && primarySlide.title || "";
308
+ const defaultLinkHref = applyBasePath(
309
+ primarySlide && primarySlide.href ? primarySlide.href : "#"
310
+ );
311
+ const overlayLinks = normalizedLinks.length ? normalizedLinks : [
312
+ {
313
+ href: defaultLinkHref,
314
+ title: "View work",
315
+ type: "primary"
316
+ }
317
+ ];
318
+ const normalizedBackground = normalizeBackground(background);
319
+ const backgroundClassName = normalizedBackground === "transparent" ? "canopy-interstitial--bg-transparent" : "";
320
+ const containerClassName = [
321
+ "canopy-interstitial",
322
+ "canopy-interstitial--hero",
323
+ backgroundClassName,
324
+ className
325
+ ].filter(Boolean).join(" ");
326
+ const renderSlide = (slide, idx, { showVeil = true, captionVariant = "overlay" } = {}) => {
327
+ const safeHref = applyBasePath(slide.href || "#");
328
+ const isStaticCaption = captionVariant === "static";
329
+ const paneClassName = [
330
+ "canopy-interstitial__pane",
331
+ showVeil ? "" : "canopy-interstitial__pane--flat",
332
+ isStaticCaption ? "canopy-interstitial__pane--static" : ""
333
+ ].filter(Boolean).join(" ");
334
+ if (isStaticCaption) {
335
+ return /* @__PURE__ */ React6.createElement("div", { className: "swiper-slide", key: safeHref || idx }, /* @__PURE__ */ React6.createElement("article", { className: paneClassName }, slide.thumbnail ? /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__media-frame" }, /* @__PURE__ */ React6.createElement(
336
+ "img",
337
+ {
338
+ src: slide.thumbnail,
339
+ alt: "",
340
+ "aria-hidden": "true",
341
+ className: "canopy-interstitial__media canopy-interstitial__media--static",
342
+ loading: idx === 0 ? "eager" : "lazy"
343
+ }
344
+ )) : null, slide.title ? /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__caption canopy-interstitial__caption--static" }, /* @__PURE__ */ React6.createElement("a", { href: safeHref, className: "canopy-interstitial__caption-link" }, slide.title)) : null));
345
+ }
346
+ return /* @__PURE__ */ React6.createElement("div", { className: "swiper-slide", key: safeHref || idx }, /* @__PURE__ */ React6.createElement("article", { className: paneClassName }, slide.thumbnail ? /* @__PURE__ */ React6.createElement(
347
+ "img",
348
+ {
349
+ src: slide.thumbnail,
350
+ alt: "",
351
+ "aria-hidden": "true",
352
+ className: "canopy-interstitial__media",
353
+ loading: idx === 0 ? "eager" : "lazy"
354
+ }
355
+ ) : null, showVeil ? /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__veil", "aria-hidden": "true" }) : null, slide.title ? /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__caption" }, /* @__PURE__ */ React6.createElement("a", { href: safeHref, className: "canopy-interstitial__caption-link" }, slide.title)) : null));
262
356
  };
263
- const sanitizedRest = (() => {
264
- const r = { ...rest };
265
- try {
266
- delete r.random;
267
- delete r.index;
268
- } catch (_) {
357
+ const renderSlider = (options = {}) => /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__slider swiper" }, /* @__PURE__ */ React6.createElement("div", { className: "swiper-wrapper" }, orderedSlides.map((slide, idx) => renderSlide(slide, idx, options))), /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__nav" }, /* @__PURE__ */ React6.createElement(
358
+ "button",
359
+ {
360
+ type: "button",
361
+ "aria-label": "Previous slide",
362
+ className: "canopy-interstitial__nav-btn canopy-interstitial__nav-btn--prev swiper-button-prev"
269
363
  }
270
- return r;
271
- })();
272
- const figureClassName = ["canopy-hero", className].filter(Boolean).join(" ");
273
- const figureStyles = { margin: 0, padding: 0, ...style };
274
- const safeHref = applyBasePath(href);
275
- return /* @__PURE__ */ React6.createElement("a", { href: safeHref, className: "canopy-hero-link" }, /* @__PURE__ */ React6.createElement("figure", { className: figureClassName, style: figureStyles, ...sanitizedRest }, /* @__PURE__ */ React6.createElement("div", { className: "canopy-hero__media", style: mediaStyles }, thumbnail ? /* @__PURE__ */ React6.createElement("img", { src: thumbnail, alt: "", "aria-hidden": "true", style: imgStyles }) : null), title ? /* @__PURE__ */ React6.createElement("figcaption", null, title) : null));
276
- }
277
-
278
- // ui/src/iiif/FeaturedHero.jsx
279
- import React7 from "react";
280
- function FeaturedHero(props = {}) {
281
- return /* @__PURE__ */ React7.createElement(Hero, { ...props });
364
+ ), /* @__PURE__ */ React6.createElement(
365
+ "button",
366
+ {
367
+ type: "button",
368
+ "aria-label": "Next slide",
369
+ className: "canopy-interstitial__nav-btn canopy-interstitial__nav-btn--next swiper-button-next"
370
+ }
371
+ )), /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__pagination swiper-pagination" }));
372
+ const overlayContent = /* @__PURE__ */ React6.createElement(React6.Fragment, null, overlayTitle ? /* @__PURE__ */ React6.createElement("h1", { className: "canopy-interstitial__headline" }, overlayTitle) : null, derivedDescription ? /* @__PURE__ */ React6.createElement("p", { className: "canopy-interstitial__description" }, derivedDescription) : null, overlayLinks.length ? /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__actions" }, overlayLinks.map((link) => /* @__PURE__ */ React6.createElement(
373
+ "a",
374
+ {
375
+ key: `${link.href}-${link.title}`,
376
+ href: link.href,
377
+ className: link.type === "secondary" ? "canopy-button canopy-button--secondary" : "canopy-button canopy-button--primary"
378
+ },
379
+ link.title
380
+ ))) : null);
381
+ const cleanedProps = sanitizeRest(rest);
382
+ return /* @__PURE__ */ React6.createElement(
383
+ "section",
384
+ {
385
+ className: containerClassName,
386
+ "data-canopy-hero-slider": "1",
387
+ style: heroStyles,
388
+ ...cleanedProps
389
+ },
390
+ /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__layout" }, /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__body" }, overlayContent)), /* @__PURE__ */ React6.createElement("div", { className: "canopy-interstitial__media-group" }, renderSlider({ showVeil: false, captionVariant: "static" })))
391
+ );
282
392
  }
283
393
 
284
394
  // ui/src/layout/SubNavigation.jsx
285
- import React8 from "react";
395
+ import React7 from "react";
286
396
  import navigationHelpers from "@canopy-iiif/app/lib/components/navigation.js";
287
397
  function resolveRelativeCandidate(page, current) {
288
398
  if (page && typeof page.relativePath === "string" && page.relativePath) return page.relativePath;
@@ -307,14 +417,14 @@ function renderNodes(nodes, parentKey = "node") {
307
417
  if (node.isActive) classes.push("is-active");
308
418
  const linkClass = classes.join(" ");
309
419
  const Tag = node.href ? "a" : "span";
310
- return /* @__PURE__ */ React8.createElement(
420
+ return /* @__PURE__ */ React7.createElement(
311
421
  "li",
312
422
  {
313
423
  key,
314
424
  className: "canopy-sub-navigation__item",
315
425
  "data-depth": depth
316
426
  },
317
- /* @__PURE__ */ React8.createElement(
427
+ /* @__PURE__ */ React7.createElement(
318
428
  Tag,
319
429
  {
320
430
  className: linkClass,
@@ -323,7 +433,7 @@ function renderNodes(nodes, parentKey = "node") {
323
433
  },
324
434
  node.title || node.slug
325
435
  ),
326
- showChildren ? /* @__PURE__ */ React8.createElement("ul", { className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested", role: "list" }, renderNodes(node.children, key)) : null
436
+ showChildren ? /* @__PURE__ */ React7.createElement("ul", { className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested", role: "list" }, renderNodes(node.children, key)) : null
327
437
  );
328
438
  });
329
439
  }
@@ -337,12 +447,12 @@ function SubNavigation({
337
447
  ariaLabel
338
448
  }) {
339
449
  const PageContext = navigationHelpers && navigationHelpers.getPageContext ? navigationHelpers.getPageContext() : null;
340
- const context = PageContext ? React8.useContext(PageContext) : null;
450
+ const context = PageContext ? React7.useContext(PageContext) : null;
341
451
  const contextNavigation = context && context.navigation ? context.navigation : null;
342
452
  const contextPage = context && context.page ? context.page : null;
343
453
  const effectiveNavigation = navigationProp || contextNavigation;
344
454
  const effectivePage = page || contextPage;
345
- const resolvedNavigation = React8.useMemo(() => {
455
+ const resolvedNavigation = React7.useMemo(() => {
346
456
  if (effectiveNavigation && effectiveNavigation.root) return effectiveNavigation;
347
457
  const candidate = resolveRelativeCandidate(effectivePage, current);
348
458
  if (!candidate) return effectiveNavigation || null;
@@ -366,11 +476,341 @@ function SubNavigation({
366
476
  if (!Object.prototype.hasOwnProperty.call(inlineStyle, "--sub-nav-indent")) {
367
477
  inlineStyle["--sub-nav-indent"] = "0.85rem";
368
478
  }
369
- return /* @__PURE__ */ React8.createElement("nav", { className: combinedClassName, style: inlineStyle, "aria-label": navLabel }, finalHeading ? /* @__PURE__ */ React8.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null, /* @__PURE__ */ React8.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root")));
479
+ return /* @__PURE__ */ React7.createElement("nav", { className: combinedClassName, style: inlineStyle, "aria-label": navLabel }, finalHeading ? /* @__PURE__ */ React7.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null, /* @__PURE__ */ React7.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root")));
370
480
  }
371
481
 
372
- // ui/src/search/MdxSearchResults.jsx
482
+ // ui/src/layout/Layout.jsx
373
483
  import React9 from "react";
484
+ import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
485
+
486
+ // ui/src/layout/ContentNavigation.jsx
487
+ import React8 from "react";
488
+ var SCROLL_OFFSET_REM = 1.618;
489
+ function depthIndex(depth) {
490
+ return Math.max(0, Math.min(5, (depth || 1) - 1));
491
+ }
492
+ function ContentNavigation({
493
+ items = [],
494
+ className = "",
495
+ style = {},
496
+ heading,
497
+ headingId,
498
+ pageTitle,
499
+ ariaLabel
500
+ }) {
501
+ const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
502
+ const savedDepthsRef = React8.useRef(null);
503
+ if ((!items || !items.length) && !headingId) return null;
504
+ const combinedClassName = ["canopy-sub-navigation canopy-content-navigation", className].filter(Boolean).join(" ");
505
+ const effectiveHeading = heading || pageTitle || null;
506
+ const navLabel = ariaLabel || (effectiveHeading ? `${effectiveHeading} navigation` : "Section navigation");
507
+ const getSavedDepth = React8.useCallback(
508
+ (id, fallback) => {
509
+ if (!id) return fallback;
510
+ if (!savedDepthsRef.current) savedDepthsRef.current = /* @__PURE__ */ new Map();
511
+ const store = savedDepthsRef.current;
512
+ if (store.has(id)) return store.get(id);
513
+ store.set(id, fallback);
514
+ return fallback;
515
+ },
516
+ []
517
+ );
518
+ const headingEntries = React8.useMemo(() => {
519
+ const entries = [];
520
+ const seen = /* @__PURE__ */ new Set();
521
+ if (headingId) {
522
+ const topId = String(headingId);
523
+ entries.push({ id: topId, depth: 1 });
524
+ seen.add(topId);
525
+ }
526
+ const pushNodes = (nodes) => {
527
+ if (!Array.isArray(nodes)) return;
528
+ nodes.forEach((node) => {
529
+ if (!node || !node.id) return;
530
+ const id = String(node.id);
531
+ if (seen.has(id)) return;
532
+ seen.add(id);
533
+ const depth = node.depth || node.level || getSavedDepth(id, 2);
534
+ entries.push({ id, depth });
535
+ if (node.children && node.children.length) pushNodes(node.children);
536
+ });
537
+ };
538
+ pushNodes(items);
539
+ return entries;
540
+ }, [headingId, items, getSavedDepth]);
541
+ const fallbackId = headingEntries.length ? headingEntries[0].id : headingId || null;
542
+ const [activeId, setActiveId] = React8.useState(fallbackId);
543
+ const activeIdRef = React8.useRef(activeId);
544
+ React8.useEffect(() => {
545
+ activeIdRef.current = activeId;
546
+ }, [activeId]);
547
+ React8.useEffect(() => {
548
+ if (!headingEntries.length) return;
549
+ if (!headingEntries.some((entry) => entry.id === activeIdRef.current)) {
550
+ const next = headingEntries[0].id;
551
+ activeIdRef.current = next;
552
+ setActiveId(next);
553
+ }
554
+ }, [headingEntries]);
555
+ const computeOffsetPx = React8.useCallback(() => {
556
+ if (!isBrowser) return 0;
557
+ try {
558
+ const root = document.documentElement;
559
+ const fontSize = root ? parseFloat(window.getComputedStyle(root).fontSize || "16") || 16 : 16;
560
+ return fontSize * SCROLL_OFFSET_REM;
561
+ } catch (_) {
562
+ return 0;
563
+ }
564
+ }, [isBrowser]);
565
+ const headingElementsRef = React8.useRef([]);
566
+ const updateActiveFromElements = React8.useCallback(
567
+ (elements) => {
568
+ if (!elements || !elements.length) return;
569
+ const offset = computeOffsetPx();
570
+ let nextId = elements[0].id;
571
+ for (const { id, element } of elements) {
572
+ const rect = element.getBoundingClientRect();
573
+ if (rect.top - offset <= 0) {
574
+ nextId = id;
575
+ } else {
576
+ break;
577
+ }
578
+ }
579
+ if (nextId && nextId !== activeIdRef.current) {
580
+ activeIdRef.current = nextId;
581
+ setActiveId(nextId);
582
+ }
583
+ },
584
+ [computeOffsetPx]
585
+ );
586
+ React8.useEffect(() => {
587
+ if (!isBrowser) return void 0;
588
+ const elements = headingEntries.map((entry) => {
589
+ const element = document.getElementById(entry.id);
590
+ return element ? { id: entry.id, element } : null;
591
+ }).filter(Boolean);
592
+ headingElementsRef.current = elements;
593
+ updateActiveFromElements(elements);
594
+ if (!elements.length) return void 0;
595
+ let ticking = false;
596
+ const handle = () => {
597
+ if (!ticking) {
598
+ ticking = true;
599
+ window.requestAnimationFrame(() => {
600
+ updateActiveFromElements(elements);
601
+ ticking = false;
602
+ });
603
+ }
604
+ };
605
+ window.addEventListener("scroll", handle, { passive: true });
606
+ window.addEventListener("resize", handle);
607
+ return () => {
608
+ window.removeEventListener("scroll", handle);
609
+ window.removeEventListener("resize", handle);
610
+ };
611
+ }, [headingEntries, isBrowser, updateActiveFromElements]);
612
+ const handleAnchorClick = React8.useCallback(
613
+ (event, targetId, options = {}) => {
614
+ var _a;
615
+ try {
616
+ if (event && typeof event.preventDefault === "function") event.preventDefault();
617
+ } catch (_) {
618
+ }
619
+ if (!isBrowser) return;
620
+ const offset = computeOffsetPx();
621
+ let top = 0;
622
+ if (targetId && targetId !== "top" && !options.scrollToTop) {
623
+ const el = document.getElementById(targetId);
624
+ if (el) {
625
+ const rect = el.getBoundingClientRect();
626
+ top = window.scrollY + rect.top - offset;
627
+ }
628
+ }
629
+ if (!Number.isFinite(top) || top < 0 || options.scrollToTop) top = 0;
630
+ const nextId = targetId && targetId !== "top" ? targetId : ((_a = headingEntries[0]) == null ? void 0 : _a.id) || headingId || null;
631
+ if (nextId) {
632
+ activeIdRef.current = nextId;
633
+ setActiveId(nextId);
634
+ }
635
+ try {
636
+ window.scrollTo({ top, behavior: "smooth" });
637
+ } catch (_) {
638
+ window.scrollTo(0, top);
639
+ }
640
+ },
641
+ [computeOffsetPx, headingEntries, headingId, isBrowser]
642
+ );
643
+ const renderNodes2 = React8.useCallback(
644
+ (nodes) => {
645
+ if (!nodes || !nodes.length) return null;
646
+ return nodes.map((node) => {
647
+ if (!node) return null;
648
+ const id = node.id ? String(node.id) : "";
649
+ const depth = node.depth || node.level || getSavedDepth(id, 2);
650
+ const idx = depthIndex(depth);
651
+ const isActive = id && activeId === id;
652
+ return /* @__PURE__ */ React8.createElement("li", { key: id || node.title, className: "canopy-sub-navigation__item", "data-depth": idx }, /* @__PURE__ */ React8.createElement(
653
+ "a",
654
+ {
655
+ className: `canopy-sub-navigation__link depth-${idx}${isActive ? " is-active" : ""}`,
656
+ href: id ? `#${id}` : "#",
657
+ onClick: (event) => handleAnchorClick(event, id || null),
658
+ "aria-current": isActive ? "location" : void 0
659
+ },
660
+ node.title
661
+ ), node.children && node.children.length ? /* @__PURE__ */ React8.createElement(
662
+ "ul",
663
+ {
664
+ className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
665
+ role: "list"
666
+ },
667
+ renderNodes2(node.children)
668
+ ) : null);
669
+ });
670
+ },
671
+ [handleAnchorClick, activeId, getSavedDepth]
672
+ );
673
+ const nestedItems = renderNodes2(items);
674
+ const topLink = headingId ? /* @__PURE__ */ React8.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React8.createElement(
675
+ "a",
676
+ {
677
+ className: `canopy-sub-navigation__link depth-0${activeId === headingId ? " is-active" : ""}`,
678
+ href: `#${headingId}`,
679
+ onClick: (event) => handleAnchorClick(event, headingId, { scrollToTop: true }),
680
+ "aria-current": activeId === headingId ? "location" : void 0
681
+ },
682
+ effectiveHeading || pageTitle || headingId
683
+ ), nestedItems ? /* @__PURE__ */ React8.createElement(
684
+ "ul",
685
+ {
686
+ className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
687
+ role: "list"
688
+ },
689
+ nestedItems
690
+ ) : null) : null;
691
+ return /* @__PURE__ */ React8.createElement("nav", { className: combinedClassName, style, "aria-label": navLabel }, /* @__PURE__ */ React8.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, topLink || nestedItems));
692
+ }
693
+
694
+ // ui/src/layout/Layout.jsx
695
+ function buildHeadingTree(headings) {
696
+ if (!Array.isArray(headings) || !headings.length) return [];
697
+ const root = [];
698
+ const stack = [];
699
+ headings.forEach((heading) => {
700
+ if (!heading || typeof heading !== "object") return;
701
+ const depth = typeof heading.depth === "number" ? heading.depth : heading.level;
702
+ if (typeof depth !== "number" || depth < 2) return;
703
+ const entry = {
704
+ id: heading.id || heading.slug || heading.title,
705
+ title: heading.title || heading.text || heading.id,
706
+ depth,
707
+ children: []
708
+ };
709
+ while (stack.length && stack[stack.length - 1].depth >= entry.depth) {
710
+ stack.pop();
711
+ }
712
+ if (!stack.length) {
713
+ root.push(entry);
714
+ } else {
715
+ stack[stack.length - 1].children.push(entry);
716
+ }
717
+ stack.push(entry);
718
+ });
719
+ return root;
720
+ }
721
+ function buildNavigationAside(sidebar, className) {
722
+ if (!sidebar) {
723
+ return /* @__PURE__ */ React9.createElement(SubNavigation, { className });
724
+ }
725
+ if (typeof sidebar === "function") {
726
+ return React9.createElement(sidebar);
727
+ }
728
+ return sidebar;
729
+ }
730
+ function Layout({
731
+ children,
732
+ sidebar,
733
+ navigation = true,
734
+ fluid = false,
735
+ contentNavigation = true,
736
+ className = "",
737
+ contentClassName = "",
738
+ sidebarClassName = "",
739
+ contentNavigationClassName = "",
740
+ ...rest
741
+ }) {
742
+ const PageContext = navigationHelpers2 && typeof navigationHelpers2.getPageContext === "function" ? navigationHelpers2.getPageContext() : null;
743
+ const context = PageContext ? React9.useContext(PageContext) : null;
744
+ const pageHeadings = React9.useMemo(() => {
745
+ const headings = context && context.page ? context.page.headings : null;
746
+ return Array.isArray(headings) ? headings : [];
747
+ }, [context]);
748
+ const contentHeading = React9.useMemo(() => {
749
+ const first = pageHeadings.find((heading) => {
750
+ const depth = heading && (heading.depth || heading.level);
751
+ return depth === 1;
752
+ });
753
+ return first && first.title ? first.title : null;
754
+ }, [pageHeadings]);
755
+ const headingAnchorId = React9.useMemo(() => {
756
+ const first = pageHeadings.find((heading) => {
757
+ const depth = heading && (heading.depth || heading.level);
758
+ return depth === 1;
759
+ });
760
+ return first && first.id ? first.id : null;
761
+ }, [pageHeadings]);
762
+ const headingTree = React9.useMemo(
763
+ () => buildHeadingTree(pageHeadings),
764
+ [pageHeadings]
765
+ );
766
+ const showLeftColumn = navigation !== false;
767
+ const hasContentNavigation = navigation !== false && contentNavigation !== false && headingTree.length > 0;
768
+ const gridClass = (() => {
769
+ if (showLeftColumn && hasContentNavigation) {
770
+ return "md:grid md:grid-cols-[17rem_minmax(0,1fr)_14rem] md:items-start md:gap-10";
771
+ }
772
+ if (showLeftColumn) {
773
+ return "md:grid md:grid-cols-[17rem_minmax(0,1fr)] md:items-start md:gap-10";
774
+ }
775
+ if (hasContentNavigation) {
776
+ return "md:grid md:grid-cols-[minmax(0,1fr)_14rem] md:items-start md:gap-10";
777
+ }
778
+ return "";
779
+ })();
780
+ const containerClassName = [
781
+ "w-full py-6 getting-started-layout",
782
+ gridClass,
783
+ fluid ? "px-4 md:px-8 lg:px-12" : "mx-auto max-w-content px-4",
784
+ className
785
+ ].filter(Boolean).join(" ");
786
+ const leftAsideClassName = [
787
+ "mt-8 md:mt-0 md:order-1 md:sticky md:top-24 md:max-h-[calc(100vh-6rem)] md:overflow-y-auto text-sm text-slate-600",
788
+ sidebarClassName
789
+ ].filter(Boolean).join(" ");
790
+ const contentOrderClass = showLeftColumn ? "md:order-2" : hasContentNavigation ? "md:order-1" : "";
791
+ const contentClassNames = [
792
+ "space-y-6",
793
+ contentOrderClass,
794
+ contentClassName
795
+ ].filter(Boolean).join(" ");
796
+ const contentNavigationAsideClassName = [
797
+ "hidden md:block md:order-3 mt-8 md:mt-0 md:sticky md:top-24 md:max-h-[calc(100vh-6rem)] md:overflow-y-auto text-sm text-slate-600",
798
+ contentNavigationClassName
799
+ ].filter(Boolean).join(" ");
800
+ const sidebarNode = showLeftColumn ? buildNavigationAside(sidebar, sidebarClassName) : null;
801
+ return /* @__PURE__ */ React9.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React9.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React9.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React9.createElement("aside", { className: contentNavigationAsideClassName }, /* @__PURE__ */ React9.createElement(
802
+ ContentNavigation,
803
+ {
804
+ items: headingTree,
805
+ heading: contentHeading || void 0,
806
+ headingId: headingAnchorId || void 0,
807
+ pageTitle: context && context.page ? context.page.title : void 0
808
+ }
809
+ )) : null);
810
+ }
811
+
812
+ // ui/src/search/MdxSearchResults.jsx
813
+ import React10 from "react";
374
814
  function MdxSearchResults(props) {
375
815
  let json = "{}";
376
816
  try {
@@ -378,11 +818,11 @@ function MdxSearchResults(props) {
378
818
  } catch (_) {
379
819
  json = "{}";
380
820
  }
381
- return /* @__PURE__ */ React9.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React9.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
821
+ return /* @__PURE__ */ React10.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React10.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
382
822
  }
383
823
 
384
824
  // ui/src/search/SearchSummary.jsx
385
- import React10 from "react";
825
+ import React11 from "react";
386
826
  function SearchSummary(props) {
387
827
  let json = "{}";
388
828
  try {
@@ -390,11 +830,11 @@ function SearchSummary(props) {
390
830
  } catch (_) {
391
831
  json = "{}";
392
832
  }
393
- return /* @__PURE__ */ React10.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React10.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
833
+ return /* @__PURE__ */ React11.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React11.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
394
834
  }
395
835
 
396
836
  // ui/src/search/MdxSearchTabs.jsx
397
- import React11 from "react";
837
+ import React12 from "react";
398
838
  function MdxSearchTabs(props) {
399
839
  let json = "{}";
400
840
  try {
@@ -402,18 +842,18 @@ function MdxSearchTabs(props) {
402
842
  } catch (_) {
403
843
  json = "{}";
404
844
  }
405
- return /* @__PURE__ */ React11.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React11.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
845
+ return /* @__PURE__ */ React12.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React12.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
406
846
  }
407
847
 
408
848
  // ui/src/search-form/MdxSearchFormModal.jsx
409
- import React15 from "react";
849
+ import React16 from "react";
410
850
 
411
851
  // ui/src/Icons.jsx
412
- import React12 from "react";
413
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React12.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React12.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
852
+ import React13 from "react";
853
+ var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React13.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React13.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
414
854
 
415
855
  // ui/src/search/SearchPanelForm.jsx
416
- import React13 from "react";
856
+ import React14 from "react";
417
857
  function readBasePath() {
418
858
  const normalize = (val) => {
419
859
  const raw = typeof val === "string" ? val.trim() : "";
@@ -476,18 +916,18 @@ function SearchPanelForm(props = {}) {
476
916
  clearLabel = "Clear search"
477
917
  } = props || {};
478
918
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
479
- const action = React13.useMemo(
919
+ const action = React14.useMemo(
480
920
  () => resolveSearchPath(searchPath),
481
921
  [searchPath]
482
922
  );
483
- const autoId = typeof React13.useId === "function" ? React13.useId() : void 0;
484
- const [fallbackId] = React13.useState(
923
+ const autoId = typeof React14.useId === "function" ? React14.useId() : void 0;
924
+ const [fallbackId] = React14.useState(
485
925
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
486
926
  );
487
927
  const inputId = inputIdProp || autoId || fallbackId;
488
- const inputRef = React13.useRef(null);
489
- const [hasValue, setHasValue] = React13.useState(false);
490
- const focusInput = React13.useCallback(() => {
928
+ const inputRef = React14.useRef(null);
929
+ const [hasValue, setHasValue] = React14.useState(false);
930
+ const focusInput = React14.useCallback(() => {
491
931
  const el = inputRef.current;
492
932
  if (!el) return;
493
933
  if (document.activeElement === el) return;
@@ -500,7 +940,7 @@ function SearchPanelForm(props = {}) {
500
940
  }
501
941
  }
502
942
  }, []);
503
- const handlePointerDown = React13.useCallback(
943
+ const handlePointerDown = React14.useCallback(
504
944
  (event) => {
505
945
  const target = event.target;
506
946
  if (target && typeof target.closest === "function") {
@@ -512,23 +952,23 @@ function SearchPanelForm(props = {}) {
512
952
  },
513
953
  [focusInput]
514
954
  );
515
- React13.useEffect(() => {
955
+ React14.useEffect(() => {
516
956
  const el = inputRef.current;
517
957
  if (!el) return;
518
958
  if (el.value && el.value.trim()) {
519
959
  setHasValue(true);
520
960
  }
521
961
  }, []);
522
- const handleInputChange = React13.useCallback((event) => {
962
+ const handleInputChange = React14.useCallback((event) => {
523
963
  var _a;
524
964
  const nextHasValue = Boolean(
525
965
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
526
966
  );
527
967
  setHasValue(nextHasValue);
528
968
  }, []);
529
- const handleClear = React13.useCallback((event) => {
969
+ const handleClear = React14.useCallback((event) => {
530
970
  }, []);
531
- const handleClearKey = React13.useCallback(
971
+ const handleClearKey = React14.useCallback(
532
972
  (event) => {
533
973
  if (event.key === "Enter" || event.key === " ") {
534
974
  event.preventDefault();
@@ -537,7 +977,7 @@ function SearchPanelForm(props = {}) {
537
977
  },
538
978
  [handleClear]
539
979
  );
540
- return /* @__PURE__ */ React13.createElement(
980
+ return /* @__PURE__ */ React14.createElement(
541
981
  "form",
542
982
  {
543
983
  action,
@@ -549,7 +989,7 @@ function SearchPanelForm(props = {}) {
549
989
  onPointerDown: handlePointerDown,
550
990
  "data-has-value": hasValue ? "1" : "0"
551
991
  },
552
- /* @__PURE__ */ React13.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React13.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React13.createElement(
992
+ /* @__PURE__ */ React14.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React14.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React14.createElement(
553
993
  "input",
554
994
  {
555
995
  id: inputId,
@@ -565,7 +1005,7 @@ function SearchPanelForm(props = {}) {
565
1005
  onInput: handleInputChange
566
1006
  }
567
1007
  )),
568
- hasValue ? /* @__PURE__ */ React13.createElement(
1008
+ hasValue ? /* @__PURE__ */ React14.createElement(
569
1009
  "button",
570
1010
  {
571
1011
  type: "button",
@@ -578,32 +1018,32 @@ function SearchPanelForm(props = {}) {
578
1018
  },
579
1019
  "\xD7"
580
1020
  ) : null,
581
- /* @__PURE__ */ React13.createElement(
1021
+ /* @__PURE__ */ React14.createElement(
582
1022
  "button",
583
1023
  {
584
1024
  type: "submit",
585
1025
  "data-canopy-search-form-trigger": "submit",
586
1026
  className: "canopy-search-form__submit"
587
1027
  },
588
- /* @__PURE__ */ React13.createElement("span", null, text),
589
- /* @__PURE__ */ React13.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React13.createElement("span", null, "\u2318"), /* @__PURE__ */ React13.createElement("span", null, "K"))
1028
+ /* @__PURE__ */ React14.createElement("span", null, text),
1029
+ /* @__PURE__ */ React14.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React14.createElement("span", null, "\u2318"), /* @__PURE__ */ React14.createElement("span", null, "K"))
590
1030
  )
591
1031
  );
592
1032
  }
593
1033
 
594
1034
  // ui/src/search/SearchPanelTeaserResults.jsx
595
- import React14 from "react";
1035
+ import React15 from "react";
596
1036
  function SearchPanelTeaserResults(props = {}) {
597
1037
  const { style, className } = props || {};
598
1038
  const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
599
- return /* @__PURE__ */ React14.createElement(
1039
+ return /* @__PURE__ */ React15.createElement(
600
1040
  "div",
601
1041
  {
602
1042
  "data-canopy-search-form-panel": true,
603
1043
  className: classes || void 0,
604
1044
  style
605
1045
  },
606
- /* @__PURE__ */ React14.createElement("div", { id: "cplist" })
1046
+ /* @__PURE__ */ React15.createElement("div", { id: "cplist" })
607
1047
  );
608
1048
  }
609
1049
 
@@ -623,11 +1063,11 @@ function MdxSearchFormModal(props = {}) {
623
1063
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
624
1064
  const resolvedSearchPath = resolveSearchPath(searchPath);
625
1065
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
626
- return /* @__PURE__ */ React15.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React15.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React15.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React15.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React15.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1066
+ return /* @__PURE__ */ React16.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React16.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React16.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React16.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
627
1067
  }
628
1068
 
629
1069
  // ui/src/search/SearchPanel.jsx
630
- import React16 from "react";
1070
+ import React17 from "react";
631
1071
  function SearchPanel(props = {}) {
632
1072
  const {
633
1073
  placeholder = "Search\u2026",
@@ -644,11 +1084,11 @@ function SearchPanel(props = {}) {
644
1084
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
645
1085
  const resolvedSearchPath = resolveSearchPath(searchPath);
646
1086
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
647
- return /* @__PURE__ */ React16.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React16.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React16.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React16.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1087
+ return /* @__PURE__ */ React17.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React17.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React17.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React17.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React17.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
648
1088
  }
649
1089
 
650
1090
  // ui/src/iiif/ManifestPrimitives.jsx
651
- import React17 from "react";
1091
+ import React18 from "react";
652
1092
  import {
653
1093
  Label as CloverLabel,
654
1094
  Metadata as CloverMetadata,
@@ -673,30 +1113,30 @@ function ensureMetadata(items) {
673
1113
  function Label({ manifest, label, ...rest }) {
674
1114
  const intl = label || manifest && manifest.label;
675
1115
  if (!hasInternationalValue(intl)) return null;
676
- return /* @__PURE__ */ React17.createElement(CloverLabel, { label: intl, ...rest });
1116
+ return /* @__PURE__ */ React18.createElement(CloverLabel, { label: intl, ...rest });
677
1117
  }
678
1118
  function Summary({ manifest, summary, ...rest }) {
679
1119
  const intl = summary || manifest && manifest.summary;
680
1120
  if (!hasInternationalValue(intl)) return null;
681
- return /* @__PURE__ */ React17.createElement(CloverSummary, { summary: intl, ...rest });
1121
+ return /* @__PURE__ */ React18.createElement(CloverSummary, { summary: intl, ...rest });
682
1122
  }
683
1123
  function Metadata({ manifest, metadata, ...rest }) {
684
1124
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
685
1125
  if (!items.length) return null;
686
- return /* @__PURE__ */ React17.createElement(CloverMetadata, { metadata: items, ...rest });
1126
+ return /* @__PURE__ */ React18.createElement(CloverMetadata, { metadata: items, ...rest });
687
1127
  }
688
1128
  function RequiredStatement({ manifest, requiredStatement, ...rest }) {
689
1129
  const stmt = requiredStatement || manifest && manifest.requiredStatement;
690
1130
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
691
1131
  return null;
692
1132
  }
693
- return /* @__PURE__ */ React17.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
1133
+ return /* @__PURE__ */ React18.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
694
1134
  }
695
1135
  export {
696
- FeaturedHero,
697
1136
  HelloWorld,
698
- Hero,
1137
+ interstitials_exports as Interstitials,
699
1138
  Label,
1139
+ Layout,
700
1140
  Metadata,
701
1141
  MdxRelatedItems as RelatedItems,
702
1142
  RequiredStatement,