@canopy-iiif/app 1.2.2 → 1.2.4

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
@@ -1220,8 +1220,22 @@ function TeaserCard({
1220
1220
  );
1221
1221
  }
1222
1222
 
1223
+ // ui/src/layout/GoogleAnalytics.jsx
1224
+ import React17 from "react";
1225
+ var GA_HOST = "https://www.googletagmanager.com/gtag/js";
1226
+ function GoogleAnalytics({ id }) {
1227
+ if (!id) return null;
1228
+ const inlineConfig = `
1229
+ window.dataLayer = window.dataLayer || [];
1230
+ function gtag(){window.dataLayer.push(arguments);}
1231
+ gtag('js', new Date());
1232
+ gtag('config', '${id}');
1233
+ `;
1234
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React17.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
1235
+ }
1236
+
1223
1237
  // ui/src/iiif/Viewer.jsx
1224
- import React17, { useEffect as useEffect2, useState as useState2 } from "react";
1238
+ import React18, { useEffect as useEffect2, useState as useState2 } from "react";
1225
1239
  var DEFAULT_VIEWER_OPTIONS = {
1226
1240
  showDownload: false,
1227
1241
  showIIIFBadge: false,
@@ -1277,7 +1291,7 @@ var Viewer = (props) => {
1277
1291
  } catch (_) {
1278
1292
  json = "{}";
1279
1293
  }
1280
- return /* @__PURE__ */ React17.createElement("div", { "data-canopy-viewer": "1", className: "not-prose" }, /* @__PURE__ */ React17.createElement(
1294
+ return /* @__PURE__ */ React18.createElement("div", { "data-canopy-viewer": "1", className: "not-prose" }, /* @__PURE__ */ React18.createElement(
1281
1295
  "script",
1282
1296
  {
1283
1297
  type: "application/json",
@@ -1285,11 +1299,11 @@ var Viewer = (props) => {
1285
1299
  }
1286
1300
  ));
1287
1301
  }
1288
- return /* @__PURE__ */ React17.createElement(CloverViewer, { ...props, options: mergedOptions });
1302
+ return /* @__PURE__ */ React18.createElement(CloverViewer, { ...props, options: mergedOptions });
1289
1303
  };
1290
1304
 
1291
1305
  // ui/src/iiif/Slider.jsx
1292
- import React18, { useEffect as useEffect3, useState as useState3 } from "react";
1306
+ import React19, { useEffect as useEffect3, useState as useState3 } from "react";
1293
1307
 
1294
1308
  // ui/src/iiif/sliderOptions.js
1295
1309
  var UNIT_TOKEN = "__canopySliderUnit";
@@ -1436,7 +1450,7 @@ var Slider = (props = {}) => {
1436
1450
  } catch (_) {
1437
1451
  json = "{}";
1438
1452
  }
1439
- return /* @__PURE__ */ React18.createElement("div", { className: sliderClassName, "data-canopy-slider": "1" }, /* @__PURE__ */ React18.createElement(
1453
+ return /* @__PURE__ */ React19.createElement("div", { className: sliderClassName, "data-canopy-slider": "1" }, /* @__PURE__ */ React19.createElement(
1440
1454
  "script",
1441
1455
  {
1442
1456
  type: "application/json",
@@ -1444,11 +1458,11 @@ var Slider = (props = {}) => {
1444
1458
  }
1445
1459
  ));
1446
1460
  }
1447
- return /* @__PURE__ */ React18.createElement(CloverSlider, { ...resolvedProps });
1461
+ return /* @__PURE__ */ React19.createElement(CloverSlider, { ...resolvedProps });
1448
1462
  };
1449
1463
 
1450
1464
  // ui/src/iiif/Scroll.jsx
1451
- import React19, { useEffect as useEffect4, useState as useState4 } from "react";
1465
+ import React20, { useEffect as useEffect4, useState as useState4 } from "react";
1452
1466
  var Scroll = (props) => {
1453
1467
  const [CloverScroll, setCloverScroll] = useState4(null);
1454
1468
  useEffect4(() => {
@@ -1473,7 +1487,7 @@ var Scroll = (props) => {
1473
1487
  } catch (_) {
1474
1488
  json = "{}";
1475
1489
  }
1476
- return /* @__PURE__ */ React19.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React19.createElement(
1490
+ return /* @__PURE__ */ React20.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React20.createElement(
1477
1491
  "script",
1478
1492
  {
1479
1493
  type: "application/json",
@@ -1481,11 +1495,11 @@ var Scroll = (props) => {
1481
1495
  }
1482
1496
  ));
1483
1497
  }
1484
- return /* @__PURE__ */ React19.createElement(CloverScroll, { ...props });
1498
+ return /* @__PURE__ */ React20.createElement(CloverScroll, { ...props });
1485
1499
  };
1486
1500
 
1487
1501
  // ui/src/iiif/Image.jsx
1488
- import React20, { useEffect as useEffect5, useState as useState5 } from "react";
1502
+ import React21, { useEffect as useEffect5, useState as useState5 } from "react";
1489
1503
  var Image = (props = {}) => {
1490
1504
  const [CloverImage, setCloverImage] = useState5(null);
1491
1505
  const baseClass = "canopy-iiif-image";
@@ -1518,7 +1532,7 @@ var Image = (props = {}) => {
1518
1532
  } catch (_) {
1519
1533
  json = "{}";
1520
1534
  }
1521
- return /* @__PURE__ */ React20.createElement("figure", { className: rootClassName }, /* @__PURE__ */ React20.createElement(
1535
+ return /* @__PURE__ */ React21.createElement("figure", { className: rootClassName }, /* @__PURE__ */ React21.createElement(
1522
1536
  "div",
1523
1537
  {
1524
1538
  className: `${baseClass}__placeholder`,
@@ -1528,20 +1542,20 @@ var Image = (props = {}) => {
1528
1542
  "--canopy-iiif-image-bg": backgroundColor
1529
1543
  }
1530
1544
  },
1531
- /* @__PURE__ */ React20.createElement(
1545
+ /* @__PURE__ */ React21.createElement(
1532
1546
  "script",
1533
1547
  {
1534
1548
  type: "application/json",
1535
1549
  dangerouslySetInnerHTML: { __html: json }
1536
1550
  }
1537
1551
  )
1538
- ), caption && /* @__PURE__ */ React20.createElement("figcaption", { className: `${baseClass}__caption` }, caption));
1552
+ ), caption && /* @__PURE__ */ React21.createElement("figcaption", { className: `${baseClass}__caption` }, caption));
1539
1553
  }
1540
- return /* @__PURE__ */ React20.createElement(CloverImage, { ...props, className: rootClassName });
1554
+ return /* @__PURE__ */ React21.createElement(CloverImage, { ...props, className: rootClassName });
1541
1555
  };
1542
1556
 
1543
1557
  // ui/src/iiif/MdxRelatedItems.jsx
1544
- import React21 from "react";
1558
+ import React22 from "react";
1545
1559
  function MdxRelatedItems(props) {
1546
1560
  let json = "{}";
1547
1561
  try {
@@ -1549,7 +1563,7 @@ function MdxRelatedItems(props) {
1549
1563
  } catch (_) {
1550
1564
  json = "{}";
1551
1565
  }
1552
- return /* @__PURE__ */ React21.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React21.createElement(
1566
+ return /* @__PURE__ */ React22.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React22.createElement(
1553
1567
  "script",
1554
1568
  {
1555
1569
  type: "application/json",
@@ -1559,7 +1573,7 @@ function MdxRelatedItems(props) {
1559
1573
  }
1560
1574
 
1561
1575
  // ui/src/search/MdxSearchResults.jsx
1562
- import React22 from "react";
1576
+ import React23 from "react";
1563
1577
  function MdxSearchResults(props) {
1564
1578
  let json = "{}";
1565
1579
  try {
@@ -1567,11 +1581,11 @@ function MdxSearchResults(props) {
1567
1581
  } catch (_) {
1568
1582
  json = "{}";
1569
1583
  }
1570
- return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1584
+ return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1571
1585
  }
1572
1586
 
1573
1587
  // ui/src/search/SearchSummary.jsx
1574
- import React23 from "react";
1588
+ import React24 from "react";
1575
1589
  function SearchSummary(props) {
1576
1590
  let json = "{}";
1577
1591
  try {
@@ -1579,11 +1593,11 @@ function SearchSummary(props) {
1579
1593
  } catch (_) {
1580
1594
  json = "{}";
1581
1595
  }
1582
- return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1596
+ return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1583
1597
  }
1584
1598
 
1585
1599
  // ui/src/search/MdxSearchTabs.jsx
1586
- import React24 from "react";
1600
+ import React25 from "react";
1587
1601
  function MdxSearchTabs(props) {
1588
1602
  let json = "{}";
1589
1603
  try {
@@ -1591,11 +1605,11 @@ function MdxSearchTabs(props) {
1591
1605
  } catch (_) {
1592
1606
  json = "{}";
1593
1607
  }
1594
- return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1608
+ return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1595
1609
  }
1596
1610
 
1597
1611
  // ui/src/search/MdxSearch.jsx
1598
- import React25 from "react";
1612
+ import React26 from "react";
1599
1613
  function MdxSearch(props = {}) {
1600
1614
  const {
1601
1615
  layout,
@@ -1613,15 +1627,15 @@ function MdxSearch(props = {}) {
1613
1627
  resultsPayload.layout = layout;
1614
1628
  }
1615
1629
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
1616
- return /* @__PURE__ */ React25.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React25.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React25.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React25.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
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);
1617
1631
  }
1618
1632
 
1619
1633
  // ui/src/search/SearchResults.jsx
1620
- import React26 from "react";
1634
+ import React27 from "react";
1621
1635
  function DefaultArticleTemplate({ record, query }) {
1622
1636
  if (!record) return null;
1623
1637
  const metadata = Array.isArray(record.metadata) ? record.metadata : [];
1624
- return /* @__PURE__ */ React26.createElement(
1638
+ return /* @__PURE__ */ React27.createElement(
1625
1639
  ArticleCard,
1626
1640
  {
1627
1641
  href: record.href,
@@ -1639,7 +1653,7 @@ function DefaultFigureTemplate({ record, thumbnailAspectRatio }) {
1639
1653
  if (!record) return null;
1640
1654
  const hasDims = Number.isFinite(Number(record.thumbnailWidth)) && Number(record.thumbnailWidth) > 0 && Number.isFinite(Number(record.thumbnailHeight)) && Number(record.thumbnailHeight) > 0;
1641
1655
  const aspect = Number.isFinite(Number(thumbnailAspectRatio)) && Number(thumbnailAspectRatio) > 0 ? Number(thumbnailAspectRatio) : hasDims ? Number(record.thumbnailWidth) / Number(record.thumbnailHeight) : void 0;
1642
- return /* @__PURE__ */ React26.createElement(
1656
+ return /* @__PURE__ */ React27.createElement(
1643
1657
  Card,
1644
1658
  {
1645
1659
  href: record.href,
@@ -1660,7 +1674,7 @@ function SearchResults({
1660
1674
  variant = "auto"
1661
1675
  }) {
1662
1676
  if (!results.length) {
1663
- return /* @__PURE__ */ React26.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React26.createElement("em", null, "No results"));
1677
+ return /* @__PURE__ */ React27.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React27.createElement("em", null, "No results"));
1664
1678
  }
1665
1679
  const normalizedType = String(type || "all").toLowerCase();
1666
1680
  const normalizedVariant = variant === "figure" || variant === "article" ? variant : "auto";
@@ -1668,9 +1682,9 @@ function SearchResults({
1668
1682
  const FigureTemplate = templates && templates.figure ? templates.figure : DefaultFigureTemplate;
1669
1683
  const ArticleTemplate = templates && templates.article ? templates.article : DefaultArticleTemplate;
1670
1684
  if (isAnnotationView) {
1671
- return /* @__PURE__ */ React26.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1685
+ return /* @__PURE__ */ React27.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1672
1686
  if (!r) return null;
1673
- return /* @__PURE__ */ React26.createElement(
1687
+ return /* @__PURE__ */ React27.createElement(
1674
1688
  ArticleTemplate,
1675
1689
  {
1676
1690
  key: r.id || i,
@@ -1688,20 +1702,20 @@ function SearchResults({
1688
1702
  return !isWorkRecord(record) || normalizedType !== "work";
1689
1703
  };
1690
1704
  if (layout === "list") {
1691
- return /* @__PURE__ */ React26.createElement("div", { id: "search-results", className: "space-y-6" }, results.map((r, i) => {
1705
+ return /* @__PURE__ */ React27.createElement("div", { id: "search-results", className: "space-y-6" }, results.map((r, i) => {
1692
1706
  if (shouldRenderAsArticle(r)) {
1693
- return /* @__PURE__ */ React26.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React26.createElement(ArticleTemplate, { record: r, query, layout }));
1707
+ return /* @__PURE__ */ React27.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React27.createElement(ArticleTemplate, { record: r, query, layout }));
1694
1708
  }
1695
1709
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1696
1710
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1697
- return /* @__PURE__ */ React26.createElement(
1711
+ return /* @__PURE__ */ React27.createElement(
1698
1712
  "div",
1699
1713
  {
1700
1714
  key: i,
1701
1715
  className: `search-result ${r.type}`,
1702
1716
  "data-thumbnail-aspect-ratio": aspect
1703
1717
  },
1704
- /* @__PURE__ */ React26.createElement(
1718
+ /* @__PURE__ */ React27.createElement(
1705
1719
  FigureTemplate,
1706
1720
  {
1707
1721
  record: r,
@@ -1713,20 +1727,20 @@ function SearchResults({
1713
1727
  );
1714
1728
  }));
1715
1729
  }
1716
- return /* @__PURE__ */ React26.createElement("div", { id: "search-results" }, /* @__PURE__ */ React26.createElement(Grid, null, results.map((r, i) => {
1730
+ return /* @__PURE__ */ React27.createElement("div", { id: "search-results" }, /* @__PURE__ */ React27.createElement(Grid, null, results.map((r, i) => {
1717
1731
  if (shouldRenderAsArticle(r)) {
1718
- return /* @__PURE__ */ React26.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React26.createElement(ArticleTemplate, { record: r, query, layout }));
1732
+ return /* @__PURE__ */ React27.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React27.createElement(ArticleTemplate, { record: r, query, layout }));
1719
1733
  }
1720
1734
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1721
1735
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1722
- return /* @__PURE__ */ React26.createElement(
1736
+ return /* @__PURE__ */ React27.createElement(
1723
1737
  GridItem,
1724
1738
  {
1725
1739
  key: i,
1726
1740
  className: `search-result ${r.type}`,
1727
1741
  "data-thumbnail-aspect-ratio": aspect
1728
1742
  },
1729
- /* @__PURE__ */ React26.createElement(
1743
+ /* @__PURE__ */ React27.createElement(
1730
1744
  FigureTemplate,
1731
1745
  {
1732
1746
  record: r,
@@ -1740,7 +1754,7 @@ function SearchResults({
1740
1754
  }
1741
1755
 
1742
1756
  // ui/src/search/SearchTabs.jsx
1743
- import React27, { useRef as useRef2, useState as useState6, useEffect as useEffect6 } from "react";
1757
+ import React28, { useRef as useRef2, useState as useState6, useEffect as useEffect6 } from "react";
1744
1758
  function SearchTabs({
1745
1759
  type = "all",
1746
1760
  onTypeChange,
@@ -1794,7 +1808,7 @@ function SearchTabs({
1794
1808
  width: `${itemBoundingBox.width}px`
1795
1809
  };
1796
1810
  }
1797
- return /* @__PURE__ */ React27.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React27.createElement(
1811
+ return /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React28.createElement(
1798
1812
  "div",
1799
1813
  {
1800
1814
  role: "tablist",
@@ -1803,7 +1817,7 @@ function SearchTabs({
1803
1817
  ref: wrapperRef,
1804
1818
  onMouseLeave: resetHighlight
1805
1819
  },
1806
- /* @__PURE__ */ React27.createElement(
1820
+ /* @__PURE__ */ React28.createElement(
1807
1821
  "div",
1808
1822
  {
1809
1823
  ref: highlightRef,
@@ -1815,7 +1829,7 @@ function SearchTabs({
1815
1829
  const active = String(type).toLowerCase() === String(t).toLowerCase();
1816
1830
  const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
1817
1831
  const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
1818
- return /* @__PURE__ */ React27.createElement(
1832
+ return /* @__PURE__ */ React28.createElement(
1819
1833
  "button",
1820
1834
  {
1821
1835
  key: t,
@@ -1833,7 +1847,7 @@ function SearchTabs({
1833
1847
  ")"
1834
1848
  );
1835
1849
  })
1836
- ), hasFilters ? /* @__PURE__ */ React27.createElement(
1850
+ ), hasFilters ? /* @__PURE__ */ React28.createElement(
1837
1851
  "button",
1838
1852
  {
1839
1853
  type: "button",
@@ -1841,12 +1855,12 @@ function SearchTabs({
1841
1855
  "aria-expanded": filtersOpen ? "true" : "false",
1842
1856
  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"
1843
1857
  },
1844
- /* @__PURE__ */ React27.createElement("span", null, filtersLabel, filterBadge)
1858
+ /* @__PURE__ */ React28.createElement("span", null, filtersLabel, filterBadge)
1845
1859
  ) : null);
1846
1860
  }
1847
1861
 
1848
1862
  // ui/src/search/SearchFiltersDialog.jsx
1849
- import React28 from "react";
1863
+ import React29 from "react";
1850
1864
  function toArray(input) {
1851
1865
  if (!input) return [];
1852
1866
  if (Array.isArray(input)) return input;
@@ -1885,20 +1899,20 @@ function FacetSection({ facet, selected, onToggle }) {
1885
1899
  const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
1886
1900
  const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
1887
1901
  const hasSelection = selectedValues.size > 0;
1888
- const [quickQuery, setQuickQuery] = React28.useState("");
1902
+ const [quickQuery, setQuickQuery] = React29.useState("");
1889
1903
  const hasQuery = quickQuery.trim().length > 0;
1890
- const filteredValues = React28.useMemo(
1904
+ const filteredValues = React29.useMemo(
1891
1905
  () => facetMatches(values, quickQuery),
1892
1906
  [values, quickQuery]
1893
1907
  );
1894
- return /* @__PURE__ */ React28.createElement(
1908
+ return /* @__PURE__ */ React29.createElement(
1895
1909
  "details",
1896
1910
  {
1897
1911
  className: "canopy-search-filters__facet",
1898
1912
  open: hasSelection
1899
1913
  },
1900
- /* @__PURE__ */ React28.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React28.createElement("span", null, label), /* @__PURE__ */ React28.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
1901
- /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React28.createElement(
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(
1902
1916
  "input",
1903
1917
  {
1904
1918
  type: "search",
@@ -1908,7 +1922,7 @@ function FacetSection({ facet, selected, onToggle }) {
1908
1922
  className: "canopy-search-filters__quick-input",
1909
1923
  "aria-label": `Filter ${label} values`
1910
1924
  }
1911
- ), quickQuery ? /* @__PURE__ */ React28.createElement(
1925
+ ), quickQuery ? /* @__PURE__ */ React29.createElement(
1912
1926
  "button",
1913
1927
  {
1914
1928
  type: "button",
@@ -1916,11 +1930,11 @@ function FacetSection({ facet, selected, onToggle }) {
1916
1930
  className: "canopy-search-filters__quick-clear"
1917
1931
  },
1918
1932
  "Clear"
1919
- ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React28.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React28.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
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) => {
1920
1934
  const valueSlug = String(entry.slug || entry.value || "");
1921
1935
  const isChecked = selectedValues.has(valueSlug);
1922
1936
  const inputId = checkboxId(valueSlug);
1923
- return /* @__PURE__ */ React28.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React28.createElement(
1937
+ return /* @__PURE__ */ React29.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React29.createElement(
1924
1938
  "input",
1925
1939
  {
1926
1940
  id: inputId,
@@ -1932,15 +1946,15 @@ function FacetSection({ facet, selected, onToggle }) {
1932
1946
  if (onToggle) onToggle(slug, valueSlug, nextChecked);
1933
1947
  }
1934
1948
  }
1935
- ), /* @__PURE__ */ React28.createElement(
1949
+ ), /* @__PURE__ */ React29.createElement(
1936
1950
  "label",
1937
1951
  {
1938
1952
  htmlFor: inputId,
1939
1953
  className: "canopy-search-filters__facet-label"
1940
1954
  },
1941
- /* @__PURE__ */ React28.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React28.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
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)
1942
1956
  ));
1943
- }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React28.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1957
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React29.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1944
1958
  );
1945
1959
  }
1946
1960
  function SearchFiltersDialog(props = {}) {
@@ -1962,7 +1976,7 @@ function SearchFiltersDialog(props = {}) {
1962
1976
  (total, set) => total + set.size,
1963
1977
  0
1964
1978
  );
1965
- React28.useEffect(() => {
1979
+ React29.useEffect(() => {
1966
1980
  if (!open) return void 0;
1967
1981
  if (typeof document === "undefined") return void 0;
1968
1982
  const body = document.body;
@@ -1979,7 +1993,7 @@ function SearchFiltersDialog(props = {}) {
1979
1993
  if (!open) return null;
1980
1994
  const brandId = "canopy-modal-filters-label";
1981
1995
  const subtitleText = subtitle != null ? subtitle : title;
1982
- return /* @__PURE__ */ React28.createElement(
1996
+ return /* @__PURE__ */ React29.createElement(
1983
1997
  CanopyModal,
1984
1998
  {
1985
1999
  id: "canopy-modal-filters",
@@ -1994,8 +2008,8 @@ function SearchFiltersDialog(props = {}) {
1994
2008
  onBackgroundClick: () => onOpenChange && onOpenChange(false),
1995
2009
  bodyClassName: "canopy-modal__body--filters"
1996
2010
  },
1997
- subtitleText ? /* @__PURE__ */ React28.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
1998
- /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React28.createElement(
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(
1999
2013
  FacetSection,
2000
2014
  {
2001
2015
  key: facet.slug || facet.label,
@@ -2003,8 +2017,8 @@ function SearchFiltersDialog(props = {}) {
2003
2017
  selected: selectedMap,
2004
2018
  onToggle
2005
2019
  }
2006
- ))) : /* @__PURE__ */ React28.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
2007
- /* @__PURE__ */ React28.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React28.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React28.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React28.createElement(
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(
2008
2022
  "button",
2009
2023
  {
2010
2024
  type: "button",
@@ -2015,7 +2029,7 @@ function SearchFiltersDialog(props = {}) {
2015
2029
  className: "canopy-search-filters__button canopy-search-filters__button--secondary"
2016
2030
  },
2017
2031
  "Clear all"
2018
- ), /* @__PURE__ */ React28.createElement(
2032
+ ), /* @__PURE__ */ React29.createElement(
2019
2033
  "button",
2020
2034
  {
2021
2035
  type: "button",
@@ -2028,7 +2042,7 @@ function SearchFiltersDialog(props = {}) {
2028
2042
  }
2029
2043
 
2030
2044
  // ui/src/search-form/MdxSearchFormModal.jsx
2031
- import React29 from "react";
2045
+ import React30 from "react";
2032
2046
  function MdxSearchFormModal(props = {}) {
2033
2047
  const {
2034
2048
  placeholder = "Search\u2026",
@@ -2044,24 +2058,24 @@ function MdxSearchFormModal(props = {}) {
2044
2058
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
2045
2059
  const resolvedSearchPath = resolveSearchPath(searchPath);
2046
2060
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
2047
- return /* @__PURE__ */ React29.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React29.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React29.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React29.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React29.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
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) } }));
2048
2062
  }
2049
2063
 
2050
2064
  // ui/src/docs/MarkdownTable.jsx
2051
- import React30 from "react";
2065
+ import React31 from "react";
2052
2066
  function MarkdownTable({ className = "", ...rest }) {
2053
2067
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
2054
- return /* @__PURE__ */ React30.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React30.createElement("table", { className: merged, ...rest }));
2068
+ return /* @__PURE__ */ React31.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React31.createElement("table", { className: merged, ...rest }));
2055
2069
  }
2056
2070
 
2057
2071
  // ui/src/docs/Diagram.jsx
2058
- import React31 from "react";
2072
+ import React32 from "react";
2059
2073
  function CanopyDiagram() {
2060
- return /* @__PURE__ */ React31.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React31.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React31.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React31.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Collection A"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React31.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React31.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Collection B"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React31.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React31.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React31.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React31.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React31.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React31.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Automated content"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React31.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React31.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React31.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React31.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Search index"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React31.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React31.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React31.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React31.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React31.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React31.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React31.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__ */ React31.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Work pages"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React31.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React31.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React31.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React31.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React31.createElement("article", null, /* @__PURE__ */ React31.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React31.createElement("ul", null, /* @__PURE__ */ React31.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React31.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React31.createElement("li", null, "Optional annotation dataset"))))));
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 & tours"), /* @__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"))))));
2061
2075
  }
2062
2076
 
2063
2077
  // ui/src/content/timeline/Timeline.jsx
2064
- import React32 from "react";
2078
+ import React33 from "react";
2065
2079
 
2066
2080
  // ui/src/content/timeline/date-utils.js
2067
2081
  var FALLBACK_LOCALE = (() => {
@@ -2380,14 +2394,14 @@ function TimelineConnector({ side, isActive, highlight }) {
2380
2394
  "canopy-timeline__connector-dot",
2381
2395
  highlight || isActive ? "is-active" : ""
2382
2396
  ].filter(Boolean).join(" ");
2383
- return /* @__PURE__ */ React32.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React32.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("span", { className: dotClasses }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__connector-line" })));
2397
+ return /* @__PURE__ */ React33.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React33.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("span", { className: dotClasses }), /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__connector-line" })));
2384
2398
  }
2385
2399
  function renderResourceSection(point) {
2386
2400
  if (!point) return null;
2387
2401
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
2388
2402
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2389
2403
  if (!manifestCards.length && !legacyResources.length) return null;
2390
- return /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React32.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React32.createElement(
2404
+ return /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React33.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React33.createElement(
2391
2405
  TeaserCard,
2392
2406
  {
2393
2407
  href: manifest.href,
@@ -2397,7 +2411,7 @@ function renderResourceSection(point) {
2397
2411
  thumbnail: manifest.thumbnail,
2398
2412
  type: manifest.type || "work"
2399
2413
  }
2400
- ))), legacyResources.map((resource, idx) => /* @__PURE__ */ React32.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React32.createElement(
2414
+ ))), legacyResources.map((resource, idx) => /* @__PURE__ */ React33.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React33.createElement(
2401
2415
  TeaserCard,
2402
2416
  {
2403
2417
  href: resource.href,
@@ -2422,26 +2436,26 @@ function Timeline({
2422
2436
  ...rest
2423
2437
  }) {
2424
2438
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
2425
- const rawPoints = React32.useMemo(() => {
2439
+ const rawPoints = React33.useMemo(() => {
2426
2440
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
2427
2441
  if (payloadPoints && payloadPoints.length) return payloadPoints;
2428
2442
  return [];
2429
2443
  }, [pointsProp, payloadPoints]);
2430
- const sanitizedPoints = React32.useMemo(
2444
+ const sanitizedPoints = React33.useMemo(
2431
2445
  () => sanitizePoints(rawPoints),
2432
2446
  [rawPoints]
2433
2447
  );
2434
2448
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
2435
- const baseLocale = React32.useMemo(
2449
+ const baseLocale = React33.useMemo(
2436
2450
  () => createLocale(localeValue),
2437
2451
  [localeValue]
2438
2452
  );
2439
2453
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
2440
- const rangeOverrides = React32.useMemo(
2454
+ const rangeOverrides = React33.useMemo(
2441
2455
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
2442
2456
  [sanitizedPoints, rangeInput]
2443
2457
  );
2444
- const effectiveRange = React32.useMemo(
2458
+ const effectiveRange = React33.useMemo(
2445
2459
  () => normalizeRange({
2446
2460
  ...rangeOverrides,
2447
2461
  locale: baseLocale
@@ -2450,7 +2464,7 @@ function Timeline({
2450
2464
  );
2451
2465
  const spanStart = effectiveRange.startDate.getTime();
2452
2466
  const span = effectiveRange.span;
2453
- const pointsWithPosition = React32.useMemo(() => {
2467
+ const pointsWithPosition = React33.useMemo(() => {
2454
2468
  if (!sanitizedPoints.length) return [];
2455
2469
  return sanitizedPoints.map((point, index) => {
2456
2470
  const timestamp = point.meta.timestamp;
@@ -2464,29 +2478,29 @@ function Timeline({
2464
2478
  };
2465
2479
  });
2466
2480
  }, [sanitizedPoints, spanStart, span]);
2467
- const [activeId, setActiveId] = React32.useState(
2481
+ const [activeId, setActiveId] = React33.useState(
2468
2482
  () => getActivePointId(pointsWithPosition)
2469
2483
  );
2470
- React32.useEffect(() => {
2484
+ React33.useEffect(() => {
2471
2485
  setActiveId(getActivePointId(pointsWithPosition));
2472
2486
  }, [pointsWithPosition]);
2473
2487
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
2474
2488
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
2475
- const thresholdMs = React32.useMemo(
2489
+ const thresholdMs = React33.useMemo(
2476
2490
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
2477
2491
  [thresholdValue, effectiveRange.granularity]
2478
2492
  );
2479
- const groupedEntries = React32.useMemo(
2493
+ const groupedEntries = React33.useMemo(
2480
2494
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
2481
2495
  granularity: effectiveRange.granularity,
2482
2496
  locale: baseLocale
2483
2497
  }),
2484
2498
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
2485
2499
  );
2486
- const [expandedGroupIds, setExpandedGroupIds] = React32.useState(
2500
+ const [expandedGroupIds, setExpandedGroupIds] = React33.useState(
2487
2501
  () => /* @__PURE__ */ new Set()
2488
2502
  );
2489
- React32.useEffect(() => {
2503
+ React33.useEffect(() => {
2490
2504
  setExpandedGroupIds((prev) => {
2491
2505
  if (!prev || prev.size === 0) return prev;
2492
2506
  const validIds = new Set(
@@ -2501,7 +2515,7 @@ function Timeline({
2501
2515
  return changed ? next : prev;
2502
2516
  });
2503
2517
  }, [groupedEntries]);
2504
- const toggleGroup = React32.useCallback((groupId) => {
2518
+ const toggleGroup = React33.useCallback((groupId) => {
2505
2519
  setExpandedGroupIds((prev) => {
2506
2520
  const next = new Set(prev || []);
2507
2521
  if (next.has(groupId)) next.delete(groupId);
@@ -2524,7 +2538,7 @@ function Timeline({
2524
2538
  point.id === activeId ? "is-active" : "",
2525
2539
  point.highlight ? "is-highlighted" : ""
2526
2540
  ].filter(Boolean).join(" ");
2527
- const connector = /* @__PURE__ */ React32.createElement(
2541
+ const connector = /* @__PURE__ */ React33.createElement(
2528
2542
  TimelineConnector,
2529
2543
  {
2530
2544
  side: point.side,
@@ -2532,9 +2546,9 @@ function Timeline({
2532
2546
  highlight: point.highlight
2533
2547
  }
2534
2548
  );
2535
- const body = /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2549
+ const body = /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2536
2550
  const resourceSection = renderResourceSection(point);
2537
- return /* @__PURE__ */ React32.createElement(
2551
+ return /* @__PURE__ */ React33.createElement(
2538
2552
  "div",
2539
2553
  {
2540
2554
  key: point.id,
@@ -2542,7 +2556,7 @@ function Timeline({
2542
2556
  style: wrapperStyle,
2543
2557
  role: "listitem"
2544
2558
  },
2545
- point.side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, connector, /* @__PURE__ */ React32.createElement("div", { className: cardClasses }, body, resourceSection))
2559
+ point.side === "left" ? /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React33.createElement(React33.Fragment, null, connector, /* @__PURE__ */ React33.createElement("div", { className: cardClasses }, body, resourceSection))
2546
2560
  );
2547
2561
  }
2548
2562
  function renderGroupEntry(entry) {
@@ -2553,7 +2567,7 @@ function Timeline({
2553
2567
  const wrapperStyle = { top: `${entry.progress * 100}%` };
2554
2568
  const isExpanded = expandedGroupIds.has(entry.id);
2555
2569
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
2556
- const connector = /* @__PURE__ */ React32.createElement(
2570
+ const connector = /* @__PURE__ */ React33.createElement(
2557
2571
  TimelineConnector,
2558
2572
  {
2559
2573
  side: entry.side,
@@ -2567,7 +2581,7 @@ function Timeline({
2567
2581
  hasActivePoint ? "is-active" : ""
2568
2582
  ].filter(Boolean).join(" ");
2569
2583
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
2570
- const header = /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React32.createElement(
2584
+ const header = /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React33.createElement(
2571
2585
  "button",
2572
2586
  {
2573
2587
  type: "button",
@@ -2577,7 +2591,7 @@ function Timeline({
2577
2591
  },
2578
2592
  isExpanded ? "Hide details" : "Show details"
2579
2593
  ));
2580
- const groupPoints = isExpanded ? /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React32.createElement(
2594
+ const groupPoints = isExpanded ? /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React33.createElement(
2581
2595
  "button",
2582
2596
  {
2583
2597
  key: point.id,
@@ -2588,11 +2602,11 @@ function Timeline({
2588
2602
  ].filter(Boolean).join(" "),
2589
2603
  onClick: () => setActiveId(point.id)
2590
2604
  },
2591
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2592
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2605
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
2606
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2593
2607
  ))) : null;
2594
- const groupCard = /* @__PURE__ */ React32.createElement("div", { className: groupClasses }, header, groupPoints);
2595
- return /* @__PURE__ */ React32.createElement(
2608
+ const groupCard = /* @__PURE__ */ React33.createElement("div", { className: groupClasses }, header, groupPoints);
2609
+ return /* @__PURE__ */ React33.createElement(
2596
2610
  "div",
2597
2611
  {
2598
2612
  key: entry.id,
@@ -2600,17 +2614,17 @@ function Timeline({
2600
2614
  style: wrapperStyle,
2601
2615
  role: "listitem"
2602
2616
  },
2603
- entry.side === "left" ? /* @__PURE__ */ React32.createElement(React32.Fragment, null, groupCard, connector) : /* @__PURE__ */ React32.createElement(React32.Fragment, null, connector, groupCard)
2617
+ entry.side === "left" ? /* @__PURE__ */ React33.createElement(React33.Fragment, null, groupCard, connector) : /* @__PURE__ */ React33.createElement(React33.Fragment, null, connector, groupCard)
2604
2618
  );
2605
2619
  }
2606
- return /* @__PURE__ */ React32.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React32.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React32.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React32.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React32.createElement(
2620
+ return /* @__PURE__ */ React33.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React33.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React33.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React33.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React33.createElement(
2607
2621
  "div",
2608
2622
  {
2609
2623
  className: "canopy-timeline__list",
2610
2624
  role: "list",
2611
2625
  style: { minHeight: trackHeight }
2612
2626
  },
2613
- /* @__PURE__ */ React32.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2627
+ /* @__PURE__ */ React33.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2614
2628
  renderSteps(stepsValue, effectiveRange),
2615
2629
  groupedEntries.map((entry) => {
2616
2630
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -2625,7 +2639,7 @@ function renderSteps(stepSize, range) {
2625
2639
  const markers = [];
2626
2640
  if (startYear < endYear) {
2627
2641
  markers.push(
2628
- /* @__PURE__ */ React32.createElement(
2642
+ /* @__PURE__ */ React33.createElement(
2629
2643
  "span",
2630
2644
  {
2631
2645
  key: "timeline-step-start",
@@ -2633,12 +2647,12 @@ function renderSteps(stepSize, range) {
2633
2647
  style: { top: "0%" },
2634
2648
  "aria-hidden": "true"
2635
2649
  },
2636
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
2637
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
2650
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-line" }),
2651
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
2638
2652
  )
2639
2653
  );
2640
2654
  markers.push(
2641
- /* @__PURE__ */ React32.createElement(
2655
+ /* @__PURE__ */ React33.createElement(
2642
2656
  "span",
2643
2657
  {
2644
2658
  key: "timeline-step-end",
@@ -2646,8 +2660,8 @@ function renderSteps(stepSize, range) {
2646
2660
  style: { top: "100%" },
2647
2661
  "aria-hidden": "true"
2648
2662
  },
2649
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
2650
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
2663
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-line" }),
2664
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
2651
2665
  )
2652
2666
  );
2653
2667
  }
@@ -2657,7 +2671,7 @@ function renderSteps(stepSize, range) {
2657
2671
  const progress = (timestamp - range.startDate.getTime()) / range.span;
2658
2672
  if (progress <= 0 || progress >= 1) continue;
2659
2673
  markers.push(
2660
- /* @__PURE__ */ React32.createElement(
2674
+ /* @__PURE__ */ React33.createElement(
2661
2675
  "span",
2662
2676
  {
2663
2677
  key: `timeline-step-${year}`,
@@ -2665,8 +2679,8 @@ function renderSteps(stepSize, range) {
2665
2679
  style: { top: `calc(${progress * 100}% - 0.5px)` },
2666
2680
  "aria-hidden": "true"
2667
2681
  },
2668
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-line" }),
2669
- /* @__PURE__ */ React32.createElement("span", { className: "canopy-timeline__step-label" }, year)
2682
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-line" }),
2683
+ /* @__PURE__ */ React33.createElement("span", { className: "canopy-timeline__step-label" }, year)
2670
2684
  )
2671
2685
  );
2672
2686
  }
@@ -2690,6 +2704,7 @@ export {
2690
2704
  Card,
2691
2705
  Container,
2692
2706
  MarkdownTable as DocsMarkdownTable,
2707
+ GoogleAnalytics,
2693
2708
  Grid,
2694
2709
  GridItem,
2695
2710
  HelloWorld,