@canopy-iiif/app 1.5.8 → 1.5.10

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.
@@ -722,7 +722,7 @@ function Hero({
722
722
  const breadcrumbNode = isBreadcrumbVariant && breadcrumbItems.length ? /* @__PURE__ */ React9.createElement("nav", { className: "canopy-interstitial__breadcrumb", "aria-label": "Breadcrumb" }, breadcrumbItems.map((item2, idx) => {
723
723
  const isLast = idx === breadcrumbItems.length - 1;
724
724
  const key = `${item2.title || idx}-${idx}`;
725
- const content = !isLast && item2.href ? /* @__PURE__ */ React9.createElement("a", { href: item2.href }, item2.title) : /* @__PURE__ */ React9.createElement("span", { className: "canopy-interstitial__breadcrumb-current" }, item2.title);
725
+ const content = !isLast && item2.href ? /* @__PURE__ */ React9.createElement("a", { href: item2.href }, item2.title) : /* @__PURE__ */ React9.createElement("span", { className: "canopy-interstitial__breadcrumb-current", "aria-current": "page" }, item2.title);
726
726
  return /* @__PURE__ */ React9.createElement(React9.Fragment, { key }, idx > 0 ? /* @__PURE__ */ React9.createElement(
727
727
  "span",
728
728
  {
@@ -843,52 +843,140 @@ function Hero({
843
843
  }
844
844
 
845
845
  // ui/src/layout/SubNavigation.jsx
846
- import React10 from "react";
846
+ import React11 from "react";
847
847
  import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
848
- function resolveRelativeCandidate(page, current) {
849
- if (page && typeof page.relativePath === "string" && page.relativePath)
850
- return page.relativePath;
851
- if (page && typeof page.slug === "string" && page.slug) return page.slug;
852
- if (typeof current === "string" && current) return current;
853
- return "";
848
+
849
+ // ui/src/layout/NavigationTree.jsx
850
+ import React10 from "react";
851
+ function normalizeDepth(depth) {
852
+ if (typeof depth !== "number") return 0;
853
+ return Math.max(0, Math.min(5, depth));
854
854
  }
855
- function renderNodes(nodes, parentKey = "node") {
855
+ function NavigationTreeList({ nodes, depth, parentKey }) {
856
856
  if (!Array.isArray(nodes) || !nodes.length) return null;
857
- return nodes.map((node, index) => {
858
- if (!node) return null;
859
- const key = node.slug || node.relativePath || `${parentKey}-${index}`;
860
- const hasChildren = Array.isArray(node.children) && node.children.length > 0;
861
- const showChildren = hasChildren && (node.isExpanded || node.depth === 0);
862
- const depth = typeof node.depth === "number" ? Math.max(0, node.depth) : 0;
863
- const depthClass = `depth-${Math.min(depth, 5)}`;
864
- const isRoadmap = !!node.isRoadmap;
865
- const isInteractive = !!(node.href && !isRoadmap);
866
- const classes = ["canopy-sub-navigation__link", depthClass];
867
- if (!node.href && !isRoadmap) classes.push("is-label");
868
- if (isRoadmap) classes.push("is-disabled");
869
- if (node.isActive) classes.push("is-active");
870
- const linkClass = classes.join(" ");
871
- const Tag = isInteractive ? "a" : "span";
872
- const badge = isRoadmap ? /* @__PURE__ */ React10.createElement("span", { className: "canopy-sub-navigation__badge" }, "Roadmap") : null;
873
- return /* @__PURE__ */ React10.createElement("li", { key, className: "canopy-sub-navigation__item", "data-depth": depth }, /* @__PURE__ */ React10.createElement(
857
+ const listClasses = ["canopy-nav-tree__list"];
858
+ if (depth > 0) listClasses.push("canopy-nav-tree__list--nested");
859
+ return /* @__PURE__ */ React10.createElement("ul", { className: listClasses.join(" "), role: "list" }, nodes.map((node, index) => /* @__PURE__ */ React10.createElement(
860
+ NavigationTreeItem,
861
+ {
862
+ key: node.slug || node.href || node.title || `${parentKey}-${index}`,
863
+ node,
864
+ depth,
865
+ nodeKey: `${parentKey}-${index}`
866
+ }
867
+ )));
868
+ }
869
+ function NavigationTreeItem({ node, depth, nodeKey }) {
870
+ if (!node) return null;
871
+ const hasChildren = Array.isArray(node.children) && node.children.length > 0;
872
+ const isRoadmap = !!node.isRoadmap;
873
+ const isInteractive = !!(node.href && !isRoadmap);
874
+ const Tag = isInteractive ? "a" : "span";
875
+ const depthClass = `depth-${normalizeDepth(depth + 1)}`;
876
+ const classes = ["canopy-nav-tree__link", depthClass];
877
+ if (!isInteractive && !isRoadmap) classes.push("is-label");
878
+ if (isRoadmap) classes.push("is-disabled");
879
+ if (node.isActive) classes.push("is-active");
880
+ const isRootLevel = depth < 0;
881
+ const panelId = hasChildren ? `canopy-section-${nodeKey}` : null;
882
+ const allowToggle = hasChildren && !isRootLevel;
883
+ const defaultExpanded = allowToggle ? !!node.isExpanded : true;
884
+ const toggleLabel = node.title ? `Toggle ${node.title} menu` : "Toggle section menu";
885
+ return /* @__PURE__ */ React10.createElement(
886
+ "li",
887
+ {
888
+ className: "canopy-nav-tree__item",
889
+ "data-depth": depth,
890
+ "data-canopy-nav-item": allowToggle ? "true" : void 0,
891
+ "data-expanded": allowToggle ? defaultExpanded ? "true" : "false" : void 0,
892
+ "data-default-expanded": allowToggle && defaultExpanded ? "true" : void 0
893
+ },
894
+ /* @__PURE__ */ React10.createElement("div", { className: "canopy-nav-tree__row" }, /* @__PURE__ */ React10.createElement(
874
895
  Tag,
875
896
  {
876
- className: linkClass,
897
+ className: classes.join(" "),
877
898
  href: isInteractive ? node.href : void 0,
878
899
  "aria-current": node.isActive ? "page" : void 0,
879
900
  tabIndex: isInteractive ? void 0 : -1
880
901
  },
881
902
  node.title || node.slug,
882
- badge
883
- ), showChildren ? /* @__PURE__ */ React10.createElement(
884
- "ul",
903
+ isRoadmap ? /* @__PURE__ */ React10.createElement("span", { className: "canopy-nav-tree__badge" }, "Roadmap") : null
904
+ ), allowToggle ? /* @__PURE__ */ React10.createElement(
905
+ "button",
885
906
  {
886
- className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
887
- role: "list"
907
+ type: "button",
908
+ className: "canopy-nav-tree__toggle",
909
+ "aria-expanded": defaultExpanded ? "true" : "false",
910
+ "aria-controls": panelId || void 0,
911
+ "aria-label": toggleLabel,
912
+ "data-canopy-nav-item-toggle": panelId || void 0
888
913
  },
889
- renderNodes(node.children, key)
890
- ) : null);
891
- });
914
+ /* @__PURE__ */ React10.createElement(
915
+ "svg",
916
+ {
917
+ xmlns: "http://www.w3.org/2000/svg",
918
+ viewBox: "0 0 24 24",
919
+ fill: "none",
920
+ stroke: "currentColor",
921
+ strokeWidth: "1.5",
922
+ className: "canopy-nav-tree__toggle-icon"
923
+ },
924
+ /* @__PURE__ */ React10.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 9l7 7 7-7" })
925
+ ),
926
+ /* @__PURE__ */ React10.createElement("span", { className: "sr-only" }, toggleLabel)
927
+ ) : null),
928
+ hasChildren ? /* @__PURE__ */ React10.createElement(
929
+ "div",
930
+ {
931
+ id: panelId || void 0,
932
+ className: "canopy-nav-tree__children",
933
+ "aria-hidden": allowToggle ? defaultExpanded ? "false" : "true" : "false",
934
+ hidden: allowToggle ? !defaultExpanded : void 0
935
+ },
936
+ /* @__PURE__ */ React10.createElement(
937
+ NavigationTreeList,
938
+ {
939
+ nodes: node.children,
940
+ depth: depth + 1,
941
+ parentKey: nodeKey
942
+ }
943
+ )
944
+ ) : null
945
+ );
946
+ }
947
+ function NavigationTree({
948
+ root,
949
+ className = "",
950
+ parentKey = "nav",
951
+ includeRoot = false,
952
+ heading,
953
+ headingClassName = "canopy-nav-tree__heading",
954
+ component: Component = "div",
955
+ ...rest
956
+ }) {
957
+ if (!root) return null;
958
+ const nodes = includeRoot ? [root] : root.children;
959
+ if (!Array.isArray(nodes) || !nodes.length) return null;
960
+ const combinedClassName = ["canopy-nav-tree", className].filter(Boolean).join(" ");
961
+ return /* @__PURE__ */ React10.createElement(
962
+ Component,
963
+ {
964
+ className: combinedClassName,
965
+ "data-canopy-nav-tree": "true",
966
+ ...rest
967
+ },
968
+ heading ? /* @__PURE__ */ React10.createElement("div", { className: headingClassName }, heading) : null,
969
+ /* @__PURE__ */ React10.createElement(NavigationTreeList, { nodes, depth: includeRoot ? -1 : 0, parentKey })
970
+ );
971
+ }
972
+
973
+ // ui/src/layout/SubNavigation.jsx
974
+ function resolveRelativeCandidate(page, current) {
975
+ if (page && typeof page.relativePath === "string" && page.relativePath)
976
+ return page.relativePath;
977
+ if (page && typeof page.slug === "string" && page.slug) return page.slug;
978
+ if (typeof current === "string" && current) return current;
979
+ return "";
892
980
  }
893
981
  function SubNavigation({
894
982
  navigation: navigationProp,
@@ -900,12 +988,12 @@ function SubNavigation({
900
988
  ariaLabel
901
989
  }) {
902
990
  const PageContext = navigationHelpers2 && navigationHelpers2.getPageContext ? navigationHelpers2.getPageContext() : null;
903
- const context = PageContext ? React10.useContext(PageContext) : null;
991
+ const context = PageContext ? React11.useContext(PageContext) : null;
904
992
  const contextNavigation = context && context.navigation ? context.navigation : null;
905
993
  const contextPage = context && context.page ? context.page : null;
906
994
  const effectiveNavigation = navigationProp || contextNavigation;
907
995
  const effectivePage = page || contextPage;
908
- const resolvedNavigation = React10.useMemo(() => {
996
+ const resolvedNavigation = React11.useMemo(() => {
909
997
  if (effectiveNavigation && effectiveNavigation.root)
910
998
  return effectiveNavigation;
911
999
  const candidate = resolveRelativeCandidate(effectivePage, current);
@@ -930,24 +1018,33 @@ function SubNavigation({
930
1018
  if (!Object.prototype.hasOwnProperty.call(inlineStyle, "--sub-nav-indent")) {
931
1019
  inlineStyle["--sub-nav-indent"] = "0.85rem";
932
1020
  }
933
- return /* @__PURE__ */ React10.createElement(
1021
+ return /* @__PURE__ */ React11.createElement(
934
1022
  "nav",
935
1023
  {
936
1024
  className: combinedClassName,
937
1025
  style: inlineStyle,
938
1026
  "aria-label": navLabel
939
1027
  },
940
- finalHeading ? /* @__PURE__ */ React10.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null,
941
- /* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root"))
1028
+ /* @__PURE__ */ React11.createElement(
1029
+ NavigationTree,
1030
+ {
1031
+ root: rootNode,
1032
+ includeRoot: true,
1033
+ component: "div",
1034
+ className: "canopy-sub-navigation__tree",
1035
+ parentKey: rootNode.slug || "root",
1036
+ heading: finalHeading || void 0
1037
+ }
1038
+ )
942
1039
  );
943
1040
  }
944
1041
 
945
1042
  // ui/src/layout/Layout.jsx
946
- import React12 from "react";
1043
+ import React13 from "react";
947
1044
  import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
948
1045
 
949
1046
  // ui/src/layout/ContentNavigation.jsx
950
- import React11 from "react";
1047
+ import React12 from "react";
951
1048
  var SCROLL_OFFSET_REM = 1.618;
952
1049
  var MAX_HEADING_DEPTH = 3;
953
1050
  function depthIndex(depth) {
@@ -966,16 +1063,20 @@ function ContentNavigation({
966
1063
  ariaLabel
967
1064
  }) {
968
1065
  const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
969
- const savedDepthsRef = React11.useRef(null);
1066
+ const savedDepthsRef = React12.useRef(null);
1067
+ const [isExpanded, setIsExpanded] = React12.useState(false);
1068
+ const handleToggle = React12.useCallback(() => {
1069
+ setIsExpanded((prev) => !prev);
1070
+ }, []);
970
1071
  if ((!items || !items.length) && !headingId) return null;
971
1072
  const combinedClassName = [
972
1073
  "canopy-sub-navigation canopy-content-navigation",
973
- "canopy-content-navigation--collapsed",
1074
+ isExpanded ? "canopy-content-navigation--expanded" : "canopy-content-navigation--collapsed",
974
1075
  className
975
1076
  ].filter(Boolean).join(" ");
976
1077
  const effectiveHeading = heading || pageTitle || null;
977
1078
  const navLabel = ariaLabel || (effectiveHeading ? `${effectiveHeading} navigation` : "Section navigation");
978
- const getSavedDepth = React11.useCallback(
1079
+ const getSavedDepth = React12.useCallback(
979
1080
  (id, fallback) => {
980
1081
  if (!id) return fallback;
981
1082
  if (!savedDepthsRef.current) savedDepthsRef.current = /* @__PURE__ */ new Map();
@@ -986,7 +1087,7 @@ function ContentNavigation({
986
1087
  },
987
1088
  []
988
1089
  );
989
- const headingEntries = React11.useMemo(() => {
1090
+ const headingEntries = React12.useMemo(() => {
990
1091
  const entries = [];
991
1092
  const seen = /* @__PURE__ */ new Set();
992
1093
  if (headingId) {
@@ -1014,12 +1115,12 @@ function ContentNavigation({
1014
1115
  return entries;
1015
1116
  }, [headingId, items, getSavedDepth]);
1016
1117
  const fallbackId = headingEntries.length ? headingEntries[0].id : headingId || null;
1017
- const [activeId, setActiveId] = React11.useState(fallbackId);
1018
- const activeIdRef = React11.useRef(activeId);
1019
- React11.useEffect(() => {
1118
+ const [activeId, setActiveId] = React12.useState(fallbackId);
1119
+ const activeIdRef = React12.useRef(activeId);
1120
+ React12.useEffect(() => {
1020
1121
  activeIdRef.current = activeId;
1021
1122
  }, [activeId]);
1022
- React11.useEffect(() => {
1123
+ React12.useEffect(() => {
1023
1124
  if (!headingEntries.length) return;
1024
1125
  if (!headingEntries.some((entry) => entry.id === activeIdRef.current)) {
1025
1126
  const next = headingEntries[0].id;
@@ -1027,7 +1128,7 @@ function ContentNavigation({
1027
1128
  setActiveId(next);
1028
1129
  }
1029
1130
  }, [headingEntries]);
1030
- const computeOffsetPx = React11.useCallback(() => {
1131
+ const computeOffsetPx = React12.useCallback(() => {
1031
1132
  if (!isBrowser) return 0;
1032
1133
  try {
1033
1134
  const root = document.documentElement;
@@ -1037,8 +1138,8 @@ function ContentNavigation({
1037
1138
  return 0;
1038
1139
  }
1039
1140
  }, [isBrowser]);
1040
- const headingElementsRef = React11.useRef([]);
1041
- const updateActiveFromElements = React11.useCallback(
1141
+ const headingElementsRef = React12.useRef([]);
1142
+ const updateActiveFromElements = React12.useCallback(
1042
1143
  (elements) => {
1043
1144
  if (!elements || !elements.length) return;
1044
1145
  const offset = computeOffsetPx();
@@ -1058,7 +1159,7 @@ function ContentNavigation({
1058
1159
  },
1059
1160
  [computeOffsetPx]
1060
1161
  );
1061
- React11.useEffect(() => {
1162
+ React12.useEffect(() => {
1062
1163
  if (!isBrowser) return void 0;
1063
1164
  const elements = headingEntries.map((entry) => {
1064
1165
  const element = document.getElementById(entry.id);
@@ -1084,7 +1185,7 @@ function ContentNavigation({
1084
1185
  window.removeEventListener("resize", handle);
1085
1186
  };
1086
1187
  }, [headingEntries, isBrowser, updateActiveFromElements]);
1087
- const handleAnchorClick = React11.useCallback(
1188
+ const handleAnchorClick = React12.useCallback(
1088
1189
  (event, targetId, options = {}) => {
1089
1190
  var _a;
1090
1191
  try {
@@ -1115,7 +1216,7 @@ function ContentNavigation({
1115
1216
  },
1116
1217
  [computeOffsetPx, headingEntries, headingId, isBrowser]
1117
1218
  );
1118
- const renderNodes2 = React11.useCallback(
1219
+ const renderNodes = React12.useCallback(
1119
1220
  (nodes) => {
1120
1221
  if (!nodes || !nodes.length) return null;
1121
1222
  return nodes.map((node) => {
@@ -1128,8 +1229,8 @@ function ContentNavigation({
1128
1229
  if (depth > MAX_HEADING_DEPTH) return null;
1129
1230
  const idx = depthIndex(depth);
1130
1231
  const isActive = id && activeId === id;
1131
- const childNodes = depth < MAX_HEADING_DEPTH ? renderNodes2(node.children) : null;
1132
- return /* @__PURE__ */ React11.createElement("li", { key: id || node.title, className: "canopy-sub-navigation__item", "data-depth": idx }, /* @__PURE__ */ React11.createElement(
1232
+ const childNodes = depth < MAX_HEADING_DEPTH ? renderNodes(node.children) : null;
1233
+ return /* @__PURE__ */ React12.createElement("li", { key: id || node.title, className: "canopy-sub-navigation__item", "data-depth": idx }, /* @__PURE__ */ React12.createElement(
1133
1234
  "a",
1134
1235
  {
1135
1236
  className: `canopy-sub-navigation__link depth-${idx}${isActive ? " is-active" : ""}`,
@@ -1138,7 +1239,7 @@ function ContentNavigation({
1138
1239
  "aria-current": isActive ? "location" : void 0
1139
1240
  },
1140
1241
  node.title
1141
- ), childNodes ? /* @__PURE__ */ React11.createElement(
1242
+ ), childNodes ? /* @__PURE__ */ React12.createElement(
1142
1243
  "ul",
1143
1244
  {
1144
1245
  className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
@@ -1150,8 +1251,8 @@ function ContentNavigation({
1150
1251
  },
1151
1252
  [handleAnchorClick, activeId, getSavedDepth]
1152
1253
  );
1153
- const nestedItems = React11.useMemo(() => renderNodes2(items), [items, renderNodes2]);
1154
- const topLink = headingId ? /* @__PURE__ */ React11.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React11.createElement(
1254
+ const nestedItems = React12.useMemo(() => renderNodes(items), [items, renderNodes]);
1255
+ const topLink = headingId ? /* @__PURE__ */ React12.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React12.createElement(
1155
1256
  "a",
1156
1257
  {
1157
1258
  className: `canopy-sub-navigation__link depth-0${activeId === headingId ? " is-active" : ""}`,
@@ -1160,7 +1261,7 @@ function ContentNavigation({
1160
1261
  "aria-current": activeId === headingId ? "location" : void 0
1161
1262
  },
1162
1263
  effectiveHeading || pageTitle || headingId
1163
- ), nestedItems ? /* @__PURE__ */ React11.createElement(
1264
+ ), nestedItems ? /* @__PURE__ */ React12.createElement(
1164
1265
  "ul",
1165
1266
  {
1166
1267
  className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
@@ -1168,7 +1269,7 @@ function ContentNavigation({
1168
1269
  },
1169
1270
  nestedItems
1170
1271
  ) : null) : null;
1171
- return /* @__PURE__ */ React11.createElement(
1272
+ return /* @__PURE__ */ React12.createElement(
1172
1273
  "nav",
1173
1274
  {
1174
1275
  className: combinedClassName,
@@ -1176,23 +1277,24 @@ function ContentNavigation({
1176
1277
  "aria-label": navLabel,
1177
1278
  "data-canopy-content-nav": "true"
1178
1279
  },
1179
- /* @__PURE__ */ React11.createElement(
1280
+ /* @__PURE__ */ React12.createElement(
1180
1281
  "button",
1181
1282
  {
1182
1283
  type: "button",
1183
1284
  className: "canopy-content-navigation__toggle",
1184
- "aria-expanded": "false",
1185
- "aria-label": "Show section navigation",
1186
- title: "Show section navigation",
1285
+ "aria-expanded": isExpanded,
1286
+ "aria-label": isExpanded ? "Hide section navigation" : "Show section navigation",
1287
+ title: isExpanded ? "Hide section navigation" : "Show section navigation",
1288
+ onClick: handleToggle,
1187
1289
  "data-canopy-content-nav-toggle": "true",
1188
1290
  "data-show-label": "Show",
1189
1291
  "data-hide-label": "Hide",
1190
1292
  "data-show-full-label": "Show section navigation",
1191
1293
  "data-hide-full-label": "Hide section navigation"
1192
1294
  },
1193
- "Show"
1295
+ isExpanded ? "Hide" : "Show"
1194
1296
  ),
1195
- /* @__PURE__ */ React11.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, topLink || nestedItems)
1297
+ /* @__PURE__ */ React12.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, topLink || nestedItems)
1196
1298
  );
1197
1299
  }
1198
1300
 
@@ -1225,10 +1327,10 @@ function buildHeadingTree(headings) {
1225
1327
  }
1226
1328
  function buildNavigationAside(sidebar, className) {
1227
1329
  if (!sidebar) {
1228
- return /* @__PURE__ */ React12.createElement(SubNavigation, { className });
1330
+ return /* @__PURE__ */ React13.createElement(SubNavigation, { className });
1229
1331
  }
1230
1332
  if (typeof sidebar === "function") {
1231
- return React12.createElement(sidebar);
1333
+ return React13.createElement(sidebar);
1232
1334
  }
1233
1335
  return sidebar;
1234
1336
  }
@@ -1330,7 +1432,7 @@ function ContentNavigationScript() {
1330
1432
  });
1331
1433
  })();
1332
1434
  `;
1333
- return /* @__PURE__ */ React12.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
1435
+ return /* @__PURE__ */ React13.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
1334
1436
  }
1335
1437
  function Layout({
1336
1438
  children,
@@ -1345,26 +1447,26 @@ function Layout({
1345
1447
  ...rest
1346
1448
  }) {
1347
1449
  const PageContext = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
1348
- const context = PageContext ? React12.useContext(PageContext) : null;
1349
- const pageHeadings = React12.useMemo(() => {
1450
+ const context = PageContext ? React13.useContext(PageContext) : null;
1451
+ const pageHeadings = React13.useMemo(() => {
1350
1452
  const headings = context && context.page ? context.page.headings : null;
1351
1453
  return Array.isArray(headings) ? headings : [];
1352
1454
  }, [context]);
1353
- const contentHeading = React12.useMemo(() => {
1455
+ const contentHeading = React13.useMemo(() => {
1354
1456
  const first = pageHeadings.find((heading) => {
1355
1457
  const depth = heading && (heading.depth || heading.level);
1356
1458
  return depth === 1;
1357
1459
  });
1358
1460
  return first && first.title ? first.title : null;
1359
1461
  }, [pageHeadings]);
1360
- const headingAnchorId = React12.useMemo(() => {
1462
+ const headingAnchorId = React13.useMemo(() => {
1361
1463
  const first = pageHeadings.find((heading) => {
1362
1464
  const depth = heading && (heading.depth || heading.level);
1363
1465
  return depth === 1;
1364
1466
  });
1365
1467
  return first && first.id ? first.id : null;
1366
1468
  }, [pageHeadings]);
1367
- const headingTree = React12.useMemo(
1469
+ const headingTree = React13.useMemo(
1368
1470
  () => buildHeadingTree(pageHeadings),
1369
1471
  [pageHeadings]
1370
1472
  );
@@ -1389,13 +1491,13 @@ function Layout({
1389
1491
  contentNavigationClassName
1390
1492
  ].filter(Boolean).join(" ");
1391
1493
  const sidebarNode = showLeftColumn ? buildNavigationAside(sidebar, sidebarClassName) : null;
1392
- return /* @__PURE__ */ React12.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React12.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React12.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
1494
+ return /* @__PURE__ */ React13.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React13.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React13.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
1393
1495
  "aside",
1394
1496
  {
1395
1497
  className: contentNavigationAsideClassName,
1396
1498
  "data-canopy-content-nav-root": "true"
1397
1499
  },
1398
- /* @__PURE__ */ React12.createElement(
1500
+ /* @__PURE__ */ React13.createElement(
1399
1501
  ContentNavigation,
1400
1502
  {
1401
1503
  items: headingTree,
@@ -1404,21 +1506,21 @@ function Layout({
1404
1506
  pageTitle: context && context.page ? context.page.title : void 0
1405
1507
  }
1406
1508
  )
1407
- ), /* @__PURE__ */ React12.createElement(ContentNavigationScript, null)) : null);
1509
+ ), /* @__PURE__ */ React13.createElement(ContentNavigationScript, null)) : null);
1408
1510
  }
1409
1511
 
1410
1512
  // ui/src/layout/CanopyHeader.jsx
1411
- import React19 from "react";
1513
+ import React20 from "react";
1412
1514
 
1413
1515
  // ui/src/search/SearchPanel.jsx
1414
- import React16 from "react";
1516
+ import React17 from "react";
1415
1517
 
1416
1518
  // ui/src/Icons.jsx
1417
- import React13 from "react";
1418
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React13.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React13.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
1519
+ import React14 from "react";
1520
+ var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", "aria-hidden": "true", focusable: "false", ...props }, /* @__PURE__ */ React14.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
1419
1521
 
1420
1522
  // ui/src/search/SearchPanelForm.jsx
1421
- import React14 from "react";
1523
+ import React15 from "react";
1422
1524
  function readBasePath() {
1423
1525
  const normalize = (val) => {
1424
1526
  const raw = typeof val === "string" ? val.trim() : "";
@@ -1481,18 +1583,18 @@ function SearchPanelForm(props = {}) {
1481
1583
  clearLabel = "Clear search"
1482
1584
  } = props || {};
1483
1585
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1484
- const action = React14.useMemo(
1586
+ const action = React15.useMemo(
1485
1587
  () => resolveSearchPath(searchPath),
1486
1588
  [searchPath]
1487
1589
  );
1488
- const autoId = typeof React14.useId === "function" ? React14.useId() : void 0;
1489
- const [fallbackId] = React14.useState(
1590
+ const autoId = typeof React15.useId === "function" ? React15.useId() : void 0;
1591
+ const [fallbackId] = React15.useState(
1490
1592
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
1491
1593
  );
1492
1594
  const inputId = inputIdProp || autoId || fallbackId;
1493
- const inputRef = React14.useRef(null);
1494
- const [hasValue, setHasValue] = React14.useState(false);
1495
- const focusInput = React14.useCallback(() => {
1595
+ const inputRef = React15.useRef(null);
1596
+ const [hasValue, setHasValue] = React15.useState(false);
1597
+ const focusInput = React15.useCallback(() => {
1496
1598
  const el = inputRef.current;
1497
1599
  if (!el) return;
1498
1600
  if (document.activeElement === el) return;
@@ -1505,7 +1607,7 @@ function SearchPanelForm(props = {}) {
1505
1607
  }
1506
1608
  }
1507
1609
  }, []);
1508
- const handlePointerDown = React14.useCallback(
1610
+ const handlePointerDown = React15.useCallback(
1509
1611
  (event) => {
1510
1612
  const target = event.target;
1511
1613
  if (target && typeof target.closest === "function") {
@@ -1517,23 +1619,23 @@ function SearchPanelForm(props = {}) {
1517
1619
  },
1518
1620
  [focusInput]
1519
1621
  );
1520
- React14.useEffect(() => {
1622
+ React15.useEffect(() => {
1521
1623
  const el = inputRef.current;
1522
1624
  if (!el) return;
1523
1625
  if (el.value && el.value.trim()) {
1524
1626
  setHasValue(true);
1525
1627
  }
1526
1628
  }, []);
1527
- const handleInputChange = React14.useCallback((event) => {
1629
+ const handleInputChange = React15.useCallback((event) => {
1528
1630
  var _a;
1529
1631
  const nextHasValue = Boolean(
1530
1632
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
1531
1633
  );
1532
1634
  setHasValue(nextHasValue);
1533
1635
  }, []);
1534
- const handleClear = React14.useCallback((event) => {
1636
+ const handleClear = React15.useCallback((event) => {
1535
1637
  }, []);
1536
- const handleClearKey = React14.useCallback(
1638
+ const handleClearKey = React15.useCallback(
1537
1639
  (event) => {
1538
1640
  if (event.key === "Enter" || event.key === " ") {
1539
1641
  event.preventDefault();
@@ -1542,7 +1644,7 @@ function SearchPanelForm(props = {}) {
1542
1644
  },
1543
1645
  [handleClear]
1544
1646
  );
1545
- return /* @__PURE__ */ React14.createElement(
1647
+ return /* @__PURE__ */ React15.createElement(
1546
1648
  "form",
1547
1649
  {
1548
1650
  action,
@@ -1554,7 +1656,7 @@ function SearchPanelForm(props = {}) {
1554
1656
  onPointerDown: handlePointerDown,
1555
1657
  "data-has-value": hasValue ? "1" : "0"
1556
1658
  },
1557
- /* @__PURE__ */ React14.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React14.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React14.createElement(
1659
+ /* @__PURE__ */ React15.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React15.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React15.createElement("span", { className: "sr-only" }, "Search"), /* @__PURE__ */ React15.createElement(
1558
1660
  "input",
1559
1661
  {
1560
1662
  id: inputId,
@@ -1564,13 +1666,12 @@ function SearchPanelForm(props = {}) {
1564
1666
  "data-canopy-search-form-input": true,
1565
1667
  placeholder,
1566
1668
  className: "canopy-search-form__input",
1567
- "aria-label": "Search",
1568
1669
  ref: inputRef,
1569
1670
  onChange: handleInputChange,
1570
1671
  onInput: handleInputChange
1571
1672
  }
1572
1673
  )),
1573
- hasValue ? /* @__PURE__ */ React14.createElement(
1674
+ hasValue ? /* @__PURE__ */ React15.createElement(
1574
1675
  "button",
1575
1676
  {
1576
1677
  type: "button",
@@ -1583,7 +1684,7 @@ function SearchPanelForm(props = {}) {
1583
1684
  },
1584
1685
  "\xD7"
1585
1686
  ) : null,
1586
- /* @__PURE__ */ React14.createElement(
1687
+ /* @__PURE__ */ React15.createElement(
1587
1688
  "button",
1588
1689
  {
1589
1690
  type: "submit",
@@ -1596,11 +1697,11 @@ function SearchPanelForm(props = {}) {
1596
1697
  }
1597
1698
 
1598
1699
  // ui/src/search/SearchPanelTeaserResults.jsx
1599
- import React15 from "react";
1700
+ import React16 from "react";
1600
1701
  function SearchPanelTeaserResults(props = {}) {
1601
1702
  const { style, className } = props || {};
1602
1703
  const classes = ["canopy-search-teaser", "is-empty", className].filter(Boolean).join(" ");
1603
- return /* @__PURE__ */ React15.createElement(
1704
+ return /* @__PURE__ */ React16.createElement(
1604
1705
  "div",
1605
1706
  {
1606
1707
  "data-canopy-search-form-panel": true,
@@ -1608,7 +1709,7 @@ function SearchPanelTeaserResults(props = {}) {
1608
1709
  className: classes || void 0,
1609
1710
  style
1610
1711
  },
1611
- /* @__PURE__ */ React15.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
1712
+ /* @__PURE__ */ React16.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
1612
1713
  );
1613
1714
  }
1614
1715
 
@@ -1629,11 +1730,11 @@ function SearchPanel(props = {}) {
1629
1730
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
1630
1731
  const resolvedSearchPath = resolveSearchPath(searchPath);
1631
1732
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
1632
- return /* @__PURE__ */ React16.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React16.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React16.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React16.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1733
+ return /* @__PURE__ */ React17.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React17.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React17.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React17.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React17.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
1633
1734
  }
1634
1735
 
1635
1736
  // ui/src/layout/CanopyBrand.jsx
1636
- import React17 from "react";
1737
+ import React18 from "react";
1637
1738
  function CanopyBrand(props = {}) {
1638
1739
  const {
1639
1740
  labelId,
@@ -1644,11 +1745,11 @@ function CanopyBrand(props = {}) {
1644
1745
  } = props || {};
1645
1746
  const spanProps = labelId ? { id: labelId } : {};
1646
1747
  const classes = ["canopy-logo", className].filter(Boolean).join(" ");
1647
- return /* @__PURE__ */ React17.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React17.createElement(Logo, null) : null, /* @__PURE__ */ React17.createElement("span", { ...spanProps }, label));
1748
+ return /* @__PURE__ */ React18.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React18.createElement(Logo, null) : null, /* @__PURE__ */ React18.createElement("span", { ...spanProps }, label));
1648
1749
  }
1649
1750
 
1650
1751
  // ui/src/layout/CanopyModal.jsx
1651
- import React18 from "react";
1752
+ import React19 from "react";
1652
1753
  function CanopyModal(props = {}) {
1653
1754
  const {
1654
1755
  id,
@@ -1699,7 +1800,7 @@ function CanopyModal(props = {}) {
1699
1800
  if (padded) bodyClasses.push("canopy-modal__body--padded");
1700
1801
  if (bodyClassName) bodyClasses.push(bodyClassName);
1701
1802
  const bodyClassNameValue = bodyClasses.join(" ");
1702
- return /* @__PURE__ */ React18.createElement("div", { ...modalProps }, /* @__PURE__ */ React18.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React18.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React18.createElement(
1803
+ return /* @__PURE__ */ React19.createElement("div", { ...modalProps }, /* @__PURE__ */ React19.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React19.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React19.createElement(
1703
1804
  "svg",
1704
1805
  {
1705
1806
  xmlns: "http://www.w3.org/2000/svg",
@@ -1709,8 +1810,8 @@ function CanopyModal(props = {}) {
1709
1810
  strokeWidth: "1.5",
1710
1811
  className: "canopy-modal__close-icon"
1711
1812
  },
1712
- /* @__PURE__ */ React18.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
1713
- ), /* @__PURE__ */ React18.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React18.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React18.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React18.createElement(
1813
+ /* @__PURE__ */ React19.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
1814
+ ), /* @__PURE__ */ React19.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React19.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React19.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React19.createElement(
1714
1815
  CanopyBrand,
1715
1816
  {
1716
1817
  labelId: resolvedLabelId,
@@ -1732,11 +1833,24 @@ function HeaderScript() {
1732
1833
  var body = doc.body;
1733
1834
  var root = doc.documentElement;
1734
1835
 
1836
+ function desktopBreakpointQuery() {
1837
+ if (typeof window === 'undefined') return '(min-width: 70rem)';
1838
+ try {
1839
+ var styles = window.getComputedStyle ? window.getComputedStyle(root) : null;
1840
+ var value = styles ? styles.getPropertyValue('--canopy-desktop-breakpoint') : '';
1841
+ if (typeof value === 'string') value = value.trim();
1842
+ if (!value) value = '70rem';
1843
+ return '(min-width: ' + value + ')';
1844
+ } catch (error) {
1845
+ return '(min-width: 70rem)';
1846
+ }
1847
+ }
1848
+
1735
1849
  function ready(fn) {
1736
1850
  if (doc.readyState === 'loading') {
1737
1851
  doc.addEventListener('DOMContentLoaded', fn, { once: true });
1738
1852
  } else {
1739
- fn();
1853
+ fn();
1740
1854
  }
1741
1855
  }
1742
1856
 
@@ -1746,6 +1860,8 @@ function HeaderScript() {
1746
1860
 
1747
1861
  var NAV_ATTR = 'data-mobile-nav';
1748
1862
  var SEARCH_ATTR = 'data-mobile-search';
1863
+ var NAV_ITEM_ATTR = 'data-canopy-nav-item';
1864
+ var NAV_ITEM_TOGGLE_ATTR = 'data-canopy-nav-item-toggle';
1749
1865
 
1750
1866
  function modalFor(type) {
1751
1867
  return doc.querySelector('[data-canopy-modal="' + type + '"]');
@@ -1827,6 +1943,51 @@ function HeaderScript() {
1827
1943
  });
1828
1944
  }
1829
1945
 
1946
+ function forEachNavTree(scope, fn) {
1947
+ if (typeof fn !== 'function') return;
1948
+ var rootNode = scope || doc;
1949
+ var trees = rootNode.querySelectorAll('[data-canopy-nav-tree]');
1950
+ each(trees, function (tree) {
1951
+ fn(tree);
1952
+ });
1953
+ }
1954
+
1955
+ function resetNavItemToggles(scope) {
1956
+ forEachNavTree(scope, function (tree) {
1957
+ var toggles = tree.querySelectorAll('[' + NAV_ITEM_TOGGLE_ATTR + ']');
1958
+ each(toggles, function (btn) {
1959
+ btn.setAttribute('aria-expanded', 'false');
1960
+ var targetId = btn.getAttribute(NAV_ITEM_TOGGLE_ATTR);
1961
+ var panel = targetId ? doc.getElementById(targetId) : null;
1962
+ var parent = btn.closest('[' + NAV_ITEM_ATTR + ']');
1963
+ if (panel) {
1964
+ panel.hidden = true;
1965
+ panel.setAttribute('aria-hidden', 'true');
1966
+ panel.setAttribute('hidden', '');
1967
+ }
1968
+ if (parent) parent.setAttribute('data-expanded', 'false');
1969
+ });
1970
+ });
1971
+ }
1972
+
1973
+ function applyDefaultNavItemState(scope) {
1974
+ forEachNavTree(scope, function (tree) {
1975
+ var defaults = tree.querySelectorAll('[data-default-expanded="true"]');
1976
+ each(defaults, function (item) {
1977
+ var toggle = item.querySelector('[' + NAV_ITEM_TOGGLE_ATTR + ']');
1978
+ var targetId = toggle ? toggle.getAttribute(NAV_ITEM_TOGGLE_ATTR) : null;
1979
+ var panel = targetId ? doc.getElementById(targetId) : null;
1980
+ item.setAttribute('data-expanded', 'true');
1981
+ if (toggle) toggle.setAttribute('aria-expanded', 'true');
1982
+ if (panel) {
1983
+ panel.hidden = false;
1984
+ panel.removeAttribute('hidden');
1985
+ panel.setAttribute('aria-hidden', 'false');
1986
+ }
1987
+ });
1988
+ });
1989
+ }
1990
+
1830
1991
  function setState(type, next) {
1831
1992
  if (type === 'nav') header.setAttribute(NAV_ATTR, next);
1832
1993
  if (type === 'search') header.setAttribute(SEARCH_ATTR, next);
@@ -1834,6 +1995,13 @@ function HeaderScript() {
1834
1995
  var navOpen = header.getAttribute(NAV_ATTR) === 'open';
1835
1996
  var searchOpen = header.getAttribute(SEARCH_ATTR) === 'open';
1836
1997
  lockScroll(navOpen || searchOpen);
1998
+ if (type === 'nav') {
1999
+ if (next !== 'open') {
2000
+ resetNavItemToggles(modalFor('nav'));
2001
+ } else {
2002
+ applyDefaultNavItemState(modalFor('nav'));
2003
+ }
2004
+ }
1837
2005
  }
1838
2006
 
1839
2007
  function toggle(type, force) {
@@ -1846,6 +2014,35 @@ function HeaderScript() {
1846
2014
  if (type === 'nav' && shouldOpen) focusNavMenu();
1847
2015
  }
1848
2016
 
2017
+ function setupNavItemToggles() {
2018
+ var toggles = doc.querySelectorAll('[' + NAV_ITEM_TOGGLE_ATTR + ']');
2019
+ each(toggles, function (btn) {
2020
+ if (btn.__canopyNavReady) return;
2021
+ btn.__canopyNavReady = true;
2022
+ btn.addEventListener('click', function (event) {
2023
+ event.preventDefault();
2024
+ event.stopPropagation();
2025
+ var targetId = btn.getAttribute(NAV_ITEM_TOGGLE_ATTR);
2026
+ if (!targetId) return;
2027
+ var panel = doc.getElementById(targetId);
2028
+ var parent = btn.closest('[' + NAV_ITEM_ATTR + ']');
2029
+ var expanded = btn.getAttribute('aria-expanded') === 'true';
2030
+ var next = !expanded;
2031
+ btn.setAttribute('aria-expanded', next ? 'true' : 'false');
2032
+ if (panel) {
2033
+ panel.hidden = !next;
2034
+ panel.setAttribute('aria-hidden', next ? 'false' : 'true');
2035
+ if (next) {
2036
+ panel.removeAttribute('hidden');
2037
+ } else {
2038
+ panel.setAttribute('hidden', '');
2039
+ }
2040
+ }
2041
+ if (parent) parent.setAttribute('data-expanded', next ? 'true' : 'false');
2042
+ });
2043
+ });
2044
+ }
2045
+
1849
2046
  each(header.querySelectorAll('[data-canopy-header-toggle]'), function (btn) {
1850
2047
  btn.addEventListener('click', function (event) {
1851
2048
  event.preventDefault();
@@ -1893,7 +2090,7 @@ function HeaderScript() {
1893
2090
  toggle('search', false);
1894
2091
  });
1895
2092
 
1896
- var mq = window.matchMedia('(min-width: 48rem)');
2093
+ var mq = window.matchMedia(desktopBreakpointQuery());
1897
2094
  function syncDesktopState() {
1898
2095
  if (mq.matches) {
1899
2096
  setState('nav', 'closed');
@@ -1910,11 +2107,13 @@ function HeaderScript() {
1910
2107
  mq.addListener(syncDesktopState);
1911
2108
  }
1912
2109
 
2110
+ setupNavItemToggles();
2111
+ applyDefaultNavItemState(null);
1913
2112
  syncDesktopState();
1914
2113
  });
1915
2114
  })();
1916
2115
  `;
1917
- return /* @__PURE__ */ React19.createElement(
2116
+ return /* @__PURE__ */ React20.createElement(
1918
2117
  "script",
1919
2118
  {
1920
2119
  dangerouslySetInnerHTML: {
@@ -1933,7 +2132,7 @@ function getSharedRoot() {
1933
2132
  function getSafePageContext() {
1934
2133
  const root = getSharedRoot();
1935
2134
  if (root && root[CONTEXT_KEY]) return root[CONTEXT_KEY];
1936
- const ctx = React19.createContext({ navigation: null, page: null });
2135
+ const ctx = React20.createContext({ navigation: null, page: null });
1937
2136
  if (root) root[CONTEXT_KEY] = ctx;
1938
2137
  return ctx;
1939
2138
  }
@@ -1943,29 +2142,55 @@ function ensureArray(navLinks) {
1943
2142
  (link) => link && typeof link === "object" && typeof link.href === "string"
1944
2143
  );
1945
2144
  }
1946
- function SectionNavList({ root }) {
1947
- if (!root || !Array.isArray(root.children) || !root.children.length) return null;
1948
- return /* @__PURE__ */ React19.createElement("ul", { className: "canopy-modal__section-list", role: "list" }, root.children.map((node) => /* @__PURE__ */ React19.createElement(SectionNavItem, { key: node.slug || node.href || node.title, node, depth: 0 })));
1949
- }
1950
- function SectionNavItem({ node, depth }) {
1951
- if (!node) return null;
1952
- const hasChildren = Array.isArray(node.children) && node.children.length > 0;
1953
- const Tag = node.href ? "a" : "span";
1954
- const classes = [
1955
- "canopy-modal__section-link",
1956
- `depth-${Math.min(5, Math.max(0, depth + 1))}`
1957
- ];
1958
- if (!node.href) classes.push("is-label");
1959
- if (node.isActive) classes.push("is-active");
1960
- return /* @__PURE__ */ React19.createElement("li", { className: "canopy-modal__section-item", "data-depth": depth }, /* @__PURE__ */ React19.createElement(
1961
- Tag,
1962
- {
1963
- className: classes.join(" "),
1964
- href: node.href || void 0,
1965
- "aria-current": node.isActive ? "page" : void 0
1966
- },
1967
- node.title || node.slug
1968
- ), hasChildren ? /* @__PURE__ */ React19.createElement("ul", { className: "canopy-modal__section-list canopy-modal__section-list--nested", role: "list" }, node.children.map((child) => /* @__PURE__ */ React19.createElement(SectionNavItem, { key: child.slug || child.href || child.title, node: child, depth: depth + 1 }))) : null);
2145
+ function normalizeHref(href) {
2146
+ if (typeof href !== "string") return "";
2147
+ let next = href.trim();
2148
+ if (!next) return "";
2149
+ try {
2150
+ const parsed = new URL(next, "https://canopy.local");
2151
+ next = parsed.pathname || "/";
2152
+ } catch (_) {
2153
+ next = next.replace(/[?#].*$/, "");
2154
+ }
2155
+ next = next.replace(/[?#].*$/, "");
2156
+ if (next.length > 1) {
2157
+ next = next.replace(/\/+$/, "");
2158
+ }
2159
+ if (!next) return "/";
2160
+ return next;
2161
+ }
2162
+ function doesLinkMatchSection(linkHref, sectionNavigation) {
2163
+ if (!sectionNavigation || !sectionNavigation.root || !linkHref) return false;
2164
+ const normalizedLink = normalizeHref(linkHref);
2165
+ if (!normalizedLink) return false;
2166
+ const root = sectionNavigation.root;
2167
+ if (typeof root.href === "string" && normalizeHref(root.href) === normalizedLink) {
2168
+ return true;
2169
+ }
2170
+ if (root.slug) {
2171
+ const slugPath = normalizeHref(`/${root.slug}`);
2172
+ if (slugPath && normalizedLink === slugPath) {
2173
+ return true;
2174
+ }
2175
+ }
2176
+ return false;
2177
+ }
2178
+ function rootSegmentFromHref(href) {
2179
+ const normalized = normalizeHref(href);
2180
+ if (!normalized || normalized === "/") return "";
2181
+ const trimmed = normalized.replace(/^\/+/, "");
2182
+ return trimmed.split("/")[0] || "";
2183
+ }
2184
+ function getLinkNavigationData(link, navigationRoots, sectionNavigation) {
2185
+ if (!link || typeof link.href !== "string") return null;
2186
+ const segment = rootSegmentFromHref(link.href);
2187
+ if (navigationRoots && segment && navigationRoots[segment]) {
2188
+ return navigationRoots[segment];
2189
+ }
2190
+ if (sectionNavigation && doesLinkMatchSection(link.href, sectionNavigation)) {
2191
+ return sectionNavigation;
2192
+ }
2193
+ return null;
1969
2194
  }
1970
2195
  function CanopyHeader(props = {}) {
1971
2196
  const {
@@ -1979,20 +2204,34 @@ function CanopyHeader(props = {}) {
1979
2204
  } = props;
1980
2205
  const navLinks = ensureArray(navLinksProp);
1981
2206
  const PageContext = getSafePageContext();
1982
- const context = React19.useContext(PageContext);
1983
- const sectionNavigation = context && context.navigation && context.navigation.root ? context.navigation : null;
2207
+ const context = React20.useContext(PageContext);
2208
+ const contextNavigation = context && context.navigation ? context.navigation : null;
2209
+ const sectionNavigation = contextNavigation && contextNavigation.root ? contextNavigation : null;
2210
+ const navigationRoots = contextNavigation && contextNavigation.allRoots ? contextNavigation.allRoots : null;
1984
2211
  const sectionHeading = sectionNavigation && sectionNavigation.title || (sectionNavigation && sectionNavigation.root ? sectionNavigation.root.title : "");
1985
2212
  const hasSectionNav = !!(sectionNavigation && sectionNavigation.root && Array.isArray(sectionNavigation.root.children) && sectionNavigation.root.children.length);
1986
2213
  const sectionLabel = sectionHeading ? `More in ${sectionHeading}` : "More in this section";
1987
2214
  const sectionAriaLabel = sectionHeading ? `${sectionHeading} section navigation` : "Section navigation";
1988
- return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
2215
+ const defaultSectionLabel = sectionLabel;
2216
+ const defaultSectionAriaLabel = sectionAriaLabel;
2217
+ const shouldAttachSectionNav = (link) => {
2218
+ const navData = getLinkNavigationData(
2219
+ link,
2220
+ navigationRoots,
2221
+ sectionNavigation
2222
+ );
2223
+ const rootNode = navData && navData.root;
2224
+ return !!(rootNode && Array.isArray(rootNode.children) && rootNode.children.length);
2225
+ };
2226
+ const hasIntegratedSectionNav = navLinks.some(shouldAttachSectionNav);
2227
+ return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(
1989
2228
  "header",
1990
2229
  {
1991
2230
  className: "canopy-header",
1992
2231
  "data-mobile-nav": "closed",
1993
2232
  "data-mobile-search": "closed"
1994
2233
  },
1995
- /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React19.createElement(
2234
+ /* @__PURE__ */ React20.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React20.createElement(
1996
2235
  CanopyBrand,
1997
2236
  {
1998
2237
  label: title,
@@ -2001,7 +2240,7 @@ function CanopyHeader(props = {}) {
2001
2240
  Logo: SiteLogo
2002
2241
  }
2003
2242
  )),
2004
- /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React19.createElement(
2243
+ /* @__PURE__ */ React20.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React20.createElement(
2005
2244
  SearchPanel,
2006
2245
  {
2007
2246
  label: searchLabel,
@@ -2009,15 +2248,23 @@ function CanopyHeader(props = {}) {
2009
2248
  placeholder: searchPlaceholder
2010
2249
  }
2011
2250
  )),
2012
- /* @__PURE__ */ React19.createElement(
2251
+ /* @__PURE__ */ React20.createElement(
2013
2252
  "nav",
2014
2253
  {
2015
2254
  className: "canopy-nav-links canopy-header__desktop-nav",
2016
2255
  "aria-label": "Primary navigation"
2017
2256
  },
2018
- navLinks.map((link) => /* @__PURE__ */ React19.createElement("a", { key: link.href, href: link.href }, link.label || link.href))
2257
+ navLinks.map((link) => /* @__PURE__ */ React20.createElement(
2258
+ "a",
2259
+ {
2260
+ key: link.href,
2261
+ href: link.href,
2262
+ "aria-current": link.isActive ? "page" : void 0
2263
+ },
2264
+ link.label || link.href
2265
+ ))
2019
2266
  ),
2020
- /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React19.createElement(
2267
+ /* @__PURE__ */ React20.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React20.createElement(
2021
2268
  "button",
2022
2269
  {
2023
2270
  type: "button",
@@ -2027,7 +2274,7 @@ function CanopyHeader(props = {}) {
2027
2274
  "aria-expanded": "false",
2028
2275
  "data-canopy-header-toggle": "search"
2029
2276
  },
2030
- /* @__PURE__ */ React19.createElement(
2277
+ /* @__PURE__ */ React20.createElement(
2031
2278
  "svg",
2032
2279
  {
2033
2280
  xmlns: "http://www.w3.org/2000/svg",
@@ -2037,7 +2284,7 @@ function CanopyHeader(props = {}) {
2037
2284
  strokeWidth: "1.5",
2038
2285
  className: "canopy-header__search-icon"
2039
2286
  },
2040
- /* @__PURE__ */ React19.createElement(
2287
+ /* @__PURE__ */ React20.createElement(
2041
2288
  "path",
2042
2289
  {
2043
2290
  strokeLinecap: "round",
@@ -2046,7 +2293,7 @@ function CanopyHeader(props = {}) {
2046
2293
  }
2047
2294
  )
2048
2295
  )
2049
- ), /* @__PURE__ */ React19.createElement(
2296
+ ), /* @__PURE__ */ React20.createElement(
2050
2297
  "button",
2051
2298
  {
2052
2299
  type: "button",
@@ -2056,7 +2303,7 @@ function CanopyHeader(props = {}) {
2056
2303
  "aria-expanded": "false",
2057
2304
  "data-canopy-header-toggle": "nav"
2058
2305
  },
2059
- /* @__PURE__ */ React19.createElement(
2306
+ /* @__PURE__ */ React20.createElement(
2060
2307
  "svg",
2061
2308
  {
2062
2309
  xmlns: "http://www.w3.org/2000/svg",
@@ -2066,7 +2313,7 @@ function CanopyHeader(props = {}) {
2066
2313
  stroke: "currentColor",
2067
2314
  className: "canopy-header__menu-icon"
2068
2315
  },
2069
- /* @__PURE__ */ React19.createElement(
2316
+ /* @__PURE__ */ React20.createElement(
2070
2317
  "path",
2071
2318
  {
2072
2319
  strokeLinecap: "round",
@@ -2076,7 +2323,7 @@ function CanopyHeader(props = {}) {
2076
2323
  )
2077
2324
  )
2078
2325
  ))
2079
- ), /* @__PURE__ */ React19.createElement(
2326
+ ), /* @__PURE__ */ React20.createElement(
2080
2327
  CanopyModal,
2081
2328
  {
2082
2329
  id: "canopy-modal-nav",
@@ -2088,24 +2335,90 @@ function CanopyHeader(props = {}) {
2088
2335
  closeLabel: "Close navigation",
2089
2336
  closeDataAttr: "nav"
2090
2337
  },
2091
- /* @__PURE__ */ React19.createElement(
2338
+ /* @__PURE__ */ React20.createElement(
2092
2339
  "nav",
2093
2340
  {
2094
2341
  className: "canopy-nav-links canopy-modal__nav",
2095
2342
  "aria-label": "Primary navigation"
2096
2343
  },
2097
- navLinks.map((link) => /* @__PURE__ */ React19.createElement("a", { key: link.href, href: link.href }, link.label || link.href))
2344
+ /* @__PURE__ */ React20.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
2345
+ const navData = getLinkNavigationData(
2346
+ link,
2347
+ navigationRoots,
2348
+ sectionNavigation
2349
+ );
2350
+ const navRoot = navData && navData.root ? navData.root : null;
2351
+ const hasChildren = !!(navRoot && Array.isArray(navRoot.children) && navRoot.children.length);
2352
+ const nestedId = hasChildren ? `canopy-modal-section-${index}` : null;
2353
+ const toggleLabel = link.label ? `Toggle ${link.label} menu` : "Toggle section menu";
2354
+ const defaultExpanded = hasChildren && !!navRoot.isExpanded;
2355
+ return /* @__PURE__ */ React20.createElement(
2356
+ "li",
2357
+ {
2358
+ className: "canopy-modal__nav-item",
2359
+ key: link.href,
2360
+ "data-canopy-nav-item": hasChildren ? "true" : void 0,
2361
+ "data-expanded": defaultExpanded ? "true" : "false",
2362
+ "data-default-expanded": defaultExpanded ? "true" : void 0
2363
+ },
2364
+ /* @__PURE__ */ React20.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React20.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React20.createElement(
2365
+ "button",
2366
+ {
2367
+ type: "button",
2368
+ className: "canopy-modal__nav-toggle",
2369
+ "aria-expanded": defaultExpanded ? "true" : "false",
2370
+ "aria-controls": nestedId || void 0,
2371
+ "aria-label": toggleLabel,
2372
+ "data-canopy-nav-item-toggle": nestedId || void 0
2373
+ },
2374
+ /* @__PURE__ */ React20.createElement(
2375
+ "svg",
2376
+ {
2377
+ xmlns: "http://www.w3.org/2000/svg",
2378
+ viewBox: "0 0 24 24",
2379
+ fill: "none",
2380
+ stroke: "currentColor",
2381
+ strokeWidth: "1.5",
2382
+ className: "canopy-modal__nav-toggle-icon"
2383
+ },
2384
+ /* @__PURE__ */ React20.createElement(
2385
+ "path",
2386
+ {
2387
+ strokeLinecap: "round",
2388
+ strokeLinejoin: "round",
2389
+ d: "M5 9l7 7 7-7"
2390
+ }
2391
+ )
2392
+ ),
2393
+ /* @__PURE__ */ React20.createElement("span", { className: "sr-only" }, toggleLabel)
2394
+ ) : null),
2395
+ hasChildren ? /* @__PURE__ */ React20.createElement(
2396
+ NavigationTree,
2397
+ {
2398
+ root: navRoot,
2399
+ parentKey: navData && navData.rootSegment ? navData.rootSegment : `root-${index}`,
2400
+ component: "div",
2401
+ className: "canopy-modal__section-nav canopy-modal__section-nav--nested",
2402
+ "aria-label": navData && navData.title ? `${navData.title} section navigation` : defaultSectionAriaLabel,
2403
+ "aria-hidden": defaultExpanded ? "false" : "true",
2404
+ hidden: !defaultExpanded,
2405
+ id: nestedId || void 0
2406
+ }
2407
+ ) : null
2408
+ );
2409
+ }))
2098
2410
  ),
2099
- hasSectionNav ? /* @__PURE__ */ React19.createElement(
2100
- "nav",
2411
+ hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React20.createElement(
2412
+ NavigationTree,
2101
2413
  {
2414
+ root: sectionNavigation.root,
2415
+ component: "nav",
2102
2416
  className: "canopy-modal__section-nav",
2103
- "aria-label": sectionAriaLabel
2104
- },
2105
- /* @__PURE__ */ React19.createElement("div", { className: "canopy-modal__section-label" }, sectionLabel),
2106
- /* @__PURE__ */ React19.createElement(SectionNavList, { root: sectionNavigation.root })
2417
+ "aria-label": defaultSectionAriaLabel,
2418
+ parentKey: "fallback-nav"
2419
+ }
2107
2420
  ) : null
2108
- ), /* @__PURE__ */ React19.createElement(
2421
+ ), /* @__PURE__ */ React20.createElement(
2109
2422
  CanopyModal,
2110
2423
  {
2111
2424
  id: "canopy-modal-search",
@@ -2118,7 +2431,7 @@ function CanopyHeader(props = {}) {
2118
2431
  closeDataAttr: "search",
2119
2432
  bodyClassName: "canopy-modal__body--search"
2120
2433
  },
2121
- /* @__PURE__ */ React19.createElement(
2434
+ /* @__PURE__ */ React20.createElement(
2122
2435
  SearchPanel,
2123
2436
  {
2124
2437
  label: searchLabel,
@@ -2126,18 +2439,18 @@ function CanopyHeader(props = {}) {
2126
2439
  placeholder: searchPlaceholder
2127
2440
  }
2128
2441
  )
2129
- ), /* @__PURE__ */ React19.createElement(HeaderScript, null));
2442
+ ), /* @__PURE__ */ React20.createElement(HeaderScript, null));
2130
2443
  }
2131
2444
 
2132
2445
  // ui/src/layout/CanopyFooter.jsx
2133
- import React20 from "react";
2446
+ import React21 from "react";
2134
2447
  function CanopyFooter({ className = "", children }) {
2135
2448
  const footerClassName = ["canopy-footer", className].filter(Boolean).join(" ");
2136
- return /* @__PURE__ */ React20.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React20.createElement("div", { className: "canopy-footer__inner" }, children));
2449
+ return /* @__PURE__ */ React21.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React21.createElement("div", { className: "canopy-footer__inner" }, children));
2137
2450
  }
2138
2451
 
2139
2452
  // ui/src/layout/TeaserCard.jsx
2140
- import React21 from "react";
2453
+ import React22 from "react";
2141
2454
  function TeaserCard({
2142
2455
  href = "",
2143
2456
  title = "",
@@ -2158,7 +2471,7 @@ function TeaserCard({
2158
2471
  ].filter(Boolean).join(" ");
2159
2472
  const showThumb = type === "work" && thumbnail;
2160
2473
  const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
2161
- return /* @__PURE__ */ React21.createElement(
2474
+ return /* @__PURE__ */ React22.createElement(
2162
2475
  Tag,
2163
2476
  {
2164
2477
  className: classes,
@@ -2166,21 +2479,22 @@ function TeaserCard({
2166
2479
  "data-canopy-item": href ? "" : void 0,
2167
2480
  ...rest
2168
2481
  },
2169
- showThumb ? /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React21.createElement(
2482
+ showThumb ? /* @__PURE__ */ React22.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React22.createElement(
2170
2483
  "img",
2171
2484
  {
2172
2485
  src: thumbnail,
2173
2486
  alt: "",
2487
+ "aria-hidden": "true",
2174
2488
  loading: "lazy",
2175
2489
  className: "canopy-search-teaser__thumb-img"
2176
2490
  }
2177
2491
  )) : null,
2178
- /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
2492
+ /* @__PURE__ */ React22.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React22.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React22.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
2179
2493
  );
2180
2494
  }
2181
2495
 
2182
2496
  // ui/src/layout/GoogleAnalytics.jsx
2183
- import React22 from "react";
2497
+ import React23 from "react";
2184
2498
  var GA_HOST = "https://www.googletagmanager.com/gtag/js";
2185
2499
  function GoogleAnalytics({ id }) {
2186
2500
  if (!id) return null;
@@ -2190,11 +2504,11 @@ function GoogleAnalytics({ id }) {
2190
2504
  gtag('js', new Date());
2191
2505
  gtag('config', '${id}');
2192
2506
  `;
2193
- return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React22.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
2507
+ return /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React23.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
2194
2508
  }
2195
2509
 
2196
2510
  // ui/src/layout/Container.jsx
2197
- import React23 from "react";
2511
+ import React24 from "react";
2198
2512
  function Container({
2199
2513
  className = "",
2200
2514
  variant = "content",
@@ -2203,7 +2517,7 @@ function Container({
2203
2517
  }) {
2204
2518
  const variantClass = variant === "wide" ? "max-w-wide" : "max-w-content";
2205
2519
  const classes = ["mx-auto", variantClass, "w-full", className].filter(Boolean).join(" ");
2206
- return /* @__PURE__ */ React23.createElement(
2520
+ return /* @__PURE__ */ React24.createElement(
2207
2521
  "div",
2208
2522
  {
2209
2523
  className: classes,
@@ -2215,7 +2529,7 @@ function Container({
2215
2529
  }
2216
2530
 
2217
2531
  // ui/src/layout/Card.jsx
2218
- import React24, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
2532
+ import React25, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
2219
2533
  var DEFAULT_CARD_ASPECT_RATIO = 4 / 3;
2220
2534
  function Card({
2221
2535
  href,
@@ -2279,8 +2593,8 @@ function Card({
2279
2593
  const hasDimensions = Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0;
2280
2594
  const ratio = hasAspectRatio ? Number(aspectRatio) : hasDimensions ? w / h : src ? DEFAULT_CARD_ASPECT_RATIO : void 0;
2281
2595
  const paddingPercent = ratio ? 100 / ratio : 100;
2282
- const caption = /* @__PURE__ */ React24.createElement("figcaption", null, title && /* @__PURE__ */ React24.createElement("span", null, title), subtitle && /* @__PURE__ */ React24.createElement("span", null, subtitle), children);
2283
- return /* @__PURE__ */ React24.createElement(
2596
+ const caption = /* @__PURE__ */ React25.createElement("figcaption", null, title && /* @__PURE__ */ React25.createElement("span", null, title), subtitle && /* @__PURE__ */ React25.createElement("span", null, subtitle), children);
2597
+ return /* @__PURE__ */ React25.createElement(
2284
2598
  "a",
2285
2599
  {
2286
2600
  href,
@@ -2292,27 +2606,29 @@ function Card({
2292
2606
  "data-image-loaded": imageLoaded ? "true" : "false",
2293
2607
  ...rest
2294
2608
  },
2295
- /* @__PURE__ */ React24.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React24.createElement(
2609
+ /* @__PURE__ */ React25.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React25.createElement(
2296
2610
  "div",
2297
2611
  {
2298
2612
  className: "canopy-card-media",
2299
2613
  style: { "--canopy-card-padding": `${paddingPercent}%` }
2300
2614
  },
2301
- inView ? /* @__PURE__ */ React24.createElement(
2615
+ inView ? /* @__PURE__ */ React25.createElement(
2302
2616
  "img",
2303
2617
  {
2304
2618
  src,
2305
2619
  alt: alt || title || "",
2620
+ "aria-hidden": !alt && !title ? "true" : void 0,
2306
2621
  loading: "lazy",
2307
2622
  onLoad: () => setImageLoaded(true),
2308
2623
  onError: () => setImageLoaded(true)
2309
2624
  }
2310
2625
  ) : null
2311
- ) : /* @__PURE__ */ React24.createElement(
2626
+ ) : /* @__PURE__ */ React25.createElement(
2312
2627
  "img",
2313
2628
  {
2314
2629
  src,
2315
2630
  alt: alt || title || "",
2631
+ "aria-hidden": !alt && !title ? "true" : void 0,
2316
2632
  loading: "lazy",
2317
2633
  onLoad: () => setImageLoaded(true),
2318
2634
  onError: () => setImageLoaded(true),
@@ -2323,13 +2639,13 @@ function Card({
2323
2639
  }
2324
2640
 
2325
2641
  // ui/src/content/ReferencedItems.jsx
2326
- import React25 from "react";
2642
+ import React26 from "react";
2327
2643
  import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
2328
2644
  function useReferencedItems(itemsProp) {
2329
2645
  if (Array.isArray(itemsProp)) return itemsProp;
2330
2646
  const PageContext = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
2331
2647
  if (!PageContext) return [];
2332
- const context = React25.useContext(PageContext);
2648
+ const context = React26.useContext(PageContext);
2333
2649
  const items = context && context.page ? context.page.referencedItems : null;
2334
2650
  return Array.isArray(items) ? items : [];
2335
2651
  }
@@ -2349,13 +2665,13 @@ function ReferencedItems({
2349
2665
  "referenced-items--empty",
2350
2666
  className
2351
2667
  ].filter(Boolean).join(" ");
2352
- return /* @__PURE__ */ React25.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
2668
+ return /* @__PURE__ */ React26.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
2353
2669
  }
2354
2670
  const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
2355
- return /* @__PURE__ */ React25.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React25.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
2671
+ return /* @__PURE__ */ React26.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React26.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
2356
2672
  if (!item) return null;
2357
2673
  const key = item.href || item.slug || item.id;
2358
- return /* @__PURE__ */ React25.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React25.createElement(
2674
+ return /* @__PURE__ */ React26.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React26.createElement(
2359
2675
  Card,
2360
2676
  {
2361
2677
  href: item.href,
@@ -2372,7 +2688,7 @@ function ReferencedItems({
2372
2688
  }
2373
2689
 
2374
2690
  // ui/src/content/References.jsx
2375
- import React26 from "react";
2691
+ import React27 from "react";
2376
2692
  import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
2377
2693
  import referenced from "@canopy-iiif/app/lib/components/referenced.js";
2378
2694
  function getPageContext() {
@@ -2403,7 +2719,7 @@ function References({
2403
2719
  ...rest
2404
2720
  }) {
2405
2721
  const PageContext = getPageContext();
2406
- const context = PageContext ? React26.useContext(PageContext) : null;
2722
+ const context = PageContext ? React27.useContext(PageContext) : null;
2407
2723
  const contextPage = context && context.page ? context.page : null;
2408
2724
  const manifestId = id || contextPage && contextPage.manifestId || "";
2409
2725
  const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
@@ -2412,11 +2728,11 @@ function References({
2412
2728
  const entries = references && references.length ? references : null;
2413
2729
  if (!entries || !entries.length) return null;
2414
2730
  const containerClass = ["references", className].filter(Boolean).join(" ");
2415
- return /* @__PURE__ */ React26.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React26.createElement("div", { className: "references__group" }, /* @__PURE__ */ React26.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React26.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React26.createElement("a", { href: entry.href }, entry.title || entry.href)))));
2731
+ return /* @__PURE__ */ React27.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React27.createElement("div", { className: "references__group" }, /* @__PURE__ */ React27.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React27.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React27.createElement("a", { href: entry.href }, entry.title || entry.href)))));
2416
2732
  }
2417
2733
 
2418
2734
  // ui/src/content/Bibliography.jsx
2419
- import React27 from "react";
2735
+ import React28 from "react";
2420
2736
  import bibliography from "@canopy-iiif/app/lib/components/bibliography.js";
2421
2737
  function resolveHeadingTag(tag, fallback) {
2422
2738
  if (typeof tag === "string" && tag.trim()) return tag;
@@ -2426,7 +2742,7 @@ function resolveHeadingTag(tag, fallback) {
2426
2742
  function NoteBody({ note }) {
2427
2743
  if (!note) return null;
2428
2744
  if (note.html) {
2429
- return /* @__PURE__ */ React27.createElement(
2745
+ return /* @__PURE__ */ React28.createElement(
2430
2746
  "div",
2431
2747
  {
2432
2748
  className: "bibliography__note-body",
@@ -2435,7 +2751,7 @@ function NoteBody({ note }) {
2435
2751
  );
2436
2752
  }
2437
2753
  if (note.text) {
2438
- return /* @__PURE__ */ React27.createElement("div", { className: "bibliography__note-body" }, note.text);
2754
+ return /* @__PURE__ */ React28.createElement("div", { className: "bibliography__note-body" }, note.text);
2439
2755
  }
2440
2756
  return null;
2441
2757
  }
@@ -2453,22 +2769,22 @@ function Bibliography({
2453
2769
  if (!entries.length) return null;
2454
2770
  const PageHeadingTag = resolveHeadingTag(pageHeadingTag, "h3");
2455
2771
  const rootClass = ["bibliography", className].filter(Boolean).join(" ");
2456
- return /* @__PURE__ */ React27.createElement("section", { className: rootClass }, /* @__PURE__ */ React27.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
2772
+ return /* @__PURE__ */ React28.createElement("section", { className: rootClass }, /* @__PURE__ */ React28.createElement("div", { className: "bibliography__pages" }, entries.map((entry) => {
2457
2773
  const key = entry.href || entry.relativePath || entry.title;
2458
2774
  const pageTitle = entry.title || entry.href;
2459
- return /* @__PURE__ */ React27.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React27.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React27.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React27.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React27.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
2775
+ return /* @__PURE__ */ React28.createElement("article", { key, className: "bibliography__page" }, /* @__PURE__ */ React28.createElement("header", { className: "bibliography__page-header" }, pageTitle ? /* @__PURE__ */ React28.createElement(PageHeadingTag, { className: "bibliography__page-title" }, pageTitle) : null, entry.href ? /* @__PURE__ */ React28.createElement("a", { className: "bibliography__page-link", href: entry.href }, entry.href) : null), /* @__PURE__ */ React28.createElement("ol", { className: "bibliography__notes" }, (entry.footnotes || []).map((note, idx) => {
2460
2776
  const noteKey = `${key || "entry"}-${note.identifier || idx}`;
2461
- return /* @__PURE__ */ React27.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React27.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React27.createElement(NoteBody, { note }));
2777
+ return /* @__PURE__ */ React28.createElement("li", { key: noteKey, className: "bibliography__note" }, note.identifier ? /* @__PURE__ */ React28.createElement("span", { className: "bibliography__note-label" }, note.identifier) : null, /* @__PURE__ */ React28.createElement(NoteBody, { note }));
2462
2778
  })));
2463
2779
  })));
2464
2780
  }
2465
2781
 
2466
2782
  // ui/src/content/timeline/MdxTimeline.jsx
2467
- import React31 from "react";
2783
+ import React32 from "react";
2468
2784
  import ReactDOMServer from "react-dom/server";
2469
2785
 
2470
2786
  // ui/src/content/timeline/Timeline.jsx
2471
- import React29 from "react";
2787
+ import React30 from "react";
2472
2788
 
2473
2789
  // ui/src/content/timeline/date-utils.js
2474
2790
  var FALLBACK_LOCALE = (() => {
@@ -2629,7 +2945,7 @@ function clampProgress(value) {
2629
2945
  }
2630
2946
 
2631
2947
  // ui/src/layout/ReferencedManifestCard.jsx
2632
- import React28 from "react";
2948
+ import React29 from "react";
2633
2949
  function normalizeMetadata(metadata, summary) {
2634
2950
  if (Array.isArray(metadata) && metadata.length) {
2635
2951
  return metadata.filter(Boolean);
@@ -2663,7 +2979,7 @@ function ReferencedManifestCard({
2663
2979
  "canopy-referenced-manifest-card",
2664
2980
  className
2665
2981
  ].filter(Boolean).join(" ");
2666
- return /* @__PURE__ */ React28.createElement(
2982
+ return /* @__PURE__ */ React29.createElement(
2667
2983
  TeaserCard,
2668
2984
  {
2669
2985
  href: resolvedHref || void 0,
@@ -2845,14 +3161,14 @@ function TimelineConnector({ side, isActive, highlight }) {
2845
3161
  "canopy-timeline__connector-dot",
2846
3162
  highlight || isActive ? "is-active" : ""
2847
3163
  ].filter(Boolean).join(" ");
2848
- return /* @__PURE__ */ React29.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React29.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement("span", { className: dotClasses }), /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__connector-line" })));
3164
+ return /* @__PURE__ */ React30.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React30.createElement(React30.Fragment, null, /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React30.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React30.createElement(React30.Fragment, null, /* @__PURE__ */ React30.createElement("span", { className: dotClasses }), /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__connector-line" })));
2849
3165
  }
2850
3166
  function renderResourceSection(point) {
2851
3167
  if (!point) return null;
2852
3168
  const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
2853
3169
  const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2854
3170
  if (!manifestCards.length && !legacyResources.length) return null;
2855
- return /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React29.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React29.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React29.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React29.createElement(
3171
+ return /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React30.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React30.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React30.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React30.createElement(
2856
3172
  TeaserCard,
2857
3173
  {
2858
3174
  href: resource.href,
@@ -2877,26 +3193,26 @@ function Timeline({
2877
3193
  ...rest
2878
3194
  }) {
2879
3195
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
2880
- const rawPoints = React29.useMemo(() => {
3196
+ const rawPoints = React30.useMemo(() => {
2881
3197
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
2882
3198
  if (payloadPoints && payloadPoints.length) return payloadPoints;
2883
3199
  return [];
2884
3200
  }, [pointsProp, payloadPoints]);
2885
- const sanitizedPoints = React29.useMemo(
3201
+ const sanitizedPoints = React30.useMemo(
2886
3202
  () => sanitizePoints(rawPoints),
2887
3203
  [rawPoints]
2888
3204
  );
2889
3205
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
2890
- const baseLocale = React29.useMemo(
3206
+ const baseLocale = React30.useMemo(
2891
3207
  () => createLocale(localeValue),
2892
3208
  [localeValue]
2893
3209
  );
2894
3210
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
2895
- const rangeOverrides = React29.useMemo(
3211
+ const rangeOverrides = React30.useMemo(
2896
3212
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
2897
3213
  [sanitizedPoints, rangeInput]
2898
3214
  );
2899
- const effectiveRange = React29.useMemo(
3215
+ const effectiveRange = React30.useMemo(
2900
3216
  () => normalizeRange({
2901
3217
  ...rangeOverrides,
2902
3218
  locale: baseLocale
@@ -2905,7 +3221,7 @@ function Timeline({
2905
3221
  );
2906
3222
  const spanStart = effectiveRange.startDate.getTime();
2907
3223
  const span = effectiveRange.span;
2908
- const pointsWithPosition = React29.useMemo(() => {
3224
+ const pointsWithPosition = React30.useMemo(() => {
2909
3225
  if (!sanitizedPoints.length) return [];
2910
3226
  return sanitizedPoints.map((point, index) => {
2911
3227
  const timestamp = point.meta.timestamp;
@@ -2919,29 +3235,29 @@ function Timeline({
2919
3235
  };
2920
3236
  });
2921
3237
  }, [sanitizedPoints, spanStart, span]);
2922
- const [activeId, setActiveId] = React29.useState(
3238
+ const [activeId, setActiveId] = React30.useState(
2923
3239
  () => getActivePointId(pointsWithPosition)
2924
3240
  );
2925
- React29.useEffect(() => {
3241
+ React30.useEffect(() => {
2926
3242
  setActiveId(getActivePointId(pointsWithPosition));
2927
3243
  }, [pointsWithPosition]);
2928
3244
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
2929
3245
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
2930
- const thresholdMs = React29.useMemo(
3246
+ const thresholdMs = React30.useMemo(
2931
3247
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
2932
3248
  [thresholdValue, effectiveRange.granularity]
2933
3249
  );
2934
- const groupedEntries = React29.useMemo(
3250
+ const groupedEntries = React30.useMemo(
2935
3251
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
2936
3252
  granularity: effectiveRange.granularity,
2937
3253
  locale: baseLocale
2938
3254
  }),
2939
3255
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
2940
3256
  );
2941
- const [expandedGroupIds, setExpandedGroupIds] = React29.useState(
3257
+ const [expandedGroupIds, setExpandedGroupIds] = React30.useState(
2942
3258
  () => /* @__PURE__ */ new Set()
2943
3259
  );
2944
- React29.useEffect(() => {
3260
+ React30.useEffect(() => {
2945
3261
  setExpandedGroupIds((prev) => {
2946
3262
  if (!prev || prev.size === 0) return prev;
2947
3263
  const validIds = new Set(
@@ -2956,7 +3272,7 @@ function Timeline({
2956
3272
  return changed ? next : prev;
2957
3273
  });
2958
3274
  }, [groupedEntries]);
2959
- const toggleGroup = React29.useCallback((groupId) => {
3275
+ const toggleGroup = React30.useCallback((groupId) => {
2960
3276
  setExpandedGroupIds((prev) => {
2961
3277
  const next = new Set(prev || []);
2962
3278
  if (next.has(groupId)) next.delete(groupId);
@@ -2979,7 +3295,7 @@ function Timeline({
2979
3295
  point.id === activeId ? "is-active" : "",
2980
3296
  point.highlight ? "is-highlighted" : ""
2981
3297
  ].filter(Boolean).join(" ");
2982
- const connector = /* @__PURE__ */ React29.createElement(
3298
+ const connector = /* @__PURE__ */ React30.createElement(
2983
3299
  TimelineConnector,
2984
3300
  {
2985
3301
  side: point.side,
@@ -2987,9 +3303,9 @@ function Timeline({
2987
3303
  highlight: point.highlight
2988
3304
  }
2989
3305
  );
2990
- const body = /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
3306
+ const body = /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2991
3307
  const resourceSection = renderResourceSection(point);
2992
- return /* @__PURE__ */ React29.createElement(
3308
+ return /* @__PURE__ */ React30.createElement(
2993
3309
  "div",
2994
3310
  {
2995
3311
  key: point.id,
@@ -2997,7 +3313,7 @@ function Timeline({
2997
3313
  style: wrapperStyle,
2998
3314
  role: "listitem"
2999
3315
  },
3000
- point.side === "left" ? /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React29.createElement(React29.Fragment, null, connector, /* @__PURE__ */ React29.createElement("div", { className: cardClasses }, body, resourceSection))
3316
+ point.side === "left" ? /* @__PURE__ */ React30.createElement(React30.Fragment, null, /* @__PURE__ */ React30.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React30.createElement(React30.Fragment, null, connector, /* @__PURE__ */ React30.createElement("div", { className: cardClasses }, body, resourceSection))
3001
3317
  );
3002
3318
  }
3003
3319
  function renderGroupEntry(entry) {
@@ -3008,7 +3324,7 @@ function Timeline({
3008
3324
  const wrapperStyle = { top: `${entry.progress * 100}%` };
3009
3325
  const isExpanded = expandedGroupIds.has(entry.id);
3010
3326
  const hasActivePoint = entry.points.some((point) => point.id === activeId);
3011
- const connector = /* @__PURE__ */ React29.createElement(
3327
+ const connector = /* @__PURE__ */ React30.createElement(
3012
3328
  TimelineConnector,
3013
3329
  {
3014
3330
  side: entry.side,
@@ -3022,7 +3338,7 @@ function Timeline({
3022
3338
  hasActivePoint ? "is-active" : ""
3023
3339
  ].filter(Boolean).join(" ");
3024
3340
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
3025
- const header = /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React29.createElement(
3341
+ const header = /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React30.createElement(
3026
3342
  "button",
3027
3343
  {
3028
3344
  type: "button",
@@ -3032,7 +3348,7 @@ function Timeline({
3032
3348
  },
3033
3349
  isExpanded ? "Hide details" : "Show details"
3034
3350
  ));
3035
- const groupPoints = isExpanded ? /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React29.createElement(
3351
+ const groupPoints = isExpanded ? /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React30.createElement(
3036
3352
  "button",
3037
3353
  {
3038
3354
  key: point.id,
@@ -3043,11 +3359,11 @@ function Timeline({
3043
3359
  ].filter(Boolean).join(" "),
3044
3360
  onClick: () => setActiveId(point.id)
3045
3361
  },
3046
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
3047
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
3362
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
3363
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
3048
3364
  ))) : null;
3049
- const groupCard = /* @__PURE__ */ React29.createElement("div", { className: groupClasses }, header, groupPoints);
3050
- return /* @__PURE__ */ React29.createElement(
3365
+ const groupCard = /* @__PURE__ */ React30.createElement("div", { className: groupClasses }, header, groupPoints);
3366
+ return /* @__PURE__ */ React30.createElement(
3051
3367
  "div",
3052
3368
  {
3053
3369
  key: entry.id,
@@ -3055,17 +3371,17 @@ function Timeline({
3055
3371
  style: wrapperStyle,
3056
3372
  role: "listitem"
3057
3373
  },
3058
- entry.side === "left" ? /* @__PURE__ */ React29.createElement(React29.Fragment, null, groupCard, connector) : /* @__PURE__ */ React29.createElement(React29.Fragment, null, connector, groupCard)
3374
+ entry.side === "left" ? /* @__PURE__ */ React30.createElement(React30.Fragment, null, groupCard, connector) : /* @__PURE__ */ React30.createElement(React30.Fragment, null, connector, groupCard)
3059
3375
  );
3060
3376
  }
3061
- return /* @__PURE__ */ React29.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React29.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React29.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React29.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React29.createElement(
3377
+ return /* @__PURE__ */ React30.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React30.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React30.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React30.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React30.createElement(
3062
3378
  "div",
3063
3379
  {
3064
3380
  className: "canopy-timeline__list",
3065
3381
  role: "list",
3066
3382
  style: { minHeight: trackHeight }
3067
3383
  },
3068
- /* @__PURE__ */ React29.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
3384
+ /* @__PURE__ */ React30.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
3069
3385
  renderSteps(stepsValue, effectiveRange),
3070
3386
  groupedEntries.map((entry) => {
3071
3387
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -3080,7 +3396,7 @@ function renderSteps(stepSize, range) {
3080
3396
  const markers = [];
3081
3397
  if (startYear < endYear) {
3082
3398
  markers.push(
3083
- /* @__PURE__ */ React29.createElement(
3399
+ /* @__PURE__ */ React30.createElement(
3084
3400
  "span",
3085
3401
  {
3086
3402
  key: "timeline-step-start",
@@ -3088,12 +3404,12 @@ function renderSteps(stepSize, range) {
3088
3404
  style: { top: "0%" },
3089
3405
  "aria-hidden": "true"
3090
3406
  },
3091
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-line" }),
3092
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
3407
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-line" }),
3408
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
3093
3409
  )
3094
3410
  );
3095
3411
  markers.push(
3096
- /* @__PURE__ */ React29.createElement(
3412
+ /* @__PURE__ */ React30.createElement(
3097
3413
  "span",
3098
3414
  {
3099
3415
  key: "timeline-step-end",
@@ -3101,8 +3417,8 @@ function renderSteps(stepSize, range) {
3101
3417
  style: { top: "100%" },
3102
3418
  "aria-hidden": "true"
3103
3419
  },
3104
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-line" }),
3105
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
3420
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-line" }),
3421
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
3106
3422
  )
3107
3423
  );
3108
3424
  }
@@ -3112,7 +3428,7 @@ function renderSteps(stepSize, range) {
3112
3428
  const progress = (timestamp - range.startDate.getTime()) / range.span;
3113
3429
  if (progress <= 0 || progress >= 1) continue;
3114
3430
  markers.push(
3115
- /* @__PURE__ */ React29.createElement(
3431
+ /* @__PURE__ */ React30.createElement(
3116
3432
  "span",
3117
3433
  {
3118
3434
  key: `timeline-step-${year}`,
@@ -3120,8 +3436,8 @@ function renderSteps(stepSize, range) {
3120
3436
  style: { top: `calc(${progress * 100}% - 0.5px)` },
3121
3437
  "aria-hidden": "true"
3122
3438
  },
3123
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-line" }),
3124
- /* @__PURE__ */ React29.createElement("span", { className: "canopy-timeline__step-label" }, year)
3439
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-line" }),
3440
+ /* @__PURE__ */ React30.createElement("span", { className: "canopy-timeline__step-label" }, year)
3125
3441
  )
3126
3442
  );
3127
3443
  }
@@ -3135,7 +3451,7 @@ function TimelinePoint() {
3135
3451
  TimelinePoint.displayName = "TimelinePoint";
3136
3452
 
3137
3453
  // ui/src/utils/manifestReferences.js
3138
- import React30 from "react";
3454
+ import React31 from "react";
3139
3455
  import navigationHelpers6 from "@canopy-iiif/app/lib/components/navigation.js";
3140
3456
  function normalizeManifestId(raw) {
3141
3457
  if (!raw) return "";
@@ -3152,13 +3468,13 @@ function normalizeManifestId(raw) {
3152
3468
  return String(raw || "").trim();
3153
3469
  }
3154
3470
  }
3155
- var PageContextFallback = React30.createContext(null);
3471
+ var PageContextFallback = React31.createContext(null);
3156
3472
  function useReferencedManifestMap() {
3157
3473
  var _a, _b;
3158
3474
  const PageContext = ((_b = (_a = navigationHelpers6) == null ? void 0 : _a.getPageContext) == null ? void 0 : _b.call(_a)) || PageContextFallback;
3159
- const pageContext = React30.useContext(PageContext);
3475
+ const pageContext = React31.useContext(PageContext);
3160
3476
  const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
3161
- return React30.useMemo(() => {
3477
+ return React31.useMemo(() => {
3162
3478
  const map = /* @__PURE__ */ new Map();
3163
3479
  referencedItems.forEach((item) => {
3164
3480
  if (!item) return;
@@ -3213,7 +3529,7 @@ function normalizeResource(resource, index) {
3213
3529
  }
3214
3530
  function normalizePoint(child, index, options) {
3215
3531
  var _a, _b, _c, _d, _e, _f;
3216
- if (!React31.isValidElement(child)) return null;
3532
+ if (!React32.isValidElement(child)) return null;
3217
3533
  if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
3218
3534
  return null;
3219
3535
  const props = child.props || {};
@@ -3229,7 +3545,7 @@ function normalizePoint(child, index, options) {
3229
3545
  try {
3230
3546
  if (props.children) {
3231
3547
  detailsHtml = ReactDOMServer.renderToStaticMarkup(
3232
- React31.createElement(React31.Fragment, null, props.children)
3548
+ React32.createElement(React32.Fragment, null, props.children)
3233
3549
  );
3234
3550
  }
3235
3551
  } catch (_) {
@@ -3278,7 +3594,7 @@ function MdxTimeline({ children, ...rest }) {
3278
3594
  const localeObj = createLocale(localeValue);
3279
3595
  const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
3280
3596
  const manifestMap = useReferencedManifestMap();
3281
- const childArray = React31.Children.toArray(children);
3597
+ const childArray = React32.Children.toArray(children);
3282
3598
  const points = childArray.map(
3283
3599
  (child, index) => normalizePoint(child, index, {
3284
3600
  range: rest.range || {},
@@ -3294,7 +3610,7 @@ function MdxTimeline({ children, ...rest }) {
3294
3610
  steps: rest.steps != null ? rest.steps : null
3295
3611
  };
3296
3612
  const json = serializeForScript(serializeProps(rest, payload, localeBase));
3297
- return /* @__PURE__ */ React31.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React31.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React31.createElement(
3613
+ return /* @__PURE__ */ React32.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React32.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React32.createElement(
3298
3614
  "script",
3299
3615
  {
3300
3616
  type: "application/json",
@@ -3304,7 +3620,7 @@ function MdxTimeline({ children, ...rest }) {
3304
3620
  }
3305
3621
 
3306
3622
  // ui/src/content/map/MdxMap.jsx
3307
- import React32 from "react";
3623
+ import React33 from "react";
3308
3624
  import ReactDOMServer2 from "react-dom/server";
3309
3625
 
3310
3626
  // ui/src/content/map/MapPoint.jsx
@@ -3331,7 +3647,7 @@ function renderDetailsHtml(children) {
3331
3647
  if (!children) return "";
3332
3648
  try {
3333
3649
  return ReactDOMServer2.renderToStaticMarkup(
3334
- React32.createElement(React32.Fragment, null, children)
3650
+ React33.createElement(React33.Fragment, null, children)
3335
3651
  );
3336
3652
  } catch (_) {
3337
3653
  return "";
@@ -3339,7 +3655,7 @@ function renderDetailsHtml(children) {
3339
3655
  }
3340
3656
  function normalizeCustomPoint(child, index, manifestMap) {
3341
3657
  var _a;
3342
- if (!React32.isValidElement(child)) return null;
3658
+ if (!React33.isValidElement(child)) return null;
3343
3659
  if (child.type !== MapPoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "MapPoint") return null;
3344
3660
  const coords = normalizeCoordinates(child.props || {});
3345
3661
  if (!coords) return null;
@@ -3384,7 +3700,7 @@ function normalizeCustomPoint(child, index, manifestMap) {
3384
3700
  };
3385
3701
  }
3386
3702
  function normalizeCustomPoints(children, manifestMap) {
3387
- return React32.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
3703
+ return React33.Children.toArray(children).map((child, index) => normalizeCustomPoint(child, index, manifestMap)).filter(Boolean);
3388
3704
  }
3389
3705
  function normalizeHeight(value) {
3390
3706
  if (value == null) return "600px";
@@ -3522,11 +3838,11 @@ function MdxMap({ children, ...rest }) {
3522
3838
  if (placeholderClass) placeholderProps.className = placeholderClass;
3523
3839
  if (rest.id) placeholderProps.id = rest.id;
3524
3840
  if (rest.style) placeholderProps.style = rest.style;
3525
- return /* @__PURE__ */ React32.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React32.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React32.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React32.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3841
+ return /* @__PURE__ */ React33.createElement("div", { "data-canopy-map": "1" }, /* @__PURE__ */ React33.createElement("div", { ...placeholderProps, "aria-live": "polite" }, /* @__PURE__ */ React33.createElement("div", { className: "canopy-map__status" }, "Loading map\u2026")), /* @__PURE__ */ React33.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3526
3842
  }
3527
3843
 
3528
3844
  // ui/src/search/MdxSearchResults.jsx
3529
- import React33 from "react";
3845
+ import React34 from "react";
3530
3846
  function MdxSearchResults(props) {
3531
3847
  let json = "{}";
3532
3848
  try {
@@ -3534,11 +3850,11 @@ function MdxSearchResults(props) {
3534
3850
  } catch (_) {
3535
3851
  json = "{}";
3536
3852
  }
3537
- return /* @__PURE__ */ React33.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React33.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3853
+ return /* @__PURE__ */ React34.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React34.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3538
3854
  }
3539
3855
 
3540
3856
  // ui/src/search/SearchSummary.jsx
3541
- import React34 from "react";
3857
+ import React35 from "react";
3542
3858
  function SearchSummary(props) {
3543
3859
  let json = "{}";
3544
3860
  try {
@@ -3546,11 +3862,11 @@ function SearchSummary(props) {
3546
3862
  } catch (_) {
3547
3863
  json = "{}";
3548
3864
  }
3549
- return /* @__PURE__ */ React34.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React34.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3865
+ return /* @__PURE__ */ React35.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React35.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3550
3866
  }
3551
3867
 
3552
3868
  // ui/src/search/MdxSearchTabs.jsx
3553
- import React35 from "react";
3869
+ import React36 from "react";
3554
3870
  function MdxSearchTabs(props) {
3555
3871
  let json = "{}";
3556
3872
  try {
@@ -3558,11 +3874,11 @@ function MdxSearchTabs(props) {
3558
3874
  } catch (_) {
3559
3875
  json = "{}";
3560
3876
  }
3561
- return /* @__PURE__ */ React35.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React35.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3877
+ return /* @__PURE__ */ React36.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React36.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3562
3878
  }
3563
3879
 
3564
3880
  // ui/src/search/MdxSearch.jsx
3565
- import React36 from "react";
3881
+ import React37 from "react";
3566
3882
  function MdxSearch(props = {}) {
3567
3883
  const {
3568
3884
  layout,
@@ -3580,11 +3896,11 @@ function MdxSearch(props = {}) {
3580
3896
  resultsPayload.layout = layout;
3581
3897
  }
3582
3898
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
3583
- return /* @__PURE__ */ React36.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React36.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React36.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React36.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
3899
+ return /* @__PURE__ */ React37.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React37.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React37.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React37.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
3584
3900
  }
3585
3901
 
3586
3902
  // ui/src/search-form/MdxSearchFormModal.jsx
3587
- import React37 from "react";
3903
+ import React38 from "react";
3588
3904
  function MdxSearchFormModal(props = {}) {
3589
3905
  const {
3590
3906
  placeholder = "Search\u2026",
@@ -3600,12 +3916,12 @@ function MdxSearchFormModal(props = {}) {
3600
3916
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
3601
3917
  const resolvedSearchPath = resolveSearchPath(searchPath);
3602
3918
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
3603
- return /* @__PURE__ */ React37.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React37.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React37.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React37.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React37.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
3919
+ return /* @__PURE__ */ React38.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React38.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React38.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React38.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React38.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
3604
3920
  }
3605
3921
 
3606
3922
  // ui/src/iiif/ManifestPrimitives.jsx
3607
3923
  var import_slugify = __toESM(require_slugify());
3608
- import React38 from "react";
3924
+ import React39 from "react";
3609
3925
  import {
3610
3926
  Label as CloverLabel,
3611
3927
  Metadata as CloverMetadata,
@@ -3746,7 +4062,7 @@ function MetadataFacetLink(props) {
3746
4062
  const valueSlug = facetSlug ? toValueSlug(text) : "";
3747
4063
  const href = facetSlug && valueSlug ? buildFacetSearchHref(facetSlug, valueSlug) : "";
3748
4064
  if (!href) return text;
3749
- return /* @__PURE__ */ React38.createElement(
4065
+ return /* @__PURE__ */ React39.createElement(
3750
4066
  "a",
3751
4067
  {
3752
4068
  href,
@@ -3772,7 +4088,7 @@ function buildFacetCustomValueContent(items, manifest) {
3772
4088
  seen.add(normalized);
3773
4089
  custom.push({
3774
4090
  matchingLabel: item.label,
3775
- Content: /* @__PURE__ */ React38.createElement(MetadataFacetLink, { facetSlug: facet.slug })
4091
+ Content: /* @__PURE__ */ React39.createElement(MetadataFacetLink, { facetSlug: facet.slug })
3776
4092
  });
3777
4093
  }
3778
4094
  return custom;
@@ -3804,12 +4120,12 @@ function mergeCustomValueContent(userContent, autoContent) {
3804
4120
  function Label({ manifest, label, ...rest }) {
3805
4121
  const intl = label || manifest && manifest.label;
3806
4122
  if (!hasInternationalValue(intl)) return null;
3807
- return /* @__PURE__ */ React38.createElement(CloverLabel, { label: intl, ...rest });
4123
+ return /* @__PURE__ */ React39.createElement(CloverLabel, { label: intl, ...rest });
3808
4124
  }
3809
4125
  function Summary({ manifest, summary, ...rest }) {
3810
4126
  const intl = summary || manifest && manifest.summary;
3811
4127
  if (!hasInternationalValue(intl)) return null;
3812
- return /* @__PURE__ */ React38.createElement(CloverSummary, { summary: intl, ...rest });
4128
+ return /* @__PURE__ */ React39.createElement(CloverSummary, { summary: intl, ...rest });
3813
4129
  }
3814
4130
  function Metadata({ manifest, metadata, customValueContent, ...rest }) {
3815
4131
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
@@ -3819,7 +4135,7 @@ function Metadata({ manifest, metadata, customValueContent, ...rest }) {
3819
4135
  customValueContent,
3820
4136
  autoCustomContent
3821
4137
  );
3822
- return /* @__PURE__ */ React38.createElement(
4138
+ return /* @__PURE__ */ React39.createElement(
3823
4139
  CloverMetadata,
3824
4140
  {
3825
4141
  metadata: items,
@@ -3833,17 +4149,17 @@ function RequiredStatement({ manifest, requiredStatement, ...rest }) {
3833
4149
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
3834
4150
  return null;
3835
4151
  }
3836
- return /* @__PURE__ */ React38.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
4152
+ return /* @__PURE__ */ React39.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
3837
4153
  }
3838
4154
 
3839
4155
  // ui/src/iiif/Properties/Id.jsx
3840
- import React39 from "react";
4156
+ import React40 from "react";
3841
4157
  function Id({ title = "IIIF Manifest", id, ...props }) {
3842
- return /* @__PURE__ */ React39.createElement("dl", null, /* @__PURE__ */ React39.createElement("dt", null, title), /* @__PURE__ */ React39.createElement("dd", null, /* @__PURE__ */ React39.createElement("a", { href: id }, id)));
4158
+ return /* @__PURE__ */ React40.createElement("dl", null, /* @__PURE__ */ React40.createElement("dt", null, title), /* @__PURE__ */ React40.createElement("dd", null, /* @__PURE__ */ React40.createElement("a", { href: id }, id)));
3843
4159
  }
3844
4160
 
3845
4161
  // ui/src/docs/CodeBlock.jsx
3846
- import React40 from "react";
4162
+ import React41 from "react";
3847
4163
  function parseHighlightAttr(attr) {
3848
4164
  if (!attr) return /* @__PURE__ */ new Set();
3849
4165
  const cleaned = String(attr || "").trim();
@@ -3889,10 +4205,10 @@ var highlightBaseStyle = {
3889
4205
  };
3890
4206
  function DocsCodeBlock(props = {}) {
3891
4207
  const { children, ...rest } = props;
3892
- const childArray = React40.Children.toArray(children);
3893
- const codeElement = childArray.find((el) => React40.isValidElement(el));
4208
+ const childArray = React41.Children.toArray(children);
4209
+ const codeElement = childArray.find((el) => React41.isValidElement(el));
3894
4210
  if (!codeElement || !codeElement.props) {
3895
- return React40.createElement("pre", props);
4211
+ return React41.createElement("pre", props);
3896
4212
  }
3897
4213
  const {
3898
4214
  className = "",
@@ -3907,8 +4223,8 @@ function DocsCodeBlock(props = {}) {
3907
4223
  const highlightSet = parseHighlightAttr(highlightAttr);
3908
4224
  const copyAttr = codeProps["data-copy"];
3909
4225
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
3910
- const [copied, setCopied] = React40.useState(false);
3911
- const handleCopy = React40.useCallback(async () => {
4226
+ const [copied, setCopied] = React41.useState(false);
4227
+ const handleCopy = React41.useCallback(async () => {
3912
4228
  const text = rawCode;
3913
4229
  try {
3914
4230
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -3973,24 +4289,26 @@ function DocsCodeBlock(props = {}) {
3973
4289
  const highlight = highlightSet.has(lineNumber);
3974
4290
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
3975
4291
  const displayLine = line === "" ? " " : line;
3976
- return React40.createElement(
4292
+ return React41.createElement(
3977
4293
  "span",
3978
4294
  { key: lineNumber, style },
3979
- React40.createElement("span", { style: lineContentStyle }, displayLine)
4295
+ React41.createElement("span", { style: lineContentStyle }, displayLine)
3980
4296
  );
3981
4297
  });
3982
- return React40.createElement(
4298
+ return React41.createElement(
3983
4299
  "div",
3984
4300
  { style: containerStyle },
3985
- showHeader ? React40.createElement(
4301
+ showHeader ? React41.createElement(
3986
4302
  "div",
3987
4303
  { style: headerStyle },
3988
- React40.createElement("span", null, showFilename ? filename : null),
3989
- enableCopy ? React40.createElement(
4304
+ React41.createElement("span", null, showFilename ? filename : null),
4305
+ enableCopy ? React41.createElement(
3990
4306
  "button",
3991
4307
  {
3992
4308
  type: "button",
3993
4309
  onClick: handleCopy,
4310
+ "aria-live": "polite",
4311
+ "aria-label": copied ? "Copied to clipboard" : "Copy code to clipboard",
3994
4312
  style: {
3995
4313
  border: "1px solid var(--color-accent-200, )",
3996
4314
  borderRadius: "6px",
@@ -4004,29 +4322,29 @@ function DocsCodeBlock(props = {}) {
4004
4322
  copied ? "Copied" : "Copy"
4005
4323
  ) : null
4006
4324
  ) : null,
4007
- React40.createElement(
4325
+ React41.createElement(
4008
4326
  "pre",
4009
4327
  { ...preRest, className: preClassName, style: mergedPreStyle },
4010
- React40.createElement("code", { style: codeStyle }, lineElements)
4328
+ React41.createElement("code", { style: codeStyle }, lineElements)
4011
4329
  )
4012
4330
  );
4013
4331
  }
4014
4332
 
4015
4333
  // ui/src/docs/MarkdownTable.jsx
4016
- import React41 from "react";
4334
+ import React42 from "react";
4017
4335
  function MarkdownTable({ className = "", ...rest }) {
4018
4336
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
4019
- return /* @__PURE__ */ React41.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React41.createElement("table", { className: merged, ...rest }));
4337
+ return /* @__PURE__ */ React42.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React42.createElement("table", { className: merged, ...rest }));
4020
4338
  }
4021
4339
 
4022
4340
  // ui/src/docs/Diagram.jsx
4023
- import React42 from "react";
4341
+ import React43 from "react";
4024
4342
  function CanopyDiagram() {
4025
- return /* @__PURE__ */ React42.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React42.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React42.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React42.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Collection A"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React42.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React42.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Collection B"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React42.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React42.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React42.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React42.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React42.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React42.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Automated content"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React42.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React42.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React42.createElement("li", null, "Author narratives"), /* @__PURE__ */ React42.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Search index"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React42.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React42.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React42.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React42.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React42.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React42.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React42.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__ */ React42.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Work pages"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React42.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React42.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React42.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React42.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React42.createElement("article", null, /* @__PURE__ */ React42.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React42.createElement("ul", null, /* @__PURE__ */ React42.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React42.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React42.createElement("li", null, "Optional annotation dataset"))))));
4343
+ return /* @__PURE__ */ React43.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React43.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React43.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React43.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Collection A"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React43.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React43.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Collection B"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React43.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React43.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React43.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React43.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React43.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React43.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Automated content"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React43.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React43.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React43.createElement("li", null, "Author narratives"), /* @__PURE__ */ React43.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Search index"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React43.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React43.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React43.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React43.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React43.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React43.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React43.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__ */ React43.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Work pages"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React43.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React43.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React43.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React43.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React43.createElement("article", null, /* @__PURE__ */ React43.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React43.createElement("ul", null, /* @__PURE__ */ React43.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React43.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React43.createElement("li", null, "Optional annotation dataset"))))));
4026
4344
  }
4027
4345
 
4028
4346
  // ui/src/docs/ThemeShowcase.jsx
4029
- import React43 from "react";
4347
+ import React44 from "react";
4030
4348
 
4031
4349
  // ../../node_modules/@radix-ui/colors/index.mjs
4032
4350
  var colors_exports = {};
@@ -7878,21 +8196,21 @@ var STEP_MAP = {
7878
8196
  800: 11,
7879
8197
  900: 12
7880
8198
  };
7881
- var Section = ({ title, description, children }) => /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React43.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React43.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
7882
- var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React43.createElement("strong", null, label)), /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React43.createElement(
8199
+ var Section = ({ title, description, children }) => /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React44.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React44.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
8200
+ var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React44.createElement("strong", null, label)), /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React44.createElement(
7883
8201
  "div",
7884
8202
  {
7885
8203
  key: `${label}-${stop}`,
7886
8204
  className: "canopy-theme-showcase__scale-stop"
7887
8205
  },
7888
- /* @__PURE__ */ React43.createElement(
8206
+ /* @__PURE__ */ React44.createElement(
7889
8207
  "span",
7890
8208
  {
7891
8209
  className: "canopy-theme-showcase__scale-chip",
7892
8210
  style: { backgroundColor: `var(${prefix}-${stop})` }
7893
8211
  }
7894
8212
  ),
7895
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
8213
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
7896
8214
  ))));
7897
8215
  var AVAILABLE = new Set(
7898
8216
  Object.keys(colors_exports).filter(
@@ -7957,9 +8275,9 @@ var PREVIEW_DATA = buildPreviewData();
7957
8275
  function encodeJson(value) {
7958
8276
  return JSON.stringify(value).replace(/</g, "\\u003c");
7959
8277
  }
7960
- var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
8278
+ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
7961
8279
  const colorValue = getRadixSwatch(name);
7962
- return /* @__PURE__ */ React43.createElement(
8280
+ return /* @__PURE__ */ React44.createElement(
7963
8281
  "button",
7964
8282
  {
7965
8283
  key: `${type}-${name}`,
@@ -7970,14 +8288,14 @@ var ColorsLabeled = ({ colors, type, getRadixSwatch }) => /* @__PURE__ */ React4
7970
8288
  "data-theme-swatch-value": name,
7971
8289
  "aria-pressed": "false"
7972
8290
  },
7973
- /* @__PURE__ */ React43.createElement(
8291
+ /* @__PURE__ */ React44.createElement(
7974
8292
  "span",
7975
8293
  {
7976
8294
  className: "canopy-theme-showcase__swatch-chip",
7977
8295
  style: { background: colorValue || "var(--color-gray-200)" }
7978
8296
  }
7979
8297
  ),
7980
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
8298
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-theme-showcase__swatch-label" }, name)
7981
8299
  );
7982
8300
  }));
7983
8301
  function ThemeShowcase() {
@@ -8137,7 +8455,7 @@ function ThemeShowcase() {
8137
8455
  .canopy-theme-showcase__swatch-controls { display: none; }
8138
8456
  .canopy-theme-showcase__clear-button { display: none; }
8139
8457
  `;
8140
- return /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React43.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React43.createElement(
8458
+ return /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase", "data-theme-showcase": true }, /* @__PURE__ */ React44.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React44.createElement(
8141
8459
  "div",
8142
8460
  {
8143
8461
  style: {
@@ -8148,18 +8466,18 @@ function ThemeShowcase() {
8148
8466
  marginBottom: "1rem"
8149
8467
  }
8150
8468
  },
8151
- /* @__PURE__ */ React43.createElement(
8469
+ /* @__PURE__ */ React44.createElement(
8152
8470
  Section,
8153
8471
  {
8154
8472
  title: "Appearance",
8155
8473
  description: "Pick the base light or dark mode for the theme preview."
8156
8474
  },
8157
- /* @__PURE__ */ React43.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
8475
+ /* @__PURE__ */ React44.createElement("div", { className: "canopy-theme-showcase__appearance-buttons" }, ["light", "dark"].map((mode) => {
8158
8476
  const label = `${mode.charAt(0).toUpperCase()}${mode.slice(1)}`;
8159
8477
  const baseClass = "canopy-theme-showcase__appearance-button";
8160
8478
  const isDefault = mode === DEFAULTS.appearance;
8161
8479
  const className = isDefault ? `${baseClass} is-active` : baseClass;
8162
- return /* @__PURE__ */ React43.createElement(
8480
+ return /* @__PURE__ */ React44.createElement(
8163
8481
  "button",
8164
8482
  {
8165
8483
  key: mode,
@@ -8171,7 +8489,7 @@ function ThemeShowcase() {
8171
8489
  );
8172
8490
  }))
8173
8491
  ),
8174
- /* @__PURE__ */ React43.createElement(
8492
+ /* @__PURE__ */ React44.createElement(
8175
8493
  "button",
8176
8494
  {
8177
8495
  type: "button",
@@ -8180,13 +8498,13 @@ function ThemeShowcase() {
8180
8498
  },
8181
8499
  "Reset"
8182
8500
  )
8183
- ), /* @__PURE__ */ React43.createElement(
8501
+ ), /* @__PURE__ */ React44.createElement(
8184
8502
  Section,
8185
8503
  {
8186
8504
  title: "Color scales",
8187
8505
  description: "Accent and gray ramps from the active theme."
8188
8506
  },
8189
- /* @__PURE__ */ React43.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React43.createElement(
8507
+ /* @__PURE__ */ React44.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React44.createElement(
8190
8508
  ColorScaleRow,
8191
8509
  {
8192
8510
  key: scale.label,
@@ -8194,13 +8512,13 @@ function ThemeShowcase() {
8194
8512
  prefix: scale.prefix
8195
8513
  }
8196
8514
  )))
8197
- ), /* @__PURE__ */ React43.createElement(
8515
+ ), /* @__PURE__ */ React44.createElement(
8198
8516
  Section,
8199
8517
  {
8200
8518
  title: "Accent color palette options",
8201
8519
  description: "Click a swatch to temporarily override the accent palette."
8202
8520
  },
8203
- /* @__PURE__ */ React43.createElement(
8521
+ /* @__PURE__ */ React44.createElement(
8204
8522
  ColorsLabeled,
8205
8523
  {
8206
8524
  colors: accentColors,
@@ -8208,13 +8526,13 @@ function ThemeShowcase() {
8208
8526
  getRadixSwatch
8209
8527
  }
8210
8528
  )
8211
- ), /* @__PURE__ */ React43.createElement(
8529
+ ), /* @__PURE__ */ React44.createElement(
8212
8530
  Section,
8213
8531
  {
8214
8532
  title: "Gray color palette options",
8215
8533
  description: "Click a swatch to preview the neutral ramp for surfaces and text."
8216
8534
  },
8217
- /* @__PURE__ */ React43.createElement(
8535
+ /* @__PURE__ */ React44.createElement(
8218
8536
  ColorsLabeled,
8219
8537
  {
8220
8538
  colors: grayColors,
@@ -8222,7 +8540,7 @@ function ThemeShowcase() {
8222
8540
  getRadixSwatch
8223
8541
  }
8224
8542
  )
8225
- ), /* @__PURE__ */ React43.createElement(
8543
+ ), /* @__PURE__ */ React44.createElement(
8226
8544
  "script",
8227
8545
  {
8228
8546
  type: "application/json",