@canopy-iiif/app 1.4.1 → 1.4.3

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.
@@ -2416,11 +2416,11 @@ function References({
2416
2416
  }
2417
2417
 
2418
2418
  // ui/src/content/timeline/MdxTimeline.jsx
2419
- import React28 from "react";
2419
+ import React30 from "react";
2420
2420
  import ReactDOMServer from "react-dom/server";
2421
2421
 
2422
2422
  // ui/src/content/timeline/Timeline.jsx
2423
- import React27 from "react";
2423
+ import React28 from "react";
2424
2424
 
2425
2425
  // ui/src/content/timeline/date-utils.js
2426
2426
  var FALLBACK_LOCALE = (() => {
@@ -2580,6 +2580,56 @@ function clampProgress(value) {
2580
2580
  return value;
2581
2581
  }
2582
2582
 
2583
+ // ui/src/layout/ReferencedManifestCard.jsx
2584
+ import React27 from "react";
2585
+ function normalizeMetadata(metadata, summary) {
2586
+ if (Array.isArray(metadata) && metadata.length) {
2587
+ return metadata.filter(Boolean);
2588
+ }
2589
+ if (summary) return [summary];
2590
+ return [];
2591
+ }
2592
+ function ReferencedManifestCard({
2593
+ manifest = null,
2594
+ href,
2595
+ title,
2596
+ summary,
2597
+ metadata,
2598
+ thumbnail,
2599
+ type,
2600
+ className = "",
2601
+ ...rest
2602
+ }) {
2603
+ var _a, _b, _c, _d, _e, _f;
2604
+ const record = manifest || {};
2605
+ const resolvedHref = (_a = href != null ? href : record.href) != null ? _a : "";
2606
+ const resolvedTitle = (_c = (_b = title != null ? title : record.title) != null ? _b : record.href) != null ? _c : "";
2607
+ const resolvedSummary = (_d = summary != null ? summary : record.summary) != null ? _d : "";
2608
+ const resolvedMetadata = normalizeMetadata(
2609
+ metadata != null ? metadata : record.metadata,
2610
+ resolvedSummary
2611
+ );
2612
+ const resolvedThumbnail = (_e = thumbnail != null ? thumbnail : record.thumbnail) != null ? _e : null;
2613
+ const resolvedType = (_f = type != null ? type : record.type) != null ? _f : "work";
2614
+ const classes = [
2615
+ "canopy-referenced-manifest-card",
2616
+ className
2617
+ ].filter(Boolean).join(" ");
2618
+ return /* @__PURE__ */ React27.createElement(
2619
+ TeaserCard,
2620
+ {
2621
+ href: resolvedHref || void 0,
2622
+ title: resolvedTitle || resolvedHref || "",
2623
+ summary: resolvedSummary,
2624
+ metadata: resolvedMetadata,
2625
+ thumbnail: resolvedThumbnail,
2626
+ type: resolvedType,
2627
+ className: classes,
2628
+ ...rest
2629
+ }
2630
+ );
2631
+ }
2632
+
2583
2633
  // ui/src/content/timeline/Timeline.jsx
2584
2634
  var DAY_MS = 24 * 60 * 60 * 1e3;
2585
2635
  var DEFAULT_TRACK_HEIGHT = 640;
@@ -2747,24 +2797,14 @@ function TimelineConnector({ side, isActive, highlight }) {
2747
2797
  "canopy-timeline__connector-dot",
2748
2798
  highlight || isActive ? "is-active" : ""
2749
2799
  ].filter(Boolean).join(" ");
2750
- return /* @__PURE__ */ React27.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React27.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement("span", { className: dotClasses }), /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__connector-line" })));
2800
+ return /* @__PURE__ */ React28.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React28.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: dotClasses }), /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__connector-line" })));
2751
2801
  }
2752
2802
  function renderResourceSection(point) {
2753
2803
  if (!point) return null;
2754
2804
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
2755
2805
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2756
2806
  if (!manifestCards.length && !legacyResources.length) return null;
2757
- return /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React27.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React27.createElement(
2758
- TeaserCard,
2759
- {
2760
- href: manifest.href,
2761
- title: manifest.title || manifest.href,
2762
- summary: manifest.summary,
2763
- metadata: Array.isArray(manifest.metadata) && manifest.metadata.length ? manifest.metadata : manifest.summary ? [manifest.summary] : [],
2764
- thumbnail: manifest.thumbnail,
2765
- type: manifest.type || "work"
2766
- }
2767
- ))), legacyResources.map((resource, idx) => /* @__PURE__ */ React27.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React27.createElement(
2807
+ return /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React28.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React28.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React28.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React28.createElement(
2768
2808
  TeaserCard,
2769
2809
  {
2770
2810
  href: resource.href,
@@ -2789,26 +2829,26 @@ function Timeline({
2789
2829
  ...rest
2790
2830
  }) {
2791
2831
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
2792
- const rawPoints = React27.useMemo(() => {
2832
+ const rawPoints = React28.useMemo(() => {
2793
2833
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
2794
2834
  if (payloadPoints && payloadPoints.length) return payloadPoints;
2795
2835
  return [];
2796
2836
  }, [pointsProp, payloadPoints]);
2797
- const sanitizedPoints = React27.useMemo(
2837
+ const sanitizedPoints = React28.useMemo(
2798
2838
  () => sanitizePoints(rawPoints),
2799
2839
  [rawPoints]
2800
2840
  );
2801
2841
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
2802
- const baseLocale = React27.useMemo(
2842
+ const baseLocale = React28.useMemo(
2803
2843
  () => createLocale(localeValue),
2804
2844
  [localeValue]
2805
2845
  );
2806
2846
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
2807
- const rangeOverrides = React27.useMemo(
2847
+ const rangeOverrides = React28.useMemo(
2808
2848
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
2809
2849
  [sanitizedPoints, rangeInput]
2810
2850
  );
2811
- const effectiveRange = React27.useMemo(
2851
+ const effectiveRange = React28.useMemo(
2812
2852
  () => normalizeRange({
2813
2853
  ...rangeOverrides,
2814
2854
  locale: baseLocale
@@ -2817,7 +2857,7 @@ function Timeline({
2817
2857
  );
2818
2858
  const spanStart = effectiveRange.startDate.getTime();
2819
2859
  const span = effectiveRange.span;
2820
- const pointsWithPosition = React27.useMemo(() => {
2860
+ const pointsWithPosition = React28.useMemo(() => {
2821
2861
  if (!sanitizedPoints.length) return [];
2822
2862
  return sanitizedPoints.map((point, index) => {
2823
2863
  const timestamp = point.meta.timestamp;
@@ -2831,29 +2871,29 @@ function Timeline({
2831
2871
  };
2832
2872
  });
2833
2873
  }, [sanitizedPoints, spanStart, span]);
2834
- const [activeId, setActiveId] = React27.useState(
2874
+ const [activeId, setActiveId] = React28.useState(
2835
2875
  () => getActivePointId(pointsWithPosition)
2836
2876
  );
2837
- React27.useEffect(() => {
2877
+ React28.useEffect(() => {
2838
2878
  setActiveId(getActivePointId(pointsWithPosition));
2839
2879
  }, [pointsWithPosition]);
2840
2880
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
2841
2881
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
2842
- const thresholdMs = React27.useMemo(
2882
+ const thresholdMs = React28.useMemo(
2843
2883
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
2844
2884
  [thresholdValue, effectiveRange.granularity]
2845
2885
  );
2846
- const groupedEntries = React27.useMemo(
2886
+ const groupedEntries = React28.useMemo(
2847
2887
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
2848
2888
  granularity: effectiveRange.granularity,
2849
2889
  locale: baseLocale
2850
2890
  }),
2851
2891
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
2852
2892
  );
2853
- const [expandedGroupIds, setExpandedGroupIds] = React27.useState(
2893
+ const [expandedGroupIds, setExpandedGroupIds] = React28.useState(
2854
2894
  () => /* @__PURE__ */ new Set()
2855
2895
  );
2856
- React27.useEffect(() => {
2896
+ React28.useEffect(() => {
2857
2897
  setExpandedGroupIds((prev) => {
2858
2898
  if (!prev || prev.size === 0) return prev;
2859
2899
  const validIds = new Set(
@@ -2868,7 +2908,7 @@ function Timeline({
2868
2908
  return changed ? next : prev;
2869
2909
  });
2870
2910
  }, [groupedEntries]);
2871
- const toggleGroup = React27.useCallback((groupId) => {
2911
+ const toggleGroup = React28.useCallback((groupId) => {
2872
2912
  setExpandedGroupIds((prev) => {
2873
2913
  const next = new Set(prev || []);
2874
2914
  if (next.has(groupId)) next.delete(groupId);
@@ -2891,7 +2931,7 @@ function Timeline({
2891
2931
  point.id === activeId ? "is-active" : "",
2892
2932
  point.highlight ? "is-highlighted" : ""
2893
2933
  ].filter(Boolean).join(" ");
2894
- const connector = /* @__PURE__ */ React27.createElement(
2934
+ const connector = /* @__PURE__ */ React28.createElement(
2895
2935
  TimelineConnector,
2896
2936
  {
2897
2937
  side: point.side,
@@ -2899,9 +2939,9 @@ function Timeline({
2899
2939
  highlight: point.highlight
2900
2940
  }
2901
2941
  );
2902
- const body = /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2942
+ const body = /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2903
2943
  const resourceSection = renderResourceSection(point);
2904
- return /* @__PURE__ */ React27.createElement(
2944
+ return /* @__PURE__ */ React28.createElement(
2905
2945
  "div",
2906
2946
  {
2907
2947
  key: point.id,
@@ -2909,7 +2949,7 @@ function Timeline({
2909
2949
  style: wrapperStyle,
2910
2950
  role: "listitem"
2911
2951
  },
2912
- point.side === "left" ? /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React27.createElement(React27.Fragment, null, connector, /* @__PURE__ */ React27.createElement("div", { className: cardClasses }, body, resourceSection))
2952
+ point.side === "left" ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React28.createElement(React28.Fragment, null, connector, /* @__PURE__ */ React28.createElement("div", { className: cardClasses }, body, resourceSection))
2913
2953
  );
2914
2954
  }
2915
2955
  function renderGroupEntry(entry) {
@@ -2920,7 +2960,7 @@ function Timeline({
2920
2960
  const wrapperStyle = { top: `${entry.progress * 100}%` };
2921
2961
  const isExpanded = expandedGroupIds.has(entry.id);
2922
2962
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
2923
- const connector = /* @__PURE__ */ React27.createElement(
2963
+ const connector = /* @__PURE__ */ React28.createElement(
2924
2964
  TimelineConnector,
2925
2965
  {
2926
2966
  side: entry.side,
@@ -2934,7 +2974,7 @@ function Timeline({
2934
2974
  hasActivePoint ? "is-active" : ""
2935
2975
  ].filter(Boolean).join(" ");
2936
2976
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
2937
- const header = /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React27.createElement(
2977
+ const header = /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React28.createElement(
2938
2978
  "button",
2939
2979
  {
2940
2980
  type: "button",
@@ -2944,7 +2984,7 @@ function Timeline({
2944
2984
  },
2945
2985
  isExpanded ? "Hide details" : "Show details"
2946
2986
  ));
2947
- const groupPoints = isExpanded ? /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React27.createElement(
2987
+ const groupPoints = isExpanded ? /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React28.createElement(
2948
2988
  "button",
2949
2989
  {
2950
2990
  key: point.id,
@@ -2955,11 +2995,11 @@ function Timeline({
2955
2995
  ].filter(Boolean).join(" "),
2956
2996
  onClick: () => setActiveId(point.id)
2957
2997
  },
2958
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2959
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2998
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2999
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2960
3000
  ))) : null;
2961
- const groupCard = /* @__PURE__ */ React27.createElement("div", { className: groupClasses }, header, groupPoints);
2962
- return /* @__PURE__ */ React27.createElement(
3001
+ const groupCard = /* @__PURE__ */ React28.createElement("div", { className: groupClasses }, header, groupPoints);
3002
+ return /* @__PURE__ */ React28.createElement(
2963
3003
  "div",
2964
3004
  {
2965
3005
  key: entry.id,
@@ -2967,17 +3007,17 @@ function Timeline({
2967
3007
  style: wrapperStyle,
2968
3008
  role: "listitem"
2969
3009
  },
2970
- entry.side === "left" ? /* @__PURE__ */ React27.createElement(React27.Fragment, null, groupCard, connector) : /* @__PURE__ */ React27.createElement(React27.Fragment, null, connector, groupCard)
3010
+ entry.side === "left" ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, groupCard, connector) : /* @__PURE__ */ React28.createElement(React28.Fragment, null, connector, groupCard)
2971
3011
  );
2972
3012
  }
2973
- return /* @__PURE__ */ React27.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React27.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React27.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React27.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React27.createElement(
3013
+ return /* @__PURE__ */ React28.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React28.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React28.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React28.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React28.createElement(
2974
3014
  "div",
2975
3015
  {
2976
3016
  className: "canopy-timeline__list",
2977
3017
  role: "list",
2978
3018
  style: { minHeight: trackHeight }
2979
3019
  },
2980
- /* @__PURE__ */ React27.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
3020
+ /* @__PURE__ */ React28.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2981
3021
  renderSteps(stepsValue, effectiveRange),
2982
3022
  groupedEntries.map((entry) => {
2983
3023
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -2992,7 +3032,7 @@ function renderSteps(stepSize, range) {
2992
3032
  const markers = [];
2993
3033
  if (startYear < endYear) {
2994
3034
  markers.push(
2995
- /* @__PURE__ */ React27.createElement(
3035
+ /* @__PURE__ */ React28.createElement(
2996
3036
  "span",
2997
3037
  {
2998
3038
  key: "timeline-step-start",
@@ -3000,12 +3040,12 @@ function renderSteps(stepSize, range) {
3000
3040
  style: { top: "0%" },
3001
3041
  "aria-hidden": "true"
3002
3042
  },
3003
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-line" }),
3004
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
3043
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-line" }),
3044
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
3005
3045
  )
3006
3046
  );
3007
3047
  markers.push(
3008
- /* @__PURE__ */ React27.createElement(
3048
+ /* @__PURE__ */ React28.createElement(
3009
3049
  "span",
3010
3050
  {
3011
3051
  key: "timeline-step-end",
@@ -3013,8 +3053,8 @@ function renderSteps(stepSize, range) {
3013
3053
  style: { top: "100%" },
3014
3054
  "aria-hidden": "true"
3015
3055
  },
3016
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-line" }),
3017
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
3056
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-line" }),
3057
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
3018
3058
  )
3019
3059
  );
3020
3060
  }
@@ -3024,7 +3064,7 @@ function renderSteps(stepSize, range) {
3024
3064
  const progress = (timestamp - range.startDate.getTime()) / range.span;
3025
3065
  if (progress <= 0 || progress >= 1) continue;
3026
3066
  markers.push(
3027
- /* @__PURE__ */ React27.createElement(
3067
+ /* @__PURE__ */ React28.createElement(
3028
3068
  "span",
3029
3069
  {
3030
3070
  key: `timeline-step-${year}`,
@@ -3032,8 +3072,8 @@ function renderSteps(stepSize, range) {
3032
3072
  style: { top: `calc(${progress * 100}% - 0.5px)` },
3033
3073
  "aria-hidden": "true"
3034
3074
  },
3035
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-line" }),
3036
- /* @__PURE__ */ React27.createElement("span", { className: "canopy-timeline__step-label" }, year)
3075
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-line" }),
3076
+ /* @__PURE__ */ React28.createElement("span", { className: "canopy-timeline__step-label" }, year)
3037
3077
  )
3038
3078
  );
3039
3079
  }
@@ -3046,7 +3086,8 @@ function TimelinePoint() {
3046
3086
  }
3047
3087
  TimelinePoint.displayName = "TimelinePoint";
3048
3088
 
3049
- // ui/src/content/timeline/MdxTimeline.jsx
3089
+ // ui/src/utils/manifestReferences.js
3090
+ import React29 from "react";
3050
3091
  import navigationHelpers6 from "@canopy-iiif/app/lib/components/navigation.js";
3051
3092
  function normalizeManifestId(raw) {
3052
3093
  if (!raw) return "";
@@ -3063,25 +3104,52 @@ function normalizeManifestId(raw) {
3063
3104
  return String(raw || "").trim();
3064
3105
  }
3065
3106
  }
3066
- var PageContextFallback = React28.createContext(null);
3107
+ var PageContextFallback = React29.createContext(null);
3067
3108
  function useReferencedManifestMap() {
3068
3109
  var _a, _b;
3069
3110
  const PageContext = ((_b = (_a = navigationHelpers6) == null ? void 0 : _a.getPageContext) == null ? void 0 : _b.call(_a)) || PageContextFallback;
3070
- const pageContext = React28.useContext(PageContext);
3111
+ const pageContext = React29.useContext(PageContext);
3071
3112
  const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
3072
- return React28.useMemo(() => {
3113
+ return React29.useMemo(() => {
3073
3114
  const map = /* @__PURE__ */ new Map();
3074
3115
  referencedItems.forEach((item) => {
3075
3116
  if (!item) return;
3076
3117
  const id = item.id || item.href;
3077
3118
  if (!id) return;
3078
3119
  const normalized = normalizeManifestId(id);
3079
- map.set(normalized, item);
3120
+ if (normalized) map.set(normalized, item);
3080
3121
  map.set(String(id), item);
3081
3122
  });
3082
3123
  return map;
3083
3124
  }, [referencedItems]);
3084
3125
  }
3126
+ function resolveManifestReferences(ids, manifestMap) {
3127
+ if (!Array.isArray(ids) || !ids.length || !manifestMap) return [];
3128
+ const seen = /* @__PURE__ */ new Set();
3129
+ const out = [];
3130
+ ids.forEach((value) => {
3131
+ if (!value) return;
3132
+ const normalized = normalizeManifestId(value);
3133
+ if (!normalized || seen.has(normalized)) return;
3134
+ seen.add(normalized);
3135
+ const record = manifestMap.get(normalized) || manifestMap.get(String(value));
3136
+ if (!record) return;
3137
+ out.push({
3138
+ id: record.id || record.href || value,
3139
+ href: record.href || null,
3140
+ title: record.title || record.label || record.href || value,
3141
+ summary: record.summary || "",
3142
+ thumbnail: record.thumbnail || null,
3143
+ thumbnailWidth: record.thumbnailWidth,
3144
+ thumbnailHeight: record.thumbnailHeight,
3145
+ type: record.type || "work",
3146
+ metadata: Array.isArray(record.metadata) && record.metadata.length ? record.metadata : record.summary ? [record.summary] : []
3147
+ });
3148
+ });
3149
+ return out;
3150
+ }
3151
+
3152
+ // ui/src/content/timeline/MdxTimeline.jsx
3085
3153
  function normalizeResource(resource, index) {
3086
3154
  if (!resource) return null;
3087
3155
  const href = resource.href || resource.id || "";
@@ -3097,7 +3165,7 @@ function normalizeResource(resource, index) {
3097
3165
  }
3098
3166
  function normalizePoint(child, index, options) {
3099
3167
  var _a, _b, _c, _d, _e, _f;
3100
- if (!React28.isValidElement(child)) return null;
3168
+ if (!React30.isValidElement(child)) return null;
3101
3169
  if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
3102
3170
  return null;
3103
3171
  const props = child.props || {};
@@ -3113,7 +3181,7 @@ function normalizePoint(child, index, options) {
3113
3181
  try {
3114
3182
  if (props.children) {
3115
3183
  detailsHtml = ReactDOMServer.renderToStaticMarkup(
3116
- React28.createElement(React28.Fragment, null, props.children)
3184
+ React30.createElement(React30.Fragment, null, props.children)
3117
3185
  );
3118
3186
  }
3119
3187
  } catch (_) {
@@ -3138,31 +3206,6 @@ function normalizePoint(child, index, options) {
3138
3206
  manifests
3139
3207
  };
3140
3208
  }
3141
- function resolveManifestReferences(ids, manifestMap) {
3142
- if (!Array.isArray(ids) || !ids.length || !manifestMap) return [];
3143
- const seen = /* @__PURE__ */ new Set();
3144
- const out = [];
3145
- ids.forEach((value) => {
3146
- if (!value) return;
3147
- const normalized = normalizeManifestId(value);
3148
- if (!normalized || seen.has(normalized)) return;
3149
- seen.add(normalized);
3150
- const record = manifestMap.get(normalized);
3151
- if (!record) return;
3152
- out.push({
3153
- id: record.id || value,
3154
- href: record.href || null,
3155
- title: record.title || record.href || value,
3156
- summary: record.summary || "",
3157
- thumbnail: record.thumbnail || null,
3158
- thumbnailWidth: record.thumbnailWidth,
3159
- thumbnailHeight: record.thumbnailHeight,
3160
- type: record.type || "work",
3161
- metadata: Array.isArray(record.metadata) && record.metadata.length ? record.metadata : record.summary ? [record.summary] : []
3162
- });
3163
- });
3164
- return out;
3165
- }
3166
3209
  function serializeProps(props, payload, locale) {
3167
3210
  const clone = {};
3168
3211
  Object.keys(props || {}).forEach((key) => {
@@ -3187,7 +3230,7 @@ function MdxTimeline({ children, ...rest }) {
3187
3230
  const localeObj = createLocale(localeValue);
3188
3231
  const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
3189
3232
  const manifestMap = useReferencedManifestMap();
3190
- const childArray = React28.Children.toArray(children);
3233
+ const childArray = React30.Children.toArray(children);
3191
3234
  const points = childArray.map(
3192
3235
  (child, index) => normalizePoint(child, index, {
3193
3236
  range: rest.range || {},
@@ -3203,7 +3246,7 @@ function MdxTimeline({ children, ...rest }) {
3203
3246
  steps: rest.steps != null ? rest.steps : null
3204
3247
  };
3205
3248
  const json = serializeForScript(serializeProps(rest, payload, localeBase));
3206
- return /* @__PURE__ */ React28.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React28.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React28.createElement(
3249
+ return /* @__PURE__ */ React30.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React30.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React30.createElement(
3207
3250
  "script",
3208
3251
  {
3209
3252
  type: "application/json",
@@ -3213,7 +3256,7 @@ function MdxTimeline({ children, ...rest }) {
3213
3256
  }
3214
3257
 
3215
3258
  // ui/src/content/map/MdxMap.jsx
3216
- import React29 from "react";
3259
+ import React31 from "react";
3217
3260
  import ReactDOMServer2 from "react-dom/server";
3218
3261
 
3219
3262
  // ui/src/content/map/MapPoint.jsx
@@ -3240,15 +3283,15 @@ function renderDetailsHtml(children) {
3240
3283
  if (!children) return "";
3241
3284
  try {
3242
3285
  return ReactDOMServer2.renderToStaticMarkup(
3243
- React29.createElement(React29.Fragment, null, children)
3286
+ React31.createElement(React31.Fragment, null, children)
3244
3287
  );
3245
3288
  } catch (_) {
3246
3289
  return "";
3247
3290
  }
3248
3291
  }
3249
- function normalizeCustomPoint(child, index) {
3292
+ function normalizeCustomPoint(child, index, manifestMap) {
3250
3293
  var _a;
3251
- if (!React29.isValidElement(child)) return null;
3294
+ if (!React31.isValidElement(child)) return null;
3252
3295
  if (child.type !== MapPoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "MapPoint") return null;
3253
3296
  const coords = normalizeCoordinates(child.props || {});
3254
3297
  if (!coords) return null;
@@ -3257,22 +3300,43 @@ function normalizeCustomPoint(child, index) {
3257
3300
  const title = props.title || props.label || `Point ${index + 1}`;
3258
3301
  const summary = props.summary || props.description || "";
3259
3302
  const href = props.href || props.link || "";
3260
- const thumbnail = props.thumbnail || props.image || "";
3303
+ let thumbnail = props.thumbnail || props.image || "";
3304
+ let thumbnailWidth = normalizeNumber(props.thumbnailWidth);
3305
+ let thumbnailHeight = normalizeNumber(props.thumbnailHeight);
3261
3306
  const detailsHtml = renderDetailsHtml(props.children);
3307
+ const manifestValues = Array.isArray(props.referencedManifests) ? props.referencedManifests : props.manifest ? [props.manifest] : Array.isArray(props.manifests) ? props.manifests : [];
3308
+ const manifests = resolveManifestReferences(manifestValues, manifestMap);
3309
+ if (!thumbnail && manifests.length) {
3310
+ const manifestWithThumb = manifests.find(
3311
+ (manifest) => manifest && manifest.thumbnail
3312
+ );
3313
+ if (manifestWithThumb) {
3314
+ thumbnail = manifestWithThumb.thumbnail || "";
3315
+ if (thumbnail && thumbnailWidth == null && typeof manifestWithThumb.thumbnailWidth === "number") {
3316
+ thumbnailWidth = manifestWithThumb.thumbnailWidth;
3317
+ }
3318
+ if (thumbnail && thumbnailHeight == null && typeof manifestWithThumb.thumbnailHeight === "number") {
3319
+ thumbnailHeight = manifestWithThumb.thumbnailHeight;
3320
+ }
3321
+ }
3322
+ }
3262
3323
  return {
3263
3324
  id,
3264
3325
  title,
3265
3326
  summary,
3266
3327
  href,
3267
3328
  thumbnail,
3329
+ thumbnailWidth,
3330
+ thumbnailHeight,
3268
3331
  lat: coords.lat,
3269
3332
  lng: coords.lng,
3270
3333
  detailsHtml,
3334
+ manifests,
3271
3335
  type: "custom"
3272
3336
  };
3273
3337
  }
3274
- function normalizeCustomPoints(children) {
3275
- return React29.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index)).filter(Boolean);
3338
+ function normalizeCustomPoints(children, manifestMap) {
3339
+ return React31.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
3276
3340
  }
3277
3341
  function normalizeHeight(value) {
3278
3342
  if (value == null) return "600px";
@@ -3378,7 +3442,8 @@ function getDatasetInfo() {
3378
3442
  }
3379
3443
  }
3380
3444
  function MdxMap({ children, ...rest }) {
3381
- const customPoints = normalizeCustomPoints(children);
3445
+ const manifestMap = useReferencedManifestMap();
3446
+ const customPoints = normalizeCustomPoints(children, manifestMap);
3382
3447
  const datasetInfo = getDatasetInfo();
3383
3448
  const navDataset = {
3384
3449
  hasFeatures: Boolean(datasetInfo && datasetInfo.hasFeatures),
@@ -3409,11 +3474,11 @@ function MdxMap({ children, ...rest }) {
3409
3474
  if (placeholderClass) placeholderProps.className = placeholderClass;
3410
3475
  if (rest.id) placeholderProps.id = rest.id;
3411
3476
  if (rest.style) placeholderProps.style = rest.style;
3412
- return /* @__PURE__ */ React29.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React29.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React29.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React29.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3477
+ return /* @__PURE__ */ React31.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React31.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React31.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3413
3478
  }
3414
3479
 
3415
3480
  // ui/src/search/MdxSearchResults.jsx
3416
- import React30 from "react";
3481
+ import React32 from "react";
3417
3482
  function MdxSearchResults(props) {
3418
3483
  let json = "{}";
3419
3484
  try {
@@ -3421,11 +3486,11 @@ function MdxSearchResults(props) {
3421
3486
  } catch (_) {
3422
3487
  json = "{}";
3423
3488
  }
3424
- return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3489
+ return /* @__PURE__ */ React32.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React32.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3425
3490
  }
3426
3491
 
3427
3492
  // ui/src/search/SearchSummary.jsx
3428
- import React31 from "react";
3493
+ import React33 from "react";
3429
3494
  function SearchSummary(props) {
3430
3495
  let json = "{}";
3431
3496
  try {
@@ -3433,11 +3498,11 @@ function SearchSummary(props) {
3433
3498
  } catch (_) {
3434
3499
  json = "{}";
3435
3500
  }
3436
- return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3501
+ return /* @__PURE__ */ React33.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React33.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3437
3502
  }
3438
3503
 
3439
3504
  // ui/src/search/MdxSearchTabs.jsx
3440
- import React32 from "react";
3505
+ import React34 from "react";
3441
3506
  function MdxSearchTabs(props) {
3442
3507
  let json = "{}";
3443
3508
  try {
@@ -3445,11 +3510,11 @@ function MdxSearchTabs(props) {
3445
3510
  } catch (_) {
3446
3511
  json = "{}";
3447
3512
  }
3448
- return /* @__PURE__ */ React32.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React32.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3513
+ return /* @__PURE__ */ React34.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React34.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3449
3514
  }
3450
3515
 
3451
3516
  // ui/src/search/MdxSearch.jsx
3452
- import React33 from "react";
3517
+ import React35 from "react";
3453
3518
  function MdxSearch(props = {}) {
3454
3519
  const {
3455
3520
  layout,
@@ -3467,11 +3532,11 @@ function MdxSearch(props = {}) {
3467
3532
  resultsPayload.layout = layout;
3468
3533
  }
3469
3534
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
3470
- return /* @__PURE__ */ React33.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React33.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React33.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React33.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
3535
+ return /* @__PURE__ */ React35.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React35.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React35.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React35.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
3471
3536
  }
3472
3537
 
3473
3538
  // ui/src/search-form/MdxSearchFormModal.jsx
3474
- import React34 from "react";
3539
+ import React36 from "react";
3475
3540
  function MdxSearchFormModal(props = {}) {
3476
3541
  const {
3477
3542
  placeholder = "Search\u2026",
@@ -3487,12 +3552,12 @@ function MdxSearchFormModal(props = {}) {
3487
3552
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
3488
3553
  const resolvedSearchPath = resolveSearchPath(searchPath);
3489
3554
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
3490
- return /* @__PURE__ */ React34.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React34.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React34.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React34.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React34.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
3555
+ return /* @__PURE__ */ React36.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React36.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React36.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React36.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React36.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
3491
3556
  }
3492
3557
 
3493
3558
  // ui/src/iiif/ManifestPrimitives.jsx
3494
3559
  var import_slugify = __toESM(require_slugify());
3495
- import React35 from "react";
3560
+ import React37 from "react";
3496
3561
  import {
3497
3562
  Label as CloverLabel,
3498
3563
  Metadata as CloverMetadata,
@@ -3633,7 +3698,7 @@ function MetadataFacetLink(props) {
3633
3698
  const valueSlug = facetSlug ? toValueSlug(text) : "";
3634
3699
  const href = facetSlug && valueSlug ? buildFacetSearchHref(facetSlug, valueSlug) : "";
3635
3700
  if (!href) return text;
3636
- return /* @__PURE__ */ React35.createElement(
3701
+ return /* @__PURE__ */ React37.createElement(
3637
3702
  "a",
3638
3703
  {
3639
3704
  href,
@@ -3659,7 +3724,7 @@ function buildFacetCustomValueContent(items, manifest) {
3659
3724
  seen.add(normalized);
3660
3725
  custom.push({
3661
3726
  matchingLabel: item.label,
3662
- Content: /* @__PURE__ */ React35.createElement(MetadataFacetLink, { facetSlug: facet.slug })
3727
+ Content: /* @__PURE__ */ React37.createElement(MetadataFacetLink, { facetSlug: facet.slug })
3663
3728
  });
3664
3729
  }
3665
3730
  return custom;
@@ -3691,12 +3756,12 @@ function mergeCustomValueContent(userContent, autoContent) {
3691
3756
  function Label({ manifest, label, ...rest }) {
3692
3757
  const intl = label || manifest && manifest.label;
3693
3758
  if (!hasInternationalValue(intl)) return null;
3694
- return /* @__PURE__ */ React35.createElement(CloverLabel, { label: intl, ...rest });
3759
+ return /* @__PURE__ */ React37.createElement(CloverLabel, { label: intl, ...rest });
3695
3760
  }
3696
3761
  function Summary({ manifest, summary, ...rest }) {
3697
3762
  const intl = summary || manifest && manifest.summary;
3698
3763
  if (!hasInternationalValue(intl)) return null;
3699
- return /* @__PURE__ */ React35.createElement(CloverSummary, { summary: intl, ...rest });
3764
+ return /* @__PURE__ */ React37.createElement(CloverSummary, { summary: intl, ...rest });
3700
3765
  }
3701
3766
  function Metadata({ manifest, metadata, customValueContent, ...rest }) {
3702
3767
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
@@ -3706,7 +3771,7 @@ function Metadata({ manifest, metadata, customValueContent, ...rest }) {
3706
3771
  customValueContent,
3707
3772
  autoCustomContent
3708
3773
  );
3709
- return /* @__PURE__ */ React35.createElement(
3774
+ return /* @__PURE__ */ React37.createElement(
3710
3775
  CloverMetadata,
3711
3776
  {
3712
3777
  metadata: items,
@@ -3720,11 +3785,11 @@ function RequiredStatement({ manifest, requiredStatement, ...rest }) {
3720
3785
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
3721
3786
  return null;
3722
3787
  }
3723
- return /* @__PURE__ */ React35.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
3788
+ return /* @__PURE__ */ React37.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
3724
3789
  }
3725
3790
 
3726
3791
  // ui/src/docs/CodeBlock.jsx
3727
- import React36 from "react";
3792
+ import React38 from "react";
3728
3793
  function parseHighlightAttr(attr) {
3729
3794
  if (!attr) return /* @__PURE__ */ new Set();
3730
3795
  const cleaned = String(attr || "").trim();
@@ -3770,10 +3835,10 @@ var highlightBaseStyle = {
3770
3835
  };
3771
3836
  function DocsCodeBlock(props = {}) {
3772
3837
  const { children, ...rest } = props;
3773
- const childArray = React36.Children.toArray(children);
3774
- const codeElement = childArray.find((el) => React36.isValidElement(el));
3838
+ const childArray = React38.Children.toArray(children);
3839
+ const codeElement = childArray.find((el) => React38.isValidElement(el));
3775
3840
  if (!codeElement || !codeElement.props) {
3776
- return React36.createElement("pre", props);
3841
+ return React38.createElement("pre", props);
3777
3842
  }
3778
3843
  const {
3779
3844
  className = "",
@@ -3788,8 +3853,8 @@ function DocsCodeBlock(props = {}) {
3788
3853
  const highlightSet = parseHighlightAttr(highlightAttr);
3789
3854
  const copyAttr = codeProps["data-copy"];
3790
3855
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
3791
- const [copied, setCopied] = React36.useState(false);
3792
- const handleCopy = React36.useCallback(async () => {
3856
+ const [copied, setCopied] = React38.useState(false);
3857
+ const handleCopy = React38.useCallback(async () => {
3793
3858
  const text = rawCode;
3794
3859
  try {
3795
3860
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -3854,20 +3919,20 @@ function DocsCodeBlock(props = {}) {
3854
3919
  const highlight = highlightSet.has(lineNumber);
3855
3920
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
3856
3921
  const displayLine = line === "" ? " " : line;
3857
- return React36.createElement(
3922
+ return React38.createElement(
3858
3923
  "span",
3859
3924
  { key: lineNumber, style },
3860
- React36.createElement("span", { style: lineContentStyle }, displayLine)
3925
+ React38.createElement("span", { style: lineContentStyle }, displayLine)
3861
3926
  );
3862
3927
  });
3863
- return React36.createElement(
3928
+ return React38.createElement(
3864
3929
  "div",
3865
3930
  { style: containerStyle },
3866
- showHeader ? React36.createElement(
3931
+ showHeader ? React38.createElement(
3867
3932
  "div",
3868
3933
  { style: headerStyle },
3869
- React36.createElement("span", null, showFilename ? filename : null),
3870
- enableCopy ? React36.createElement(
3934
+ React38.createElement("span", null, showFilename ? filename : null),
3935
+ enableCopy ? React38.createElement(
3871
3936
  "button",
3872
3937
  {
3873
3938
  type: "button",
@@ -3886,29 +3951,29 @@ function DocsCodeBlock(props = {}) {
3886
3951
  copied ? "Copied" : "Copy"
3887
3952
  ) : null
3888
3953
  ) : null,
3889
- React36.createElement(
3954
+ React38.createElement(
3890
3955
  "pre",
3891
3956
  { ...preRest, className: preClassName, style: mergedPreStyle },
3892
- React36.createElement("code", { style: codeStyle }, lineElements)
3957
+ React38.createElement("code", { style: codeStyle }, lineElements)
3893
3958
  )
3894
3959
  );
3895
3960
  }
3896
3961
 
3897
3962
  // ui/src/docs/MarkdownTable.jsx
3898
- import React37 from "react";
3963
+ import React39 from "react";
3899
3964
  function MarkdownTable({ className = "", ...rest }) {
3900
3965
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
3901
- return /* @__PURE__ */ React37.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React37.createElement("table", { className: merged, ...rest }));
3966
+ return /* @__PURE__ */ React39.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React39.createElement("table", { className: merged, ...rest }));
3902
3967
  }
3903
3968
 
3904
3969
  // ui/src/docs/Diagram.jsx
3905
- import React38 from "react";
3970
+ import React40 from "react";
3906
3971
  function CanopyDiagram() {
3907
- return /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React38.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Collection A"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React38.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React38.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Collection B"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React38.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React38.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React38.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Automated content"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React38.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React38.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React38.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React38.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Search index"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React38.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React38.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React38.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React38.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__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Work pages"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React38.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React38.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React38.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React38.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React38.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React38.createElement("li", null, "Optional annotation dataset"))))));
3972
+ return /* @__PURE__ */ React40.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React40.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React40.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React40.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Collection A"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React40.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React40.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Collection B"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React40.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React40.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React40.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React40.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React40.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Automated content"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React40.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React40.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React40.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React40.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Search index"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React40.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React40.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React40.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React40.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React40.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React40.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__ */ React40.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Work pages"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React40.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React40.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React40.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React40.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React40.createElement("article", null, /* @__PURE__ */ React40.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React40.createElement("ul", null, /* @__PURE__ */ React40.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React40.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React40.createElement("li", null, "Optional annotation dataset"))))));
3908
3973
  }
3909
3974
 
3910
3975
  // ui/src/docs/ThemeShowcase.jsx
3911
- import React39 from "react";
3976
+ import React41 from "react";
3912
3977
 
3913
3978
  // ../../node_modules/@radix-ui/colors/index.mjs
3914
3979
  var colors_exports = {};
@@ -7741,21 +7806,21 @@ var ACCENT_COLOR_NAMES = [
7741
7806
  "sky"
7742
7807
  ];
7743
7808
  var GRAY_COLOR_NAMES = ["gray", "mauve", "slate", "sage", "olive", "sand"];
7744
- var Section = ({ title, description, children }) => /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React39.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React39.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
7745
- var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React39.createElement("strong", null, label)), /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React39.createElement(
7809
+ var Section = ({ title, description, children }) => /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React41.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
7810
+ var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React41.createElement("strong", null, label)), /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React41.createElement(
7746
7811
  "div",
7747
7812
  {
7748
7813
  key: `${label}-${stop}`,
7749
7814
  className: "canopy-theme-showcase__scale-stop"
7750
7815
  },
7751
- /* @__PURE__ */ React39.createElement(
7816
+ /* @__PURE__ */ React41.createElement(
7752
7817
  "span",
7753
7818
  {
7754
7819
  className: "canopy-theme-showcase__scale-chip",
7755
7820
  style: { backgroundColor: `var(${prefix}-${stop})` }
7756
7821
  }
7757
7822
  ),
7758
- /* @__PURE__ */ React39.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
7823
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
7759
7824
  ))));
7760
7825
  function ThemeShowcase() {
7761
7826
  const accentColors = ACCENT_COLOR_NAMES;
@@ -7766,15 +7831,15 @@ function ThemeShowcase() {
7766
7831
  if (!scale) return null;
7767
7832
  return scale[`${name}9`] || Object.values(scale)[8];
7768
7833
  };
7769
- const ColorsLabeled = ({ colors }) => /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
7834
+ const ColorsLabeled = ({ colors }) => /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
7770
7835
  const colorValue = getRadixSwatch(name);
7771
- return /* @__PURE__ */ React39.createElement("div", { key: name, className: "canopy-theme-showcase__swatch" }, /* @__PURE__ */ React39.createElement(
7836
+ return /* @__PURE__ */ React41.createElement("div", { key: name, className: "canopy-theme-showcase__swatch" }, /* @__PURE__ */ React41.createElement(
7772
7837
  "div",
7773
7838
  {
7774
7839
  className: "canopy-theme-showcase__swatch-chip",
7775
7840
  style: { background: colorValue || "var(--color-gray-200)" }
7776
7841
  }
7777
- ), /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase__swatch-label" }, name));
7842
+ ), /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase__swatch-label" }, name));
7778
7843
  }));
7779
7844
  const styles = `
7780
7845
  .canopy-theme-showcase__section {
@@ -7858,13 +7923,13 @@ function ThemeShowcase() {
7858
7923
  font-weight: 300;
7859
7924
  }
7860
7925
  `;
7861
- return /* @__PURE__ */ React39.createElement("div", { className: "canopy-theme-showcase" }, /* @__PURE__ */ React39.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React39.createElement(
7926
+ return /* @__PURE__ */ React41.createElement("div", { className: "canopy-theme-showcase" }, /* @__PURE__ */ React41.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React41.createElement(
7862
7927
  Section,
7863
7928
  {
7864
7929
  title: "Color scales",
7865
7930
  description: "Accent and gray ramps from the active theme."
7866
7931
  },
7867
- /* @__PURE__ */ React39.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React39.createElement(
7932
+ /* @__PURE__ */ React41.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React41.createElement(
7868
7933
  ColorScaleRow,
7869
7934
  {
7870
7935
  key: scale.label,
@@ -7872,20 +7937,20 @@ function ThemeShowcase() {
7872
7937
  prefix: scale.prefix
7873
7938
  }
7874
7939
  )))
7875
- ), /* @__PURE__ */ React39.createElement(
7940
+ ), /* @__PURE__ */ React41.createElement(
7876
7941
  Section,
7877
7942
  {
7878
7943
  title: "Accent color palette options",
7879
7944
  description: "Primary color steps used for buttons, links, and highlights."
7880
7945
  },
7881
- /* @__PURE__ */ React39.createElement(ColorsLabeled, { colors: accentColors })
7882
- ), /* @__PURE__ */ React39.createElement(
7946
+ /* @__PURE__ */ React41.createElement(ColorsLabeled, { colors: accentColors })
7947
+ ), /* @__PURE__ */ React41.createElement(
7883
7948
  Section,
7884
7949
  {
7885
7950
  title: "Gray color palette options",
7886
7951
  description: "Neutral color steps used for backgrounds, borders, and text."
7887
7952
  },
7888
- /* @__PURE__ */ React39.createElement(ColorsLabeled, { colors: grayColors })
7953
+ /* @__PURE__ */ React41.createElement(ColorsLabeled, { colors: grayColors })
7889
7954
  ));
7890
7955
  }
7891
7956
  export {