@canopy-iiif/app 1.8.15 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2087,7 +2087,7 @@ function Layout({
2087
2087
  }
2088
2088
 
2089
2089
  // ui/src/layout/CanopyHeader.jsx
2090
- import React21 from "react";
2090
+ import React24 from "react";
2091
2091
 
2092
2092
  // ui/src/search/SearchPanel.jsx
2093
2093
  import React18 from "react";
@@ -2400,6 +2400,368 @@ function CanopyModal(props = {}) {
2400
2400
  )) : null, children)));
2401
2401
  }
2402
2402
 
2403
+ // ui/src/layout/pageContext.js
2404
+ import React21 from "react";
2405
+ var CONTEXT_KEY = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
2406
+ function getSharedRoot() {
2407
+ if (typeof globalThis !== "undefined") return globalThis;
2408
+ if (typeof window !== "undefined") return window;
2409
+ if (typeof global !== "undefined") return global;
2410
+ return null;
2411
+ }
2412
+ function getSafePageContext() {
2413
+ const root = getSharedRoot();
2414
+ if (root && root[CONTEXT_KEY]) return root[CONTEXT_KEY];
2415
+ const ctx = React21.createContext({ navigation: null, page: null, site: null });
2416
+ if (root) root[CONTEXT_KEY] = ctx;
2417
+ return ctx;
2418
+ }
2419
+
2420
+ // ui/src/layout/LanguageToggle.jsx
2421
+ import React23 from "react";
2422
+
2423
+ // ui/src/layout/languageToggleShared.jsx
2424
+ import React22 from "react";
2425
+ function readBasePath3() {
2426
+ const normalize = (value) => {
2427
+ if (!value) return "";
2428
+ const raw = String(value).trim();
2429
+ if (!raw) return "";
2430
+ const prefixed = raw.startsWith("/") ? raw : `/${raw}`;
2431
+ const cleaned = prefixed.replace(/\/+$/, "");
2432
+ return cleaned === "/" ? "" : cleaned;
2433
+ };
2434
+ try {
2435
+ if (typeof window !== "undefined" && window.CANOPY_BASE_PATH != null) {
2436
+ const candidate = normalize(window.CANOPY_BASE_PATH);
2437
+ if (candidate || candidate === "") return candidate;
2438
+ }
2439
+ } catch (_) {
2440
+ }
2441
+ try {
2442
+ if (typeof globalThis !== "undefined" && globalThis.CANOPY_BASE_PATH != null) {
2443
+ const candidate = normalize(globalThis.CANOPY_BASE_PATH);
2444
+ if (candidate || candidate === "") return candidate;
2445
+ }
2446
+ } catch (_) {
2447
+ }
2448
+ try {
2449
+ if (typeof process !== "undefined" && process.env && process.env.CANOPY_BASE_PATH) {
2450
+ const candidate = normalize(process.env.CANOPY_BASE_PATH);
2451
+ if (candidate || candidate === "") return candidate;
2452
+ }
2453
+ } catch (_) {
2454
+ }
2455
+ return "";
2456
+ }
2457
+ function withBasePath2(href) {
2458
+ try {
2459
+ const raw = typeof href === "string" ? href.trim() : "";
2460
+ if (!raw) return raw;
2461
+ if (/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(raw)) return raw;
2462
+ if (!raw.startsWith("/")) return raw;
2463
+ const base = readBasePath3();
2464
+ if (!base || base === "/") return raw;
2465
+ if (raw === base || raw.startsWith(`${base}/`)) return raw;
2466
+ return `${base}${raw}`;
2467
+ } catch (_) {
2468
+ return href;
2469
+ }
2470
+ }
2471
+ function normalizeLocales(locales) {
2472
+ if (!Array.isArray(locales)) return [];
2473
+ const normalized = locales.map((entry, index) => {
2474
+ if (!entry || typeof entry !== "object") return null;
2475
+ const lang = typeof entry.lang === "string" ? entry.lang.trim() : "";
2476
+ if (!lang) return null;
2477
+ const label = typeof entry.label === "string" && entry.label.trim() ? entry.label.trim() : lang.toUpperCase();
2478
+ return { lang, label, default: entry.default === true, index };
2479
+ }).filter(Boolean);
2480
+ if (!normalized.length) return [];
2481
+ const explicitDefault = normalized.find((item) => item.default);
2482
+ if (explicitDefault) {
2483
+ normalized.forEach((item) => {
2484
+ item.default = item.index === explicitDefault.index;
2485
+ });
2486
+ } else {
2487
+ normalized[0].default = true;
2488
+ }
2489
+ return normalized.map(({ index, ...rest }) => rest);
2490
+ }
2491
+ function splitHref(href = "/") {
2492
+ try {
2493
+ if (/^[a-z][a-z0-9+.-]*:/i.test(href)) {
2494
+ const url = new URL(href);
2495
+ return {
2496
+ pathname: url.pathname || "/",
2497
+ suffix: `${url.search || ""}${url.hash || ""}`
2498
+ };
2499
+ }
2500
+ } catch (_) {
2501
+ }
2502
+ const raw = typeof href === "string" ? href : String(href || "/");
2503
+ const match = raw.match(/^[^?#]+/);
2504
+ const pathname = match ? match[0] : "/";
2505
+ const suffix = raw.slice(pathname.length);
2506
+ return {
2507
+ pathname: pathname || "/",
2508
+ suffix
2509
+ };
2510
+ }
2511
+ function normalizePathname(pathname = "/") {
2512
+ if (!pathname) return "/";
2513
+ const trimmed = pathname.trim();
2514
+ if (!trimmed) return "/";
2515
+ if (!trimmed.startsWith("/")) return `/${trimmed}`;
2516
+ return trimmed === "/" ? "/" : `/${trimmed.replace(/^\/+/, "")}`;
2517
+ }
2518
+ function stripLocaleFromPath(pathname, locales, defaultLocale) {
2519
+ const normalizedPath = normalizePathname(pathname);
2520
+ const segments = normalizedPath.replace(/^\/+/, "").split("/");
2521
+ const first = segments[0] || "";
2522
+ const match = locales.find((loc) => loc.lang === first);
2523
+ if (match && match.lang !== defaultLocale.lang) {
2524
+ segments.shift();
2525
+ const remainder = segments.join("/");
2526
+ return {
2527
+ locale: match,
2528
+ pathname: remainder ? `/${remainder}` : "/"
2529
+ };
2530
+ }
2531
+ return { locale: defaultLocale, pathname: normalizedPath };
2532
+ }
2533
+ function buildLocaleHref(locale, basePath2, suffix, defaultLocale) {
2534
+ const normalizedBase = normalizePathname(basePath2);
2535
+ const needsPrefix = locale.lang !== defaultLocale.lang;
2536
+ const prefixed = needsPrefix ? `/${locale.lang}${normalizedBase === "/" ? "" : normalizedBase}` : normalizedBase;
2537
+ const href = withBasePath2(prefixed || "/");
2538
+ return `${href}${suffix || ""}`;
2539
+ }
2540
+ function buildLanguageToggleConfig(toggle, page) {
2541
+ if (!toggle || !Array.isArray(toggle.locales)) return null;
2542
+ const locales = normalizeLocales(toggle.locales);
2543
+ if (locales.length <= 1) return null;
2544
+ const defaultLocale = locales.find((loc) => loc.default) || locales[0];
2545
+ const pageHref = page && page.href ? page.href : "/";
2546
+ const { pathname } = splitHref(pageHref);
2547
+ const { locale: activeLocale } = stripLocaleFromPath(
2548
+ pathname,
2549
+ locales,
2550
+ defaultLocale
2551
+ );
2552
+ const homePathname = "/";
2553
+ const homeSuffix = "";
2554
+ const messageMap = toggle && toggle.messages ? toggle.messages : {};
2555
+ const defaultCopy = messageMap.__default || {};
2556
+ const localeCopy = messageMap[activeLocale.lang] || null;
2557
+ const fallbackLabel = defaultCopy.label || "Language";
2558
+ const label = localeCopy && localeCopy.label || fallbackLabel;
2559
+ const links = locales.map((locale) => ({
2560
+ lang: locale.lang,
2561
+ label: locale.label || locale.lang.toUpperCase(),
2562
+ href: buildLocaleHref(locale, homePathname, homeSuffix, defaultLocale),
2563
+ isActive: locale.lang === activeLocale.lang
2564
+ }));
2565
+ return { label, links };
2566
+ }
2567
+ function LanguageToggleControl({
2568
+ config,
2569
+ variant = "inline",
2570
+ className = "",
2571
+ showLabel = false,
2572
+ control = "select"
2573
+ }) {
2574
+ if (!config) return null;
2575
+ const classes = [
2576
+ "canopy-language-toggle",
2577
+ variant ? `canopy-language-toggle--${variant}` : null,
2578
+ control ? `canopy-language-toggle--${control}` : null,
2579
+ className
2580
+ ].filter(Boolean).join(" ").trim();
2581
+ const ariaLabel = config.label || "Language";
2582
+ const resolvedControl = control === "list" ? "list" : "select";
2583
+ const selectId = typeof React22.useId === "function" && resolvedControl === "select" ? React22.useId() : void 0;
2584
+ const links = Array.isArray(config.links) ? config.links : [];
2585
+ if (!links.length) return null;
2586
+ const activeLink = links.find((link) => link.isActive);
2587
+ const fallbackHref = links[0].href;
2588
+ const selectedHref = activeLink ? activeLink.href : fallbackHref;
2589
+ const navigate = React22.useCallback((href) => {
2590
+ if (!href) return;
2591
+ try {
2592
+ if (typeof window !== "undefined" && window.location) {
2593
+ if (typeof window.location.assign === "function") {
2594
+ window.location.assign(href);
2595
+ } else {
2596
+ window.location.href = href;
2597
+ }
2598
+ return;
2599
+ }
2600
+ } catch (_) {
2601
+ }
2602
+ try {
2603
+ if (typeof document !== "undefined" && document.location) {
2604
+ document.location.href = href;
2605
+ }
2606
+ } catch (_) {
2607
+ }
2608
+ }, []);
2609
+ const handleSelectChange = React22.useCallback(
2610
+ (event) => {
2611
+ if (!event || !event.target) return;
2612
+ const nextHref = event.target.value;
2613
+ if (!nextHref || nextHref === selectedHref) return;
2614
+ navigate(nextHref);
2615
+ },
2616
+ [navigate, selectedHref]
2617
+ );
2618
+ const labelElement = showLabel && config.label ? resolvedControl === "select" ? /* @__PURE__ */ React22.createElement(
2619
+ "label",
2620
+ {
2621
+ className: "canopy-language-toggle__label",
2622
+ htmlFor: selectId
2623
+ },
2624
+ config.label
2625
+ ) : /* @__PURE__ */ React22.createElement("span", { className: "canopy-language-toggle__label" }, config.label) : null;
2626
+ return /* @__PURE__ */ React22.createElement("div", { className: classes || void 0 }, labelElement, resolvedControl === "select" ? /* @__PURE__ */ React22.createElement("div", { className: "canopy-language-toggle__select" }, /* @__PURE__ */ React22.createElement(
2627
+ "select",
2628
+ {
2629
+ id: selectId,
2630
+ className: "canopy-language-toggle__select-input",
2631
+ value: selectedHref,
2632
+ onChange: handleSelectChange,
2633
+ "aria-label": ariaLabel,
2634
+ "data-canopy-language-select": "true"
2635
+ },
2636
+ links.map((link) => /* @__PURE__ */ React22.createElement(
2637
+ "option",
2638
+ {
2639
+ key: link.lang,
2640
+ value: link.href,
2641
+ "data-lang": link.lang,
2642
+ "data-canopy-language-option": "true"
2643
+ },
2644
+ link.label
2645
+ ))
2646
+ )) : /* @__PURE__ */ React22.createElement("nav", { className: "canopy-language-toggle__nav", "aria-label": ariaLabel }, /* @__PURE__ */ React22.createElement("ul", { className: "canopy-language-toggle__list", role: "list" }, links.map((link) => /* @__PURE__ */ React22.createElement("li", { key: link.lang }, /* @__PURE__ */ React22.createElement(
2647
+ "button",
2648
+ {
2649
+ type: "button",
2650
+ className: "canopy-language-toggle__button",
2651
+ "data-active": link.isActive ? "true" : void 0,
2652
+ "aria-pressed": link.isActive ? "true" : "false",
2653
+ "data-canopy-language-button": "true",
2654
+ "data-href": link.href,
2655
+ onClick: () => navigate(link.href)
2656
+ },
2657
+ link.label
2658
+ ))))), /* @__PURE__ */ React22.createElement(LanguageToggleRuntime, null));
2659
+ }
2660
+ function LanguageToggleRuntime() {
2661
+ const code = `
2662
+ (function () {
2663
+ if (typeof window === 'undefined' || typeof document === 'undefined') return;
2664
+ if (window.__CANOPY_LANGUAGE_TOGGLE_INIT__) return;
2665
+ window.__CANOPY_LANGUAGE_TOGGLE_INIT__ = true;
2666
+
2667
+ function navigate(href) {
2668
+ if (!href) return;
2669
+ try {
2670
+ if (window.location && typeof window.location.assign === 'function') {
2671
+ window.location.assign(href);
2672
+ } else if (window.location) {
2673
+ window.location.href = href;
2674
+ }
2675
+ } catch (_) {}
2676
+ }
2677
+
2678
+ function bindSelect(select) {
2679
+ if (!select || select.dataset.canopyLanguageBound === 'true') return;
2680
+ select.dataset.canopyLanguageBound = 'true';
2681
+ select.addEventListener('change', function (event) {
2682
+ var target = event && event.target ? event.target : select;
2683
+ var href = target && target.value;
2684
+ if (!href || href === '#') return;
2685
+ navigate(href);
2686
+ });
2687
+ }
2688
+
2689
+ function bindButtons(root) {
2690
+ var buttons = root.querySelectorAll('[data-canopy-language-button]');
2691
+ Array.prototype.forEach.call(buttons, function (btn) {
2692
+ if (!btn || btn.dataset.canopyLanguageBound === 'true') return;
2693
+ btn.dataset.canopyLanguageBound = 'true';
2694
+ btn.addEventListener('click', function (event) {
2695
+ event.preventDefault();
2696
+ var href = btn.getAttribute('data-href');
2697
+ navigate(href);
2698
+ });
2699
+ });
2700
+ }
2701
+
2702
+ function scan(root) {
2703
+ if (!root) root = document;
2704
+ var selects = root.querySelectorAll('[data-canopy-language-select]');
2705
+ Array.prototype.forEach.call(selects, bindSelect);
2706
+ bindButtons(root);
2707
+ }
2708
+
2709
+ if (document.readyState === 'loading') {
2710
+ document.addEventListener('DOMContentLoaded', function () {
2711
+ scan(document);
2712
+ });
2713
+ } else {
2714
+ scan(document);
2715
+ }
2716
+ })();
2717
+ `;
2718
+ return /* @__PURE__ */ React22.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
2719
+ }
2720
+
2721
+ // ui/src/layout/LanguageToggle.jsx
2722
+ function LanguageToggle({
2723
+ languageToggle,
2724
+ page,
2725
+ variant = "inline",
2726
+ className = "",
2727
+ showLabel = false,
2728
+ control,
2729
+ label,
2730
+ ariaLabel
2731
+ }) {
2732
+ const PageContext = getSafePageContext();
2733
+ const context = React23.useContext(PageContext);
2734
+ const siteLanguageToggle = context && context.site && context.site.languageToggle || null;
2735
+ const pageData = page || (context && context.page ? context.page : null);
2736
+ const resolvedToggle = languageToggle === false ? null : languageToggle === true || typeof languageToggle === "undefined" ? siteLanguageToggle : languageToggle;
2737
+ const normalizeControl = (value) => value === "list" ? "list" : value === "select" ? "select" : null;
2738
+ const toggleControl = normalizeControl(
2739
+ resolvedToggle && typeof resolvedToggle.control === "string" ? resolvedToggle.control : null
2740
+ );
2741
+ const resolvedControl = normalizeControl(typeof control === "string" ? control : null) || toggleControl || "select";
2742
+ const config = React23.useMemo(() => {
2743
+ if (!resolvedToggle) return null;
2744
+ const base = buildLanguageToggleConfig(resolvedToggle, pageData);
2745
+ if (!base) return null;
2746
+ return {
2747
+ ...base,
2748
+ label: typeof label === "string" ? label : base.label,
2749
+ ariaLabel: typeof ariaLabel === "string" ? ariaLabel : base.ariaLabel
2750
+ };
2751
+ }, [resolvedToggle, pageData, label, ariaLabel]);
2752
+ if (!config) return null;
2753
+ return /* @__PURE__ */ React23.createElement(
2754
+ LanguageToggleControl,
2755
+ {
2756
+ config,
2757
+ variant,
2758
+ className,
2759
+ showLabel,
2760
+ control: resolvedControl
2761
+ }
2762
+ );
2763
+ }
2764
+
2403
2765
  // ui/src/layout/CanopyHeader.jsx
2404
2766
  function HeaderScript() {
2405
2767
  const code = `
@@ -2690,7 +3052,7 @@ function HeaderScript() {
2690
3052
  });
2691
3053
  })();
2692
3054
  `;
2693
- return /* @__PURE__ */ React21.createElement(
3055
+ return /* @__PURE__ */ React24.createElement(
2694
3056
  "script",
2695
3057
  {
2696
3058
  dangerouslySetInnerHTML: {
@@ -2699,20 +3061,6 @@ function HeaderScript() {
2699
3061
  }
2700
3062
  );
2701
3063
  }
2702
- var CONTEXT_KEY = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
2703
- function getSharedRoot() {
2704
- if (typeof globalThis !== "undefined") return globalThis;
2705
- if (typeof window !== "undefined") return window;
2706
- if (typeof global !== "undefined") return global;
2707
- return null;
2708
- }
2709
- function getSafePageContext() {
2710
- const root = getSharedRoot();
2711
- if (root && root[CONTEXT_KEY]) return root[CONTEXT_KEY];
2712
- const ctx = React21.createContext({ navigation: null, page: null, site: null });
2713
- if (root) root[CONTEXT_KEY] = ctx;
2714
- return ctx;
2715
- }
2716
3064
  function ensureArray(navLinks) {
2717
3065
  if (!Array.isArray(navLinks)) return [];
2718
3066
  return navLinks.filter(
@@ -2777,15 +3125,26 @@ function CanopyHeader(props = {}) {
2777
3125
  searchPlaceholder = "Search\u2026",
2778
3126
  brandHref = "/",
2779
3127
  title: titleProp,
2780
- logo: SiteLogo
3128
+ logo: SiteLogo,
3129
+ languageToggle: languageToggleProp
2781
3130
  } = props;
2782
3131
  const PageContext = getSafePageContext();
2783
- const context = React21.useContext(PageContext);
3132
+ const context = React24.useContext(PageContext);
2784
3133
  const contextPrimaryNav = context && Array.isArray(context.primaryNavigation) ? context.primaryNavigation : [];
2785
3134
  const navLinks = navLinksProp && navLinksProp.length ? ensureArray(navLinksProp) : ensureArray(contextPrimaryNav);
2786
3135
  const contextNavigation = context && context.navigation ? context.navigation : null;
2787
3136
  const contextSite = context && context.site ? context.site : null;
3137
+ const pageData = context && context.page ? context.page : null;
2788
3138
  const contextSiteTitle = contextSite && typeof contextSite.title === "string" ? contextSite.title.trim() : "";
3139
+ const siteLanguageToggle = contextSite && contextSite.languageToggle ? contextSite.languageToggle : null;
3140
+ const siteRoutes = contextSite && contextSite.routes ? contextSite.routes : null;
3141
+ const siteDefaultRoutes = contextSite && contextSite.routesDefault ? contextSite.routesDefault : null;
3142
+ const searchRouteValue = siteRoutes && typeof siteRoutes.search === "string" ? siteRoutes.search : "";
3143
+ const defaultSearchRoute = siteDefaultRoutes && typeof siteDefaultRoutes.search === "string" ? siteDefaultRoutes.search : "search";
3144
+ const trimmedSearchRoute = searchRouteValue ? searchRouteValue.replace(/^\/+|\/+$/g, "") : "";
3145
+ const usesDirectorySearchRoute = trimmedSearchRoute && trimmedSearchRoute !== (defaultSearchRoute || "search");
3146
+ const normalizedSearchRoute = usesDirectorySearchRoute ? `/${trimmedSearchRoute}/` : `/${(trimmedSearchRoute || defaultSearchRoute || "search").replace(/^\/+/, "")}`;
3147
+ const resolvedLanguageToggle = languageToggleProp === false ? null : languageToggleProp === true || typeof languageToggleProp === "undefined" ? siteLanguageToggle : languageToggleProp;
2789
3148
  const defaultHeaderTitle = contextSiteTitle || "Site title";
2790
3149
  const normalizedTitleProp = typeof titleProp === "string" ? titleProp.trim() : "";
2791
3150
  const resolvedTitle = normalizedTitleProp || defaultHeaderTitle;
@@ -2807,14 +3166,14 @@ function CanopyHeader(props = {}) {
2807
3166
  return !!(rootNode && Array.isArray(rootNode.children) && rootNode.children.length);
2808
3167
  };
2809
3168
  const hasIntegratedSectionNav = navLinks.some(shouldAttachSectionNav);
2810
- return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(
3169
+ return /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
2811
3170
  "header",
2812
3171
  {
2813
3172
  className: "canopy-header",
2814
3173
  "data-mobile-nav": "closed",
2815
3174
  "data-mobile-search": "closed"
2816
3175
  },
2817
- /* @__PURE__ */ React21.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React21.createElement(
3176
+ /* @__PURE__ */ React24.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React24.createElement(
2818
3177
  CanopyBrand,
2819
3178
  {
2820
3179
  label: resolvedTitle,
@@ -2823,21 +3182,22 @@ function CanopyHeader(props = {}) {
2823
3182
  Logo: SiteLogo
2824
3183
  }
2825
3184
  )),
2826
- /* @__PURE__ */ React21.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React21.createElement(
3185
+ /* @__PURE__ */ React24.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React24.createElement(
2827
3186
  SearchPanel,
2828
3187
  {
2829
3188
  label: searchLabel,
2830
3189
  hotkey: searchHotkey,
2831
- placeholder: searchPlaceholder
3190
+ placeholder: searchPlaceholder,
3191
+ searchPath: normalizedSearchRoute
2832
3192
  }
2833
3193
  )),
2834
- /* @__PURE__ */ React21.createElement(
3194
+ /* @__PURE__ */ React24.createElement(
2835
3195
  "nav",
2836
3196
  {
2837
3197
  className: "canopy-nav-links canopy-header__desktop-nav",
2838
3198
  "aria-label": "Primary navigation"
2839
3199
  },
2840
- navLinks.map((link) => /* @__PURE__ */ React21.createElement(
3200
+ navLinks.map((link) => /* @__PURE__ */ React24.createElement(
2841
3201
  "a",
2842
3202
  {
2843
3203
  key: link.href,
@@ -2847,7 +3207,15 @@ function CanopyHeader(props = {}) {
2847
3207
  link.label || link.href
2848
3208
  ))
2849
3209
  ),
2850
- /* @__PURE__ */ React21.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React21.createElement(
3210
+ /* @__PURE__ */ React24.createElement("div", { className: "canopy-header__actions" }, resolvedLanguageToggle ? /* @__PURE__ */ React24.createElement(
3211
+ LanguageToggle,
3212
+ {
3213
+ languageToggle: resolvedLanguageToggle,
3214
+ page: pageData,
3215
+ variant: "desktop",
3216
+ className: "canopy-header__language-toggle canopy-header__language-toggle--desktop"
3217
+ }
3218
+ ) : null, /* @__PURE__ */ React24.createElement(
2851
3219
  "button",
2852
3220
  {
2853
3221
  type: "button",
@@ -2857,7 +3225,7 @@ function CanopyHeader(props = {}) {
2857
3225
  "aria-expanded": "false",
2858
3226
  "data-canopy-header-toggle": "search"
2859
3227
  },
2860
- /* @__PURE__ */ React21.createElement(
3228
+ /* @__PURE__ */ React24.createElement(
2861
3229
  "svg",
2862
3230
  {
2863
3231
  xmlns: "http://www.w3.org/2000/svg",
@@ -2867,7 +3235,7 @@ function CanopyHeader(props = {}) {
2867
3235
  strokeWidth: "1.5",
2868
3236
  className: "canopy-header__search-icon"
2869
3237
  },
2870
- /* @__PURE__ */ React21.createElement(
3238
+ /* @__PURE__ */ React24.createElement(
2871
3239
  "path",
2872
3240
  {
2873
3241
  strokeLinecap: "round",
@@ -2876,7 +3244,7 @@ function CanopyHeader(props = {}) {
2876
3244
  }
2877
3245
  )
2878
3246
  )
2879
- ), /* @__PURE__ */ React21.createElement(
3247
+ ), /* @__PURE__ */ React24.createElement(
2880
3248
  "button",
2881
3249
  {
2882
3250
  type: "button",
@@ -2886,7 +3254,7 @@ function CanopyHeader(props = {}) {
2886
3254
  "aria-expanded": "false",
2887
3255
  "data-canopy-header-toggle": "nav"
2888
3256
  },
2889
- /* @__PURE__ */ React21.createElement(
3257
+ /* @__PURE__ */ React24.createElement(
2890
3258
  "svg",
2891
3259
  {
2892
3260
  xmlns: "http://www.w3.org/2000/svg",
@@ -2896,7 +3264,7 @@ function CanopyHeader(props = {}) {
2896
3264
  stroke: "currentColor",
2897
3265
  className: "canopy-header__menu-icon"
2898
3266
  },
2899
- /* @__PURE__ */ React21.createElement(
3267
+ /* @__PURE__ */ React24.createElement(
2900
3268
  "path",
2901
3269
  {
2902
3270
  strokeLinecap: "round",
@@ -2906,7 +3274,7 @@ function CanopyHeader(props = {}) {
2906
3274
  )
2907
3275
  )
2908
3276
  ))
2909
- ), /* @__PURE__ */ React21.createElement(
3277
+ ), /* @__PURE__ */ React24.createElement(
2910
3278
  CanopyModal,
2911
3279
  {
2912
3280
  id: "canopy-modal-nav",
@@ -2918,13 +3286,22 @@ function CanopyHeader(props = {}) {
2918
3286
  closeLabel: "Close navigation",
2919
3287
  closeDataAttr: "nav"
2920
3288
  },
2921
- /* @__PURE__ */ React21.createElement(
3289
+ resolvedLanguageToggle ? /* @__PURE__ */ React24.createElement(
3290
+ LanguageToggle,
3291
+ {
3292
+ languageToggle: resolvedLanguageToggle,
3293
+ page: pageData,
3294
+ variant: "mobile",
3295
+ className: "canopy-header__language-toggle canopy-header__language-toggle--mobile"
3296
+ }
3297
+ ) : null,
3298
+ /* @__PURE__ */ React24.createElement(
2922
3299
  "nav",
2923
3300
  {
2924
3301
  className: "canopy-nav-links canopy-modal__nav",
2925
3302
  "aria-label": "Primary navigation"
2926
3303
  },
2927
- /* @__PURE__ */ React21.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
3304
+ /* @__PURE__ */ React24.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
2928
3305
  const navData = getLinkNavigationData(
2929
3306
  link,
2930
3307
  navigationRoots,
@@ -2935,7 +3312,7 @@ function CanopyHeader(props = {}) {
2935
3312
  const nestedId = hasChildren ? `canopy-modal-section-${index}` : null;
2936
3313
  const toggleLabel = link.label ? `Toggle ${link.label} menu` : "Toggle section menu";
2937
3314
  const defaultExpanded = hasChildren && !!navRoot.isExpanded;
2938
- return /* @__PURE__ */ React21.createElement(
3315
+ return /* @__PURE__ */ React24.createElement(
2939
3316
  "li",
2940
3317
  {
2941
3318
  className: "canopy-modal__nav-item",
@@ -2944,7 +3321,7 @@ function CanopyHeader(props = {}) {
2944
3321
  "data-expanded": defaultExpanded ? "true" : "false",
2945
3322
  "data-default-expanded": defaultExpanded ? "true" : void 0
2946
3323
  },
2947
- /* @__PURE__ */ React21.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React21.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React21.createElement(
3324
+ /* @__PURE__ */ React24.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React24.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React24.createElement(
2948
3325
  "button",
2949
3326
  {
2950
3327
  type: "button",
@@ -2954,7 +3331,7 @@ function CanopyHeader(props = {}) {
2954
3331
  "aria-label": toggleLabel,
2955
3332
  "data-canopy-nav-item-toggle": nestedId || void 0
2956
3333
  },
2957
- /* @__PURE__ */ React21.createElement(
3334
+ /* @__PURE__ */ React24.createElement(
2958
3335
  "svg",
2959
3336
  {
2960
3337
  xmlns: "http://www.w3.org/2000/svg",
@@ -2964,7 +3341,7 @@ function CanopyHeader(props = {}) {
2964
3341
  strokeWidth: "1.5",
2965
3342
  className: "canopy-modal__nav-toggle-icon"
2966
3343
  },
2967
- /* @__PURE__ */ React21.createElement(
3344
+ /* @__PURE__ */ React24.createElement(
2968
3345
  "path",
2969
3346
  {
2970
3347
  strokeLinecap: "round",
@@ -2973,9 +3350,9 @@ function CanopyHeader(props = {}) {
2973
3350
  }
2974
3351
  )
2975
3352
  ),
2976
- /* @__PURE__ */ React21.createElement("span", { className: "sr-only" }, toggleLabel)
3353
+ /* @__PURE__ */ React24.createElement("span", { className: "sr-only" }, toggleLabel)
2977
3354
  ) : null),
2978
- hasChildren ? /* @__PURE__ */ React21.createElement(
3355
+ hasChildren ? /* @__PURE__ */ React24.createElement(
2979
3356
  NavigationTree,
2980
3357
  {
2981
3358
  root: navRoot,
@@ -2991,7 +3368,7 @@ function CanopyHeader(props = {}) {
2991
3368
  );
2992
3369
  }))
2993
3370
  ),
2994
- hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React21.createElement(
3371
+ hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React24.createElement(
2995
3372
  NavigationTree,
2996
3373
  {
2997
3374
  root: sectionNavigation.root,
@@ -3001,7 +3378,7 @@ function CanopyHeader(props = {}) {
3001
3378
  parentKey: "fallback-nav"
3002
3379
  }
3003
3380
  ) : null
3004
- ), /* @__PURE__ */ React21.createElement(
3381
+ ), /* @__PURE__ */ React24.createElement(
3005
3382
  CanopyModal,
3006
3383
  {
3007
3384
  id: "canopy-modal-search",
@@ -3014,26 +3391,27 @@ function CanopyHeader(props = {}) {
3014
3391
  closeDataAttr: "search",
3015
3392
  bodyClassName: "canopy-modal__body--search"
3016
3393
  },
3017
- /* @__PURE__ */ React21.createElement(
3394
+ /* @__PURE__ */ React24.createElement(
3018
3395
  SearchPanel,
3019
3396
  {
3020
3397
  label: searchLabel,
3021
3398
  hotkey: searchHotkey,
3022
- placeholder: searchPlaceholder
3399
+ placeholder: searchPlaceholder,
3400
+ searchPath: normalizedSearchRoute
3023
3401
  }
3024
3402
  )
3025
- ), /* @__PURE__ */ React21.createElement(HeaderScript, null));
3403
+ ), /* @__PURE__ */ React24.createElement(HeaderScript, null));
3026
3404
  }
3027
3405
 
3028
3406
  // ui/src/layout/CanopyFooter.jsx
3029
- import React22 from "react";
3407
+ import React25 from "react";
3030
3408
  function CanopyFooter({ className = "", children }) {
3031
3409
  const footerClassName = ["canopy-footer", className].filter(Boolean).join(" ");
3032
- return /* @__PURE__ */ React22.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React22.createElement("div", { className: "canopy-footer__inner" }, children));
3410
+ return /* @__PURE__ */ React25.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React25.createElement("div", { className: "canopy-footer__inner" }, children));
3033
3411
  }
3034
3412
 
3035
3413
  // ui/src/layout/TeaserCard.jsx
3036
- import React23 from "react";
3414
+ import React26 from "react";
3037
3415
  function TeaserCard({
3038
3416
  href = "",
3039
3417
  title = "",
@@ -3054,7 +3432,7 @@ function TeaserCard({
3054
3432
  ].filter(Boolean).join(" ");
3055
3433
  const showThumb = type === "work" && thumbnail;
3056
3434
  const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
3057
- return /* @__PURE__ */ React23.createElement(
3435
+ return /* @__PURE__ */ React26.createElement(
3058
3436
  Tag,
3059
3437
  {
3060
3438
  className: classes,
@@ -3062,7 +3440,7 @@ function TeaserCard({
3062
3440
  "data-canopy-item": href ? "" : void 0,
3063
3441
  ...rest
3064
3442
  },
3065
- showThumb ? /* @__PURE__ */ React23.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React23.createElement(
3443
+ showThumb ? /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React26.createElement(
3066
3444
  "img",
3067
3445
  {
3068
3446
  src: thumbnail,
@@ -3072,12 +3450,12 @@ function TeaserCard({
3072
3450
  className: "canopy-search-teaser__thumb-img"
3073
3451
  }
3074
3452
  )) : null,
3075
- /* @__PURE__ */ React23.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React23.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React23.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
3453
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React26.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React26.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
3076
3454
  );
3077
3455
  }
3078
3456
 
3079
3457
  // ui/src/layout/GoogleAnalytics.jsx
3080
- import React24 from "react";
3458
+ import React27 from "react";
3081
3459
  var GA_HOST = "https://www.googletagmanager.com/gtag/js";
3082
3460
  function GoogleAnalytics({ id }) {
3083
3461
  if (!id) return null;
@@ -3087,11 +3465,11 @@ function GoogleAnalytics({ id }) {
3087
3465
  gtag('js', new Date());
3088
3466
  gtag('config', '${id}');
3089
3467
  `;
3090
- return /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React24.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
3468
+ return /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React27.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
3091
3469
  }
3092
3470
 
3093
3471
  // ui/src/layout/Container.jsx
3094
- import React25 from "react";
3472
+ import React28 from "react";
3095
3473
  function Container({
3096
3474
  className = "",
3097
3475
  variant = "content",
@@ -3100,7 +3478,7 @@ function Container({
3100
3478
  }) {
3101
3479
  const variantClass = variant === "wide" ? "max-w-wide" : "max-w-content";
3102
3480
  const classes = ["mx-auto", variantClass, "w-full", className].filter(Boolean).join(" ");
3103
- return /* @__PURE__ */ React25.createElement(
3481
+ return /* @__PURE__ */ React28.createElement(
3104
3482
  "div",
3105
3483
  {
3106
3484
  className: classes,
@@ -3112,7 +3490,7 @@ function Container({
3112
3490
  }
3113
3491
 
3114
3492
  // ui/src/layout/Card.jsx
3115
- import React26, { useEffect as useEffect6, useRef as useRef2, useState as useState5 } from "react";
3493
+ import React29, { useEffect as useEffect6, useRef as useRef2, useState as useState5 } from "react";
3116
3494
  var DEFAULT_CARD_ASPECT_RATIO = 4 / 3;
3117
3495
  function Card({
3118
3496
  href,
@@ -3176,8 +3554,8 @@ function Card({
3176
3554
  const hasDimensions = Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0;
3177
3555
  const ratio = hasAspectRatio ? Number(aspectRatio) : hasDimensions ? w / h : src ? DEFAULT_CARD_ASPECT_RATIO : void 0;
3178
3556
  const paddingPercent = ratio ? 100 / ratio : 100;
3179
- const caption = /* @__PURE__ */ React26.createElement("figcaption", null, title && /* @__PURE__ */ React26.createElement("span", null, title), subtitle && /* @__PURE__ */ React26.createElement("span", null, subtitle), children);
3180
- return /* @__PURE__ */ React26.createElement(
3557
+ const caption = /* @__PURE__ */ React29.createElement("figcaption", null, title && /* @__PURE__ */ React29.createElement("span", null, title), subtitle && /* @__PURE__ */ React29.createElement("span", null, subtitle), children);
3558
+ return /* @__PURE__ */ React29.createElement(
3181
3559
  "a",
3182
3560
  {
3183
3561
  href,
@@ -3189,13 +3567,13 @@ function Card({
3189
3567
  "data-image-loaded": imageLoaded ? "true" : "false",
3190
3568
  ...rest
3191
3569
  },
3192
- /* @__PURE__ */ React26.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React26.createElement(
3570
+ /* @__PURE__ */ React29.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React29.createElement(
3193
3571
  "div",
3194
3572
  {
3195
3573
  className: "canopy-card-media",
3196
3574
  style: { "--canopy-card-padding": `${paddingPercent}%` }
3197
3575
  },
3198
- inView ? /* @__PURE__ */ React26.createElement(
3576
+ inView ? /* @__PURE__ */ React29.createElement(
3199
3577
  "img",
3200
3578
  {
3201
3579
  src,
@@ -3206,7 +3584,7 @@ function Card({
3206
3584
  onError: () => setImageLoaded(true)
3207
3585
  }
3208
3586
  ) : null
3209
- ) : /* @__PURE__ */ React26.createElement(
3587
+ ) : /* @__PURE__ */ React29.createElement(
3210
3588
  "img",
3211
3589
  {
3212
3590
  src,
@@ -3222,13 +3600,13 @@ function Card({
3222
3600
  }
3223
3601
 
3224
3602
  // ui/src/content/ReferencedItems.jsx
3225
- import React27 from "react";
3603
+ import React30 from "react";
3226
3604
  import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
3227
3605
  function useReferencedItems(itemsProp) {
3228
3606
  if (Array.isArray(itemsProp)) return itemsProp;
3229
3607
  const PageContext = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
3230
3608
  if (!PageContext) return [];
3231
- const context = React27.useContext(PageContext);
3609
+ const context = React30.useContext(PageContext);
3232
3610
  const items = context && context.page ? context.page.referencedItems : null;
3233
3611
  return Array.isArray(items) ? items : [];
3234
3612
  }
@@ -3248,13 +3626,13 @@ function ReferencedItems({
3248
3626
  "referenced-items--empty",
3249
3627
  className
3250
3628
  ].filter(Boolean).join(" ");
3251
- return /* @__PURE__ */ React27.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
3629
+ return /* @__PURE__ */ React30.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
3252
3630
  }
3253
3631
  const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
3254
- return /* @__PURE__ */ React27.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React27.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
3632
+ return /* @__PURE__ */ React30.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React30.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
3255
3633
  if (!item) return null;
3256
3634
  const key = item.href || item.slug || item.id;
3257
- return /* @__PURE__ */ React27.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React27.createElement(
3635
+ return /* @__PURE__ */ React30.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React30.createElement(
3258
3636
  Card,
3259
3637
  {
3260
3638
  href: item.href,
@@ -3271,7 +3649,7 @@ function ReferencedItems({
3271
3649
  }
3272
3650
 
3273
3651
  // ui/src/content/References.jsx
3274
- import React28 from "react";
3652
+ import React31 from "react";
3275
3653
  import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
3276
3654
  import referenced from "@canopy-iiif/app/lib/components/referenced.js";
3277
3655
  function getPageContext() {
@@ -3302,7 +3680,7 @@ function References({
3302
3680
  ...rest
3303
3681
  }) {
3304
3682
  const PageContext = getPageContext();
3305
- const context = PageContext ? React28.useContext(PageContext) : null;
3683
+ const context = PageContext ? React31.useContext(PageContext) : null;
3306
3684
  const contextPage = context && context.page ? context.page : null;
3307
3685
  const manifestId = id || contextPage && contextPage.manifestId || "";
3308
3686
  const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
@@ -3311,12 +3689,12 @@ function References({
3311
3689
  const entries = references && references.length ? references : null;
3312
3690
  if (!entries || !entries.length) return null;
3313
3691
  const containerClass = ["references", className].filter(Boolean).join(" ");
3314
- return /* @__PURE__ */ React28.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React28.createElement("div", { className: "references__group" }, /* @__PURE__ */ React28.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React28.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React28.createElement("a", { href: entry.href }, entry.title || entry.href)))));
3692
+ return /* @__PURE__ */ React31.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React31.createElement("div", { className: "references__group" }, /* @__PURE__ */ React31.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React31.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React31.createElement("a", { href: entry.href }, entry.title || entry.href)))));
3315
3693
  }
3316
3694
 
3317
3695
  // ui/src/content/Index.jsx
3318
3696
  var import_slugify = __toESM(require_slugify());
3319
- import React29 from "react";
3697
+ import React32 from "react";
3320
3698
  import metadataIndexHelpers from "@canopy-iiif/app/lib/components/metadata-index.js";
3321
3699
  var metadataModule = metadataIndexHelpers && typeof metadataIndexHelpers === "object" ? metadataIndexHelpers : null;
3322
3700
  var SLUG_OPTIONS = { lower: true, strict: true, trim: true };
@@ -3394,7 +3772,7 @@ function normalizeBasePath2(value) {
3394
3772
  const cleaned = prefixed.replace(/\/+$/, "");
3395
3773
  return cleaned === "/" ? "" : cleaned;
3396
3774
  }
3397
- function readBasePath3() {
3775
+ function readBasePath4() {
3398
3776
  if (cachedBasePath2 !== null) return cachedBasePath2;
3399
3777
  const candidates = [];
3400
3778
  try {
@@ -3425,8 +3803,8 @@ function readBasePath3() {
3425
3803
  cachedBasePath2 = "";
3426
3804
  return cachedBasePath2;
3427
3805
  }
3428
- function withBasePath2(href) {
3429
- const base = readBasePath3();
3806
+ function withBasePath3(href) {
3807
+ const base = readBasePath4();
3430
3808
  const raw = typeof href === "string" ? href.trim() : "";
3431
3809
  if (!base) return raw || "";
3432
3810
  if (!raw) return base || "";
@@ -3440,7 +3818,7 @@ function buildSearchHref(labelSlug, valueSlug) {
3440
3818
  params.set("type", "work");
3441
3819
  params.set(labelSlug, valueSlug);
3442
3820
  const url = `/search?${params.toString()}`;
3443
- return withBasePath2(url);
3821
+ return withBasePath3(url);
3444
3822
  } catch (_) {
3445
3823
  return "";
3446
3824
  }
@@ -3479,7 +3857,7 @@ function Index({
3479
3857
  const entries = filterByLabel(data, label);
3480
3858
  if (!entries.length) return null;
3481
3859
  const containerClass = ["canopy-index", className].filter(Boolean).join(" ");
3482
- return /* @__PURE__ */ React29.createElement("div", { className: containerClass, ...rest }, entries.map((entry) => /* @__PURE__ */ React29.createElement(
3860
+ return /* @__PURE__ */ React32.createElement("div", { className: containerClass, ...rest }, entries.map((entry) => /* @__PURE__ */ React32.createElement(
3483
3861
  IndexGroup,
3484
3862
  {
3485
3863
  key: entry.slug || entry.label,
@@ -3490,7 +3868,7 @@ function Index({
3490
3868
  expandLabel,
3491
3869
  collapseLabel
3492
3870
  }
3493
- )), /* @__PURE__ */ React29.createElement(
3871
+ )), /* @__PURE__ */ React32.createElement(
3494
3872
  "script",
3495
3873
  {
3496
3874
  "data-canopy-index-script": "",
@@ -3507,10 +3885,10 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
3507
3885
  const hiddenValues = hasOverflow ? values.slice(maxVisible) : [];
3508
3886
  const labelCollapsed = typeof expandLabel === "string" && expandLabel.trim() ? expandLabel.trim() : "Show more";
3509
3887
  const labelExpanded = typeof collapseLabel === "string" && collapseLabel.trim() ? collapseLabel.trim() : "Show less";
3510
- return /* @__PURE__ */ React29.createElement("dl", { className: "canopy-index__group", "data-canopy-index-group": "", "data-expanded": "0" }, /* @__PURE__ */ React29.createElement("dt", null, label), /* @__PURE__ */ React29.createElement("div", { className: "canopy-index__values" }, visibleValues.map((value) => {
3888
+ return /* @__PURE__ */ React32.createElement("dl", { className: "canopy-index__group", "data-canopy-index-group": "", "data-expanded": "0" }, /* @__PURE__ */ React32.createElement("dt", null, label), /* @__PURE__ */ React32.createElement("div", { className: "canopy-index__values" }, visibleValues.map((value) => {
3511
3889
  const href = buildSearchHref(labelSlug, value.slug);
3512
3890
  const key = `${labelSlug || label}-${value.slug || value.value}`;
3513
- return /* @__PURE__ */ React29.createElement("dd", { key }, href ? /* @__PURE__ */ React29.createElement(
3891
+ return /* @__PURE__ */ React32.createElement("dd", { key }, href ? /* @__PURE__ */ React32.createElement(
3514
3892
  "a",
3515
3893
  {
3516
3894
  href,
@@ -3523,7 +3901,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
3523
3901
  }), hiddenValues.map((value) => {
3524
3902
  const href = buildSearchHref(labelSlug, value.slug);
3525
3903
  const key = `${labelSlug || label}-hidden-${value.slug || value.value}`;
3526
- return /* @__PURE__ */ React29.createElement("dd", { key, "data-canopy-index-hidden": "", hidden: true }, href ? /* @__PURE__ */ React29.createElement(
3904
+ return /* @__PURE__ */ React32.createElement("dd", { key, "data-canopy-index-hidden": "", hidden: true }, href ? /* @__PURE__ */ React32.createElement(
3527
3905
  "a",
3528
3906
  {
3529
3907
  href,
@@ -3533,7 +3911,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
3533
3911
  },
3534
3912
  value.value
3535
3913
  ) : value.value);
3536
- })), hasOverflow && /* @__PURE__ */ React29.createElement("div", { className: "canopy-index__more-wrapper" }, /* @__PURE__ */ React29.createElement(
3914
+ })), hasOverflow && /* @__PURE__ */ React32.createElement("div", { className: "canopy-index__more-wrapper" }, /* @__PURE__ */ React32.createElement(
3537
3915
  "button",
3538
3916
  {
3539
3917
  type: "button",
@@ -3547,7 +3925,7 @@ function IndexGroup({ label, labelSlug, values, limit, expandLabel, collapseLabe
3547
3925
  }
3548
3926
 
3549
3927
  // ui/src/content/Bibliography.jsx
3550
- import React30 from "react";
3928
+ import React33 from "react";
3551
3929
  import bibliography from "@canopy-iiif/app/lib/components/bibliography.js";
3552
3930
  function resolveHeadingTag(tag, fallback) {
3553
3931
  if (typeof tag === "string" && tag.trim()) return tag;
@@ -3557,7 +3935,7 @@ function resolveHeadingTag(tag, fallback) {
3557
3935
  function NoteBody({ note }) {
3558
3936
  if (!note) return null;
3559
3937
  if (note.html) {
3560
- return /* @__PURE__ */ React30.createElement(
3938
+ return /* @__PURE__ */ React33.createElement(
3561
3939
  "div",
3562
3940
  {
3563
3941
  className: "bibliography__note-body",
@@ -3566,7 +3944,7 @@ function NoteBody({ note }) {
3566
3944
  );
3567
3945
  }
3568
3946
  if (note.text) {
3569
- return /* @__PURE__ */ React30.createElement("div", { className: "bibliography__note-body" }, note.text);
3947
+ return /* @__PURE__ */ React33.createElement("div", { className: "bibliography__note-body" }, note.text);
3570
3948
  }
3571
3949
  return null;
3572
3950
  }
@@ -3584,22 +3962,22 @@ function Bibliography({
3584
3962
  if (!entries.length) return null;
3585
3963
  const PageHeadingTag = resolveHeadingTag(pageHeadingTag, "h3");
3586
3964
  const rootClass = ["bibliography", className].filter(Boolean).join(" ");
3587
- return /* @__PURE__ */ React30.createElement("section", { className: rootClass }, /* @__PURE__ */ React30.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
3965
+ return /* @__PURE__ */ React33.createElement("section", { className: rootClass }, /* @__PURE__ */ React33.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
3588
3966
  const key = entry.href || entry.relativePath || entry.title;
3589
3967
  const pageTitle = entry.title || entry.href;
3590
- return /* @__PURE__ */ React30.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React30.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React30.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React30.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React30.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
3968
+ return /* @__PURE__ */ React33.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React33.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React33.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React33.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React33.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
3591
3969
  const noteKey = `${key || "entry"}-${note.identifier || idx}`;
3592
- return /* @__PURE__ */ React30.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React30.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React30.createElement(NoteBody, { note }));
3970
+ return /* @__PURE__ */ React33.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React33.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React33.createElement(NoteBody, { note }));
3593
3971
  })));
3594
3972
  })));
3595
3973
  }
3596
3974
 
3597
3975
  // ui/src/content/timeline/MdxTimeline.jsx
3598
- import React34 from "react";
3976
+ import React37 from "react";
3599
3977
  import ReactDOMServer from "react-dom/server";
3600
3978
 
3601
3979
  // ui/src/content/timeline/Timeline.jsx
3602
- import React32 from "react";
3980
+ import React35 from "react";
3603
3981
 
3604
3982
  // ui/src/content/timeline/date-utils.js
3605
3983
  var FALLBACK_LOCALE = (() => {
@@ -3760,7 +4138,7 @@ function clampProgress(value) {
3760
4138
  }
3761
4139
 
3762
4140
  // ui/src/layout/ReferencedManifestCard.jsx
3763
- import React31 from "react";
4141
+ import React34 from "react";
3764
4142
  function normalizeMetadata(metadata, summary) {
3765
4143
  if (Array.isArray(metadata) && metadata.length) {
3766
4144
  return metadata.filter(Boolean);
@@ -3794,7 +4172,7 @@ function ReferencedManifestCard({
3794
4172
  "canopy-referenced-manifest-card",
3795
4173
  className
3796
4174
  ].filter(Boolean).join(" ");
3797
- return /* @__PURE__ */ React31.createElement(
4175
+ return /* @__PURE__ */ React34.createElement(
3798
4176
  TeaserCard,
3799
4177
  {
3800
4178
  href: resolvedHref || void 0,
@@ -3976,14 +4354,14 @@ function TimelineConnector({ side, isActive, highlight }) {
3976
4354
  "canopy-timeline__connector-dot",
3977
4355
  highlight || isActive ? "is-active" : ""
3978
4356
  ].filter(Boolean).join(" ");
3979
- return /* @__PURE__ */ React32.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React32.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("span", { className: dotClasses }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__connector-line" })));
4357
+ return /* @__PURE__ */ React35.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React35.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement("span", { className: dotClasses }), /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__connector-line" })));
3980
4358
  }
3981
4359
  function renderResourceSection(point) {
3982
4360
  if (!point) return null;
3983
4361
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
3984
4362
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
3985
4363
  if (!manifestCards.length && !legacyResources.length) return null;
3986
- return /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React32.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React32.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React32.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React32.createElement(
4364
+ return /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React35.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React35.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React35.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React35.createElement(
3987
4365
  TeaserCard,
3988
4366
  {
3989
4367
  href: resource.href,
@@ -4008,26 +4386,26 @@ function Timeline({
4008
4386
  ...rest
4009
4387
  }) {
4010
4388
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
4011
- const rawPoints = React32.useMemo(() => {
4389
+ const rawPoints = React35.useMemo(() => {
4012
4390
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
4013
4391
  if (payloadPoints && payloadPoints.length) return payloadPoints;
4014
4392
  return [];
4015
4393
  }, [pointsProp, payloadPoints]);
4016
- const sanitizedPoints = React32.useMemo(
4394
+ const sanitizedPoints = React35.useMemo(
4017
4395
  () => sanitizePoints(rawPoints),
4018
4396
  [rawPoints]
4019
4397
  );
4020
4398
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
4021
- const baseLocale = React32.useMemo(
4399
+ const baseLocale = React35.useMemo(
4022
4400
  () => createLocale(localeValue),
4023
4401
  [localeValue]
4024
4402
  );
4025
4403
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
4026
- const rangeOverrides = React32.useMemo(
4404
+ const rangeOverrides = React35.useMemo(
4027
4405
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
4028
4406
  [sanitizedPoints, rangeInput]
4029
4407
  );
4030
- const effectiveRange = React32.useMemo(
4408
+ const effectiveRange = React35.useMemo(
4031
4409
  () => normalizeRange({
4032
4410
  ...rangeOverrides,
4033
4411
  locale: baseLocale
@@ -4036,7 +4414,7 @@ function Timeline({
4036
4414
  );
4037
4415
  const spanStart = effectiveRange.startDate.getTime();
4038
4416
  const span = effectiveRange.span;
4039
- const pointsWithPosition = React32.useMemo(() => {
4417
+ const pointsWithPosition = React35.useMemo(() => {
4040
4418
  if (!sanitizedPoints.length) return [];
4041
4419
  return sanitizedPoints.map((point, index) => {
4042
4420
  const timestamp = point.meta.timestamp;
@@ -4050,29 +4428,29 @@ function Timeline({
4050
4428
  };
4051
4429
  });
4052
4430
  }, [sanitizedPoints, spanStart, span]);
4053
- const [activeId, setActiveId] = React32.useState(
4431
+ const [activeId, setActiveId] = React35.useState(
4054
4432
  () => getActivePointId(pointsWithPosition)
4055
4433
  );
4056
- React32.useEffect(() => {
4434
+ React35.useEffect(() => {
4057
4435
  setActiveId(getActivePointId(pointsWithPosition));
4058
4436
  }, [pointsWithPosition]);
4059
4437
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
4060
4438
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
4061
- const thresholdMs = React32.useMemo(
4439
+ const thresholdMs = React35.useMemo(
4062
4440
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
4063
4441
  [thresholdValue, effectiveRange.granularity]
4064
4442
  );
4065
- const groupedEntries = React32.useMemo(
4443
+ const groupedEntries = React35.useMemo(
4066
4444
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
4067
4445
  granularity: effectiveRange.granularity,
4068
4446
  locale: baseLocale
4069
4447
  }),
4070
4448
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
4071
4449
  );
4072
- const [expandedGroupIds, setExpandedGroupIds] = React32.useState(
4450
+ const [expandedGroupIds, setExpandedGroupIds] = React35.useState(
4073
4451
  () => /* @__PURE__ */ new Set()
4074
4452
  );
4075
- React32.useEffect(() => {
4453
+ React35.useEffect(() => {
4076
4454
  setExpandedGroupIds((prev) => {
4077
4455
  if (!prev || prev.size === 0) return prev;
4078
4456
  const validIds = new Set(
@@ -4087,7 +4465,7 @@ function Timeline({
4087
4465
  return changed ? next : prev;
4088
4466
  });
4089
4467
  }, [groupedEntries]);
4090
- const toggleGroup = React32.useCallback((groupId) => {
4468
+ const toggleGroup = React35.useCallback((groupId) => {
4091
4469
  setExpandedGroupIds((prev) => {
4092
4470
  const next = new Set(prev || []);
4093
4471
  if (next.has(groupId)) next.delete(groupId);
@@ -4110,7 +4488,7 @@ function Timeline({
4110
4488
  point.id === activeId ? "is-active" : "",
4111
4489
  point.highlight ? "is-highlighted" : ""
4112
4490
  ].filter(Boolean).join(" ");
4113
- const connector = /* @__PURE__ */ React32.createElement(
4491
+ const connector = /* @__PURE__ */ React35.createElement(
4114
4492
  TimelineConnector,
4115
4493
  {
4116
4494
  side: point.side,
@@ -4118,9 +4496,9 @@ function Timeline({
4118
4496
  highlight: point.highlight
4119
4497
  }
4120
4498
  );
4121
- const body = /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
4499
+ const body = /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
4122
4500
  const resourceSection = renderResourceSection(point);
4123
- return /* @__PURE__ */ React32.createElement(
4501
+ return /* @__PURE__ */ React35.createElement(
4124
4502
  "div",
4125
4503
  {
4126
4504
  key: point.id,
@@ -4128,7 +4506,7 @@ function Timeline({
4128
4506
  style: wrapperStyle,
4129
4507
  role: "listitem"
4130
4508
  },
4131
- point.side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, connector, /* @__PURE__ */ React32.createElement("div", { className: cardClasses }, body, resourceSection))
4509
+ point.side === "left" ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React35.createElement(React35.Fragment, null, connector, /* @__PURE__ */ React35.createElement("div", { className: cardClasses }, body, resourceSection))
4132
4510
  );
4133
4511
  }
4134
4512
  function renderGroupEntry(entry) {
@@ -4139,7 +4517,7 @@ function Timeline({
4139
4517
  const wrapperStyle = { top: `${entry.progress * 100}%` };
4140
4518
  const isExpanded = expandedGroupIds.has(entry.id);
4141
4519
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
4142
- const connector = /* @__PURE__ */ React32.createElement(
4520
+ const connector = /* @__PURE__ */ React35.createElement(
4143
4521
  TimelineConnector,
4144
4522
  {
4145
4523
  side: entry.side,
@@ -4153,7 +4531,7 @@ function Timeline({
4153
4531
  hasActivePoint ? "is-active" : ""
4154
4532
  ].filter(Boolean).join(" ");
4155
4533
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
4156
- const header = /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React32.createElement(
4534
+ const header = /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React35.createElement(
4157
4535
  "button",
4158
4536
  {
4159
4537
  type: "button",
@@ -4163,7 +4541,7 @@ function Timeline({
4163
4541
  },
4164
4542
  isExpanded ? "Hide details" : "Show details"
4165
4543
  ));
4166
- const groupPoints = isExpanded ? /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React32.createElement(
4544
+ const groupPoints = isExpanded ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React35.createElement(
4167
4545
  "button",
4168
4546
  {
4169
4547
  key: point.id,
@@ -4174,11 +4552,11 @@ function Timeline({
4174
4552
  ].filter(Boolean).join(" "),
4175
4553
  onClick: () => setActiveId(point.id)
4176
4554
  },
4177
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
4178
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
4555
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
4556
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
4179
4557
  ))) : null;
4180
- const groupCard = /* @__PURE__ */ React32.createElement("div", { className: groupClasses }, header, groupPoints);
4181
- return /* @__PURE__ */ React32.createElement(
4558
+ const groupCard = /* @__PURE__ */ React35.createElement("div", { className: groupClasses }, header, groupPoints);
4559
+ return /* @__PURE__ */ React35.createElement(
4182
4560
  "div",
4183
4561
  {
4184
4562
  key: entry.id,
@@ -4186,17 +4564,17 @@ function Timeline({
4186
4564
  style: wrapperStyle,
4187
4565
  role: "listitem"
4188
4566
  },
4189
- entry.side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, groupCard, connector) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, connector, groupCard)
4567
+ entry.side === "left" ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, groupCard, connector) : /* @__PURE__ */ React35.createElement(React35.Fragment, null, connector, groupCard)
4190
4568
  );
4191
4569
  }
4192
- return /* @__PURE__ */ React32.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React32.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React32.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React32.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React32.createElement(
4570
+ return /* @__PURE__ */ React35.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React35.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React35.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React35.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React35.createElement(
4193
4571
  "div",
4194
4572
  {
4195
4573
  className: "canopy-timeline__list",
4196
4574
  role: "list",
4197
4575
  style: { minHeight: trackHeight }
4198
4576
  },
4199
- /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
4577
+ /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
4200
4578
  renderSteps(stepsValue, effectiveRange),
4201
4579
  groupedEntries.map((entry) => {
4202
4580
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -4211,7 +4589,7 @@ function renderSteps(stepSize, range) {
4211
4589
  const markers = [];
4212
4590
  if (startYear < endYear) {
4213
4591
  markers.push(
4214
- /* @__PURE__ */ React32.createElement(
4592
+ /* @__PURE__ */ React35.createElement(
4215
4593
  "span",
4216
4594
  {
4217
4595
  key: "timeline-step-start",
@@ -4219,12 +4597,12 @@ function renderSteps(stepSize, range) {
4219
4597
  style: { top: "0%" },
4220
4598
  "aria-hidden": "true"
4221
4599
  },
4222
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
4223
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
4600
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
4601
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
4224
4602
  )
4225
4603
  );
4226
4604
  markers.push(
4227
- /* @__PURE__ */ React32.createElement(
4605
+ /* @__PURE__ */ React35.createElement(
4228
4606
  "span",
4229
4607
  {
4230
4608
  key: "timeline-step-end",
@@ -4232,8 +4610,8 @@ function renderSteps(stepSize, range) {
4232
4610
  style: { top: "100%" },
4233
4611
  "aria-hidden": "true"
4234
4612
  },
4235
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
4236
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
4613
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
4614
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
4237
4615
  )
4238
4616
  );
4239
4617
  }
@@ -4243,7 +4621,7 @@ function renderSteps(stepSize, range) {
4243
4621
  const progress = (timestamp - range.startDate.getTime()) / range.span;
4244
4622
  if (progress <= 0 || progress >= 1) continue;
4245
4623
  markers.push(
4246
- /* @__PURE__ */ React32.createElement(
4624
+ /* @__PURE__ */ React35.createElement(
4247
4625
  "span",
4248
4626
  {
4249
4627
  key: `timeline-step-${year}`,
@@ -4251,8 +4629,8 @@ function renderSteps(stepSize, range) {
4251
4629
  style: { top: `calc(${progress * 100}% - 0.5px)` },
4252
4630
  "aria-hidden": "true"
4253
4631
  },
4254
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
4255
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, year)
4632
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
4633
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, year)
4256
4634
  )
4257
4635
  );
4258
4636
  }
@@ -4266,7 +4644,7 @@ function TimelinePoint() {
4266
4644
  TimelinePoint.displayName = "TimelinePoint";
4267
4645
 
4268
4646
  // ui/src/utils/manifestReferences.js
4269
- import React33 from "react";
4647
+ import React36 from "react";
4270
4648
  var CONTEXT_KEY2 = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
4271
4649
  function getGlobalRoot() {
4272
4650
  if (typeof globalThis !== "undefined") return globalThis;
@@ -4277,7 +4655,7 @@ function getGlobalRoot() {
4277
4655
  function getPageContext2() {
4278
4656
  const root = getGlobalRoot();
4279
4657
  if (root && root[CONTEXT_KEY2]) return root[CONTEXT_KEY2];
4280
- const ctx = React33.createContext({
4658
+ const ctx = React36.createContext({
4281
4659
  navigation: null,
4282
4660
  page: null,
4283
4661
  site: null,
@@ -4301,7 +4679,7 @@ function normalizeManifestId(raw) {
4301
4679
  return String(raw || "").trim();
4302
4680
  }
4303
4681
  }
4304
- var PageContextFallback = React33.createContext(null);
4682
+ var PageContextFallback = React36.createContext(null);
4305
4683
  var referencedModule = null;
4306
4684
  var REFERENCED_SPEC = "@canopy-iiif/app/lib/components/referenced.js";
4307
4685
  function getReferencedModule() {
@@ -4327,9 +4705,9 @@ function getReferencedModule() {
4327
4705
  }
4328
4706
  function useReferencedManifestMap() {
4329
4707
  const PageContext = getPageContext2() || PageContextFallback;
4330
- const pageContext = React33.useContext(PageContext);
4708
+ const pageContext = React36.useContext(PageContext);
4331
4709
  const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
4332
- return React33.useMemo(() => {
4710
+ return React36.useMemo(() => {
4333
4711
  const map = /* @__PURE__ */ new Map();
4334
4712
  referencedItems.forEach((item) => {
4335
4713
  if (!item) return;
@@ -4440,7 +4818,7 @@ function normalizeResource(resource, index) {
4440
4818
  }
4441
4819
  function normalizePoint(child, index, options) {
4442
4820
  var _a, _b, _c, _d, _e, _f;
4443
- if (!React34.isValidElement(child)) return null;
4821
+ if (!React37.isValidElement(child)) return null;
4444
4822
  if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
4445
4823
  return null;
4446
4824
  const props = child.props || {};
@@ -4456,7 +4834,7 @@ function normalizePoint(child, index, options) {
4456
4834
  try {
4457
4835
  if (props.children) {
4458
4836
  detailsHtml = ReactDOMServer.renderToStaticMarkup(
4459
- React34.createElement(React34.Fragment, null, props.children)
4837
+ React37.createElement(React37.Fragment, null, props.children)
4460
4838
  );
4461
4839
  }
4462
4840
  } catch (_) {
@@ -4505,7 +4883,7 @@ function MdxTimeline({ children, ...rest }) {
4505
4883
  const localeObj = createLocale(localeValue);
4506
4884
  const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
4507
4885
  const manifestMap = useReferencedManifestMap();
4508
- const childArray = React34.Children.toArray(children);
4886
+ const childArray = React37.Children.toArray(children);
4509
4887
  const points = childArray.map(
4510
4888
  (child, index) => normalizePoint(child, index, {
4511
4889
  range: rest.range || {},
@@ -4521,7 +4899,7 @@ function MdxTimeline({ children, ...rest }) {
4521
4899
  steps: rest.steps != null ? rest.steps : null
4522
4900
  };
4523
4901
  const json = serializeForScript(serializeProps(rest, payload, localeBase));
4524
- return /* @__PURE__ */ React34.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React34.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React34.createElement(
4902
+ return /* @__PURE__ */ React37.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React37.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React37.createElement(
4525
4903
  "script",
4526
4904
  {
4527
4905
  type: "application/json",
@@ -4531,7 +4909,7 @@ function MdxTimeline({ children, ...rest }) {
4531
4909
  }
4532
4910
 
4533
4911
  // ui/src/content/map/MdxMap.jsx
4534
- import React35 from "react";
4912
+ import React38 from "react";
4535
4913
  import ReactDOMServer2 from "react-dom/server";
4536
4914
 
4537
4915
  // ui/src/content/map/MapPoint.jsx
@@ -4566,7 +4944,7 @@ function renderDetailsHtml(children) {
4566
4944
  if (!children) return "";
4567
4945
  try {
4568
4946
  return ReactDOMServer2.renderToStaticMarkup(
4569
- React35.createElement(React35.Fragment, null, children)
4947
+ React38.createElement(React38.Fragment, null, children)
4570
4948
  );
4571
4949
  } catch (_) {
4572
4950
  return "";
@@ -4599,7 +4977,7 @@ function pickManifestSummary(manifest) {
4599
4977
  }
4600
4978
  function normalizeCustomPoint(child, index, manifestMap) {
4601
4979
  var _a;
4602
- if (!React35.isValidElement(child)) return null;
4980
+ if (!React38.isValidElement(child)) return null;
4603
4981
  if (child.type !== MapPoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "MapPoint") return null;
4604
4982
  const coords = normalizeCoordinates(child.props || {});
4605
4983
  if (!coords) return null;
@@ -4662,7 +5040,7 @@ function normalizeCustomPoint(child, index, manifestMap) {
4662
5040
  };
4663
5041
  }
4664
5042
  function normalizeCustomPoints(children, manifestMap) {
4665
- return React35.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
5043
+ return React38.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
4666
5044
  }
4667
5045
  function normalizeHeight(value) {
4668
5046
  if (value == null) return "600px";
@@ -4839,11 +5217,11 @@ function MdxMap({ children, ...rest }) {
4839
5217
  if (placeholderClass) placeholderProps.className = placeholderClass;
4840
5218
  if (rest.id) placeholderProps.id = rest.id;
4841
5219
  if (rest.style) placeholderProps.style = rest.style;
4842
- return /* @__PURE__ */ React35.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React35.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React35.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5220
+ return /* @__PURE__ */ React38.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React38.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React38.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React38.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
4843
5221
  }
4844
5222
 
4845
5223
  // ui/src/content/gallery/Gallery.jsx
4846
- import React36 from "react";
5224
+ import React39 from "react";
4847
5225
  var INLINE_SCRIPT2 = `(() => {
4848
5226
  if (typeof window === 'undefined') return;
4849
5227
  if (window.__canopyGalleryBound) return;
@@ -5354,7 +5732,7 @@ function shuffleItems(list) {
5354
5732
  function renderMetaList(meta, className) {
5355
5733
  const entries = ensureArray2(meta).filter((entry) => entry || entry === 0);
5356
5734
  if (!entries.length) return null;
5357
- return /* @__PURE__ */ React36.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React36.createElement("li", { key: `meta-${index}` }, entry)));
5735
+ return /* @__PURE__ */ React39.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React39.createElement("li", { key: `meta-${index}` }, entry)));
5358
5736
  }
5359
5737
  function renderPreview(props = {}) {
5360
5738
  const source = typeof props.media === "string" && props.media || props.thumbnail || props.src || props.image && props.image.src || props.image;
@@ -5362,7 +5740,7 @@ function renderPreview(props = {}) {
5362
5740
  const alt = props.thumbnailAlt || props.imageAlt || props.alt || props.title || "";
5363
5741
  const width = props.thumbnailWidth || props.imageWidth || props.width;
5364
5742
  const height = props.thumbnailHeight || props.imageHeight || props.height;
5365
- return /* @__PURE__ */ React36.createElement(
5743
+ return /* @__PURE__ */ React39.createElement(
5366
5744
  "img",
5367
5745
  {
5368
5746
  src: source,
@@ -5373,11 +5751,11 @@ function renderPreview(props = {}) {
5373
5751
  }
5374
5752
  );
5375
5753
  }
5376
- return /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
5754
+ return /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
5377
5755
  }
5378
5756
  function normalizeItem(child, index, galleryId, manifestMap) {
5379
5757
  var _a;
5380
- if (!React36.isValidElement(child)) return null;
5758
+ if (!React39.isValidElement(child)) return null;
5381
5759
  if (child.type !== GalleryItem && ((_a = child.type) == null ? void 0 : _a.displayName) !== "GalleryItem")
5382
5760
  return null;
5383
5761
  const props = child.props || {};
@@ -5452,7 +5830,7 @@ function buildCaptionContent(itemProps) {
5452
5830
  if (itemProps.caption) return itemProps.caption;
5453
5831
  const kicker = itemProps.kicker || itemProps.label || itemProps.eyebrow;
5454
5832
  const summary = itemProps.summary || itemProps.description;
5455
- return /* @__PURE__ */ React36.createElement(React36.Fragment, null, kicker ? /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, summary ? /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__summary" }, summary) : null, renderMetaList(
5833
+ return /* @__PURE__ */ React39.createElement(React39.Fragment, null, kicker ? /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, summary ? /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__summary" }, summary) : null, renderMetaList(
5456
5834
  itemProps.meta,
5457
5835
  "canopy-gallery__meta canopy-gallery__meta--caption"
5458
5836
  ));
@@ -5470,7 +5848,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5470
5848
  const kicker = props.kicker || props.label || props.eyebrow;
5471
5849
  const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
5472
5850
  const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
5473
- return /* @__PURE__ */ React36.createElement(
5851
+ return /* @__PURE__ */ React39.createElement(
5474
5852
  "div",
5475
5853
  {
5476
5854
  id: modalId,
@@ -5483,14 +5861,14 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5483
5861
  "data-canopy-gallery-modal": "true",
5484
5862
  "data-canopy-gallery-close": closeTargetId
5485
5863
  },
5486
- /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React36.createElement(
5864
+ /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React39.createElement(
5487
5865
  GalleryThumbnailNav,
5488
5866
  {
5489
5867
  items: navItems,
5490
5868
  activeModalId: modalId,
5491
5869
  groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
5492
5870
  }
5493
- ), /* @__PURE__ */ React36.createElement(
5871
+ ), /* @__PURE__ */ React39.createElement(
5494
5872
  "a",
5495
5873
  {
5496
5874
  className: "canopy-gallery__modal-close",
@@ -5498,7 +5876,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5498
5876
  "aria-label": `Close popup for ${modalTitle}`
5499
5877
  },
5500
5878
  "X"
5501
- )), /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React36.createElement(
5879
+ )), /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React39.createElement(
5502
5880
  "button",
5503
5881
  {
5504
5882
  type: "button",
@@ -5506,7 +5884,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5506
5884
  "aria-label": "Scroll left through gallery thumbnails",
5507
5885
  "data-canopy-gallery-nav-prev": "true"
5508
5886
  },
5509
- /* @__PURE__ */ React36.createElement(
5887
+ /* @__PURE__ */ React39.createElement(
5510
5888
  "span",
5511
5889
  {
5512
5890
  className: "canopy-gallery__nav-button-icon",
@@ -5515,8 +5893,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5515
5893
  },
5516
5894
  "<"
5517
5895
  ),
5518
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
5519
- ), /* @__PURE__ */ React36.createElement(
5896
+ /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
5897
+ ), /* @__PURE__ */ React39.createElement(
5520
5898
  "button",
5521
5899
  {
5522
5900
  type: "button",
@@ -5524,7 +5902,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5524
5902
  "aria-label": "Scroll right through gallery thumbnails",
5525
5903
  "data-canopy-gallery-nav-next": "true"
5526
5904
  },
5527
- /* @__PURE__ */ React36.createElement(
5905
+ /* @__PURE__ */ React39.createElement(
5528
5906
  "span",
5529
5907
  {
5530
5908
  className: "canopy-gallery__nav-button-icon",
@@ -5533,8 +5911,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5533
5911
  },
5534
5912
  ">"
5535
5913
  ),
5536
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
5537
- ), /* @__PURE__ */ React36.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React36.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), summary ? /* @__PURE__ */ React36.createElement(
5914
+ /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
5915
+ ), /* @__PURE__ */ React39.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React39.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React39.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), summary ? /* @__PURE__ */ React39.createElement(
5538
5916
  "p",
5539
5917
  {
5540
5918
  id: modalDescriptionId || void 0,
@@ -5544,20 +5922,20 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
5544
5922
  ) : null, renderMetaList(
5545
5923
  props.meta,
5546
5924
  "canopy-gallery__meta canopy-gallery__meta--modal"
5547
- ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React36.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
5925
+ ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React39.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
5548
5926
  );
5549
5927
  }
5550
5928
  function GalleryFigure({ item }) {
5551
5929
  const { props, modalId, triggerLabel } = item;
5552
- return /* @__PURE__ */ React36.createElement(
5930
+ return /* @__PURE__ */ React39.createElement(
5553
5931
  "figure",
5554
5932
  {
5555
5933
  className: "canopy-gallery__item",
5556
5934
  "data-gallery-item-index": item.index
5557
5935
  },
5558
- /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
5559
- /* @__PURE__ */ React36.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
5560
- /* @__PURE__ */ React36.createElement(
5936
+ /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
5937
+ /* @__PURE__ */ React39.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
5938
+ /* @__PURE__ */ React39.createElement(
5561
5939
  "a",
5562
5940
  {
5563
5941
  className: "canopy-gallery__trigger",
@@ -5567,27 +5945,27 @@ function GalleryFigure({ item }) {
5567
5945
  "aria-label": triggerLabel,
5568
5946
  "data-canopy-gallery-trigger": modalId
5569
5947
  },
5570
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
5948
+ /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
5571
5949
  )
5572
5950
  );
5573
5951
  }
5574
5952
  function GalleryThumbnailNav({ items, activeModalId, groupName }) {
5575
5953
  if (!items || items.length < 2) return null;
5576
5954
  const radioGroup = groupName || "canopy-gallery-nav";
5577
- return /* @__PURE__ */ React36.createElement(
5955
+ return /* @__PURE__ */ React39.createElement(
5578
5956
  "nav",
5579
5957
  {
5580
5958
  className: "canopy-gallery__nav",
5581
5959
  "aria-label": "Gallery navigation",
5582
5960
  "data-canopy-gallery-nav": "true"
5583
5961
  },
5584
- /* @__PURE__ */ React36.createElement(
5962
+ /* @__PURE__ */ React39.createElement(
5585
5963
  "div",
5586
5964
  {
5587
5965
  className: "canopy-gallery__nav-viewport",
5588
5966
  "data-canopy-gallery-nav-viewport": "true"
5589
5967
  },
5590
- /* @__PURE__ */ React36.createElement(
5968
+ /* @__PURE__ */ React39.createElement(
5591
5969
  "ul",
5592
5970
  {
5593
5971
  className: "canopy-gallery__nav-list",
@@ -5597,7 +5975,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
5597
5975
  items.map((item, index) => {
5598
5976
  const optionId = `${radioGroup}-${item.modalId || index}`;
5599
5977
  const isActive = item.modalId === activeModalId;
5600
- return /* @__PURE__ */ React36.createElement(
5978
+ return /* @__PURE__ */ React39.createElement(
5601
5979
  "li",
5602
5980
  {
5603
5981
  key: `${item.key}-nav`,
@@ -5605,7 +5983,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
5605
5983
  "data-canopy-gallery-nav-item": "true",
5606
5984
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
5607
5985
  },
5608
- /* @__PURE__ */ React36.createElement(
5986
+ /* @__PURE__ */ React39.createElement(
5609
5987
  "input",
5610
5988
  {
5611
5989
  type: "radio",
@@ -5621,15 +5999,15 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
5621
5999
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
5622
6000
  }
5623
6001
  ),
5624
- /* @__PURE__ */ React36.createElement(
6002
+ /* @__PURE__ */ React39.createElement(
5625
6003
  "label",
5626
6004
  {
5627
6005
  className: "canopy-gallery__nav-link",
5628
6006
  htmlFor: optionId,
5629
6007
  "data-canopy-gallery-nav-active": isActive ? "1" : void 0
5630
6008
  },
5631
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
5632
- /* @__PURE__ */ React36.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
6009
+ /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
6010
+ /* @__PURE__ */ React39.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
5633
6011
  )
5634
6012
  );
5635
6013
  })
@@ -5642,7 +6020,7 @@ function GalleryContent({ children, flex = false }) {
5642
6020
  "canopy-gallery-item__content",
5643
6021
  flex ? "canopy-gallery-item__content_flex" : null
5644
6022
  ].filter(Boolean).join(" ");
5645
- return /* @__PURE__ */ React36.createElement("div", { className: contentClassName }, children);
6023
+ return /* @__PURE__ */ React39.createElement("div", { className: contentClassName }, children);
5646
6024
  }
5647
6025
  function GalleryItem() {
5648
6026
  return null;
@@ -5666,7 +6044,7 @@ function Gallery({
5666
6044
  const galleryId = id ? String(id) : nextGalleryInstanceId();
5667
6045
  const HeadingTag = "h3";
5668
6046
  const closeTargetId = `${galleryId}-close`;
5669
- const childArray = React36.Children.toArray(children);
6047
+ const childArray = React39.Children.toArray(children);
5670
6048
  const items = childArray.map((child, index) => normalizeItem(child, index, galleryId, manifestMap)).filter(Boolean);
5671
6049
  if (!items.length) return null;
5672
6050
  const popupMode = normalizePopupSize(popupSize);
@@ -5678,7 +6056,7 @@ function Gallery({
5678
6056
  className
5679
6057
  ].filter(Boolean).join(" ");
5680
6058
  const navGroupName = `${galleryId}-nav`;
5681
- return /* @__PURE__ */ React36.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React36.createElement(
6059
+ return /* @__PURE__ */ React39.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React39.createElement(
5682
6060
  "div",
5683
6061
  {
5684
6062
  id: closeTargetId,
@@ -5686,7 +6064,7 @@ function Gallery({
5686
6064
  "aria-hidden": "true",
5687
6065
  tabIndex: -1
5688
6066
  }
5689
- ), (title || description) && /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React36.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React36.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React36.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React36.createElement(
6067
+ ), (title || description) && /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React39.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React39.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React39.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React39.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React39.createElement(
5690
6068
  GalleryModal,
5691
6069
  {
5692
6070
  key: `${item.modalId}-modal`,
@@ -5695,7 +6073,7 @@ function Gallery({
5695
6073
  navItems: orderedItems,
5696
6074
  navGroupName
5697
6075
  }
5698
- ))), /* @__PURE__ */ React36.createElement(
6076
+ ))), /* @__PURE__ */ React39.createElement(
5699
6077
  "script",
5700
6078
  {
5701
6079
  "data-canopy-gallery-script": "true",
@@ -5707,7 +6085,7 @@ Gallery.Item = GalleryItem;
5707
6085
  Gallery.Content = GalleryContent;
5708
6086
 
5709
6087
  // ui/src/search/MdxSearchResults.jsx
5710
- import React37 from "react";
6088
+ import React40 from "react";
5711
6089
  function MdxSearchResults(props) {
5712
6090
  let json = "{}";
5713
6091
  try {
@@ -5715,11 +6093,11 @@ function MdxSearchResults(props) {
5715
6093
  } catch (_) {
5716
6094
  json = "{}";
5717
6095
  }
5718
- return /* @__PURE__ */ React37.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React37.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6096
+ return /* @__PURE__ */ React40.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React40.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5719
6097
  }
5720
6098
 
5721
6099
  // ui/src/search/SearchSummary.jsx
5722
- import React38 from "react";
6100
+ import React41 from "react";
5723
6101
  function SearchSummary(props) {
5724
6102
  let json = "{}";
5725
6103
  try {
@@ -5727,11 +6105,11 @@ function SearchSummary(props) {
5727
6105
  } catch (_) {
5728
6106
  json = "{}";
5729
6107
  }
5730
- return /* @__PURE__ */ React38.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React38.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6108
+ return /* @__PURE__ */ React41.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React41.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5731
6109
  }
5732
6110
 
5733
6111
  // ui/src/search/MdxSearchTabs.jsx
5734
- import React39 from "react";
6112
+ import React42 from "react";
5735
6113
  function MdxSearchTabs(props) {
5736
6114
  let json = "{}";
5737
6115
  try {
@@ -5739,11 +6117,11 @@ function MdxSearchTabs(props) {
5739
6117
  } catch (_) {
5740
6118
  json = "{}";
5741
6119
  }
5742
- return /* @__PURE__ */ React39.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React39.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
6120
+ return /* @__PURE__ */ React42.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React42.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
5743
6121
  }
5744
6122
 
5745
6123
  // ui/src/search/MdxSearch.jsx
5746
- import React40 from "react";
6124
+ import React43 from "react";
5747
6125
  function MdxSearch(props = {}) {
5748
6126
  const {
5749
6127
  layout,
@@ -5761,11 +6139,11 @@ function MdxSearch(props = {}) {
5761
6139
  resultsPayload.layout = layout;
5762
6140
  }
5763
6141
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
5764
- return /* @__PURE__ */ React40.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React40.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React40.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React40.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
6142
+ return /* @__PURE__ */ React43.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React43.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React43.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React43.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
5765
6143
  }
5766
6144
 
5767
6145
  // ui/src/search-form/MdxSearchFormModal.jsx
5768
- import React41 from "react";
6146
+ import React44 from "react";
5769
6147
  function MdxSearchFormModal(props = {}) {
5770
6148
  const {
5771
6149
  placeholder = "Search\u2026",
@@ -5781,12 +6159,12 @@ function MdxSearchFormModal(props = {}) {
5781
6159
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
5782
6160
  const resolvedSearchPath = resolveSearchPath(searchPath);
5783
6161
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
5784
- return /* @__PURE__ */ React41.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React41.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React41.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React41.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React41.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
6162
+ return /* @__PURE__ */ React44.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React44.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React44.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React44.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React44.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
5785
6163
  }
5786
6164
 
5787
6165
  // ui/src/iiif/ManifestPrimitives.jsx
5788
6166
  var import_slugify2 = __toESM(require_slugify());
5789
- import React42 from "react";
6167
+ import React45 from "react";
5790
6168
  import {
5791
6169
  Label as CloverLabel,
5792
6170
  Metadata as CloverMetadata,
@@ -5863,7 +6241,7 @@ function normalizeBasePath3(value) {
5863
6241
  return cleaned === "/" ? "" : cleaned;
5864
6242
  }
5865
6243
  var cachedBasePath3 = null;
5866
- function readBasePath4() {
6244
+ function readBasePath5() {
5867
6245
  if (cachedBasePath3 !== null) return cachedBasePath3;
5868
6246
  const candidates = [];
5869
6247
  try {
@@ -5894,13 +6272,13 @@ function readBasePath4() {
5894
6272
  cachedBasePath3 = "";
5895
6273
  return cachedBasePath3;
5896
6274
  }
5897
- function withBasePath3(href) {
6275
+ function withBasePath4(href) {
5898
6276
  try {
5899
6277
  const raw = typeof href === "string" ? href.trim() : "";
5900
6278
  if (!raw) return href;
5901
6279
  if (/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(raw)) return raw;
5902
6280
  if (!raw.startsWith("/")) return raw;
5903
- const base = readBasePath4();
6281
+ const base = readBasePath5();
5904
6282
  if (!base) return raw;
5905
6283
  if (raw === base || raw.startsWith(`${base}/`)) return raw;
5906
6284
  return `${base}${raw}`;
@@ -5915,7 +6293,7 @@ function buildFacetSearchHref(labelSlug, valueSlug) {
5915
6293
  params.set("type", "work");
5916
6294
  params.set(labelSlug, valueSlug);
5917
6295
  const path = `/search?${params.toString()}`;
5918
- return withBasePath3(path);
6296
+ return withBasePath4(path);
5919
6297
  } catch (_) {
5920
6298
  return "";
5921
6299
  }
@@ -5927,7 +6305,7 @@ function MetadataFacetLink(props) {
5927
6305
  const valueSlug = facetSlug ? toValueSlug(text) : "";
5928
6306
  const href = facetSlug && valueSlug ? buildFacetSearchHref(facetSlug, valueSlug) : "";
5929
6307
  if (!href) return text;
5930
- return /* @__PURE__ */ React42.createElement(
6308
+ return /* @__PURE__ */ React45.createElement(
5931
6309
  "a",
5932
6310
  {
5933
6311
  href,
@@ -5953,7 +6331,7 @@ function buildFacetCustomValueContent(items, manifest) {
5953
6331
  seen.add(normalized);
5954
6332
  custom.push({
5955
6333
  matchingLabel: item.label,
5956
- Content: /* @__PURE__ */ React42.createElement(MetadataFacetLink, { facetSlug: facet.slug })
6334
+ Content: /* @__PURE__ */ React45.createElement(MetadataFacetLink, { facetSlug: facet.slug })
5957
6335
  });
5958
6336
  }
5959
6337
  return custom;
@@ -5985,12 +6363,12 @@ function mergeCustomValueContent(userContent, autoContent) {
5985
6363
  function Label({ manifest, label, ...rest }) {
5986
6364
  const intl = label || manifest && manifest.label;
5987
6365
  if (!hasInternationalValue(intl)) return null;
5988
- return /* @__PURE__ */ React42.createElement(CloverLabel, { label: intl, ...rest });
6366
+ return /* @__PURE__ */ React45.createElement(CloverLabel, { label: intl, ...rest });
5989
6367
  }
5990
6368
  function Summary({ manifest, summary, ...rest }) {
5991
6369
  const intl = summary || manifest && manifest.summary;
5992
6370
  if (!hasInternationalValue(intl)) return null;
5993
- return /* @__PURE__ */ React42.createElement(CloverSummary, { summary: intl, ...rest });
6371
+ return /* @__PURE__ */ React45.createElement(CloverSummary, { summary: intl, ...rest });
5994
6372
  }
5995
6373
  function Metadata({ manifest, metadata, customValueContent, ...rest }) {
5996
6374
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
@@ -6000,7 +6378,7 @@ function Metadata({ manifest, metadata, customValueContent, ...rest }) {
6000
6378
  customValueContent,
6001
6379
  autoCustomContent
6002
6380
  );
6003
- return /* @__PURE__ */ React42.createElement(
6381
+ return /* @__PURE__ */ React45.createElement(
6004
6382
  CloverMetadata,
6005
6383
  {
6006
6384
  metadata: items,
@@ -6014,17 +6392,17 @@ function RequiredStatement({ manifest, requiredStatement, ...rest }) {
6014
6392
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
6015
6393
  return null;
6016
6394
  }
6017
- return /* @__PURE__ */ React42.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
6395
+ return /* @__PURE__ */ React45.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
6018
6396
  }
6019
6397
 
6020
6398
  // ui/src/iiif/Properties/Id.jsx
6021
- import React43 from "react";
6399
+ import React46 from "react";
6022
6400
  function Id({ title = "IIIF Manifest", id, ...props }) {
6023
- return /* @__PURE__ */ React43.createElement("dl", null, /* @__PURE__ */ React43.createElement("dt", null, title), /* @__PURE__ */ React43.createElement("dd", null, /* @__PURE__ */ React43.createElement("a", { href: id }, id)));
6401
+ return /* @__PURE__ */ React46.createElement("dl", null, /* @__PURE__ */ React46.createElement("dt", null, title), /* @__PURE__ */ React46.createElement("dd", null, /* @__PURE__ */ React46.createElement("a", { href: id }, id)));
6024
6402
  }
6025
6403
 
6026
6404
  // ui/src/docs/CodeBlock.jsx
6027
- import React44 from "react";
6405
+ import React47 from "react";
6028
6406
  function parseHighlightAttr(attr) {
6029
6407
  if (!attr) return /* @__PURE__ */ new Set();
6030
6408
  const cleaned = String(attr || "").trim();
@@ -6070,10 +6448,10 @@ var highlightBaseStyle = {
6070
6448
  };
6071
6449
  function DocsCodeBlock(props = {}) {
6072
6450
  const { children, ...rest } = props;
6073
- const childArray = React44.Children.toArray(children);
6074
- const codeElement = childArray.find((el) => React44.isValidElement(el));
6451
+ const childArray = React47.Children.toArray(children);
6452
+ const codeElement = childArray.find((el) => React47.isValidElement(el));
6075
6453
  if (!codeElement || !codeElement.props) {
6076
- return React44.createElement("pre", props);
6454
+ return React47.createElement("pre", props);
6077
6455
  }
6078
6456
  const {
6079
6457
  className = "",
@@ -6088,9 +6466,9 @@ function DocsCodeBlock(props = {}) {
6088
6466
  const highlightSet = parseHighlightAttr(highlightAttr);
6089
6467
  const copyAttr = codeProps["data-copy"];
6090
6468
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
6091
- const [copied, setCopied] = React44.useState(false);
6092
- const buttonRef = React44.useRef(null);
6093
- const handleCopy = React44.useCallback(async () => {
6469
+ const [copied, setCopied] = React47.useState(false);
6470
+ const buttonRef = React47.useRef(null);
6471
+ const handleCopy = React47.useCallback(async () => {
6094
6472
  const text = trimmedCode;
6095
6473
  try {
6096
6474
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -6112,12 +6490,12 @@ function DocsCodeBlock(props = {}) {
6112
6490
  setCopied(false);
6113
6491
  }
6114
6492
  }, [trimmedCode]);
6115
- React44.useEffect(() => {
6493
+ React47.useEffect(() => {
6116
6494
  if (buttonRef.current) {
6117
6495
  buttonRef.current.setAttribute("data-docs-copy-hydrated", "true");
6118
6496
  }
6119
6497
  }, []);
6120
- React44.useEffect(() => {
6498
+ React47.useEffect(() => {
6121
6499
  if (!buttonRef.current) return;
6122
6500
  if (copied) buttonRef.current.setAttribute("data-docs-copy-active", "true");
6123
6501
  else buttonRef.current.removeAttribute("data-docs-copy-active");
@@ -6180,27 +6558,27 @@ function DocsCodeBlock(props = {}) {
6180
6558
  const highlight = highlightSet.has(lineNumber);
6181
6559
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
6182
6560
  const displayLine = line === "" ? " " : line;
6183
- return React44.createElement(
6561
+ return React47.createElement(
6184
6562
  "span",
6185
6563
  {
6186
6564
  key: lineNumber,
6187
6565
  style,
6188
6566
  "data-docs-code-line": line
6189
6567
  },
6190
- React44.createElement("span", { style: lineContentStyle }, displayLine)
6568
+ React47.createElement("span", { style: lineContentStyle }, displayLine)
6191
6569
  );
6192
6570
  });
6193
- return React44.createElement(
6571
+ return React47.createElement(
6194
6572
  "div",
6195
6573
  {
6196
6574
  style: containerStyle,
6197
6575
  "data-docs-code-block": "true"
6198
6576
  },
6199
- showHeader ? React44.createElement(
6577
+ showHeader ? React47.createElement(
6200
6578
  "div",
6201
6579
  { style: headerStyle },
6202
- React44.createElement("span", null, showFilename ? filename : null),
6203
- enableCopy ? React44.createElement(
6580
+ React47.createElement("span", null, showFilename ? filename : null),
6581
+ enableCopy ? React47.createElement(
6204
6582
  "button",
6205
6583
  {
6206
6584
  ref: buttonRef,
@@ -6211,8 +6589,8 @@ function DocsCodeBlock(props = {}) {
6211
6589
  "data-docs-copy-button": "true",
6212
6590
  style: buttonStyle
6213
6591
  },
6214
- React44.createElement("span", null, "Copy"),
6215
- React44.createElement(
6592
+ React47.createElement("span", null, "Copy"),
6593
+ React47.createElement(
6216
6594
  "span",
6217
6595
  {
6218
6596
  "aria-hidden": "true",
@@ -6222,7 +6600,7 @@ function DocsCodeBlock(props = {}) {
6222
6600
  )
6223
6601
  ) : null
6224
6602
  ) : null,
6225
- enableCopy ? React44.createElement("textarea", {
6603
+ enableCopy ? React47.createElement("textarea", {
6226
6604
  "data-docs-copy-source": "true",
6227
6605
  tabIndex: -1,
6228
6606
  readOnly: true,
@@ -6237,29 +6615,29 @@ function DocsCodeBlock(props = {}) {
6237
6615
  pointerEvents: "none"
6238
6616
  }
6239
6617
  }) : null,
6240
- React44.createElement(
6618
+ React47.createElement(
6241
6619
  "pre",
6242
6620
  { ...preRest, className: preClassName, style: mergedPreStyle },
6243
- React44.createElement("code", { style: codeStyle }, lineElements)
6621
+ React47.createElement("code", { style: codeStyle }, lineElements)
6244
6622
  )
6245
6623
  );
6246
6624
  }
6247
6625
 
6248
6626
  // ui/src/docs/MarkdownTable.jsx
6249
- import React45 from "react";
6627
+ import React48 from "react";
6250
6628
  function MarkdownTable({ className = "", ...rest }) {
6251
6629
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
6252
- return /* @__PURE__ */ React45.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React45.createElement("table", { className: merged, ...rest }));
6630
+ return /* @__PURE__ */ React48.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React48.createElement("table", { className: merged, ...rest }));
6253
6631
  }
6254
6632
 
6255
6633
  // ui/src/docs/Diagram.jsx
6256
- import React46 from "react";
6634
+ import React49 from "react";
6257
6635
  function CanopyDiagram() {
6258
- return /* @__PURE__ */ React46.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React46.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React46.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React46.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Collection A"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React46.createElement("li", null, /* @__PURE__ */ React46.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Collection B"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React46.createElement("li", null, /* @__PURE__ */ React46.createElement("em", null, "Portraits")))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React46.createElement("li", null, /* @__PURE__ */ React46.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React46.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React46.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React46.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React46.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Automated content"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React46.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React46.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React46.createElement("li", null, "Author narratives"), /* @__PURE__ */ React46.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Search index"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React46.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React46.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React46.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React46.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React46.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React46.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React46.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__ */ React46.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Work pages"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React46.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React46.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React46.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React46.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React46.createElement("article", null, /* @__PURE__ */ React46.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React46.createElement("ul", null, /* @__PURE__ */ React46.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React46.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React46.createElement("li", null, "Optional annotation dataset"))))));
6636
+ return /* @__PURE__ */ React49.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React49.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React49.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React49.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Collection A"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React49.createElement("li", null, /* @__PURE__ */ React49.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Collection B"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React49.createElement("li", null, /* @__PURE__ */ React49.createElement("em", null, "Portraits")))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React49.createElement("li", null, /* @__PURE__ */ React49.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React49.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React49.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React49.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React49.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Automated content"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React49.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React49.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React49.createElement("li", null, "Author narratives"), /* @__PURE__ */ React49.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Search index"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React49.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React49.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React49.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React49.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React49.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React49.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React49.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__ */ React49.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Work pages"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React49.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React49.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React49.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React49.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React49.createElement("article", null, /* @__PURE__ */ React49.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React49.createElement("ul", null, /* @__PURE__ */ React49.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React49.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React49.createElement("li", null, "Optional annotation dataset"))))));
6259
6637
  }
6260
6638
 
6261
6639
  // ui/src/docs/ThemeShowcase.jsx
6262
- import React47 from "react";
6640
+ import React50 from "react";
6263
6641
 
6264
6642
  // ../../node_modules/@radix-ui/colors/index.mjs
6265
6643
  var colors_exports = {};
@@ -10111,21 +10489,21 @@ var STEP_MAP = {
10111
10489
  800: 11,
10112
10490
  900: 12
10113
10491
  };
10114
- var Section = ({ title, description, children }) => /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React47.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React47.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
10115
- var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React47.createElement("strong", null, label)), /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React47.createElement(
10492
+ var Section = ({ title, description, children }) => /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React50.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React50.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
10493
+ var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React50.createElement("strong", null, label)), /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React50.createElement(
10116
10494
  "div",
10117
10495
  {
10118
10496
  key: `${label}-${stop}`,
10119
10497
  className: "canopy-theme-showcase__scale-stop"
10120
10498
  },
10121
- /* @__PURE__ */ React47.createElement(
10499
+ /* @__PURE__ */ React50.createElement(
10122
10500
  "span",
10123
10501
  {
10124
10502
  className: "canopy-theme-showcase__scale-chip",
10125
10503
  style: { backgroundColor: `var(${prefix}-${stop})` }
10126
10504
  }
10127
10505
  ),
10128
- /* @__PURE__ */ React47.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
10506
+ /* @__PURE__ */ React50.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
10129
10507
  ))));
10130
10508
  var AVAILABLE = new Set(
10131
10509
  Object.keys(colors_exports).filter(
@@ -10190,9 +10568,9 @@ var PREVIEW_DATA = buildPreviewData();
10190
10568
  function encodeJson(value) {
10191
10569
  return JSON.stringify(value).replace(/</g, "\\u003c");
10192
10570
  }
10193
- var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
10571
+ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
10194
10572
  const colorValue = getRadixSwatch(name);
10195
- return /* @__PURE__ */ React47.createElement(
10573
+ return /* @__PURE__ */ React50.createElement(
10196
10574
  "button",
10197
10575
  {
10198
10576
  key: `${type}-${name}`,
@@ -10203,14 +10581,14 @@ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React4
10203
10581
  "data-theme-swatch-value": name,
10204
10582
  "aria-pressed": "false"
10205
10583
  },
10206
- /* @__PURE__ */ React47.createElement(
10584
+ /* @__PURE__ */ React50.createElement(
10207
10585
  "span",
10208
10586
  {
10209
10587
  className: "canopy-theme-showcase__swatch-chip",
10210
10588
  style: { background: colorValue || "var(--color-gray-200)" }
10211
10589
  }
10212
10590
  ),
10213
- /* @__PURE__ */ React47.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
10591
+ /* @__PURE__ */ React50.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
10214
10592
  );
10215
10593
  }));
10216
10594
  function ThemeShowcase() {
@@ -10370,7 +10748,7 @@ function ThemeShowcase() {
10370
10748
  .canopy-theme-showcase__swatch-controls { display: none; }
10371
10749
  .canopy-theme-showcase__clear-button { display: none; }
10372
10750
  `;
10373
- return /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React47.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React47.createElement(
10751
+ return /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React50.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React50.createElement(
10374
10752
  "div",
10375
10753
  {
10376
10754
  style: {
@@ -10381,18 +10759,18 @@ function ThemeShowcase() {
10381
10759
  marginBottom: "1rem"
10382
10760
  }
10383
10761
  },
10384
- /* @__PURE__ */ React47.createElement(
10762
+ /* @__PURE__ */ React50.createElement(
10385
10763
  Section,
10386
10764
  {
10387
10765
  title: "Appearance",
10388
10766
  description: "Pick the base light or dark mode for the theme preview."
10389
10767
  },
10390
- /* @__PURE__ */ React47.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
10768
+ /* @__PURE__ */ React50.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
10391
10769
  const label = `${mode.charAt(0).toUpperCase()}${mode.slice(1)}`;
10392
10770
  const baseClass = "canopy-theme-showcase__appearance-button";
10393
10771
  const isDefault = mode === DEFAULTS.appearance;
10394
10772
  const className = isDefault ? `${baseClass} is-active` : baseClass;
10395
- return /* @__PURE__ */ React47.createElement(
10773
+ return /* @__PURE__ */ React50.createElement(
10396
10774
  "button",
10397
10775
  {
10398
10776
  key: mode,
@@ -10404,7 +10782,7 @@ function ThemeShowcase() {
10404
10782
  );
10405
10783
  }))
10406
10784
  ),
10407
- /* @__PURE__ */ React47.createElement(
10785
+ /* @__PURE__ */ React50.createElement(
10408
10786
  "button",
10409
10787
  {
10410
10788
  type: "button",
@@ -10413,13 +10791,13 @@ function ThemeShowcase() {
10413
10791
  },
10414
10792
  "Reset"
10415
10793
  )
10416
- ), /* @__PURE__ */ React47.createElement(
10794
+ ), /* @__PURE__ */ React50.createElement(
10417
10795
  Section,
10418
10796
  {
10419
10797
  title: "Color scales",
10420
10798
  description: "Accent and gray ramps from the active theme."
10421
10799
  },
10422
- /* @__PURE__ */ React47.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React47.createElement(
10800
+ /* @__PURE__ */ React50.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React50.createElement(
10423
10801
  ColorScaleRow,
10424
10802
  {
10425
10803
  key: scale.label,
@@ -10427,13 +10805,13 @@ function ThemeShowcase() {
10427
10805
  prefix: scale.prefix
10428
10806
  }
10429
10807
  )))
10430
- ), /* @__PURE__ */ React47.createElement(
10808
+ ), /* @__PURE__ */ React50.createElement(
10431
10809
  Section,
10432
10810
  {
10433
10811
  title: "Accent color palette options",
10434
10812
  description: "Click a swatch to temporarily override the accent palette."
10435
10813
  },
10436
- /* @__PURE__ */ React47.createElement(
10814
+ /* @__PURE__ */ React50.createElement(
10437
10815
  ColorsLabeled,
10438
10816
  {
10439
10817
  colors: accentColors,
@@ -10441,13 +10819,13 @@ function ThemeShowcase() {
10441
10819
  getRadixSwatch
10442
10820
  }
10443
10821
  )
10444
- ), /* @__PURE__ */ React47.createElement(
10822
+ ), /* @__PURE__ */ React50.createElement(
10445
10823
  Section,
10446
10824
  {
10447
10825
  title: "Gray color palette options",
10448
10826
  description: "Click a swatch to preview the neutral ramp for surfaces and text."
10449
10827
  },
10450
- /* @__PURE__ */ React47.createElement(
10828
+ /* @__PURE__ */ React50.createElement(
10451
10829
  ColorsLabeled,
10452
10830
  {
10453
10831
  colors: grayColors,
@@ -10455,7 +10833,7 @@ function ThemeShowcase() {
10455
10833
  getRadixSwatch
10456
10834
  }
10457
10835
  )
10458
- ), /* @__PURE__ */ React47.createElement(
10836
+ ), /* @__PURE__ */ React50.createElement(
10459
10837
  "script",
10460
10838
  {
10461
10839
  type: "application/json",
@@ -10488,6 +10866,7 @@ export {
10488
10866
  Index,
10489
10867
  interstitials_exports as Interstitials,
10490
10868
  Label,
10869
+ LanguageToggle,
10491
10870
  Layout,
10492
10871
  MdxMap as Map,
10493
10872
  MapPoint,