@canopy-iiif/app 0.9.13 → 0.9.14

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,7 +173,7 @@ __export(interstitials_exports, {
173
173
  });
174
174
 
175
175
  // ui/src/interstitials/Hero.jsx
176
- import React6 from "react";
176
+ import React8 from "react";
177
177
  import helpers from "@canopy-iiif/app/lib/components/featured.js";
178
178
 
179
179
  // ui/src/interstitials/hero-utils.js
@@ -183,6 +183,48 @@ function computeHeroHeightStyle(height) {
183
183
  return { width: "100%", height: val };
184
184
  }
185
185
 
186
+ // ui/src/layout/Button.jsx
187
+ import React6 from "react";
188
+ var VARIANTS = /* @__PURE__ */ new Set(["primary", "secondary"]);
189
+ function Button({
190
+ label,
191
+ href = "#",
192
+ target,
193
+ rel,
194
+ variant = "primary",
195
+ className = "",
196
+ children,
197
+ ...rest
198
+ }) {
199
+ const resolvedVariant = VARIANTS.has(variant) ? variant : "primary";
200
+ const computedRel = target === "_blank" && !rel ? "noopener noreferrer" : rel;
201
+ const content = children != null ? children : label;
202
+ if (!content) return null;
203
+ const classes = [
204
+ "canopy-button",
205
+ `canopy-button--${resolvedVariant}`,
206
+ className
207
+ ].filter(Boolean).join(" ");
208
+ return /* @__PURE__ */ React6.createElement(
209
+ "a",
210
+ {
211
+ href,
212
+ className: classes,
213
+ target,
214
+ rel: computedRel,
215
+ ...rest
216
+ },
217
+ content
218
+ );
219
+ }
220
+
221
+ // ui/src/layout/ButtonWrapper.jsx
222
+ import React7 from "react";
223
+ function ButtonWrapper({ className = "", children, ...rest }) {
224
+ const classes = ["canopy-button-group", className].filter(Boolean).join(" ");
225
+ return /* @__PURE__ */ React7.createElement("div", { className: classes, ...rest }, children);
226
+ }
227
+
186
228
  // ui/src/interstitials/Hero.jsx
187
229
  var basePath = (() => {
188
230
  try {
@@ -225,7 +267,8 @@ function normalizeLinks(links) {
225
267
  const title = link.title ? String(link.title) : "";
226
268
  if (!href || !title) return null;
227
269
  const type = link.type === "secondary" ? "secondary" : "primary";
228
- return { href, title, type };
270
+ const target = link.target ? String(link.target) : void 0;
271
+ return { href, title, type, target };
229
272
  }).filter(Boolean);
230
273
  }
231
274
  function sanitizeRest(rest) {
@@ -332,7 +375,7 @@ function Hero({
332
375
  isStaticCaption ? "canopy-interstitial__pane--static" : ""
333
376
  ].filter(Boolean).join(" ");
334
377
  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(
378
+ return /* @__PURE__ */ React8.createElement("div", { className: "swiper-slide", key: safeHref || idx }, /* @__PURE__ */ React8.createElement("article", { className: paneClassName }, slide.thumbnail ? /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__media-frame" }, /* @__PURE__ */ React8.createElement(
336
379
  "img",
337
380
  {
338
381
  src: slide.thumbnail,
@@ -341,9 +384,9 @@ function Hero({
341
384
  className: "canopy-interstitial__media canopy-interstitial__media--static",
342
385
  loading: idx === 0 ? "eager" : "lazy"
343
386
  }
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));
387
+ )) : null, slide.title ? /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__caption canopy-interstitial__caption--static" }, /* @__PURE__ */ React8.createElement("a", { href: safeHref, className: "canopy-interstitial__caption-link" }, slide.title)) : null));
345
388
  }
346
- return /* @__PURE__ */ React6.createElement("div", { className: "swiper-slide", key: safeHref || idx }, /* @__PURE__ */ React6.createElement("article", { className: paneClassName }, slide.thumbnail ? /* @__PURE__ */ React6.createElement(
389
+ return /* @__PURE__ */ React8.createElement("div", { className: "swiper-slide", key: safeHref || idx }, /* @__PURE__ */ React8.createElement("article", { className: paneClassName }, slide.thumbnail ? /* @__PURE__ */ React8.createElement(
347
390
  "img",
348
391
  {
349
392
  src: slide.thumbnail,
@@ -352,34 +395,35 @@ function Hero({
352
395
  className: "canopy-interstitial__media",
353
396
  loading: idx === 0 ? "eager" : "lazy"
354
397
  }
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));
398
+ ) : null, showVeil ? /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__veil", "aria-hidden": "true" }) : null, slide.title ? /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__caption" }, /* @__PURE__ */ React8.createElement("a", { href: safeHref, className: "canopy-interstitial__caption-link" }, slide.title)) : null));
356
399
  };
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(
400
+ const renderSlider = (options = {}) => /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__slider swiper" }, /* @__PURE__ */ React8.createElement("div", { className: "swiper-wrapper" }, orderedSlides.map((slide, idx) => renderSlide(slide, idx, options))), /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__nav" }, /* @__PURE__ */ React8.createElement(
358
401
  "button",
359
402
  {
360
403
  type: "button",
361
404
  "aria-label": "Previous slide",
362
405
  className: "canopy-interstitial__nav-btn canopy-interstitial__nav-btn--prev swiper-button-prev"
363
406
  }
364
- ), /* @__PURE__ */ React6.createElement(
407
+ ), /* @__PURE__ */ React8.createElement(
365
408
  "button",
366
409
  {
367
410
  type: "button",
368
411
  "aria-label": "Next slide",
369
412
  className: "canopy-interstitial__nav-btn canopy-interstitial__nav-btn--next swiper-button-next"
370
413
  }
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",
414
+ )), /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__pagination swiper-pagination" }));
415
+ const overlayContent = /* @__PURE__ */ React8.createElement(React8.Fragment, null, overlayTitle ? /* @__PURE__ */ React8.createElement("h1", { className: "canopy-interstitial__headline" }, overlayTitle) : null, derivedDescription ? /* @__PURE__ */ React8.createElement("p", { className: "canopy-interstitial__description" }, derivedDescription) : null, overlayLinks.length ? /* @__PURE__ */ React8.createElement(ButtonWrapper, { className: "canopy-interstitial__actions" }, overlayLinks.map((link) => /* @__PURE__ */ React8.createElement(
416
+ Button,
374
417
  {
375
418
  key: `${link.href}-${link.title}`,
376
419
  href: link.href,
377
- className: link.type === "secondary" ? "canopy-button canopy-button--secondary" : "canopy-button canopy-button--primary"
378
- },
379
- link.title
420
+ label: link.title,
421
+ variant: link.type,
422
+ target: link.target
423
+ }
380
424
  ))) : null);
381
425
  const cleanedProps = sanitizeRest(rest);
382
- return /* @__PURE__ */ React6.createElement(
426
+ return /* @__PURE__ */ React8.createElement(
383
427
  "section",
384
428
  {
385
429
  className: containerClassName,
@@ -387,12 +431,12 @@ function Hero({
387
431
  style: heroStyles,
388
432
  ...cleanedProps
389
433
  },
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" })))
434
+ /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__layout" }, /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__body" }, overlayContent)), /* @__PURE__ */ React8.createElement("div", { className: "canopy-interstitial__media-group" }, renderSlider({ showVeil: false, captionVariant: "static" })))
391
435
  );
392
436
  }
393
437
 
394
438
  // ui/src/layout/SubNavigation.jsx
395
- import React7 from "react";
439
+ import React9 from "react";
396
440
  import navigationHelpers from "@canopy-iiif/app/lib/components/navigation.js";
397
441
  function resolveRelativeCandidate(page, current) {
398
442
  if (page && typeof page.relativePath === "string" && page.relativePath) return page.relativePath;
@@ -417,14 +461,14 @@ function renderNodes(nodes, parentKey = "node") {
417
461
  if (node.isActive) classes.push("is-active");
418
462
  const linkClass = classes.join(" ");
419
463
  const Tag = node.href ? "a" : "span";
420
- return /* @__PURE__ */ React7.createElement(
464
+ return /* @__PURE__ */ React9.createElement(
421
465
  "li",
422
466
  {
423
467
  key,
424
468
  className: "canopy-sub-navigation__item",
425
469
  "data-depth": depth
426
470
  },
427
- /* @__PURE__ */ React7.createElement(
471
+ /* @__PURE__ */ React9.createElement(
428
472
  Tag,
429
473
  {
430
474
  className: linkClass,
@@ -433,7 +477,7 @@ function renderNodes(nodes, parentKey = "node") {
433
477
  },
434
478
  node.title || node.slug
435
479
  ),
436
- showChildren ? /* @__PURE__ */ React7.createElement("ul", { className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested", role: "list" }, renderNodes(node.children, key)) : null
480
+ showChildren ? /* @__PURE__ */ React9.createElement("ul", { className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested", role: "list" }, renderNodes(node.children, key)) : null
437
481
  );
438
482
  });
439
483
  }
@@ -447,12 +491,12 @@ function SubNavigation({
447
491
  ariaLabel
448
492
  }) {
449
493
  const PageContext = navigationHelpers && navigationHelpers.getPageContext ? navigationHelpers.getPageContext() : null;
450
- const context = PageContext ? React7.useContext(PageContext) : null;
494
+ const context = PageContext ? React9.useContext(PageContext) : null;
451
495
  const contextNavigation = context && context.navigation ? context.navigation : null;
452
496
  const contextPage = context && context.page ? context.page : null;
453
497
  const effectiveNavigation = navigationProp || contextNavigation;
454
498
  const effectivePage = page || contextPage;
455
- const resolvedNavigation = React7.useMemo(() => {
499
+ const resolvedNavigation = React9.useMemo(() => {
456
500
  if (effectiveNavigation && effectiveNavigation.root) return effectiveNavigation;
457
501
  const candidate = resolveRelativeCandidate(effectivePage, current);
458
502
  if (!candidate) return effectiveNavigation || null;
@@ -476,15 +520,15 @@ function SubNavigation({
476
520
  if (!Object.prototype.hasOwnProperty.call(inlineStyle, "--sub-nav-indent")) {
477
521
  inlineStyle["--sub-nav-indent"] = "0.85rem";
478
522
  }
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")));
523
+ return /* @__PURE__ */ React9.createElement("nav", { className: combinedClassName, style: inlineStyle, "aria-label": navLabel }, finalHeading ? /* @__PURE__ */ React9.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null, /* @__PURE__ */ React9.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root")));
480
524
  }
481
525
 
482
526
  // ui/src/layout/Layout.jsx
483
- import React9 from "react";
527
+ import React11 from "react";
484
528
  import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
485
529
 
486
530
  // ui/src/layout/ContentNavigation.jsx
487
- import React8 from "react";
531
+ import React10 from "react";
488
532
  var SCROLL_OFFSET_REM = 1.618;
489
533
  function depthIndex(depth) {
490
534
  return Math.max(0, Math.min(5, (depth || 1) - 1));
@@ -499,12 +543,12 @@ function ContentNavigation({
499
543
  ariaLabel
500
544
  }) {
501
545
  const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
502
- const savedDepthsRef = React8.useRef(null);
546
+ const savedDepthsRef = React10.useRef(null);
503
547
  if ((!items || !items.length) && !headingId) return null;
504
548
  const combinedClassName = ["canopy-sub-navigation canopy-content-navigation", className].filter(Boolean).join(" ");
505
549
  const effectiveHeading = heading || pageTitle || null;
506
550
  const navLabel = ariaLabel || (effectiveHeading ? `${effectiveHeading} navigation` : "Section navigation");
507
- const getSavedDepth = React8.useCallback(
551
+ const getSavedDepth = React10.useCallback(
508
552
  (id, fallback) => {
509
553
  if (!id) return fallback;
510
554
  if (!savedDepthsRef.current) savedDepthsRef.current = /* @__PURE__ */ new Map();
@@ -515,7 +559,7 @@ function ContentNavigation({
515
559
  },
516
560
  []
517
561
  );
518
- const headingEntries = React8.useMemo(() => {
562
+ const headingEntries = React10.useMemo(() => {
519
563
  const entries = [];
520
564
  const seen = /* @__PURE__ */ new Set();
521
565
  if (headingId) {
@@ -539,12 +583,12 @@ function ContentNavigation({
539
583
  return entries;
540
584
  }, [headingId, items, getSavedDepth]);
541
585
  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(() => {
586
+ const [activeId, setActiveId] = React10.useState(fallbackId);
587
+ const activeIdRef = React10.useRef(activeId);
588
+ React10.useEffect(() => {
545
589
  activeIdRef.current = activeId;
546
590
  }, [activeId]);
547
- React8.useEffect(() => {
591
+ React10.useEffect(() => {
548
592
  if (!headingEntries.length) return;
549
593
  if (!headingEntries.some((entry) => entry.id === activeIdRef.current)) {
550
594
  const next = headingEntries[0].id;
@@ -552,7 +596,7 @@ function ContentNavigation({
552
596
  setActiveId(next);
553
597
  }
554
598
  }, [headingEntries]);
555
- const computeOffsetPx = React8.useCallback(() => {
599
+ const computeOffsetPx = React10.useCallback(() => {
556
600
  if (!isBrowser) return 0;
557
601
  try {
558
602
  const root = document.documentElement;
@@ -562,8 +606,8 @@ function ContentNavigation({
562
606
  return 0;
563
607
  }
564
608
  }, [isBrowser]);
565
- const headingElementsRef = React8.useRef([]);
566
- const updateActiveFromElements = React8.useCallback(
609
+ const headingElementsRef = React10.useRef([]);
610
+ const updateActiveFromElements = React10.useCallback(
567
611
  (elements) => {
568
612
  if (!elements || !elements.length) return;
569
613
  const offset = computeOffsetPx();
@@ -583,7 +627,7 @@ function ContentNavigation({
583
627
  },
584
628
  [computeOffsetPx]
585
629
  );
586
- React8.useEffect(() => {
630
+ React10.useEffect(() => {
587
631
  if (!isBrowser) return void 0;
588
632
  const elements = headingEntries.map((entry) => {
589
633
  const element = document.getElementById(entry.id);
@@ -609,7 +653,7 @@ function ContentNavigation({
609
653
  window.removeEventListener("resize", handle);
610
654
  };
611
655
  }, [headingEntries, isBrowser, updateActiveFromElements]);
612
- const handleAnchorClick = React8.useCallback(
656
+ const handleAnchorClick = React10.useCallback(
613
657
  (event, targetId, options = {}) => {
614
658
  var _a;
615
659
  try {
@@ -640,7 +684,7 @@ function ContentNavigation({
640
684
  },
641
685
  [computeOffsetPx, headingEntries, headingId, isBrowser]
642
686
  );
643
- const renderNodes2 = React8.useCallback(
687
+ const renderNodes2 = React10.useCallback(
644
688
  (nodes) => {
645
689
  if (!nodes || !nodes.length) return null;
646
690
  return nodes.map((node) => {
@@ -649,7 +693,7 @@ function ContentNavigation({
649
693
  const depth = node.depth || node.level || getSavedDepth(id, 2);
650
694
  const idx = depthIndex(depth);
651
695
  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(
696
+ return /* @__PURE__ */ React10.createElement("li", { key: id || node.title, className: "canopy-sub-navigation__item", "data-depth": idx }, /* @__PURE__ */ React10.createElement(
653
697
  "a",
654
698
  {
655
699
  className: `canopy-sub-navigation__link depth-${idx}${isActive ? " is-active" : ""}`,
@@ -658,7 +702,7 @@ function ContentNavigation({
658
702
  "aria-current": isActive ? "location" : void 0
659
703
  },
660
704
  node.title
661
- ), node.children && node.children.length ? /* @__PURE__ */ React8.createElement(
705
+ ), node.children && node.children.length ? /* @__PURE__ */ React10.createElement(
662
706
  "ul",
663
707
  {
664
708
  className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
@@ -671,7 +715,7 @@ function ContentNavigation({
671
715
  [handleAnchorClick, activeId, getSavedDepth]
672
716
  );
673
717
  const nestedItems = renderNodes2(items);
674
- const topLink = headingId ? /* @__PURE__ */ React8.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React8.createElement(
718
+ const topLink = headingId ? /* @__PURE__ */ React10.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React10.createElement(
675
719
  "a",
676
720
  {
677
721
  className: `canopy-sub-navigation__link depth-0${activeId === headingId ? " is-active" : ""}`,
@@ -680,7 +724,7 @@ function ContentNavigation({
680
724
  "aria-current": activeId === headingId ? "location" : void 0
681
725
  },
682
726
  effectiveHeading || pageTitle || headingId
683
- ), nestedItems ? /* @__PURE__ */ React8.createElement(
727
+ ), nestedItems ? /* @__PURE__ */ React10.createElement(
684
728
  "ul",
685
729
  {
686
730
  className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
@@ -688,7 +732,7 @@ function ContentNavigation({
688
732
  },
689
733
  nestedItems
690
734
  ) : 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));
735
+ return /* @__PURE__ */ React10.createElement("nav", { className: combinedClassName, style, "aria-label": navLabel }, /* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, topLink || nestedItems));
692
736
  }
693
737
 
694
738
  // ui/src/layout/Layout.jsx
@@ -720,10 +764,10 @@ function buildHeadingTree(headings) {
720
764
  }
721
765
  function buildNavigationAside(sidebar, className) {
722
766
  if (!sidebar) {
723
- return /* @__PURE__ */ React9.createElement(SubNavigation, { className });
767
+ return /* @__PURE__ */ React11.createElement(SubNavigation, { className });
724
768
  }
725
769
  if (typeof sidebar === "function") {
726
- return React9.createElement(sidebar);
770
+ return React11.createElement(sidebar);
727
771
  }
728
772
  return sidebar;
729
773
  }
@@ -740,26 +784,26 @@ function Layout({
740
784
  ...rest
741
785
  }) {
742
786
  const PageContext = navigationHelpers2 && typeof navigationHelpers2.getPageContext === "function" ? navigationHelpers2.getPageContext() : null;
743
- const context = PageContext ? React9.useContext(PageContext) : null;
744
- const pageHeadings = React9.useMemo(() => {
787
+ const context = PageContext ? React11.useContext(PageContext) : null;
788
+ const pageHeadings = React11.useMemo(() => {
745
789
  const headings = context && context.page ? context.page.headings : null;
746
790
  return Array.isArray(headings) ? headings : [];
747
791
  }, [context]);
748
- const contentHeading = React9.useMemo(() => {
792
+ const contentHeading = React11.useMemo(() => {
749
793
  const first = pageHeadings.find((heading) => {
750
794
  const depth = heading && (heading.depth || heading.level);
751
795
  return depth === 1;
752
796
  });
753
797
  return first && first.title ? first.title : null;
754
798
  }, [pageHeadings]);
755
- const headingAnchorId = React9.useMemo(() => {
799
+ const headingAnchorId = React11.useMemo(() => {
756
800
  const first = pageHeadings.find((heading) => {
757
801
  const depth = heading && (heading.depth || heading.level);
758
802
  return depth === 1;
759
803
  });
760
804
  return first && first.id ? first.id : null;
761
805
  }, [pageHeadings]);
762
- const headingTree = React9.useMemo(
806
+ const headingTree = React11.useMemo(
763
807
  () => buildHeadingTree(pageHeadings),
764
808
  [pageHeadings]
765
809
  );
@@ -798,7 +842,7 @@ function Layout({
798
842
  contentNavigationClassName
799
843
  ].filter(Boolean).join(" ");
800
844
  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(
845
+ return /* @__PURE__ */ React11.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React11.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React11.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React11.createElement("aside", { className: contentNavigationAsideClassName }, /* @__PURE__ */ React11.createElement(
802
846
  ContentNavigation,
803
847
  {
804
848
  items: headingTree,
@@ -810,17 +854,17 @@ function Layout({
810
854
  }
811
855
 
812
856
  // ui/src/layout/CanopyHeader.jsx
813
- import React16 from "react";
857
+ import React18 from "react";
814
858
 
815
859
  // ui/src/search/SearchPanel.jsx
816
- import React13 from "react";
860
+ import React15 from "react";
817
861
 
818
862
  // ui/src/Icons.jsx
819
- import React10 from "react";
820
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React10.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React10.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" }));
863
+ import React12 from "react";
864
+ 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" }));
821
865
 
822
866
  // ui/src/search/SearchPanelForm.jsx
823
- import React11 from "react";
867
+ import React13 from "react";
824
868
  function readBasePath() {
825
869
  const normalize = (val) => {
826
870
  const raw = typeof val === "string" ? val.trim() : "";
@@ -883,18 +927,18 @@ function SearchPanelForm(props = {}) {
883
927
  clearLabel = "Clear search"
884
928
  } = props || {};
885
929
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
886
- const action = React11.useMemo(
930
+ const action = React13.useMemo(
887
931
  () => resolveSearchPath(searchPath),
888
932
  [searchPath]
889
933
  );
890
- const autoId = typeof React11.useId === "function" ? React11.useId() : void 0;
891
- const [fallbackId] = React11.useState(
934
+ const autoId = typeof React13.useId === "function" ? React13.useId() : void 0;
935
+ const [fallbackId] = React13.useState(
892
936
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
893
937
  );
894
938
  const inputId = inputIdProp || autoId || fallbackId;
895
- const inputRef = React11.useRef(null);
896
- const [hasValue, setHasValue] = React11.useState(false);
897
- const focusInput = React11.useCallback(() => {
939
+ const inputRef = React13.useRef(null);
940
+ const [hasValue, setHasValue] = React13.useState(false);
941
+ const focusInput = React13.useCallback(() => {
898
942
  const el = inputRef.current;
899
943
  if (!el) return;
900
944
  if (document.activeElement === el) return;
@@ -907,7 +951,7 @@ function SearchPanelForm(props = {}) {
907
951
  }
908
952
  }
909
953
  }, []);
910
- const handlePointerDown = React11.useCallback(
954
+ const handlePointerDown = React13.useCallback(
911
955
  (event) => {
912
956
  const target = event.target;
913
957
  if (target && typeof target.closest === "function") {
@@ -919,23 +963,23 @@ function SearchPanelForm(props = {}) {
919
963
  },
920
964
  [focusInput]
921
965
  );
922
- React11.useEffect(() => {
966
+ React13.useEffect(() => {
923
967
  const el = inputRef.current;
924
968
  if (!el) return;
925
969
  if (el.value && el.value.trim()) {
926
970
  setHasValue(true);
927
971
  }
928
972
  }, []);
929
- const handleInputChange = React11.useCallback((event) => {
973
+ const handleInputChange = React13.useCallback((event) => {
930
974
  var _a;
931
975
  const nextHasValue = Boolean(
932
976
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
933
977
  );
934
978
  setHasValue(nextHasValue);
935
979
  }, []);
936
- const handleClear = React11.useCallback((event) => {
980
+ const handleClear = React13.useCallback((event) => {
937
981
  }, []);
938
- const handleClearKey = React11.useCallback(
982
+ const handleClearKey = React13.useCallback(
939
983
  (event) => {
940
984
  if (event.key === "Enter" || event.key === " ") {
941
985
  event.preventDefault();
@@ -944,7 +988,7 @@ function SearchPanelForm(props = {}) {
944
988
  },
945
989
  [handleClear]
946
990
  );
947
- return /* @__PURE__ */ React11.createElement(
991
+ return /* @__PURE__ */ React13.createElement(
948
992
  "form",
949
993
  {
950
994
  action,
@@ -956,7 +1000,7 @@ function SearchPanelForm(props = {}) {
956
1000
  onPointerDown: handlePointerDown,
957
1001
  "data-has-value": hasValue ? "1" : "0"
958
1002
  },
959
- /* @__PURE__ */ React11.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React11.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React11.createElement(
1003
+ /* @__PURE__ */ React13.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React13.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React13.createElement(
960
1004
  "input",
961
1005
  {
962
1006
  id: inputId,
@@ -972,7 +1016,7 @@ function SearchPanelForm(props = {}) {
972
1016
  onInput: handleInputChange
973
1017
  }
974
1018
  )),
975
- hasValue ? /* @__PURE__ */ React11.createElement(
1019
+ hasValue ? /* @__PURE__ */ React13.createElement(
976
1020
  "button",
977
1021
  {
978
1022
  type: "button",
@@ -985,32 +1029,32 @@ function SearchPanelForm(props = {}) {
985
1029
  },
986
1030
  "\xD7"
987
1031
  ) : null,
988
- /* @__PURE__ */ React11.createElement(
1032
+ /* @__PURE__ */ React13.createElement(
989
1033
  "button",
990
1034
  {
991
1035
  type: "submit",
992
1036
  "data-canopy-search-form-trigger": "submit",
993
1037
  className: "canopy-search-form__submit"
994
1038
  },
995
- /* @__PURE__ */ React11.createElement("span", null, text),
996
- /* @__PURE__ */ React11.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React11.createElement("span", null, "\u2318"), /* @__PURE__ */ React11.createElement("span", null, "K"))
1039
+ /* @__PURE__ */ React13.createElement("span", null, text),
1040
+ /* @__PURE__ */ React13.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React13.createElement("span", null, "\u2318"), /* @__PURE__ */ React13.createElement("span", null, "K"))
997
1041
  )
998
1042
  );
999
1043
  }
1000
1044
 
1001
1045
  // ui/src/search/SearchPanelTeaserResults.jsx
1002
- import React12 from "react";
1046
+ import React14 from "react";
1003
1047
  function SearchPanelTeaserResults(props = {}) {
1004
1048
  const { style, className } = props || {};
1005
1049
  const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
1006
- return /* @__PURE__ */ React12.createElement(
1050
+ return /* @__PURE__ */ React14.createElement(
1007
1051
  "div",
1008
1052
  {
1009
1053
  "data-canopy-search-form-panel": true,
1010
1054
  className: classes || void 0,
1011
1055
  style
1012
1056
  },
1013
- /* @__PURE__ */ React12.createElement("div", { id: "cplist" })
1057
+ /* @__PURE__ */ React14.createElement("div", { id: "cplist" })
1014
1058
  );
1015
1059
  }
1016
1060
 
@@ -1031,11 +1075,11 @@ function SearchPanel(props = {}) {
1031
1075
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1032
1076
  const resolvedSearchPath = resolveSearchPath(searchPath);
1033
1077
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
1034
- return /* @__PURE__ */ React13.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React13.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React13.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React13.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React13.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1078
+ 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) } }));
1035
1079
  }
1036
1080
 
1037
1081
  // ui/src/layout/CanopyBrand.jsx
1038
- import React14 from "react";
1082
+ import React16 from "react";
1039
1083
  function CanopyBrand(props = {}) {
1040
1084
  const {
1041
1085
  labelId,
@@ -1046,11 +1090,11 @@ function CanopyBrand(props = {}) {
1046
1090
  } = props || {};
1047
1091
  const spanProps = labelId ? { id: labelId } : {};
1048
1092
  const classes = ["canopy-logo", className].filter(Boolean).join(" ");
1049
- return /* @__PURE__ */ React14.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React14.createElement(Logo, null) : null, /* @__PURE__ */ React14.createElement("span", { ...spanProps }, label));
1093
+ return /* @__PURE__ */ React16.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React16.createElement(Logo, null) : null, /* @__PURE__ */ React16.createElement("span", { ...spanProps }, label));
1050
1094
  }
1051
1095
 
1052
1096
  // ui/src/layout/CanopyModal.jsx
1053
- import React15 from "react";
1097
+ import React17 from "react";
1054
1098
  function CanopyModal(props = {}) {
1055
1099
  const {
1056
1100
  id,
@@ -1101,7 +1145,7 @@ function CanopyModal(props = {}) {
1101
1145
  if (padded) bodyClasses.push("canopy-modal__body--padded");
1102
1146
  if (bodyClassName) bodyClasses.push(bodyClassName);
1103
1147
  const bodyClassNameValue = bodyClasses.join(" ");
1104
- return /* @__PURE__ */ React15.createElement("div", { ...modalProps }, /* @__PURE__ */ React15.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React15.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React15.createElement(
1148
+ return /* @__PURE__ */ React17.createElement("div", { ...modalProps }, /* @__PURE__ */ React17.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React17.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React17.createElement(
1105
1149
  "svg",
1106
1150
  {
1107
1151
  xmlns: "http://www.w3.org/2000/svg",
@@ -1111,8 +1155,8 @@ function CanopyModal(props = {}) {
1111
1155
  strokeWidth: "1.5",
1112
1156
  className: "canopy-modal__close-icon"
1113
1157
  },
1114
- /* @__PURE__ */ React15.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
1115
- ), /* @__PURE__ */ React15.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React15.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React15.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React15.createElement(
1158
+ /* @__PURE__ */ React17.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
1159
+ ), /* @__PURE__ */ React17.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React17.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React17.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React17.createElement(
1116
1160
  CanopyBrand,
1117
1161
  {
1118
1162
  labelId: resolvedLabelId,
@@ -1316,7 +1360,7 @@ function HeaderScript() {
1316
1360
  });
1317
1361
  })();
1318
1362
  `;
1319
- return /* @__PURE__ */ React16.createElement(
1363
+ return /* @__PURE__ */ React18.createElement(
1320
1364
  "script",
1321
1365
  {
1322
1366
  dangerouslySetInnerHTML: {
@@ -1340,7 +1384,7 @@ function CanopyHeader(props = {}) {
1340
1384
  logo: SiteLogo
1341
1385
  } = props;
1342
1386
  const navLinks = ensureArray(navLinksProp);
1343
- return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement("header", { className: "canopy-header", "data-mobile-nav": "closed", "data-mobile-search": "closed" }, /* @__PURE__ */ React16.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React16.createElement(
1387
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("header", { className: "canopy-header", "data-mobile-nav": "closed", "data-mobile-search": "closed" }, /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React18.createElement(
1344
1388
  CanopyBrand,
1345
1389
  {
1346
1390
  label: title,
@@ -1348,7 +1392,7 @@ function CanopyHeader(props = {}) {
1348
1392
  className: "canopy-header__brand-link",
1349
1393
  Logo: SiteLogo
1350
1394
  }
1351
- )), /* @__PURE__ */ React16.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React16.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })), /* @__PURE__ */ React16.createElement("nav", { className: "canopy-nav-links canopy-header__desktop-nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React16.createElement("a", { key: link.href, href: link.href }, link.label || link.href))), /* @__PURE__ */ React16.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React16.createElement(
1395
+ )), /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React18.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })), /* @__PURE__ */ React18.createElement("nav", { className: "canopy-nav-links canopy-header__desktop-nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React18.createElement("a", { key: link.href, href: link.href }, link.label || link.href))), /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React18.createElement(
1352
1396
  "button",
1353
1397
  {
1354
1398
  type: "button",
@@ -1358,7 +1402,7 @@ function CanopyHeader(props = {}) {
1358
1402
  "aria-expanded": "false",
1359
1403
  "data-canopy-header-toggle": "search"
1360
1404
  },
1361
- /* @__PURE__ */ React16.createElement(
1405
+ /* @__PURE__ */ React18.createElement(
1362
1406
  "svg",
1363
1407
  {
1364
1408
  xmlns: "http://www.w3.org/2000/svg",
@@ -1368,9 +1412,9 @@ function CanopyHeader(props = {}) {
1368
1412
  strokeWidth: "1.5",
1369
1413
  className: "canopy-header__search-icon"
1370
1414
  },
1371
- /* @__PURE__ */ React16.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-3.8-3.8M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z" })
1415
+ /* @__PURE__ */ React18.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-3.8-3.8M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z" })
1372
1416
  )
1373
- ), /* @__PURE__ */ React16.createElement(
1417
+ ), /* @__PURE__ */ React18.createElement(
1374
1418
  "button",
1375
1419
  {
1376
1420
  type: "button",
@@ -1380,7 +1424,7 @@ function CanopyHeader(props = {}) {
1380
1424
  "aria-expanded": "false",
1381
1425
  "data-canopy-header-toggle": "nav"
1382
1426
  },
1383
- /* @__PURE__ */ React16.createElement(
1427
+ /* @__PURE__ */ React18.createElement(
1384
1428
  "svg",
1385
1429
  {
1386
1430
  xmlns: "http://www.w3.org/2000/svg",
@@ -1390,9 +1434,9 @@ function CanopyHeader(props = {}) {
1390
1434
  stroke: "currentColor",
1391
1435
  className: "canopy-header__menu-icon"
1392
1436
  },
1393
- /* @__PURE__ */ React16.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" })
1437
+ /* @__PURE__ */ React18.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" })
1394
1438
  )
1395
- ))), /* @__PURE__ */ React16.createElement(
1439
+ ))), /* @__PURE__ */ React18.createElement(
1396
1440
  CanopyModal,
1397
1441
  {
1398
1442
  id: "canopy-modal-nav",
@@ -1404,8 +1448,8 @@ function CanopyHeader(props = {}) {
1404
1448
  closeLabel: "Close navigation",
1405
1449
  closeDataAttr: "nav"
1406
1450
  },
1407
- /* @__PURE__ */ React16.createElement("nav", { className: "canopy-nav-links canopy-modal__nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React16.createElement("a", { key: link.href, href: link.href }, link.label || link.href)))
1408
- ), /* @__PURE__ */ React16.createElement(
1451
+ /* @__PURE__ */ React18.createElement("nav", { className: "canopy-nav-links canopy-modal__nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React18.createElement("a", { key: link.href, href: link.href }, link.label || link.href)))
1452
+ ), /* @__PURE__ */ React18.createElement(
1409
1453
  CanopyModal,
1410
1454
  {
1411
1455
  id: "canopy-modal-search",
@@ -1418,19 +1462,26 @@ function CanopyHeader(props = {}) {
1418
1462
  closeDataAttr: "search",
1419
1463
  bodyClassName: "canopy-modal__body--search"
1420
1464
  },
1421
- /* @__PURE__ */ React16.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })
1422
- ), /* @__PURE__ */ React16.createElement(HeaderScript, null));
1465
+ /* @__PURE__ */ React18.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })
1466
+ ), /* @__PURE__ */ React18.createElement(HeaderScript, null));
1423
1467
  }
1424
1468
 
1425
1469
  // ui/src/layout/CanopyFooter.jsx
1426
- import React17 from "react";
1470
+ import React19 from "react";
1427
1471
  function CanopyFooter({ className = "", children }) {
1428
1472
  const footerClassName = ["canopy-footer", className].filter(Boolean).join(" ");
1429
- return /* @__PURE__ */ React17.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React17.createElement("div", { className: "canopy-footer__inner" }, children));
1473
+ return /* @__PURE__ */ React19.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React19.createElement("div", { className: "canopy-footer__inner" }, children));
1474
+ }
1475
+
1476
+ // ui/src/layout/Container.jsx
1477
+ import React20 from "react";
1478
+ function Container({ className = "", children, ...rest }) {
1479
+ const classes = ["mx-auto", "max-w-content", "w-full", "px-6", className].filter(Boolean).join(" ");
1480
+ return /* @__PURE__ */ React20.createElement("div", { className: classes, ...rest }, children);
1430
1481
  }
1431
1482
 
1432
1483
  // ui/src/search/MdxSearchResults.jsx
1433
- import React18 from "react";
1484
+ import React21 from "react";
1434
1485
  function MdxSearchResults(props) {
1435
1486
  let json = "{}";
1436
1487
  try {
@@ -1438,11 +1489,11 @@ function MdxSearchResults(props) {
1438
1489
  } catch (_) {
1439
1490
  json = "{}";
1440
1491
  }
1441
- return /* @__PURE__ */ React18.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React18.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1492
+ return /* @__PURE__ */ React21.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React21.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1442
1493
  }
1443
1494
 
1444
1495
  // ui/src/search/SearchSummary.jsx
1445
- import React19 from "react";
1496
+ import React22 from "react";
1446
1497
  function SearchSummary(props) {
1447
1498
  let json = "{}";
1448
1499
  try {
@@ -1450,11 +1501,11 @@ function SearchSummary(props) {
1450
1501
  } catch (_) {
1451
1502
  json = "{}";
1452
1503
  }
1453
- return /* @__PURE__ */ React19.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React19.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1504
+ return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1454
1505
  }
1455
1506
 
1456
1507
  // ui/src/search/MdxSearchTabs.jsx
1457
- import React20 from "react";
1508
+ import React23 from "react";
1458
1509
  function MdxSearchTabs(props) {
1459
1510
  let json = "{}";
1460
1511
  try {
@@ -1462,11 +1513,11 @@ function MdxSearchTabs(props) {
1462
1513
  } catch (_) {
1463
1514
  json = "{}";
1464
1515
  }
1465
- return /* @__PURE__ */ React20.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React20.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1516
+ return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1466
1517
  }
1467
1518
 
1468
1519
  // ui/src/search-form/MdxSearchFormModal.jsx
1469
- import React21 from "react";
1520
+ import React24 from "react";
1470
1521
  function MdxSearchFormModal(props = {}) {
1471
1522
  const {
1472
1523
  placeholder = "Search\u2026",
@@ -1482,11 +1533,11 @@ function MdxSearchFormModal(props = {}) {
1482
1533
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1483
1534
  const resolvedSearchPath = resolveSearchPath(searchPath);
1484
1535
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
1485
- return /* @__PURE__ */ React21.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React21.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React21.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React21.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React21.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1536
+ return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React24.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React24.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React24.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1486
1537
  }
1487
1538
 
1488
1539
  // ui/src/iiif/ManifestPrimitives.jsx
1489
- import React22 from "react";
1540
+ import React25 from "react";
1490
1541
  import {
1491
1542
  Label as CloverLabel,
1492
1543
  Metadata as CloverMetadata,
@@ -1511,28 +1562,28 @@ function ensureMetadata(items) {
1511
1562
  function Label({ manifest, label, ...rest }) {
1512
1563
  const intl = label || manifest && manifest.label;
1513
1564
  if (!hasInternationalValue(intl)) return null;
1514
- return /* @__PURE__ */ React22.createElement(CloverLabel, { label: intl, ...rest });
1565
+ return /* @__PURE__ */ React25.createElement(CloverLabel, { label: intl, ...rest });
1515
1566
  }
1516
1567
  function Summary({ manifest, summary, ...rest }) {
1517
1568
  const intl = summary || manifest && manifest.summary;
1518
1569
  if (!hasInternationalValue(intl)) return null;
1519
- return /* @__PURE__ */ React22.createElement(CloverSummary, { summary: intl, ...rest });
1570
+ return /* @__PURE__ */ React25.createElement(CloverSummary, { summary: intl, ...rest });
1520
1571
  }
1521
1572
  function Metadata({ manifest, metadata, ...rest }) {
1522
1573
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
1523
1574
  if (!items.length) return null;
1524
- return /* @__PURE__ */ React22.createElement(CloverMetadata, { metadata: items, ...rest });
1575
+ return /* @__PURE__ */ React25.createElement(CloverMetadata, { metadata: items, ...rest });
1525
1576
  }
1526
1577
  function RequiredStatement({ manifest, requiredStatement, ...rest }) {
1527
1578
  const stmt = requiredStatement || manifest && manifest.requiredStatement;
1528
1579
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
1529
1580
  return null;
1530
1581
  }
1531
- return /* @__PURE__ */ React22.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
1582
+ return /* @__PURE__ */ React25.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
1532
1583
  }
1533
1584
 
1534
1585
  // ui/src/docs/CodeBlock.jsx
1535
- import React23 from "react";
1586
+ import React26 from "react";
1536
1587
  function parseHighlightAttr(attr) {
1537
1588
  if (!attr) return /* @__PURE__ */ new Set();
1538
1589
  const cleaned = String(attr || "").trim();
@@ -1578,10 +1629,10 @@ var highlightBaseStyle = {
1578
1629
  };
1579
1630
  function DocsCodeBlock(props = {}) {
1580
1631
  const { children, ...rest } = props;
1581
- const childArray = React23.Children.toArray(children);
1582
- const codeElement = childArray.find((el) => React23.isValidElement(el));
1632
+ const childArray = React26.Children.toArray(children);
1633
+ const codeElement = childArray.find((el) => React26.isValidElement(el));
1583
1634
  if (!codeElement || !codeElement.props) {
1584
- return React23.createElement("pre", props);
1635
+ return React26.createElement("pre", props);
1585
1636
  }
1586
1637
  const {
1587
1638
  className = "",
@@ -1596,8 +1647,8 @@ function DocsCodeBlock(props = {}) {
1596
1647
  const highlightSet = parseHighlightAttr(highlightAttr);
1597
1648
  const copyAttr = codeProps["data-copy"];
1598
1649
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
1599
- const [copied, setCopied] = React23.useState(false);
1600
- const handleCopy = React23.useCallback(async () => {
1650
+ const [copied, setCopied] = React26.useState(false);
1651
+ const handleCopy = React26.useCallback(async () => {
1601
1652
  const text = rawCode;
1602
1653
  try {
1603
1654
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -1623,7 +1674,7 @@ function DocsCodeBlock(props = {}) {
1623
1674
  borderRadius: "12px",
1624
1675
  overflow: "hidden",
1625
1676
  margin: "1.5rem 0",
1626
- background: "var(--color-brand-100, #e0f2ff)",
1677
+ background: "var(--color-brand-100)",
1627
1678
  fontFamily: "var(--font-mono)",
1628
1679
  fontSize: "0.85rem"
1629
1680
  };
@@ -1633,13 +1684,14 @@ function DocsCodeBlock(props = {}) {
1633
1684
  justifyContent: "space-between",
1634
1685
  padding: "1rem 1.25rem",
1635
1686
  fontWeight: 700,
1636
- background: "var(--color-brand-200, #dbeafe)",
1687
+ background: "var(--color-brand-100)",
1688
+ borderBottom: "1px solid var(--color-brand-200)",
1637
1689
  color: "var(--color-brand-900)"
1638
1690
  };
1639
1691
  const preStyle = {
1640
1692
  margin: 0,
1641
- background: "var(--color-brand-100, #e0f2ff)",
1642
- color: "var(--color-brand-800, #1f2d5c)",
1693
+ background: "var(--color-brand-100)",
1694
+ color: "var(--color-brand-800)",
1643
1695
  lineHeight: 1.55,
1644
1696
  padding: "1rem 0",
1645
1697
  overflowX: "auto"
@@ -1660,20 +1712,20 @@ function DocsCodeBlock(props = {}) {
1660
1712
  const highlight = highlightSet.has(lineNumber);
1661
1713
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
1662
1714
  const displayLine = line === "" ? " " : line;
1663
- return React23.createElement(
1715
+ return React26.createElement(
1664
1716
  "span",
1665
1717
  { key: lineNumber, style },
1666
- React23.createElement("span", { style: lineContentStyle }, displayLine)
1718
+ React26.createElement("span", { style: lineContentStyle }, displayLine)
1667
1719
  );
1668
1720
  });
1669
- return React23.createElement(
1721
+ return React26.createElement(
1670
1722
  "div",
1671
1723
  { style: containerStyle },
1672
- React23.createElement(
1724
+ React26.createElement(
1673
1725
  "div",
1674
1726
  { style: headerStyle },
1675
- React23.createElement("span", null, showFilename ? filename : null),
1676
- enableCopy ? React23.createElement(
1727
+ React26.createElement("span", null, showFilename ? filename : null),
1728
+ enableCopy ? React26.createElement(
1677
1729
  "button",
1678
1730
  {
1679
1731
  type: "button",
@@ -1692,19 +1744,30 @@ function DocsCodeBlock(props = {}) {
1692
1744
  copied ? "Copied" : "Copy"
1693
1745
  ) : null
1694
1746
  ),
1695
- React23.createElement(
1747
+ React26.createElement(
1696
1748
  "pre",
1697
1749
  { ...preRest, className: preClassName, style: mergedPreStyle },
1698
- React23.createElement("code", { style: codeStyle }, lineElements)
1750
+ React26.createElement("code", { style: codeStyle }, lineElements)
1699
1751
  )
1700
1752
  );
1701
1753
  }
1754
+
1755
+ // ui/src/docs/MarkdownTable.jsx
1756
+ import React27 from "react";
1757
+ function MarkdownTable({ className = "", ...rest }) {
1758
+ const merged = ["markdown-table", className].filter(Boolean).join(" ");
1759
+ return /* @__PURE__ */ React27.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React27.createElement("table", { className: merged, ...rest }));
1760
+ }
1702
1761
  export {
1762
+ Button,
1763
+ ButtonWrapper,
1703
1764
  CanopyBrand,
1704
1765
  CanopyFooter,
1705
1766
  CanopyHeader,
1706
1767
  CanopyModal,
1768
+ Container,
1707
1769
  DocsCodeBlock,
1770
+ MarkdownTable as DocsMarkdownTable,
1708
1771
  HelloWorld,
1709
1772
  interstitials_exports as Interstitials,
1710
1773
  Label,