@canopy-iiif/app 1.9.13 → 1.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ui/dist/index.mjs CHANGED
@@ -42,6 +42,94 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
42
42
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
43
43
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
44
44
 
45
+ // lib/default-locale.js
46
+ var require_default_locale = __commonJS({
47
+ "lib/default-locale.js"(exports2, module2) {
48
+ "use strict";
49
+ module2.exports = {
50
+ common: {
51
+ actions: {
52
+ open: "Open",
53
+ close: "Close",
54
+ clear: "Clear",
55
+ clear_all: "Clear all",
56
+ done: "Done",
57
+ show: "Show",
58
+ hide: "Hide"
59
+ },
60
+ nouns: {
61
+ search: "Search",
62
+ filters: "Filters",
63
+ results: "results",
64
+ values: "values",
65
+ types: "types",
66
+ items: "items",
67
+ navigation: "navigation",
68
+ section_navigation: "section navigation",
69
+ content_navigation: "content navigation",
70
+ primary_navigation: "Primary navigation",
71
+ metadata: "metadata",
72
+ gallery: "gallery",
73
+ gallery_thumbnails: "gallery thumbnails",
74
+ map: "map",
75
+ map_data: "map data",
76
+ map_locations: "map locations",
77
+ item_label: "Item",
78
+ details: "details",
79
+ breadcrumb: "Breadcrumb",
80
+ home: "Home"
81
+ },
82
+ types: {
83
+ work: "Works",
84
+ page: "Pages",
85
+ docs: "Docs"
86
+ },
87
+ statuses: {
88
+ loading: "Loading\u2026",
89
+ empty_short: "No {content}",
90
+ empty_detail: "No {content} available.",
91
+ unavailable: "{content} unavailable.",
92
+ unavailable_detail: "{content} is unavailable.",
93
+ failed: "Unable to load {content}.",
94
+ loading_content: "Loading {content}\u2026",
95
+ summary_content: "Showing {shown} of {total} {content}",
96
+ search_summary: 'Found {shown} of {total} in {type} for "{query}"',
97
+ no_matches: "No matches found."
98
+ },
99
+ phrases: {
100
+ placeholder_search: "Search\u2026",
101
+ results_label: "Search results",
102
+ open_content: "Open {content}",
103
+ close_content: "Close {content}",
104
+ show_content: "Show {content}",
105
+ hide_content: "Hide {content}",
106
+ nav_label: "{content} navigation",
107
+ search_content: "Search {content}",
108
+ filter_values: "Filter {content} values",
109
+ clear_content_search: "Clear {content} search",
110
+ none_applied: "No {content} applied",
111
+ applied_count: "{count} {content} applied",
112
+ toggle_content: "Toggle {content}",
113
+ scroll_direction_content: "Scroll {direction} through {content}",
114
+ step_content: "{direction} {content}",
115
+ item_numbered: "{content} {index}",
116
+ content_key: "{content} key"
117
+ },
118
+ directions: {
119
+ left: "left",
120
+ right: "right",
121
+ previous: "Previous",
122
+ next: "Next"
123
+ },
124
+ misc: {
125
+ referenced_by: "Referenced by",
126
+ on_this_page: "On this page"
127
+ }
128
+ }
129
+ };
130
+ }
131
+ });
132
+
45
133
  // ../../node_modules/lodash-es/_freeGlobal.js
46
134
  var freeGlobal, freeGlobal_default;
47
135
  var init_freeGlobal = __esm({
@@ -43228,17 +43316,106 @@ function ButtonWrapper({
43228
43316
  }
43229
43317
 
43230
43318
  // ui/src/layout/CanopyHeader.jsx
43231
- import React18 from "react";
43319
+ import React19 from "react";
43232
43320
 
43233
43321
  // ui/src/search/SearchPanel.jsx
43234
- import React11 from "react";
43322
+ import React13 from "react";
43235
43323
 
43236
43324
  // ui/src/Icons.jsx
43237
43325
  import React8 from "react";
43238
43326
  var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React8.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", "aria-hidden": "true", focusable: "false", ...props }, /* @__PURE__ */ React8.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" }));
43239
43327
 
43240
43328
  // ui/src/search/SearchPanelForm.jsx
43329
+ import React11 from "react";
43330
+
43331
+ // ui/src/locale/index.js
43332
+ import React10 from "react";
43333
+
43334
+ // ui/src/layout/pageContext.js
43241
43335
  import React9 from "react";
43336
+ var CONTEXT_KEY = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
43337
+ function getSharedRoot() {
43338
+ if (typeof globalThis !== "undefined") return globalThis;
43339
+ if (typeof window !== "undefined") return window;
43340
+ if (typeof global !== "undefined") return global;
43341
+ return null;
43342
+ }
43343
+ function getSafePageContext() {
43344
+ const root2 = getSharedRoot();
43345
+ if (root2 && root2[CONTEXT_KEY]) return root2[CONTEXT_KEY];
43346
+ const ctx = React9.createContext({ navigation: null, page: null, site: null });
43347
+ if (root2) root2[CONTEXT_KEY] = ctx;
43348
+ return ctx;
43349
+ }
43350
+
43351
+ // ui/src/locale/index.js
43352
+ var import_default_locale = __toESM(require_default_locale());
43353
+ function getGlobalScope() {
43354
+ if (typeof globalThis !== "undefined") return globalThis;
43355
+ if (typeof window !== "undefined") return window;
43356
+ if (typeof global !== "undefined") return global;
43357
+ return null;
43358
+ }
43359
+ function readRuntimeMessages() {
43360
+ const scope = getGlobalScope();
43361
+ const candidate = scope && scope.CANOPY_LOCALE_MESSAGES;
43362
+ if (candidate && typeof candidate === "object") return candidate;
43363
+ return import_default_locale.default || {};
43364
+ }
43365
+ function accessPath(obj, path) {
43366
+ if (!obj || typeof obj !== "object" || !path) return void 0;
43367
+ const parts = Array.isArray(path) ? path : String(path).split(".");
43368
+ let current2 = obj;
43369
+ for (const part of parts) {
43370
+ if (!current2 || typeof current2 !== "object") return void 0;
43371
+ const key = String(part).trim();
43372
+ if (!key || !(key in current2)) return void 0;
43373
+ current2 = current2[key];
43374
+ }
43375
+ return current2;
43376
+ }
43377
+ function formatTemplate(template, replacements = {}) {
43378
+ if (template == null) return template;
43379
+ const str = String(template);
43380
+ if (!replacements || typeof replacements !== "object") return str;
43381
+ return str.replace(/\{([^}]+)\}/g, (match2, key) => {
43382
+ if (!Object.prototype.hasOwnProperty.call(replacements, key)) return match2;
43383
+ const value = replacements[key];
43384
+ if (value == null) return match2;
43385
+ return String(value);
43386
+ });
43387
+ }
43388
+ function useLocaleMessages() {
43389
+ const PageContext3 = getSafePageContext();
43390
+ const context = PageContext3 ? React10.useContext(PageContext3) : null;
43391
+ const siteMessages = context && context.site && context.site.localeMessages && typeof context.site.localeMessages === "object" ? context.site.localeMessages : null;
43392
+ return siteMessages || readRuntimeMessages();
43393
+ }
43394
+ function useLocale() {
43395
+ const messages = useLocaleMessages();
43396
+ const getString = React10.useCallback(
43397
+ (path, fallback) => {
43398
+ const value = path ? accessPath(messages, path) : void 0;
43399
+ if (typeof value === "string" || typeof value === "number") {
43400
+ return value;
43401
+ }
43402
+ return fallback;
43403
+ },
43404
+ [messages]
43405
+ );
43406
+ const formatString = React10.useCallback(
43407
+ (path, fallback, replacements) => {
43408
+ const template = path ? accessPath(messages, path) : void 0;
43409
+ const resolved = template != null ? template : fallback;
43410
+ if (resolved == null) return resolved;
43411
+ return formatTemplate(resolved, replacements);
43412
+ },
43413
+ [messages]
43414
+ );
43415
+ return { messages, getString, formatString };
43416
+ }
43417
+
43418
+ // ui/src/search/SearchPanelForm.jsx
43242
43419
  function readBasePath() {
43243
43420
  const normalize = (val) => {
43244
43421
  const raw = typeof val === "string" ? val.trim() : "";
@@ -43293,26 +43470,35 @@ function resolveSearchPath(pathValue) {
43293
43470
  }
43294
43471
  function SearchPanelForm(props = {}) {
43295
43472
  const {
43296
- placeholder = "Search\u2026",
43297
- buttonLabel = "Search",
43473
+ placeholder,
43474
+ buttonLabel,
43298
43475
  label,
43299
43476
  searchPath = "/search",
43300
43477
  inputId: inputIdProp,
43301
- clearLabel = "Clear search"
43478
+ clearLabel
43302
43479
  } = props || {};
43303
- const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
43304
- const action = React9.useMemo(
43480
+ const { getString, formatString } = useLocale();
43481
+ const searchLabel = getString("common.nouns.search", "Search");
43482
+ const placeholderText = placeholder != null ? placeholder : getString("common.phrases.placeholder_search", "Search\u2026");
43483
+ const buttonText = buttonLabel != null ? buttonLabel : getString("common.nouns.search", "Search");
43484
+ const clearText = clearLabel != null ? clearLabel : formatString(
43485
+ "common.phrases.clear_content_search",
43486
+ "Clear {content} search",
43487
+ { content: searchLabel }
43488
+ );
43489
+ const text = typeof label === "string" && label.trim() ? label.trim() : buttonText;
43490
+ const action = React11.useMemo(
43305
43491
  () => resolveSearchPath(searchPath),
43306
43492
  [searchPath]
43307
43493
  );
43308
- const autoId = typeof React9.useId === "function" ? React9.useId() : void 0;
43309
- const [fallbackId] = React9.useState(
43494
+ const autoId = typeof React11.useId === "function" ? React11.useId() : void 0;
43495
+ const [fallbackId] = React11.useState(
43310
43496
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
43311
43497
  );
43312
43498
  const inputId = inputIdProp || autoId || fallbackId;
43313
- const inputRef = React9.useRef(null);
43314
- const [hasValue, setHasValue] = React9.useState(false);
43315
- const focusInput = React9.useCallback(() => {
43499
+ const inputRef = React11.useRef(null);
43500
+ const [hasValue, setHasValue] = React11.useState(false);
43501
+ const focusInput = React11.useCallback(() => {
43316
43502
  const el = inputRef.current;
43317
43503
  if (!el) return;
43318
43504
  if (document.activeElement === el) return;
@@ -43325,7 +43511,7 @@ function SearchPanelForm(props = {}) {
43325
43511
  }
43326
43512
  }
43327
43513
  }, []);
43328
- const handlePointerDown = React9.useCallback(
43514
+ const handlePointerDown = React11.useCallback(
43329
43515
  (event) => {
43330
43516
  const target = event.target;
43331
43517
  if (target && typeof target.closest === "function") {
@@ -43337,23 +43523,23 @@ function SearchPanelForm(props = {}) {
43337
43523
  },
43338
43524
  [focusInput]
43339
43525
  );
43340
- React9.useEffect(() => {
43526
+ React11.useEffect(() => {
43341
43527
  const el = inputRef.current;
43342
43528
  if (!el) return;
43343
43529
  if (el.value && el.value.trim()) {
43344
43530
  setHasValue(true);
43345
43531
  }
43346
43532
  }, []);
43347
- const handleInputChange = React9.useCallback((event) => {
43533
+ const handleInputChange = React11.useCallback((event) => {
43348
43534
  var _a2;
43349
43535
  const nextHasValue = Boolean(
43350
43536
  ((_a2 = event == null ? void 0 : event.target) == null ? void 0 : _a2.value) && event.target.value.trim()
43351
43537
  );
43352
43538
  setHasValue(nextHasValue);
43353
43539
  }, []);
43354
- const handleClear = React9.useCallback((event) => {
43540
+ const handleClear = React11.useCallback((event) => {
43355
43541
  }, []);
43356
- const handleClearKey = React9.useCallback(
43542
+ const handleClearKey = React11.useCallback(
43357
43543
  (event) => {
43358
43544
  if (event.key === "Enter" || event.key === " ") {
43359
43545
  event.preventDefault();
@@ -43362,7 +43548,7 @@ function SearchPanelForm(props = {}) {
43362
43548
  },
43363
43549
  [handleClear]
43364
43550
  );
43365
- return /* @__PURE__ */ React9.createElement(
43551
+ return /* @__PURE__ */ React11.createElement(
43366
43552
  "form",
43367
43553
  {
43368
43554
  action,
@@ -43374,7 +43560,7 @@ function SearchPanelForm(props = {}) {
43374
43560
  onPointerDown: handlePointerDown,
43375
43561
  "data-has-value": hasValue ? "1" : "0"
43376
43562
  },
43377
- /* @__PURE__ */ React9.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React9.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React9.createElement("span", { className: "sr-only" }, "Search"), /* @__PURE__ */ React9.createElement(
43563
+ /* @__PURE__ */ React11.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React11.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React11.createElement("span", { className: "sr-only" }, searchLabel), /* @__PURE__ */ React11.createElement(
43378
43564
  "input",
43379
43565
  {
43380
43566
  id: inputId,
@@ -43382,14 +43568,14 @@ function SearchPanelForm(props = {}) {
43382
43568
  name: "q",
43383
43569
  inputMode: "search",
43384
43570
  "data-canopy-search-form-input": true,
43385
- placeholder,
43571
+ placeholder: placeholderText,
43386
43572
  className: "canopy-search-form__input",
43387
43573
  ref: inputRef,
43388
43574
  onChange: handleInputChange,
43389
43575
  onInput: handleInputChange
43390
43576
  }
43391
43577
  )),
43392
- hasValue ? /* @__PURE__ */ React9.createElement(
43578
+ hasValue ? /* @__PURE__ */ React11.createElement(
43393
43579
  "button",
43394
43580
  {
43395
43581
  type: "button",
@@ -43397,12 +43583,12 @@ function SearchPanelForm(props = {}) {
43397
43583
  onClick: handleClear,
43398
43584
  onPointerDown: (event) => event.stopPropagation(),
43399
43585
  onKeyDown: handleClearKey,
43400
- "aria-label": clearLabel,
43586
+ "aria-label": clearText,
43401
43587
  "data-canopy-search-form-clear": true
43402
43588
  },
43403
43589
  "\xD7"
43404
43590
  ) : null,
43405
- /* @__PURE__ */ React9.createElement(
43591
+ /* @__PURE__ */ React11.createElement(
43406
43592
  "button",
43407
43593
  {
43408
43594
  type: "submit",
@@ -43415,11 +43601,11 @@ function SearchPanelForm(props = {}) {
43415
43601
  }
43416
43602
 
43417
43603
  // ui/src/search/SearchPanelTeaserResults.jsx
43418
- import React10 from "react";
43604
+ import React12 from "react";
43419
43605
  function SearchPanelTeaserResults(props = {}) {
43420
43606
  const { style, className } = props || {};
43421
43607
  const classes = ["canopy-search-teaser", "is-empty", className].filter(Boolean).join(" ");
43422
- return /* @__PURE__ */ React10.createElement(
43608
+ return /* @__PURE__ */ React12.createElement(
43423
43609
  "div",
43424
43610
  {
43425
43611
  "data-canopy-search-form-panel": true,
@@ -43427,65 +43613,49 @@ function SearchPanelTeaserResults(props = {}) {
43427
43613
  className: classes || void 0,
43428
43614
  style
43429
43615
  },
43430
- /* @__PURE__ */ React10.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
43616
+ /* @__PURE__ */ React12.createElement("div", { id: "cplist", className: "canopy-search-teaser__list" })
43431
43617
  );
43432
43618
  }
43433
43619
 
43434
43620
  // ui/src/search/SearchPanel.jsx
43435
43621
  function SearchPanel(props = {}) {
43436
43622
  const {
43437
- placeholder = "Search\u2026",
43623
+ placeholder: placeholderProp,
43438
43624
  hotkey = "mod+k",
43439
43625
  maxResults = 8,
43440
43626
  groupOrder = ["work", "docs", "page"],
43441
43627
  // Kept for backward compat; form always renders submit
43442
43628
  button = true,
43443
43629
  // eslint-disable-line no-unused-vars
43444
- buttonLabel = "Search",
43630
+ buttonLabel: buttonLabelProp,
43445
43631
  label,
43446
43632
  searchPath = "/search"
43447
43633
  } = props || {};
43448
- const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
43634
+ const { getString } = useLocale();
43635
+ const placeholder = placeholderProp != null ? placeholderProp : getString("common.phrases.placeholder_search", "Search\u2026");
43636
+ const resolvedButtonLabel = buttonLabelProp != null ? buttonLabelProp : getString("common.nouns.search", "Search");
43637
+ const text = typeof label === "string" && label.trim() ? label.trim() : resolvedButtonLabel;
43449
43638
  const resolvedSearchPath = resolveSearchPath(searchPath);
43450
43639
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
43451
- return /* @__PURE__ */ React11.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React11.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React11.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React11.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React11.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
43452
- }
43453
-
43454
- // ui/src/layout/CanopyBrand.jsx
43455
- import React13 from "react";
43456
-
43457
- // ui/src/layout/pageContext.js
43458
- import React12 from "react";
43459
- var CONTEXT_KEY = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
43460
- function getSharedRoot() {
43461
- if (typeof globalThis !== "undefined") return globalThis;
43462
- if (typeof window !== "undefined") return window;
43463
- if (typeof global !== "undefined") return global;
43464
- return null;
43465
- }
43466
- function getSafePageContext() {
43467
- const root2 = getSharedRoot();
43468
- if (root2 && root2[CONTEXT_KEY]) return root2[CONTEXT_KEY];
43469
- const ctx = React12.createContext({ navigation: null, page: null, site: null });
43470
- if (root2) root2[CONTEXT_KEY] = ctx;
43471
- return ctx;
43640
+ return /* @__PURE__ */ React13.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React13.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React13.createElement(SearchPanelForm, { placeholder, buttonLabel: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React13.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React13.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
43472
43641
  }
43473
43642
 
43474
43643
  // ui/src/layout/CanopyBrand.jsx
43644
+ import React14 from "react";
43475
43645
  var PageContext = getSafePageContext();
43476
43646
  function CanopyBrand(props = {}) {
43477
43647
  const { labelId, label: labelProp, href = "/", className, Logo } = props || {};
43478
- const context = React13.useContext(PageContext);
43648
+ const context = React14.useContext(PageContext);
43479
43649
  const contextSiteTitle = context && context.site && typeof context.site.title === "string" ? context.site.title.trim() : "";
43480
43650
  const normalizedLabel = typeof labelProp === "string" && labelProp.trim() ? labelProp : "";
43481
43651
  const resolvedLabel = normalizedLabel || contextSiteTitle || "Site title";
43482
43652
  const spanProps = labelId ? { id: labelId } : {};
43483
43653
  const classes = ["canopy-logo", className].filter(Boolean).join(" ");
43484
- return /* @__PURE__ */ React13.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React13.createElement(Logo, null) : null, /* @__PURE__ */ React13.createElement("span", { ...spanProps }, resolvedLabel));
43654
+ return /* @__PURE__ */ React14.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React14.createElement(Logo, null) : null, /* @__PURE__ */ React14.createElement("span", { ...spanProps }, resolvedLabel));
43485
43655
  }
43486
43656
 
43487
43657
  // ui/src/layout/CanopyModal.jsx
43488
- import React14 from "react";
43658
+ import React15 from "react";
43489
43659
  function CanopyModal(props = {}) {
43490
43660
  const {
43491
43661
  id,
@@ -43495,7 +43665,7 @@ function CanopyModal(props = {}) {
43495
43665
  label,
43496
43666
  logo: Logo,
43497
43667
  href = "/",
43498
- closeLabel = "Close",
43668
+ closeLabel,
43499
43669
  closeDataAttr,
43500
43670
  onClose,
43501
43671
  onBackgroundClick,
@@ -43521,10 +43691,12 @@ function CanopyModal(props = {}) {
43521
43691
  if (event.target === event.currentTarget) onBackgroundClick(event);
43522
43692
  };
43523
43693
  }
43694
+ const { getString } = useLocale();
43695
+ const resolvedCloseLabel = closeLabel || getString("common.actions.close", "Close");
43524
43696
  const closeButtonProps = {
43525
43697
  type: "button",
43526
43698
  className: "canopy-modal__close",
43527
- "aria-label": closeLabel
43699
+ "aria-label": resolvedCloseLabel
43528
43700
  };
43529
43701
  if (typeof closeDataAttr === "string" && closeDataAttr) {
43530
43702
  closeButtonProps["data-canopy-header-close"] = closeDataAttr;
@@ -43536,7 +43708,7 @@ function CanopyModal(props = {}) {
43536
43708
  if (padded) bodyClasses.push("canopy-modal__body--padded");
43537
43709
  if (bodyClassName) bodyClasses.push(bodyClassName);
43538
43710
  const bodyClassNameValue = bodyClasses.join(" ");
43539
- return /* @__PURE__ */ React14.createElement("div", { ...modalProps }, /* @__PURE__ */ React14.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React14.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React14.createElement(
43711
+ return /* @__PURE__ */ React15.createElement("div", { ...modalProps }, /* @__PURE__ */ React15.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React15.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React15.createElement(
43540
43712
  "svg",
43541
43713
  {
43542
43714
  xmlns: "http://www.w3.org/2000/svg",
@@ -43546,8 +43718,8 @@ function CanopyModal(props = {}) {
43546
43718
  strokeWidth: "1.5",
43547
43719
  className: "canopy-modal__close-icon"
43548
43720
  },
43549
- /* @__PURE__ */ React14.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
43550
- ), /* @__PURE__ */ React14.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React14.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React14.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React14.createElement(
43721
+ /* @__PURE__ */ React15.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
43722
+ ), /* @__PURE__ */ React15.createElement("span", { className: "sr-only" }, resolvedCloseLabel)), /* @__PURE__ */ React15.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React15.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React15.createElement(
43551
43723
  CanopyBrand,
43552
43724
  {
43553
43725
  labelId: resolvedLabelId,
@@ -43560,26 +43732,34 @@ function CanopyModal(props = {}) {
43560
43732
  }
43561
43733
 
43562
43734
  // ui/src/layout/NavigationTree.jsx
43563
- import React15 from "react";
43735
+ import React16 from "react";
43564
43736
  function normalizeDepth(depth) {
43565
43737
  if (typeof depth !== "number") return 0;
43566
43738
  return Math.max(0, Math.min(5, depth));
43567
43739
  }
43568
- function NavigationTreeList({ nodes, depth, parentKey }) {
43740
+ function NavigationTreeList({
43741
+ nodes,
43742
+ depth,
43743
+ parentKey,
43744
+ buildToggleLabel,
43745
+ buildNavLabel
43746
+ }) {
43569
43747
  if (!Array.isArray(nodes) || !nodes.length) return null;
43570
43748
  const listClasses = ["canopy-nav-tree__list"];
43571
43749
  if (depth > 0) listClasses.push("canopy-nav-tree__list--nested");
43572
- return /* @__PURE__ */ React15.createElement("ul", { className: listClasses.join(" "), role: "list" }, nodes.map((node, index) => /* @__PURE__ */ React15.createElement(
43750
+ return /* @__PURE__ */ React16.createElement("ul", { className: listClasses.join(" "), role: "list" }, nodes.map((node, index) => /* @__PURE__ */ React16.createElement(
43573
43751
  NavigationTreeItem,
43574
43752
  {
43575
43753
  key: node.slug || node.href || node.title || `${parentKey}-${index}`,
43576
43754
  node,
43577
43755
  depth,
43578
- nodeKey: `${parentKey}-${index}`
43756
+ nodeKey: `${parentKey}-${index}`,
43757
+ buildToggleLabel,
43758
+ buildNavLabel
43579
43759
  }
43580
43760
  )));
43581
43761
  }
43582
- function NavigationTreeItem({ node, depth, nodeKey }) {
43762
+ function NavigationTreeItem({ node, depth, nodeKey, buildToggleLabel, buildNavLabel }) {
43583
43763
  if (!node) return null;
43584
43764
  const hasChildren = Array.isArray(node.children) && node.children.length > 0;
43585
43765
  const isInteractive = !!node.href;
@@ -43592,8 +43772,8 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43592
43772
  const panelId = hasChildren ? `canopy-section-${nodeKey}` : null;
43593
43773
  const allowToggle = hasChildren && !isRootLevel;
43594
43774
  const defaultExpanded = allowToggle ? !!node.isExpanded : true;
43595
- const toggleLabel = node.title ? `Toggle ${node.title} menu` : "Toggle section menu";
43596
- return /* @__PURE__ */ React15.createElement(
43775
+ const toggleLabel = buildToggleLabel ? buildToggleLabel(node.title || node.slug) : `Toggle ${node.title || "section"} menu`;
43776
+ return /* @__PURE__ */ React16.createElement(
43597
43777
  "li",
43598
43778
  {
43599
43779
  className: "canopy-nav-tree__item",
@@ -43602,7 +43782,7 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43602
43782
  "data-expanded": allowToggle ? defaultExpanded ? "true" : "false" : void 0,
43603
43783
  "data-default-expanded": allowToggle && defaultExpanded ? "true" : void 0
43604
43784
  },
43605
- /* @__PURE__ */ React15.createElement("div", { className: "canopy-nav-tree__row" }, /* @__PURE__ */ React15.createElement("div", { className: "canopy-nav-tree__link-wrapper" }, /* @__PURE__ */ React15.createElement(
43785
+ /* @__PURE__ */ React16.createElement("div", { className: "canopy-nav-tree__row" }, /* @__PURE__ */ React16.createElement("div", { className: "canopy-nav-tree__link-wrapper" }, /* @__PURE__ */ React16.createElement(
43606
43786
  Tag,
43607
43787
  {
43608
43788
  className: classes.join(" "),
@@ -43611,7 +43791,7 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43611
43791
  tabIndex: isInteractive ? void 0 : -1
43612
43792
  },
43613
43793
  node.title || node.slug
43614
- )), allowToggle ? /* @__PURE__ */ React15.createElement(
43794
+ )), allowToggle ? /* @__PURE__ */ React16.createElement(
43615
43795
  "button",
43616
43796
  {
43617
43797
  type: "button",
@@ -43621,7 +43801,7 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43621
43801
  "aria-label": toggleLabel,
43622
43802
  "data-canopy-nav-item-toggle": panelId || void 0
43623
43803
  },
43624
- /* @__PURE__ */ React15.createElement(
43804
+ /* @__PURE__ */ React16.createElement(
43625
43805
  "svg",
43626
43806
  {
43627
43807
  xmlns: "http://www.w3.org/2000/svg",
@@ -43631,7 +43811,7 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43631
43811
  strokeWidth: "1.5",
43632
43812
  className: "canopy-nav-tree__toggle-icon"
43633
43813
  },
43634
- /* @__PURE__ */ React15.createElement(
43814
+ /* @__PURE__ */ React16.createElement(
43635
43815
  "path",
43636
43816
  {
43637
43817
  strokeLinecap: "round",
@@ -43640,9 +43820,9 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43640
43820
  }
43641
43821
  )
43642
43822
  ),
43643
- /* @__PURE__ */ React15.createElement("span", { className: "sr-only" }, toggleLabel)
43823
+ /* @__PURE__ */ React16.createElement("span", { className: "sr-only" }, toggleLabel)
43644
43824
  ) : null),
43645
- hasChildren ? /* @__PURE__ */ React15.createElement(
43825
+ hasChildren ? /* @__PURE__ */ React16.createElement(
43646
43826
  "div",
43647
43827
  {
43648
43828
  id: panelId || void 0,
@@ -43650,12 +43830,14 @@ function NavigationTreeItem({ node, depth, nodeKey }) {
43650
43830
  "aria-hidden": allowToggle ? defaultExpanded ? "false" : "true" : "false",
43651
43831
  hidden: allowToggle ? !defaultExpanded : void 0
43652
43832
  },
43653
- /* @__PURE__ */ React15.createElement(
43833
+ /* @__PURE__ */ React16.createElement(
43654
43834
  NavigationTreeList,
43655
43835
  {
43656
43836
  nodes: node.children,
43657
43837
  depth: depth + 1,
43658
- parentKey: nodeKey
43838
+ parentKey: nodeKey,
43839
+ buildToggleLabel,
43840
+ buildNavLabel
43659
43841
  }
43660
43842
  )
43661
43843
  ) : null
@@ -43672,33 +43854,53 @@ function NavigationTree({
43672
43854
  ...rest
43673
43855
  }) {
43674
43856
  if (!root2) return null;
43857
+ const { formatString, getString } = useLocale();
43858
+ const navFallback = getString("common.nouns.navigation", "navigation");
43859
+ const buildNavLabel = React16.useCallback(
43860
+ (value) => formatString(
43861
+ "common.phrases.nav_label",
43862
+ "{content} navigation",
43863
+ { content: value || navFallback }
43864
+ ),
43865
+ [formatString, navFallback]
43866
+ );
43867
+ const buildToggleLabel = React16.useCallback(
43868
+ (value) => formatString(
43869
+ "common.phrases.toggle_content",
43870
+ "Toggle {content}",
43871
+ { content: buildNavLabel(value) }
43872
+ ),
43873
+ [buildNavLabel, formatString]
43874
+ );
43675
43875
  const nodes = includeRoot ? [root2] : root2.children;
43676
43876
  if (!Array.isArray(nodes) || !nodes.length) return null;
43677
43877
  const combinedClassName = ["canopy-nav-tree", className].filter(Boolean).join(" ");
43678
- return /* @__PURE__ */ React15.createElement(
43878
+ return /* @__PURE__ */ React16.createElement(
43679
43879
  Component,
43680
43880
  {
43681
43881
  className: combinedClassName,
43682
43882
  "data-canopy-nav-tree": "true",
43683
43883
  ...rest
43684
43884
  },
43685
- heading ? /* @__PURE__ */ React15.createElement("div", { className: headingClassName }, heading) : null,
43686
- /* @__PURE__ */ React15.createElement(
43885
+ heading ? /* @__PURE__ */ React16.createElement("div", { className: headingClassName }, heading) : null,
43886
+ /* @__PURE__ */ React16.createElement(
43687
43887
  NavigationTreeList,
43688
43888
  {
43689
43889
  nodes,
43690
43890
  depth: includeRoot ? -1 : 0,
43691
- parentKey
43891
+ parentKey,
43892
+ buildToggleLabel,
43893
+ buildNavLabel
43692
43894
  }
43693
43895
  )
43694
43896
  );
43695
43897
  }
43696
43898
 
43697
43899
  // ui/src/layout/LanguageToggle.jsx
43698
- import React17 from "react";
43900
+ import React18 from "react";
43699
43901
 
43700
43902
  // ui/src/layout/languageToggleShared.jsx
43701
- import React16 from "react";
43903
+ import React17 from "react";
43702
43904
  function readBasePath2() {
43703
43905
  const normalize = (value) => {
43704
43906
  if (!value) return "";
@@ -43857,13 +44059,13 @@ function LanguageToggleControl({
43857
44059
  ].filter(Boolean).join(" ").trim();
43858
44060
  const ariaLabel = config.label || "Language";
43859
44061
  const resolvedControl = control === "list" ? "list" : "select";
43860
- const selectId = typeof React16.useId === "function" && resolvedControl === "select" ? React16.useId() : void 0;
44062
+ const selectId = typeof React17.useId === "function" && resolvedControl === "select" ? React17.useId() : void 0;
43861
44063
  const links = Array.isArray(config.links) ? config.links : [];
43862
44064
  if (!links.length) return null;
43863
44065
  const activeLink = links.find((link) => link.isActive);
43864
44066
  const fallbackHref = links[0].href;
43865
44067
  const selectedHref = activeLink ? activeLink.href : fallbackHref;
43866
- const navigate = React16.useCallback((href) => {
44068
+ const navigate = React17.useCallback((href) => {
43867
44069
  if (!href) return;
43868
44070
  try {
43869
44071
  if (typeof window !== "undefined" && window.location) {
@@ -43883,7 +44085,7 @@ function LanguageToggleControl({
43883
44085
  } catch (_) {
43884
44086
  }
43885
44087
  }, []);
43886
- const handleSelectChange = React16.useCallback(
44088
+ const handleSelectChange = React17.useCallback(
43887
44089
  (event) => {
43888
44090
  if (!event || !event.target) return;
43889
44091
  const nextHref = event.target.value;
@@ -43892,15 +44094,15 @@ function LanguageToggleControl({
43892
44094
  },
43893
44095
  [navigate, selectedHref]
43894
44096
  );
43895
- const labelElement = showLabel && config.label ? resolvedControl === "select" ? /* @__PURE__ */ React16.createElement(
44097
+ const labelElement = showLabel && config.label ? resolvedControl === "select" ? /* @__PURE__ */ React17.createElement(
43896
44098
  "label",
43897
44099
  {
43898
44100
  className: "canopy-language-toggle__label",
43899
44101
  htmlFor: selectId
43900
44102
  },
43901
44103
  config.label
43902
- ) : /* @__PURE__ */ React16.createElement("span", { className: "canopy-language-toggle__label" }, config.label) : null;
43903
- return /* @__PURE__ */ React16.createElement("div", { className: classes || void 0 }, labelElement, resolvedControl === "select" ? /* @__PURE__ */ React16.createElement("div", { className: "canopy-language-toggle__select" }, /* @__PURE__ */ React16.createElement(
44104
+ ) : /* @__PURE__ */ React17.createElement("span", { className: "canopy-language-toggle__label" }, config.label) : null;
44105
+ return /* @__PURE__ */ React17.createElement("div", { className: classes || void 0 }, labelElement, resolvedControl === "select" ? /* @__PURE__ */ React17.createElement("div", { className: "canopy-language-toggle__select" }, /* @__PURE__ */ React17.createElement(
43904
44106
  "select",
43905
44107
  {
43906
44108
  id: selectId,
@@ -43910,7 +44112,7 @@ function LanguageToggleControl({
43910
44112
  "aria-label": ariaLabel,
43911
44113
  "data-canopy-language-select": "true"
43912
44114
  },
43913
- links.map((link) => /* @__PURE__ */ React16.createElement(
44115
+ links.map((link) => /* @__PURE__ */ React17.createElement(
43914
44116
  "option",
43915
44117
  {
43916
44118
  key: link.lang,
@@ -43920,7 +44122,7 @@ function LanguageToggleControl({
43920
44122
  },
43921
44123
  link.label
43922
44124
  ))
43923
- )) : /* @__PURE__ */ React16.createElement("nav", { className: "canopy-language-toggle__nav", "aria-label": ariaLabel }, /* @__PURE__ */ React16.createElement("ul", { className: "canopy-language-toggle__list", role: "list" }, links.map((link) => /* @__PURE__ */ React16.createElement("li", { key: link.lang }, /* @__PURE__ */ React16.createElement(
44125
+ )) : /* @__PURE__ */ React17.createElement("nav", { className: "canopy-language-toggle__nav", "aria-label": ariaLabel }, /* @__PURE__ */ React17.createElement("ul", { className: "canopy-language-toggle__list", role: "list" }, links.map((link) => /* @__PURE__ */ React17.createElement("li", { key: link.lang }, /* @__PURE__ */ React17.createElement(
43924
44126
  "button",
43925
44127
  {
43926
44128
  type: "button",
@@ -43932,7 +44134,7 @@ function LanguageToggleControl({
43932
44134
  onClick: () => navigate(link.href)
43933
44135
  },
43934
44136
  link.label
43935
- ))))), /* @__PURE__ */ React16.createElement(LanguageToggleRuntime, null));
44137
+ ))))), /* @__PURE__ */ React17.createElement(LanguageToggleRuntime, null));
43936
44138
  }
43937
44139
  function LanguageToggleRuntime() {
43938
44140
  const code = `
@@ -43992,7 +44194,7 @@ function LanguageToggleRuntime() {
43992
44194
  }
43993
44195
  })();
43994
44196
  `;
43995
- return /* @__PURE__ */ React16.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
44197
+ return /* @__PURE__ */ React17.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
43996
44198
  }
43997
44199
 
43998
44200
  // ui/src/layout/LanguageToggle.jsx
@@ -44007,7 +44209,7 @@ function LanguageToggle({
44007
44209
  ariaLabel
44008
44210
  }) {
44009
44211
  const PageContext3 = getSafePageContext();
44010
- const context = React17.useContext(PageContext3);
44212
+ const context = React18.useContext(PageContext3);
44011
44213
  const siteLanguageToggle = context && context.site && context.site.languageToggle || null;
44012
44214
  const pageData = page || (context && context.page ? context.page : null);
44013
44215
  const resolvedToggle = languageToggle === false ? null : languageToggle === true || typeof languageToggle === "undefined" ? siteLanguageToggle : languageToggle;
@@ -44016,7 +44218,7 @@ function LanguageToggle({
44016
44218
  resolvedToggle && typeof resolvedToggle.control === "string" ? resolvedToggle.control : null
44017
44219
  );
44018
44220
  const resolvedControl = normalizeControl(typeof control === "string" ? control : null) || toggleControl || "select";
44019
- const config = React17.useMemo(() => {
44221
+ const config = React18.useMemo(() => {
44020
44222
  if (!resolvedToggle) return null;
44021
44223
  const base = buildLanguageToggleConfig(resolvedToggle, pageData);
44022
44224
  if (!base) return null;
@@ -44027,7 +44229,7 @@ function LanguageToggle({
44027
44229
  };
44028
44230
  }, [resolvedToggle, pageData, label, ariaLabel]);
44029
44231
  if (!config) return null;
44030
- return /* @__PURE__ */ React17.createElement(
44232
+ return /* @__PURE__ */ React18.createElement(
44031
44233
  LanguageToggleControl,
44032
44234
  {
44033
44235
  config,
@@ -44329,7 +44531,7 @@ function HeaderScript() {
44329
44531
  });
44330
44532
  })();
44331
44533
  `;
44332
- return /* @__PURE__ */ React18.createElement(
44534
+ return /* @__PURE__ */ React19.createElement(
44333
44535
  "script",
44334
44536
  {
44335
44537
  dangerouslySetInnerHTML: {
@@ -44397,16 +44599,17 @@ function getLinkNavigationData(link, navigationRoots, sectionNavigation) {
44397
44599
  function CanopyHeader(props = {}) {
44398
44600
  const {
44399
44601
  navigation: navLinksProp,
44400
- searchLabel = "Search",
44602
+ searchLabel: searchLabelProp,
44401
44603
  searchHotkey = "mod+k",
44402
- searchPlaceholder = "Search\u2026",
44604
+ searchPlaceholder: searchPlaceholderProp,
44403
44605
  brandHref = "/",
44404
44606
  title: titleProp,
44405
44607
  logo: SiteLogo,
44406
44608
  languageToggle: languageToggleProp
44407
44609
  } = props;
44408
44610
  const PageContext3 = getSafePageContext();
44409
- const context = React18.useContext(PageContext3);
44611
+ const context = React19.useContext(PageContext3);
44612
+ const { getString, formatString } = useLocale();
44410
44613
  const contextPrimaryNav = context && Array.isArray(context.primaryNavigation) ? context.primaryNavigation : [];
44411
44614
  const navLinks = navLinksProp && navLinksProp.length ? ensureArray(navLinksProp) : ensureArray(contextPrimaryNav);
44412
44615
  const contextNavigation = context && context.navigation ? context.navigation : null;
@@ -44422,6 +44625,32 @@ function CanopyHeader(props = {}) {
44422
44625
  const usesDirectorySearchRoute = trimmedSearchRoute && trimmedSearchRoute !== (defaultSearchRoute || "search");
44423
44626
  const normalizedSearchRoute = usesDirectorySearchRoute ? `/${trimmedSearchRoute}/` : `/${(trimmedSearchRoute || defaultSearchRoute || "search").replace(/^\/+/, "")}`;
44424
44627
  const resolvedLanguageToggle = languageToggleProp === false ? null : languageToggleProp === true || typeof languageToggleProp === "undefined" ? siteLanguageToggle : languageToggleProp;
44628
+ const resolvedSearchLabel = searchLabelProp != null ? searchLabelProp : getString("common.nouns.search", "Search");
44629
+ const resolvedSearchPlaceholder = searchPlaceholderProp != null ? searchPlaceholderProp : getString("common.phrases.placeholder_search", "Search\u2026");
44630
+ const primaryNavigationLabel = getString(
44631
+ "common.nouns.primary_navigation",
44632
+ "Primary navigation"
44633
+ );
44634
+ const openSearchButtonLabel = formatString(
44635
+ "common.phrases.open_content",
44636
+ "Open {content}",
44637
+ { content: resolvedSearchLabel }
44638
+ );
44639
+ const openNavButtonLabel = formatString(
44640
+ "common.phrases.open_content",
44641
+ "Open {content}",
44642
+ { content: primaryNavigationLabel }
44643
+ );
44644
+ const closeNavLabel = formatString(
44645
+ "common.phrases.close_content",
44646
+ "Close {content}",
44647
+ { content: primaryNavigationLabel }
44648
+ );
44649
+ const closeSearchLabel = formatString(
44650
+ "common.phrases.close_content",
44651
+ "Close {content}",
44652
+ { content: resolvedSearchLabel }
44653
+ );
44425
44654
  const defaultHeaderTitle = contextSiteTitle || "Site title";
44426
44655
  const normalizedTitleProp = typeof titleProp === "string" ? titleProp.trim() : "";
44427
44656
  const resolvedTitle = normalizedTitleProp || defaultHeaderTitle;
@@ -44429,8 +44658,20 @@ function CanopyHeader(props = {}) {
44429
44658
  const navigationRoots = contextNavigation && contextNavigation.allRoots ? contextNavigation.allRoots : null;
44430
44659
  const sectionHeading = sectionNavigation && sectionNavigation.title || (sectionNavigation && sectionNavigation.root ? sectionNavigation.root.title : "");
44431
44660
  const hasSectionNav = !!(sectionNavigation && sectionNavigation.root && Array.isArray(sectionNavigation.root.children) && sectionNavigation.root.children.length);
44432
- const sectionLabel = sectionHeading ? `More in ${sectionHeading}` : "More in this section";
44433
- const sectionAriaLabel = sectionHeading ? `${sectionHeading} section navigation` : "Section navigation";
44661
+ const sectionNavFallback = getString(
44662
+ "common.nouns.section_navigation",
44663
+ "Section navigation"
44664
+ );
44665
+ const sectionLabel = sectionHeading ? formatString(
44666
+ "common.phrases.nav_label",
44667
+ "{content} navigation",
44668
+ { content: sectionHeading }
44669
+ ) : sectionNavFallback;
44670
+ const sectionAriaLabel = sectionHeading ? formatString(
44671
+ "common.phrases.nav_label",
44672
+ "{content} navigation",
44673
+ { content: sectionHeading }
44674
+ ) : sectionNavFallback;
44434
44675
  const defaultSectionLabel = sectionLabel;
44435
44676
  const defaultSectionAriaLabel = sectionAriaLabel;
44436
44677
  const shouldAttachSectionNav = (link) => {
@@ -44443,14 +44684,14 @@ function CanopyHeader(props = {}) {
44443
44684
  return !!(rootNode && Array.isArray(rootNode.children) && rootNode.children.length);
44444
44685
  };
44445
44686
  const hasIntegratedSectionNav = navLinks.some(shouldAttachSectionNav);
44446
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
44687
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
44447
44688
  "header",
44448
44689
  {
44449
44690
  className: "canopy-header",
44450
44691
  "data-mobile-nav": "closed",
44451
44692
  "data-mobile-search": "closed"
44452
44693
  },
44453
- /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React18.createElement(
44694
+ /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React19.createElement(
44454
44695
  CanopyBrand,
44455
44696
  {
44456
44697
  label: resolvedTitle,
@@ -44459,22 +44700,22 @@ function CanopyHeader(props = {}) {
44459
44700
  Logo: SiteLogo
44460
44701
  }
44461
44702
  )),
44462
- /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React18.createElement(
44703
+ /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React19.createElement(
44463
44704
  SearchPanel,
44464
44705
  {
44465
- label: searchLabel,
44706
+ label: resolvedSearchLabel,
44466
44707
  hotkey: searchHotkey,
44467
- placeholder: searchPlaceholder,
44708
+ placeholder: resolvedSearchPlaceholder,
44468
44709
  searchPath: normalizedSearchRoute
44469
44710
  }
44470
44711
  )),
44471
- /* @__PURE__ */ React18.createElement(
44712
+ /* @__PURE__ */ React19.createElement(
44472
44713
  "nav",
44473
44714
  {
44474
44715
  className: "canopy-nav-links canopy-header__desktop-nav",
44475
- "aria-label": "Primary navigation"
44716
+ "aria-label": primaryNavigationLabel
44476
44717
  },
44477
- navLinks.map((link) => /* @__PURE__ */ React18.createElement(
44718
+ navLinks.map((link) => /* @__PURE__ */ React19.createElement(
44478
44719
  "a",
44479
44720
  {
44480
44721
  key: link.href,
@@ -44484,7 +44725,7 @@ function CanopyHeader(props = {}) {
44484
44725
  link.label || link.href
44485
44726
  ))
44486
44727
  ),
44487
- /* @__PURE__ */ React18.createElement("div", { className: "canopy-header__actions" }, resolvedLanguageToggle ? /* @__PURE__ */ React18.createElement(
44728
+ /* @__PURE__ */ React19.createElement("div", { className: "canopy-header__actions" }, resolvedLanguageToggle ? /* @__PURE__ */ React19.createElement(
44488
44729
  LanguageToggle,
44489
44730
  {
44490
44731
  languageToggle: resolvedLanguageToggle,
@@ -44492,17 +44733,17 @@ function CanopyHeader(props = {}) {
44492
44733
  variant: "desktop",
44493
44734
  className: "canopy-header__language-toggle canopy-header__language-toggle--desktop"
44494
44735
  }
44495
- ) : null, /* @__PURE__ */ React18.createElement(
44736
+ ) : null, /* @__PURE__ */ React19.createElement(
44496
44737
  "button",
44497
44738
  {
44498
44739
  type: "button",
44499
44740
  className: "canopy-header__icon-button canopy-header__search-trigger",
44500
- "aria-label": "Open search",
44741
+ "aria-label": openSearchButtonLabel,
44501
44742
  "aria-controls": "canopy-modal-search",
44502
44743
  "aria-expanded": "false",
44503
44744
  "data-canopy-header-toggle": "search"
44504
44745
  },
44505
- /* @__PURE__ */ React18.createElement(
44746
+ /* @__PURE__ */ React19.createElement(
44506
44747
  "svg",
44507
44748
  {
44508
44749
  xmlns: "http://www.w3.org/2000/svg",
@@ -44512,7 +44753,7 @@ function CanopyHeader(props = {}) {
44512
44753
  strokeWidth: "1.5",
44513
44754
  className: "canopy-header__search-icon"
44514
44755
  },
44515
- /* @__PURE__ */ React18.createElement(
44756
+ /* @__PURE__ */ React19.createElement(
44516
44757
  "path",
44517
44758
  {
44518
44759
  strokeLinecap: "round",
@@ -44521,17 +44762,17 @@ function CanopyHeader(props = {}) {
44521
44762
  }
44522
44763
  )
44523
44764
  )
44524
- ), /* @__PURE__ */ React18.createElement(
44765
+ ), /* @__PURE__ */ React19.createElement(
44525
44766
  "button",
44526
44767
  {
44527
44768
  type: "button",
44528
44769
  className: "canopy-header__icon-button canopy-header__menu",
44529
- "aria-label": "Open navigation",
44770
+ "aria-label": openNavButtonLabel,
44530
44771
  "aria-controls": "canopy-modal-nav",
44531
44772
  "aria-expanded": "false",
44532
44773
  "data-canopy-header-toggle": "nav"
44533
44774
  },
44534
- /* @__PURE__ */ React18.createElement(
44775
+ /* @__PURE__ */ React19.createElement(
44535
44776
  "svg",
44536
44777
  {
44537
44778
  xmlns: "http://www.w3.org/2000/svg",
@@ -44541,7 +44782,7 @@ function CanopyHeader(props = {}) {
44541
44782
  stroke: "currentColor",
44542
44783
  className: "canopy-header__menu-icon"
44543
44784
  },
44544
- /* @__PURE__ */ React18.createElement(
44785
+ /* @__PURE__ */ React19.createElement(
44545
44786
  "path",
44546
44787
  {
44547
44788
  strokeLinecap: "round",
@@ -44551,7 +44792,7 @@ function CanopyHeader(props = {}) {
44551
44792
  )
44552
44793
  )
44553
44794
  ))
44554
- ), /* @__PURE__ */ React18.createElement(
44795
+ ), /* @__PURE__ */ React19.createElement(
44555
44796
  CanopyModal,
44556
44797
  {
44557
44798
  id: "canopy-modal-nav",
@@ -44560,10 +44801,10 @@ function CanopyHeader(props = {}) {
44560
44801
  label: resolvedTitle,
44561
44802
  logo: SiteLogo,
44562
44803
  href: brandHref,
44563
- closeLabel: "Close navigation",
44804
+ closeLabel: closeNavLabel,
44564
44805
  closeDataAttr: "nav"
44565
44806
  },
44566
- resolvedLanguageToggle ? /* @__PURE__ */ React18.createElement(
44807
+ resolvedLanguageToggle ? /* @__PURE__ */ React19.createElement(
44567
44808
  LanguageToggle,
44568
44809
  {
44569
44810
  languageToggle: resolvedLanguageToggle,
@@ -44572,13 +44813,13 @@ function CanopyHeader(props = {}) {
44572
44813
  className: "canopy-header__language-toggle canopy-header__language-toggle--mobile"
44573
44814
  }
44574
44815
  ) : null,
44575
- /* @__PURE__ */ React18.createElement(
44816
+ /* @__PURE__ */ React19.createElement(
44576
44817
  "nav",
44577
44818
  {
44578
44819
  className: "canopy-nav-links canopy-modal__nav",
44579
- "aria-label": "Primary navigation"
44820
+ "aria-label": primaryNavigationLabel
44580
44821
  },
44581
- /* @__PURE__ */ React18.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
44822
+ /* @__PURE__ */ React19.createElement("ul", { className: "canopy-modal__nav-list", role: "list" }, navLinks.map((link, index) => {
44582
44823
  const navData = getLinkNavigationData(
44583
44824
  link,
44584
44825
  navigationRoots,
@@ -44587,9 +44828,18 @@ function CanopyHeader(props = {}) {
44587
44828
  const navRoot = navData && navData.root ? navData.root : null;
44588
44829
  const hasChildren = !!(navRoot && Array.isArray(navRoot.children) && navRoot.children.length);
44589
44830
  const nestedId = hasChildren ? `canopy-modal-section-${index}` : null;
44590
- const toggleLabel = link.label ? `Toggle ${link.label} menu` : "Toggle section menu";
44831
+ const toggleLabelTarget = link.label ? formatString(
44832
+ "common.phrases.nav_label",
44833
+ "{content} navigation",
44834
+ { content: link.label }
44835
+ ) : primaryNavigationLabel;
44836
+ const toggleLabel = formatString(
44837
+ "common.phrases.toggle_content",
44838
+ "Toggle {content}",
44839
+ { content: toggleLabelTarget }
44840
+ );
44591
44841
  const defaultExpanded = hasChildren && !!navRoot.isExpanded;
44592
- return /* @__PURE__ */ React18.createElement(
44842
+ return /* @__PURE__ */ React19.createElement(
44593
44843
  "li",
44594
44844
  {
44595
44845
  className: "canopy-modal__nav-item",
@@ -44598,7 +44848,7 @@ function CanopyHeader(props = {}) {
44598
44848
  "data-expanded": defaultExpanded ? "true" : "false",
44599
44849
  "data-default-expanded": defaultExpanded ? "true" : void 0
44600
44850
  },
44601
- /* @__PURE__ */ React18.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React18.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React18.createElement(
44851
+ /* @__PURE__ */ React19.createElement("div", { className: "canopy-modal__nav-row" }, /* @__PURE__ */ React19.createElement("a", { href: link.href }, link.label || link.href), hasChildren ? /* @__PURE__ */ React19.createElement(
44602
44852
  "button",
44603
44853
  {
44604
44854
  type: "button",
@@ -44608,7 +44858,7 @@ function CanopyHeader(props = {}) {
44608
44858
  "aria-label": toggleLabel,
44609
44859
  "data-canopy-nav-item-toggle": nestedId || void 0
44610
44860
  },
44611
- /* @__PURE__ */ React18.createElement(
44861
+ /* @__PURE__ */ React19.createElement(
44612
44862
  "svg",
44613
44863
  {
44614
44864
  xmlns: "http://www.w3.org/2000/svg",
@@ -44618,7 +44868,7 @@ function CanopyHeader(props = {}) {
44618
44868
  strokeWidth: "1.5",
44619
44869
  className: "canopy-modal__nav-toggle-icon"
44620
44870
  },
44621
- /* @__PURE__ */ React18.createElement(
44871
+ /* @__PURE__ */ React19.createElement(
44622
44872
  "path",
44623
44873
  {
44624
44874
  strokeLinecap: "round",
@@ -44627,16 +44877,20 @@ function CanopyHeader(props = {}) {
44627
44877
  }
44628
44878
  )
44629
44879
  ),
44630
- /* @__PURE__ */ React18.createElement("span", { className: "sr-only" }, toggleLabel)
44880
+ /* @__PURE__ */ React19.createElement("span", { className: "sr-only" }, toggleLabel)
44631
44881
  ) : null),
44632
- hasChildren ? /* @__PURE__ */ React18.createElement(
44882
+ hasChildren ? /* @__PURE__ */ React19.createElement(
44633
44883
  NavigationTree,
44634
44884
  {
44635
44885
  root: navRoot,
44636
44886
  parentKey: navData && navData.rootSegment ? navData.rootSegment : `root-${index}`,
44637
44887
  component: "div",
44638
44888
  className: "canopy-modal__section-nav canopy-modal__section-nav--nested",
44639
- "aria-label": navData && navData.title ? `${navData.title} section navigation` : defaultSectionAriaLabel,
44889
+ "aria-label": navData && navData.title ? formatString(
44890
+ "common.phrases.nav_label",
44891
+ "{content} navigation",
44892
+ { content: navData.title }
44893
+ ) : defaultSectionAriaLabel,
44640
44894
  "aria-hidden": defaultExpanded ? "false" : "true",
44641
44895
  hidden: !defaultExpanded,
44642
44896
  id: nestedId || void 0
@@ -44645,7 +44899,7 @@ function CanopyHeader(props = {}) {
44645
44899
  );
44646
44900
  }))
44647
44901
  ),
44648
- hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React18.createElement(
44902
+ hasSectionNav && !hasIntegratedSectionNav ? /* @__PURE__ */ React19.createElement(
44649
44903
  NavigationTree,
44650
44904
  {
44651
44905
  root: sectionNavigation.root,
@@ -44655,7 +44909,7 @@ function CanopyHeader(props = {}) {
44655
44909
  parentKey: "fallback-nav"
44656
44910
  }
44657
44911
  ) : null
44658
- ), /* @__PURE__ */ React18.createElement(
44912
+ ), /* @__PURE__ */ React19.createElement(
44659
44913
  CanopyModal,
44660
44914
  {
44661
44915
  id: "canopy-modal-search",
@@ -44664,31 +44918,31 @@ function CanopyHeader(props = {}) {
44664
44918
  label: resolvedTitle,
44665
44919
  logo: SiteLogo,
44666
44920
  href: brandHref,
44667
- closeLabel: "Close search",
44921
+ closeLabel: closeSearchLabel,
44668
44922
  closeDataAttr: "search",
44669
44923
  bodyClassName: "canopy-modal__body--search"
44670
44924
  },
44671
- /* @__PURE__ */ React18.createElement(
44925
+ /* @__PURE__ */ React19.createElement(
44672
44926
  SearchPanel,
44673
44927
  {
44674
- label: searchLabel,
44928
+ label: resolvedSearchLabel,
44675
44929
  hotkey: searchHotkey,
44676
- placeholder: searchPlaceholder,
44930
+ placeholder: resolvedSearchPlaceholder,
44677
44931
  searchPath: normalizedSearchRoute
44678
44932
  }
44679
44933
  )
44680
- ), /* @__PURE__ */ React18.createElement(HeaderScript, null));
44934
+ ), /* @__PURE__ */ React19.createElement(HeaderScript, null));
44681
44935
  }
44682
44936
 
44683
44937
  // ui/src/layout/CanopyFooter.jsx
44684
- import React19 from "react";
44938
+ import React20 from "react";
44685
44939
  function CanopyFooter({ className = "", children }) {
44686
44940
  const footerClassName = ["canopy-footer", className].filter(Boolean).join(" ");
44687
- return /* @__PURE__ */ React19.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React19.createElement("div", { className: "canopy-footer__inner" }, children));
44941
+ return /* @__PURE__ */ React20.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React20.createElement("div", { className: "canopy-footer__inner" }, children));
44688
44942
  }
44689
44943
 
44690
44944
  // ui/src/layout/TeaserCard.jsx
44691
- import React20 from "react";
44945
+ import React21 from "react";
44692
44946
  function TeaserCard({
44693
44947
  href = "",
44694
44948
  title = "",
@@ -44709,7 +44963,7 @@ function TeaserCard({
44709
44963
  ].filter(Boolean).join(" ");
44710
44964
  const showThumb = type === "work" && thumbnail;
44711
44965
  const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
44712
- return /* @__PURE__ */ React20.createElement(
44966
+ return /* @__PURE__ */ React21.createElement(
44713
44967
  Tag,
44714
44968
  {
44715
44969
  className: classes,
@@ -44717,7 +44971,7 @@ function TeaserCard({
44717
44971
  "data-canopy-item": href ? "" : void 0,
44718
44972
  ...rest
44719
44973
  },
44720
- showThumb ? /* @__PURE__ */ React20.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React20.createElement(
44974
+ showThumb ? /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React21.createElement(
44721
44975
  "img",
44722
44976
  {
44723
44977
  src: thumbnail,
@@ -44727,12 +44981,12 @@ function TeaserCard({
44727
44981
  className: "canopy-search-teaser__thumb-img"
44728
44982
  }
44729
44983
  )) : null,
44730
- /* @__PURE__ */ React20.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React20.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React20.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
44984
+ /* @__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)
44731
44985
  );
44732
44986
  }
44733
44987
 
44734
44988
  // ui/src/layout/GoogleAnalytics.jsx
44735
- import React21 from "react";
44989
+ import React22 from "react";
44736
44990
  var GA_HOST = "https://www.googletagmanager.com/gtag/js";
44737
44991
  function GoogleAnalytics({ id }) {
44738
44992
  if (!id) return null;
@@ -44742,11 +44996,11 @@ function GoogleAnalytics({ id }) {
44742
44996
  gtag('js', new Date());
44743
44997
  gtag('config', '${id}');
44744
44998
  `;
44745
- return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement("script", { async: true, src: `${GA_HOST}?id=${encodeURIComponent(id)}` }), /* @__PURE__ */ React21.createElement("script", { dangerouslySetInnerHTML: { __html: inlineConfig } }));
44999
+ 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 } }));
44746
45000
  }
44747
45001
 
44748
45002
  // ui/src/iiif/Viewer.jsx
44749
- import React22, { useEffect as useEffect2, useState as useState2 } from "react";
45003
+ import React23, { useEffect as useEffect2, useState as useState2 } from "react";
44750
45004
  var DEFAULT_VIEWER_OPTIONS = {
44751
45005
  showDownload: false,
44752
45006
  showIIIFBadge: false,
@@ -44802,7 +45056,7 @@ var Viewer = (props) => {
44802
45056
  } catch (_) {
44803
45057
  json = "{}";
44804
45058
  }
44805
- return /* @__PURE__ */ React22.createElement("div", { "data-canopy-viewer": "1", className: "not-prose" }, /* @__PURE__ */ React22.createElement(
45059
+ return /* @__PURE__ */ React23.createElement("div", { "data-canopy-viewer": "1", className: "not-prose" }, /* @__PURE__ */ React23.createElement(
44806
45060
  "script",
44807
45061
  {
44808
45062
  type: "application/json",
@@ -44810,11 +45064,11 @@ var Viewer = (props) => {
44810
45064
  }
44811
45065
  ));
44812
45066
  }
44813
- return /* @__PURE__ */ React22.createElement(CloverViewer, { ...props, options: mergedOptions });
45067
+ return /* @__PURE__ */ React23.createElement(CloverViewer, { ...props, options: mergedOptions });
44814
45068
  };
44815
45069
 
44816
45070
  // ui/src/iiif/Slider.jsx
44817
- import React23, { useEffect as useEffect3, useState as useState3 } from "react";
45071
+ import React24, { useEffect as useEffect3, useState as useState3 } from "react";
44818
45072
 
44819
45073
  // ui/src/iiif/sliderOptions.js
44820
45074
  var UNIT_TOKEN = "__canopySliderUnit";
@@ -44961,7 +45215,7 @@ var Slider = (props = {}) => {
44961
45215
  } catch (_) {
44962
45216
  json = "{}";
44963
45217
  }
44964
- return /* @__PURE__ */ React23.createElement("div", { className: sliderClassName, "data-canopy-slider": "1" }, /* @__PURE__ */ React23.createElement(
45218
+ return /* @__PURE__ */ React24.createElement("div", { className: sliderClassName, "data-canopy-slider": "1" }, /* @__PURE__ */ React24.createElement(
44965
45219
  "script",
44966
45220
  {
44967
45221
  type: "application/json",
@@ -44969,11 +45223,11 @@ var Slider = (props = {}) => {
44969
45223
  }
44970
45224
  ));
44971
45225
  }
44972
- return /* @__PURE__ */ React23.createElement(CloverSlider, { ...resolvedProps });
45226
+ return /* @__PURE__ */ React24.createElement(CloverSlider, { ...resolvedProps });
44973
45227
  };
44974
45228
 
44975
45229
  // ui/src/iiif/Scroll.jsx
44976
- import React24, { useEffect as useEffect4, useState as useState4 } from "react";
45230
+ import React25, { useEffect as useEffect4, useState as useState4 } from "react";
44977
45231
  var Scroll = (props) => {
44978
45232
  const [CloverScroll, setCloverScroll] = useState4(null);
44979
45233
  useEffect4(() => {
@@ -44998,7 +45252,7 @@ var Scroll = (props) => {
44998
45252
  } catch (_) {
44999
45253
  json = "{}";
45000
45254
  }
45001
- return /* @__PURE__ */ React24.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React24.createElement(
45255
+ return /* @__PURE__ */ React25.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React25.createElement(
45002
45256
  "script",
45003
45257
  {
45004
45258
  type: "application/json",
@@ -45006,11 +45260,11 @@ var Scroll = (props) => {
45006
45260
  }
45007
45261
  ));
45008
45262
  }
45009
- return /* @__PURE__ */ React24.createElement(CloverScroll, { ...props });
45263
+ return /* @__PURE__ */ React25.createElement(CloverScroll, { ...props });
45010
45264
  };
45011
45265
 
45012
45266
  // ui/src/iiif/Image.jsx
45013
- import React25, { useEffect as useEffect5, useState as useState5 } from "react";
45267
+ import React26, { useEffect as useEffect5, useState as useState5 } from "react";
45014
45268
  var Image = (props = {}) => {
45015
45269
  const [CloverImage, setCloverImage] = useState5(null);
45016
45270
  const baseClass = "canopy-iiif-image";
@@ -45043,7 +45297,7 @@ var Image = (props = {}) => {
45043
45297
  } catch (_) {
45044
45298
  json = "{}";
45045
45299
  }
45046
- return /* @__PURE__ */ React25.createElement("figure", { className: rootClassName }, /* @__PURE__ */ React25.createElement(
45300
+ return /* @__PURE__ */ React26.createElement("figure", { className: rootClassName }, /* @__PURE__ */ React26.createElement(
45047
45301
  "div",
45048
45302
  {
45049
45303
  className: `${baseClass}__placeholder`,
@@ -45053,20 +45307,20 @@ var Image = (props = {}) => {
45053
45307
  "--canopy-iiif-image-bg": backgroundColor
45054
45308
  }
45055
45309
  },
45056
- /* @__PURE__ */ React25.createElement(
45310
+ /* @__PURE__ */ React26.createElement(
45057
45311
  "script",
45058
45312
  {
45059
45313
  type: "application/json",
45060
45314
  dangerouslySetInnerHTML: { __html: json }
45061
45315
  }
45062
45316
  )
45063
- ), caption && /* @__PURE__ */ React25.createElement("figcaption", { className: `${baseClass}__caption` }, caption));
45317
+ ), caption && /* @__PURE__ */ React26.createElement("figcaption", { className: `${baseClass}__caption` }, caption));
45064
45318
  }
45065
- return /* @__PURE__ */ React25.createElement(CloverImage, { ...props, className: rootClassName });
45319
+ return /* @__PURE__ */ React26.createElement(CloverImage, { ...props, className: rootClassName });
45066
45320
  };
45067
45321
 
45068
45322
  // ui/src/iiif/ImageStory.jsx
45069
- import React26, { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef2 } from "react";
45323
+ import React27, { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef2 } from "react";
45070
45324
 
45071
45325
  // ui/src/iiif/imageStoryRuntime.js
45072
45326
  var STORIIIES_STYLE_URL = "https://unpkg.com/@cogapp/storiiies-viewer@latest/dist/storiiies-viewer.css";
@@ -45292,7 +45546,7 @@ var ImageStory = (props = {}) => {
45292
45546
  }
45293
45547
  };
45294
45548
  }, [iiifContent, disablePanAndZoom, pointOfInterestSvgUrl, viewerOptions]);
45295
- return /* @__PURE__ */ React26.createElement(
45549
+ return /* @__PURE__ */ React27.createElement(
45296
45550
  "div",
45297
45551
  {
45298
45552
  ref: containerRef,
@@ -45305,7 +45559,7 @@ var ImageStory = (props = {}) => {
45305
45559
  },
45306
45560
  ...rest
45307
45561
  },
45308
- /* @__PURE__ */ React26.createElement(
45562
+ /* @__PURE__ */ React27.createElement(
45309
45563
  "script",
45310
45564
  {
45311
45565
  type: "application/json",
@@ -45316,13 +45570,13 @@ var ImageStory = (props = {}) => {
45316
45570
  };
45317
45571
 
45318
45572
  // ui/src/iiif/Properties/Id.jsx
45319
- import React27 from "react";
45573
+ import React28 from "react";
45320
45574
  function Id({ title = "IIIF Manifest", id, ...props }) {
45321
- return /* @__PURE__ */ React27.createElement("dl", null, /* @__PURE__ */ React27.createElement("dt", null, title), /* @__PURE__ */ React27.createElement("dd", null, /* @__PURE__ */ React27.createElement("a", { href: id }, id)));
45575
+ return /* @__PURE__ */ React28.createElement("dl", null, /* @__PURE__ */ React28.createElement("dt", null, title), /* @__PURE__ */ React28.createElement("dd", null, /* @__PURE__ */ React28.createElement("a", { href: id }, id)));
45322
45576
  }
45323
45577
 
45324
45578
  // ui/src/iiif/MdxRelatedItems.jsx
45325
- import React28 from "react";
45579
+ import React29 from "react";
45326
45580
  function MdxRelatedItems(props) {
45327
45581
  let json = "{}";
45328
45582
  try {
@@ -45330,7 +45584,7 @@ function MdxRelatedItems(props) {
45330
45584
  } catch (_) {
45331
45585
  json = "{}";
45332
45586
  }
45333
- return /* @__PURE__ */ React28.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React28.createElement(
45587
+ return /* @__PURE__ */ React29.createElement("div", { "data-canopy-related-items": "1" }, /* @__PURE__ */ React29.createElement(
45334
45588
  "script",
45335
45589
  {
45336
45590
  type: "application/json",
@@ -45340,7 +45594,7 @@ function MdxRelatedItems(props) {
45340
45594
  }
45341
45595
 
45342
45596
  // ui/src/search/MdxSearchResults.jsx
45343
- import React29 from "react";
45597
+ import React30 from "react";
45344
45598
  function MdxSearchResults(props) {
45345
45599
  let json = "{}";
45346
45600
  try {
@@ -45348,11 +45602,11 @@ function MdxSearchResults(props) {
45348
45602
  } catch (_) {
45349
45603
  json = "{}";
45350
45604
  }
45351
- return /* @__PURE__ */ React29.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React29.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45605
+ return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45352
45606
  }
45353
45607
 
45354
45608
  // ui/src/search/SearchSummary.jsx
45355
- import React30 from "react";
45609
+ import React31 from "react";
45356
45610
  function SearchSummary(props) {
45357
45611
  let json = "{}";
45358
45612
  try {
@@ -45360,11 +45614,11 @@ function SearchSummary(props) {
45360
45614
  } catch (_) {
45361
45615
  json = "{}";
45362
45616
  }
45363
- return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45617
+ return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45364
45618
  }
45365
45619
 
45366
45620
  // ui/src/search/MdxSearchTabs.jsx
45367
- import React31 from "react";
45621
+ import React32 from "react";
45368
45622
  function MdxSearchTabs(props) {
45369
45623
  let json = "{}";
45370
45624
  try {
@@ -45372,11 +45626,11 @@ function MdxSearchTabs(props) {
45372
45626
  } catch (_) {
45373
45627
  json = "{}";
45374
45628
  }
45375
- return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45629
+ return /* @__PURE__ */ React32.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React32.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
45376
45630
  }
45377
45631
 
45378
45632
  // ui/src/search/MdxSearch.jsx
45379
- import React32 from "react";
45633
+ import React33 from "react";
45380
45634
  function MdxSearch(props = {}) {
45381
45635
  const {
45382
45636
  layout,
@@ -45394,15 +45648,15 @@ function MdxSearch(props = {}) {
45394
45648
  resultsPayload.layout = layout;
45395
45649
  }
45396
45650
  const classes = ["canopy-search", className].filter(Boolean).join(" ");
45397
- return /* @__PURE__ */ React32.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React32.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React32.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React32.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
45651
+ return /* @__PURE__ */ React33.createElement("section", { className: classes, "data-canopy-search": "1" }, showTabs ? /* @__PURE__ */ React33.createElement(MdxSearchTabs, { ...tabsProps }) : null, showSummary ? /* @__PURE__ */ React33.createElement(SearchSummary, { ...summaryProps }) : null, showResults ? /* @__PURE__ */ React33.createElement(MdxSearchResults, { ...resultsPayload }) : null, children || null);
45398
45652
  }
45399
45653
 
45400
45654
  // ui/src/search/SearchResults.jsx
45401
- import React33 from "react";
45655
+ import React34 from "react";
45402
45656
  function DefaultArticleTemplate({ record, query }) {
45403
45657
  if (!record) return null;
45404
45658
  const metadata = Array.isArray(record.metadata) ? record.metadata : [];
45405
- return /* @__PURE__ */ React33.createElement(
45659
+ return /* @__PURE__ */ React34.createElement(
45406
45660
  ArticleCard,
45407
45661
  {
45408
45662
  href: record.href,
@@ -45420,7 +45674,7 @@ function DefaultFigureTemplate({ record, thumbnailAspectRatio }) {
45420
45674
  if (!record) return null;
45421
45675
  const hasDims = Number.isFinite(Number(record.thumbnailWidth)) && Number(record.thumbnailWidth) > 0 && Number.isFinite(Number(record.thumbnailHeight)) && Number(record.thumbnailHeight) > 0;
45422
45676
  const aspect = Number.isFinite(Number(thumbnailAspectRatio)) && Number(thumbnailAspectRatio) > 0 ? Number(thumbnailAspectRatio) : hasDims ? Number(record.thumbnailWidth) / Number(record.thumbnailHeight) : void 0;
45423
- return /* @__PURE__ */ React33.createElement(
45677
+ return /* @__PURE__ */ React34.createElement(
45424
45678
  Card,
45425
45679
  {
45426
45680
  href: record.href,
@@ -45440,8 +45694,17 @@ function SearchResults({
45440
45694
  templates = {},
45441
45695
  variant = "auto"
45442
45696
  }) {
45697
+ const { getString } = useLocale();
45698
+ const resultsRegionLabel = getString(
45699
+ "common.phrases.results_label",
45700
+ "Search results"
45701
+ );
45702
+ const noResultsLabel = getString(
45703
+ "common.statuses.no_matches",
45704
+ "No matches found."
45705
+ );
45443
45706
  if (!results.length) {
45444
- return /* @__PURE__ */ React33.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React33.createElement("em", null, "No results"));
45707
+ return /* @__PURE__ */ React34.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React34.createElement("em", null, noResultsLabel));
45445
45708
  }
45446
45709
  const normalizedType = String(type || "all").toLowerCase();
45447
45710
  const normalizedVariant = variant === "figure" || variant === "article" ? variant : "auto";
@@ -45449,9 +45712,9 @@ function SearchResults({
45449
45712
  const FigureTemplate = templates && templates.figure ? templates.figure : DefaultFigureTemplate;
45450
45713
  const ArticleTemplate = templates && templates.article ? templates.article : DefaultArticleTemplate;
45451
45714
  if (isAnnotationView) {
45452
- return /* @__PURE__ */ React33.createElement("div", { id: "search-results", className: "space-y-4", role: "region", "aria-label": "Search results" }, results.map((r, i) => {
45715
+ return /* @__PURE__ */ React34.createElement("div", { id: "search-results", className: "space-y-4", role: "region", "aria-label": resultsRegionLabel }, results.map((r, i) => {
45453
45716
  if (!r) return null;
45454
- return /* @__PURE__ */ React33.createElement(
45717
+ return /* @__PURE__ */ React34.createElement(
45455
45718
  ArticleTemplate,
45456
45719
  {
45457
45720
  key: r.id || i,
@@ -45469,20 +45732,20 @@ function SearchResults({
45469
45732
  return !isWorkRecord(record) || normalizedType !== "work";
45470
45733
  };
45471
45734
  if (layout === "list") {
45472
- return /* @__PURE__ */ React33.createElement("div", { id: "search-results", className: "space-y-6", role: "region", "aria-label": "Search results" }, results.map((r, i) => {
45735
+ return /* @__PURE__ */ React34.createElement("div", { id: "search-results", className: "space-y-6", role: "region", "aria-label": resultsRegionLabel }, results.map((r, i) => {
45473
45736
  if (shouldRenderAsArticle(r)) {
45474
- return /* @__PURE__ */ React33.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React33.createElement(ArticleTemplate, { record: r, query, layout }));
45737
+ return /* @__PURE__ */ React34.createElement("div", { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React34.createElement(ArticleTemplate, { record: r, query, layout }));
45475
45738
  }
45476
45739
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
45477
45740
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
45478
- return /* @__PURE__ */ React33.createElement(
45741
+ return /* @__PURE__ */ React34.createElement(
45479
45742
  "div",
45480
45743
  {
45481
45744
  key: i,
45482
45745
  className: `search-result ${r.type}`,
45483
45746
  "data-thumbnail-aspect-ratio": aspect
45484
45747
  },
45485
- /* @__PURE__ */ React33.createElement(
45748
+ /* @__PURE__ */ React34.createElement(
45486
45749
  FigureTemplate,
45487
45750
  {
45488
45751
  record: r,
@@ -45494,20 +45757,20 @@ function SearchResults({
45494
45757
  );
45495
45758
  }));
45496
45759
  }
45497
- return /* @__PURE__ */ React33.createElement("div", { id: "search-results", role: "region", "aria-label": "Search results" }, /* @__PURE__ */ React33.createElement(Grid, null, results.map((r, i) => {
45760
+ return /* @__PURE__ */ React34.createElement("div", { id: "search-results", role: "region", "aria-label": resultsRegionLabel }, /* @__PURE__ */ React34.createElement(Grid, null, results.map((r, i) => {
45498
45761
  if (shouldRenderAsArticle(r)) {
45499
- return /* @__PURE__ */ React33.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React33.createElement(ArticleTemplate, { record: r, query, layout }));
45762
+ return /* @__PURE__ */ React34.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, /* @__PURE__ */ React34.createElement(ArticleTemplate, { record: r, query, layout }));
45500
45763
  }
45501
45764
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
45502
45765
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
45503
- return /* @__PURE__ */ React33.createElement(
45766
+ return /* @__PURE__ */ React34.createElement(
45504
45767
  GridItem,
45505
45768
  {
45506
45769
  key: i,
45507
45770
  className: `search-result ${r.type}`,
45508
45771
  "data-thumbnail-aspect-ratio": aspect
45509
45772
  },
45510
- /* @__PURE__ */ React33.createElement(
45773
+ /* @__PURE__ */ React34.createElement(
45511
45774
  FigureTemplate,
45512
45775
  {
45513
45776
  record: r,
@@ -45521,7 +45784,7 @@ function SearchResults({
45521
45784
  }
45522
45785
 
45523
45786
  // ui/src/search/SearchTabs.jsx
45524
- import React34, { useRef as useRef3, useState as useState6, useEffect as useEffect7 } from "react";
45787
+ import React35, { useRef as useRef3, useState as useState6, useEffect as useEffect7 } from "react";
45525
45788
  function SearchTabs({
45526
45789
  type = "all",
45527
45790
  onTypeChange,
@@ -45532,10 +45795,34 @@ function SearchTabs({
45532
45795
  filtersLabel = "Filters",
45533
45796
  filtersOpen = false
45534
45797
  }) {
45798
+ const { getString, formatString } = useLocale();
45799
+ const typeLabels = React35.useMemo(
45800
+ () => ({
45801
+ work: getString("common.types.work", "Works"),
45802
+ page: getString("common.types.page", "Pages"),
45803
+ docs: getString("common.types.docs", "Docs")
45804
+ }),
45805
+ [getString]
45806
+ );
45807
+ const allTypesLabel = getString("common.nouns.items", "items");
45535
45808
  const orderedTypes = Array.isArray(types) ? types : [];
45536
- const toLabel = (t) => t && t.length ? t.charAt(0).toUpperCase() + t.slice(1) : "";
45809
+ const toLabel = (t) => {
45810
+ const key = String(t || "").toLowerCase();
45811
+ if (!key) return "";
45812
+ if (key === "all") {
45813
+ return allTypesLabel ? String(allTypesLabel) : "All";
45814
+ }
45815
+ if (typeLabels[key]) return typeLabels[key];
45816
+ return key.charAt(0).toUpperCase() + key.slice(1);
45817
+ };
45537
45818
  const hasFilters = typeof onOpenFilters === "function";
45538
- const filterBadge = activeFilterCount > 0 ? /* @__PURE__ */ React34.createElement("span", { className: "canopy-search-tabs__filters-count" }, "(", activeFilterCount, ")") : null;
45819
+ const resolvedFiltersLabel = typeof filtersLabel === "string" && filtersLabel.trim() ? filtersLabel : getString("common.nouns.filters", "Filters");
45820
+ const filterBadge = activeFilterCount > 0 ? /* @__PURE__ */ React35.createElement("span", { className: "canopy-search-tabs__filters-count" }, "(", activeFilterCount, ")") : null;
45821
+ const searchTypesLabel = formatString(
45822
+ "common.phrases.search_content",
45823
+ "Search types",
45824
+ { content: getString("common.nouns.types", "types") }
45825
+ );
45539
45826
  const [itemBoundingBox, setItemBoundingBox] = useState6(null);
45540
45827
  const [wrapperBoundingBox, setWrapperBoundingBox] = useState6(null);
45541
45828
  const [highlightedTab, setHighlightedTab] = useState6(null);
@@ -45575,16 +45862,16 @@ function SearchTabs({
45575
45862
  width: `${itemBoundingBox.width}px`
45576
45863
  };
45577
45864
  }
45578
- return /* @__PURE__ */ React34.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React34.createElement(
45865
+ return /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React35.createElement(
45579
45866
  "div",
45580
45867
  {
45581
45868
  role: "tablist",
45582
- "aria-label": "Search types",
45869
+ "aria-label": searchTypesLabel || "Search types",
45583
45870
  className: "canopy-search-tabs",
45584
45871
  ref: wrapperRef,
45585
45872
  onMouseLeave: resetHighlight
45586
45873
  },
45587
- /* @__PURE__ */ React34.createElement(
45874
+ /* @__PURE__ */ React35.createElement(
45588
45875
  "div",
45589
45876
  {
45590
45877
  ref: highlightRef,
@@ -45596,7 +45883,7 @@ function SearchTabs({
45596
45883
  const active = String(type).toLowerCase() === String(t).toLowerCase();
45597
45884
  const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
45598
45885
  const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
45599
- return /* @__PURE__ */ React34.createElement(
45886
+ return /* @__PURE__ */ React35.createElement(
45600
45887
  "button",
45601
45888
  {
45602
45889
  key: t,
@@ -45614,7 +45901,7 @@ function SearchTabs({
45614
45901
  ")"
45615
45902
  );
45616
45903
  })
45617
- ), hasFilters ? /* @__PURE__ */ React34.createElement(
45904
+ ), hasFilters ? /* @__PURE__ */ React35.createElement(
45618
45905
  Button,
45619
45906
  {
45620
45907
  as: "button",
@@ -45624,13 +45911,13 @@ function SearchTabs({
45624
45911
  "aria-expanded": filtersOpen ? "true" : "false",
45625
45912
  className: "canopy-search-tabs__filters-button"
45626
45913
  },
45627
- /* @__PURE__ */ React34.createElement("span", null, filtersLabel),
45914
+ /* @__PURE__ */ React35.createElement("span", null, resolvedFiltersLabel),
45628
45915
  filterBadge
45629
45916
  ) : null);
45630
45917
  }
45631
45918
 
45632
45919
  // ui/src/search/SearchFiltersDialog.jsx
45633
- import React35 from "react";
45920
+ import React36 from "react";
45634
45921
  var PageContext2 = getSafePageContext();
45635
45922
  function toArray(input) {
45636
45923
  if (!input) return [];
@@ -45664,49 +45951,59 @@ function facetMatches(values = [], query) {
45664
45951
  });
45665
45952
  return [...starts, ...contains2].slice(0, 10);
45666
45953
  }
45667
- function FacetSection({ facet, selected, onToggle }) {
45954
+ function FacetSection({
45955
+ facet,
45956
+ selected,
45957
+ onToggle,
45958
+ searchPlaceholder,
45959
+ filterLabelBuilder,
45960
+ clearButtonLabel,
45961
+ clearAriaBuilder,
45962
+ noMatchesLabel,
45963
+ emptyValuesLabel
45964
+ }) {
45668
45965
  if (!facet || !facet.label || !Array.isArray(facet.values)) return null;
45669
45966
  const { label, slug, values } = facet;
45670
45967
  const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
45671
45968
  const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
45672
45969
  const hasSelection = selectedValues.size > 0;
45673
- const [quickQuery, setQuickQuery] = React35.useState("");
45970
+ const [quickQuery, setQuickQuery] = React36.useState("");
45674
45971
  const hasQuery = quickQuery.trim().length > 0;
45675
- const filteredValues = React35.useMemo(
45972
+ const filteredValues = React36.useMemo(
45676
45973
  () => facetMatches(values, quickQuery),
45677
45974
  [values, quickQuery]
45678
45975
  );
45679
- return /* @__PURE__ */ React35.createElement(
45976
+ return /* @__PURE__ */ React36.createElement(
45680
45977
  "details",
45681
45978
  {
45682
45979
  className: "canopy-search-filters__facet",
45683
45980
  open: hasSelection
45684
45981
  },
45685
- /* @__PURE__ */ React35.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React35.createElement("span", null, label), /* @__PURE__ */ React35.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
45686
- /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React35.createElement(
45982
+ /* @__PURE__ */ React36.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React36.createElement("span", null, label), /* @__PURE__ */ React36.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
45983
+ /* @__PURE__ */ React36.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React36.createElement(
45687
45984
  "input",
45688
45985
  {
45689
45986
  type: "search",
45690
45987
  value: quickQuery,
45691
45988
  onChange: (event) => setQuickQuery(event.target.value),
45692
- placeholder: "Search values",
45989
+ placeholder: searchPlaceholder,
45693
45990
  className: "canopy-search-filters__quick-input",
45694
- "aria-label": `Filter ${label} values`
45991
+ "aria-label": filterLabelBuilder ? filterLabelBuilder(label) : `Filter ${label} values`
45695
45992
  }
45696
- ), quickQuery ? /* @__PURE__ */ React35.createElement(
45993
+ ), quickQuery ? /* @__PURE__ */ React36.createElement(
45697
45994
  "button",
45698
45995
  {
45699
45996
  type: "button",
45700
45997
  onClick: () => setQuickQuery(""),
45701
45998
  className: "canopy-search-filters__quick-clear",
45702
- "aria-label": `Clear ${label} filter search`
45999
+ "aria-label": clearAriaBuilder ? clearAriaBuilder(label) : `Clear ${label} filter search`
45703
46000
  },
45704
- "Clear"
45705
- ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React35.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React35.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
46001
+ clearButtonLabel || "Clear"
46002
+ ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-search-filters__facet-notice" }, noMatchesLabel) : null, /* @__PURE__ */ React36.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
45706
46003
  const valueSlug = String(entry.slug || entry.value || "");
45707
46004
  const isChecked = selectedValues.has(valueSlug);
45708
46005
  const inputId = checkboxId(valueSlug);
45709
- return /* @__PURE__ */ React35.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React35.createElement(
46006
+ return /* @__PURE__ */ React36.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React36.createElement(
45710
46007
  "input",
45711
46008
  {
45712
46009
  id: inputId,
@@ -45718,15 +46015,15 @@ function FacetSection({ facet, selected, onToggle }) {
45718
46015
  if (onToggle) onToggle(slug, valueSlug, nextChecked);
45719
46016
  }
45720
46017
  }
45721
- ), /* @__PURE__ */ React35.createElement(
46018
+ ), /* @__PURE__ */ React36.createElement(
45722
46019
  "label",
45723
46020
  {
45724
46021
  htmlFor: inputId,
45725
46022
  className: "canopy-search-filters__facet-label"
45726
46023
  },
45727
- /* @__PURE__ */ React35.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React35.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
46024
+ /* @__PURE__ */ React36.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React36.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
45728
46025
  ));
45729
- }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React35.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
46026
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React36.createElement("li", { className: "canopy-search-filters__facet-empty" }, emptyValuesLabel) : null))
45730
46027
  );
45731
46028
  }
45732
46029
  function SearchFiltersDialog(props = {}) {
@@ -45738,17 +46035,50 @@ function SearchFiltersDialog(props = {}) {
45738
46035
  onToggle,
45739
46036
  onClear,
45740
46037
  title,
45741
- subtitle = "Refine results by metadata",
46038
+ subtitle,
45742
46039
  brandLabel: brandLabelProp,
45743
46040
  brandHref = "/",
45744
46041
  logo: SiteLogo
45745
46042
  } = props;
46043
+ const { getString, formatString } = useLocale();
46044
+ const filtersLabel = getString("common.nouns.filters", "filters");
46045
+ const valuesLabel = getString("common.nouns.values", "values");
46046
+ const metadataLabel = getString("common.nouns.metadata", "metadata");
46047
+ const searchValuesPlaceholder = formatString(
46048
+ "common.phrases.search_content",
46049
+ "Search values",
46050
+ { content: valuesLabel }
46051
+ );
46052
+ const filterValuesLabel = (content) => formatString(
46053
+ "common.phrases.filter_values",
46054
+ "Filter {content} values",
46055
+ { content: content || valuesLabel }
46056
+ );
46057
+ const clearSearchLabel = (content) => formatString(
46058
+ "common.phrases.clear_content_search",
46059
+ "Clear {content} search",
46060
+ { content: content || filtersLabel }
46061
+ );
46062
+ const emptyValuesLabel = formatString(
46063
+ "common.statuses.empty_detail",
46064
+ "No {content} available.",
46065
+ { content: valuesLabel }
46066
+ );
46067
+ const noMatchesLabel = getString(
46068
+ "common.statuses.no_matches",
46069
+ "No matches found."
46070
+ );
46071
+ const subtitleText = subtitle != null ? subtitle : formatString(
46072
+ "common.phrases.filter_values",
46073
+ "Filter {content} values",
46074
+ { content: metadataLabel }
46075
+ );
45746
46076
  const selectedMap = normalizeSelected(selected);
45747
46077
  const activeCount = Array.from(selectedMap.values()).reduce(
45748
46078
  (total, set) => total + set.size,
45749
46079
  0
45750
46080
  );
45751
- React35.useEffect(() => {
46081
+ React36.useEffect(() => {
45752
46082
  if (!open) return void 0;
45753
46083
  if (typeof document === "undefined") return void 0;
45754
46084
  const body = document.body;
@@ -45762,13 +46092,35 @@ function SearchFiltersDialog(props = {}) {
45762
46092
  if (root2) root2.style.overflow = prevRoot;
45763
46093
  };
45764
46094
  }, [open]);
45765
- const context = React35.useContext(PageContext2);
46095
+ const context = React36.useContext(PageContext2);
45766
46096
  const contextSiteTitle = context && context.site && typeof context.site.title === "string" ? context.site.title.trim() : "";
45767
46097
  const resolvedBrandLabel = typeof brandLabelProp === "string" && brandLabelProp.trim() ? brandLabelProp : contextSiteTitle || "Site title";
45768
46098
  if (!open) return null;
45769
46099
  const brandId = "canopy-modal-filters-label";
45770
- const subtitleText = subtitle != null ? subtitle : title;
45771
- return /* @__PURE__ */ React35.createElement(
46100
+ const resolvedSubtitle = subtitleText || title;
46101
+ const modalCloseLabel = formatString(
46102
+ "common.phrases.close_content",
46103
+ "Close {content}",
46104
+ { content: filtersLabel }
46105
+ );
46106
+ const filterUnavailableLabel = formatString(
46107
+ "common.statuses.unavailable_detail",
46108
+ "{content} is unavailable.",
46109
+ { content: filtersLabel }
46110
+ );
46111
+ const noneAppliedLabel = formatString(
46112
+ "common.phrases.none_applied",
46113
+ "No {content} applied",
46114
+ { content: filtersLabel }
46115
+ );
46116
+ const appliedCountLabel = activeCount ? formatString(
46117
+ "common.phrases.applied_count",
46118
+ "{count} {content} applied",
46119
+ { count: activeCount, content: filtersLabel }
46120
+ ) : noneAppliedLabel;
46121
+ const clearAllLabel = getString("common.actions.clear_all", "Clear all");
46122
+ const doneLabel = getString("common.actions.done", "Done");
46123
+ return /* @__PURE__ */ React36.createElement(
45772
46124
  CanopyModal,
45773
46125
  {
45774
46126
  id: "canopy-modal-filters",
@@ -45778,22 +46130,28 @@ function SearchFiltersDialog(props = {}) {
45778
46130
  label: resolvedBrandLabel,
45779
46131
  logo: SiteLogo,
45780
46132
  href: brandHref,
45781
- closeLabel: "Close filters",
46133
+ closeLabel: modalCloseLabel || "Close",
45782
46134
  onClose: () => onOpenChange && onOpenChange(false),
45783
46135
  onBackgroundClick: () => onOpenChange && onOpenChange(false),
45784
46136
  bodyClassName: "canopy-modal__body--filters"
45785
46137
  },
45786
- subtitleText ? /* @__PURE__ */ React35.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
45787
- /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React35.createElement(
46138
+ resolvedSubtitle ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-search-filters__subtitle" }, resolvedSubtitle) : null,
46139
+ /* @__PURE__ */ React36.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React36.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React36.createElement(
45788
46140
  FacetSection,
45789
46141
  {
45790
46142
  key: facet.slug || facet.label,
45791
46143
  facet,
45792
46144
  selected: selectedMap,
45793
- onToggle
45794
- }
45795
- ))) : /* @__PURE__ */ React35.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
45796
- /* @__PURE__ */ React35.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React35.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React35.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React35.createElement(
46145
+ onToggle,
46146
+ searchPlaceholder: searchValuesPlaceholder,
46147
+ filterLabelBuilder: filterValuesLabel,
46148
+ clearButtonLabel: getString("common.actions.clear", "Clear"),
46149
+ clearAriaBuilder: clearSearchLabel,
46150
+ noMatchesLabel,
46151
+ emptyValuesLabel
46152
+ }
46153
+ ))) : /* @__PURE__ */ React36.createElement("p", { className: "canopy-search-filters__empty" }, filterUnavailableLabel)),
46154
+ /* @__PURE__ */ React36.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React36.createElement("div", null, appliedCountLabel), /* @__PURE__ */ React36.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React36.createElement(
45797
46155
  "button",
45798
46156
  {
45799
46157
  type: "button",
@@ -45803,54 +46161,57 @@ function SearchFiltersDialog(props = {}) {
45803
46161
  disabled: !activeCount,
45804
46162
  className: "canopy-search-filters__button canopy-search-filters__button--secondary"
45805
46163
  },
45806
- "Clear all"
45807
- ), /* @__PURE__ */ React35.createElement(
46164
+ clearAllLabel
46165
+ ), /* @__PURE__ */ React36.createElement(
45808
46166
  "button",
45809
46167
  {
45810
46168
  type: "button",
45811
46169
  onClick: () => onOpenChange && onOpenChange(false),
45812
46170
  className: "canopy-search-filters__button canopy-search-filters__button--primary"
45813
46171
  },
45814
- "Done"
46172
+ doneLabel
45815
46173
  )))
45816
46174
  );
45817
46175
  }
45818
46176
 
45819
46177
  // ui/src/search-form/MdxSearchFormModal.jsx
45820
- import React36 from "react";
46178
+ import React37 from "react";
45821
46179
  function MdxSearchFormModal(props = {}) {
45822
46180
  const {
45823
- placeholder = "Search\u2026",
46181
+ placeholder: placeholderProp,
45824
46182
  hotkey = "mod+k",
45825
46183
  maxResults = 8,
45826
46184
  groupOrder = ["work", "page"],
45827
46185
  button = true,
45828
46186
  // kept for backward compat; ignored by teaser form
45829
- buttonLabel = "Search",
46187
+ buttonLabel: buttonLabelProp,
45830
46188
  label,
45831
46189
  searchPath = "/search"
45832
46190
  } = props || {};
45833
- const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
46191
+ const { getString } = useLocale();
46192
+ const placeholder = placeholderProp != null ? placeholderProp : getString("common.phrases.placeholder_search", "Search\u2026");
46193
+ const resolvedButtonLabel = buttonLabelProp != null ? buttonLabelProp : getString("common.nouns.search", "Search");
46194
+ const text = typeof label === "string" && label.trim() ? label.trim() : resolvedButtonLabel;
45834
46195
  const resolvedSearchPath = resolveSearchPath(searchPath);
45835
46196
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
45836
- return /* @__PURE__ */ React36.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React36.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React36.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React36.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React36.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
46197
+ 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: resolvedButtonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React37.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React37.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
45837
46198
  }
45838
46199
 
45839
46200
  // ui/src/docs/MarkdownTable.jsx
45840
- import React37 from "react";
46201
+ import React38 from "react";
45841
46202
  function MarkdownTable({ className = "", ...rest }) {
45842
46203
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
45843
- return /* @__PURE__ */ React37.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React37.createElement("table", { className: merged, ...rest }));
46204
+ return /* @__PURE__ */ React38.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React38.createElement("table", { className: merged, ...rest }));
45844
46205
  }
45845
46206
 
45846
46207
  // ui/src/docs/Diagram.jsx
45847
- import React38 from "react";
46208
+ import React39 from "react";
45848
46209
  function CanopyDiagram() {
45849
- return /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React38.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Collection A"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React38.createElement("li", null, /* @__PURE__ */ React38.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Collection B"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React38.createElement("li", null, /* @__PURE__ */ React38.createElement("em", null, "Portraits")))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React38.createElement("li", null, /* @__PURE__ */ React38.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React38.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Automated content"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React38.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React38.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React38.createElement("li", null, "Author narratives"), /* @__PURE__ */ React38.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Search index"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React38.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React38.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React38.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React38.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React38.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React38.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React38.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__ */ React38.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Work pages"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React38.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React38.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React38.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React38.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React38.createElement("article", null, /* @__PURE__ */ React38.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React38.createElement("ul", null, /* @__PURE__ */ React38.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React38.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React38.createElement("li", null, "Optional annotation dataset"))))));
46210
+ return /* @__PURE__ */ React39.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React39.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React39.createElement("h3", null, "IIIF Providers"), /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 45 manifests while 5 manifests are directly retrieved as-is via IIIF endpoints."), /* @__PURE__ */ React39.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Collection A"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "30 Manifests"), /* @__PURE__ */ React39.createElement("li", null, /* @__PURE__ */ React39.createElement("em", null, "Manuscripts")))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Collection B"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "15 Manifests"), /* @__PURE__ */ React39.createElement("li", null, /* @__PURE__ */ React39.createElement("em", null, "Portraits")))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Manifests (direct)"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "5 Manifests"), /* @__PURE__ */ React39.createElement("li", null, /* @__PURE__ */ React39.createElement("em", null, "Scrapbooks")))))), /* @__PURE__ */ React39.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React39.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React39.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy retrieves collections and syncs all manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React39.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Automated content"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "50 manifests \u2192 50 work pages"), /* @__PURE__ */ React39.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React39.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React39.createElement("li", null, "Author narratives"), /* @__PURE__ */ React39.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Search index"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React39.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React39.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React39.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React39.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React39.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React39.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React39.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__ */ React39.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Work pages"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "50 generated HTML pages"), /* @__PURE__ */ React39.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React39.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React39.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React39.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React39.createElement("article", null, /* @__PURE__ */ React39.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React39.createElement("ul", null, /* @__PURE__ */ React39.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React39.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React39.createElement("li", null, "Optional annotation dataset"))))));
45850
46211
  }
45851
46212
 
45852
46213
  // ui/src/content/timeline/Timeline.jsx
45853
- import React40 from "react";
46214
+ import React41 from "react";
45854
46215
 
45855
46216
  // ui/src/content/timeline/date-utils.js
45856
46217
  var FALLBACK_LOCALE = (() => {
@@ -46003,7 +46364,7 @@ function clampProgress(value) {
46003
46364
  }
46004
46365
 
46005
46366
  // ui/src/layout/ReferencedManifestCard.jsx
46006
- import React39 from "react";
46367
+ import React40 from "react";
46007
46368
  function normalizeMetadata(metadata, summary) {
46008
46369
  if (Array.isArray(metadata) && metadata.length) {
46009
46370
  return metadata.filter(Boolean);
@@ -46037,7 +46398,7 @@ function ReferencedManifestCard({
46037
46398
  "canopy-referenced-manifest-card",
46038
46399
  className
46039
46400
  ].filter(Boolean).join(" ");
46040
- return /* @__PURE__ */ React39.createElement(
46401
+ return /* @__PURE__ */ React40.createElement(
46041
46402
  TeaserCard,
46042
46403
  {
46043
46404
  href: resolvedHref || void 0,
@@ -46219,14 +46580,14 @@ function TimelineConnector({ side, isActive, highlight }) {
46219
46580
  "canopy-timeline__connector-dot",
46220
46581
  highlight || isActive ? "is-active" : ""
46221
46582
  ].filter(Boolean).join(" ");
46222
- return /* @__PURE__ */ React40.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React40.createElement(React40.Fragment, null, /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React40.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React40.createElement(React40.Fragment, null, /* @__PURE__ */ React40.createElement("span", { className: dotClasses }), /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__connector-line" })));
46583
+ return /* @__PURE__ */ React41.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React41.createElement(React41.Fragment, null, /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React41.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React41.createElement(React41.Fragment, null, /* @__PURE__ */ React41.createElement("span", { className: dotClasses }), /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__connector-line" })));
46223
46584
  }
46224
46585
  function renderResourceSection(point2) {
46225
46586
  if (!point2) return null;
46226
46587
  const manifestCards = Array.isArray(point2.manifests) ? point2.manifests.filter(Boolean) : [];
46227
46588
  const legacyResources = Array.isArray(point2.resources) ? point2.resources.filter(Boolean) : [];
46228
46589
  if (!manifestCards.length && !legacyResources.length) return null;
46229
- return /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React40.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React40.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React40.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React40.createElement(
46590
+ return /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React41.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React41.createElement(ReferencedManifestCard, { manifest }))), legacyResources.map((resource, idx) => /* @__PURE__ */ React41.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React41.createElement(
46230
46591
  TeaserCard,
46231
46592
  {
46232
46593
  href: resource.href,
@@ -46251,26 +46612,26 @@ function Timeline({
46251
46612
  ...rest
46252
46613
  }) {
46253
46614
  const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
46254
- const rawPoints = React40.useMemo(() => {
46615
+ const rawPoints = React41.useMemo(() => {
46255
46616
  if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
46256
46617
  if (payloadPoints && payloadPoints.length) return payloadPoints;
46257
46618
  return [];
46258
46619
  }, [pointsProp, payloadPoints]);
46259
- const sanitizedPoints = React40.useMemo(
46620
+ const sanitizedPoints = React41.useMemo(
46260
46621
  () => sanitizePoints(rawPoints),
46261
46622
  [rawPoints]
46262
46623
  );
46263
46624
  const localeValue = payload && payload.locale ? payload.locale : localeProp;
46264
- const baseLocale = React40.useMemo(
46625
+ const baseLocale = React41.useMemo(
46265
46626
  () => createLocale(localeValue),
46266
46627
  [localeValue]
46267
46628
  );
46268
46629
  const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
46269
- const rangeOverrides = React40.useMemo(
46630
+ const rangeOverrides = React41.useMemo(
46270
46631
  () => deriveRangeOverrides(sanitizedPoints, rangeInput),
46271
46632
  [sanitizedPoints, rangeInput]
46272
46633
  );
46273
- const effectiveRange = React40.useMemo(
46634
+ const effectiveRange = React41.useMemo(
46274
46635
  () => normalizeRange({
46275
46636
  ...rangeOverrides,
46276
46637
  locale: baseLocale
@@ -46279,7 +46640,7 @@ function Timeline({
46279
46640
  );
46280
46641
  const spanStart = effectiveRange.startDate.getTime();
46281
46642
  const span = effectiveRange.span;
46282
- const pointsWithPosition = React40.useMemo(() => {
46643
+ const pointsWithPosition = React41.useMemo(() => {
46283
46644
  if (!sanitizedPoints.length) return [];
46284
46645
  return sanitizedPoints.map((point2, index) => {
46285
46646
  const timestamp = point2.meta.timestamp;
@@ -46293,29 +46654,29 @@ function Timeline({
46293
46654
  };
46294
46655
  });
46295
46656
  }, [sanitizedPoints, spanStart, span]);
46296
- const [activeId, setActiveId] = React40.useState(
46657
+ const [activeId, setActiveId] = React41.useState(
46297
46658
  () => getActivePointId(pointsWithPosition)
46298
46659
  );
46299
- React40.useEffect(() => {
46660
+ React41.useEffect(() => {
46300
46661
  setActiveId(getActivePointId(pointsWithPosition));
46301
46662
  }, [pointsWithPosition]);
46302
46663
  const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
46303
46664
  const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
46304
- const thresholdMs = React40.useMemo(
46665
+ const thresholdMs = React41.useMemo(
46305
46666
  () => getThresholdMs(thresholdValue, effectiveRange.granularity),
46306
46667
  [thresholdValue, effectiveRange.granularity]
46307
46668
  );
46308
- const groupedEntries = React40.useMemo(
46669
+ const groupedEntries = React41.useMemo(
46309
46670
  () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
46310
46671
  granularity: effectiveRange.granularity,
46311
46672
  locale: baseLocale
46312
46673
  }),
46313
46674
  [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
46314
46675
  );
46315
- const [expandedGroupIds, setExpandedGroupIds] = React40.useState(
46676
+ const [expandedGroupIds, setExpandedGroupIds] = React41.useState(
46316
46677
  () => /* @__PURE__ */ new Set()
46317
46678
  );
46318
- React40.useEffect(() => {
46679
+ React41.useEffect(() => {
46319
46680
  setExpandedGroupIds((prev) => {
46320
46681
  if (!prev || prev.size === 0) return prev;
46321
46682
  const validIds = new Set(
@@ -46330,7 +46691,7 @@ function Timeline({
46330
46691
  return changed ? next : prev;
46331
46692
  });
46332
46693
  }, [groupedEntries]);
46333
- const toggleGroup = React40.useCallback((groupId) => {
46694
+ const toggleGroup = React41.useCallback((groupId) => {
46334
46695
  setExpandedGroupIds((prev) => {
46335
46696
  const next = new Set(prev || []);
46336
46697
  if (next.has(groupId)) next.delete(groupId);
@@ -46353,7 +46714,7 @@ function Timeline({
46353
46714
  point2.id === activeId ? "is-active" : "",
46354
46715
  point2.highlight ? "is-highlighted" : ""
46355
46716
  ].filter(Boolean).join(" ");
46356
- const connector = /* @__PURE__ */ React40.createElement(
46717
+ const connector = /* @__PURE__ */ React41.createElement(
46357
46718
  TimelineConnector,
46358
46719
  {
46359
46720
  side: point2.side,
@@ -46361,9 +46722,9 @@ function Timeline({
46361
46722
  highlight: point2.highlight
46362
46723
  }
46363
46724
  );
46364
- const body = /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__point-date" }, point2.meta.label), /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__point-title" }, point2.title), point2.summary ? /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__point-summary" }, point2.summary) : null);
46725
+ const body = /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__point-date" }, point2.meta.label), /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__point-title" }, point2.title), point2.summary ? /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__point-summary" }, point2.summary) : null);
46365
46726
  const resourceSection = renderResourceSection(point2);
46366
- return /* @__PURE__ */ React40.createElement(
46727
+ return /* @__PURE__ */ React41.createElement(
46367
46728
  "div",
46368
46729
  {
46369
46730
  key: point2.id,
@@ -46371,7 +46732,7 @@ function Timeline({
46371
46732
  style: wrapperStyle,
46372
46733
  role: "listitem"
46373
46734
  },
46374
- point2.side === "left" ? /* @__PURE__ */ React40.createElement(React40.Fragment, null, /* @__PURE__ */ React40.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React40.createElement(React40.Fragment, null, connector, /* @__PURE__ */ React40.createElement("div", { className: cardClasses }, body, resourceSection))
46735
+ point2.side === "left" ? /* @__PURE__ */ React41.createElement(React41.Fragment, null, /* @__PURE__ */ React41.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React41.createElement(React41.Fragment, null, connector, /* @__PURE__ */ React41.createElement("div", { className: cardClasses }, body, resourceSection))
46375
46736
  );
46376
46737
  }
46377
46738
  function renderGroupEntry(entry) {
@@ -46382,7 +46743,7 @@ function Timeline({
46382
46743
  const wrapperStyle = { top: `${entry.progress * 100}%` };
46383
46744
  const isExpanded = expandedGroupIds.has(entry.id);
46384
46745
  const hasActivePoint = entry.points.some((point2) => point2.id === activeId);
46385
- const connector = /* @__PURE__ */ React40.createElement(
46746
+ const connector = /* @__PURE__ */ React41.createElement(
46386
46747
  TimelineConnector,
46387
46748
  {
46388
46749
  side: entry.side,
@@ -46396,7 +46757,7 @@ function Timeline({
46396
46757
  hasActivePoint ? "is-active" : ""
46397
46758
  ].filter(Boolean).join(" ");
46398
46759
  const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
46399
- const header = /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React40.createElement(
46760
+ const header = /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React41.createElement(
46400
46761
  "button",
46401
46762
  {
46402
46763
  type: "button",
@@ -46406,7 +46767,7 @@ function Timeline({
46406
46767
  },
46407
46768
  isExpanded ? "Hide details" : "Show details"
46408
46769
  ));
46409
- const groupPoints = isExpanded ? /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point2) => /* @__PURE__ */ React40.createElement(
46770
+ const groupPoints = isExpanded ? /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point2) => /* @__PURE__ */ React41.createElement(
46410
46771
  "button",
46411
46772
  {
46412
46773
  key: point2.id,
@@ -46417,11 +46778,11 @@ function Timeline({
46417
46778
  ].filter(Boolean).join(" "),
46418
46779
  onClick: () => setActiveId(point2.id)
46419
46780
  },
46420
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__point-date" }, point2.meta.label),
46421
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__group-point-title" }, point2.title)
46781
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__point-date" }, point2.meta.label),
46782
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__group-point-title" }, point2.title)
46422
46783
  ))) : null;
46423
- const groupCard = /* @__PURE__ */ React40.createElement("div", { className: groupClasses }, header, groupPoints);
46424
- return /* @__PURE__ */ React40.createElement(
46784
+ const groupCard = /* @__PURE__ */ React41.createElement("div", { className: groupClasses }, header, groupPoints);
46785
+ return /* @__PURE__ */ React41.createElement(
46425
46786
  "div",
46426
46787
  {
46427
46788
  key: entry.id,
@@ -46429,17 +46790,17 @@ function Timeline({
46429
46790
  style: wrapperStyle,
46430
46791
  role: "listitem"
46431
46792
  },
46432
- entry.side === "left" ? /* @__PURE__ */ React40.createElement(React40.Fragment, null, groupCard, connector) : /* @__PURE__ */ React40.createElement(React40.Fragment, null, connector, groupCard)
46793
+ entry.side === "left" ? /* @__PURE__ */ React41.createElement(React41.Fragment, null, groupCard, connector) : /* @__PURE__ */ React41.createElement(React41.Fragment, null, connector, groupCard)
46433
46794
  );
46434
46795
  }
46435
- return /* @__PURE__ */ React40.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React40.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React40.createElement(
46796
+ return /* @__PURE__ */ React41.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React41.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React41.createElement(
46436
46797
  "div",
46437
46798
  {
46438
46799
  className: "canopy-timeline__list",
46439
46800
  role: "list",
46440
46801
  style: { minHeight: trackHeight }
46441
46802
  },
46442
- /* @__PURE__ */ React40.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
46803
+ /* @__PURE__ */ React41.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
46443
46804
  renderSteps(stepsValue, effectiveRange),
46444
46805
  groupedEntries.map((entry) => {
46445
46806
  if (entry.type === "group") return renderGroupEntry(entry);
@@ -46454,7 +46815,7 @@ function renderSteps(stepSize, range) {
46454
46815
  const markers = [];
46455
46816
  if (startYear < endYear) {
46456
46817
  markers.push(
46457
- /* @__PURE__ */ React40.createElement(
46818
+ /* @__PURE__ */ React41.createElement(
46458
46819
  "span",
46459
46820
  {
46460
46821
  key: "timeline-step-start",
@@ -46462,12 +46823,12 @@ function renderSteps(stepSize, range) {
46462
46823
  style: { top: "0%" },
46463
46824
  "aria-hidden": "true"
46464
46825
  },
46465
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-line" }),
46466
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
46826
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-line" }),
46827
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
46467
46828
  )
46468
46829
  );
46469
46830
  markers.push(
46470
- /* @__PURE__ */ React40.createElement(
46831
+ /* @__PURE__ */ React41.createElement(
46471
46832
  "span",
46472
46833
  {
46473
46834
  key: "timeline-step-end",
@@ -46475,8 +46836,8 @@ function renderSteps(stepSize, range) {
46475
46836
  style: { top: "100%" },
46476
46837
  "aria-hidden": "true"
46477
46838
  },
46478
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-line" }),
46479
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
46839
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-line" }),
46840
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
46480
46841
  )
46481
46842
  );
46482
46843
  }
@@ -46486,7 +46847,7 @@ function renderSteps(stepSize, range) {
46486
46847
  const progress = (timestamp - range.startDate.getTime()) / range.span;
46487
46848
  if (progress <= 0 || progress >= 1) continue;
46488
46849
  markers.push(
46489
- /* @__PURE__ */ React40.createElement(
46850
+ /* @__PURE__ */ React41.createElement(
46490
46851
  "span",
46491
46852
  {
46492
46853
  key: `timeline-step-${year}`,
@@ -46494,8 +46855,8 @@ function renderSteps(stepSize, range) {
46494
46855
  style: { top: `calc(${progress * 100}% - 0.5px)` },
46495
46856
  "aria-hidden": "true"
46496
46857
  },
46497
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-line" }),
46498
- /* @__PURE__ */ React40.createElement("span", { className: "canopy-timeline__step-label" }, year)
46858
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-line" }),
46859
+ /* @__PURE__ */ React41.createElement("span", { className: "canopy-timeline__step-label" }, year)
46499
46860
  )
46500
46861
  );
46501
46862
  }
@@ -46509,7 +46870,7 @@ function TimelinePoint() {
46509
46870
  TimelinePoint.displayName = "TimelinePoint";
46510
46871
 
46511
46872
  // ui/src/content/map/Map.jsx
46512
- import React41 from "react";
46873
+ import React42 from "react";
46513
46874
  import { createRoot } from "react-dom/client";
46514
46875
  var DEFAULT_TILE_LAYERS = [
46515
46876
  {
@@ -46941,7 +47302,7 @@ function MapPopupContent({ marker }) {
46941
47302
  ...manifest,
46942
47303
  href: manifest.href ? withBasePath3(manifest.href) : manifest.href || ""
46943
47304
  }));
46944
- return /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__popup" }, thumbnail ? /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__popup-media" }, /* @__PURE__ */ React41.createElement(
47305
+ return /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__popup" }, thumbnail ? /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__popup-media" }, /* @__PURE__ */ React42.createElement(
46945
47306
  "img",
46946
47307
  {
46947
47308
  src: thumbnail,
@@ -46950,19 +47311,19 @@ function MapPopupContent({ marker }) {
46950
47311
  width: typeof thumbWidth === "number" && thumbWidth > 0 ? thumbWidth : void 0,
46951
47312
  height: typeof thumbHeight === "number" && thumbHeight > 0 ? thumbHeight : void 0
46952
47313
  }
46953
- )) : null, /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__popup-body" }, title ? href ? /* @__PURE__ */ React41.createElement("a", { href, className: "canopy-map__popup-title" }, title) : /* @__PURE__ */ React41.createElement("span", { className: "canopy-map__popup-title" }, title) : null, summary ? /* @__PURE__ */ React41.createElement("p", { className: "canopy-map__popup-summary" }, summary) : null, marker.detailsHtml ? /* @__PURE__ */ React41.createElement(
47314
+ )) : null, /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__popup-body" }, title ? href ? /* @__PURE__ */ React42.createElement("a", { href, className: "canopy-map__popup-title" }, title) : /* @__PURE__ */ React42.createElement("span", { className: "canopy-map__popup-title" }, title) : null, summary ? /* @__PURE__ */ React42.createElement("p", { className: "canopy-map__popup-summary" }, summary) : null, marker.detailsHtml ? /* @__PURE__ */ React42.createElement(
46954
47315
  "div",
46955
47316
  {
46956
47317
  className: "canopy-map__popup-details",
46957
47318
  dangerouslySetInnerHTML: { __html: marker.detailsHtml }
46958
47319
  }
46959
- ) : null, !summary && !marker.detailsHtml && href && !title ? /* @__PURE__ */ React41.createElement("a", { href, className: "canopy-map__popup-link" }, "View item") : null, normalizedManifests.length ? /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__popup-manifests" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__popup-manifests-list" }, normalizedManifests.map((manifest, index) => /* @__PURE__ */ React41.createElement(
47320
+ ) : null, !summary && !marker.detailsHtml && href && !title ? /* @__PURE__ */ React42.createElement("a", { href, className: "canopy-map__popup-link" }, "View item") : null, normalizedManifests.length ? /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__popup-manifests" }, /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__popup-manifests-list" }, normalizedManifests.map((manifest, index) => /* @__PURE__ */ React42.createElement(
46960
47321
  "div",
46961
47322
  {
46962
47323
  key: manifest.id || manifest.href || `manifest-${index}`,
46963
47324
  className: "canopy-map__popup-manifests-item"
46964
47325
  },
46965
- /* @__PURE__ */ React41.createElement(ReferencedManifestCard, { manifest })
47326
+ /* @__PURE__ */ React42.createElement(ReferencedManifestCard, { manifest })
46966
47327
  )))) : null));
46967
47328
  }
46968
47329
  function renderPopup(marker) {
@@ -46974,7 +47335,7 @@ function renderPopup(marker) {
46974
47335
  if (hadError) return;
46975
47336
  try {
46976
47337
  if (!root2) root2 = createRoot(container);
46977
- root2.render(/* @__PURE__ */ React41.createElement(MapPopupContent, { marker }));
47338
+ root2.render(/* @__PURE__ */ React42.createElement(MapPopupContent, { marker }));
46978
47339
  } catch (error) {
46979
47340
  hadError = true;
46980
47341
  if (root2) {
@@ -47156,26 +47517,26 @@ function Map3({
47156
47517
  defaultCenter = null,
47157
47518
  defaultZoom = null
47158
47519
  } = {}) {
47159
- const containerRef = React41.useRef(null);
47160
- const mapRef = React41.useRef(null);
47161
- const layerRef = React41.useRef(null);
47162
- const [leafletLib, setLeafletLib] = React41.useState(() => resolveGlobalLeaflet());
47163
- const [leafletError, setLeafletError] = React41.useState(null);
47520
+ const containerRef = React42.useRef(null);
47521
+ const mapRef = React42.useRef(null);
47522
+ const layerRef = React42.useRef(null);
47523
+ const [leafletLib, setLeafletLib] = React42.useState(() => resolveGlobalLeaflet());
47524
+ const [leafletError, setLeafletError] = React42.useState(null);
47164
47525
  const datasetInfo = navDataset && typeof navDataset === "object" ? navDataset : null;
47165
47526
  const datasetHref = datasetInfo && datasetInfo.href || "/api/navplace.json";
47166
47527
  const datasetVersion = datasetInfo && datasetInfo.version;
47167
47528
  const datasetHasFeatures = !!(datasetInfo && datasetInfo.hasFeatures);
47168
- const [navState, setNavState] = React41.useState(() => ({
47529
+ const [navState, setNavState] = React42.useState(() => ({
47169
47530
  loading: false,
47170
47531
  error: null,
47171
47532
  markers: []
47172
47533
  }));
47173
- const [iiifTargets, setIiifTargets] = React41.useState(() => ({
47534
+ const [iiifTargets, setIiifTargets] = React42.useState(() => ({
47174
47535
  loading: false,
47175
47536
  error: null,
47176
47537
  keys: []
47177
47538
  }));
47178
- React41.useEffect(() => {
47539
+ React42.useEffect(() => {
47179
47540
  if (!iiifContent) {
47180
47541
  setIiifTargets({ loading: false, error: null, keys: [] });
47181
47542
  return;
@@ -47223,7 +47584,7 @@ function Map3({
47223
47584
  const navTargets = iiifTargets.keys || [];
47224
47585
  const navTargetsKey = navTargets.join("|");
47225
47586
  const shouldFetchNav = datasetHasFeatures && navTargets.length > 0;
47226
- React41.useEffect(() => {
47587
+ React42.useEffect(() => {
47227
47588
  if (!shouldFetchNav) {
47228
47589
  setNavState({ loading: false, error: null, markers: [] });
47229
47590
  return void 0;
@@ -47255,7 +47616,7 @@ function Map3({
47255
47616
  cancelled = true;
47256
47617
  };
47257
47618
  }, [datasetHref, datasetVersion, navTargetsKey, shouldFetchNav]);
47258
- React41.useEffect(() => {
47619
+ React42.useEffect(() => {
47259
47620
  if (leafletLib) return;
47260
47621
  let cancelled = false;
47261
47622
  waitForLeaflet().then((lib) => {
@@ -47267,7 +47628,7 @@ function Map3({
47267
47628
  cancelled = true;
47268
47629
  };
47269
47630
  }, [leafletLib]);
47270
- const navMatchMap = React41.useMemo(() => {
47631
+ const navMatchMap = React42.useMemo(() => {
47271
47632
  const matchMap = createMarkerMap();
47272
47633
  (navState.markers || []).forEach((marker) => {
47273
47634
  if (!marker || !Array.isArray(marker.matchKeys)) return;
@@ -47278,7 +47639,7 @@ function Map3({
47278
47639
  });
47279
47640
  return matchMap;
47280
47641
  }, [navState.markers]);
47281
- const normalizedCustom = React41.useMemo(() => {
47642
+ const normalizedCustom = React42.useMemo(() => {
47282
47643
  return normalizeCustomMarkers(customPoints).map((point2) => {
47283
47644
  if (!point2 || point2.thumbnail || !point2.href) return point2;
47284
47645
  const match2 = navMatchMap.get(normalizeKey(point2.href));
@@ -47293,20 +47654,20 @@ function Map3({
47293
47654
  };
47294
47655
  });
47295
47656
  }, [customPoints, navMatchMap]);
47296
- const allMarkers = React41.useMemo(() => {
47657
+ const allMarkers = React42.useMemo(() => {
47297
47658
  return [...navState.markers || [], ...normalizedCustom];
47298
47659
  }, [navState.markers, normalizedCustom]);
47299
- const normalizedGeoReferences = React41.useMemo(
47660
+ const normalizedGeoReferences = React42.useMemo(
47300
47661
  () => normalizeGeoReferences(geoReferences),
47301
47662
  [geoReferences]
47302
47663
  );
47303
- const resolvedKeyInput = React41.useMemo(() => {
47664
+ const resolvedKeyInput = React42.useMemo(() => {
47304
47665
  if (Array.isArray(keyConfig) && keyConfig.length) return keyConfig;
47305
47666
  if (Array.isArray(mapKey) && mapKey.length) return mapKey;
47306
47667
  if (Array.isArray(legend) && legend.length) return legend;
47307
47668
  return [];
47308
47669
  }, [keyConfig, mapKey, legend]);
47309
- const normalizedLegendConfig = React41.useMemo(() => {
47670
+ const normalizedLegendConfig = React42.useMemo(() => {
47310
47671
  if (!Array.isArray(resolvedKeyInput) || !resolvedKeyInput.length) return [];
47311
47672
  return resolvedKeyInput.map((entry) => {
47312
47673
  if (!entry) return null;
@@ -47322,7 +47683,7 @@ function Map3({
47322
47683
  };
47323
47684
  }).filter(Boolean);
47324
47685
  }, [resolvedKeyInput]);
47325
- const markerKeyData = React41.useMemo(() => {
47686
+ const markerKeyData = React42.useMemo(() => {
47326
47687
  if (!normalizedLegendConfig.length) return { groups: [], metaMap: null };
47327
47688
  const metaMap = createMarkerMap();
47328
47689
  const palette = generateLegendColors(normalizedLegendConfig.length);
@@ -47343,11 +47704,11 @@ function Map3({
47343
47704
  }, [normalizedLegendConfig]);
47344
47705
  const markerKeyGroups = markerKeyData.groups;
47345
47706
  const markerKeyMetaMap = markerKeyData.metaMap;
47346
- const clusterOptions = React41.useMemo(
47707
+ const clusterOptions = React42.useMemo(
47347
47708
  () => buildClusterOptions(leafletLib, typeof maxClusterRadius === "number" ? maxClusterRadius : null),
47348
47709
  [leafletLib, maxClusterRadius]
47349
47710
  );
47350
- React41.useEffect(() => {
47711
+ React42.useEffect(() => {
47351
47712
  if (!containerRef.current || mapRef.current || !leafletLib) return void 0;
47352
47713
  const map = leafletLib.map(containerRef.current, {
47353
47714
  zoomControl: true,
@@ -47385,7 +47746,7 @@ function Map3({
47385
47746
  layerRef.current = null;
47386
47747
  };
47387
47748
  }, [tileLayers, disableTileLayers, scrollWheelZoom, cluster, clusterOptions, leafletLib]);
47388
- React41.useEffect(() => {
47749
+ React42.useEffect(() => {
47389
47750
  const map = mapRef.current;
47390
47751
  if (!map || !leafletLib) return void 0;
47391
47752
  if (!normalizedGeoReferences.length) return void 0;
@@ -47424,7 +47785,7 @@ function Map3({
47424
47785
  });
47425
47786
  };
47426
47787
  }, [leafletLib, normalizedGeoReferences]);
47427
- React41.useEffect(() => {
47788
+ React42.useEffect(() => {
47428
47789
  const map = mapRef.current;
47429
47790
  const layer = layerRef.current;
47430
47791
  if (!map || !layer || !leafletLib) return;
@@ -47562,16 +47923,16 @@ function Map3({
47562
47923
  ].filter(Boolean).join(" ");
47563
47924
  const statusLabel = leafletError ? leafletError.message || "Failed to load map library" : !leafletLib ? "Loading map\u2026" : iiifTargets.error ? iiifTargets.error : datasetUnavailable ? "Map data is unavailable for this site." : navState.error ? navState.error : isLoadingMarkers ? "Loading map data\u2026" : !iiifContent && !hasCustomPoints && !hasGeoReferences ? "Add iiifContent or MapPoint markers to populate this map." : !hasMarkers && !hasGeoReferences ? "No map locations available." : "";
47564
47925
  const showStatus = Boolean(statusLabel);
47565
- const mapElement = /* @__PURE__ */ React41.createElement("div", { className: rootClass, id: id || void 0, style: style || void 0 }, /* @__PURE__ */ React41.createElement(
47926
+ const mapElement = /* @__PURE__ */ React42.createElement("div", { className: rootClass, id: id || void 0, style: style || void 0 }, /* @__PURE__ */ React42.createElement(
47566
47927
  "div",
47567
47928
  {
47568
47929
  ref: containerRef,
47569
47930
  className: "canopy-map__canvas",
47570
47931
  style: { height: height || "600px" }
47571
47932
  }
47572
- ), showStatus ? /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__overlays" }, /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__status", "aria-live": "polite" }, statusLabel)) : null);
47933
+ ), showStatus ? /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__overlays" }, /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__status", "aria-live": "polite" }, statusLabel)) : null);
47573
47934
  if (!hasKey) return mapElement;
47574
- return /* @__PURE__ */ React41.createElement(React41.Fragment, null, mapElement, /* @__PURE__ */ React41.createElement("div", { className: "canopy-map__key", "aria-label": "Map key" }, /* @__PURE__ */ React41.createElement("ul", { className: "canopy-map__key-list" }, markerKeyGroups.map((group) => /* @__PURE__ */ React41.createElement("li", { key: group.label, className: "canopy-map__key-item" }, /* @__PURE__ */ React41.createElement(
47935
+ return /* @__PURE__ */ React42.createElement(React42.Fragment, null, mapElement, /* @__PURE__ */ React42.createElement("div", { className: "canopy-map__key", "aria-label": "Map key" }, /* @__PURE__ */ React42.createElement("ul", { className: "canopy-map__key-list" }, markerKeyGroups.map((group) => /* @__PURE__ */ React42.createElement("li", { key: group.label, className: "canopy-map__key-item" }, /* @__PURE__ */ React42.createElement(
47575
47936
  "span",
47576
47937
  {
47577
47938
  className: [
@@ -47581,7 +47942,7 @@ function Map3({
47581
47942
  "aria-hidden": "true",
47582
47943
  style: { backgroundColor: group.color || void 0 }
47583
47944
  }
47584
- ), /* @__PURE__ */ React41.createElement("span", { className: "canopy-map__key-label" }, group.label))))));
47945
+ ), /* @__PURE__ */ React42.createElement("span", { className: "canopy-map__key-label" }, group.label))))));
47585
47946
  }
47586
47947
 
47587
47948
  // ui/src/content/map/MapPoint.jsx
@@ -47591,10 +47952,10 @@ function MapPoint() {
47591
47952
  MapPoint.displayName = "MapPoint";
47592
47953
 
47593
47954
  // ui/src/content/gallery/Gallery.jsx
47594
- import React43 from "react";
47955
+ import React44 from "react";
47595
47956
 
47596
47957
  // ui/src/utils/manifestReferences.js
47597
- import React42 from "react";
47958
+ import React43 from "react";
47598
47959
  var CONTEXT_KEY2 = typeof Symbol === "function" ? Symbol.for("__CANOPY_PAGE_CONTEXT__") : "__CANOPY_PAGE_CONTEXT__";
47599
47960
  function getGlobalRoot() {
47600
47961
  if (typeof globalThis !== "undefined") return globalThis;
@@ -47605,7 +47966,7 @@ function getGlobalRoot() {
47605
47966
  function getPageContext() {
47606
47967
  const root2 = getGlobalRoot();
47607
47968
  if (root2 && root2[CONTEXT_KEY2]) return root2[CONTEXT_KEY2];
47608
- const ctx = React42.createContext({
47969
+ const ctx = React43.createContext({
47609
47970
  navigation: null,
47610
47971
  page: null,
47611
47972
  site: null,
@@ -47629,7 +47990,7 @@ function normalizeManifestId(raw) {
47629
47990
  return String(raw || "").trim();
47630
47991
  }
47631
47992
  }
47632
- var PageContextFallback = React42.createContext(null);
47993
+ var PageContextFallback = React43.createContext(null);
47633
47994
  var referencedModule = null;
47634
47995
  var REFERENCED_SPEC = "@canopy-iiif/app/lib/components/referenced.js";
47635
47996
  function getReferencedModule() {
@@ -47655,9 +48016,9 @@ function getReferencedModule() {
47655
48016
  }
47656
48017
  function useReferencedManifestMap() {
47657
48018
  const PageContext3 = getPageContext() || PageContextFallback;
47658
- const pageContext = React42.useContext(PageContext3);
48019
+ const pageContext = React43.useContext(PageContext3);
47659
48020
  const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
47660
- return React42.useMemo(() => {
48021
+ return React43.useMemo(() => {
47661
48022
  const map = /* @__PURE__ */ new Map();
47662
48023
  referencedItems.forEach((item) => {
47663
48024
  if (!item) return;
@@ -48263,7 +48624,7 @@ function shuffleItems(list) {
48263
48624
  function renderMetaList(meta, className) {
48264
48625
  const entries = ensureArray4(meta).filter((entry) => entry || entry === 0);
48265
48626
  if (!entries.length) return null;
48266
- return /* @__PURE__ */ React43.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React43.createElement("li", { key: `meta-${index}` }, entry)));
48627
+ return /* @__PURE__ */ React44.createElement("ul", { className, role: "list" }, entries.map((entry, index) => /* @__PURE__ */ React44.createElement("li", { key: `meta-${index}` }, entry)));
48267
48628
  }
48268
48629
  function renderPreview(props = {}) {
48269
48630
  const source = typeof props.media === "string" && props.media || props.thumbnail || props.src || props.image && props.image.src || props.image;
@@ -48271,7 +48632,7 @@ function renderPreview(props = {}) {
48271
48632
  const alt = props.thumbnailAlt || props.imageAlt || props.alt || props.title || "";
48272
48633
  const width = props.thumbnailWidth || props.imageWidth || props.width;
48273
48634
  const height = props.thumbnailHeight || props.imageHeight || props.height;
48274
- return /* @__PURE__ */ React43.createElement(
48635
+ return /* @__PURE__ */ React44.createElement(
48275
48636
  "img",
48276
48637
  {
48277
48638
  src: source,
@@ -48282,7 +48643,7 @@ function renderPreview(props = {}) {
48282
48643
  }
48283
48644
  );
48284
48645
  }
48285
- return /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
48646
+ return /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__placeholder", "aria-hidden": "true" });
48286
48647
  }
48287
48648
  function renderFlexibleContent(content, options = {}) {
48288
48649
  var _a2, _b;
@@ -48295,25 +48656,25 @@ function renderFlexibleContent(content, options = {}) {
48295
48656
  if (content == null || content === false) return null;
48296
48657
  const isPrimitive = typeof content === "string" || typeof content === "number" || typeof content === "bigint";
48297
48658
  if (isPrimitive) {
48298
- return /* @__PURE__ */ React43.createElement(InlineTag, { className, id }, content);
48659
+ return /* @__PURE__ */ React44.createElement(InlineTag, { className, id }, content);
48299
48660
  }
48300
- if (React43.isValidElement(content)) {
48301
- if (content.type === React43.Fragment) {
48302
- return /* @__PURE__ */ React43.createElement(BlockTag, { className, id }, content);
48661
+ if (React44.isValidElement(content)) {
48662
+ if (content.type === React44.Fragment) {
48663
+ return /* @__PURE__ */ React44.createElement(BlockTag, { className, id }, content);
48303
48664
  }
48304
48665
  const mergedClassName = [(_a2 = content.props) == null ? void 0 : _a2.className, className].filter(Boolean).join(" ");
48305
- return React43.cloneElement(content, {
48666
+ return React44.cloneElement(content, {
48306
48667
  ...content.props,
48307
48668
  className: mergedClassName || void 0,
48308
48669
  id: ((_b = content.props) == null ? void 0 : _b.id) || id
48309
48670
  });
48310
48671
  }
48311
48672
  const FallbackTag = BlockTag;
48312
- return /* @__PURE__ */ React43.createElement(FallbackTag, { className, id }, content);
48673
+ return /* @__PURE__ */ React44.createElement(FallbackTag, { className, id }, content);
48313
48674
  }
48314
48675
  function normalizeItem(child, index, galleryId, manifestMap) {
48315
48676
  var _a2;
48316
- if (!React43.isValidElement(child)) return null;
48677
+ if (!React44.isValidElement(child)) return null;
48317
48678
  if (child.type !== GalleryItem && ((_a2 = child.type) == null ? void 0 : _a2.displayName) !== "GalleryItem")
48318
48679
  return null;
48319
48680
  const props = child.props || {};
@@ -48388,7 +48749,7 @@ function buildCaptionContent(itemProps) {
48388
48749
  if (itemProps.caption) return itemProps.caption;
48389
48750
  const kicker = itemProps.kicker || itemProps.label || itemProps.eyebrow;
48390
48751
  const summary = itemProps.summary || itemProps.description;
48391
- return /* @__PURE__ */ React43.createElement(React43.Fragment, null, kicker ? /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, renderFlexibleContent(summary, {
48752
+ return /* @__PURE__ */ React44.createElement(React44.Fragment, null, kicker ? /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__kicker" }, kicker) : null, itemProps.title ? /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__title-text" }, itemProps.title) : null, renderFlexibleContent(summary, {
48392
48753
  inlineTag: "span",
48393
48754
  blockTag: "div",
48394
48755
  className: "canopy-gallery__summary"
@@ -48410,7 +48771,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48410
48771
  const kicker = props.kicker || props.label || props.eyebrow;
48411
48772
  const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
48412
48773
  const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
48413
- return /* @__PURE__ */ React43.createElement(
48774
+ return /* @__PURE__ */ React44.createElement(
48414
48775
  "div",
48415
48776
  {
48416
48777
  id: modalId,
@@ -48423,14 +48784,14 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48423
48784
  "data-canopy-gallery-modal": "true",
48424
48785
  "data-canopy-gallery-close": closeTargetId
48425
48786
  },
48426
- /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React43.createElement(
48787
+ /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React44.createElement(
48427
48788
  GalleryThumbnailNav,
48428
48789
  {
48429
48790
  items: navItems,
48430
48791
  activeModalId: modalId,
48431
48792
  groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
48432
48793
  }
48433
- ), /* @__PURE__ */ React43.createElement(
48794
+ ), /* @__PURE__ */ React44.createElement(
48434
48795
  "a",
48435
48796
  {
48436
48797
  className: "canopy-gallery__modal-close",
@@ -48438,7 +48799,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48438
48799
  "aria-label": `Close popup for ${modalTitle}`
48439
48800
  },
48440
48801
  "X"
48441
- )), /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React43.createElement(
48802
+ )), /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React44.createElement(
48442
48803
  "button",
48443
48804
  {
48444
48805
  type: "button",
@@ -48446,7 +48807,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48446
48807
  "aria-label": "Scroll left through gallery thumbnails",
48447
48808
  "data-canopy-gallery-nav-prev": "true"
48448
48809
  },
48449
- /* @__PURE__ */ React43.createElement(
48810
+ /* @__PURE__ */ React44.createElement(
48450
48811
  "span",
48451
48812
  {
48452
48813
  className: "canopy-gallery__nav-button-icon",
@@ -48455,8 +48816,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48455
48816
  },
48456
48817
  "<"
48457
48818
  ),
48458
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
48459
- ), /* @__PURE__ */ React43.createElement(
48819
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
48820
+ ), /* @__PURE__ */ React44.createElement(
48460
48821
  "button",
48461
48822
  {
48462
48823
  type: "button",
@@ -48464,7 +48825,7 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48464
48825
  "aria-label": "Scroll right through gallery thumbnails",
48465
48826
  "data-canopy-gallery-nav-next": "true"
48466
48827
  },
48467
- /* @__PURE__ */ React43.createElement(
48828
+ /* @__PURE__ */ React44.createElement(
48468
48829
  "span",
48469
48830
  {
48470
48831
  className: "canopy-gallery__nav-button-icon",
@@ -48473,8 +48834,8 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48473
48834
  },
48474
48835
  ">"
48475
48836
  ),
48476
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
48477
- ), /* @__PURE__ */ React43.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React43.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React43.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), renderFlexibleContent(summary, {
48837
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
48838
+ ), /* @__PURE__ */ React44.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React44.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React44.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), renderFlexibleContent(summary, {
48478
48839
  inlineTag: "p",
48479
48840
  blockTag: "div",
48480
48841
  className: "canopy-gallery__modal-summary",
@@ -48482,20 +48843,20 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
48482
48843
  }), renderMetaList(
48483
48844
  props.meta,
48484
48845
  "canopy-gallery__meta canopy-gallery__meta--modal"
48485
- ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React43.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
48846
+ ), manifests && manifests.length ? manifests.map((manifest) => /* @__PURE__ */ React44.createElement("a", { key: manifest.id || manifest.href, href: manifest.href }, manifest.title || manifest.href)) : null)), /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-body" }, props.children)))
48486
48847
  );
48487
48848
  }
48488
48849
  function GalleryFigure({ item }) {
48489
48850
  const { props, modalId, triggerLabel } = item;
48490
- return /* @__PURE__ */ React43.createElement(
48851
+ return /* @__PURE__ */ React44.createElement(
48491
48852
  "figure",
48492
48853
  {
48493
48854
  className: "canopy-gallery__item",
48494
48855
  "data-gallery-item-index": item.index
48495
48856
  },
48496
- /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
48497
- /* @__PURE__ */ React43.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
48498
- /* @__PURE__ */ React43.createElement(
48857
+ /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__media" }, renderPreview(props)),
48858
+ /* @__PURE__ */ React44.createElement("figcaption", { className: "canopy-gallery__caption" }, buildCaptionContent(props)),
48859
+ /* @__PURE__ */ React44.createElement(
48499
48860
  "a",
48500
48861
  {
48501
48862
  className: "canopy-gallery__trigger",
@@ -48505,27 +48866,27 @@ function GalleryFigure({ item }) {
48505
48866
  "aria-label": triggerLabel,
48506
48867
  "data-canopy-gallery-trigger": modalId
48507
48868
  },
48508
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
48869
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__trigger-label" }, triggerLabel)
48509
48870
  )
48510
48871
  );
48511
48872
  }
48512
48873
  function GalleryThumbnailNav({ items, activeModalId, groupName }) {
48513
48874
  if (!items || items.length < 2) return null;
48514
48875
  const radioGroup = groupName || "canopy-gallery-nav";
48515
- return /* @__PURE__ */ React43.createElement(
48876
+ return /* @__PURE__ */ React44.createElement(
48516
48877
  "nav",
48517
48878
  {
48518
48879
  className: "canopy-gallery__nav",
48519
48880
  "aria-label": "Gallery navigation",
48520
48881
  "data-canopy-gallery-nav": "true"
48521
48882
  },
48522
- /* @__PURE__ */ React43.createElement(
48883
+ /* @__PURE__ */ React44.createElement(
48523
48884
  "div",
48524
48885
  {
48525
48886
  className: "canopy-gallery__nav-viewport",
48526
48887
  "data-canopy-gallery-nav-viewport": "true"
48527
48888
  },
48528
- /* @__PURE__ */ React43.createElement(
48889
+ /* @__PURE__ */ React44.createElement(
48529
48890
  "ul",
48530
48891
  {
48531
48892
  className: "canopy-gallery__nav-list",
@@ -48535,7 +48896,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
48535
48896
  items.map((item, index) => {
48536
48897
  const optionId = `${radioGroup}-${item.modalId || index}`;
48537
48898
  const isActive = item.modalId === activeModalId;
48538
- return /* @__PURE__ */ React43.createElement(
48899
+ return /* @__PURE__ */ React44.createElement(
48539
48900
  "li",
48540
48901
  {
48541
48902
  key: `${item.key}-nav`,
@@ -48543,7 +48904,7 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
48543
48904
  "data-canopy-gallery-nav-item": "true",
48544
48905
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
48545
48906
  },
48546
- /* @__PURE__ */ React43.createElement(
48907
+ /* @__PURE__ */ React44.createElement(
48547
48908
  "input",
48548
48909
  {
48549
48910
  type: "radio",
@@ -48559,15 +48920,15 @@ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
48559
48920
  "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
48560
48921
  }
48561
48922
  ),
48562
- /* @__PURE__ */ React43.createElement(
48923
+ /* @__PURE__ */ React44.createElement(
48563
48924
  "label",
48564
48925
  {
48565
48926
  className: "canopy-gallery__nav-link",
48566
48927
  htmlFor: optionId,
48567
48928
  "data-canopy-gallery-nav-active": isActive ? "1" : void 0
48568
48929
  },
48569
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
48570
- /* @__PURE__ */ React43.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
48930
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
48931
+ /* @__PURE__ */ React44.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
48571
48932
  )
48572
48933
  );
48573
48934
  })
@@ -48580,7 +48941,7 @@ function GalleryContent({ children, flex = false }) {
48580
48941
  "canopy-gallery-item__content",
48581
48942
  flex ? "canopy-gallery-item__content_flex" : null
48582
48943
  ].filter(Boolean).join(" ");
48583
- return /* @__PURE__ */ React43.createElement("div", { className: contentClassName }, children);
48944
+ return /* @__PURE__ */ React44.createElement("div", { className: contentClassName }, children);
48584
48945
  }
48585
48946
  function GalleryItem() {
48586
48947
  return null;
@@ -48604,7 +48965,7 @@ function Gallery({
48604
48965
  const galleryId = id ? String(id) : nextGalleryInstanceId();
48605
48966
  const HeadingTag = "h3";
48606
48967
  const closeTargetId = `${galleryId}-close`;
48607
- const childArray = React43.Children.toArray(children);
48968
+ const childArray = React44.Children.toArray(children);
48608
48969
  const items = childArray.map((child, index) => normalizeItem(child, index, galleryId, manifestMap)).filter(Boolean);
48609
48970
  if (!items.length) return null;
48610
48971
  const popupMode = normalizePopupSize(popupSize);
@@ -48616,7 +48977,7 @@ function Gallery({
48616
48977
  className
48617
48978
  ].filter(Boolean).join(" ");
48618
48979
  const navGroupName = `${galleryId}-nav`;
48619
- return /* @__PURE__ */ React43.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React43.createElement(
48980
+ return /* @__PURE__ */ React44.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React44.createElement(
48620
48981
  "div",
48621
48982
  {
48622
48983
  id: closeTargetId,
@@ -48624,7 +48985,7 @@ function Gallery({
48624
48985
  "aria-hidden": "true",
48625
48986
  tabIndex: -1
48626
48987
  }
48627
- ), (title || description) && /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React43.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React43.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React43.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React43.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React43.createElement(
48988
+ ), (title || description) && /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React44.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React44.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React44.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React44.createElement(
48628
48989
  GalleryModal,
48629
48990
  {
48630
48991
  key: `${item.modalId}-modal`,
@@ -48633,7 +48994,7 @@ function Gallery({
48633
48994
  navItems: orderedItems,
48634
48995
  navGroupName
48635
48996
  }
48636
- ))), /* @__PURE__ */ React43.createElement(
48997
+ ))), /* @__PURE__ */ React44.createElement(
48637
48998
  "script",
48638
48999
  {
48639
49000
  "data-canopy-gallery-script": "true",