@canopy-iiif/app 1.4.10 → 1.4.12

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.
package/ui/dist/index.mjs CHANGED
@@ -1554,8 +1554,14 @@ var Image = (props = {}) => {
1554
1554
  return /* @__PURE__ */ React21.createElement(CloverImage, { ...props, className: rootClassName });
1555
1555
  };
1556
1556
 
1557
- // ui/src/iiif/MdxRelatedItems.jsx
1557
+ // ui/src/iiif/Properties/Id.jsx
1558
1558
  import React22 from "react";
1559
+ function Id({ title = "IIIF Manifest", id, ...props }) {
1560
+ return /* @__PURE__ */ React22.createElement("dl", null, /* @__PURE__ */ React22.createElement("dt", null, title), /* @__PURE__ */ React22.createElement("dd", null, /* @__PURE__ */ React22.createElement("a", { href: id }, id)));
1561
+ }
1562
+
1563
+ // ui/src/iiif/MdxRelatedItems.jsx
1564
+ import React23 from "react";
1559
1565
  function MdxRelatedItems(props) {
1560
1566
  let json = "{}";
1561
1567
  try {
@@ -1563,7 +1569,7 @@ function MdxRelatedItems(props) {
1563
1569
  } catch (_) {
1564
1570
  json = "{}";
1565
1571
  }
1566
- return /* @__PURE__ */ React22.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React22.createElement(
1572
+ return /* @__PURE__ */ React23.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React23.createElement(
1567
1573
  "script",
1568
1574
  {
1569
1575
  type: "application/json",
@@ -1573,7 +1579,7 @@ function MdxRelatedItems(props) {
1573
1579
  }
1574
1580
 
1575
1581
  // ui/src/search/MdxSearchResults.jsx
1576
- import React23 from "react";
1582
+ import React24 from "react";
1577
1583
  function MdxSearchResults(props) {
1578
1584
  let json = "{}";
1579
1585
  try {
@@ -1581,11 +1587,11 @@ function MdxSearchResults(props) {
1581
1587
  } catch (_) {
1582
1588
  json = "{}";
1583
1589
  }
1584
- return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1590
+ return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1585
1591
  }
1586
1592
 
1587
1593
  // ui/src/search/SearchSummary.jsx
1588
- import React24 from "react";
1594
+ import React25 from "react";
1589
1595
  function SearchSummary(props) {
1590
1596
  let json = "{}";
1591
1597
  try {
@@ -1593,11 +1599,11 @@ function SearchSummary(props) {
1593
1599
  } catch (_) {
1594
1600
  json = "{}";
1595
1601
  }
1596
- return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1602
+ return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1597
1603
  }
1598
1604
 
1599
1605
  // ui/src/search/MdxSearchTabs.jsx
1600
- import React25 from "react";
1606
+ import React26 from "react";
1601
1607
  function MdxSearchTabs(props) {
1602
1608
  let json = "{}";
1603
1609
  try {
@@ -1605,11 +1611,11 @@ function MdxSearchTabs(props) {
1605
1611
  } catch (_) {
1606
1612
  json = "{}";
1607
1613
  }
1608
- return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1614
+ return /* @__PURE__ */ React26.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React26.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1609
1615
  }
1610
1616
 
1611
1617
  // ui/src/search/MdxSearch.jsx
1612
- import React26 from "react";
1618
+ import React27 from "react";
1613
1619
  function MdxSearch(props = {}) {
1614
1620
  const {
1615
1621
  layout,
@@ -1627,15 +1633,15 @@ function MdxSearch(props = {}) {
1627
1633
  resultsPayload.layout = layout;
1628
1634
  }
1629
1635
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
1630
- return /* @__PURE__ */ React26.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React26.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React26.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React26.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
1636
+ return /* @__PURE__ */ React27.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React27.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React27.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React27.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
1631
1637
  }
1632
1638
 
1633
1639
  // ui/src/search/SearchResults.jsx
1634
- import React27 from "react";
1640
+ import React28 from "react";
1635
1641
  function DefaultArticleTemplate({ record, query }) {
1636
1642
  if (!record) return null;
1637
1643
  const metadata = Array.isArray(record.metadata) ? record.metadata : [];
1638
- return /* @__PURE__ */ React27.createElement(
1644
+ return /* @__PURE__ */ React28.createElement(
1639
1645
  ArticleCard,
1640
1646
  {
1641
1647
  href: record.href,
@@ -1653,7 +1659,7 @@ function DefaultFigureTemplate({ record, thumbnailAspectRatio }) {
1653
1659
  if (!record) return null;
1654
1660
  const hasDims = Number.isFinite(Number(record.thumbnailWidth)) && Number(record.thumbnailWidth) > 0 && Number.isFinite(Number(record.thumbnailHeight)) && Number(record.thumbnailHeight) > 0;
1655
1661
  const aspect = Number.isFinite(Number(thumbnailAspectRatio)) && Number(thumbnailAspectRatio) > 0 ? Number(thumbnailAspectRatio) : hasDims ? Number(record.thumbnailWidth) / Number(record.thumbnailHeight) : void 0;
1656
- return /* @__PURE__ */ React27.createElement(
1662
+ return /* @__PURE__ */ React28.createElement(
1657
1663
  Card,
1658
1664
  {
1659
1665
  href: record.href,
@@ -1674,7 +1680,7 @@ function SearchResults({
1674
1680
  variant = "auto"
1675
1681
  }) {
1676
1682
  if (!results.length) {
1677
- return /* @__PURE__ */ React27.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React27.createElement("em", null, "No results"));
1683
+ return /* @__PURE__ */ React28.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React28.createElement("em", null, "No results"));
1678
1684
  }
1679
1685
  const normalizedType = String(type || "all").toLowerCase();
1680
1686
  const normalizedVariant = variant === "figure" || variant === "article" ? variant : "auto";
@@ -1682,9 +1688,9 @@ function SearchResults({
1682
1688
  const FigureTemplate = templates && templates.figure ? templates.figure : DefaultFigureTemplate;
1683
1689
  const ArticleTemplate = templates && templates.article ? templates.article : DefaultArticleTemplate;
1684
1690
  if (isAnnotationView) {
1685
- return /* @__PURE__ */ React27.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1691
+ return /* @__PURE__ */ React28.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1686
1692
  if (!r) return null;
1687
- return /* @__PURE__ */ React27.createElement(
1693
+ return /* @__PURE__ */ React28.createElement(
1688
1694
  ArticleTemplate,
1689
1695
  {
1690
1696
  key: r.id || i,
@@ -1702,20 +1708,20 @@ function SearchResults({
1702
1708
  return !isWorkRecord(record) || normalizedType !== "work";
1703
1709
  };
1704
1710
  if (layout === "list") {
1705
- return /* @__PURE__ */ React27.createElement("div", { id: "search-results", className: "space-y-6" }, results.map((r, i) => {
1711
+ return /* @__PURE__ */ React28.createElement("div", { id: "search-results", className: "space-y-6" }, results.map((r, i) => {
1706
1712
  if (shouldRenderAsArticle(r)) {
1707
- return /* @__PURE__ */ React27.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React27.createElement(ArticleTemplate, { record: r, query, layout }));
1713
+ return /* @__PURE__ */ React28.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React28.createElement(ArticleTemplate, { record: r, query, layout }));
1708
1714
  }
1709
1715
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1710
1716
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1711
- return /* @__PURE__ */ React27.createElement(
1717
+ return /* @__PURE__ */ React28.createElement(
1712
1718
  "div",
1713
1719
  {
1714
1720
  key: i,
1715
1721
  className: `search-result ${r.type}`,
1716
1722
  "data-thumbnail-aspect-ratio": aspect
1717
1723
  },
1718
- /* @__PURE__ */ React27.createElement(
1724
+ /* @__PURE__ */ React28.createElement(
1719
1725
  FigureTemplate,
1720
1726
  {
1721
1727
  record: r,
@@ -1727,20 +1733,20 @@ function SearchResults({
1727
1733
  );
1728
1734
  }));
1729
1735
  }
1730
- return /* @__PURE__ */ React27.createElement("div", { id: "search-results" }, /* @__PURE__ */ React27.createElement(Grid, null, results.map((r, i) => {
1736
+ return /* @__PURE__ */ React28.createElement("div", { id: "search-results" }, /* @__PURE__ */ React28.createElement(Grid, null, results.map((r, i) => {
1731
1737
  if (shouldRenderAsArticle(r)) {
1732
- return /* @__PURE__ */ React27.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React27.createElement(ArticleTemplate, { record: r, query, layout }));
1738
+ return /* @__PURE__ */ React28.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React28.createElement(ArticleTemplate, { record: r, query, layout }));
1733
1739
  }
1734
1740
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1735
1741
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1736
- return /* @__PURE__ */ React27.createElement(
1742
+ return /* @__PURE__ */ React28.createElement(
1737
1743
  GridItem,
1738
1744
  {
1739
1745
  key: i,
1740
1746
  className: `search-result ${r.type}`,
1741
1747
  "data-thumbnail-aspect-ratio": aspect
1742
1748
  },
1743
- /* @__PURE__ */ React27.createElement(
1749
+ /* @__PURE__ */ React28.createElement(
1744
1750
  FigureTemplate,
1745
1751
  {
1746
1752
  record: r,
@@ -1754,7 +1760,7 @@ function SearchResults({
1754
1760
  }
1755
1761
 
1756
1762
  // ui/src/search/SearchTabs.jsx
1757
- import React28, { useRef as useRef2, useState as useState6, useEffect as useEffect6 } from "react";
1763
+ import React29, { useRef as useRef2, useState as useState6, useEffect as useEffect6 } from "react";
1758
1764
  function SearchTabs({
1759
1765
  type = "all",
1760
1766
  onTypeChange,
@@ -1808,7 +1814,7 @@ function SearchTabs({
1808
1814
  width: `${itemBoundingBox.width}px`
1809
1815
  };
1810
1816
  }
1811
- return /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React28.createElement(
1817
+ return /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React29.createElement(
1812
1818
  "div",
1813
1819
  {
1814
1820
  role: "tablist",
@@ -1817,7 +1823,7 @@ function SearchTabs({
1817
1823
  ref: wrapperRef,
1818
1824
  onMouseLeave: resetHighlight
1819
1825
  },
1820
- /* @__PURE__ */ React28.createElement(
1826
+ /* @__PURE__ */ React29.createElement(
1821
1827
  "div",
1822
1828
  {
1823
1829
  ref: highlightRef,
@@ -1829,7 +1835,7 @@ function SearchTabs({
1829
1835
  const active = String(type).toLowerCase() === String(t).toLowerCase();
1830
1836
  const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
1831
1837
  const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
1832
- return /* @__PURE__ */ React28.createElement(
1838
+ return /* @__PURE__ */ React29.createElement(
1833
1839
  "button",
1834
1840
  {
1835
1841
  key: t,
@@ -1847,7 +1853,7 @@ function SearchTabs({
1847
1853
  ")"
1848
1854
  );
1849
1855
  })
1850
- ), hasFilters ? /* @__PURE__ */ React28.createElement(
1856
+ ), hasFilters ? /* @__PURE__ */ React29.createElement(
1851
1857
  "button",
1852
1858
  {
1853
1859
  type: "button",
@@ -1855,12 +1861,12 @@ function SearchTabs({
1855
1861
  "aria-expanded": filtersOpen ? "true" : "false",
1856
1862
  className: "inline-flex items-center gap-2 rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm font-medium text-slate-700 shadow-sm transition hover:border-brand-200 hover:bg-brand-50 hover:text-brand-700"
1857
1863
  },
1858
- /* @__PURE__ */ React28.createElement("span", null, filtersLabel, filterBadge)
1864
+ /* @__PURE__ */ React29.createElement("span", null, filtersLabel, filterBadge)
1859
1865
  ) : null);
1860
1866
  }
1861
1867
 
1862
1868
  // ui/src/search/SearchFiltersDialog.jsx
1863
- import React29 from "react";
1869
+ import React30 from "react";
1864
1870
  function toArray(input) {
1865
1871
  if (!input) return [];
1866
1872
  if (Array.isArray(input)) return input;
@@ -1899,20 +1905,20 @@ function FacetSection({ facet, selected, onToggle }) {
1899
1905
  const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
1900
1906
  const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
1901
1907
  const hasSelection = selectedValues.size > 0;
1902
- const [quickQuery, setQuickQuery] = React29.useState("");
1908
+ const [quickQuery, setQuickQuery] = React30.useState("");
1903
1909
  const hasQuery = quickQuery.trim().length > 0;
1904
- const filteredValues = React29.useMemo(
1910
+ const filteredValues = React30.useMemo(
1905
1911
  () => facetMatches(values, quickQuery),
1906
1912
  [values, quickQuery]
1907
1913
  );
1908
- return /* @__PURE__ */ React29.createElement(
1914
+ return /* @__PURE__ */ React30.createElement(
1909
1915
  "details",
1910
1916
  {
1911
1917
  className: "canopy-search-filters__facet",
1912
1918
  open: hasSelection
1913
1919
  },
1914
- /* @__PURE__ */ React29.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React29.createElement("span", null, label), /* @__PURE__ */ React29.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
1915
- /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React29.createElement(
1920
+ /* @__PURE__ */ React30.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React30.createElement("span", null, label), /* @__PURE__ */ React30.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
1921
+ /* @__PURE__ */ React30.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React30.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React30.createElement(
1916
1922
  "input",
1917
1923
  {
1918
1924
  type: "search",
@@ -1922,7 +1928,7 @@ function FacetSection({ facet, selected, onToggle }) {
1922
1928
  className: "canopy-search-filters__quick-input",
1923
1929
  "aria-label": `Filter ${label} values`
1924
1930
  }
1925
- ), quickQuery ? /* @__PURE__ */ React29.createElement(
1931
+ ), quickQuery ? /* @__PURE__ */ React30.createElement(
1926
1932
  "button",
1927
1933
  {
1928
1934
  type: "button",
@@ -1930,11 +1936,11 @@ function FacetSection({ facet, selected, onToggle }) {
1930
1936
  className: "canopy-search-filters__quick-clear"
1931
1937
  },
1932
1938
  "Clear"
1933
- ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React29.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React29.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
1939
+ ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React30.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React30.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
1934
1940
  const valueSlug = String(entry.slug || entry.value || "");
1935
1941
  const isChecked = selectedValues.has(valueSlug);
1936
1942
  const inputId = checkboxId(valueSlug);
1937
- return /* @__PURE__ */ React29.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React29.createElement(
1943
+ return /* @__PURE__ */ React30.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React30.createElement(
1938
1944
  "input",
1939
1945
  {
1940
1946
  id: inputId,
@@ -1946,15 +1952,15 @@ function FacetSection({ facet, selected, onToggle }) {
1946
1952
  if (onToggle) onToggle(slug, valueSlug, nextChecked);
1947
1953
  }
1948
1954
  }
1949
- ), /* @__PURE__ */ React29.createElement(
1955
+ ), /* @__PURE__ */ React30.createElement(
1950
1956
  "label",
1951
1957
  {
1952
1958
  htmlFor: inputId,
1953
1959
  className: "canopy-search-filters__facet-label"
1954
1960
  },
1955
- /* @__PURE__ */ React29.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React29.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
1961
+ /* @__PURE__ */ React30.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React30.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
1956
1962
  ));
1957
- }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React29.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1963
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React30.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1958
1964
  );
1959
1965
  }
1960
1966
  function SearchFiltersDialog(props = {}) {
@@ -1976,7 +1982,7 @@ function SearchFiltersDialog(props = {}) {
1976
1982
  (total, set) => total + set.size,
1977
1983
  0
1978
1984
  );
1979
- React29.useEffect(() => {
1985
+ React30.useEffect(() => {
1980
1986
  if (!open) return void 0;
1981
1987
  if (typeof document === "undefined") return void 0;
1982
1988
  const body = document.body;
@@ -1993,7 +1999,7 @@ function SearchFiltersDialog(props = {}) {
1993
1999
  if (!open) return null;
1994
2000
  const brandId = "canopy-modal-filters-label";
1995
2001
  const subtitleText = subtitle != null ? subtitle : title;
1996
- return /* @__PURE__ */ React29.createElement(
2002
+ return /* @__PURE__ */ React30.createElement(
1997
2003
  CanopyModal,
1998
2004
  {
1999
2005
  id: "canopy-modal-filters",
@@ -2008,8 +2014,8 @@ function SearchFiltersDialog(props = {}) {
2008
2014
  onBackgroundClick: () => onOpenChange && onOpenChange(false),
2009
2015
  bodyClassName: "canopy-modal__body--filters"
2010
2016
  },
2011
- subtitleText ? /* @__PURE__ */ React29.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
2012
- /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React29.createElement(
2017
+ subtitleText ? /* @__PURE__ */ React30.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
2018
+ /* @__PURE__ */ React30.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React30.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React30.createElement(
2013
2019
  FacetSection,
2014
2020
  {
2015
2021
  key: facet.slug || facet.label,
@@ -2017,8 +2023,8 @@ function SearchFiltersDialog(props = {}) {
2017
2023
  selected: selectedMap,
2018
2024
  onToggle
2019
2025
  }
2020
- ))) : /* @__PURE__ */ React29.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
2021
- /* @__PURE__ */ React29.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React29.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React29.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React29.createElement(
2026
+ ))) : /* @__PURE__ */ React30.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
2027
+ /* @__PURE__ */ React30.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React30.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React30.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React30.createElement(
2022
2028
  "button",
2023
2029
  {
2024
2030
  type: "button",
@@ -2029,7 +2035,7 @@ function SearchFiltersDialog(props = {}) {
2029
2035
  className: "canopy-search-filters__button canopy-search-filters__button--secondary"
2030
2036
  },
2031
2037
  "Clear all"
2032
- ), /* @__PURE__ */ React29.createElement(
2038
+ ), /* @__PURE__ */ React30.createElement(
2033
2039
  "button",
2034
2040
  {
2035
2041
  type: "button",
@@ -2042,7 +2048,7 @@ function SearchFiltersDialog(props = {}) {
2042
2048
  }
2043
2049
 
2044
2050
  // ui/src/search-form/MdxSearchFormModal.jsx
2045
- import React30 from "react";
2051
+ import React31 from "react";
2046
2052
  function MdxSearchFormModal(props = {}) {
2047
2053
  const {
2048
2054
  placeholder = "Search\u2026",
@@ -2058,24 +2064,24 @@ function MdxSearchFormModal(props = {}) {
2058
2064
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
2059
2065
  const resolvedSearchPath = resolveSearchPath(searchPath);
2060
2066
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
2061
- return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React30.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React30.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React30.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2067
+ return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React31.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React31.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React31.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2062
2068
  }
2063
2069
 
2064
2070
  // ui/src/docs/MarkdownTable.jsx
2065
- import React31 from "react";
2071
+ import React32 from "react";
2066
2072
  function MarkdownTable({ className = "", ...rest }) {
2067
2073
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
2068
- return /* @__PURE__ */ React31.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React31.createElement("table", { className: merged, ...rest }));
2074
+ return /* @__PURE__ */ React32.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React32.createElement("table", { className: merged, ...rest }));
2069
2075
  }
2070
2076
 
2071
2077
  // ui/src/docs/Diagram.jsx
2072
- import React32 from "react";
2078
+ import React33 from "react";
2073
2079
  function CanopyDiagram() {
2074
- return /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React32.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Collection A"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React32.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React32.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Collection B"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React32.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React32.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React32.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Automated content"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React32.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React32.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React32.createElement("li", null, "Author narratives"), /* @__PURE__ */ React32.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Search index"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React32.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React32.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React32.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React32.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__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Work pages"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React32.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React32.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React32.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React32.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React32.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React32.createElement("li", null, "Optional annotation dataset"))))));
2080
+ return /* @__PURE__ */ React33.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React33.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React33.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React33.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Collection A"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React33.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React33.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Collection B"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React33.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React33.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React33.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React33.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React33.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React33.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Automated content"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React33.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React33.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React33.createElement("li", null, "Author narratives"), /* @__PURE__ */ React33.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Search index"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React33.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React33.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React33.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React33.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React33.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React33.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React33.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__ */ React33.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Work pages"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React33.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React33.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React33.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React33.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React33.createElement("article", null, /* @__PURE__ */ React33.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React33.createElement("ul", null, /* @__PURE__ */ React33.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React33.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React33.createElement("li", null, "Optional annotation dataset"))))));
2075
2081
  }
2076
2082
 
2077
2083
  // ui/src/content/timeline/Timeline.jsx
2078
- import React34 from "react";
2084
+ import React35 from "react";
2079
2085
 
2080
2086
  // ui/src/content/timeline/date-utils.js
2081
2087
  var FALLBACK_LOCALE = (() => {
@@ -2228,7 +2234,7 @@ function clampProgress(value) {
2228
2234
  }
2229
2235
 
2230
2236
  // ui/src/layout/ReferencedManifestCard.jsx
2231
- import React33 from "react";
2237
+ import React34 from "react";
2232
2238
  function normalizeMetadata(metadata, summary) {
2233
2239
  if (Array.isArray(metadata) && metadata.length) {
2234
2240
  return metadata.filter(Boolean);
@@ -2262,7 +2268,7 @@ function ReferencedManifestCard({
2262
2268
  "canopy-referenced-manifest-card",
2263
2269
  className
2264
2270
  ].filter(Boolean).join(" ");
2265
- return /* @__PURE__ */ React33.createElement(
2271
+ return /* @__PURE__ */ React34.createElement(
2266
2272
  TeaserCard,
2267
2273
  {
2268
2274
  href: resolvedHref || void 0,
@@ -2444,14 +2450,14 @@ function TimelineConnector({ side, isActive, highlight }) {
2444
2450
  "canopy-timeline__connector-dot",
2445
2451
  highlight || isActive ? "is-active" : ""
2446
2452
  ].filter(Boolean).join(" ");
2447
- return /* @__PURE__ */ React34.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React34.createElement(React34.Fragment, null, /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React34.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React34.createElement(React34.Fragment, null, /* @__PURE__ */ React34.createElement("span", { className: dotClasses }), /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__connector-line" })));
2453
+ 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" })));
2448
2454
  }
2449
2455
  function renderResourceSection(point) {
2450
2456
  if (!point) return null;
2451
2457
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
2452
2458
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2453
2459
  if (!manifestCards.length && !legacyResources.length) return null;
2454
- return /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React34.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React34.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React34.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React34.createElement(
2460
+ 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(
2455
2461
  TeaserCard,
2456
2462
  {
2457
2463
  href: resource.href,
@@ -2476,26 +2482,26 @@ function Timeline({
2476
2482
  ...rest
2477
2483
  }) {
2478
2484
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
2479
- const rawPoints = React34.useMemo(() => {
2485
+ const rawPoints = React35.useMemo(() => {
2480
2486
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
2481
2487
  if (payloadPoints && payloadPoints.length) return payloadPoints;
2482
2488
  return [];
2483
2489
  }, [pointsProp, payloadPoints]);
2484
- const sanitizedPoints = React34.useMemo(
2490
+ const sanitizedPoints = React35.useMemo(
2485
2491
  () => sanitizePoints(rawPoints),
2486
2492
  [rawPoints]
2487
2493
  );
2488
2494
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
2489
- const baseLocale = React34.useMemo(
2495
+ const baseLocale = React35.useMemo(
2490
2496
  () => createLocale(localeValue),
2491
2497
  [localeValue]
2492
2498
  );
2493
2499
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
2494
- const rangeOverrides = React34.useMemo(
2500
+ const rangeOverrides = React35.useMemo(
2495
2501
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
2496
2502
  [sanitizedPoints, rangeInput]
2497
2503
  );
2498
- const effectiveRange = React34.useMemo(
2504
+ const effectiveRange = React35.useMemo(
2499
2505
  () => normalizeRange({
2500
2506
  ...rangeOverrides,
2501
2507
  locale: baseLocale
@@ -2504,7 +2510,7 @@ function Timeline({
2504
2510
  );
2505
2511
  const spanStart = effectiveRange.startDate.getTime();
2506
2512
  const span = effectiveRange.span;
2507
- const pointsWithPosition = React34.useMemo(() => {
2513
+ const pointsWithPosition = React35.useMemo(() => {
2508
2514
  if (!sanitizedPoints.length) return [];
2509
2515
  return sanitizedPoints.map((point, index) => {
2510
2516
  const timestamp = point.meta.timestamp;
@@ -2518,29 +2524,29 @@ function Timeline({
2518
2524
  };
2519
2525
  });
2520
2526
  }, [sanitizedPoints, spanStart, span]);
2521
- const [activeId, setActiveId] = React34.useState(
2527
+ const [activeId, setActiveId] = React35.useState(
2522
2528
  () => getActivePointId(pointsWithPosition)
2523
2529
  );
2524
- React34.useEffect(() => {
2530
+ React35.useEffect(() => {
2525
2531
  setActiveId(getActivePointId(pointsWithPosition));
2526
2532
  }, [pointsWithPosition]);
2527
2533
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
2528
2534
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
2529
- const thresholdMs = React34.useMemo(
2535
+ const thresholdMs = React35.useMemo(
2530
2536
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
2531
2537
  [thresholdValue, effectiveRange.granularity]
2532
2538
  );
2533
- const groupedEntries = React34.useMemo(
2539
+ const groupedEntries = React35.useMemo(
2534
2540
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
2535
2541
  granularity: effectiveRange.granularity,
2536
2542
  locale: baseLocale
2537
2543
  }),
2538
2544
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
2539
2545
  );
2540
- const [expandedGroupIds, setExpandedGroupIds] = React34.useState(
2546
+ const [expandedGroupIds, setExpandedGroupIds] = React35.useState(
2541
2547
  () => /* @__PURE__ */ new Set()
2542
2548
  );
2543
- React34.useEffect(() => {
2549
+ React35.useEffect(() => {
2544
2550
  setExpandedGroupIds((prev) => {
2545
2551
  if (!prev || prev.size === 0) return prev;
2546
2552
  const validIds = new Set(
@@ -2555,7 +2561,7 @@ function Timeline({
2555
2561
  return changed ? next : prev;
2556
2562
  });
2557
2563
  }, [groupedEntries]);
2558
- const toggleGroup = React34.useCallback((groupId) => {
2564
+ const toggleGroup = React35.useCallback((groupId) => {
2559
2565
  setExpandedGroupIds((prev) => {
2560
2566
  const next = new Set(prev || []);
2561
2567
  if (next.has(groupId)) next.delete(groupId);
@@ -2578,7 +2584,7 @@ function Timeline({
2578
2584
  point.id === activeId ? "is-active" : "",
2579
2585
  point.highlight ? "is-highlighted" : ""
2580
2586
  ].filter(Boolean).join(" ");
2581
- const connector = /* @__PURE__ */ React34.createElement(
2587
+ const connector = /* @__PURE__ */ React35.createElement(
2582
2588
  TimelineConnector,
2583
2589
  {
2584
2590
  side: point.side,
@@ -2586,9 +2592,9 @@ function Timeline({
2586
2592
  highlight: point.highlight
2587
2593
  }
2588
2594
  );
2589
- const body = /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2595
+ 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);
2590
2596
  const resourceSection = renderResourceSection(point);
2591
- return /* @__PURE__ */ React34.createElement(
2597
+ return /* @__PURE__ */ React35.createElement(
2592
2598
  "div",
2593
2599
  {
2594
2600
  key: point.id,
@@ -2596,7 +2602,7 @@ function Timeline({
2596
2602
  style: wrapperStyle,
2597
2603
  role: "listitem"
2598
2604
  },
2599
- point.side === "left" ? /* @__PURE__ */ React34.createElement(React34.Fragment, null, /* @__PURE__ */ React34.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React34.createElement(React34.Fragment, null, connector, /* @__PURE__ */ React34.createElement("div", { className: cardClasses }, body, resourceSection))
2605
+ 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))
2600
2606
  );
2601
2607
  }
2602
2608
  function renderGroupEntry(entry) {
@@ -2607,7 +2613,7 @@ function Timeline({
2607
2613
  const wrapperStyle = { top: `${entry.progress * 100}%` };
2608
2614
  const isExpanded = expandedGroupIds.has(entry.id);
2609
2615
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
2610
- const connector = /* @__PURE__ */ React34.createElement(
2616
+ const connector = /* @__PURE__ */ React35.createElement(
2611
2617
  TimelineConnector,
2612
2618
  {
2613
2619
  side: entry.side,
@@ -2621,7 +2627,7 @@ function Timeline({
2621
2627
  hasActivePoint ? "is-active" : ""
2622
2628
  ].filter(Boolean).join(" ");
2623
2629
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
2624
- const header = /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React34.createElement(
2630
+ 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(
2625
2631
  "button",
2626
2632
  {
2627
2633
  type: "button",
@@ -2631,7 +2637,7 @@ function Timeline({
2631
2637
  },
2632
2638
  isExpanded ? "Hide details" : "Show details"
2633
2639
  ));
2634
- const groupPoints = isExpanded ? /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React34.createElement(
2640
+ const groupPoints = isExpanded ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React35.createElement(
2635
2641
  "button",
2636
2642
  {
2637
2643
  key: point.id,
@@ -2642,11 +2648,11 @@ function Timeline({
2642
2648
  ].filter(Boolean).join(" "),
2643
2649
  onClick: () => setActiveId(point.id)
2644
2650
  },
2645
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2646
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2651
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2652
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2647
2653
  ))) : null;
2648
- const groupCard = /* @__PURE__ */ React34.createElement("div", { className: groupClasses }, header, groupPoints);
2649
- return /* @__PURE__ */ React34.createElement(
2654
+ const groupCard = /* @__PURE__ */ React35.createElement("div", { className: groupClasses }, header, groupPoints);
2655
+ return /* @__PURE__ */ React35.createElement(
2650
2656
  "div",
2651
2657
  {
2652
2658
  key: entry.id,
@@ -2654,17 +2660,17 @@ function Timeline({
2654
2660
  style: wrapperStyle,
2655
2661
  role: "listitem"
2656
2662
  },
2657
- entry.side === "left" ? /* @__PURE__ */ React34.createElement(React34.Fragment, null, groupCard, connector) : /* @__PURE__ */ React34.createElement(React34.Fragment, null, connector, groupCard)
2663
+ entry.side === "left" ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, groupCard, connector) : /* @__PURE__ */ React35.createElement(React35.Fragment, null, connector, groupCard)
2658
2664
  );
2659
2665
  }
2660
- return /* @__PURE__ */ React34.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React34.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React34.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React34.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React34.createElement(
2666
+ 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(
2661
2667
  "div",
2662
2668
  {
2663
2669
  className: "canopy-timeline__list",
2664
2670
  role: "list",
2665
2671
  style: { minHeight: trackHeight }
2666
2672
  },
2667
- /* @__PURE__ */ React34.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2673
+ /* @__PURE__ */ React35.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2668
2674
  renderSteps(stepsValue, effectiveRange),
2669
2675
  groupedEntries.map((entry) => {
2670
2676
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -2679,7 +2685,7 @@ function renderSteps(stepSize, range) {
2679
2685
  const markers = [];
2680
2686
  if (startYear < endYear) {
2681
2687
  markers.push(
2682
- /* @__PURE__ */ React34.createElement(
2688
+ /* @__PURE__ */ React35.createElement(
2683
2689
  "span",
2684
2690
  {
2685
2691
  key: "timeline-step-start",
@@ -2687,12 +2693,12 @@ function renderSteps(stepSize, range) {
2687
2693
  style: { top: "0%" },
2688
2694
  "aria-hidden": "true"
2689
2695
  },
2690
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-line" }),
2691
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
2696
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
2697
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
2692
2698
  )
2693
2699
  );
2694
2700
  markers.push(
2695
- /* @__PURE__ */ React34.createElement(
2701
+ /* @__PURE__ */ React35.createElement(
2696
2702
  "span",
2697
2703
  {
2698
2704
  key: "timeline-step-end",
@@ -2700,8 +2706,8 @@ function renderSteps(stepSize, range) {
2700
2706
  style: { top: "100%" },
2701
2707
  "aria-hidden": "true"
2702
2708
  },
2703
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-line" }),
2704
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
2709
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
2710
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
2705
2711
  )
2706
2712
  );
2707
2713
  }
@@ -2711,7 +2717,7 @@ function renderSteps(stepSize, range) {
2711
2717
  const progress = (timestamp - range.startDate.getTime()) / range.span;
2712
2718
  if (progress <= 0 || progress >= 1) continue;
2713
2719
  markers.push(
2714
- /* @__PURE__ */ React34.createElement(
2720
+ /* @__PURE__ */ React35.createElement(
2715
2721
  "span",
2716
2722
  {
2717
2723
  key: `timeline-step-${year}`,
@@ -2719,8 +2725,8 @@ function renderSteps(stepSize, range) {
2719
2725
  style: { top: `calc(${progress * 100}% - 0.5px)` },
2720
2726
  "aria-hidden": "true"
2721
2727
  },
2722
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-line" }),
2723
- /* @__PURE__ */ React34.createElement("span", { className: "canopy-timeline__step-label" }, year)
2728
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-line" }),
2729
+ /* @__PURE__ */ React35.createElement("span", { className: "canopy-timeline__step-label" }, year)
2724
2730
  )
2725
2731
  );
2726
2732
  }
@@ -2734,7 +2740,7 @@ function TimelinePoint() {
2734
2740
  TimelinePoint.displayName = "TimelinePoint";
2735
2741
 
2736
2742
  // ui/src/content/map/Map.jsx
2737
- import React35 from "react";
2743
+ import React36 from "react";
2738
2744
  import { createRoot } from "react-dom/client";
2739
2745
  var DEFAULT_TILE_LAYERS = [
2740
2746
  {
@@ -3001,7 +3007,7 @@ function MapPopupContent({ marker }) {
3001
3007
  ...manifest,
3002
3008
  href: manifest.href ? withBasePath(manifest.href) : manifest.href || ""
3003
3009
  }));
3004
- return /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__popup" }, thumbnail ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__popup-media" }, /* @__PURE__ */ React35.createElement(
3010
+ return /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__popup" }, thumbnail ? /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__popup-media" }, /* @__PURE__ */ React36.createElement(
3005
3011
  "img",
3006
3012
  {
3007
3013
  src: thumbnail,
@@ -3010,19 +3016,19 @@ function MapPopupContent({ marker }) {
3010
3016
  width: typeof thumbWidth === "number" && thumbWidth > 0 ? thumbWidth : void 0,
3011
3017
  height: typeof thumbHeight === "number" && thumbHeight > 0 ? thumbHeight : void 0
3012
3018
  }
3013
- )) : null, /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__popup-body" }, title ? href ? /* @__PURE__ */ React35.createElement("a", { href, className: "canopy-map__popup-title" }, title) : /* @__PURE__ */ React35.createElement("span", { className: "canopy-map__popup-title" }, title) : null, summary ? /* @__PURE__ */ React35.createElement("p", { className: "canopy-map__popup-summary" }, summary) : null, marker.detailsHtml ? /* @__PURE__ */ React35.createElement(
3019
+ )) : null, /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__popup-body" }, title ? href ? /* @__PURE__ */ React36.createElement("a", { href, className: "canopy-map__popup-title" }, title) : /* @__PURE__ */ React36.createElement("span", { className: "canopy-map__popup-title" }, title) : null, summary ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-map__popup-summary" }, summary) : null, marker.detailsHtml ? /* @__PURE__ */ React36.createElement(
3014
3020
  "div",
3015
3021
  {
3016
3022
  className: "canopy-map__popup-details",
3017
3023
  dangerouslySetInnerHTML: { __html: marker.detailsHtml }
3018
3024
  }
3019
- ) : null, !summary && !marker.detailsHtml && href && !title ? /* @__PURE__ */ React35.createElement("a", { href, className: "canopy-map__popup-link" }, "View item") : null, normalizedManifests.length ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__popup-manifests" }, /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__popup-manifests-list" }, normalizedManifests.map((manifest, index) => /* @__PURE__ */ React35.createElement(
3025
+ ) : null, !summary && !marker.detailsHtml && href && !title ? /* @__PURE__ */ React36.createElement("a", { href, className: "canopy-map__popup-link" }, "View item") : null, normalizedManifests.length ? /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__popup-manifests" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__popup-manifests-list" }, normalizedManifests.map((manifest, index) => /* @__PURE__ */ React36.createElement(
3020
3026
  "div",
3021
3027
  {
3022
3028
  key: manifest.id || manifest.href || `manifest-${index}`,
3023
3029
  className: "canopy-map__popup-manifests-item"
3024
3030
  },
3025
- /* @__PURE__ */ React35.createElement(ReferencedManifestCard, { manifest })
3031
+ /* @__PURE__ */ React36.createElement(ReferencedManifestCard, { manifest })
3026
3032
  )))) : null));
3027
3033
  }
3028
3034
  function renderPopup(marker) {
@@ -3034,7 +3040,7 @@ function renderPopup(marker) {
3034
3040
  if (hadError) return;
3035
3041
  try {
3036
3042
  if (!root) root = createRoot(container);
3037
- root.render(/* @__PURE__ */ React35.createElement(MapPopupContent, { marker }));
3043
+ root.render(/* @__PURE__ */ React36.createElement(MapPopupContent, { marker }));
3038
3044
  } catch (error) {
3039
3045
  hadError = true;
3040
3046
  if (root) {
@@ -3159,26 +3165,26 @@ function Map2({
3159
3165
  defaultCenter = null,
3160
3166
  defaultZoom = null
3161
3167
  } = {}) {
3162
- const containerRef = React35.useRef(null);
3163
- const mapRef = React35.useRef(null);
3164
- const layerRef = React35.useRef(null);
3165
- const [leafletLib, setLeafletLib] = React35.useState(() => resolveGlobalLeaflet());
3166
- const [leafletError, setLeafletError] = React35.useState(null);
3168
+ const containerRef = React36.useRef(null);
3169
+ const mapRef = React36.useRef(null);
3170
+ const layerRef = React36.useRef(null);
3171
+ const [leafletLib, setLeafletLib] = React36.useState(() => resolveGlobalLeaflet());
3172
+ const [leafletError, setLeafletError] = React36.useState(null);
3167
3173
  const datasetInfo = navDataset && typeof navDataset === "object" ? navDataset : null;
3168
3174
  const datasetHref = datasetInfo && datasetInfo.href || "/api/navplace.json";
3169
3175
  const datasetVersion = datasetInfo && datasetInfo.version;
3170
3176
  const datasetHasFeatures = !!(datasetInfo && datasetInfo.hasFeatures);
3171
- const [navState, setNavState] = React35.useState(() => ({
3177
+ const [navState, setNavState] = React36.useState(() => ({
3172
3178
  loading: false,
3173
3179
  error: null,
3174
3180
  markers: []
3175
3181
  }));
3176
- const [iiifTargets, setIiifTargets] = React35.useState(() => ({
3182
+ const [iiifTargets, setIiifTargets] = React36.useState(() => ({
3177
3183
  loading: false,
3178
3184
  error: null,
3179
3185
  keys: []
3180
3186
  }));
3181
- React35.useEffect(() => {
3187
+ React36.useEffect(() => {
3182
3188
  if (!iiifContent) {
3183
3189
  setIiifTargets({ loading: false, error: null, keys: [] });
3184
3190
  return;
@@ -3226,7 +3232,7 @@ function Map2({
3226
3232
  const navTargets = iiifTargets.keys || [];
3227
3233
  const navTargetsKey = navTargets.join("|");
3228
3234
  const shouldFetchNav = datasetHasFeatures && navTargets.length > 0;
3229
- React35.useEffect(() => {
3235
+ React36.useEffect(() => {
3230
3236
  if (!shouldFetchNav) {
3231
3237
  setNavState({ loading: false, error: null, markers: [] });
3232
3238
  return void 0;
@@ -3258,7 +3264,7 @@ function Map2({
3258
3264
  cancelled = true;
3259
3265
  };
3260
3266
  }, [datasetHref, datasetVersion, navTargetsKey, shouldFetchNav]);
3261
- React35.useEffect(() => {
3267
+ React36.useEffect(() => {
3262
3268
  if (leafletLib) return;
3263
3269
  let cancelled = false;
3264
3270
  waitForLeaflet().then((lib) => {
@@ -3270,7 +3276,7 @@ function Map2({
3270
3276
  cancelled = true;
3271
3277
  };
3272
3278
  }, [leafletLib]);
3273
- const navMatchMap = React35.useMemo(() => {
3279
+ const navMatchMap = React36.useMemo(() => {
3274
3280
  const matchMap = createMarkerMap();
3275
3281
  (navState.markers || []).forEach((marker) => {
3276
3282
  if (!marker || !Array.isArray(marker.matchKeys)) return;
@@ -3281,7 +3287,7 @@ function Map2({
3281
3287
  });
3282
3288
  return matchMap;
3283
3289
  }, [navState.markers]);
3284
- const normalizedCustom = React35.useMemo(() => {
3290
+ const normalizedCustom = React36.useMemo(() => {
3285
3291
  return normalizeCustomMarkers(customPoints).map((point) => {
3286
3292
  if (!point || point.thumbnail || !point.href) return point;
3287
3293
  const match = navMatchMap.get(normalizeKey(point.href));
@@ -3296,11 +3302,11 @@ function Map2({
3296
3302
  };
3297
3303
  });
3298
3304
  }, [customPoints, navMatchMap]);
3299
- const allMarkers = React35.useMemo(() => {
3305
+ const allMarkers = React36.useMemo(() => {
3300
3306
  return [...navState.markers || [], ...normalizedCustom];
3301
3307
  }, [navState.markers, normalizedCustom]);
3302
- const clusterOptions = React35.useMemo(() => buildClusterOptions(leafletLib), [leafletLib]);
3303
- React35.useEffect(() => {
3308
+ const clusterOptions = React36.useMemo(() => buildClusterOptions(leafletLib), [leafletLib]);
3309
+ React36.useEffect(() => {
3304
3310
  if (!containerRef.current || mapRef.current || !leafletLib) return void 0;
3305
3311
  const map = leafletLib.map(containerRef.current, {
3306
3312
  zoomControl: true,
@@ -3338,7 +3344,7 @@ function Map2({
3338
3344
  layerRef.current = null;
3339
3345
  };
3340
3346
  }, [tileLayers, scrollWheelZoom, cluster, clusterOptions, leafletLib]);
3341
- React35.useEffect(() => {
3347
+ React36.useEffect(() => {
3342
3348
  const map = mapRef.current;
3343
3349
  const layer = layerRef.current;
3344
3350
  if (!map || !layer || !leafletLib) return;
@@ -3442,14 +3448,14 @@ function Map2({
3442
3448
  ].filter(Boolean).join(" ");
3443
3449
  const statusLabel = leafletError ? leafletError.message || "Failed to load map library" : !leafletLib ? "Loading map\u2026" : iiifTargets.error ? iiifTargets.error : datasetUnavailable ? "Map data is unavailable for this site." : navState.error ? navState.error : isLoadingMarkers ? "Loading map data\u2026" : !iiifContent && !hasCustomPoints ? "Add iiifContent or MapPoint markers to populate this map." : !hasMarkers ? "No map locations available." : "";
3444
3450
  const showStatus = Boolean(statusLabel);
3445
- return /* @__PURE__ */ React35.createElement("div", { className: rootClass, id: id || void 0, style: style || void 0 }, /* @__PURE__ */ React35.createElement(
3451
+ return /* @__PURE__ */ React36.createElement("div", { className: rootClass, id: id || void 0, style: style || void 0 }, /* @__PURE__ */ React36.createElement(
3446
3452
  "div",
3447
3453
  {
3448
3454
  ref: containerRef,
3449
3455
  className: "canopy-map__canvas",
3450
3456
  style: { height: height || "600px" }
3451
3457
  }
3452
- ), showStatus ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-map__status", "aria-live": "polite" }, statusLabel) : null);
3458
+ ), showStatus ? /* @__PURE__ */ React36.createElement("div", { className: "canopy-map__status", "aria-live": "polite" }, statusLabel) : null);
3453
3459
  }
3454
3460
 
3455
3461
  // ui/src/content/map/MapPoint.jsx
@@ -3473,6 +3479,7 @@ export {
3473
3479
  Grid,
3474
3480
  GridItem,
3475
3481
  HelloWorld,
3482
+ Id,
3476
3483
  Image,
3477
3484
  Map2 as Map,
3478
3485
  MapPoint,