@canopy-iiif/app 0.9.0 → 0.9.2

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.
@@ -479,8 +479,338 @@ function SubNavigation({
479
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")));
480
480
  }
481
481
 
482
- // ui/src/search/MdxSearchResults.jsx
482
+ // ui/src/layout/Layout.jsx
483
+ import React9 from "react";
484
+ import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
485
+
486
+ // ui/src/layout/ContentNavigation.jsx
483
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";
484
814
  function MdxSearchResults(props) {
485
815
  let json = "{}";
486
816
  try {
@@ -488,11 +818,11 @@ function MdxSearchResults(props) {
488
818
  } catch (_) {
489
819
  json = "{}";
490
820
  }
491
- return /* @__PURE__ */ React8.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React8.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 } }));
492
822
  }
493
823
 
494
824
  // ui/src/search/SearchSummary.jsx
495
- import React9 from "react";
825
+ import React11 from "react";
496
826
  function SearchSummary(props) {
497
827
  let json = "{}";
498
828
  try {
@@ -500,11 +830,11 @@ function SearchSummary(props) {
500
830
  } catch (_) {
501
831
  json = "{}";
502
832
  }
503
- return /* @__PURE__ */ React9.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React9.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 } }));
504
834
  }
505
835
 
506
836
  // ui/src/search/MdxSearchTabs.jsx
507
- import React10 from "react";
837
+ import React12 from "react";
508
838
  function MdxSearchTabs(props) {
509
839
  let json = "{}";
510
840
  try {
@@ -512,18 +842,18 @@ function MdxSearchTabs(props) {
512
842
  } catch (_) {
513
843
  json = "{}";
514
844
  }
515
- return /* @__PURE__ */ React10.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React10.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 } }));
516
846
  }
517
847
 
518
848
  // ui/src/search-form/MdxSearchFormModal.jsx
519
- import React14 from "react";
849
+ import React16 from "react";
520
850
 
521
851
  // ui/src/Icons.jsx
522
- import React11 from "react";
523
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React11.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React11.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" }));
524
854
 
525
855
  // ui/src/search/SearchPanelForm.jsx
526
- import React12 from "react";
856
+ import React14 from "react";
527
857
  function readBasePath() {
528
858
  const normalize = (val) => {
529
859
  const raw = typeof val === "string" ? val.trim() : "";
@@ -586,18 +916,18 @@ function SearchPanelForm(props = {}) {
586
916
  clearLabel = "Clear search"
587
917
  } = props || {};
588
918
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
589
- const action = React12.useMemo(
919
+ const action = React14.useMemo(
590
920
  () => resolveSearchPath(searchPath),
591
921
  [searchPath]
592
922
  );
593
- const autoId = typeof React12.useId === "function" ? React12.useId() : void 0;
594
- const [fallbackId] = React12.useState(
923
+ const autoId = typeof React14.useId === "function" ? React14.useId() : void 0;
924
+ const [fallbackId] = React14.useState(
595
925
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
596
926
  );
597
927
  const inputId = inputIdProp || autoId || fallbackId;
598
- const inputRef = React12.useRef(null);
599
- const [hasValue, setHasValue] = React12.useState(false);
600
- const focusInput = React12.useCallback(() => {
928
+ const inputRef = React14.useRef(null);
929
+ const [hasValue, setHasValue] = React14.useState(false);
930
+ const focusInput = React14.useCallback(() => {
601
931
  const el = inputRef.current;
602
932
  if (!el) return;
603
933
  if (document.activeElement === el) return;
@@ -610,7 +940,7 @@ function SearchPanelForm(props = {}) {
610
940
  }
611
941
  }
612
942
  }, []);
613
- const handlePointerDown = React12.useCallback(
943
+ const handlePointerDown = React14.useCallback(
614
944
  (event) => {
615
945
  const target = event.target;
616
946
  if (target && typeof target.closest === "function") {
@@ -622,23 +952,23 @@ function SearchPanelForm(props = {}) {
622
952
  },
623
953
  [focusInput]
624
954
  );
625
- React12.useEffect(() => {
955
+ React14.useEffect(() => {
626
956
  const el = inputRef.current;
627
957
  if (!el) return;
628
958
  if (el.value && el.value.trim()) {
629
959
  setHasValue(true);
630
960
  }
631
961
  }, []);
632
- const handleInputChange = React12.useCallback((event) => {
962
+ const handleInputChange = React14.useCallback((event) => {
633
963
  var _a;
634
964
  const nextHasValue = Boolean(
635
965
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
636
966
  );
637
967
  setHasValue(nextHasValue);
638
968
  }, []);
639
- const handleClear = React12.useCallback((event) => {
969
+ const handleClear = React14.useCallback((event) => {
640
970
  }, []);
641
- const handleClearKey = React12.useCallback(
971
+ const handleClearKey = React14.useCallback(
642
972
  (event) => {
643
973
  if (event.key === "Enter" || event.key === " ") {
644
974
  event.preventDefault();
@@ -647,7 +977,7 @@ function SearchPanelForm(props = {}) {
647
977
  },
648
978
  [handleClear]
649
979
  );
650
- return /* @__PURE__ */ React12.createElement(
980
+ return /* @__PURE__ */ React14.createElement(
651
981
  "form",
652
982
  {
653
983
  action,
@@ -659,7 +989,7 @@ function SearchPanelForm(props = {}) {
659
989
  onPointerDown: handlePointerDown,
660
990
  "data-has-value": hasValue ? "1" : "0"
661
991
  },
662
- /* @__PURE__ */ React12.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React12.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React12.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(
663
993
  "input",
664
994
  {
665
995
  id: inputId,
@@ -675,7 +1005,7 @@ function SearchPanelForm(props = {}) {
675
1005
  onInput: handleInputChange
676
1006
  }
677
1007
  )),
678
- hasValue ? /* @__PURE__ */ React12.createElement(
1008
+ hasValue ? /* @__PURE__ */ React14.createElement(
679
1009
  "button",
680
1010
  {
681
1011
  type: "button",
@@ -688,32 +1018,32 @@ function SearchPanelForm(props = {}) {
688
1018
  },
689
1019
  "\xD7"
690
1020
  ) : null,
691
- /* @__PURE__ */ React12.createElement(
1021
+ /* @__PURE__ */ React14.createElement(
692
1022
  "button",
693
1023
  {
694
1024
  type: "submit",
695
1025
  "data-canopy-search-form-trigger": "submit",
696
1026
  className: "canopy-search-form__submit"
697
1027
  },
698
- /* @__PURE__ */ React12.createElement("span", null, text),
699
- /* @__PURE__ */ React12.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React12.createElement("span", null, "\u2318"), /* @__PURE__ */ React12.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"))
700
1030
  )
701
1031
  );
702
1032
  }
703
1033
 
704
1034
  // ui/src/search/SearchPanelTeaserResults.jsx
705
- import React13 from "react";
1035
+ import React15 from "react";
706
1036
  function SearchPanelTeaserResults(props = {}) {
707
1037
  const { style, className } = props || {};
708
1038
  const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
709
- return /* @__PURE__ */ React13.createElement(
1039
+ return /* @__PURE__ */ React15.createElement(
710
1040
  "div",
711
1041
  {
712
1042
  "data-canopy-search-form-panel": true,
713
1043
  className: classes || void 0,
714
1044
  style
715
1045
  },
716
- /* @__PURE__ */ React13.createElement("div", { id: "cplist" })
1046
+ /* @__PURE__ */ React15.createElement("div", { id: "cplist" })
717
1047
  );
718
1048
  }
719
1049
 
@@ -733,11 +1063,11 @@ function MdxSearchFormModal(props = {}) {
733
1063
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
734
1064
  const resolvedSearchPath = resolveSearchPath(searchPath);
735
1065
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
736
- return /* @__PURE__ */ React14.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React14.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React14.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React14.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React14.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) } }));
737
1067
  }
738
1068
 
739
1069
  // ui/src/search/SearchPanel.jsx
740
- import React15 from "react";
1070
+ import React17 from "react";
741
1071
  function SearchPanel(props = {}) {
742
1072
  const {
743
1073
  placeholder = "Search\u2026",
@@ -754,11 +1084,11 @@ function SearchPanel(props = {}) {
754
1084
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
755
1085
  const resolvedSearchPath = resolveSearchPath(searchPath);
756
1086
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
757
- 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) } }));
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) } }));
758
1088
  }
759
1089
 
760
1090
  // ui/src/iiif/ManifestPrimitives.jsx
761
- import React16 from "react";
1091
+ import React18 from "react";
762
1092
  import {
763
1093
  Label as CloverLabel,
764
1094
  Metadata as CloverMetadata,
@@ -783,29 +1113,30 @@ function ensureMetadata(items) {
783
1113
  function Label({ manifest, label, ...rest }) {
784
1114
  const intl = label || manifest && manifest.label;
785
1115
  if (!hasInternationalValue(intl)) return null;
786
- return /* @__PURE__ */ React16.createElement(CloverLabel, { label: intl, ...rest });
1116
+ return /* @__PURE__ */ React18.createElement(CloverLabel, { label: intl, ...rest });
787
1117
  }
788
1118
  function Summary({ manifest, summary, ...rest }) {
789
1119
  const intl = summary || manifest && manifest.summary;
790
1120
  if (!hasInternationalValue(intl)) return null;
791
- return /* @__PURE__ */ React16.createElement(CloverSummary, { summary: intl, ...rest });
1121
+ return /* @__PURE__ */ React18.createElement(CloverSummary, { summary: intl, ...rest });
792
1122
  }
793
1123
  function Metadata({ manifest, metadata, ...rest }) {
794
1124
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
795
1125
  if (!items.length) return null;
796
- return /* @__PURE__ */ React16.createElement(CloverMetadata, { metadata: items, ...rest });
1126
+ return /* @__PURE__ */ React18.createElement(CloverMetadata, { metadata: items, ...rest });
797
1127
  }
798
1128
  function RequiredStatement({ manifest, requiredStatement, ...rest }) {
799
1129
  const stmt = requiredStatement || manifest && manifest.requiredStatement;
800
1130
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
801
1131
  return null;
802
1132
  }
803
- return /* @__PURE__ */ React16.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
1133
+ return /* @__PURE__ */ React18.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
804
1134
  }
805
1135
  export {
806
1136
  HelloWorld,
807
1137
  interstitials_exports as Interstitials,
808
1138
  Label,
1139
+ Layout,
809
1140
  Metadata,
810
1141
  MdxRelatedItems as RelatedItems,
811
1142
  RequiredStatement,