@canopy-iiif/app 1.9.21 → 1.10.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.
@@ -656,6 +656,7 @@ async function mountImageStory(element, props = {}) {
656
656
  // ui/src/iiif/ImageStory.jsx
657
657
  var DEFAULT_IMAGE_STORY_HEIGHT = 600;
658
658
  var NUMERIC_HEIGHT_PATTERN = /^[+-]?(?:\d+|\d*\.\d+)$/;
659
+ var SIZE_EPSILON = 1;
659
660
  function resolveContainerHeight(value) {
660
661
  if (typeof value === "number" && Number.isFinite(value)) {
661
662
  return `${value}px`;
@@ -706,6 +707,7 @@ var ImageStory = (props = {}) => {
706
707
  let mounted = false;
707
708
  let resizeObserver = null;
708
709
  let pollId = null;
710
+ let lastKnownSize = null;
709
711
  const payload = sanitizeImageStoryProps({
710
712
  iiifContent,
711
713
  disablePanAndZoom,
@@ -734,12 +736,39 @@ var ImageStory = (props = {}) => {
734
736
  pollId = null;
735
737
  }
736
738
  };
737
- const hasUsableSize = () => {
738
- if (!node) return false;
739
+ const measureSize = () => {
740
+ if (!node) return null;
739
741
  const rect = node.getBoundingClientRect();
740
- const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth;
741
- const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight;
742
- return width > 2 && height2 > 2;
742
+ const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth || 0;
743
+ const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight || 0;
744
+ return { width, height: height2 };
745
+ };
746
+ const hasUsableSize = () => {
747
+ const size = measureSize();
748
+ if (!size) return false;
749
+ const usable = size.width > 2 && size.height > 2;
750
+ if (usable) {
751
+ lastKnownSize = size;
752
+ }
753
+ return usable;
754
+ };
755
+ const hasMeaningfulSizeChange = () => {
756
+ const size = measureSize();
757
+ if (!size) return false;
758
+ if (size.width <= 2 || size.height <= 2) {
759
+ return true;
760
+ }
761
+ if (!lastKnownSize) {
762
+ lastKnownSize = size;
763
+ return true;
764
+ }
765
+ const widthDelta = Math.abs(size.width - lastKnownSize.width);
766
+ const heightDelta = Math.abs(size.height - lastKnownSize.height);
767
+ if (widthDelta > SIZE_EPSILON || heightDelta > SIZE_EPSILON) {
768
+ lastKnownSize = size;
769
+ return true;
770
+ }
771
+ return false;
743
772
  };
744
773
  const mountViewer = () => {
745
774
  if (!node || mounted || cancelled) return false;
@@ -755,8 +784,9 @@ var ImageStory = (props = {}) => {
755
784
  });
756
785
  return true;
757
786
  };
758
- if (!mountViewer()) {
759
- if (typeof window !== "undefined" && typeof window.ResizeObserver === "function") {
787
+ const scheduleWatchers = () => {
788
+ if (mounted || cancelled) return;
789
+ if (!resizeObserver && typeof window !== "undefined" && typeof window.ResizeObserver === "function") {
760
790
  resizeObserver = new window.ResizeObserver(() => {
761
791
  if (mounted || cancelled) return;
762
792
  mountViewer();
@@ -775,12 +805,48 @@ var ImageStory = (props = {}) => {
775
805
  }
776
806
  }, 200);
777
807
  };
778
- schedulePoll();
808
+ if (!pollId) {
809
+ schedulePoll();
810
+ }
811
+ };
812
+ const beginMounting = () => {
813
+ if (!mountViewer()) {
814
+ scheduleWatchers();
815
+ }
816
+ };
817
+ const remountViewer = () => {
818
+ if (cancelled) return;
819
+ if (mounted) {
820
+ mounted = false;
821
+ destroyCleanup();
822
+ }
823
+ beginMounting();
824
+ };
825
+ beginMounting();
826
+ const handleGalleryModalChange = (event) => {
827
+ if (!node || !event || typeof document === "undefined") return;
828
+ const detail = event.detail || {};
829
+ if (detail.state !== "open") return;
830
+ const modal = detail.modal || (detail.modalId ? document.getElementById(detail.modalId) : null);
831
+ if (!modal || !modal.contains(node)) return;
832
+ if (!mounted) return;
833
+ if (hasMeaningfulSizeChange()) {
834
+ remountViewer();
835
+ }
836
+ };
837
+ if (typeof window !== "undefined" && window.addEventListener) {
838
+ window.addEventListener("canopy:gallery:modal-change", handleGalleryModalChange);
779
839
  }
780
840
  return () => {
781
841
  cancelled = true;
782
842
  disconnectWatchers();
783
843
  destroyCleanup();
844
+ if (typeof window !== "undefined" && window.removeEventListener) {
845
+ window.removeEventListener(
846
+ "canopy:gallery:modal-change",
847
+ handleGalleryModalChange
848
+ );
849
+ }
784
850
  };
785
851
  }, [iiifContent, disablePanAndZoom, pointOfInterestSvgUrl, viewerOptions]);
786
852
  return /* @__PURE__ */ React6.createElement(
@@ -953,8 +1019,8 @@ function formatTemplate(template, replacements = {}) {
953
1019
  });
954
1020
  }
955
1021
  function useLocaleMessages() {
956
- const PageContext2 = getSafePageContext();
957
- const context = PageContext2 ? React11.useContext(PageContext2) : null;
1022
+ const PageContext3 = getSafePageContext();
1023
+ const context = PageContext3 ? React11.useContext(PageContext3) : null;
958
1024
  const siteMessages = context && context.site && context.site.localeMessages && typeof context.site.localeMessages === "object" ? context.site.localeMessages : null;
959
1025
  return siteMessages || readRuntimeMessages();
960
1026
  }
@@ -1130,8 +1196,8 @@ function Hero({
1130
1196
  const { getString } = useLocale();
1131
1197
  const normalizedVariant = normalizeVariant(variant);
1132
1198
  const isBreadcrumbVariant = normalizedVariant === "breadcrumb";
1133
- const PageContext2 = navigationHelpers && typeof navigationHelpers.getPageContext === "function" ? navigationHelpers.getPageContext() : null;
1134
- const pageContext = PageContext2 ? React12.useContext(PageContext2) : null;
1199
+ const PageContext3 = navigationHelpers && typeof navigationHelpers.getPageContext === "function" ? navigationHelpers.getPageContext() : null;
1200
+ const pageContext = PageContext3 ? React12.useContext(PageContext3) : null;
1135
1201
  let orderedSlides = [];
1136
1202
  if (!isBreadcrumbVariant) {
1137
1203
  const resolved = resolveFeaturedItem({ item, index, random });
@@ -1528,8 +1594,8 @@ function SubNavigation({
1528
1594
  heading,
1529
1595
  ariaLabel
1530
1596
  }) {
1531
- const PageContext2 = navigationHelpers2 && navigationHelpers2.getPageContext ? navigationHelpers2.getPageContext() : null;
1532
- const context = PageContext2 ? React14.useContext(PageContext2) : null;
1597
+ const PageContext3 = navigationHelpers2 && navigationHelpers2.getPageContext ? navigationHelpers2.getPageContext() : null;
1598
+ const context = PageContext3 ? React14.useContext(PageContext3) : null;
1533
1599
  const contextNavigation = context && context.navigation ? context.navigation : null;
1534
1600
  const contextPage = context && context.page ? context.page : null;
1535
1601
  const effectiveNavigation = navigationProp || contextNavigation;
@@ -1580,12 +1646,39 @@ function SubNavigation({
1580
1646
  );
1581
1647
  }
1582
1648
 
1583
- // ui/src/layout/Layout.jsx
1584
- import React16 from "react";
1585
- import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
1586
-
1587
1649
  // ui/src/layout/ContentNavigation.jsx
1588
1650
  import React15 from "react";
1651
+
1652
+ // ui/src/layout/headingUtils.js
1653
+ function buildHeadingTree(headings) {
1654
+ if (!Array.isArray(headings) || !headings.length) return [];
1655
+ const root = [];
1656
+ const stack = [];
1657
+ headings.forEach((heading) => {
1658
+ if (!heading || typeof heading !== "object") return;
1659
+ const depth = typeof heading.depth === "number" ? heading.depth : heading.level;
1660
+ if (typeof depth !== "number" || depth < 2) return;
1661
+ const entry = {
1662
+ id: heading.id || heading.slug || heading.title,
1663
+ title: heading.title || heading.text || heading.id,
1664
+ depth,
1665
+ children: []
1666
+ };
1667
+ while (stack.length && stack[stack.length - 1].depth >= entry.depth) {
1668
+ stack.pop();
1669
+ }
1670
+ if (!stack.length) {
1671
+ root.push(entry);
1672
+ } else {
1673
+ stack[stack.length - 1].children.push(entry);
1674
+ }
1675
+ stack.push(entry);
1676
+ });
1677
+ return root;
1678
+ }
1679
+
1680
+ // ui/src/layout/ContentNavigation.jsx
1681
+ var PageContext = typeof getSafePageContext === "function" ? getSafePageContext() : null;
1589
1682
  var SCROLL_OFFSET_REM = 1.618;
1590
1683
  var MAX_HEADING_DEPTH = 3;
1591
1684
  function resolveDepth(value, fallback = 1) {
@@ -1597,28 +1690,56 @@ function buildNodeKey(id, parentKey, index) {
1597
1690
  return `${parentKey || "section"}-${sanitized || index}`;
1598
1691
  }
1599
1692
  function ContentNavigation({
1600
- items = [],
1693
+ items: itemsProp = [],
1601
1694
  className = "",
1602
1695
  style = {},
1603
1696
  heading,
1604
1697
  headingId,
1605
1698
  pageTitle,
1606
- ariaLabel
1699
+ ariaLabel,
1700
+ collapsible = false
1607
1701
  }) {
1608
1702
  const { getString, formatString } = useLocale();
1703
+ const context = PageContext ? React15.useContext(PageContext) : null;
1704
+ const contextHeadings = React15.useMemo(() => {
1705
+ const headings = context && context.page ? context.page.headings : null;
1706
+ return Array.isArray(headings) ? headings : [];
1707
+ }, [context]);
1708
+ const resolvedItems = React15.useMemo(() => {
1709
+ if (itemsProp && itemsProp.length) return itemsProp;
1710
+ return buildHeadingTree(contextHeadings);
1711
+ }, [itemsProp, contextHeadings]);
1712
+ const topHeading = React15.useMemo(() => {
1713
+ return contextHeadings.find((entry) => {
1714
+ const depth = entry && (entry.depth || entry.level);
1715
+ return depth === 1;
1716
+ }) || null;
1717
+ }, [contextHeadings]);
1718
+ const resolvedHeadingId = headingId || topHeading && topHeading.id || null;
1719
+ const resolvedPageTitle = pageTitle || (context && context.page ? context.page.title : null) || null;
1720
+ const inferredHeading = topHeading && (topHeading.title || topHeading.text) || null;
1609
1721
  const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
1610
1722
  const savedDepthsRef = React15.useRef(null);
1611
- const [isExpanded, setIsExpanded] = React15.useState(false);
1723
+ const [internalExpanded, setInternalExpanded] = React15.useState(
1724
+ collapsible ? false : true
1725
+ );
1726
+ React15.useEffect(() => {
1727
+ setInternalExpanded(collapsible ? false : true);
1728
+ }, [collapsible]);
1612
1729
  const handleToggle = React15.useCallback(() => {
1613
- setIsExpanded((prev) => !prev);
1614
- }, []);
1615
- if ((!items || !items.length) && !headingId) return null;
1730
+ if (!collapsible) return;
1731
+ setInternalExpanded((prev) => !prev);
1732
+ }, [collapsible]);
1733
+ const isExpanded = collapsible ? internalExpanded : true;
1734
+ if ((!resolvedItems || !resolvedItems.length) && !resolvedHeadingId)
1735
+ return null;
1616
1736
  const combinedClassName = [
1617
1737
  "canopy-sub-navigation canopy-content-navigation",
1618
1738
  isExpanded ? "canopy-content-navigation--expanded" : "canopy-content-navigation--collapsed",
1739
+ !collapsible ? "canopy-content-navigation--static" : null,
1619
1740
  className
1620
1741
  ].filter(Boolean).join(" ");
1621
- const effectiveHeading = heading || pageTitle || null;
1742
+ const effectiveHeading = heading || inferredHeading || resolvedPageTitle || null;
1622
1743
  const fallbackNavLabel = getString(
1623
1744
  "common.nouns.section_navigation",
1624
1745
  "Section navigation"
@@ -1666,8 +1787,8 @@ function ContentNavigation({
1666
1787
  const headingEntries = React15.useMemo(() => {
1667
1788
  const entries = [];
1668
1789
  const seen = /* @__PURE__ */ new Set();
1669
- if (headingId) {
1670
- const topId = String(headingId);
1790
+ if (resolvedHeadingId) {
1791
+ const topId = String(resolvedHeadingId);
1671
1792
  entries.push({ id: topId, depth: 1 });
1672
1793
  seen.add(topId);
1673
1794
  }
@@ -1687,10 +1808,10 @@ function ContentNavigation({
1687
1808
  if (node.children && node.children.length) pushNodes(node.children);
1688
1809
  });
1689
1810
  };
1690
- pushNodes(items);
1811
+ pushNodes(resolvedItems);
1691
1812
  return entries;
1692
- }, [headingId, items, getSavedDepth]);
1693
- const fallbackId = headingEntries.length ? headingEntries[0].id : headingId || null;
1813
+ }, [resolvedHeadingId, resolvedItems, getSavedDepth]);
1814
+ const fallbackId = headingEntries.length ? headingEntries[0].id : resolvedHeadingId || null;
1694
1815
  const [activeId, setActiveId] = React15.useState(fallbackId);
1695
1816
  const activeIdRef = React15.useRef(activeId);
1696
1817
  React15.useEffect(() => {
@@ -1802,7 +1923,7 @@ function ContentNavigation({
1802
1923
  }
1803
1924
  }
1804
1925
  if (!Number.isFinite(top) || top < 0 || options.scrollToTop) top = 0;
1805
- const nextId = targetId && targetId !== "top" ? targetId : ((_a = headingEntries[0]) == null ? void 0 : _a.id) || headingId || null;
1926
+ const nextId = targetId && targetId !== "top" ? targetId : ((_a = headingEntries[0]) == null ? void 0 : _a.id) || resolvedHeadingId || null;
1806
1927
  if (nextId) {
1807
1928
  activeIdRef.current = nextId;
1808
1929
  setActiveId(nextId);
@@ -1813,7 +1934,7 @@ function ContentNavigation({
1813
1934
  window.scrollTo(0, top);
1814
1935
  }
1815
1936
  },
1816
- [computeOffsetPx, headingEntries, headingId, isBrowser]
1937
+ [computeOffsetPx, headingEntries, resolvedHeadingId, isBrowser]
1817
1938
  );
1818
1939
  const navTreeRoot = React15.useMemo(() => {
1819
1940
  function mapNodes(nodes2, parentKey = "section") {
@@ -1847,13 +1968,19 @@ function ContentNavigation({
1847
1968
  };
1848
1969
  }).filter(Boolean);
1849
1970
  }
1850
- const nodes = mapNodes(items, "section");
1971
+ const nodes = mapNodes(resolvedItems, "section");
1851
1972
  return {
1852
1973
  slug: "content-nav-root",
1853
- title: effectiveHeading || pageTitle || onThisPageLabel,
1974
+ title: effectiveHeading || resolvedPageTitle || onThisPageLabel,
1854
1975
  children: nodes
1855
1976
  };
1856
- }, [items, effectiveHeading, pageTitle, activeId, getSavedDepth]);
1977
+ }, [
1978
+ resolvedItems,
1979
+ effectiveHeading,
1980
+ resolvedPageTitle,
1981
+ activeId,
1982
+ getSavedDepth
1983
+ ]);
1857
1984
  return /* @__PURE__ */ React15.createElement(
1858
1985
  "nav",
1859
1986
  {
@@ -1862,7 +1989,7 @@ function ContentNavigation({
1862
1989
  "aria-label": navLabel,
1863
1990
  "data-canopy-content-nav": "true"
1864
1991
  },
1865
- /* @__PURE__ */ React15.createElement(
1992
+ collapsible ? /* @__PURE__ */ React15.createElement(
1866
1993
  "button",
1867
1994
  {
1868
1995
  type: "button",
@@ -1951,7 +2078,7 @@ function ContentNavigation({
1951
2078
  /* @__PURE__ */ React15.createElement("span", { className: "sr-only" }, toggleSrLabel)
1952
2079
  ),
1953
2080
  /* @__PURE__ */ React15.createElement("span", { className: "sr-only", "data-canopy-content-nav-toggle-sr": "true" }, toggleSrLabel)
1954
- ),
2081
+ ) : null,
1955
2082
  /* @__PURE__ */ React15.createElement(
1956
2083
  NavigationTree,
1957
2084
  {
@@ -1964,42 +2091,8 @@ function ContentNavigation({
1964
2091
  );
1965
2092
  }
1966
2093
 
1967
- // ui/src/layout/Layout.jsx
1968
- function buildHeadingTree(headings) {
1969
- if (!Array.isArray(headings) || !headings.length) return [];
1970
- const root = [];
1971
- const stack = [];
1972
- headings.forEach((heading) => {
1973
- if (!heading || typeof heading !== "object") return;
1974
- const depth = typeof heading.depth === "number" ? heading.depth : heading.level;
1975
- if (typeof depth !== "number" || depth < 2) return;
1976
- const entry = {
1977
- id: heading.id || heading.slug || heading.title,
1978
- title: heading.title || heading.text || heading.id,
1979
- depth,
1980
- children: []
1981
- };
1982
- while (stack.length && stack[stack.length - 1].depth >= entry.depth) {
1983
- stack.pop();
1984
- }
1985
- if (!stack.length) {
1986
- root.push(entry);
1987
- } else {
1988
- stack[stack.length - 1].children.push(entry);
1989
- }
1990
- stack.push(entry);
1991
- });
1992
- return root;
1993
- }
1994
- function buildNavigationAside(sidebar, className) {
1995
- if (!sidebar) {
1996
- return /* @__PURE__ */ React16.createElement(SubNavigation, { className });
1997
- }
1998
- if (typeof sidebar === "function") {
1999
- return React16.createElement(sidebar);
2000
- }
2001
- return sidebar;
2002
- }
2094
+ // ui/src/layout/ContentNavigationScript.jsx
2095
+ import React16 from "react";
2003
2096
  function ContentNavigationScript() {
2004
2097
  const code = `
2005
2098
  (function () {
@@ -2085,16 +2178,32 @@ function ContentNavigationScript() {
2085
2178
  function setupFloatingState(root) {
2086
2179
  if (!root || typeof IntersectionObserver !== 'function') return;
2087
2180
  if (root.__canopyContentNavFloating) return;
2181
+ var nav = root.querySelector('[data-canopy-content-nav]');
2182
+ if (!nav) return;
2088
2183
  var sentinel = root.querySelector('[data-canopy-content-nav-sentinel]');
2184
+ if (!sentinel) {
2185
+ sentinel = document.createElement('div');
2186
+ sentinel.setAttribute('aria-hidden', 'true');
2187
+ sentinel.setAttribute('data-canopy-content-nav-sentinel', 'true');
2188
+ root.insertBefore(sentinel, nav);
2189
+ }
2089
2190
  var placeholder = root.querySelector('[data-canopy-content-nav-placeholder]');
2090
- var nav = root.querySelector('[data-canopy-content-nav]');
2091
- if (!sentinel || !nav) return;
2191
+ if (!placeholder) {
2192
+ placeholder = document.createElement('div');
2193
+ placeholder.setAttribute('aria-hidden', 'true');
2194
+ placeholder.setAttribute('data-canopy-content-nav-placeholder', 'true');
2195
+ if (nav.nextSibling) {
2196
+ root.insertBefore(placeholder, nav.nextSibling);
2197
+ } else {
2198
+ root.appendChild(placeholder);
2199
+ }
2200
+ }
2092
2201
  root.__canopyContentNavFloating = true;
2093
2202
 
2094
2203
  function syncPosition() {
2095
2204
  try {
2096
2205
  var rect = root.getBoundingClientRect();
2097
- nav.style.setProperty('--canopy-content-nav-fixed-right', '1.618rem');
2206
+ nav.style.setProperty('--canopy-content-nav-fixed-left', rect.left + 'px');
2098
2207
  nav.style.setProperty('--canopy-content-nav-fixed-width', rect.width + 'px');
2099
2208
  if (placeholder) placeholder.style.width = rect.width + 'px';
2100
2209
  } catch (_) {}
@@ -2266,10 +2375,44 @@ function ContentNavigationScript() {
2266
2375
  }
2267
2376
 
2268
2377
  ready(function () {
2269
- var roots = Array.prototype.slice.call(
2270
- document.querySelectorAll('[data-canopy-content-nav-root]')
2378
+ var rootSet = new Set();
2379
+ var navNodes = Array.prototype.slice.call(
2380
+ document.querySelectorAll('[data-canopy-content-nav]')
2271
2381
  );
2382
+ navNodes.forEach(function (nav) {
2383
+ if (!nav || !nav.closest) return;
2384
+ var root = nav.closest('[data-canopy-content-nav-root]');
2385
+ if (!root) {
2386
+ root = nav.parentElement || nav;
2387
+ if (root && !root.hasAttribute('data-canopy-content-nav-root')) {
2388
+ root.setAttribute('data-canopy-content-nav-root', 'true');
2389
+ }
2390
+ }
2391
+ if (root) rootSet.add(root);
2392
+ });
2393
+
2394
+ var roots = Array.from(rootSet);
2272
2395
  if (!roots.length) return;
2396
+
2397
+ var collapsibleRoots = [];
2398
+ roots.forEach(function (root) {
2399
+ var nav = root.querySelector('[data-canopy-content-nav]');
2400
+ if (!nav) return;
2401
+ var isStatic = nav.classList.contains('canopy-content-navigation--static');
2402
+ if (isStatic) {
2403
+ root.classList.remove('is-collapsed');
2404
+ nav.classList.add('canopy-content-navigation--expanded');
2405
+ nav.classList.remove('canopy-content-navigation--collapsed');
2406
+ nav.setAttribute('data-expanded', 'true');
2407
+ } else {
2408
+ collapsibleRoots.push(root);
2409
+ }
2410
+ setupFloatingState(root);
2411
+ setupActiveHeadingWatcher(root);
2412
+ });
2413
+
2414
+ if (!collapsibleRoots.length) return;
2415
+
2273
2416
  var stored = getStored();
2274
2417
  var collapsed = true;
2275
2418
  var isDesktop = false;
@@ -2289,7 +2432,7 @@ function ContentNavigationScript() {
2289
2432
 
2290
2433
  function sync(next) {
2291
2434
  collapsed = !!next;
2292
- roots.forEach(function (root) {
2435
+ collapsibleRoots.forEach(function (root) {
2293
2436
  applyState(root, collapsed);
2294
2437
  });
2295
2438
  setStored(collapsed ? '1' : '0');
@@ -2297,7 +2440,7 @@ function ContentNavigationScript() {
2297
2440
 
2298
2441
  sync(collapsed);
2299
2442
 
2300
- roots.forEach(function (root) {
2443
+ collapsibleRoots.forEach(function (root) {
2301
2444
  var toggle = root.querySelector('[data-canopy-content-nav-toggle]');
2302
2445
  if (!toggle) return;
2303
2446
  toggle.addEventListener('click', function (event) {
@@ -2305,16 +2448,23 @@ function ContentNavigationScript() {
2305
2448
  sync(!collapsed);
2306
2449
  });
2307
2450
  });
2308
-
2309
- roots.forEach(function (root) {
2310
- setupFloatingState(root);
2311
- setupActiveHeadingWatcher(root);
2312
- });
2313
2451
  });
2314
2452
  })();
2315
2453
  `;
2316
2454
  return /* @__PURE__ */ React16.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
2317
2455
  }
2456
+
2457
+ // ui/src/layout/Layout.jsx
2458
+ import React17 from "react";
2459
+ function buildNavigationAside(sidebar, className) {
2460
+ if (!sidebar) {
2461
+ return /* @__PURE__ */ React17.createElement(SubNavigation, { className });
2462
+ }
2463
+ if (typeof sidebar === "function") {
2464
+ return React17.createElement(sidebar);
2465
+ }
2466
+ return sidebar;
2467
+ }
2318
2468
  function Layout({
2319
2469
  children,
2320
2470
  sidebar,
@@ -2327,27 +2477,27 @@ function Layout({
2327
2477
  contentNavigationClassName = "",
2328
2478
  ...rest
2329
2479
  }) {
2330
- const PageContext2 = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
2331
- const context = PageContext2 ? React16.useContext(PageContext2) : null;
2332
- const pageHeadings = React16.useMemo(() => {
2480
+ const PageContext3 = typeof getSafePageContext === "function" ? getSafePageContext() : null;
2481
+ const context = PageContext3 ? React17.useContext(PageContext3) : null;
2482
+ const pageHeadings = React17.useMemo(() => {
2333
2483
  const headings = context && context.page ? context.page.headings : null;
2334
2484
  return Array.isArray(headings) ? headings : [];
2335
2485
  }, [context]);
2336
- const contentHeading = React16.useMemo(() => {
2486
+ const contentHeading = React17.useMemo(() => {
2337
2487
  const first = pageHeadings.find((heading) => {
2338
2488
  const depth = heading && (heading.depth || heading.level);
2339
2489
  return depth === 1;
2340
2490
  });
2341
2491
  return first && first.title ? first.title : null;
2342
2492
  }, [pageHeadings]);
2343
- const headingAnchorId = React16.useMemo(() => {
2493
+ const headingAnchorId = React17.useMemo(() => {
2344
2494
  const first = pageHeadings.find((heading) => {
2345
2495
  const depth = heading && (heading.depth || heading.level);
2346
2496
  return depth === 1;
2347
2497
  });
2348
2498
  return first && first.id ? first.id : null;
2349
2499
  }, [pageHeadings]);
2350
- const headingTree = React16.useMemo(
2500
+ const headingTree = React17.useMemo(
2351
2501
  () => buildHeadingTree(pageHeadings),
2352
2502
  [pageHeadings]
2353
2503
  );
@@ -2372,50 +2522,37 @@ function Layout({
2372
2522
  contentNavigationClassName
2373
2523
  ].filter(Boolean).join(" ");
2374
2524
  const sidebarNode = showLeftColumn ? buildNavigationAside(sidebar, sidebarClassName) : null;
2375
- return /* @__PURE__ */ React16.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React16.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React16.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
2525
+ return /* @__PURE__ */ React17.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React17.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React17.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(
2376
2526
  "aside",
2377
2527
  {
2378
2528
  className: contentNavigationAsideClassName,
2379
2529
  "data-canopy-content-nav-root": "true"
2380
2530
  },
2381
- /* @__PURE__ */ React16.createElement(
2382
- "div",
2383
- {
2384
- "data-canopy-content-nav-sentinel": "true",
2385
- "aria-hidden": "true"
2386
- }
2387
- ),
2388
- /* @__PURE__ */ React16.createElement(
2531
+ /* @__PURE__ */ React17.createElement(
2389
2532
  ContentNavigation,
2390
2533
  {
2391
2534
  items: headingTree,
2392
2535
  heading: contentHeading || void 0,
2393
2536
  headingId: headingAnchorId || void 0,
2394
- pageTitle: context && context.page ? context.page.title : void 0
2395
- }
2396
- ),
2397
- /* @__PURE__ */ React16.createElement(
2398
- "div",
2399
- {
2400
- "data-canopy-content-nav-placeholder": "true",
2401
- "aria-hidden": "true"
2537
+ pageTitle: context && context.page ? context.page.title : void 0,
2538
+ collapsible: true
2402
2539
  }
2403
2540
  )
2404
- ), /* @__PURE__ */ React16.createElement(ContentNavigationScript, null)) : null);
2541
+ ), /* @__PURE__ */ React17.createElement(ContentNavigationScript, null)) : null);
2405
2542
  }
2406
2543
 
2407
2544
  // ui/src/layout/CanopyHeader.jsx
2408
- import React25 from "react";
2545
+ import React26 from "react";
2409
2546
 
2410
2547
  // ui/src/search/SearchPanel.jsx
2411
- import React20 from "react";
2548
+ import React21 from "react";
2412
2549
 
2413
2550
  // ui/src/Icons.jsx
2414
- import React17 from "react";
2415
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React17.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", "aria-hidden": "true", focusable: "false", ...props }, /* @__PURE__ */ React17.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" }));
2551
+ import React18 from "react";
2552
+ var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React18.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", "aria-hidden": "true", focusable: "false", ...props }, /* @__PURE__ */ React18.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" }));
2416
2553
 
2417
2554
  // ui/src/search/SearchPanelForm.jsx
2418
- import React18 from "react";
2555
+ import React19 from "react";
2419
2556
  function readBasePath2() {
2420
2557
  const normalize = (val) => {
2421
2558
  const raw = typeof val === "string" ? val.trim() : "";
@@ -2487,18 +2624,18 @@ function SearchPanelForm(props = {}) {
2487
2624
  { content: searchLabel }
2488
2625
  );
2489
2626
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonText;
2490
- const action = React18.useMemo(
2627
+ const action = React19.useMemo(
2491
2628
  () => resolveSearchPath(searchPath),
2492
2629
  [searchPath]
2493
2630
  );
2494
- const autoId = typeof React18.useId === "function" ? React18.useId() : void 0;
2495
- const [fallbackId] = React18.useState(
2631
+ const autoId = typeof React19.useId === "function" ? React19.useId() : void 0;
2632
+ const [fallbackId] = React19.useState(
2496
2633
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
2497
2634
  );
2498
2635
  const inputId = inputIdProp || autoId || fallbackId;
2499
- const inputRef = React18.useRef(null);
2500
- const [hasValue, setHasValue] = React18.useState(false);
2501
- const focusInput = React18.useCallback(() => {
2636
+ const inputRef = React19.useRef(null);
2637
+ const [hasValue, setHasValue] = React19.useState(false);
2638
+ const focusInput = React19.useCallback(() => {
2502
2639
  const el = inputRef.current;
2503
2640
  if (!el) return;
2504
2641
  if (document.activeElement === el) return;
@@ -2511,7 +2648,7 @@ function SearchPanelForm(props = {}) {
2511
2648
  }
2512
2649
  }
2513
2650
  }, []);
2514
- const handlePointerDown = React18.useCallback(
2651
+ const handlePointerDown = React19.useCallback(
2515
2652
  (event) => {
2516
2653
  const target = event.target;
2517
2654
  if (target && typeof target.closest === "function") {
@@ -2523,23 +2660,23 @@ function SearchPanelForm(props = {}) {
2523
2660
  },
2524
2661
  [focusInput]
2525
2662
  );
2526
- React18.useEffect(() => {
2663
+ React19.useEffect(() => {
2527
2664
  const el = inputRef.current;
2528
2665
  if (!el) return;
2529
2666
  if (el.value && el.value.trim()) {
2530
2667
  setHasValue(true);
2531
2668
  }
2532
2669
  }, []);
2533
- const handleInputChange = React18.useCallback((event) => {
2670
+ const handleInputChange = React19.useCallback((event) => {
2534
2671
  var _a;
2535
2672
  const nextHasValue = Boolean(
2536
2673
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
2537
2674
  );
2538
2675
  setHasValue(nextHasValue);
2539
2676
  }, []);
2540
- const handleClear = React18.useCallback((event) => {
2677
+ const handleClear = React19.useCallback((event) => {
2541
2678
  }, []);
2542
- const handleClearKey = React18.useCallback(
2679
+ const handleClearKey = React19.useCallback(
2543
2680
  (event) => {
2544
2681
  if (event.key === "Enter" || event.key === " ") {
2545
2682
  event.preventDefault();
@@ -2548,7 +2685,7 @@ function SearchPanelForm(props = {}) {
2548
2685
  },
2549
2686
  [handleClear]
2550
2687
  );
2551
- return /* @__PURE__ */ React18.createElement(
2688
+ return /* @__PURE__ */ React19.createElement(
2552
2689
  "form",
2553
2690
  {
2554
2691
  action,
@@ -2560,7 +2697,7 @@ function SearchPanelForm(props = {}) {
2560
2697
  onPointerDown: handlePointerDown,
2561
2698
  "data-has-value": hasValue ? "1" : "0"
2562
2699
  },
2563
- /* @__PURE__ */ React18.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React18.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React18.createElement("span", { className: "sr-only" }, searchLabel), /* @__PURE__ */ React18.createElement(
2700
+ /* @__PURE__ */ React19.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React19.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React19.createElement("span", { className: "sr-only" }, searchLabel), /* @__PURE__ */ React19.createElement(
2564
2701
  "input",
2565
2702
  {
2566
2703
  id: inputId,
@@ -2575,7 +2712,7 @@ function SearchPanelForm(props = {}) {
2575
2712
  onInput: handleInputChange
2576
2713
  }
2577
2714
  )),
2578
- hasValue ? /* @__PURE__ */ React18.createElement(
2715
+ hasValue ? /* @__PURE__ */ React19.createElement(
2579
2716
  "button",
2580
2717
  {
2581
2718
  type: "button",
@@ -2588,7 +2725,7 @@ function SearchPanelForm(props = {}) {
2588
2725
  },
2589
2726
  "\xD7"
2590
2727
  ) : null,
2591
- /* @__PURE__ */ React18.createElement(
2728
+ /* @__PURE__ */ React19.createElement(
2592
2729
  "button",
2593
2730
  {
2594
2731
  type: "submit",
@@ -2601,11 +2738,11 @@ function SearchPanelForm(props = {}) {
2601
2738
  }
2602
2739
 
2603
2740
  // ui/src/search/SearchPanelTeaserResults.jsx
2604
- import React19 from "react";
2741
+ import React20 from "react";
2605
2742
  function SearchPanelTeaserResults(props = {}) {
2606
2743
  const { style, className } = props || {};
2607
2744
  const classes = ["canopy-search-teaser", "is-empty", className].filter(Boolean).join(" ");
2608
- return /* @__PURE__ */ React19.createElement(
2745
+ return /* @__PURE__ */ React20.createElement(
2609
2746
  "div",
2610
2747
  {
2611
2748
  "data-canopy-search-form-panel": true,
@@ -2613,7 +2750,7 @@ function SearchPanelTeaserResults(props = {}) {
2613
2750
  className: classes || void 0,
2614
2751
  style
2615
2752
  },
2616
- /* @__PURE__ */ React19.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
2753
+ /* @__PURE__ */ React20.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
2617
2754
  );
2618
2755
  }
2619
2756
 
@@ -2637,25 +2774,25 @@ function SearchPanel(props = {}) {
2637
2774
  const text = typeof label === "string" && label.trim() ? label.trim() : resolvedButtonLabel;
2638
2775
  const resolvedSearchPath = resolveSearchPath(searchPath);
2639
2776
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
2640
- return /* @__PURE__ */ React20.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React20.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React20.createElement(SearchPanelForm, { placeholder, buttonLabel: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React20.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React20.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2777
+ 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: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React21.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React21.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2641
2778
  }
2642
2779
 
2643
2780
  // ui/src/layout/CanopyBrand.jsx
2644
- import React21 from "react";
2645
- var PageContext = getSafePageContext();
2781
+ import React22 from "react";
2782
+ var PageContext2 = getSafePageContext();
2646
2783
  function CanopyBrand(props = {}) {
2647
2784
  const { labelId, label: labelProp, href = "/", className, Logo } = props || {};
2648
- const context = React21.useContext(PageContext);
2785
+ const context = React22.useContext(PageContext2);
2649
2786
  const contextSiteTitle = context && context.site && typeof context.site.title === "string" ? context.site.title.trim() : "";
2650
2787
  const normalizedLabel = typeof labelProp === "string" && labelProp.trim() ? labelProp : "";
2651
2788
  const resolvedLabel = normalizedLabel || contextSiteTitle || "Site title";
2652
2789
  const spanProps = labelId ? { id: labelId } : {};
2653
2790
  const classes = ["canopy-logo", className].filter(Boolean).join(" ");
2654
- return /* @__PURE__ */ React21.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React21.createElement(Logo, null) : null, /* @__PURE__ */ React21.createElement("span", { ...spanProps }, resolvedLabel));
2791
+ return /* @__PURE__ */ React22.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React22.createElement(Logo, null) : null, /* @__PURE__ */ React22.createElement("span", { ...spanProps }, resolvedLabel));
2655
2792
  }
2656
2793
 
2657
2794
  // ui/src/layout/CanopyModal.jsx
2658
- import React22 from "react";
2795
+ import React23 from "react";
2659
2796
  function CanopyModal(props = {}) {
2660
2797
  const {
2661
2798
  id,
@@ -2708,7 +2845,7 @@ function CanopyModal(props = {}) {
2708
2845
  if (padded) bodyClasses.push("canopy-modal__body--padded");
2709
2846
  if (bodyClassName) bodyClasses.push(bodyClassName);
2710
2847
  const bodyClassNameValue = bodyClasses.join(" ");
2711
- return /* @__PURE__ */ React22.createElement("div", { ...modalProps }, /* @__PURE__ */ React22.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React22.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React22.createElement(
2848
+ return /* @__PURE__ */ React23.createElement("div", { ...modalProps }, /* @__PURE__ */ React23.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React23.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React23.createElement(
2712
2849
  "svg",
2713
2850
  {
2714
2851
  xmlns: "http://www.w3.org/2000/svg",
@@ -2718,8 +2855,8 @@ function CanopyModal(props = {}) {
2718
2855
  strokeWidth: "1.5",
2719
2856
  className: "canopy-modal__close-icon"
2720
2857
  },
2721
- /* @__PURE__ */ React22.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
2722
- ), /* @__PURE__ */ React22.createElement("span", { className: "sr-only" }, resolvedCloseLabel)), /* @__PURE__ */ React22.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React22.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React22.createElement(
2858
+ /* @__PURE__ */ React23.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
2859
+ ), /* @__PURE__ */ React23.createElement("span", { className: "sr-only" }, resolvedCloseLabel)), /* @__PURE__ */ React23.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React23.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React23.createElement(
2723
2860
  CanopyBrand,
2724
2861
  {
2725
2862
  labelId: resolvedLabelId,
@@ -2732,10 +2869,10 @@ function CanopyModal(props = {}) {
2732
2869
  }
2733
2870
 
2734
2871
  // ui/src/layout/LanguageToggle.jsx
2735
- import React24 from "react";
2872
+ import React25 from "react";
2736
2873
 
2737
2874
  // ui/src/layout/languageToggleShared.jsx
2738
- import React23 from "react";
2875
+ import React24 from "react";
2739
2876
  function readBasePath3() {
2740
2877
  const normalize = (value) => {
2741
2878
  if (!value) return "";
@@ -2894,13 +3031,13 @@ function LanguageToggleControl({
2894
3031
  ].filter(Boolean).join(" ").trim();
2895
3032
  const ariaLabel = config.label || "Language";
2896
3033
  const resolvedControl = control === "list" ? "list" : "select";
2897
- const selectId = typeof React23.useId === "function" && resolvedControl === "select" ? React23.useId() : void 0;
3034
+ const selectId = typeof React24.useId === "function" && resolvedControl === "select" ? React24.useId() : void 0;
2898
3035
  const links = Array.isArray(config.links) ? config.links : [];
2899
3036
  if (!links.length) return null;
2900
3037
  const activeLink = links.find((link) => link.isActive);
2901
3038
  const fallbackHref = links[0].href;
2902
3039
  const selectedHref = activeLink ? activeLink.href : fallbackHref;
2903
- const navigate = React23.useCallback((href) => {
3040
+ const navigate = React24.useCallback((href) => {
2904
3041
  if (!href) return;
2905
3042
  try {
2906
3043
  if (typeof window !== "undefined" && window.location) {
@@ -2920,7 +3057,7 @@ function LanguageToggleControl({
2920
3057
  } catch (_) {
2921
3058
  }
2922
3059
  }, []);
2923
- const handleSelectChange = React23.useCallback(
3060
+ const handleSelectChange = React24.useCallback(
2924
3061
  (event) => {
2925
3062
  if (!event || !event.target) return;
2926
3063
  const nextHref = event.target.value;
@@ -2929,15 +3066,15 @@ function LanguageToggleControl({
2929
3066
  },
2930
3067
  [navigate, selectedHref]
2931
3068
  );
2932
- const labelElement = showLabel && config.label ? resolvedControl === "select" ? /* @__PURE__ */ React23.createElement(
3069
+ const labelElement = showLabel && config.label ? resolvedControl === "select" ? /* @__PURE__ */ React24.createElement(
2933
3070
  "label",
2934
3071
  {
2935
3072
  className: "canopy-language-toggle__label",
2936
3073
  htmlFor: selectId
2937
3074
  },
2938
3075
  config.label
2939
- ) : /* @__PURE__ */ React23.createElement("span", { className: "canopy-language-toggle__label" }, config.label) : null;
2940
- return /* @__PURE__ */ React23.createElement("div", { className: classes || void 0 }, labelElement, resolvedControl === "select" ? /* @__PURE__ */ React23.createElement("div", { className: "canopy-language-toggle__select" }, /* @__PURE__ */ React23.createElement(
3076
+ ) : /* @__PURE__ */ React24.createElement("span", { className: "canopy-language-toggle__label" }, config.label) : null;
3077
+ return /* @__PURE__ */ React24.createElement("div", { className: classes || void 0 }, labelElement, resolvedControl === "select" ? /* @__PURE__ */ React24.createElement("div", { className: "canopy-language-toggle__select" }, /* @__PURE__ */ React24.createElement(
2941
3078
  "select",
2942
3079
  {
2943
3080
  id: selectId,
@@ -2947,7 +3084,7 @@ function LanguageToggleControl({
2947
3084
  "aria-label": ariaLabel,
2948
3085
  "data-canopy-language-select": "true"
2949
3086
  },
2950
- links.map((link) => /* @__PURE__ */ React23.createElement(
3087
+ links.map((link) => /* @__PURE__ */ React24.createElement(
2951
3088
  "option",
2952
3089
  {
2953
3090
  key: link.lang,
@@ -2957,7 +3094,7 @@ function LanguageToggleControl({
2957
3094
  },
2958
3095
  link.label
2959
3096
  ))
2960
- )) : /* @__PURE__ */ React23.createElement("nav", { className: "canopy-language-toggle__nav", "aria-label": ariaLabel }, /* @__PURE__ */ React23.createElement("ul", { className: "canopy-language-toggle__list", role: "list" }, links.map((link) => /* @__PURE__ */ React23.createElement("li", { key: link.lang }, /* @__PURE__ */ React23.createElement(
3097
+ )) : /* @__PURE__ */ React24.createElement("nav", { className: "canopy-language-toggle__nav", "aria-label": ariaLabel }, /* @__PURE__ */ React24.createElement("ul", { className: "canopy-language-toggle__list", role: "list" }, links.map((link) => /* @__PURE__ */ React24.createElement("li", { key: link.lang }, /* @__PURE__ */ React24.createElement(
2961
3098
  "button",
2962
3099
  {
2963
3100
  type: "button",
@@ -2969,7 +3106,7 @@ function LanguageToggleControl({
2969
3106
  onClick: () => navigate(link.href)
2970
3107
  },
2971
3108
  link.label
2972
- ))))), /* @__PURE__ */ React23.createElement(LanguageToggleRuntime, null));
3109
+ ))))), /* @__PURE__ */ React24.createElement(LanguageToggleRuntime, null));
2973
3110
  }
2974
3111
  function LanguageToggleRuntime() {
2975
3112
  const code = `
@@ -3029,7 +3166,7 @@ function LanguageToggleRuntime() {
3029
3166
  }
3030
3167
  })();
3031
3168
  `;
3032
- return /* @__PURE__ */ React23.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
3169
+ return /* @__PURE__ */ React24.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
3033
3170
  }
3034
3171
 
3035
3172
  // ui/src/layout/LanguageToggle.jsx
@@ -3043,8 +3180,8 @@ function LanguageToggle({
3043
3180
  label,
3044
3181
  ariaLabel
3045
3182
  }) {
3046
- const PageContext2 = getSafePageContext();
3047
- const context = React24.useContext(PageContext2);
3183
+ const PageContext3 = getSafePageContext();
3184
+ const context = React25.useContext(PageContext3);
3048
3185
  const siteLanguageToggle = context && context.site && context.site.languageToggle || null;
3049
3186
  const pageData = page || (context && context.page ? context.page : null);
3050
3187
  const resolvedToggle = languageToggle === false ? null : languageToggle === true || typeof languageToggle === "undefined" ? siteLanguageToggle : languageToggle;
@@ -3053,7 +3190,7 @@ function LanguageToggle({
3053
3190
  resolvedToggle && typeof resolvedToggle.control === "string" ? resolvedToggle.control : null
3054
3191
  );
3055
3192
  const resolvedControl = normalizeControl(typeof control === "string" ? control : null) || toggleControl || "select";
3056
- const config = React24.useMemo(() => {
3193
+ const config = React25.useMemo(() => {
3057
3194
  if (!resolvedToggle) return null;
3058
3195
  const base = buildLanguageToggleConfig(resolvedToggle, pageData);
3059
3196
  if (!base) return null;
@@ -3064,7 +3201,7 @@ function LanguageToggle({
3064
3201
  };
3065
3202
  }, [resolvedToggle, pageData, label, ariaLabel]);
3066
3203
  if (!config) return null;
3067
- return /* @__PURE__ */ React24.createElement(
3204
+ return /* @__PURE__ */ React25.createElement(
3068
3205
  LanguageToggleControl,
3069
3206
  {
3070
3207
  config,
@@ -3366,7 +3503,7 @@ function HeaderScript() {
3366
3503
  });
3367
3504
  })();
3368
3505
  `;
3369
- return /* @__PURE__ */ React25.createElement(
3506
+ return /* @__PURE__ */ React26.createElement(
3370
3507
  "script",
3371
3508
  {
3372
3509
  dangerouslySetInnerHTML: {
@@ -3442,8 +3579,8 @@ function CanopyHeader(props = {}) {
3442
3579
  logo: SiteLogo,
3443
3580
  languageToggle: languageToggleProp
3444
3581
  } = props;
3445
- const PageContext2 = getSafePageContext();
3446
- const context = React25.useContext(PageContext2);
3582
+ const PageContext3 = getSafePageContext();
3583
+ const context = React26.useContext(PageContext3);
3447
3584
  const { getString, formatString } = useLocale();
3448
3585
  const contextPrimaryNav = context && Array.isArray(context.primaryNavigation) ? context.primaryNavigation : [];
3449
3586
  const navLinks = navLinksProp && navLinksProp.length ? ensureArray(navLinksProp) : ensureArray(contextPrimaryNav);
@@ -3519,14 +3656,14 @@ function CanopyHeader(props = {}) {
3519
3656
  return !!(rootNode && Array.isArray(rootNode.children) && rootNode.children.length);
3520
3657
  };
3521
3658
  const hasIntegratedSectionNav = navLinks.some(shouldAttachSectionNav);
3522
- return /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement(
3659
+ return /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(
3523
3660
  "header",
3524
3661
  {
3525
3662
  className: "canopy-header",
3526
3663
  "data-mobile-nav": "closed",
3527
3664
  "data-mobile-search": "closed"
3528
3665
  },
3529
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React25.createElement(
3666
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React26.createElement(
3530
3667
  CanopyBrand,
3531
3668
  {
3532
3669
  label: resolvedTitle,
@@ -3535,7 +3672,7 @@ function CanopyHeader(props = {}) {
3535
3672
  Logo: SiteLogo
3536
3673
  }
3537
3674
  )),
3538
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React25.createElement(
3675
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React26.createElement(
3539
3676
  SearchPanel,
3540
3677
  {
3541
3678
  label: resolvedSearchLabel,
@@ -3544,13 +3681,13 @@ function CanopyHeader(props = {}) {
3544
3681
  searchPath: normalizedSearchRoute
3545
3682
  }
3546
3683
  )),
3547
- /* @__PURE__ */ React25.createElement(
3684
+ /* @__PURE__ */ React26.createElement(
3548
3685
  "nav",
3549
3686
  {
3550
3687
  className: "canopy-nav-links canopy-header__desktop-nav",
3551
3688
  "aria-label": primaryNavigationLabel
3552
3689
  },
3553
- navLinks.map((link) => /* @__PURE__ */ React25.createElement(
3690
+ navLinks.map((link) => /* @__PURE__ */ React26.createElement(
3554
3691
  "a",
3555
3692
  {
3556
3693
  key: link.href,
@@ -3560,7 +3697,7 @@ function CanopyHeader(props = {}) {
3560
3697
  link.label || link.href
3561
3698
  ))
3562
3699
  ),
3563
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-header__actions" }, resolvedLanguageToggle ? /* @__PURE__ */ React25.createElement(
3700
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-header__actions" }, resolvedLanguageToggle ? /* @__PURE__ */ React26.createElement(
3564
3701
  LanguageToggle,
3565
3702
  {
3566
3703
  languageToggle: resolvedLanguageToggle,
@@ -3568,7 +3705,7 @@ function CanopyHeader(props = {}) {
3568
3705
  variant: "desktop",
3569
3706
  className: "canopy-header__language-toggle canopy-header__language-toggle--desktop"
3570
3707
  }
3571
- ) : null, /* @__PURE__ */ React25.createElement(
3708
+ ) : null, /* @__PURE__ */ React26.createElement(
3572
3709
  "button",
3573
3710
  {
3574
3711
  type: "button",
@@ -3578,7 +3715,7 @@ function CanopyHeader(props = {}) {
3578
3715
  "aria-expanded": "false",
3579
3716
  "data-canopy-header-toggle": "search"
3580
3717
  },
3581
- /* @__PURE__ */ React25.createElement(
3718
+ /* @__PURE__ */ React26.createElement(
3582
3719
  "svg",
3583
3720
  {
3584
3721
  xmlns: "http://www.w3.org/2000/svg",
@@ -3588,7 +3725,7 @@ function CanopyHeader(props = {}) {
3588
3725
  strokeWidth: "1.5",
3589
3726
  className: "canopy-header__search-icon"
3590
3727
  },
3591
- /* @__PURE__ */ React25.createElement(
3728
+ /* @__PURE__ */ React26.createElement(
3592
3729
  "path",
3593
3730
  {
3594
3731
  strokeLinecap: "round",
@@ -3597,7 +3734,7 @@ function CanopyHeader(props = {}) {
3597
3734
  }
3598
3735
  )
3599
3736
  )
3600
- ), /* @__PURE__ */ React25.createElement(
3737
+ ), /* @__PURE__ */ React26.createElement(
3601
3738
  "button",
3602
3739
  {
3603
3740
  type: "button",
@@ -3607,7 +3744,7 @@ function CanopyHeader(props = {}) {
3607
3744
  "aria-expanded": "false",
3608
3745
  "data-canopy-header-toggle": "nav"
3609
3746
  },
3610
- /* @__PURE__ */ React25.createElement(
3747
+ /* @__PURE__ */ React26.createElement(
3611
3748
  "svg",
3612
3749
  {
3613
3750
  xmlns: "http://www.w3.org/2000/svg",
@@ -3617,7 +3754,7 @@ function CanopyHeader(props = {}) {
3617
3754
  stroke: "currentColor",
3618
3755
  className: "canopy-header__menu-icon"
3619
3756
  },
3620
- /* @__PURE__ */ React25.createElement(
3757
+ /* @__PURE__ */ React26.createElement(
3621
3758
  "path",
3622
3759
  {
3623
3760
  strokeLinecap: "round",
@@ -3627,7 +3764,7 @@ function CanopyHeader(props = {}) {
3627
3764
  )
3628
3765
  )
3629
3766
  ))
3630
- ), /* @__PURE__ */ React25.createElement(
3767
+ ), /* @__PURE__ */ React26.createElement(
3631
3768
  CanopyModal,
3632
3769
  {
3633
3770
  id: "canopy-modal-nav",
@@ -3639,7 +3776,7 @@ function CanopyHeader(props = {}) {
3639
3776
  closeLabel: closeNavLabel,
3640
3777
  closeDataAttr: "nav"
3641
3778
  },
3642
- resolvedLanguageToggle ? /* @__PURE__ */ React25.createElement(
3779
+ resolvedLanguageToggle ? /* @__PURE__ */ React26.createElement(
3643
3780
  LanguageToggle,
3644
3781
  {
3645
3782
  languageToggle: resolvedLanguageToggle,
@@ -3648,13 +3785,13 @@ function CanopyHeader(props = {}) {
3648
3785
  className: "canopy-header__language-toggle canopy-header__language-toggle--mobile"
3649
3786
  }
3650
3787
  ) : null,
3651
- /* @__PURE__ */ React25.createElement(
3788
+ /* @__PURE__ */ React26.createElement(
3652
3789
  "nav",
3653
3790
  {
3654
3791
  className: "canopy-nav-links canopy-modal__nav",
3655
3792
  "aria-label": primaryNavigationLabel
3656
3793
  },
3657
- /* @__PURE__ */ React25.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
3794
+ /* @__PURE__ */ React26.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
3658
3795
  const navData = getLinkNavigationData(
3659
3796
  link,
3660
3797
  navigationRoots,
@@ -3674,7 +3811,7 @@ function CanopyHeader(props = {}) {
3674
3811
  { content: toggleLabelTarget }
3675
3812
  );
3676
3813
  const defaultExpanded = hasChildren && !!navRoot.isExpanded;
3677
- return /* @__PURE__ */ React25.createElement(
3814
+ return /* @__PURE__ */ React26.createElement(
3678
3815
  "li",
3679
3816
  {
3680
3817
  className: "canopy-modal__nav-item",
@@ -3683,7 +3820,7 @@ function CanopyHeader(props = {}) {
3683
3820
  "data-expanded": defaultExpanded ? "true" : "false",
3684
3821
  "data-default-expanded": defaultExpanded ? "true" : void 0
3685
3822
  },
3686
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React25.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React25.createElement(
3823
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React26.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React26.createElement(
3687
3824
  "button",
3688
3825
  {
3689
3826
  type: "button",
@@ -3693,7 +3830,7 @@ function CanopyHeader(props = {}) {
3693
3830
  "aria-label": toggleLabel,
3694
3831
  "data-canopy-nav-item-toggle": nestedId || void 0
3695
3832
  },
3696
- /* @__PURE__ */ React25.createElement(
3833
+ /* @__PURE__ */ React26.createElement(
3697
3834
  "svg",
3698
3835
  {
3699
3836
  xmlns: "http://www.w3.org/2000/svg",
@@ -3703,7 +3840,7 @@ function CanopyHeader(props = {}) {
3703
3840
  strokeWidth: "1.5",
3704
3841
  className: "canopy-modal__nav-toggle-icon"
3705
3842
  },
3706
- /* @__PURE__ */ React25.createElement(
3843
+ /* @__PURE__ */ React26.createElement(
3707
3844
  "path",
3708
3845
  {
3709
3846
  strokeLinecap: "round",
@@ -3712,9 +3849,9 @@ function CanopyHeader(props = {}) {
3712
3849
  }
3713
3850
  )
3714
3851
  ),
3715
- /* @__PURE__ */ React25.createElement("span", { className: "sr-only" }, toggleLabel)
3852
+ /* @__PURE__ */ React26.createElement("span", { className: "sr-only" }, toggleLabel)
3716
3853
  ) : null),
3717
- hasChildren ? /* @__PURE__ */ React25.createElement(
3854
+ hasChildren ? /* @__PURE__ */ React26.createElement(
3718
3855
  NavigationTree,
3719
3856
  {
3720
3857
  root: navRoot,
@@ -3734,7 +3871,7 @@ function CanopyHeader(props = {}) {
3734
3871
  );
3735
3872
  }))
3736
3873
  ),
3737
- hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React25.createElement(
3874
+ hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React26.createElement(
3738
3875
  NavigationTree,
3739
3876
  {
3740
3877
  root: sectionNavigation.root,
@@ -3744,7 +3881,7 @@ function CanopyHeader(props = {}) {
3744
3881
  parentKey: "fallback-nav"
3745
3882
  }
3746
3883
  ) : null
3747
- ), /* @__PURE__ */ React25.createElement(
3884
+ ), /* @__PURE__ */ React26.createElement(
3748
3885
  CanopyModal,
3749
3886
  {
3750
3887
  id: "canopy-modal-search",
@@ -3757,7 +3894,7 @@ function CanopyHeader(props = {}) {
3757
3894
  closeDataAttr: "search",
3758
3895
  bodyClassName: "canopy-modal__body--search"
3759
3896
  },
3760
- /* @__PURE__ */ React25.createElement(
3897
+ /* @__PURE__ */ React26.createElement(
3761
3898
  SearchPanel,
3762
3899
  {
3763
3900
  label: resolvedSearchLabel,
@@ -3766,18 +3903,18 @@ function CanopyHeader(props = {}) {
3766
3903
  searchPath: normalizedSearchRoute
3767
3904
  }
3768
3905
  )
3769
- ), /* @__PURE__ */ React25.createElement(HeaderScript, null));
3906
+ ), /* @__PURE__ */ React26.createElement(HeaderScript, null));
3770
3907
  }
3771
3908
 
3772
3909
  // ui/src/layout/CanopyFooter.jsx
3773
- import React26 from "react";
3910
+ import React27 from "react";
3774
3911
  function CanopyFooter({ className = "", children }) {
3775
3912
  const footerClassName = ["canopy-footer", className].filter(Boolean).join(" ");
3776
- return /* @__PURE__ */ React26.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React26.createElement("div", { className: "canopy-footer__inner" }, children));
3913
+ return /* @__PURE__ */ React27.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React27.createElement("div", { className: "canopy-footer__inner" }, children));
3777
3914
  }
3778
3915
 
3779
3916
  // ui/src/layout/TeaserCard.jsx
3780
- import React27 from "react";
3917
+ import React28 from "react";
3781
3918
  function TeaserCard({
3782
3919
  href = "",
3783
3920
  title = "",
@@ -3798,7 +3935,7 @@ function TeaserCard({
3798
3935
  ].filter(Boolean).join(" ");
3799
3936
  const showThumb = type === "work" && thumbnail;
3800
3937
  const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
3801
- return /* @__PURE__ */ React27.createElement(
3938
+ return /* @__PURE__ */ React28.createElement(
3802
3939
  Tag,
3803
3940
  {
3804
3941
  className: classes,
@@ -3806,7 +3943,7 @@ function TeaserCard({
3806
3943
  "data-canopy-item": href ? "" : void 0,
3807
3944
  ...rest
3808
3945
  },
3809
- showThumb ? /* @__PURE__ */ React27.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React27.createElement(
3946
+ showThumb ? /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React28.createElement(
3810
3947
  "img",
3811
3948
  {
3812
3949
  src: thumbnail,
@@ -3816,12 +3953,12 @@ function TeaserCard({
3816
3953
  className: "canopy-search-teaser__thumb-img"
3817
3954
  }
3818
3955
  )) : null,
3819
- /* @__PURE__ */ React27.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React27.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React27.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
3956
+ /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React28.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React28.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
3820
3957
  );
3821
3958
  }
3822
3959
 
3823
3960
  // ui/src/layout/GoogleAnalytics.jsx
3824
- import React28 from "react";
3961
+ import React29 from "react";
3825
3962
  var GA_HOST = "https://www.googletagmanager.com/gtag/js";
3826
3963
  function GoogleAnalytics({ id }) {
3827
3964
  if (!id) return null;
@@ -3831,11 +3968,11 @@ function GoogleAnalytics({ id }) {
3831
3968
  gtag('js', new Date());
3832
3969
  gtag('config', '${id}');
3833
3970
  `;
3834
- return /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React28.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
3971
+ return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React29.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
3835
3972
  }
3836
3973
 
3837
3974
  // ui/src/layout/Container.jsx
3838
- import React29 from "react";
3975
+ import React30 from "react";
3839
3976
  function Container({
3840
3977
  className = "",
3841
3978
  variant = "content",
@@ -3844,7 +3981,7 @@ function Container({
3844
3981
  }) {
3845
3982
  const variantClass = variant === "wide" ? "max-w-wide" : "max-w-content";
3846
3983
  const classes = ["mx-auto", variantClass, "w-full", className].filter(Boolean).join(" ");
3847
- return /* @__PURE__ */ React29.createElement(
3984
+ return /* @__PURE__ */ React30.createElement(
3848
3985
  "div",
3849
3986
  {
3850
3987
  className: classes,
@@ -3856,7 +3993,7 @@ function Container({
3856
3993
  }
3857
3994
 
3858
3995
  // ui/src/layout/Card.jsx
3859
- import React30, { useEffect as useEffect6, useRef as useRef2, useState as useState5 } from "react";
3996
+ import React31, { useEffect as useEffect6, useRef as useRef2, useState as useState5 } from "react";
3860
3997
  var DEFAULT_CARD_ASPECT_RATIO = 4 / 3;
3861
3998
  function Card({
3862
3999
  href,
@@ -3920,8 +4057,8 @@ function Card({
3920
4057
  const hasDimensions = Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0;
3921
4058
  const ratio = hasAspectRatio ? Number(aspectRatio) : hasDimensions ? w / h : src ? DEFAULT_CARD_ASPECT_RATIO : void 0;
3922
4059
  const paddingPercent = ratio ? 100 / ratio : 100;
3923
- const caption = /* @__PURE__ */ React30.createElement("figcaption", null, title && /* @__PURE__ */ React30.createElement("span", null, title), subtitle && /* @__PURE__ */ React30.createElement("span", null, subtitle), children);
3924
- return /* @__PURE__ */ React30.createElement(
4060
+ const caption = /* @__PURE__ */ React31.createElement("figcaption", null, title && /* @__PURE__ */ React31.createElement("span", null, title), subtitle && /* @__PURE__ */ React31.createElement("span", null, subtitle), children);
4061
+ return /* @__PURE__ */ React31.createElement(
3925
4062
  "a",
3926
4063
  {
3927
4064
  href,
@@ -3933,13 +4070,13 @@ function Card({
3933
4070
  "data-image-loaded": imageLoaded ? "true" : "false",
3934
4071
  ...rest
3935
4072
  },
3936
- /* @__PURE__ */ React30.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React30.createElement(
4073
+ /* @__PURE__ */ React31.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React31.createElement(
3937
4074
  "div",
3938
4075
  {
3939
4076
  className: "canopy-card-media",
3940
4077
  style: { "--canopy-card-padding": `${paddingPercent}%` }
3941
4078
  },
3942
- inView ? /* @__PURE__ */ React30.createElement(
4079
+ inView ? /* @__PURE__ */ React31.createElement(
3943
4080
  "img",
3944
4081
  {
3945
4082
  src,
@@ -3950,7 +4087,7 @@ function Card({
3950
4087
  onError: () => setImageLoaded(true)
3951
4088
  }
3952
4089
  ) : null
3953
- ) : /* @__PURE__ */ React30.createElement(
4090
+ ) : /* @__PURE__ */ React31.createElement(
3954
4091
  "img",
3955
4092
  {
3956
4093
  src,
@@ -3966,13 +4103,13 @@ function Card({
3966
4103
  }
3967
4104
 
3968
4105
  // ui/src/content/ReferencedItems.jsx
3969
- import React31 from "react";
3970
- import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
4106
+ import React32 from "react";
4107
+ import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
3971
4108
  function useReferencedItems(itemsProp) {
3972
4109
  if (Array.isArray(itemsProp)) return itemsProp;
3973
- const PageContext2 = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
3974
- if (!PageContext2) return [];
3975
- const context = React31.useContext(PageContext2);
4110
+ const PageContext3 = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
4111
+ if (!PageContext3) return [];
4112
+ const context = React32.useContext(PageContext3);
3976
4113
  const items = context && context.page ? context.page.referencedItems : null;
3977
4114
  return Array.isArray(items) ? items : [];
3978
4115
  }
@@ -3992,13 +4129,13 @@ function ReferencedItems({
3992
4129
  "referenced-items--empty",
3993
4130
  className
3994
4131
  ].filter(Boolean).join(" ");
3995
- return /* @__PURE__ */ React31.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
4132
+ return /* @__PURE__ */ React32.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
3996
4133
  }
3997
4134
  const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
3998
- return /* @__PURE__ */ React31.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React31.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
4135
+ return /* @__PURE__ */ React32.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React32.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
3999
4136
  if (!item) return null;
4000
4137
  const key = item.href || item.slug || item.id;
4001
- return /* @__PURE__ */ React31.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React31.createElement(
4138
+ return /* @__PURE__ */ React32.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React32.createElement(
4002
4139
  Card,
4003
4140
  {
4004
4141
  href: item.href,
@@ -4015,15 +4152,15 @@ function ReferencedItems({
4015
4152
  }
4016
4153
 
4017
4154
  // ui/src/content/References.jsx
4018
- import React32 from "react";
4019
- import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
4155
+ import React33 from "react";
4156
+ import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
4020
4157
  import referenced from "@canopy-iiif/app/lib/components/referenced.js";
4021
4158
  function getPageContext() {
4022
- if (!navigationHelpers5 || typeof navigationHelpers5.getPageContext !== "function") {
4159
+ if (!navigationHelpers4 || typeof navigationHelpers4.getPageContext !== "function") {
4023
4160
  return null;
4024
4161
  }
4025
4162
  try {
4026
- return navigationHelpers5.getPageContext();
4163
+ return navigationHelpers4.getPageContext();
4027
4164
  } catch (_) {
4028
4165
  return null;
4029
4166
  }
@@ -4047,8 +4184,8 @@ function References({
4047
4184
  }) {
4048
4185
  const { getString } = useLocale();
4049
4186
  const resolvedTitle = title != null ? title : getString("common.misc.referenced_by", "Referenced by");
4050
- const PageContext2 = getPageContext();
4051
- const context = PageContext2 ? React32.useContext(PageContext2) : null;
4187
+ const PageContext3 = getPageContext();
4188
+ const context = PageContext3 ? React33.useContext(PageContext3) : null;
4052
4189
  const contextPage = context && context.page ? context.page : null;
4053
4190
  const manifestId = id || contextPage && contextPage.manifestId || "";
4054
4191
  const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
@@ -4057,12 +4194,12 @@ function References({
4057
4194
  const entries = references && references.length ? references : null;
4058
4195
  if (!entries || !entries.length) return null;
4059
4196
  const containerClass = ["references", className].filter(Boolean).join(" ");
4060
- return /* @__PURE__ */ React32.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React32.createElement("div", { className: "references__group" }, /* @__PURE__ */ React32.createElement("dt", null, resolvedTitle), entries.map((entry) => /* @__PURE__ */ React32.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React32.createElement("a", { href: entry.href }, entry.title || entry.href)))));
4197
+ return /* @__PURE__ */ React33.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React33.createElement("div", { className: "references__group" }, /* @__PURE__ */ React33.createElement("dt", null, resolvedTitle), entries.map((entry) => /* @__PURE__ */ React33.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React33.createElement("a", { href: entry.href }, entry.title || entry.href)))));
4061
4198
  }
4062
4199
 
4063
4200
  // ui/src/content/Index.jsx
4064
4201
  var import_slugify = __toESM(require_slugify());
4065
- import React33 from "react";
4202
+ import React34 from "react";
4066
4203
  import metadataIndexHelpers from "@canopy-iiif/app/lib/components/metadata-index.js";
4067
4204
  var metadataModule = metadataIndexHelpers && typeof metadataIndexHelpers === "object" ? metadataIndexHelpers : null;
4068
4205
  var SLUG_OPTIONS = { lower: true, strict: true, trim: true };
@@ -4225,7 +4362,7 @@ function Index({
4225
4362
  const entries = filterByLabel(data, label);
4226
4363
  if (!entries.length) return null;
4227
4364
  const containerClass = ["canopy-index", className].filter(Boolean).join(" ");
4228
- return /* @__PURE__ */ React33.createElement("div", { className: containerClass, ...rest }, entries.map((entry) => /* @__PURE__ */ React33.createElement(
4365
+ return /* @__PURE__ */ React34.createElement("div", { className: containerClass, ...rest }, entries.map((entry) => /* @__PURE__ */ React34.createElement(
4229
4366
  IndexGroup,
4230
4367
  {
4231
4368
  key: entry.slug || entry.label,
@@ -4236,7 +4373,7 @@ function Index({
4236
4373
  expandLabel,
4237
4374
  collapseLabel
4238
4375
  }
4239
- )), /* @__PURE__ */ React33.createElement(
4376
+ )), /* @__PURE__ */ React34.createElement(
4240
4377
  "script",
4241
4378
  {
4242
4379
  "data-canopy-index-script": "",
@@ -4253,10 +4390,10 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
4253
4390
  const hiddenValues = hasOverflow ? values.slice(maxVisible) : [];
4254
4391
  const labelCollapsed = typeof expandLabel === "string" && expandLabel.trim() ? expandLabel.trim() : "Show more";
4255
4392
  const labelExpanded = typeof collapseLabel === "string" && collapseLabel.trim() ? collapseLabel.trim() : "Show less";
4256
- return /* @__PURE__ */ React33.createElement("dl", { className: "canopy-index__group", "data-canopy-index-group": "", "data-expanded": "0" }, /* @__PURE__ */ React33.createElement("dt", null, label), /* @__PURE__ */ React33.createElement("div", { className: "canopy-index__values" }, visibleValues.map((value) => {
4393
+ return /* @__PURE__ */ React34.createElement("dl", { className: "canopy-index__group", "data-canopy-index-group": "", "data-expanded": "0" }, /* @__PURE__ */ React34.createElement("dt", null, label), /* @__PURE__ */ React34.createElement("div", { className: "canopy-index__values" }, visibleValues.map((value) => {
4257
4394
  const href = buildSearchHref(labelSlug, value.slug);
4258
4395
  const key = `${labelSlug || label}-${value.slug || value.value}`;
4259
- return /* @__PURE__ */ React33.createElement("dd", { key }, href ? /* @__PURE__ */ React33.createElement(
4396
+ return /* @__PURE__ */ React34.createElement("dd", { key }, href ? /* @__PURE__ */ React34.createElement(
4260
4397
  "a",
4261
4398
  {
4262
4399
  href,
@@ -4269,7 +4406,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
4269
4406
  }), hiddenValues.map((value) => {
4270
4407
  const href = buildSearchHref(labelSlug, value.slug);
4271
4408
  const key = `${labelSlug || label}-hidden-${value.slug || value.value}`;
4272
- return /* @__PURE__ */ React33.createElement("dd", { key, "data-canopy-index-hidden": "", hidden: true }, href ? /* @__PURE__ */ React33.createElement(
4409
+ return /* @__PURE__ */ React34.createElement("dd", { key, "data-canopy-index-hidden": "", hidden: true }, href ? /* @__PURE__ */ React34.createElement(
4273
4410
  "a",
4274
4411
  {
4275
4412
  href,
@@ -4279,7 +4416,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
4279
4416
  },
4280
4417
  value.value
4281
4418
  ) : value.value);
4282
- })), hasOverflow && /* @__PURE__ */ React33.createElement("div", { className: "canopy-index__more-wrapper" }, /* @__PURE__ */ React33.createElement(
4419
+ })), hasOverflow && /* @__PURE__ */ React34.createElement("div", { className: "canopy-index__more-wrapper" }, /* @__PURE__ */ React34.createElement(
4283
4420
  "button",
4284
4421
  {
4285
4422
  type: "button",
@@ -4293,7 +4430,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
4293
4430
  }
4294
4431
 
4295
4432
  // ui/src/content/Bibliography.jsx
4296
- import React34 from "react";
4433
+ import React35 from "react";
4297
4434
  import bibliography from "@canopy-iiif/app/lib/components/bibliography.js";
4298
4435
  function resolveHeadingTag(tag, fallback) {
4299
4436
  if (typeof tag === "string" && tag.trim()) return tag;
@@ -4303,7 +4440,7 @@ function resolveHeadingTag(tag, fallback) {
4303
4440
  function NoteBody({ note }) {
4304
4441
  if (!note) return null;
4305
4442
  if (note.html) {
4306
- return /* @__PURE__ */ React34.createElement(
4443
+ return /* @__PURE__ */ React35.createElement(
4307
4444
  "div",
4308
4445
  {
4309
4446
  className: "bibliography__note-body",
@@ -4312,7 +4449,7 @@ function NoteBody({ note }) {
4312
4449
  );
4313
4450
  }
4314
4451
  if (note.text) {
4315
- return /* @__PURE__ */ React34.createElement("div", { className: "bibliography__note-body" }, note.text);
4452
+ return /* @__PURE__ */ React35.createElement("div", { className: "bibliography__note-body" }, note.text);
4316
4453
  }
4317
4454
  return null;
4318
4455
  }
@@ -4330,22 +4467,22 @@ function Bibliography({
4330
4467
  if (!entries.length) return null;
4331
4468
  const PageHeadingTag = resolveHeadingTag(pageHeadingTag, "h3");
4332
4469
  const rootClass = ["bibliography", className].filter(Boolean).join(" ");
4333
- return /* @__PURE__ */ React34.createElement("section", { className: rootClass }, /* @__PURE__ */ React34.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
4470
+ return /* @__PURE__ */ React35.createElement("section", { className: rootClass }, /* @__PURE__ */ React35.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
4334
4471
  const key = entry.href || entry.relativePath || entry.title;
4335
4472
  const pageTitle = entry.title || entry.href;
4336
- return /* @__PURE__ */ React34.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React34.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React34.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React34.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React34.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
4473
+ return /* @__PURE__ */ React35.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React35.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React35.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React35.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React35.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
4337
4474
  const noteKey = `${key || "entry"}-${note.identifier || idx}`;
4338
- return /* @__PURE__ */ React34.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React34.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React34.createElement(NoteBody, { note }));
4475
+ return /* @__PURE__ */ React35.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React35.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React35.createElement(NoteBody, { note }));
4339
4476
  })));
4340
4477
  })));
4341
4478
  }
4342
4479
 
4343
4480
  // ui/src/content/timeline/MdxTimeline.jsx
4344
- import React38 from "react";
4481
+ import React39 from "react";
4345
4482
  import ReactDOMServer from "react-dom/server";
4346
4483
 
4347
4484
  // ui/src/content/timeline/Timeline.jsx
4348
- import React36 from "react";
4485
+ import React37 from "react";
4349
4486
 
4350
4487
  // ui/src/content/timeline/date-utils.js
4351
4488
  var FALLBACK_LOCALE = (() => {
@@ -4506,7 +4643,7 @@ function clampProgress(value) {
4506
4643
  }
4507
4644
 
4508
4645
  // ui/src/layout/ReferencedManifestCard.jsx
4509
- import React35 from "react";
4646
+ import React36 from "react";
4510
4647
  function normalizeMetadata(metadata, summary) {
4511
4648
  if (Array.isArray(metadata) && metadata.length) {
4512
4649
  return metadata.filter(Boolean);
@@ -4540,7 +4677,7 @@ function ReferencedManifestCard({
4540
4677
  "canopy-referenced-manifest-card",
4541
4678
  className
4542
4679
  ].filter(Boolean).join(" ");
4543
- return /* @__PURE__ */ React35.createElement(
4680
+ return /* @__PURE__ */ React36.createElement(
4544
4681
  TeaserCard,
4545
4682
  {
4546
4683
  href: resolvedHref || void 0,
@@ -4722,14 +4859,14 @@ function TimelineConnector({ side, isActive, highlight }) {
4722
4859
  "canopy-timeline__connector-dot",
4723
4860
  highlight || isActive ? "is-active" : ""
4724
4861
  ].filter(Boolean).join(" ");
4725
- return /* @__PURE__ */ React36.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React36.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement("span", { className: dotClasses }), /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__connector-line" })));
4862
+ return /* @__PURE__ */ React37.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React37.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement("span", { className: dotClasses }), /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__connector-line" })));
4726
4863
  }
4727
4864
  function renderResourceSection(point) {
4728
4865
  if (!point) return null;
4729
4866
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
4730
4867
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
4731
4868
  if (!manifestCards.length && !legacyResources.length) return null;
4732
- return /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React36.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React36.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React36.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React36.createElement(
4869
+ return /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React37.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React37.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React37.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React37.createElement(
4733
4870
  TeaserCard,
4734
4871
  {
4735
4872
  href: resource.href,
@@ -4754,26 +4891,26 @@ function Timeline({
4754
4891
  ...rest
4755
4892
  }) {
4756
4893
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
4757
- const rawPoints = React36.useMemo(() => {
4894
+ const rawPoints = React37.useMemo(() => {
4758
4895
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
4759
4896
  if (payloadPoints && payloadPoints.length) return payloadPoints;
4760
4897
  return [];
4761
4898
  }, [pointsProp, payloadPoints]);
4762
- const sanitizedPoints = React36.useMemo(
4899
+ const sanitizedPoints = React37.useMemo(
4763
4900
  () => sanitizePoints(rawPoints),
4764
4901
  [rawPoints]
4765
4902
  );
4766
4903
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
4767
- const baseLocale = React36.useMemo(
4904
+ const baseLocale = React37.useMemo(
4768
4905
  () => createLocale(localeValue),
4769
4906
  [localeValue]
4770
4907
  );
4771
4908
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
4772
- const rangeOverrides = React36.useMemo(
4909
+ const rangeOverrides = React37.useMemo(
4773
4910
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
4774
4911
  [sanitizedPoints, rangeInput]
4775
4912
  );
4776
- const effectiveRange = React36.useMemo(
4913
+ const effectiveRange = React37.useMemo(
4777
4914
  () => normalizeRange({
4778
4915
  ...rangeOverrides,
4779
4916
  locale: baseLocale
@@ -4782,7 +4919,7 @@ function Timeline({
4782
4919
  );
4783
4920
  const spanStart = effectiveRange.startDate.getTime();
4784
4921
  const span = effectiveRange.span;
4785
- const pointsWithPosition = React36.useMemo(() => {
4922
+ const pointsWithPosition = React37.useMemo(() => {
4786
4923
  if (!sanitizedPoints.length) return [];
4787
4924
  return sanitizedPoints.map((point, index) => {
4788
4925
  const timestamp = point.meta.timestamp;
@@ -4796,29 +4933,29 @@ function Timeline({
4796
4933
  };
4797
4934
  });
4798
4935
  }, [sanitizedPoints, spanStart, span]);
4799
- const [activeId, setActiveId] = React36.useState(
4936
+ const [activeId, setActiveId] = React37.useState(
4800
4937
  () => getActivePointId(pointsWithPosition)
4801
4938
  );
4802
- React36.useEffect(() => {
4939
+ React37.useEffect(() => {
4803
4940
  setActiveId(getActivePointId(pointsWithPosition));
4804
4941
  }, [pointsWithPosition]);
4805
4942
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
4806
4943
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
4807
- const thresholdMs = React36.useMemo(
4944
+ const thresholdMs = React37.useMemo(
4808
4945
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
4809
4946
  [thresholdValue, effectiveRange.granularity]
4810
4947
  );
4811
- const groupedEntries = React36.useMemo(
4948
+ const groupedEntries = React37.useMemo(
4812
4949
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
4813
4950
  granularity: effectiveRange.granularity,
4814
4951
  locale: baseLocale
4815
4952
  }),
4816
4953
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
4817
4954
  );
4818
- const [expandedGroupIds, setExpandedGroupIds] = React36.useState(
4955
+ const [expandedGroupIds, setExpandedGroupIds] = React37.useState(
4819
4956
  () => /* @__PURE__ */ new Set()
4820
4957
  );
4821
- React36.useEffect(() => {
4958
+ React37.useEffect(() => {
4822
4959
  setExpandedGroupIds((prev) => {
4823
4960
  if (!prev || prev.size === 0) return prev;
4824
4961
  const validIds = new Set(
@@ -4833,7 +4970,7 @@ function Timeline({
4833
4970
  return changed ? next : prev;
4834
4971
  });
4835
4972
  }, [groupedEntries]);
4836
- const toggleGroup = React36.useCallback((groupId) => {
4973
+ const toggleGroup = React37.useCallback((groupId) => {
4837
4974
  setExpandedGroupIds((prev) => {
4838
4975
  const next = new Set(prev || []);
4839
4976
  if (next.has(groupId)) next.delete(groupId);
@@ -4856,7 +4993,7 @@ function Timeline({
4856
4993
  point.id === activeId ? "is-active" : "",
4857
4994
  point.highlight ? "is-highlighted" : ""
4858
4995
  ].filter(Boolean).join(" ");
4859
- const connector = /* @__PURE__ */ React36.createElement(
4996
+ const connector = /* @__PURE__ */ React37.createElement(
4860
4997
  TimelineConnector,
4861
4998
  {
4862
4999
  side: point.side,
@@ -4864,9 +5001,9 @@ function Timeline({
4864
5001
  highlight: point.highlight
4865
5002
  }
4866
5003
  );
4867
- const body = /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
5004
+ const body = /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
4868
5005
  const resourceSection = renderResourceSection(point);
4869
- return /* @__PURE__ */ React36.createElement(
5006
+ return /* @__PURE__ */ React37.createElement(
4870
5007
  "div",
4871
5008
  {
4872
5009
  key: point.id,
@@ -4874,7 +5011,7 @@ function Timeline({
4874
5011
  style: wrapperStyle,
4875
5012
  role: "listitem"
4876
5013
  },
4877
- point.side === "left" ? /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React36.createElement(React36.Fragment, null, connector, /* @__PURE__ */ React36.createElement("div", { className: cardClasses }, body, resourceSection))
5014
+ point.side === "left" ? /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React37.createElement(React37.Fragment, null, connector, /* @__PURE__ */ React37.createElement("div", { className: cardClasses }, body, resourceSection))
4878
5015
  );
4879
5016
  }
4880
5017
  function renderGroupEntry(entry) {
@@ -4885,7 +5022,7 @@ function Timeline({
4885
5022
  const wrapperStyle = { top: `${entry.progress * 100}%` };
4886
5023
  const isExpanded = expandedGroupIds.has(entry.id);
4887
5024
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
4888
- const connector = /* @__PURE__ */ React36.createElement(
5025
+ const connector = /* @__PURE__ */ React37.createElement(
4889
5026
  TimelineConnector,
4890
5027
  {
4891
5028
  side: entry.side,
@@ -4899,7 +5036,7 @@ function Timeline({
4899
5036
  hasActivePoint ? "is-active" : ""
4900
5037
  ].filter(Boolean).join(" ");
4901
5038
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
4902
- const header = /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React36.createElement(
5039
+ const header = /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React37.createElement(
4903
5040
  "button",
4904
5041
  {
4905
5042
  type: "button",
@@ -4909,7 +5046,7 @@ function Timeline({
4909
5046
  },
4910
5047
  isExpanded ? "Hide details" : "Show details"
4911
5048
  ));
4912
- const groupPoints = isExpanded ? /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React36.createElement(
5049
+ const groupPoints = isExpanded ? /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React37.createElement(
4913
5050
  "button",
4914
5051
  {
4915
5052
  key: point.id,
@@ -4920,11 +5057,11 @@ function Timeline({
4920
5057
  ].filter(Boolean).join(" "),
4921
5058
  onClick: () => setActiveId(point.id)
4922
5059
  },
4923
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
4924
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
5060
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
5061
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
4925
5062
  ))) : null;
4926
- const groupCard = /* @__PURE__ */ React36.createElement("div", { className: groupClasses }, header, groupPoints);
4927
- return /* @__PURE__ */ React36.createElement(
5063
+ const groupCard = /* @__PURE__ */ React37.createElement("div", { className: groupClasses }, header, groupPoints);
5064
+ return /* @__PURE__ */ React37.createElement(
4928
5065
  "div",
4929
5066
  {
4930
5067
  key: entry.id,
@@ -4932,17 +5069,17 @@ function Timeline({
4932
5069
  style: wrapperStyle,
4933
5070
  role: "listitem"
4934
5071
  },
4935
- entry.side === "left" ? /* @__PURE__ */ React36.createElement(React36.Fragment, null, groupCard, connector) : /* @__PURE__ */ React36.createElement(React36.Fragment, null, connector, groupCard)
5072
+ entry.side === "left" ? /* @__PURE__ */ React37.createElement(React37.Fragment, null, groupCard, connector) : /* @__PURE__ */ React37.createElement(React37.Fragment, null, connector, groupCard)
4936
5073
  );
4937
5074
  }
4938
- return /* @__PURE__ */ React36.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React36.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React36.createElement(
5075
+ return /* @__PURE__ */ React37.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React37.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React37.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React37.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React37.createElement(
4939
5076
  "div",
4940
5077
  {
4941
5078
  className: "canopy-timeline__list",
4942
5079
  role: "list",
4943
5080
  style: { minHeight: trackHeight }
4944
5081
  },
4945
- /* @__PURE__ */ React36.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
5082
+ /* @__PURE__ */ React37.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
4946
5083
  renderSteps(stepsValue, effectiveRange),
4947
5084
  groupedEntries.map((entry) => {
4948
5085
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -4957,7 +5094,7 @@ function renderSteps(stepSize, range) {
4957
5094
  const markers = [];
4958
5095
  if (startYear < endYear) {
4959
5096
  markers.push(
4960
- /* @__PURE__ */ React36.createElement(
5097
+ /* @__PURE__ */ React37.createElement(
4961
5098
  "span",
4962
5099
  {
4963
5100
  key: "timeline-step-start",
@@ -4965,12 +5102,12 @@ function renderSteps(stepSize, range) {
4965
5102
  style: { top: "0%" },
4966
5103
  "aria-hidden": "true"
4967
5104
  },
4968
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-line" }),
4969
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
5105
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-line" }),
5106
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
4970
5107
  )
4971
5108
  );
4972
5109
  markers.push(
4973
- /* @__PURE__ */ React36.createElement(
5110
+ /* @__PURE__ */ React37.createElement(
4974
5111
  "span",
4975
5112
  {
4976
5113
  key: "timeline-step-end",
@@ -4978,8 +5115,8 @@ function renderSteps(stepSize, range) {
4978
5115
  style: { top: "100%" },
4979
5116
  "aria-hidden": "true"
4980
5117
  },
4981
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-line" }),
4982
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
5118
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-line" }),
5119
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
4983
5120
  )
4984
5121
  );
4985
5122
  }
@@ -4989,7 +5126,7 @@ function renderSteps(stepSize, range) {
4989
5126
  const progress = (timestamp - range.startDate.getTime()) / range.span;
4990
5127
  if (progress <= 0 || progress >= 1) continue;
4991
5128
  markers.push(
4992
- /* @__PURE__ */ React36.createElement(
5129
+ /* @__PURE__ */ React37.createElement(
4993
5130
  "span",
4994
5131
  {
4995
5132
  key: `timeline-step-${year}`,
@@ -4997,8 +5134,8 @@ function renderSteps(stepSize, range) {
4997
5134
  style: { top: `calc(${progress * 100}% - 0.5px)` },
4998
5135
  "aria-hidden": "true"
4999
5136
  },
5000
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-line" }),
5001
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-timeline__step-label" }, year)
5137
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-line" }),
5138
+ /* @__PURE__ */ React37.createElement("span", { className: "canopy-timeline__step-label" }, year)
5002
5139
  )
5003
5140
  );
5004
5141
  }
@@ -5012,7 +5149,7 @@ function TimelinePoint() {
5012
5149
  TimelinePoint.displayName = "TimelinePoint";
5013
5150
 
5014
5151
  // ui/src/utils/manifestReferences.js
5015
- import React37 from "react";
5152
+ import React38 from "react";
5016
5153
  var CONTEXT_KEY2 = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
5017
5154
  function getGlobalRoot() {
5018
5155
  if (typeof globalThis !== "undefined") return globalThis;
@@ -5023,7 +5160,7 @@ function getGlobalRoot() {
5023
5160
  function getPageContext2() {
5024
5161
  const root = getGlobalRoot();
5025
5162
  if (root && root[CONTEXT_KEY2]) return root[CONTEXT_KEY2];
5026
- const ctx = React37.createContext({
5163
+ const ctx = React38.createContext({
5027
5164
  navigation: null,
5028
5165
  page: null,
5029
5166
  site: null,
@@ -5047,7 +5184,7 @@ function normalizeManifestId(raw) {
5047
5184
  return String(raw || "").trim();
5048
5185
  }
5049
5186
  }
5050
- var PageContextFallback = React37.createContext(null);
5187
+ var PageContextFallback = React38.createContext(null);
5051
5188
  var referencedModule = null;
5052
5189
  var REFERENCED_SPEC = "@canopy-iiif/app/lib/components/referenced.js";
5053
5190
  function getReferencedModule() {
@@ -5072,10 +5209,10 @@ function getReferencedModule() {
5072
5209
  return referencedModule;
5073
5210
  }
5074
5211
  function useReferencedManifestMap() {
5075
- const PageContext2 = getPageContext2() || PageContextFallback;
5076
- const pageContext = React37.useContext(PageContext2);
5212
+ const PageContext3 = getPageContext2() || PageContextFallback;
5213
+ const pageContext = React38.useContext(PageContext3);
5077
5214
  const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
5078
- return React37.useMemo(() => {
5215
+ return React38.useMemo(() => {
5079
5216
  const map = /* @__PURE__ */ new Map();
5080
5217
  referencedItems.forEach((item) => {
5081
5218
  if (!item) return;
@@ -5186,7 +5323,7 @@ function normalizeResource(resource, index) {
5186
5323
  }
5187
5324
  function normalizePoint(child, index, options) {
5188
5325
  var _a, _b, _c, _d, _e, _f;
5189
- if (!React38.isValidElement(child)) return null;
5326
+ if (!React39.isValidElement(child)) return null;
5190
5327
  if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
5191
5328
  return null;
5192
5329
  const props = child.props || {};
@@ -5202,7 +5339,7 @@ function normalizePoint(child, index, options) {
5202
5339
  try {
5203
5340
  if (props.children) {
5204
5341
  detailsHtml = ReactDOMServer.renderToStaticMarkup(
5205
- React38.createElement(React38.Fragment, null, props.children)
5342
+ React39.createElement(React39.Fragment, null, props.children)
5206
5343
  );
5207
5344
  }
5208
5345
  } catch (_) {
@@ -5251,7 +5388,7 @@ function MdxTimeline({ children, ...rest }) {
5251
5388
  const localeObj = createLocale(localeValue);
5252
5389
  const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
5253
5390
  const manifestMap = useReferencedManifestMap();
5254
- const childArray = React38.Children.toArray(children);
5391
+ const childArray = React39.Children.toArray(children);
5255
5392
  const points = childArray.map(
5256
5393
  (child, index) => normalizePoint(child, index, {
5257
5394
  range: rest.range || {},
@@ -5267,7 +5404,7 @@ function MdxTimeline({ children, ...rest }) {
5267
5404
  steps: rest.steps != null ? rest.steps : null
5268
5405
  };
5269
5406
  const json = serializeForScript(serializeProps(rest, payload, localeBase));
5270
- return /* @__PURE__ */ React38.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React38.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React38.createElement(
5407
+ return /* @__PURE__ */ React39.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React39.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React39.createElement(
5271
5408
  "script",
5272
5409
  {
5273
5410
  type: "application/json",
@@ -5277,7 +5414,7 @@ function MdxTimeline({ children, ...rest }) {
5277
5414
  }
5278
5415
 
5279
5416
  // ui/src/content/map/MdxMap.jsx
5280
- import React39 from "react";
5417
+ import React40 from "react";
5281
5418
  import ReactDOMServer2 from "react-dom/server";
5282
5419
 
5283
5420
  // ui/src/content/map/MapPoint.jsx
@@ -5312,7 +5449,7 @@ function renderDetailsHtml(children) {
5312
5449
  if (!children) return "";
5313
5450
  try {
5314
5451
  return ReactDOMServer2.renderToStaticMarkup(
5315
- React39.createElement(React39.Fragment, null, children)
5452
+ React40.createElement(React40.Fragment, null, children)
5316
5453
  );
5317
5454
  } catch (_) {
5318
5455
  return "";
@@ -5345,7 +5482,7 @@ function pickManifestSummary(manifest) {
5345
5482
  }
5346
5483
  function normalizeCustomPoint(child, index, manifestMap) {
5347
5484
  var _a;
5348
- if (!React39.isValidElement(child)) return null;
5485
+ if (!React40.isValidElement(child)) return null;
5349
5486
  if (child.type !== MapPoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "MapPoint") return null;
5350
5487
  const coords = normalizeCoordinates(child.props || {});
5351
5488
  if (!coords) return null;
@@ -5408,7 +5545,7 @@ function normalizeCustomPoint(child, index, manifestMap) {
5408
5545
  };
5409
5546
  }
5410
5547
  function normalizeCustomPoints(children, manifestMap) {
5411
- return React39.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
5548
+ return React40.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
5412
5549
  }
5413
5550
  function normalizeHeight(value) {
5414
5551
  if (value == null) return "600px";
@@ -5585,11 +5722,11 @@ function MdxMap({ children, ...rest }) {
5585
5722
  if (placeholderClass) placeholderProps.className = placeholderClass;
5586
5723
  if (rest.id) placeholderProps.id = rest.id;
5587
5724
  if (rest.style) placeholderProps.style = rest.style;
5588
- return /* @__PURE__ */ React39.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React39.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React39.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React39.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5725
+ return /* @__PURE__ */ React40.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React40.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React40.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5589
5726
  }
5590
5727
 
5591
5728
  // ui/src/content/gallery/Gallery.jsx
5592
- import React40 from "react";
5729
+ import React41 from "react";
5593
5730
  var INLINE_SCRIPT2 = `(() => {
5594
5731
  if (typeof window === 'undefined') return;
5595
5732
  if (window.__canopyGalleryBound) return;
@@ -5606,6 +5743,23 @@ var INLINE_SCRIPT2 = `(() => {
5606
5743
  const NAV_OPTION_SELECTOR = '[data-canopy-gallery-nav-option]';
5607
5744
  const NAV_ITEM_SELECTOR = '[data-canopy-gallery-nav-item]';
5608
5745
 
5746
+ function emitModalState(modal, state) {
5747
+ if (!modal || typeof window === 'undefined') return;
5748
+ const detail = { modalId: modal.id || '', modal, state };
5749
+ try {
5750
+ const EventCtor = window.CustomEvent || CustomEvent;
5751
+ if (typeof EventCtor === 'function') {
5752
+ window.dispatchEvent(new EventCtor('canopy:gallery:modal-change', { detail }));
5753
+ return;
5754
+ }
5755
+ } catch (_) {}
5756
+ try {
5757
+ const fallback = document.createEvent('CustomEvent');
5758
+ fallback.initCustomEvent('canopy:gallery:modal-change', true, true, detail);
5759
+ window.dispatchEvent(fallback);
5760
+ } catch (_) {}
5761
+ }
5762
+
5609
5763
  function isVisible(node) {
5610
5764
  return !!(node && (node.offsetWidth || node.offsetHeight || node.getClientRects().length));
5611
5765
  }
@@ -5736,6 +5890,7 @@ var INLINE_SCRIPT2 = `(() => {
5736
5890
  lockScroll();
5737
5891
  document.addEventListener('keydown', handleKeydown, true);
5738
5892
  } else if (activeModal !== modal) {
5893
+ emitModalState(activeModal, 'close');
5739
5894
  activeModal.removeAttribute('data-canopy-gallery-active');
5740
5895
  }
5741
5896
  activeModal = modal;
@@ -5744,6 +5899,7 @@ var INLINE_SCRIPT2 = `(() => {
5744
5899
  if (!focusActiveNav(modal)) {
5745
5900
  focusInitial(modal);
5746
5901
  }
5902
+ emitModalState(modal, 'open');
5747
5903
  return;
5748
5904
  }
5749
5905
  if (!activeModal) return;
@@ -5777,6 +5933,7 @@ var INLINE_SCRIPT2 = `(() => {
5777
5933
  }
5778
5934
  });
5779
5935
  }
5936
+ emitModalState(previous, 'close');
5780
5937
  }
5781
5938
 
5782
5939
  function modalFromHash() {
@@ -6100,7 +6257,7 @@ function shuffleItems(list) {
6100
6257
  function renderMetaList(meta, className) {
6101
6258
  const entries = ensureArray2(meta).filter((entry) => entry || entry === 0);
6102
6259
  if (!entries.length) return null;
6103
- return /* @__PURE__ */ React40.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React40.createElement("li", { key: `meta-${index}` }, entry)));
6260
+ return /* @__PURE__ */ React41.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React41.createElement("li", { key: `meta-${index}` }, entry)));
6104
6261
  }
6105
6262
  function renderPreview(props = {}) {
6106
6263
  const source = typeof props.media === "string" && props.media || props.thumbnail || props.src || props.image && props.image.src || props.image;
@@ -6108,7 +6265,7 @@ function renderPreview(props = {}) {
6108
6265
  const alt = props.thumbnailAlt || props.imageAlt || props.alt || props.title || "";
6109
6266
  const width = props.thumbnailWidth || props.imageWidth || props.width;
6110
6267
  const height = props.thumbnailHeight || props.imageHeight || props.height;
6111
- return /* @__PURE__ */ React40.createElement(
6268
+ return /* @__PURE__ */ React41.createElement(
6112
6269
  "img",
6113
6270
  {
6114
6271
  src: source,
@@ -6119,7 +6276,7 @@ function renderPreview(props = {}) {
6119
6276
  }
6120
6277
  );
6121
6278
  }
6122
- return /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
6279
+ return /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
6123
6280
  }
6124
6281
  function renderFlexibleContent(content, options = {}) {
6125
6282
  var _a, _b;
@@ -6132,25 +6289,25 @@ function renderFlexibleContent(content, options = {}) {
6132
6289
  if (content == null || content === false) return null;
6133
6290
  const isPrimitive = typeof content === "string" || typeof content === "number" || typeof content === "bigint";
6134
6291
  if (isPrimitive) {
6135
- return /* @__PURE__ */ React40.createElement(InlineTag, { className, id }, content);
6292
+ return /* @__PURE__ */ React41.createElement(InlineTag, { className, id }, content);
6136
6293
  }
6137
- if (React40.isValidElement(content)) {
6138
- if (content.type === React40.Fragment) {
6139
- return /* @__PURE__ */ React40.createElement(BlockTag, { className, id }, content);
6294
+ if (React41.isValidElement(content)) {
6295
+ if (content.type === React41.Fragment) {
6296
+ return /* @__PURE__ */ React41.createElement(BlockTag, { className, id }, content);
6140
6297
  }
6141
6298
  const mergedClassName = [(_a = content.props) == null ? void 0 : _a.className, className].filter(Boolean).join(" ");
6142
- return React40.cloneElement(content, {
6299
+ return React41.cloneElement(content, {
6143
6300
  ...content.props,
6144
6301
  className: mergedClassName || void 0,
6145
6302
  id: ((_b = content.props) == null ? void 0 : _b.id) || id
6146
6303
  });
6147
6304
  }
6148
6305
  const FallbackTag = BlockTag;
6149
- return /* @__PURE__ */ React40.createElement(FallbackTag, { className, id }, content);
6306
+ return /* @__PURE__ */ React41.createElement(FallbackTag, { className, id }, content);
6150
6307
  }
6151
6308
  function normalizeItem(child, index, galleryId, manifestMap) {
6152
6309
  var _a;
6153
- if (!React40.isValidElement(child)) return null;
6310
+ if (!React41.isValidElement(child)) return null;
6154
6311
  if (child.type !== GalleryItem && ((_a = child.type) == null ? void 0 : _a.displayName) !== "GalleryItem")
6155
6312
  return null;
6156
6313
  const props = child.props || {};
@@ -6225,7 +6382,7 @@ function buildCaptionContent(itemProps) {
6225
6382
  if (itemProps.caption) return itemProps.caption;
6226
6383
  const kicker = itemProps.kicker || itemProps.label || itemProps.eyebrow;
6227
6384
  const summary = itemProps.summary || itemProps.description;
6228
- return /* @__PURE__ */ React40.createElement(React40.Fragment, null, kicker ? /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, renderFlexibleContent(summary, {
6385
+ return /* @__PURE__ */ React41.createElement(React41.Fragment, null, kicker ? /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, renderFlexibleContent(summary, {
6229
6386
  inlineTag: "span",
6230
6387
  blockTag: "div",
6231
6388
  className: "canopy-gallery__summary"
@@ -6235,6 +6392,7 @@ function buildCaptionContent(itemProps) {
6235
6392
  ));
6236
6393
  }
6237
6394
  function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6395
+ const { getString, formatString } = useLocale();
6238
6396
  const {
6239
6397
  props,
6240
6398
  modalId,
@@ -6247,7 +6405,13 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6247
6405
  const kicker = props.kicker || props.label || props.eyebrow;
6248
6406
  const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
6249
6407
  const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
6250
- return /* @__PURE__ */ React40.createElement(
6408
+ const closeButtonText = getString("common.actions.close", "Close");
6409
+ const closeButtonLabel = formatString(
6410
+ "common.phrases.close_content",
6411
+ "Close {content}",
6412
+ { content: modalTitle }
6413
+ );
6414
+ return /* @__PURE__ */ React41.createElement(
6251
6415
  "div",
6252
6416
  {
6253
6417
  id: modalId,
@@ -6260,22 +6424,23 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6260
6424
  "data-canopy-gallery-modal": "true",
6261
6425
  "data-canopy-gallery-close": closeTargetId
6262
6426
  },
6263
- /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React40.createElement(
6427
+ /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React41.createElement(
6264
6428
  GalleryThumbnailNav,
6265
6429
  {
6266
6430
  items: navItems,
6267
6431
  activeModalId: modalId,
6268
6432
  groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
6269
6433
  }
6270
- ), /* @__PURE__ */ React40.createElement(
6271
- "a",
6434
+ ), /* @__PURE__ */ React41.createElement(
6435
+ Button,
6272
6436
  {
6273
6437
  className: "canopy-gallery__modal-close",
6274
6438
  href: `#${closeTargetId}`,
6275
- "aria-label": `Close popup for ${modalTitle}`
6276
- },
6277
- "X"
6278
- )), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React40.createElement(
6439
+ label: closeButtonText,
6440
+ "aria-label": closeButtonLabel,
6441
+ variant: "secondary"
6442
+ }
6443
+ )), /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React41.createElement(
6279
6444
  "button",
6280
6445
  {
6281
6446
  type: "button",
@@ -6283,7 +6448,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6283
6448
  "aria-label": "Scroll left through gallery thumbnails",
6284
6449
  "data-canopy-gallery-nav-prev": "true"
6285
6450
  },
6286
- /* @__PURE__ */ React40.createElement(
6451
+ /* @__PURE__ */ React41.createElement(
6287
6452
  "span",
6288
6453
  {
6289
6454
  className: "canopy-gallery__nav-button-icon",
@@ -6292,8 +6457,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6292
6457
  },
6293
6458
  "<"
6294
6459
  ),
6295
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
6296
- ), /* @__PURE__ */ React40.createElement(
6460
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
6461
+ ), /* @__PURE__ */ React41.createElement(
6297
6462
  "button",
6298
6463
  {
6299
6464
  type: "button",
@@ -6301,7 +6466,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6301
6466
  "aria-label": "Scroll right through gallery thumbnails",
6302
6467
  "data-canopy-gallery-nav-next": "true"
6303
6468
  },
6304
- /* @__PURE__ */ React40.createElement(
6469
+ /* @__PURE__ */ React41.createElement(
6305
6470
  "span",
6306
6471
  {
6307
6472
  className: "canopy-gallery__nav-button-icon",
@@ -6310,8 +6475,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6310
6475
  },
6311
6476
  ">"
6312
6477
  ),
6313
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
6314
- ), /* @__PURE__ */ React40.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React40.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), renderFlexibleContent(summary, {
6478
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
6479
+ ), /* @__PURE__ */ React41.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React41.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), renderFlexibleContent(summary, {
6315
6480
  inlineTag: "p",
6316
6481
  blockTag: "div",
6317
6482
  className: "canopy-gallery__modal-summary",
@@ -6319,20 +6484,20 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
6319
6484
  }), renderMetaList(
6320
6485
  props.meta,
6321
6486
  "canopy-gallery__meta canopy-gallery__meta--modal"
6322
- ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React40.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
6487
+ ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React41.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
6323
6488
  );
6324
6489
  }
6325
6490
  function GalleryFigure({ item }) {
6326
6491
  const { props, modalId, triggerLabel } = item;
6327
- return /* @__PURE__ */ React40.createElement(
6492
+ return /* @__PURE__ */ React41.createElement(
6328
6493
  "figure",
6329
6494
  {
6330
6495
  className: "canopy-gallery__item",
6331
6496
  "data-gallery-item-index": item.index
6332
6497
  },
6333
- /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
6334
- /* @__PURE__ */ React40.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
6335
- /* @__PURE__ */ React40.createElement(
6498
+ /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
6499
+ /* @__PURE__ */ React41.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
6500
+ /* @__PURE__ */ React41.createElement(
6336
6501
  "a",
6337
6502
  {
6338
6503
  className: "canopy-gallery__trigger",
@@ -6342,27 +6507,27 @@ function GalleryFigure({ item }) {
6342
6507
  "aria-label": triggerLabel,
6343
6508
  "data-canopy-gallery-trigger": modalId
6344
6509
  },
6345
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
6510
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
6346
6511
  )
6347
6512
  );
6348
6513
  }
6349
6514
  function GalleryThumbnailNav({ items, activeModalId, groupName }) {
6350
6515
  if (!items || items.length < 2) return null;
6351
6516
  const radioGroup = groupName || "canopy-gallery-nav";
6352
- return /* @__PURE__ */ React40.createElement(
6517
+ return /* @__PURE__ */ React41.createElement(
6353
6518
  "nav",
6354
6519
  {
6355
6520
  className: "canopy-gallery__nav",
6356
6521
  "aria-label": "Gallery navigation",
6357
6522
  "data-canopy-gallery-nav": "true"
6358
6523
  },
6359
- /* @__PURE__ */ React40.createElement(
6524
+ /* @__PURE__ */ React41.createElement(
6360
6525
  "div",
6361
6526
  {
6362
6527
  className: "canopy-gallery__nav-viewport",
6363
6528
  "data-canopy-gallery-nav-viewport": "true"
6364
6529
  },
6365
- /* @__PURE__ */ React40.createElement(
6530
+ /* @__PURE__ */ React41.createElement(
6366
6531
  "ul",
6367
6532
  {
6368
6533
  className: "canopy-gallery__nav-list",
@@ -6372,7 +6537,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
6372
6537
  items.map((item, index) => {
6373
6538
  const optionId = `${radioGroup}-${item.modalId || index}`;
6374
6539
  const isActive = item.modalId === activeModalId;
6375
- return /* @__PURE__ */ React40.createElement(
6540
+ return /* @__PURE__ */ React41.createElement(
6376
6541
  "li",
6377
6542
  {
6378
6543
  key: `${item.key}-nav`,
@@ -6380,7 +6545,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
6380
6545
  "data-canopy-gallery-nav-item": "true",
6381
6546
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
6382
6547
  },
6383
- /* @__PURE__ */ React40.createElement(
6548
+ /* @__PURE__ */ React41.createElement(
6384
6549
  "input",
6385
6550
  {
6386
6551
  type: "radio",
@@ -6396,15 +6561,15 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
6396
6561
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
6397
6562
  }
6398
6563
  ),
6399
- /* @__PURE__ */ React40.createElement(
6564
+ /* @__PURE__ */ React41.createElement(
6400
6565
  "label",
6401
6566
  {
6402
6567
  className: "canopy-gallery__nav-link",
6403
6568
  htmlFor: optionId,
6404
6569
  "data-canopy-gallery-nav-active": isActive ? "1" : void 0
6405
6570
  },
6406
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
6407
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
6571
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
6572
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
6408
6573
  )
6409
6574
  );
6410
6575
  })
@@ -6417,7 +6582,7 @@ function GalleryContent({ children, flex = false }) {
6417
6582
  "canopy-gallery-item__content",
6418
6583
  flex ? "canopy-gallery-item__content_flex" : null
6419
6584
  ].filter(Boolean).join(" ");
6420
- return /* @__PURE__ */ React40.createElement("div", { className: contentClassName }, children);
6585
+ return /* @__PURE__ */ React41.createElement("div", { className: contentClassName }, children);
6421
6586
  }
6422
6587
  function GalleryItem() {
6423
6588
  return null;
@@ -6441,7 +6606,7 @@ function Gallery({
6441
6606
  const galleryId = id ? String(id) : nextGalleryInstanceId();
6442
6607
  const HeadingTag = "h3";
6443
6608
  const closeTargetId = `${galleryId}-close`;
6444
- const childArray = React40.Children.toArray(children);
6609
+ const childArray = React41.Children.toArray(children);
6445
6610
  const items = childArray.map((child, index) => normalizeItem(child, index, galleryId, manifestMap)).filter(Boolean);
6446
6611
  if (!items.length) return null;
6447
6612
  const popupMode = normalizePopupSize(popupSize);
@@ -6453,7 +6618,7 @@ function Gallery({
6453
6618
  className
6454
6619
  ].filter(Boolean).join(" ");
6455
6620
  const navGroupName = `${galleryId}-nav`;
6456
- return /* @__PURE__ */ React40.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React40.createElement(
6621
+ return /* @__PURE__ */ React41.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React41.createElement(
6457
6622
  "div",
6458
6623
  {
6459
6624
  id: closeTargetId,
@@ -6461,7 +6626,7 @@ function Gallery({
6461
6626
  "aria-hidden": "true",
6462
6627
  tabIndex: -1
6463
6628
  }
6464
- ), (title || description) && /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React40.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React40.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React40.createElement(
6629
+ ), (title || description) && /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React41.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React41.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React41.createElement(
6465
6630
  GalleryModal,
6466
6631
  {
6467
6632
  key: `${item.modalId}-modal`,
@@ -6470,7 +6635,7 @@ function Gallery({
6470
6635
  navItems: orderedItems,
6471
6636
  navGroupName
6472
6637
  }
6473
- ))), /* @__PURE__ */ React40.createElement(
6638
+ ))), /* @__PURE__ */ React41.createElement(
6474
6639
  "script",
6475
6640
  {
6476
6641
  "data-canopy-gallery-script": "true",
@@ -6482,7 +6647,7 @@ Gallery.Item = GalleryItem;
6482
6647
  Gallery.Content = GalleryContent;
6483
6648
 
6484
6649
  // ui/src/search/MdxSearchResults.jsx
6485
- import React41 from "react";
6650
+ import React42 from "react";
6486
6651
  function MdxSearchResults(props) {
6487
6652
  let json = "{}";
6488
6653
  try {
@@ -6490,11 +6655,11 @@ function MdxSearchResults(props) {
6490
6655
  } catch (_) {
6491
6656
  json = "{}";
6492
6657
  }
6493
- return /* @__PURE__ */ React41.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React41.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6658
+ return /* @__PURE__ */ React42.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React42.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6494
6659
  }
6495
6660
 
6496
6661
  // ui/src/search/SearchSummary.jsx
6497
- import React42 from "react";
6662
+ import React43 from "react";
6498
6663
  function SearchSummary(props) {
6499
6664
  let json = "{}";
6500
6665
  try {
@@ -6502,11 +6667,11 @@ function SearchSummary(props) {
6502
6667
  } catch (_) {
6503
6668
  json = "{}";
6504
6669
  }
6505
- return /* @__PURE__ */ React42.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React42.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6670
+ return /* @__PURE__ */ React43.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React43.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6506
6671
  }
6507
6672
 
6508
6673
  // ui/src/search/MdxSearchTabs.jsx
6509
- import React43 from "react";
6674
+ import React44 from "react";
6510
6675
  function MdxSearchTabs(props) {
6511
6676
  let json = "{}";
6512
6677
  try {
@@ -6514,11 +6679,11 @@ function MdxSearchTabs(props) {
6514
6679
  } catch (_) {
6515
6680
  json = "{}";
6516
6681
  }
6517
- return /* @__PURE__ */ React43.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React43.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6682
+ return /* @__PURE__ */ React44.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React44.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6518
6683
  }
6519
6684
 
6520
6685
  // ui/src/search/MdxSearch.jsx
6521
- import React44 from "react";
6686
+ import React45 from "react";
6522
6687
  function MdxSearch(props = {}) {
6523
6688
  const {
6524
6689
  layout,
@@ -6536,11 +6701,11 @@ function MdxSearch(props = {}) {
6536
6701
  resultsPayload.layout = layout;
6537
6702
  }
6538
6703
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
6539
- return /* @__PURE__ */ React44.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React44.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React44.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React44.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
6704
+ return /* @__PURE__ */ React45.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React45.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React45.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React45.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
6540
6705
  }
6541
6706
 
6542
6707
  // ui/src/search-form/MdxSearchFormModal.jsx
6543
- import React45 from "react";
6708
+ import React46 from "react";
6544
6709
  function MdxSearchFormModal(props = {}) {
6545
6710
  const {
6546
6711
  placeholder: placeholderProp,
@@ -6559,12 +6724,12 @@ function MdxSearchFormModal(props = {}) {
6559
6724
  const text = typeof label === "string" && label.trim() ? label.trim() : resolvedButtonLabel;
6560
6725
  const resolvedSearchPath = resolveSearchPath(searchPath);
6561
6726
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
6562
- return /* @__PURE__ */ React45.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React45.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React45.createElement(SearchPanelForm, { placeholder, buttonLabel: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React45.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React45.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
6727
+ return /* @__PURE__ */ React46.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React46.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React46.createElement(SearchPanelForm, { placeholder, buttonLabel: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React46.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React46.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
6563
6728
  }
6564
6729
 
6565
6730
  // ui/src/iiif/ManifestPrimitives.jsx
6566
6731
  var import_slugify2 = __toESM(require_slugify());
6567
- import React46 from "react";
6732
+ import React47 from "react";
6568
6733
  import {
6569
6734
  Label as CloverLabel,
6570
6735
  Metadata as CloverMetadata,
@@ -6705,7 +6870,7 @@ function MetadataFacetLink(props) {
6705
6870
  const valueSlug = facetSlug ? toValueSlug(text) : "";
6706
6871
  const href = facetSlug && valueSlug ? buildFacetSearchHref(facetSlug, valueSlug) : "";
6707
6872
  if (!href) return text;
6708
- return /* @__PURE__ */ React46.createElement(
6873
+ return /* @__PURE__ */ React47.createElement(
6709
6874
  "a",
6710
6875
  {
6711
6876
  href,
@@ -6731,7 +6896,7 @@ function buildFacetCustomValueContent(items, manifest) {
6731
6896
  seen.add(normalized);
6732
6897
  custom.push({
6733
6898
  matchingLabel: item.label,
6734
- Content: /* @__PURE__ */ React46.createElement(MetadataFacetLink, { facetSlug: facet.slug })
6899
+ Content: /* @__PURE__ */ React47.createElement(MetadataFacetLink, { facetSlug: facet.slug })
6735
6900
  });
6736
6901
  }
6737
6902
  return custom;
@@ -6763,12 +6928,12 @@ function mergeCustomValueContent(userContent, autoContent) {
6763
6928
  function Label({ manifest, label, ...rest }) {
6764
6929
  const intl = label || manifest && manifest.label;
6765
6930
  if (!hasInternationalValue(intl)) return null;
6766
- return /* @__PURE__ */ React46.createElement(CloverLabel, { label: intl, ...rest });
6931
+ return /* @__PURE__ */ React47.createElement(CloverLabel, { label: intl, ...rest });
6767
6932
  }
6768
6933
  function Summary({ manifest, summary, ...rest }) {
6769
6934
  const intl = summary || manifest && manifest.summary;
6770
6935
  if (!hasInternationalValue(intl)) return null;
6771
- return /* @__PURE__ */ React46.createElement(CloverSummary, { summary: intl, ...rest });
6936
+ return /* @__PURE__ */ React47.createElement(CloverSummary, { summary: intl, ...rest });
6772
6937
  }
6773
6938
  function Metadata({ manifest, metadata, customValueContent, ...rest }) {
6774
6939
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
@@ -6778,7 +6943,7 @@ function Metadata({ manifest, metadata, customValueContent, ...rest }) {
6778
6943
  customValueContent,
6779
6944
  autoCustomContent
6780
6945
  );
6781
- return /* @__PURE__ */ React46.createElement(
6946
+ return /* @__PURE__ */ React47.createElement(
6782
6947
  CloverMetadata,
6783
6948
  {
6784
6949
  metadata: items,
@@ -6792,17 +6957,17 @@ function RequiredStatement({ manifest, requiredStatement, ...rest }) {
6792
6957
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
6793
6958
  return null;
6794
6959
  }
6795
- return /* @__PURE__ */ React46.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
6960
+ return /* @__PURE__ */ React47.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
6796
6961
  }
6797
6962
 
6798
6963
  // ui/src/iiif/Properties/Id.jsx
6799
- import React47 from "react";
6964
+ import React48 from "react";
6800
6965
  function Id({ title = "IIIF Manifest", id, ...props }) {
6801
- return /* @__PURE__ */ React47.createElement("dl", null, /* @__PURE__ */ React47.createElement("dt", null, title), /* @__PURE__ */ React47.createElement("dd", null, /* @__PURE__ */ React47.createElement("a", { href: id }, id)));
6966
+ return /* @__PURE__ */ React48.createElement("dl", null, /* @__PURE__ */ React48.createElement("dt", null, title), /* @__PURE__ */ React48.createElement("dd", null, /* @__PURE__ */ React48.createElement("a", { href: id }, id)));
6802
6967
  }
6803
6968
 
6804
6969
  // ui/src/docs/CodeBlock.jsx
6805
- import React48 from "react";
6970
+ import React49 from "react";
6806
6971
  function parseHighlightAttr(attr) {
6807
6972
  if (!attr) return /* @__PURE__ */ new Set();
6808
6973
  const cleaned = String(attr || "").trim();
@@ -6848,10 +7013,10 @@ var highlightBaseStyle = {
6848
7013
  };
6849
7014
  function DocsCodeBlock(props = {}) {
6850
7015
  const { children, ...rest } = props;
6851
- const childArray = React48.Children.toArray(children);
6852
- const codeElement = childArray.find((el) => React48.isValidElement(el));
7016
+ const childArray = React49.Children.toArray(children);
7017
+ const codeElement = childArray.find((el) => React49.isValidElement(el));
6853
7018
  if (!codeElement || !codeElement.props) {
6854
- return React48.createElement("pre", props);
7019
+ return React49.createElement("pre", props);
6855
7020
  }
6856
7021
  const {
6857
7022
  className = "",
@@ -6866,9 +7031,9 @@ function DocsCodeBlock(props = {}) {
6866
7031
  const highlightSet = parseHighlightAttr(highlightAttr);
6867
7032
  const copyAttr = codeProps["data-copy"];
6868
7033
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
6869
- const [copied, setCopied] = React48.useState(false);
6870
- const buttonRef = React48.useRef(null);
6871
- const handleCopy = React48.useCallback(async () => {
7034
+ const [copied, setCopied] = React49.useState(false);
7035
+ const buttonRef = React49.useRef(null);
7036
+ const handleCopy = React49.useCallback(async () => {
6872
7037
  const text = trimmedCode;
6873
7038
  try {
6874
7039
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -6890,12 +7055,12 @@ function DocsCodeBlock(props = {}) {
6890
7055
  setCopied(false);
6891
7056
  }
6892
7057
  }, [trimmedCode]);
6893
- React48.useEffect(() => {
7058
+ React49.useEffect(() => {
6894
7059
  if (buttonRef.current) {
6895
7060
  buttonRef.current.setAttribute("data-docs-copy-hydrated", "true");
6896
7061
  }
6897
7062
  }, []);
6898
- React48.useEffect(() => {
7063
+ React49.useEffect(() => {
6899
7064
  if (!buttonRef.current) return;
6900
7065
  if (copied) buttonRef.current.setAttribute("data-docs-copy-active", "true");
6901
7066
  else buttonRef.current.removeAttribute("data-docs-copy-active");
@@ -6958,27 +7123,27 @@ function DocsCodeBlock(props = {}) {
6958
7123
  const highlight = highlightSet.has(lineNumber);
6959
7124
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
6960
7125
  const displayLine = line === "" ? " " : line;
6961
- return React48.createElement(
7126
+ return React49.createElement(
6962
7127
  "span",
6963
7128
  {
6964
7129
  key: lineNumber,
6965
7130
  style,
6966
7131
  "data-docs-code-line": line
6967
7132
  },
6968
- React48.createElement("span", { style: lineContentStyle }, displayLine)
7133
+ React49.createElement("span", { style: lineContentStyle }, displayLine)
6969
7134
  );
6970
7135
  });
6971
- return React48.createElement(
7136
+ return React49.createElement(
6972
7137
  "div",
6973
7138
  {
6974
7139
  style: containerStyle,
6975
7140
  "data-docs-code-block": "true"
6976
7141
  },
6977
- showHeader ? React48.createElement(
7142
+ showHeader ? React49.createElement(
6978
7143
  "div",
6979
7144
  { style: headerStyle },
6980
- React48.createElement("span", null, showFilename ? filename : null),
6981
- enableCopy ? React48.createElement(
7145
+ React49.createElement("span", null, showFilename ? filename : null),
7146
+ enableCopy ? React49.createElement(
6982
7147
  "button",
6983
7148
  {
6984
7149
  ref: buttonRef,
@@ -6989,8 +7154,8 @@ function DocsCodeBlock(props = {}) {
6989
7154
  "data-docs-copy-button": "true",
6990
7155
  style: buttonStyle
6991
7156
  },
6992
- React48.createElement("span", null, "Copy"),
6993
- React48.createElement(
7157
+ React49.createElement("span", null, "Copy"),
7158
+ React49.createElement(
6994
7159
  "span",
6995
7160
  {
6996
7161
  "aria-hidden": "true",
@@ -7000,7 +7165,7 @@ function DocsCodeBlock(props = {}) {
7000
7165
  )
7001
7166
  ) : null
7002
7167
  ) : null,
7003
- enableCopy ? React48.createElement("textarea", {
7168
+ enableCopy ? React49.createElement("textarea", {
7004
7169
  "data-docs-copy-source": "true",
7005
7170
  tabIndex: -1,
7006
7171
  readOnly: true,
@@ -7015,29 +7180,29 @@ function DocsCodeBlock(props = {}) {
7015
7180
  pointerEvents: "none"
7016
7181
  }
7017
7182
  }) : null,
7018
- React48.createElement(
7183
+ React49.createElement(
7019
7184
  "pre",
7020
7185
  { ...preRest, className: preClassName, style: mergedPreStyle },
7021
- React48.createElement("code", { style: codeStyle }, lineElements)
7186
+ React49.createElement("code", { style: codeStyle }, lineElements)
7022
7187
  )
7023
7188
  );
7024
7189
  }
7025
7190
 
7026
7191
  // ui/src/docs/MarkdownTable.jsx
7027
- import React49 from "react";
7192
+ import React50 from "react";
7028
7193
  function MarkdownTable({ className = "", ...rest }) {
7029
7194
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
7030
- return /* @__PURE__ */ React49.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React49.createElement("table", { className: merged, ...rest }));
7195
+ return /* @__PURE__ */ React50.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React50.createElement("table", { className: merged, ...rest }));
7031
7196
  }
7032
7197
 
7033
7198
  // ui/src/docs/Diagram.jsx
7034
- import React50 from "react";
7199
+ import React51 from "react";
7035
7200
  function CanopyDiagram() {
7036
- return /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React50.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React50.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Collection A"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React50.createElement("li", null, /* @__PURE__ */ React50.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Collection B"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React50.createElement("li", null, /* @__PURE__ */ React50.createElement("em", null, "Portraits")))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React50.createElement("li", null, /* @__PURE__ */ React50.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React50.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React50.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Automated content"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React50.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React50.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React50.createElement("li", null, "Author narratives"), /* @__PURE__ */ React50.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Search index"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React50.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React50.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React50.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React50.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React50.createElement("span", { className: "canopy-diagram__section-summary" }, "The output is a lightweight bundle of HTML, CSS, JS, and JSON assets that can deploy anywhere."), /* @__PURE__ */ React50.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Work pages"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React50.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React50.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React50.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React50.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React50.createElement("article", null, /* @__PURE__ */ React50.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React50.createElement("ul", null, /* @__PURE__ */ React50.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React50.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React50.createElement("li", null, "Optional annotation dataset"))))));
7201
+ return /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React51.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React51.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Collection A"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React51.createElement("li", null, /* @__PURE__ */ React51.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Collection B"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React51.createElement("li", null, /* @__PURE__ */ React51.createElement("em", null, "Portraits")))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React51.createElement("li", null, /* @__PURE__ */ React51.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React51.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React51.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Automated content"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React51.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React51.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React51.createElement("li", null, "Author narratives"), /* @__PURE__ */ React51.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Search index"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React51.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React51.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React51.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React51.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React51.createElement("span", { className: "canopy-diagram__section-summary" }, "The output is a lightweight bundle of HTML, CSS, JS, and JSON assets that can deploy anywhere."), /* @__PURE__ */ React51.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Work pages"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React51.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React51.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React51.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React51.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React51.createElement("article", null, /* @__PURE__ */ React51.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React51.createElement("ul", null, /* @__PURE__ */ React51.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React51.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React51.createElement("li", null, "Optional annotation dataset"))))));
7037
7202
  }
7038
7203
 
7039
7204
  // ui/src/docs/ThemeShowcase.jsx
7040
- import React51 from "react";
7205
+ import React52 from "react";
7041
7206
 
7042
7207
  // ../../node_modules/@radix-ui/colors/index.mjs
7043
7208
  var colors_exports = {};
@@ -10889,21 +11054,21 @@ var STEP_MAP = {
10889
11054
  800: 11,
10890
11055
  900: 12
10891
11056
  };
10892
- var Section = ({ title, description, children }) => /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React51.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React51.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
10893
- var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React51.createElement("strong", null, label)), /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React51.createElement(
11057
+ var Section = ({ title, description, children }) => /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React52.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React52.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
11058
+ var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React52.createElement("strong", null, label)), /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React52.createElement(
10894
11059
  "div",
10895
11060
  {
10896
11061
  key: `${label}-${stop}`,
10897
11062
  className: "canopy-theme-showcase__scale-stop"
10898
11063
  },
10899
- /* @__PURE__ */ React51.createElement(
11064
+ /* @__PURE__ */ React52.createElement(
10900
11065
  "span",
10901
11066
  {
10902
11067
  className: "canopy-theme-showcase__scale-chip",
10903
11068
  style: { backgroundColor: `var(${prefix}-${stop})` }
10904
11069
  }
10905
11070
  ),
10906
- /* @__PURE__ */ React51.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
11071
+ /* @__PURE__ */ React52.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
10907
11072
  ))));
10908
11073
  var AVAILABLE = new Set(
10909
11074
  Object.keys(colors_exports).filter(
@@ -10968,9 +11133,9 @@ var PREVIEW_DATA = buildPreviewData();
10968
11133
  function encodeJson(value) {
10969
11134
  return JSON.stringify(value).replace(/</g, "\\u003c");
10970
11135
  }
10971
- var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
11136
+ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
10972
11137
  const colorValue = getRadixSwatch(name);
10973
- return /* @__PURE__ */ React51.createElement(
11138
+ return /* @__PURE__ */ React52.createElement(
10974
11139
  "button",
10975
11140
  {
10976
11141
  key: `${type}-${name}`,
@@ -10981,14 +11146,14 @@ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React5
10981
11146
  "data-theme-swatch-value": name,
10982
11147
  "aria-pressed": "false"
10983
11148
  },
10984
- /* @__PURE__ */ React51.createElement(
11149
+ /* @__PURE__ */ React52.createElement(
10985
11150
  "span",
10986
11151
  {
10987
11152
  className: "canopy-theme-showcase__swatch-chip",
10988
11153
  style: { background: colorValue || "var(--color-gray-200)" }
10989
11154
  }
10990
11155
  ),
10991
- /* @__PURE__ */ React51.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
11156
+ /* @__PURE__ */ React52.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
10992
11157
  );
10993
11158
  }));
10994
11159
  function ThemeShowcase() {
@@ -11148,7 +11313,7 @@ function ThemeShowcase() {
11148
11313
  .canopy-theme-showcase__swatch-controls { display: none; }
11149
11314
  .canopy-theme-showcase__clear-button { display: none; }
11150
11315
  `;
11151
- return /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React51.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React51.createElement(
11316
+ return /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React52.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React52.createElement(
11152
11317
  "div",
11153
11318
  {
11154
11319
  style: {
@@ -11159,18 +11324,18 @@ function ThemeShowcase() {
11159
11324
  marginBottom: "1rem"
11160
11325
  }
11161
11326
  },
11162
- /* @__PURE__ */ React51.createElement(
11327
+ /* @__PURE__ */ React52.createElement(
11163
11328
  Section,
11164
11329
  {
11165
11330
  title: "Appearance",
11166
11331
  description: "Pick the base light or dark mode for the theme preview."
11167
11332
  },
11168
- /* @__PURE__ */ React51.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
11333
+ /* @__PURE__ */ React52.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
11169
11334
  const label = `${mode.charAt(0).toUpperCase()}${mode.slice(1)}`;
11170
11335
  const baseClass = "canopy-theme-showcase__appearance-button";
11171
11336
  const isDefault = mode === DEFAULTS.appearance;
11172
11337
  const className = isDefault ? `${baseClass} is-active` : baseClass;
11173
- return /* @__PURE__ */ React51.createElement(
11338
+ return /* @__PURE__ */ React52.createElement(
11174
11339
  "button",
11175
11340
  {
11176
11341
  key: mode,
@@ -11182,7 +11347,7 @@ function ThemeShowcase() {
11182
11347
  );
11183
11348
  }))
11184
11349
  ),
11185
- /* @__PURE__ */ React51.createElement(
11350
+ /* @__PURE__ */ React52.createElement(
11186
11351
  "button",
11187
11352
  {
11188
11353
  type: "button",
@@ -11191,13 +11356,13 @@ function ThemeShowcase() {
11191
11356
  },
11192
11357
  "Reset"
11193
11358
  )
11194
- ), /* @__PURE__ */ React51.createElement(
11359
+ ), /* @__PURE__ */ React52.createElement(
11195
11360
  Section,
11196
11361
  {
11197
11362
  title: "Color scales",
11198
11363
  description: "Accent and gray ramps from the active theme."
11199
11364
  },
11200
- /* @__PURE__ */ React51.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React51.createElement(
11365
+ /* @__PURE__ */ React52.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React52.createElement(
11201
11366
  ColorScaleRow,
11202
11367
  {
11203
11368
  key: scale.label,
@@ -11205,13 +11370,13 @@ function ThemeShowcase() {
11205
11370
  prefix: scale.prefix
11206
11371
  }
11207
11372
  )))
11208
- ), /* @__PURE__ */ React51.createElement(
11373
+ ), /* @__PURE__ */ React52.createElement(
11209
11374
  Section,
11210
11375
  {
11211
11376
  title: "Accent color palette options",
11212
11377
  description: "Click a swatch to temporarily override the accent palette."
11213
11378
  },
11214
- /* @__PURE__ */ React51.createElement(
11379
+ /* @__PURE__ */ React52.createElement(
11215
11380
  ColorsLabeled,
11216
11381
  {
11217
11382
  colors: accentColors,
@@ -11219,13 +11384,13 @@ function ThemeShowcase() {
11219
11384
  getRadixSwatch
11220
11385
  }
11221
11386
  )
11222
- ), /* @__PURE__ */ React51.createElement(
11387
+ ), /* @__PURE__ */ React52.createElement(
11223
11388
  Section,
11224
11389
  {
11225
11390
  title: "Gray color palette options",
11226
11391
  description: "Click a swatch to preview the neutral ramp for surfaces and text."
11227
11392
  },
11228
- /* @__PURE__ */ React51.createElement(
11393
+ /* @__PURE__ */ React52.createElement(
11229
11394
  ColorsLabeled,
11230
11395
  {
11231
11396
  colors: grayColors,
@@ -11233,7 +11398,7 @@ function ThemeShowcase() {
11233
11398
  getRadixSwatch
11234
11399
  }
11235
11400
  )
11236
- ), /* @__PURE__ */ React51.createElement(
11401
+ ), /* @__PURE__ */ React52.createElement(
11237
11402
  "script",
11238
11403
  {
11239
11404
  type: "application/json",
@@ -11253,6 +11418,8 @@ export {
11253
11418
  CanopyModal,
11254
11419
  Card,
11255
11420
  Container,
11421
+ ContentNavigation,
11422
+ ContentNavigationScript,
11256
11423
  DocsCodeBlock,
11257
11424
  MarkdownTable as DocsMarkdownTable,
11258
11425
  Gallery,