@canopy-iiif/app 0.9.14 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ui/dist/index.mjs CHANGED
@@ -458,8 +458,7 @@ function SearchPanelForm(props = {}) {
458
458
  "data-canopy-search-form-trigger": "submit",
459
459
  className: "canopy-search-form__submit"
460
460
  },
461
- /* @__PURE__ */ React9.createElement("span", null, text),
462
- /* @__PURE__ */ React9.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React9.createElement("span", null, "\u2318"), /* @__PURE__ */ React9.createElement("span", null, "K"))
461
+ text
463
462
  )
464
463
  );
465
464
  }
@@ -793,7 +792,9 @@ function HeaderScript() {
793
792
  }
794
793
  function ensureArray(navLinks) {
795
794
  if (!Array.isArray(navLinks)) return [];
796
- return navLinks.filter((link) => link && typeof link === "object" && typeof link.href === "string");
795
+ return navLinks.filter(
796
+ (link) => link && typeof link === "object" && typeof link.href === "string"
797
+ );
797
798
  }
798
799
  function CanopyHeader(props = {}) {
799
800
  const {
@@ -806,59 +807,98 @@ function CanopyHeader(props = {}) {
806
807
  logo: SiteLogo
807
808
  } = props;
808
809
  const navLinks = ensureArray(navLinksProp);
809
- return /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement("header", { className: "canopy-header", "data-mobile-nav": "closed", "data-mobile-search": "closed" }, /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React14.createElement(
810
- CanopyBrand,
811
- {
812
- label: title,
813
- href: brandHref,
814
- className: "canopy-header__brand-link",
815
- Logo: SiteLogo
816
- }
817
- )), /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React14.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })), /* @__PURE__ */ React14.createElement("nav", { className: "canopy-nav-links canopy-header__desktop-nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React14.createElement("a", { key: link.href, href: link.href }, link.label || link.href))), /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React14.createElement(
818
- "button",
810
+ return /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(
811
+ "header",
819
812
  {
820
- type: "button",
821
- className: "canopy-header__icon-button canopy-header__search-trigger",
822
- "aria-label": "Open search",
823
- "aria-controls": "canopy-modal-search",
824
- "aria-expanded": "false",
825
- "data-canopy-header-toggle": "search"
813
+ className: "canopy-header",
814
+ "data-mobile-nav": "closed",
815
+ "data-mobile-search": "closed"
826
816
  },
817
+ /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React14.createElement(
818
+ CanopyBrand,
819
+ {
820
+ label: title,
821
+ href: brandHref,
822
+ className: "canopy-header__brand-link",
823
+ Logo: SiteLogo
824
+ }
825
+ )),
826
+ /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React14.createElement(
827
+ SearchPanel,
828
+ {
829
+ label: searchLabel,
830
+ hotkey: searchHotkey,
831
+ placeholder: searchPlaceholder
832
+ }
833
+ )),
827
834
  /* @__PURE__ */ React14.createElement(
828
- "svg",
835
+ "nav",
829
836
  {
830
- xmlns: "http://www.w3.org/2000/svg",
831
- viewBox: "0 0 24 24",
832
- fill: "none",
833
- stroke: "currentColor",
834
- strokeWidth: "1.5",
835
- className: "canopy-header__search-icon"
837
+ className: "canopy-nav-links canopy-header__desktop-nav",
838
+ "aria-label": "Primary navigation"
836
839
  },
837
- /* @__PURE__ */ React14.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-3.8-3.8M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z" })
838
- )
839
- ), /* @__PURE__ */ React14.createElement(
840
- "button",
841
- {
842
- type: "button",
843
- className: "canopy-header__icon-button canopy-header__menu",
844
- "aria-label": "Open navigation",
845
- "aria-controls": "canopy-modal-nav",
846
- "aria-expanded": "false",
847
- "data-canopy-header-toggle": "nav"
848
- },
849
- /* @__PURE__ */ React14.createElement(
850
- "svg",
840
+ navLinks.map((link) => /* @__PURE__ */ React14.createElement("a", { key: link.href, href: link.href }, link.label || link.href))
841
+ ),
842
+ /* @__PURE__ */ React14.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React14.createElement(
843
+ "button",
851
844
  {
852
- xmlns: "http://www.w3.org/2000/svg",
853
- fill: "none",
854
- viewBox: "0 0 24 24",
855
- strokeWidth: "1.5",
856
- stroke: "currentColor",
857
- className: "canopy-header__menu-icon"
845
+ type: "button",
846
+ className: "canopy-header__icon-button canopy-header__search-trigger",
847
+ "aria-label": "Open search",
848
+ "aria-controls": "canopy-modal-search",
849
+ "aria-expanded": "false",
850
+ "data-canopy-header-toggle": "search"
858
851
  },
859
- /* @__PURE__ */ React14.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" })
860
- )
861
- ))), /* @__PURE__ */ React14.createElement(
852
+ /* @__PURE__ */ React14.createElement(
853
+ "svg",
854
+ {
855
+ xmlns: "http://www.w3.org/2000/svg",
856
+ viewBox: "0 0 24 24",
857
+ fill: "none",
858
+ stroke: "currentColor",
859
+ strokeWidth: "1.5",
860
+ className: "canopy-header__search-icon"
861
+ },
862
+ /* @__PURE__ */ React14.createElement(
863
+ "path",
864
+ {
865
+ strokeLinecap: "round",
866
+ strokeLinejoin: "round",
867
+ d: "m21 21-3.8-3.8M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z"
868
+ }
869
+ )
870
+ )
871
+ ), /* @__PURE__ */ React14.createElement(
872
+ "button",
873
+ {
874
+ type: "button",
875
+ className: "canopy-header__icon-button canopy-header__menu",
876
+ "aria-label": "Open navigation",
877
+ "aria-controls": "canopy-modal-nav",
878
+ "aria-expanded": "false",
879
+ "data-canopy-header-toggle": "nav"
880
+ },
881
+ /* @__PURE__ */ React14.createElement(
882
+ "svg",
883
+ {
884
+ xmlns: "http://www.w3.org/2000/svg",
885
+ fill: "none",
886
+ viewBox: "0 0 24 24",
887
+ strokeWidth: "1.5",
888
+ stroke: "currentColor",
889
+ className: "canopy-header__menu-icon"
890
+ },
891
+ /* @__PURE__ */ React14.createElement(
892
+ "path",
893
+ {
894
+ strokeLinecap: "round",
895
+ strokeLinejoin: "round",
896
+ d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
897
+ }
898
+ )
899
+ )
900
+ ))
901
+ ), /* @__PURE__ */ React14.createElement(
862
902
  CanopyModal,
863
903
  {
864
904
  id: "canopy-modal-nav",
@@ -870,7 +910,14 @@ function CanopyHeader(props = {}) {
870
910
  closeLabel: "Close navigation",
871
911
  closeDataAttr: "nav"
872
912
  },
873
- /* @__PURE__ */ React14.createElement("nav", { className: "canopy-nav-links canopy-modal__nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React14.createElement("a", { key: link.href, href: link.href }, link.label || link.href)))
913
+ /* @__PURE__ */ React14.createElement(
914
+ "nav",
915
+ {
916
+ className: "canopy-nav-links canopy-modal__nav",
917
+ "aria-label": "Primary navigation"
918
+ },
919
+ navLinks.map((link) => /* @__PURE__ */ React14.createElement("a", { key: link.href, href: link.href }, link.label || link.href))
920
+ )
874
921
  ), /* @__PURE__ */ React14.createElement(
875
922
  CanopyModal,
876
923
  {
@@ -884,7 +931,14 @@ function CanopyHeader(props = {}) {
884
931
  closeDataAttr: "search",
885
932
  bodyClassName: "canopy-modal__body--search"
886
933
  },
887
- /* @__PURE__ */ React14.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })
934
+ /* @__PURE__ */ React14.createElement(
935
+ SearchPanel,
936
+ {
937
+ label: searchLabel,
938
+ hotkey: searchHotkey,
939
+ placeholder: searchPlaceholder
940
+ }
941
+ )
888
942
  ), /* @__PURE__ */ React14.createElement(HeaderScript, null));
889
943
  }
890
944
 
@@ -1038,8 +1092,45 @@ var Scroll = (props) => {
1038
1092
  return /* @__PURE__ */ React18.createElement(CloverScroll, { ...props });
1039
1093
  };
1040
1094
 
1095
+ // ui/src/iiif/Image.jsx
1096
+ import React19, { useEffect as useEffect5, useState as useState5 } from "react";
1097
+ var Image = (props) => {
1098
+ const [CloverImage, setCloverImage] = useState5(null);
1099
+ useEffect5(() => {
1100
+ let mounted = true;
1101
+ const canUseDom = typeof window !== "undefined" && typeof document !== "undefined";
1102
+ if (canUseDom) {
1103
+ import("@samvera/clover-iiif/image").then((mod) => {
1104
+ if (!mounted) return;
1105
+ const Comp = mod && (mod.default || mod.Image || mod);
1106
+ setCloverImage(() => Comp);
1107
+ }).catch(() => {
1108
+ });
1109
+ }
1110
+ return () => {
1111
+ mounted = false;
1112
+ };
1113
+ }, []);
1114
+ if (!CloverImage) {
1115
+ let json = "{}";
1116
+ try {
1117
+ json = JSON.stringify(props || {});
1118
+ } catch (_) {
1119
+ json = "{}";
1120
+ }
1121
+ return /* @__PURE__ */ React19.createElement("div", { "data-canopy-image": "1", className: "not-prose" }, /* @__PURE__ */ React19.createElement(
1122
+ "script",
1123
+ {
1124
+ type: "application/json",
1125
+ dangerouslySetInnerHTML: { __html: json }
1126
+ }
1127
+ ));
1128
+ }
1129
+ return /* @__PURE__ */ React19.createElement(CloverImage, { ...props });
1130
+ };
1131
+
1041
1132
  // ui/src/iiif/MdxRelatedItems.jsx
1042
- import React19 from "react";
1133
+ import React20 from "react";
1043
1134
  function MdxRelatedItems(props) {
1044
1135
  let json = "{}";
1045
1136
  try {
@@ -1047,11 +1138,11 @@ function MdxRelatedItems(props) {
1047
1138
  } catch (_) {
1048
1139
  json = "{}";
1049
1140
  }
1050
- return /* @__PURE__ */ React19.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React19.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1141
+ return /* @__PURE__ */ React20.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React20.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1051
1142
  }
1052
1143
 
1053
1144
  // ui/src/search/MdxSearchResults.jsx
1054
- import React20 from "react";
1145
+ import React21 from "react";
1055
1146
  function MdxSearchResults(props) {
1056
1147
  let json = "{}";
1057
1148
  try {
@@ -1059,11 +1150,11 @@ function MdxSearchResults(props) {
1059
1150
  } catch (_) {
1060
1151
  json = "{}";
1061
1152
  }
1062
- return /* @__PURE__ */ React20.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React20.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1153
+ return /* @__PURE__ */ React21.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React21.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1063
1154
  }
1064
1155
 
1065
1156
  // ui/src/search/SearchSummary.jsx
1066
- import React21 from "react";
1157
+ import React22 from "react";
1067
1158
  function SearchSummary(props) {
1068
1159
  let json = "{}";
1069
1160
  try {
@@ -1071,11 +1162,11 @@ function SearchSummary(props) {
1071
1162
  } catch (_) {
1072
1163
  json = "{}";
1073
1164
  }
1074
- return /* @__PURE__ */ React21.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React21.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1165
+ return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1075
1166
  }
1076
1167
 
1077
1168
  // ui/src/search/MdxSearchTabs.jsx
1078
- import React22 from "react";
1169
+ import React23 from "react";
1079
1170
  function MdxSearchTabs(props) {
1080
1171
  let json = "{}";
1081
1172
  try {
@@ -1083,11 +1174,11 @@ function MdxSearchTabs(props) {
1083
1174
  } catch (_) {
1084
1175
  json = "{}";
1085
1176
  }
1086
- return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1177
+ return /* @__PURE__ */ React23.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React23.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
1087
1178
  }
1088
1179
 
1089
1180
  // ui/src/search/SearchResults.jsx
1090
- import React23 from "react";
1181
+ import React24 from "react";
1091
1182
  function SearchResults({
1092
1183
  results = [],
1093
1184
  type = "all",
@@ -1095,19 +1186,19 @@ function SearchResults({
1095
1186
  query = ""
1096
1187
  }) {
1097
1188
  if (!results.length) {
1098
- return /* @__PURE__ */ React23.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React23.createElement("em", null, "No results"));
1189
+ return /* @__PURE__ */ React24.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React24.createElement("em", null, "No results"));
1099
1190
  }
1100
1191
  const normalizedType = String(type || "all").toLowerCase();
1101
1192
  const isAnnotationView = normalizedType === "annotation";
1102
1193
  if (isAnnotationView) {
1103
- return /* @__PURE__ */ React23.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1194
+ return /* @__PURE__ */ React24.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
1104
1195
  if (!r) return null;
1105
1196
  return renderTextCard(r, r.id || i);
1106
1197
  }));
1107
1198
  }
1108
1199
  const renderTextCard = (record, key) => {
1109
1200
  if (!record) return null;
1110
- return /* @__PURE__ */ React23.createElement(
1201
+ return /* @__PURE__ */ React24.createElement(
1111
1202
  TextCard,
1112
1203
  {
1113
1204
  key,
@@ -1123,20 +1214,20 @@ function SearchResults({
1123
1214
  const isWorkRecord = (record) => String(record && record.type).toLowerCase() === "work";
1124
1215
  const shouldRenderAsTextCard = (record) => !isWorkRecord(record) || normalizedType !== "work";
1125
1216
  if (layout === "list") {
1126
- return /* @__PURE__ */ React23.createElement("ul", { id: "search-results", className: "space-y-3" }, results.map((r, i) => {
1217
+ return /* @__PURE__ */ React24.createElement("ul", { id: "search-results", className: "space-y-3" }, results.map((r, i) => {
1127
1218
  if (shouldRenderAsTextCard(r)) {
1128
- return /* @__PURE__ */ React23.createElement("li", { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
1219
+ return /* @__PURE__ */ React24.createElement("li", { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
1129
1220
  }
1130
1221
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1131
1222
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1132
- return /* @__PURE__ */ React23.createElement(
1223
+ return /* @__PURE__ */ React24.createElement(
1133
1224
  "li",
1134
1225
  {
1135
1226
  key: i,
1136
1227
  className: `search-result ${r.type}`,
1137
1228
  "data-thumbnail-aspect-ratio": aspect
1138
1229
  },
1139
- /* @__PURE__ */ React23.createElement(
1230
+ /* @__PURE__ */ React24.createElement(
1140
1231
  Card,
1141
1232
  {
1142
1233
  href: r.href,
@@ -1150,20 +1241,20 @@ function SearchResults({
1150
1241
  );
1151
1242
  }));
1152
1243
  }
1153
- return /* @__PURE__ */ React23.createElement("div", { id: "search-results" }, /* @__PURE__ */ React23.createElement(Grid, null, results.map((r, i) => {
1244
+ return /* @__PURE__ */ React24.createElement("div", { id: "search-results" }, /* @__PURE__ */ React24.createElement(Grid, null, results.map((r, i) => {
1154
1245
  if (shouldRenderAsTextCard(r)) {
1155
- return /* @__PURE__ */ React23.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
1246
+ return /* @__PURE__ */ React24.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
1156
1247
  }
1157
1248
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
1158
1249
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
1159
- return /* @__PURE__ */ React23.createElement(
1250
+ return /* @__PURE__ */ React24.createElement(
1160
1251
  GridItem,
1161
1252
  {
1162
1253
  key: i,
1163
1254
  className: `search-result ${r.type}`,
1164
1255
  "data-thumbnail-aspect-ratio": aspect
1165
1256
  },
1166
- /* @__PURE__ */ React23.createElement(
1257
+ /* @__PURE__ */ React24.createElement(
1167
1258
  Card,
1168
1259
  {
1169
1260
  href: r.href,
@@ -1179,7 +1270,7 @@ function SearchResults({
1179
1270
  }
1180
1271
 
1181
1272
  // ui/src/search/SearchTabs.jsx
1182
- import React24 from "react";
1273
+ import React25 from "react";
1183
1274
  function SearchTabs({
1184
1275
  type = "all",
1185
1276
  onTypeChange,
@@ -1194,7 +1285,7 @@ function SearchTabs({
1194
1285
  const toLabel = (t) => t && t.length ? t.charAt(0).toUpperCase() + t.slice(1) : "";
1195
1286
  const hasFilters = typeof onOpenFilters === "function";
1196
1287
  const filterBadge = activeFilterCount > 0 ? ` (${activeFilterCount})` : "";
1197
- return /* @__PURE__ */ React24.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React24.createElement(
1288
+ return /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React25.createElement(
1198
1289
  "div",
1199
1290
  {
1200
1291
  role: "tablist",
@@ -1205,7 +1296,7 @@ function SearchTabs({
1205
1296
  const active = String(type).toLowerCase() === String(t).toLowerCase();
1206
1297
  const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
1207
1298
  const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
1208
- return /* @__PURE__ */ React24.createElement(
1299
+ return /* @__PURE__ */ React25.createElement(
1209
1300
  "button",
1210
1301
  {
1211
1302
  key: t,
@@ -1220,7 +1311,7 @@ function SearchTabs({
1220
1311
  ")"
1221
1312
  );
1222
1313
  })
1223
- ), hasFilters ? /* @__PURE__ */ React24.createElement(
1314
+ ), hasFilters ? /* @__PURE__ */ React25.createElement(
1224
1315
  "button",
1225
1316
  {
1226
1317
  type: "button",
@@ -1228,12 +1319,12 @@ function SearchTabs({
1228
1319
  "aria-expanded": filtersOpen ? "true" : "false",
1229
1320
  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"
1230
1321
  },
1231
- /* @__PURE__ */ React24.createElement("span", null, filtersLabel, filterBadge)
1322
+ /* @__PURE__ */ React25.createElement("span", null, filtersLabel, filterBadge)
1232
1323
  ) : null);
1233
1324
  }
1234
1325
 
1235
1326
  // ui/src/search/SearchFiltersDialog.jsx
1236
- import React25 from "react";
1327
+ import React26 from "react";
1237
1328
  function toArray(input) {
1238
1329
  if (!input) return [];
1239
1330
  if (Array.isArray(input)) return input;
@@ -1272,20 +1363,20 @@ function FacetSection({ facet, selected, onToggle }) {
1272
1363
  const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
1273
1364
  const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
1274
1365
  const hasSelection = selectedValues.size > 0;
1275
- const [quickQuery, setQuickQuery] = React25.useState("");
1366
+ const [quickQuery, setQuickQuery] = React26.useState("");
1276
1367
  const hasQuery = quickQuery.trim().length > 0;
1277
- const filteredValues = React25.useMemo(
1368
+ const filteredValues = React26.useMemo(
1278
1369
  () => facetMatches(values, quickQuery),
1279
1370
  [values, quickQuery]
1280
1371
  );
1281
- return /* @__PURE__ */ React25.createElement(
1372
+ return /* @__PURE__ */ React26.createElement(
1282
1373
  "details",
1283
1374
  {
1284
1375
  className: "canopy-search-filters__facet",
1285
1376
  open: hasSelection
1286
1377
  },
1287
- /* @__PURE__ */ React25.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React25.createElement("span", null, label), /* @__PURE__ */ React25.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
1288
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React25.createElement(
1378
+ /* @__PURE__ */ React26.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React26.createElement("span", null, label), /* @__PURE__ */ React26.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
1379
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React26.createElement(
1289
1380
  "input",
1290
1381
  {
1291
1382
  type: "search",
@@ -1295,7 +1386,7 @@ function FacetSection({ facet, selected, onToggle }) {
1295
1386
  className: "canopy-search-filters__quick-input",
1296
1387
  "aria-label": `Filter ${label} values`
1297
1388
  }
1298
- ), quickQuery ? /* @__PURE__ */ React25.createElement(
1389
+ ), quickQuery ? /* @__PURE__ */ React26.createElement(
1299
1390
  "button",
1300
1391
  {
1301
1392
  type: "button",
@@ -1303,11 +1394,11 @@ function FacetSection({ facet, selected, onToggle }) {
1303
1394
  className: "canopy-search-filters__quick-clear"
1304
1395
  },
1305
1396
  "Clear"
1306
- ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React25.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React25.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
1397
+ ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React26.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
1307
1398
  const valueSlug = String(entry.slug || entry.value || "");
1308
1399
  const isChecked = selectedValues.has(valueSlug);
1309
1400
  const inputId = checkboxId(valueSlug);
1310
- return /* @__PURE__ */ React25.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React25.createElement(
1401
+ return /* @__PURE__ */ React26.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React26.createElement(
1311
1402
  "input",
1312
1403
  {
1313
1404
  id: inputId,
@@ -1319,15 +1410,15 @@ function FacetSection({ facet, selected, onToggle }) {
1319
1410
  if (onToggle) onToggle(slug, valueSlug, nextChecked);
1320
1411
  }
1321
1412
  }
1322
- ), /* @__PURE__ */ React25.createElement(
1413
+ ), /* @__PURE__ */ React26.createElement(
1323
1414
  "label",
1324
1415
  {
1325
1416
  htmlFor: inputId,
1326
1417
  className: "canopy-search-filters__facet-label"
1327
1418
  },
1328
- /* @__PURE__ */ React25.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React25.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
1419
+ /* @__PURE__ */ React26.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React26.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
1329
1420
  ));
1330
- }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React25.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1421
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React26.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
1331
1422
  );
1332
1423
  }
1333
1424
  function SearchFiltersDialog(props = {}) {
@@ -1349,7 +1440,7 @@ function SearchFiltersDialog(props = {}) {
1349
1440
  (total, set) => total + set.size,
1350
1441
  0
1351
1442
  );
1352
- React25.useEffect(() => {
1443
+ React26.useEffect(() => {
1353
1444
  if (!open) return void 0;
1354
1445
  if (typeof document === "undefined") return void 0;
1355
1446
  const body = document.body;
@@ -1366,7 +1457,7 @@ function SearchFiltersDialog(props = {}) {
1366
1457
  if (!open) return null;
1367
1458
  const brandId = "canopy-modal-filters-label";
1368
1459
  const subtitleText = subtitle != null ? subtitle : title;
1369
- return /* @__PURE__ */ React25.createElement(
1460
+ return /* @__PURE__ */ React26.createElement(
1370
1461
  CanopyModal,
1371
1462
  {
1372
1463
  id: "canopy-modal-filters",
@@ -1381,8 +1472,8 @@ function SearchFiltersDialog(props = {}) {
1381
1472
  onBackgroundClick: () => onOpenChange && onOpenChange(false),
1382
1473
  bodyClassName: "canopy-modal__body--filters"
1383
1474
  },
1384
- subtitleText ? /* @__PURE__ */ React25.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
1385
- /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React25.createElement(
1475
+ subtitleText ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
1476
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React26.createElement(
1386
1477
  FacetSection,
1387
1478
  {
1388
1479
  key: facet.slug || facet.label,
@@ -1390,8 +1481,8 @@ function SearchFiltersDialog(props = {}) {
1390
1481
  selected: selectedMap,
1391
1482
  onToggle
1392
1483
  }
1393
- ))) : /* @__PURE__ */ React25.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
1394
- /* @__PURE__ */ React25.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React25.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React25.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React25.createElement(
1484
+ ))) : /* @__PURE__ */ React26.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
1485
+ /* @__PURE__ */ React26.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React26.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React26.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React26.createElement(
1395
1486
  "button",
1396
1487
  {
1397
1488
  type: "button",
@@ -1402,7 +1493,7 @@ function SearchFiltersDialog(props = {}) {
1402
1493
  className: "canopy-search-filters__button canopy-search-filters__button--secondary"
1403
1494
  },
1404
1495
  "Clear all"
1405
- ), /* @__PURE__ */ React25.createElement(
1496
+ ), /* @__PURE__ */ React26.createElement(
1406
1497
  "button",
1407
1498
  {
1408
1499
  type: "button",
@@ -1415,7 +1506,7 @@ function SearchFiltersDialog(props = {}) {
1415
1506
  }
1416
1507
 
1417
1508
  // ui/src/search-form/MdxSearchFormModal.jsx
1418
- import React26 from "react";
1509
+ import React27 from "react";
1419
1510
  function MdxSearchFormModal(props = {}) {
1420
1511
  const {
1421
1512
  placeholder = "Search\u2026",
@@ -1431,14 +1522,14 @@ function MdxSearchFormModal(props = {}) {
1431
1522
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1432
1523
  const resolvedSearchPath = resolveSearchPath(searchPath);
1433
1524
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
1434
- return /* @__PURE__ */ React26.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React26.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React26.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React26.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React26.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1525
+ return /* @__PURE__ */ React27.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React27.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React27.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React27.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React27.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1435
1526
  }
1436
1527
 
1437
1528
  // ui/src/docs/MarkdownTable.jsx
1438
- import React27 from "react";
1529
+ import React28 from "react";
1439
1530
  function MarkdownTable({ className = "", ...rest }) {
1440
1531
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
1441
- return /* @__PURE__ */ React27.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React27.createElement("table", { className: merged, ...rest }));
1532
+ return /* @__PURE__ */ React28.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React28.createElement("table", { className: merged, ...rest }));
1442
1533
  }
1443
1534
  export {
1444
1535
  Button,
@@ -1453,6 +1544,7 @@ export {
1453
1544
  Grid,
1454
1545
  GridItem,
1455
1546
  HelloWorld,
1547
+ Image,
1456
1548
  MdxRelatedItems as RelatedItems,
1457
1549
  Scroll,
1458
1550
  SearchFiltersDialog,