@canopy-iiif/app 0.10.17 → 0.10.19

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.
@@ -1766,8 +1766,204 @@ function Container({
1766
1766
  );
1767
1767
  }
1768
1768
 
1769
+ // ui/src/content/ReferencedItems.jsx
1770
+ import React23 from "react";
1771
+ import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
1772
+
1773
+ // ui/src/layout/Card.jsx
1774
+ import React22, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
1775
+ function Card({
1776
+ href,
1777
+ src,
1778
+ alt,
1779
+ title,
1780
+ subtitle,
1781
+ // Optional intrinsic dimensions or aspect ratio to compute a responsive height
1782
+ imgWidth,
1783
+ imgHeight,
1784
+ aspectRatio,
1785
+ className,
1786
+ style,
1787
+ children,
1788
+ lazy = true,
1789
+ ...rest
1790
+ }) {
1791
+ const containerRef = useRef(null);
1792
+ const [inView, setInView] = useState5(!lazy);
1793
+ const [imageLoaded, setImageLoaded] = useState5(!lazy);
1794
+ useEffect5(() => {
1795
+ if (!lazy) return;
1796
+ if (!containerRef.current) return;
1797
+ if (typeof IntersectionObserver !== "function") {
1798
+ setInView(true);
1799
+ return;
1800
+ }
1801
+ const el = containerRef.current;
1802
+ const obs = new IntersectionObserver(
1803
+ (entries) => {
1804
+ for (const entry of entries) {
1805
+ if (entry.isIntersecting) {
1806
+ setInView(true);
1807
+ try {
1808
+ obs.unobserve(el);
1809
+ } catch (_) {
1810
+ }
1811
+ break;
1812
+ }
1813
+ }
1814
+ },
1815
+ { root: null, rootMargin: "100px", threshold: 0.1 }
1816
+ );
1817
+ try {
1818
+ obs.observe(el);
1819
+ } catch (_) {
1820
+ }
1821
+ return () => {
1822
+ try {
1823
+ obs.disconnect();
1824
+ } catch (_) {
1825
+ }
1826
+ };
1827
+ }, [lazy]);
1828
+ const w = Number(imgWidth);
1829
+ const h = Number(imgHeight);
1830
+ const ratio = Number.isFinite(Number(aspectRatio)) && Number(aspectRatio) > 0 ? Number(aspectRatio) : Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0 ? w / h : void 0;
1831
+ const paddingPercent = ratio ? 100 / ratio : 100;
1832
+ const caption = /* @__PURE__ */ React22.createElement("figcaption", null, title && /* @__PURE__ */ React22.createElement("span", null, title), subtitle && /* @__PURE__ */ React22.createElement("span", null, subtitle), children);
1833
+ return /* @__PURE__ */ React22.createElement(
1834
+ "a",
1835
+ {
1836
+ href,
1837
+ className: ["canopy-card", className].filter(Boolean).join(" "),
1838
+ style,
1839
+ ref: containerRef,
1840
+ "data-aspect-ratio": ratio,
1841
+ "data-in-view": inView ? "true" : "false",
1842
+ "data-image-loaded": imageLoaded ? "true" : "false",
1843
+ ...rest
1844
+ },
1845
+ /* @__PURE__ */ React22.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React22.createElement(
1846
+ "div",
1847
+ {
1848
+ className: "canopy-card-media",
1849
+ style: { "--canopy-card-padding": `${paddingPercent}%` }
1850
+ },
1851
+ inView ? /* @__PURE__ */ React22.createElement(
1852
+ "img",
1853
+ {
1854
+ src,
1855
+ alt: alt || title || "",
1856
+ loading: "lazy",
1857
+ onLoad: () => setImageLoaded(true),
1858
+ onError: () => setImageLoaded(true)
1859
+ }
1860
+ ) : null
1861
+ ) : /* @__PURE__ */ React22.createElement(
1862
+ "img",
1863
+ {
1864
+ src,
1865
+ alt: alt || title || "",
1866
+ loading: "lazy",
1867
+ onLoad: () => setImageLoaded(true),
1868
+ onError: () => setImageLoaded(true),
1869
+ className: "canopy-card-image"
1870
+ }
1871
+ ) : null, caption)
1872
+ );
1873
+ }
1874
+
1875
+ // ui/src/content/ReferencedItems.jsx
1876
+ function useReferencedItems(itemsProp) {
1877
+ if (Array.isArray(itemsProp)) return itemsProp;
1878
+ const PageContext = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
1879
+ if (!PageContext) return [];
1880
+ const context = React23.useContext(PageContext);
1881
+ const items = context && context.page ? context.page.referencedItems : null;
1882
+ return Array.isArray(items) ? items : [];
1883
+ }
1884
+ function ReferencedItems({
1885
+ items: itemsProp,
1886
+ emptyLabel = null,
1887
+ className = "",
1888
+ children,
1889
+ ...rest
1890
+ }) {
1891
+ const items = useReferencedItems(itemsProp);
1892
+ const hasItems = items.length > 0;
1893
+ if (!hasItems) {
1894
+ if (!emptyLabel) return null;
1895
+ const emptyClass = [
1896
+ "referenced-items",
1897
+ "referenced-items--empty",
1898
+ className
1899
+ ].filter(Boolean).join(" ");
1900
+ return /* @__PURE__ */ React23.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
1901
+ }
1902
+ const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
1903
+ return /* @__PURE__ */ React23.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React23.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
1904
+ if (!item) return null;
1905
+ const key = item.href || item.slug || item.id;
1906
+ return /* @__PURE__ */ React23.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React23.createElement(
1907
+ Card,
1908
+ {
1909
+ href: item.href,
1910
+ src: item.thumbnail,
1911
+ imgWidth: item.thumbnailWidth,
1912
+ imgHeight: item.thumbnailHeight,
1913
+ title: item.title,
1914
+ subtitle: item.summary,
1915
+ className: "referenced-items__card",
1916
+ lazy: false
1917
+ }
1918
+ ));
1919
+ })));
1920
+ }
1921
+
1922
+ // ui/src/content/References.jsx
1923
+ import React24 from "react";
1924
+ import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
1925
+ function getPageContext() {
1926
+ if (!navigationHelpers4 || typeof navigationHelpers4.getPageContext !== "function") {
1927
+ return null;
1928
+ }
1929
+ try {
1930
+ return navigationHelpers4.getPageContext();
1931
+ } catch (_) {
1932
+ return null;
1933
+ }
1934
+ }
1935
+ function resolveReferences(manifestId, contextList) {
1936
+ if (contextList && contextList.length) return contextList;
1937
+ if (!manifestId) return [];
1938
+ try {
1939
+ return referenced.getReferencesForManifest(manifestId);
1940
+ } catch (_) {
1941
+ return [];
1942
+ }
1943
+ }
1944
+ function References({
1945
+ id = "",
1946
+ title = "Referenced by",
1947
+ emptyLabel = null,
1948
+ className = "",
1949
+ children,
1950
+ ...rest
1951
+ }) {
1952
+ const PageContext = getPageContext();
1953
+ const context = PageContext ? React24.useContext(PageContext) : null;
1954
+ const contextPage = context && context.page ? context.page : null;
1955
+ const manifestId = id || contextPage && contextPage.manifestId || "";
1956
+ const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
1957
+ const references = resolveReferences(manifestId, contextReferences);
1958
+ if (!manifestId) return null;
1959
+ const containerClass = ["references", className].filter(Boolean).join(" ");
1960
+ const list = references.length ? references : null;
1961
+ const entries = list && list.length ? list : null;
1962
+ return /* @__PURE__ */ React24.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React24.createElement("div", { className: "references__group" }, /* @__PURE__ */ React24.createElement("dt", null, title), entries ? entries.map((entry) => /* @__PURE__ */ React24.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React24.createElement("a", { href: entry.href }, entry.title || entry.href))) : emptyLabel ? /* @__PURE__ */ React24.createElement("dd", { className: "references__empty" }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel) : null));
1963
+ }
1964
+
1769
1965
  // ui/src/search/MdxSearchResults.jsx
1770
- import React22 from "react";
1966
+ import React25 from "react";
1771
1967
  function MdxSearchResults(props) {
1772
1968
  let json = "{}";
1773
1969
  try {
@@ -1775,11 +1971,11 @@ function MdxSearchResults(props) {
1775
1971
  } catch (_) {
1776
1972
  json = "{}";
1777
1973
  }
1778
- return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1974
+ return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1779
1975
  }
1780
1976
 
1781
1977
  // ui/src/search/SearchSummary.jsx
1782
- import React23 from "react";
1978
+ import React26 from "react";
1783
1979
  function SearchSummary(props) {
1784
1980
  let json = "{}";
1785
1981
  try {
@@ -1787,11 +1983,11 @@ function SearchSummary(props) {
1787
1983
  } catch (_) {
1788
1984
  json = "{}";
1789
1985
  }
1790
- return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1986
+ return /* @__PURE__ */ React26.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React26.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1791
1987
  }
1792
1988
 
1793
1989
  // ui/src/search/MdxSearchTabs.jsx
1794
- import React24 from "react";
1990
+ import React27 from "react";
1795
1991
  function MdxSearchTabs(props) {
1796
1992
  let json = "{}";
1797
1993
  try {
@@ -1799,11 +1995,11 @@ function MdxSearchTabs(props) {
1799
1995
  } catch (_) {
1800
1996
  json = "{}";
1801
1997
  }
1802
- return /* @__PURE__ */ React24.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React24.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1998
+ return /* @__PURE__ */ React27.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React27.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1803
1999
  }
1804
2000
 
1805
2001
  // ui/src/search-form/MdxSearchFormModal.jsx
1806
- import React25 from "react";
2002
+ import React28 from "react";
1807
2003
  function MdxSearchFormModal(props = {}) {
1808
2004
  const {
1809
2005
  placeholder = "Search\u2026",
@@ -1819,11 +2015,11 @@ function MdxSearchFormModal(props = {}) {
1819
2015
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1820
2016
  const resolvedSearchPath = resolveSearchPath(searchPath);
1821
2017
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
1822
- return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React25.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React25.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React25.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2018
+ return /* @__PURE__ */ React28.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React28.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React28.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React28.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React28.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1823
2019
  }
1824
2020
 
1825
2021
  // ui/src/iiif/ManifestPrimitives.jsx
1826
- import React26 from "react";
2022
+ import React29 from "react";
1827
2023
  import {
1828
2024
  Label as CloverLabel,
1829
2025
  Metadata as CloverMetadata,
@@ -1848,28 +2044,28 @@ function ensureMetadata(items) {
1848
2044
  function Label({ manifest, label, ...rest }) {
1849
2045
  const intl = label || manifest && manifest.label;
1850
2046
  if (!hasInternationalValue(intl)) return null;
1851
- return /* @__PURE__ */ React26.createElement(CloverLabel, { label: intl, ...rest });
2047
+ return /* @__PURE__ */ React29.createElement(CloverLabel, { label: intl, ...rest });
1852
2048
  }
1853
2049
  function Summary({ manifest, summary, ...rest }) {
1854
2050
  const intl = summary || manifest && manifest.summary;
1855
2051
  if (!hasInternationalValue(intl)) return null;
1856
- return /* @__PURE__ */ React26.createElement(CloverSummary, { summary: intl, ...rest });
2052
+ return /* @__PURE__ */ React29.createElement(CloverSummary, { summary: intl, ...rest });
1857
2053
  }
1858
2054
  function Metadata({ manifest, metadata, ...rest }) {
1859
2055
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
1860
2056
  if (!items.length) return null;
1861
- return /* @__PURE__ */ React26.createElement(CloverMetadata, { metadata: items, ...rest });
2057
+ return /* @__PURE__ */ React29.createElement(CloverMetadata, { metadata: items, ...rest });
1862
2058
  }
1863
2059
  function RequiredStatement({ manifest, requiredStatement, ...rest }) {
1864
2060
  const stmt = requiredStatement || manifest && manifest.requiredStatement;
1865
2061
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
1866
2062
  return null;
1867
2063
  }
1868
- return /* @__PURE__ */ React26.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
2064
+ return /* @__PURE__ */ React29.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
1869
2065
  }
1870
2066
 
1871
2067
  // ui/src/docs/CodeBlock.jsx
1872
- import React27 from "react";
2068
+ import React30 from "react";
1873
2069
  function parseHighlightAttr(attr) {
1874
2070
  if (!attr) return /* @__PURE__ */ new Set();
1875
2071
  const cleaned = String(attr || "").trim();
@@ -1915,10 +2111,10 @@ var highlightBaseStyle = {
1915
2111
  };
1916
2112
  function DocsCodeBlock(props = {}) {
1917
2113
  const { children, ...rest } = props;
1918
- const childArray = React27.Children.toArray(children);
1919
- const codeElement = childArray.find((el) => React27.isValidElement(el));
2114
+ const childArray = React30.Children.toArray(children);
2115
+ const codeElement = childArray.find((el) => React30.isValidElement(el));
1920
2116
  if (!codeElement || !codeElement.props) {
1921
- return React27.createElement("pre", props);
2117
+ return React30.createElement("pre", props);
1922
2118
  }
1923
2119
  const {
1924
2120
  className = "",
@@ -1933,8 +2129,8 @@ function DocsCodeBlock(props = {}) {
1933
2129
  const highlightSet = parseHighlightAttr(highlightAttr);
1934
2130
  const copyAttr = codeProps["data-copy"];
1935
2131
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
1936
- const [copied, setCopied] = React27.useState(false);
1937
- const handleCopy = React27.useCallback(async () => {
2132
+ const [copied, setCopied] = React30.useState(false);
2133
+ const handleCopy = React30.useCallback(async () => {
1938
2134
  const text = rawCode;
1939
2135
  try {
1940
2136
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -1998,20 +2194,20 @@ function DocsCodeBlock(props = {}) {
1998
2194
  const highlight = highlightSet.has(lineNumber);
1999
2195
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
2000
2196
  const displayLine = line === "" ? " " : line;
2001
- return React27.createElement(
2197
+ return React30.createElement(
2002
2198
  "span",
2003
2199
  { key: lineNumber, style },
2004
- React27.createElement("span", { style: lineContentStyle }, displayLine)
2200
+ React30.createElement("span", { style: lineContentStyle }, displayLine)
2005
2201
  );
2006
2202
  });
2007
- return React27.createElement(
2203
+ return React30.createElement(
2008
2204
  "div",
2009
2205
  { style: containerStyle },
2010
- React27.createElement(
2206
+ React30.createElement(
2011
2207
  "div",
2012
2208
  { style: headerStyle },
2013
- React27.createElement("span", null, showFilename ? filename : null),
2014
- enableCopy ? React27.createElement(
2209
+ React30.createElement("span", null, showFilename ? filename : null),
2210
+ enableCopy ? React30.createElement(
2015
2211
  "button",
2016
2212
  {
2017
2213
  type: "button",
@@ -2030,19 +2226,19 @@ function DocsCodeBlock(props = {}) {
2030
2226
  copied ? "Copied" : "Copy"
2031
2227
  ) : null
2032
2228
  ),
2033
- React27.createElement(
2229
+ React30.createElement(
2034
2230
  "pre",
2035
2231
  { ...preRest, className: preClassName, style: mergedPreStyle },
2036
- React27.createElement("code", { style: codeStyle }, lineElements)
2232
+ React30.createElement("code", { style: codeStyle }, lineElements)
2037
2233
  )
2038
2234
  );
2039
2235
  }
2040
2236
 
2041
2237
  // ui/src/docs/MarkdownTable.jsx
2042
- import React28 from "react";
2238
+ import React31 from "react";
2043
2239
  function MarkdownTable({ className = "", ...rest }) {
2044
2240
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
2045
- return /* @__PURE__ */ React28.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React28.createElement("table", { className: merged, ...rest }));
2241
+ return /* @__PURE__ */ React31.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React31.createElement("table", { className: merged, ...rest }));
2046
2242
  }
2047
2243
  export {
2048
2244
  Button,
@@ -2060,6 +2256,8 @@ export {
2060
2256
  Label,
2061
2257
  Layout,
2062
2258
  Metadata,
2259
+ ReferencedItems,
2260
+ References,
2063
2261
  MdxRelatedItems as RelatedItems,
2064
2262
  RequiredStatement,
2065
2263
  Scroll,