@canopy-iiif/app 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/build/iiif.js +18 -8
- package/lib/build/mdx.js +39 -23
- package/package.json +3 -2
- package/ui/dist/index.mjs +704 -293
- package/ui/dist/index.mjs.map +4 -4
- package/ui/dist/server.mjs +640 -76
- package/ui/dist/server.mjs.map +4 -4
- package/ui/styles/components/header/_header.scss +153 -3
- package/ui/styles/components/header/_logo.scss +3 -2
- package/ui/styles/components/header/_navbar.scss +52 -10
- package/ui/styles/components/index.scss +1 -0
- package/ui/styles/components/modal/_modal.scss +122 -0
- package/ui/styles/components/modal/index.scss +1 -0
- package/ui/styles/components/search/_filters.scss +197 -225
- package/ui/styles/index.css +532 -313
- package/ui/theme.js +8 -8
package/ui/dist/index.mjs
CHANGED
|
@@ -226,8 +226,621 @@ function Grid({
|
|
|
226
226
|
));
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
// ui/src/layout/CanopyHeader.jsx
|
|
230
|
+
import React11 from "react";
|
|
231
|
+
|
|
232
|
+
// ui/src/search/SearchPanel.jsx
|
|
233
|
+
import React8 from "react";
|
|
234
|
+
|
|
235
|
+
// ui/src/Icons.jsx
|
|
236
|
+
import React5 from "react";
|
|
237
|
+
var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React5.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React5.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" }));
|
|
238
|
+
|
|
239
|
+
// ui/src/search/SearchPanelForm.jsx
|
|
240
|
+
import React6 from "react";
|
|
241
|
+
function readBasePath() {
|
|
242
|
+
const normalize = (val) => {
|
|
243
|
+
const raw = typeof val === "string" ? val.trim() : "";
|
|
244
|
+
if (!raw) return "";
|
|
245
|
+
return raw.replace(/\/+$/, "");
|
|
246
|
+
};
|
|
247
|
+
try {
|
|
248
|
+
if (typeof window !== "undefined" && window.CANOPY_BASE_PATH != null) {
|
|
249
|
+
const fromWindow = normalize(window.CANOPY_BASE_PATH);
|
|
250
|
+
if (fromWindow) return fromWindow;
|
|
251
|
+
}
|
|
252
|
+
} catch (_) {
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
if (typeof globalThis !== "undefined" && globalThis.CANOPY_BASE_PATH != null) {
|
|
256
|
+
const fromGlobal = normalize(globalThis.CANOPY_BASE_PATH);
|
|
257
|
+
if (fromGlobal) return fromGlobal;
|
|
258
|
+
}
|
|
259
|
+
} catch (_) {
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
if (typeof process !== "undefined" && process.env && process.env.CANOPY_BASE_PATH) {
|
|
263
|
+
const fromEnv = normalize(process.env.CANOPY_BASE_PATH);
|
|
264
|
+
if (fromEnv) return fromEnv;
|
|
265
|
+
}
|
|
266
|
+
} catch (_) {
|
|
267
|
+
}
|
|
268
|
+
return "";
|
|
269
|
+
}
|
|
270
|
+
function isAbsoluteUrl(href) {
|
|
271
|
+
try {
|
|
272
|
+
return /^https?:/i.test(String(href || ""));
|
|
273
|
+
} catch (_) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function resolveSearchPath(pathValue) {
|
|
278
|
+
let raw = typeof pathValue === "string" ? pathValue.trim() : "";
|
|
279
|
+
if (!raw) raw = "/search";
|
|
280
|
+
if (isAbsoluteUrl(raw)) return raw;
|
|
281
|
+
const normalizedPath = raw.startsWith("/") ? raw : `/${raw}`;
|
|
282
|
+
const base = readBasePath();
|
|
283
|
+
if (!base) return normalizedPath;
|
|
284
|
+
const baseWithLead = base.startsWith("/") ? base : `/${base}`;
|
|
285
|
+
const baseTrimmed = baseWithLead.replace(/\/+$/, "");
|
|
286
|
+
if (!baseTrimmed) return normalizedPath;
|
|
287
|
+
if (normalizedPath === baseTrimmed || normalizedPath.startsWith(`${baseTrimmed}/`)) {
|
|
288
|
+
return normalizedPath;
|
|
289
|
+
}
|
|
290
|
+
const pathTrimmed = normalizedPath.replace(/^\/+/, "");
|
|
291
|
+
return `${baseTrimmed}/${pathTrimmed}`;
|
|
292
|
+
}
|
|
293
|
+
function SearchPanelForm(props = {}) {
|
|
294
|
+
const {
|
|
295
|
+
placeholder = "Search\u2026",
|
|
296
|
+
buttonLabel = "Search",
|
|
297
|
+
label,
|
|
298
|
+
searchPath = "/search",
|
|
299
|
+
inputId: inputIdProp,
|
|
300
|
+
clearLabel = "Clear search"
|
|
301
|
+
} = props || {};
|
|
302
|
+
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
303
|
+
const action = React6.useMemo(
|
|
304
|
+
() => resolveSearchPath(searchPath),
|
|
305
|
+
[searchPath]
|
|
306
|
+
);
|
|
307
|
+
const autoId = typeof React6.useId === "function" ? React6.useId() : void 0;
|
|
308
|
+
const [fallbackId] = React6.useState(
|
|
309
|
+
() => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
|
|
310
|
+
);
|
|
311
|
+
const inputId = inputIdProp || autoId || fallbackId;
|
|
312
|
+
const inputRef = React6.useRef(null);
|
|
313
|
+
const [hasValue, setHasValue] = React6.useState(false);
|
|
314
|
+
const focusInput = React6.useCallback(() => {
|
|
315
|
+
const el = inputRef.current;
|
|
316
|
+
if (!el) return;
|
|
317
|
+
if (document.activeElement === el) return;
|
|
318
|
+
try {
|
|
319
|
+
el.focus({ preventScroll: true });
|
|
320
|
+
} catch (_) {
|
|
321
|
+
try {
|
|
322
|
+
el.focus();
|
|
323
|
+
} catch (_2) {
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}, []);
|
|
327
|
+
const handlePointerDown = React6.useCallback(
|
|
328
|
+
(event) => {
|
|
329
|
+
const target = event.target;
|
|
330
|
+
if (target && typeof target.closest === "function") {
|
|
331
|
+
if (target.closest("[data-canopy-search-form-trigger]")) return;
|
|
332
|
+
if (target.closest("[data-canopy-search-form-clear]")) return;
|
|
333
|
+
}
|
|
334
|
+
event.preventDefault();
|
|
335
|
+
focusInput();
|
|
336
|
+
},
|
|
337
|
+
[focusInput]
|
|
338
|
+
);
|
|
339
|
+
React6.useEffect(() => {
|
|
340
|
+
const el = inputRef.current;
|
|
341
|
+
if (!el) return;
|
|
342
|
+
if (el.value && el.value.trim()) {
|
|
343
|
+
setHasValue(true);
|
|
344
|
+
}
|
|
345
|
+
}, []);
|
|
346
|
+
const handleInputChange = React6.useCallback((event) => {
|
|
347
|
+
var _a;
|
|
348
|
+
const nextHasValue = Boolean(
|
|
349
|
+
((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
|
|
350
|
+
);
|
|
351
|
+
setHasValue(nextHasValue);
|
|
352
|
+
}, []);
|
|
353
|
+
const handleClear = React6.useCallback((event) => {
|
|
354
|
+
}, []);
|
|
355
|
+
const handleClearKey = React6.useCallback(
|
|
356
|
+
(event) => {
|
|
357
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
358
|
+
event.preventDefault();
|
|
359
|
+
handleClear(event);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
[handleClear]
|
|
363
|
+
);
|
|
364
|
+
return /* @__PURE__ */ React6.createElement(
|
|
365
|
+
"form",
|
|
366
|
+
{
|
|
367
|
+
action,
|
|
368
|
+
method: "get",
|
|
369
|
+
role: "search",
|
|
370
|
+
autoComplete: "off",
|
|
371
|
+
spellCheck: "false",
|
|
372
|
+
className: "canopy-search-form canopy-search-form-shell",
|
|
373
|
+
onPointerDown: handlePointerDown,
|
|
374
|
+
"data-has-value": hasValue ? "1" : "0"
|
|
375
|
+
},
|
|
376
|
+
/* @__PURE__ */ React6.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React6.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React6.createElement(
|
|
377
|
+
"input",
|
|
378
|
+
{
|
|
379
|
+
id: inputId,
|
|
380
|
+
type: "search",
|
|
381
|
+
name: "q",
|
|
382
|
+
inputMode: "search",
|
|
383
|
+
"data-canopy-search-form-input": true,
|
|
384
|
+
placeholder,
|
|
385
|
+
className: "canopy-search-form__input",
|
|
386
|
+
"aria-label": "Search",
|
|
387
|
+
ref: inputRef,
|
|
388
|
+
onChange: handleInputChange,
|
|
389
|
+
onInput: handleInputChange
|
|
390
|
+
}
|
|
391
|
+
)),
|
|
392
|
+
hasValue ? /* @__PURE__ */ React6.createElement(
|
|
393
|
+
"button",
|
|
394
|
+
{
|
|
395
|
+
type: "button",
|
|
396
|
+
className: "canopy-search-form__clear",
|
|
397
|
+
onClick: handleClear,
|
|
398
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
399
|
+
onKeyDown: handleClearKey,
|
|
400
|
+
"aria-label": clearLabel,
|
|
401
|
+
"data-canopy-search-form-clear": true
|
|
402
|
+
},
|
|
403
|
+
"\xD7"
|
|
404
|
+
) : null,
|
|
405
|
+
/* @__PURE__ */ React6.createElement(
|
|
406
|
+
"button",
|
|
407
|
+
{
|
|
408
|
+
type: "submit",
|
|
409
|
+
"data-canopy-search-form-trigger": "submit",
|
|
410
|
+
className: "canopy-search-form__submit"
|
|
411
|
+
},
|
|
412
|
+
/* @__PURE__ */ React6.createElement("span", null, text),
|
|
413
|
+
/* @__PURE__ */ React6.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React6.createElement("span", null, "\u2318"), /* @__PURE__ */ React6.createElement("span", null, "K"))
|
|
414
|
+
)
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ui/src/search/SearchPanelTeaserResults.jsx
|
|
419
|
+
import React7 from "react";
|
|
420
|
+
function SearchPanelTeaserResults(props = {}) {
|
|
421
|
+
const { style, className } = props || {};
|
|
422
|
+
const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
|
|
423
|
+
return /* @__PURE__ */ React7.createElement(
|
|
424
|
+
"div",
|
|
425
|
+
{
|
|
426
|
+
"data-canopy-search-form-panel": true,
|
|
427
|
+
className: classes || void 0,
|
|
428
|
+
style
|
|
429
|
+
},
|
|
430
|
+
/* @__PURE__ */ React7.createElement("div", { id: "cplist" })
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ui/src/search/SearchPanel.jsx
|
|
435
|
+
function SearchPanel(props = {}) {
|
|
436
|
+
const {
|
|
437
|
+
placeholder = "Search\u2026",
|
|
438
|
+
hotkey = "mod+k",
|
|
439
|
+
maxResults = 8,
|
|
440
|
+
groupOrder = ["work", "docs", "page"],
|
|
441
|
+
// Kept for backward compat; form always renders submit
|
|
442
|
+
button = true,
|
|
443
|
+
// eslint-disable-line no-unused-vars
|
|
444
|
+
buttonLabel = "Search",
|
|
445
|
+
label,
|
|
446
|
+
searchPath = "/search"
|
|
447
|
+
} = props || {};
|
|
448
|
+
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
449
|
+
const resolvedSearchPath = resolveSearchPath(searchPath);
|
|
450
|
+
const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
|
|
451
|
+
return /* @__PURE__ */ React8.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React8.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React8.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React8.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React8.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ui/src/layout/CanopyBrand.jsx
|
|
455
|
+
import React9 from "react";
|
|
456
|
+
function CanopyBrand(props = {}) {
|
|
457
|
+
const {
|
|
458
|
+
labelId,
|
|
459
|
+
label = "Canopy IIIF",
|
|
460
|
+
href = "/",
|
|
461
|
+
className,
|
|
462
|
+
Logo
|
|
463
|
+
} = props || {};
|
|
464
|
+
const spanProps = labelId ? { id: labelId } : {};
|
|
465
|
+
const classes = ["canopy-logo", className].filter(Boolean).join(" ");
|
|
466
|
+
return /* @__PURE__ */ React9.createElement("a", { href, className: classes }, typeof Logo === "function" ? /* @__PURE__ */ React9.createElement(Logo, null) : null, /* @__PURE__ */ React9.createElement("span", { ...spanProps }, label));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ui/src/layout/CanopyModal.jsx
|
|
470
|
+
import React10 from "react";
|
|
471
|
+
function CanopyModal(props = {}) {
|
|
472
|
+
const {
|
|
473
|
+
id,
|
|
474
|
+
variant,
|
|
475
|
+
open = false,
|
|
476
|
+
labelledBy,
|
|
477
|
+
label,
|
|
478
|
+
logo: Logo,
|
|
479
|
+
href = "/",
|
|
480
|
+
closeLabel = "Close",
|
|
481
|
+
closeDataAttr,
|
|
482
|
+
onClose,
|
|
483
|
+
onBackgroundClick,
|
|
484
|
+
bodyClassName,
|
|
485
|
+
padded = true,
|
|
486
|
+
className,
|
|
487
|
+
children
|
|
488
|
+
} = props;
|
|
489
|
+
const rootClassName = ["canopy-modal", variant ? `canopy-modal--${variant}` : null, className].filter(Boolean).join(" ");
|
|
490
|
+
const modalProps = {
|
|
491
|
+
id,
|
|
492
|
+
className: rootClassName,
|
|
493
|
+
role: "dialog",
|
|
494
|
+
"aria-modal": "true",
|
|
495
|
+
"aria-hidden": open ? "false" : "true",
|
|
496
|
+
"data-open": open ? "true" : "false"
|
|
497
|
+
};
|
|
498
|
+
if (variant) modalProps["data-canopy-modal"] = variant;
|
|
499
|
+
const resolvedLabelId = labelledBy || (label ? `${variant || "modal"}-label` : void 0);
|
|
500
|
+
if (resolvedLabelId) modalProps["aria-labelledby"] = resolvedLabelId;
|
|
501
|
+
if (typeof onBackgroundClick === "function") {
|
|
502
|
+
modalProps.onClick = (event) => {
|
|
503
|
+
if (event.target === event.currentTarget) onBackgroundClick(event);
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const closeButtonProps = {
|
|
507
|
+
type: "button",
|
|
508
|
+
className: "canopy-modal__close",
|
|
509
|
+
"aria-label": closeLabel
|
|
510
|
+
};
|
|
511
|
+
if (typeof closeDataAttr === "string" && closeDataAttr) {
|
|
512
|
+
closeButtonProps["data-canopy-header-close"] = closeDataAttr;
|
|
513
|
+
}
|
|
514
|
+
if (typeof onClose === "function") {
|
|
515
|
+
closeButtonProps.onClick = onClose;
|
|
516
|
+
}
|
|
517
|
+
const bodyClasses = ["canopy-modal__body"];
|
|
518
|
+
if (padded) bodyClasses.push("canopy-modal__body--padded");
|
|
519
|
+
if (bodyClassName) bodyClasses.push(bodyClassName);
|
|
520
|
+
const bodyClassNameValue = bodyClasses.join(" ");
|
|
521
|
+
return /* @__PURE__ */ React10.createElement("div", { ...modalProps }, /* @__PURE__ */ React10.createElement("div", { className: "canopy-modal__panel" }, /* @__PURE__ */ React10.createElement("button", { ...closeButtonProps }, /* @__PURE__ */ React10.createElement(
|
|
522
|
+
"svg",
|
|
523
|
+
{
|
|
524
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
525
|
+
viewBox: "0 0 24 24",
|
|
526
|
+
fill: "none",
|
|
527
|
+
stroke: "currentColor",
|
|
528
|
+
strokeWidth: "1.5",
|
|
529
|
+
className: "canopy-modal__close-icon"
|
|
530
|
+
},
|
|
531
|
+
/* @__PURE__ */ React10.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6l12 12M6 18L18 6" })
|
|
532
|
+
), /* @__PURE__ */ React10.createElement("span", { className: "sr-only" }, closeLabel)), /* @__PURE__ */ React10.createElement("div", { className: bodyClassNameValue }, label ? /* @__PURE__ */ React10.createElement("div", { className: "canopy-modal__brand" }, /* @__PURE__ */ React10.createElement(
|
|
533
|
+
CanopyBrand,
|
|
534
|
+
{
|
|
535
|
+
labelId: resolvedLabelId,
|
|
536
|
+
label,
|
|
537
|
+
href,
|
|
538
|
+
Logo,
|
|
539
|
+
className: "canopy-modal__brand-link"
|
|
540
|
+
}
|
|
541
|
+
)) : null, children)));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// ui/src/layout/CanopyHeader.jsx
|
|
545
|
+
function HeaderScript() {
|
|
546
|
+
const code = `
|
|
547
|
+
(function () {
|
|
548
|
+
if (typeof window === 'undefined') return;
|
|
549
|
+
|
|
550
|
+
var doc = document;
|
|
551
|
+
var body = doc.body;
|
|
552
|
+
var root = doc.documentElement;
|
|
553
|
+
|
|
554
|
+
function ready(fn) {
|
|
555
|
+
if (doc.readyState === 'loading') {
|
|
556
|
+
doc.addEventListener('DOMContentLoaded', fn, { once: true });
|
|
557
|
+
} else {
|
|
558
|
+
fn();
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
ready(function () {
|
|
563
|
+
var header = doc.querySelector('.canopy-header');
|
|
564
|
+
if (!header) return;
|
|
565
|
+
|
|
566
|
+
var NAV_ATTR = 'data-mobile-nav';
|
|
567
|
+
var SEARCH_ATTR = 'data-mobile-search';
|
|
568
|
+
|
|
569
|
+
function modalFor(type) {
|
|
570
|
+
return doc.querySelector('[data-canopy-modal="' + type + '"]');
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function each(list, fn) {
|
|
574
|
+
if (!list || typeof fn !== 'function') return;
|
|
575
|
+
Array.prototype.forEach.call(list, fn);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function setExpanded(type, expanded) {
|
|
579
|
+
var toggles = header.querySelectorAll('[data-canopy-header-toggle="' + type + '"]');
|
|
580
|
+
each(toggles, function (btn) {
|
|
581
|
+
btn.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
|
582
|
+
});
|
|
583
|
+
var modal = modalFor(type);
|
|
584
|
+
if (modal) {
|
|
585
|
+
modal.setAttribute('data-open', expanded ? 'true' : 'false');
|
|
586
|
+
modal.setAttribute('aria-hidden', expanded ? 'false' : 'true');
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function lockScroll(shouldLock) {
|
|
591
|
+
if (!body) return;
|
|
592
|
+
if (shouldLock) {
|
|
593
|
+
if (!body.dataset.canopyScrollLock) {
|
|
594
|
+
body.dataset.canopyScrollPrevOverflow = body.style.overflow || '';
|
|
595
|
+
if (root && root.dataset) {
|
|
596
|
+
root.dataset.canopyScrollPrevOverflow = root.style.overflow || '';
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
body.dataset.canopyScrollLock = '1';
|
|
600
|
+
body.style.overflow = 'hidden';
|
|
601
|
+
if (root) root.style.overflow = 'hidden';
|
|
602
|
+
} else {
|
|
603
|
+
if (body.dataset.canopyScrollLock) {
|
|
604
|
+
delete body.dataset.canopyScrollLock;
|
|
605
|
+
body.style.overflow = body.dataset.canopyScrollPrevOverflow || '';
|
|
606
|
+
delete body.dataset.canopyScrollPrevOverflow;
|
|
607
|
+
}
|
|
608
|
+
if (root && root.dataset) {
|
|
609
|
+
root.style.overflow = root.dataset.canopyScrollPrevOverflow || '';
|
|
610
|
+
delete root.dataset.canopyScrollPrevOverflow;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function stateFor(type) {
|
|
616
|
+
if (type === 'nav') return header.getAttribute(NAV_ATTR);
|
|
617
|
+
if (type === 'search') return header.getAttribute(SEARCH_ATTR);
|
|
618
|
+
return 'closed';
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function focusSearchForm() {
|
|
622
|
+
var input = header.querySelector('[data-canopy-search-form-input]');
|
|
623
|
+
if (!input) return;
|
|
624
|
+
var raf = typeof window !== 'undefined' && window.requestAnimationFrame;
|
|
625
|
+
(raf || function (fn) { return setTimeout(fn, 16); })(function () {
|
|
626
|
+
try {
|
|
627
|
+
input.focus({ preventScroll: true });
|
|
628
|
+
} catch (_) {
|
|
629
|
+
try { input.focus(); } catch (_) {}
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function focusNavMenu() {
|
|
635
|
+
var modal = modalFor('nav');
|
|
636
|
+
if (!modal) return;
|
|
637
|
+
var target = modal.querySelector('button, a, input, [tabindex]:not([tabindex="-1"])');
|
|
638
|
+
if (!target) return;
|
|
639
|
+
var raf = typeof window !== 'undefined' && window.requestAnimationFrame;
|
|
640
|
+
(raf || function (fn) { return setTimeout(fn, 16); })(function () {
|
|
641
|
+
try {
|
|
642
|
+
target.focus({ preventScroll: true });
|
|
643
|
+
} catch (_) {
|
|
644
|
+
try { target.focus(); } catch (_) {}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function setState(type, next) {
|
|
650
|
+
if (type === 'nav') header.setAttribute(NAV_ATTR, next);
|
|
651
|
+
if (type === 'search') header.setAttribute(SEARCH_ATTR, next);
|
|
652
|
+
setExpanded(type, next === 'open');
|
|
653
|
+
var navOpen = header.getAttribute(NAV_ATTR) === 'open';
|
|
654
|
+
var searchOpen = header.getAttribute(SEARCH_ATTR) === 'open';
|
|
655
|
+
lockScroll(navOpen || searchOpen);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function toggle(type, force) {
|
|
659
|
+
var current = stateFor(type) === 'open';
|
|
660
|
+
var shouldOpen = typeof force === 'boolean' ? force : !current;
|
|
661
|
+
if (shouldOpen && type === 'nav') setState('search', 'closed');
|
|
662
|
+
if (shouldOpen && type === 'search') setState('nav', 'closed');
|
|
663
|
+
setState(type, shouldOpen ? 'open' : 'closed');
|
|
664
|
+
if (type === 'search' && shouldOpen) focusSearchForm();
|
|
665
|
+
if (type === 'nav' && shouldOpen) focusNavMenu();
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
each(header.querySelectorAll('[data-canopy-header-toggle]'), function (btn) {
|
|
669
|
+
btn.addEventListener('click', function (event) {
|
|
670
|
+
event.preventDefault();
|
|
671
|
+
var type = btn.getAttribute('data-canopy-header-toggle');
|
|
672
|
+
if (!type) return;
|
|
673
|
+
toggle(type);
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
each(doc.querySelectorAll('[data-canopy-header-close]'), function (btn) {
|
|
678
|
+
btn.addEventListener('click', function () {
|
|
679
|
+
var type = btn.getAttribute('data-canopy-header-close');
|
|
680
|
+
if (!type) return;
|
|
681
|
+
toggle(type, false);
|
|
682
|
+
});
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
var navModal = modalFor('nav');
|
|
686
|
+
if (navModal) {
|
|
687
|
+
navModal.addEventListener('click', function (event) {
|
|
688
|
+
if (event.target === navModal) {
|
|
689
|
+
toggle('nav', false);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
var target = event.target && event.target.closest && event.target.closest('a');
|
|
693
|
+
if (!target) return;
|
|
694
|
+
toggle('nav', false);
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
var searchModal = modalFor('search');
|
|
699
|
+
if (searchModal) {
|
|
700
|
+
searchModal.addEventListener('click', function (event) {
|
|
701
|
+
if (event.target === searchModal) toggle('search', false);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
doc.addEventListener('keydown', function (event) {
|
|
706
|
+
if (event.key !== 'Escape') return;
|
|
707
|
+
var navOpen = header.getAttribute(NAV_ATTR) === 'open';
|
|
708
|
+
var searchOpen = header.getAttribute(SEARCH_ATTR) === 'open';
|
|
709
|
+
if (!navOpen && !searchOpen) return;
|
|
710
|
+
event.preventDefault();
|
|
711
|
+
toggle('nav', false);
|
|
712
|
+
toggle('search', false);
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
var mq = window.matchMedia('(min-width: 48rem)');
|
|
716
|
+
function syncDesktopState() {
|
|
717
|
+
if (mq.matches) {
|
|
718
|
+
setState('nav', 'closed');
|
|
719
|
+
setState('search', 'closed');
|
|
720
|
+
setExpanded('nav', false);
|
|
721
|
+
setExpanded('search', false);
|
|
722
|
+
lockScroll(false);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
try {
|
|
727
|
+
mq.addEventListener('change', syncDesktopState);
|
|
728
|
+
} catch (_) {
|
|
729
|
+
mq.addListener(syncDesktopState);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
syncDesktopState();
|
|
733
|
+
});
|
|
734
|
+
})();
|
|
735
|
+
`;
|
|
736
|
+
return /* @__PURE__ */ React11.createElement(
|
|
737
|
+
"script",
|
|
738
|
+
{
|
|
739
|
+
dangerouslySetInnerHTML: {
|
|
740
|
+
__html: code
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
function ensureArray(navLinks) {
|
|
746
|
+
if (!Array.isArray(navLinks)) return [];
|
|
747
|
+
return navLinks.filter((link) => link && typeof link === "object" && typeof link.href === "string");
|
|
748
|
+
}
|
|
749
|
+
function CanopyHeader(props = {}) {
|
|
750
|
+
const {
|
|
751
|
+
navigation: navLinksProp,
|
|
752
|
+
searchLabel = "Search",
|
|
753
|
+
searchHotkey = "mod+k",
|
|
754
|
+
searchPlaceholder = "Search\u2026",
|
|
755
|
+
brandHref = "/",
|
|
756
|
+
title = "Canopy IIIF",
|
|
757
|
+
logo: SiteLogo
|
|
758
|
+
} = props;
|
|
759
|
+
const navLinks = ensureArray(navLinksProp);
|
|
760
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("header", { className: "canopy-header", "data-mobile-nav": "closed", "data-mobile-search": "closed" }, /* @__PURE__ */ React11.createElement("div", { className: "canopy-header__brand" }, /* @__PURE__ */ React11.createElement(
|
|
761
|
+
CanopyBrand,
|
|
762
|
+
{
|
|
763
|
+
label: title,
|
|
764
|
+
href: brandHref,
|
|
765
|
+
className: "canopy-header__brand-link",
|
|
766
|
+
Logo: SiteLogo
|
|
767
|
+
}
|
|
768
|
+
)), /* @__PURE__ */ React11.createElement("div", { className: "canopy-header__desktop-search" }, /* @__PURE__ */ React11.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })), /* @__PURE__ */ React11.createElement("nav", { className: "canopy-nav-links canopy-header__desktop-nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React11.createElement("a", { key: link.href, href: link.href }, link.label || link.href))), /* @__PURE__ */ React11.createElement("div", { className: "canopy-header__actions" }, /* @__PURE__ */ React11.createElement(
|
|
769
|
+
"button",
|
|
770
|
+
{
|
|
771
|
+
type: "button",
|
|
772
|
+
className: "canopy-header__icon-button canopy-header__search-trigger",
|
|
773
|
+
"aria-label": "Open search",
|
|
774
|
+
"aria-controls": "canopy-modal-search",
|
|
775
|
+
"aria-expanded": "false",
|
|
776
|
+
"data-canopy-header-toggle": "search"
|
|
777
|
+
},
|
|
778
|
+
/* @__PURE__ */ React11.createElement(
|
|
779
|
+
"svg",
|
|
780
|
+
{
|
|
781
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
782
|
+
viewBox: "0 0 24 24",
|
|
783
|
+
fill: "none",
|
|
784
|
+
stroke: "currentColor",
|
|
785
|
+
strokeWidth: "1.5",
|
|
786
|
+
className: "canopy-header__search-icon"
|
|
787
|
+
},
|
|
788
|
+
/* @__PURE__ */ React11.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-3.8-3.8M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z" })
|
|
789
|
+
)
|
|
790
|
+
), /* @__PURE__ */ React11.createElement(
|
|
791
|
+
"button",
|
|
792
|
+
{
|
|
793
|
+
type: "button",
|
|
794
|
+
className: "canopy-header__icon-button canopy-header__menu",
|
|
795
|
+
"aria-label": "Open navigation",
|
|
796
|
+
"aria-controls": "canopy-modal-nav",
|
|
797
|
+
"aria-expanded": "false",
|
|
798
|
+
"data-canopy-header-toggle": "nav"
|
|
799
|
+
},
|
|
800
|
+
/* @__PURE__ */ React11.createElement(
|
|
801
|
+
"svg",
|
|
802
|
+
{
|
|
803
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
804
|
+
fill: "none",
|
|
805
|
+
viewBox: "0 0 24 24",
|
|
806
|
+
strokeWidth: "1.5",
|
|
807
|
+
stroke: "currentColor",
|
|
808
|
+
className: "canopy-header__menu-icon"
|
|
809
|
+
},
|
|
810
|
+
/* @__PURE__ */ React11.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" })
|
|
811
|
+
)
|
|
812
|
+
))), /* @__PURE__ */ React11.createElement(
|
|
813
|
+
CanopyModal,
|
|
814
|
+
{
|
|
815
|
+
id: "canopy-modal-nav",
|
|
816
|
+
variant: "nav",
|
|
817
|
+
labelledBy: "canopy-modal-nav-label",
|
|
818
|
+
label: title,
|
|
819
|
+
logo: SiteLogo,
|
|
820
|
+
href: brandHref,
|
|
821
|
+
closeLabel: "Close navigation",
|
|
822
|
+
closeDataAttr: "nav"
|
|
823
|
+
},
|
|
824
|
+
/* @__PURE__ */ React11.createElement("nav", { className: "canopy-nav-links canopy-modal__nav", "aria-label": "Primary navigation" }, navLinks.map((link) => /* @__PURE__ */ React11.createElement("a", { key: link.href, href: link.href }, link.label || link.href)))
|
|
825
|
+
), /* @__PURE__ */ React11.createElement(
|
|
826
|
+
CanopyModal,
|
|
827
|
+
{
|
|
828
|
+
id: "canopy-modal-search",
|
|
829
|
+
variant: "search",
|
|
830
|
+
labelledBy: "canopy-modal-search-label",
|
|
831
|
+
label: title,
|
|
832
|
+
logo: SiteLogo,
|
|
833
|
+
href: brandHref,
|
|
834
|
+
closeLabel: "Close search",
|
|
835
|
+
closeDataAttr: "search",
|
|
836
|
+
bodyClassName: "canopy-modal__body--search"
|
|
837
|
+
},
|
|
838
|
+
/* @__PURE__ */ React11.createElement(SearchPanel, { label: searchLabel, hotkey: searchHotkey, placeholder: searchPlaceholder })
|
|
839
|
+
), /* @__PURE__ */ React11.createElement(HeaderScript, null));
|
|
840
|
+
}
|
|
841
|
+
|
|
229
842
|
// ui/src/iiif/Viewer.jsx
|
|
230
|
-
import
|
|
843
|
+
import React12, { useEffect as useEffect2, useState as useState2 } from "react";
|
|
231
844
|
var DEFAULT_VIEWER_OPTIONS = {
|
|
232
845
|
showDownload: false,
|
|
233
846
|
showIIIFBadge: false,
|
|
@@ -283,7 +896,7 @@ var Viewer = (props) => {
|
|
|
283
896
|
} catch (_) {
|
|
284
897
|
json = "{}";
|
|
285
898
|
}
|
|
286
|
-
return /* @__PURE__ */
|
|
899
|
+
return /* @__PURE__ */ React12.createElement("div", { "data-canopy-viewer": "1", className: "not-prose" }, /* @__PURE__ */ React12.createElement(
|
|
287
900
|
"script",
|
|
288
901
|
{
|
|
289
902
|
type: "application/json",
|
|
@@ -291,11 +904,11 @@ var Viewer = (props) => {
|
|
|
291
904
|
}
|
|
292
905
|
));
|
|
293
906
|
}
|
|
294
|
-
return /* @__PURE__ */
|
|
907
|
+
return /* @__PURE__ */ React12.createElement(CloverViewer, { ...props, options: mergedOptions });
|
|
295
908
|
};
|
|
296
909
|
|
|
297
910
|
// ui/src/iiif/Slider.jsx
|
|
298
|
-
import
|
|
911
|
+
import React13, { useEffect as useEffect3, useState as useState3 } from "react";
|
|
299
912
|
var Slider = (props) => {
|
|
300
913
|
const [CloverSlider, setCloverSlider] = useState3(null);
|
|
301
914
|
useEffect3(() => {
|
|
@@ -321,7 +934,7 @@ var Slider = (props) => {
|
|
|
321
934
|
} catch (_) {
|
|
322
935
|
json = "{}";
|
|
323
936
|
}
|
|
324
|
-
return /* @__PURE__ */
|
|
937
|
+
return /* @__PURE__ */ React13.createElement("div", { "data-canopy-slider": "1", className: "not-prose" }, /* @__PURE__ */ React13.createElement(
|
|
325
938
|
"script",
|
|
326
939
|
{
|
|
327
940
|
type: "application/json",
|
|
@@ -329,11 +942,11 @@ var Slider = (props) => {
|
|
|
329
942
|
}
|
|
330
943
|
));
|
|
331
944
|
}
|
|
332
|
-
return /* @__PURE__ */
|
|
945
|
+
return /* @__PURE__ */ React13.createElement(CloverSlider, { ...props });
|
|
333
946
|
};
|
|
334
947
|
|
|
335
948
|
// ui/src/iiif/Scroll.jsx
|
|
336
|
-
import
|
|
949
|
+
import React14, { useEffect as useEffect4, useState as useState4 } from "react";
|
|
337
950
|
var Scroll = (props) => {
|
|
338
951
|
const [CloverScroll, setCloverScroll] = useState4(null);
|
|
339
952
|
useEffect4(() => {
|
|
@@ -358,7 +971,7 @@ var Scroll = (props) => {
|
|
|
358
971
|
} catch (_) {
|
|
359
972
|
json = "{}";
|
|
360
973
|
}
|
|
361
|
-
return /* @__PURE__ */
|
|
974
|
+
return /* @__PURE__ */ React14.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React14.createElement(
|
|
362
975
|
"script",
|
|
363
976
|
{
|
|
364
977
|
type: "application/json",
|
|
@@ -366,11 +979,11 @@ var Scroll = (props) => {
|
|
|
366
979
|
}
|
|
367
980
|
));
|
|
368
981
|
}
|
|
369
|
-
return /* @__PURE__ */
|
|
982
|
+
return /* @__PURE__ */ React14.createElement(CloverScroll, { ...props });
|
|
370
983
|
};
|
|
371
984
|
|
|
372
985
|
// ui/src/iiif/MdxRelatedItems.jsx
|
|
373
|
-
import
|
|
986
|
+
import React15 from "react";
|
|
374
987
|
function MdxRelatedItems(props) {
|
|
375
988
|
let json = "{}";
|
|
376
989
|
try {
|
|
@@ -378,11 +991,11 @@ function MdxRelatedItems(props) {
|
|
|
378
991
|
} catch (_) {
|
|
379
992
|
json = "{}";
|
|
380
993
|
}
|
|
381
|
-
return /* @__PURE__ */
|
|
994
|
+
return /* @__PURE__ */ React15.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React15.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
382
995
|
}
|
|
383
996
|
|
|
384
997
|
// ui/src/search/MdxSearchResults.jsx
|
|
385
|
-
import
|
|
998
|
+
import React16 from "react";
|
|
386
999
|
function MdxSearchResults(props) {
|
|
387
1000
|
let json = "{}";
|
|
388
1001
|
try {
|
|
@@ -390,11 +1003,11 @@ function MdxSearchResults(props) {
|
|
|
390
1003
|
} catch (_) {
|
|
391
1004
|
json = "{}";
|
|
392
1005
|
}
|
|
393
|
-
return /* @__PURE__ */
|
|
1006
|
+
return /* @__PURE__ */ React16.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
394
1007
|
}
|
|
395
1008
|
|
|
396
1009
|
// ui/src/search/SearchSummary.jsx
|
|
397
|
-
import
|
|
1010
|
+
import React17 from "react";
|
|
398
1011
|
function SearchSummary(props) {
|
|
399
1012
|
let json = "{}";
|
|
400
1013
|
try {
|
|
@@ -402,11 +1015,11 @@ function SearchSummary(props) {
|
|
|
402
1015
|
} catch (_) {
|
|
403
1016
|
json = "{}";
|
|
404
1017
|
}
|
|
405
|
-
return /* @__PURE__ */
|
|
1018
|
+
return /* @__PURE__ */ React17.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React17.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
406
1019
|
}
|
|
407
1020
|
|
|
408
1021
|
// ui/src/search/MdxSearchTabs.jsx
|
|
409
|
-
import
|
|
1022
|
+
import React18 from "react";
|
|
410
1023
|
function MdxSearchTabs(props) {
|
|
411
1024
|
let json = "{}";
|
|
412
1025
|
try {
|
|
@@ -414,11 +1027,11 @@ function MdxSearchTabs(props) {
|
|
|
414
1027
|
} catch (_) {
|
|
415
1028
|
json = "{}";
|
|
416
1029
|
}
|
|
417
|
-
return /* @__PURE__ */
|
|
1030
|
+
return /* @__PURE__ */ React18.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React18.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
418
1031
|
}
|
|
419
1032
|
|
|
420
1033
|
// ui/src/search/SearchResults.jsx
|
|
421
|
-
import
|
|
1034
|
+
import React19 from "react";
|
|
422
1035
|
function SearchResults({
|
|
423
1036
|
results = [],
|
|
424
1037
|
type = "all",
|
|
@@ -426,19 +1039,19 @@ function SearchResults({
|
|
|
426
1039
|
query = ""
|
|
427
1040
|
}) {
|
|
428
1041
|
if (!results.length) {
|
|
429
|
-
return /* @__PURE__ */
|
|
1042
|
+
return /* @__PURE__ */ React19.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React19.createElement("em", null, "No results"));
|
|
430
1043
|
}
|
|
431
1044
|
const normalizedType = String(type || "all").toLowerCase();
|
|
432
1045
|
const isAnnotationView = normalizedType === "annotation";
|
|
433
1046
|
if (isAnnotationView) {
|
|
434
|
-
return /* @__PURE__ */
|
|
1047
|
+
return /* @__PURE__ */ React19.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
|
|
435
1048
|
if (!r) return null;
|
|
436
1049
|
return renderTextCard(r, r.id || i);
|
|
437
1050
|
}));
|
|
438
1051
|
}
|
|
439
1052
|
const renderTextCard = (record, key) => {
|
|
440
1053
|
if (!record) return null;
|
|
441
|
-
return /* @__PURE__ */
|
|
1054
|
+
return /* @__PURE__ */ React19.createElement(
|
|
442
1055
|
TextCard,
|
|
443
1056
|
{
|
|
444
1057
|
key,
|
|
@@ -454,20 +1067,20 @@ function SearchResults({
|
|
|
454
1067
|
const isWorkRecord = (record) => String(record && record.type).toLowerCase() === "work";
|
|
455
1068
|
const shouldRenderAsTextCard = (record) => !isWorkRecord(record) || normalizedType !== "work";
|
|
456
1069
|
if (layout === "list") {
|
|
457
|
-
return /* @__PURE__ */
|
|
1070
|
+
return /* @__PURE__ */ React19.createElement("ul", { id: "search-results", className: "space-y-3" }, results.map((r, i) => {
|
|
458
1071
|
if (shouldRenderAsTextCard(r)) {
|
|
459
|
-
return /* @__PURE__ */
|
|
1072
|
+
return /* @__PURE__ */ React19.createElement("li", { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
|
|
460
1073
|
}
|
|
461
1074
|
const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
|
|
462
1075
|
const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
|
|
463
|
-
return /* @__PURE__ */
|
|
1076
|
+
return /* @__PURE__ */ React19.createElement(
|
|
464
1077
|
"li",
|
|
465
1078
|
{
|
|
466
1079
|
key: i,
|
|
467
1080
|
className: `search-result ${r.type}`,
|
|
468
1081
|
"data-thumbnail-aspect-ratio": aspect
|
|
469
1082
|
},
|
|
470
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ React19.createElement(
|
|
471
1084
|
Card,
|
|
472
1085
|
{
|
|
473
1086
|
href: r.href,
|
|
@@ -481,20 +1094,20 @@ function SearchResults({
|
|
|
481
1094
|
);
|
|
482
1095
|
}));
|
|
483
1096
|
}
|
|
484
|
-
return /* @__PURE__ */
|
|
1097
|
+
return /* @__PURE__ */ React19.createElement("div", { id: "search-results" }, /* @__PURE__ */ React19.createElement(Grid, null, results.map((r, i) => {
|
|
485
1098
|
if (shouldRenderAsTextCard(r)) {
|
|
486
|
-
return /* @__PURE__ */
|
|
1099
|
+
return /* @__PURE__ */ React19.createElement(GridItem, { key: i, className: `search-result ${r && r.type}` }, renderTextCard(r, i));
|
|
487
1100
|
}
|
|
488
1101
|
const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
|
|
489
1102
|
const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
|
|
490
|
-
return /* @__PURE__ */
|
|
1103
|
+
return /* @__PURE__ */ React19.createElement(
|
|
491
1104
|
GridItem,
|
|
492
1105
|
{
|
|
493
1106
|
key: i,
|
|
494
1107
|
className: `search-result ${r.type}`,
|
|
495
1108
|
"data-thumbnail-aspect-ratio": aspect
|
|
496
1109
|
},
|
|
497
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ React19.createElement(
|
|
498
1111
|
Card,
|
|
499
1112
|
{
|
|
500
1113
|
href: r.href,
|
|
@@ -510,7 +1123,7 @@ function SearchResults({
|
|
|
510
1123
|
}
|
|
511
1124
|
|
|
512
1125
|
// ui/src/search/SearchTabs.jsx
|
|
513
|
-
import
|
|
1126
|
+
import React20 from "react";
|
|
514
1127
|
function SearchTabs({
|
|
515
1128
|
type = "all",
|
|
516
1129
|
onTypeChange,
|
|
@@ -525,7 +1138,7 @@ function SearchTabs({
|
|
|
525
1138
|
const toLabel = (t) => t && t.length ? t.charAt(0).toUpperCase() + t.slice(1) : "";
|
|
526
1139
|
const hasFilters = typeof onOpenFilters === "function";
|
|
527
1140
|
const filterBadge = activeFilterCount > 0 ? ` (${activeFilterCount})` : "";
|
|
528
|
-
return /* @__PURE__ */
|
|
1141
|
+
return /* @__PURE__ */ React20.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React20.createElement(
|
|
529
1142
|
"div",
|
|
530
1143
|
{
|
|
531
1144
|
role: "tablist",
|
|
@@ -536,7 +1149,7 @@ function SearchTabs({
|
|
|
536
1149
|
const active = String(type).toLowerCase() === String(t).toLowerCase();
|
|
537
1150
|
const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
|
|
538
1151
|
const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
|
|
539
|
-
return /* @__PURE__ */
|
|
1152
|
+
return /* @__PURE__ */ React20.createElement(
|
|
540
1153
|
"button",
|
|
541
1154
|
{
|
|
542
1155
|
key: t,
|
|
@@ -551,7 +1164,7 @@ function SearchTabs({
|
|
|
551
1164
|
")"
|
|
552
1165
|
);
|
|
553
1166
|
})
|
|
554
|
-
), hasFilters ? /* @__PURE__ */
|
|
1167
|
+
), hasFilters ? /* @__PURE__ */ React20.createElement(
|
|
555
1168
|
"button",
|
|
556
1169
|
{
|
|
557
1170
|
type: "button",
|
|
@@ -559,12 +1172,12 @@ function SearchTabs({
|
|
|
559
1172
|
"aria-expanded": filtersOpen ? "true" : "false",
|
|
560
1173
|
className: "inline-flex items-center gap-2 rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm font-medium text-slate-700 shadow-sm transition hover:border-brand-200 hover:bg-brand-50 hover:text-brand-700"
|
|
561
1174
|
},
|
|
562
|
-
/* @__PURE__ */
|
|
1175
|
+
/* @__PURE__ */ React20.createElement("span", null, filtersLabel, filterBadge)
|
|
563
1176
|
) : null);
|
|
564
1177
|
}
|
|
565
1178
|
|
|
566
1179
|
// ui/src/search/SearchFiltersDialog.jsx
|
|
567
|
-
import
|
|
1180
|
+
import React21 from "react";
|
|
568
1181
|
function toArray(input) {
|
|
569
1182
|
if (!input) return [];
|
|
570
1183
|
if (Array.isArray(input)) return input;
|
|
@@ -603,20 +1216,20 @@ function FacetSection({ facet, selected, onToggle }) {
|
|
|
603
1216
|
const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
|
|
604
1217
|
const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
|
|
605
1218
|
const hasSelection = selectedValues.size > 0;
|
|
606
|
-
const [quickQuery, setQuickQuery] =
|
|
1219
|
+
const [quickQuery, setQuickQuery] = React21.useState("");
|
|
607
1220
|
const hasQuery = quickQuery.trim().length > 0;
|
|
608
|
-
const filteredValues =
|
|
1221
|
+
const filteredValues = React21.useMemo(
|
|
609
1222
|
() => facetMatches(values, quickQuery),
|
|
610
1223
|
[values, quickQuery]
|
|
611
1224
|
);
|
|
612
|
-
return /* @__PURE__ */
|
|
1225
|
+
return /* @__PURE__ */ React21.createElement(
|
|
613
1226
|
"details",
|
|
614
1227
|
{
|
|
615
1228
|
className: "canopy-search-filters__facet",
|
|
616
1229
|
open: hasSelection
|
|
617
1230
|
},
|
|
618
|
-
/* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
1231
|
+
/* @__PURE__ */ React21.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React21.createElement("span", null, label), /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
|
|
1232
|
+
/* @__PURE__ */ React21.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React21.createElement(
|
|
620
1233
|
"input",
|
|
621
1234
|
{
|
|
622
1235
|
type: "search",
|
|
@@ -626,7 +1239,7 @@ function FacetSection({ facet, selected, onToggle }) {
|
|
|
626
1239
|
className: "canopy-search-filters__quick-input",
|
|
627
1240
|
"aria-label": `Filter ${label} values`
|
|
628
1241
|
}
|
|
629
|
-
), quickQuery ? /* @__PURE__ */
|
|
1242
|
+
), quickQuery ? /* @__PURE__ */ React21.createElement(
|
|
630
1243
|
"button",
|
|
631
1244
|
{
|
|
632
1245
|
type: "button",
|
|
@@ -634,11 +1247,11 @@ function FacetSection({ facet, selected, onToggle }) {
|
|
|
634
1247
|
className: "canopy-search-filters__quick-clear"
|
|
635
1248
|
},
|
|
636
1249
|
"Clear"
|
|
637
|
-
) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */
|
|
1250
|
+
) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React21.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React21.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
|
|
638
1251
|
const valueSlug = String(entry.slug || entry.value || "");
|
|
639
1252
|
const isChecked = selectedValues.has(valueSlug);
|
|
640
1253
|
const inputId = checkboxId(valueSlug);
|
|
641
|
-
return /* @__PURE__ */
|
|
1254
|
+
return /* @__PURE__ */ React21.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React21.createElement(
|
|
642
1255
|
"input",
|
|
643
1256
|
{
|
|
644
1257
|
id: inputId,
|
|
@@ -650,15 +1263,15 @@ function FacetSection({ facet, selected, onToggle }) {
|
|
|
650
1263
|
if (onToggle) onToggle(slug, valueSlug, nextChecked);
|
|
651
1264
|
}
|
|
652
1265
|
}
|
|
653
|
-
), /* @__PURE__ */
|
|
1266
|
+
), /* @__PURE__ */ React21.createElement(
|
|
654
1267
|
"label",
|
|
655
1268
|
{
|
|
656
1269
|
htmlFor: inputId,
|
|
657
1270
|
className: "canopy-search-filters__facet-label"
|
|
658
1271
|
},
|
|
659
|
-
/* @__PURE__ */
|
|
1272
|
+
/* @__PURE__ */ React21.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
|
|
660
1273
|
));
|
|
661
|
-
}), !filteredValues.length && !hasQuery ? /* @__PURE__ */
|
|
1274
|
+
}), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React21.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
|
|
662
1275
|
);
|
|
663
1276
|
}
|
|
664
1277
|
function SearchFiltersDialog(props = {}) {
|
|
@@ -669,35 +1282,51 @@ function SearchFiltersDialog(props = {}) {
|
|
|
669
1282
|
selected = {},
|
|
670
1283
|
onToggle,
|
|
671
1284
|
onClear,
|
|
672
|
-
title
|
|
673
|
-
subtitle = "Refine results by metadata"
|
|
1285
|
+
title,
|
|
1286
|
+
subtitle = "Refine results by metadata",
|
|
1287
|
+
brandLabel = "Canopy IIIF",
|
|
1288
|
+
brandHref = "/",
|
|
1289
|
+
logo: SiteLogo
|
|
674
1290
|
} = props;
|
|
675
1291
|
const selectedMap = normalizeSelected(selected);
|
|
676
1292
|
const activeCount = Array.from(selectedMap.values()).reduce(
|
|
677
1293
|
(total, set) => total + set.size,
|
|
678
1294
|
0
|
|
679
1295
|
);
|
|
1296
|
+
React21.useEffect(() => {
|
|
1297
|
+
if (!open) return void 0;
|
|
1298
|
+
if (typeof document === "undefined") return void 0;
|
|
1299
|
+
const body = document.body;
|
|
1300
|
+
const root = document.documentElement;
|
|
1301
|
+
const prevBody = body ? body.style.overflow : "";
|
|
1302
|
+
const prevRoot = root ? root.style.overflow : "";
|
|
1303
|
+
if (body) body.style.overflow = "hidden";
|
|
1304
|
+
if (root) root.style.overflow = "hidden";
|
|
1305
|
+
return () => {
|
|
1306
|
+
if (body) body.style.overflow = prevBody;
|
|
1307
|
+
if (root) root.style.overflow = prevRoot;
|
|
1308
|
+
};
|
|
1309
|
+
}, [open]);
|
|
680
1310
|
if (!open) return null;
|
|
681
|
-
|
|
682
|
-
|
|
1311
|
+
const brandId = "canopy-modal-filters-label";
|
|
1312
|
+
const subtitleText = subtitle != null ? subtitle : title;
|
|
1313
|
+
return /* @__PURE__ */ React21.createElement(
|
|
1314
|
+
CanopyModal,
|
|
683
1315
|
{
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
1316
|
+
id: "canopy-modal-filters",
|
|
1317
|
+
variant: "filters",
|
|
1318
|
+
open: true,
|
|
1319
|
+
labelledBy: brandId,
|
|
1320
|
+
label: brandLabel,
|
|
1321
|
+
logo: SiteLogo,
|
|
1322
|
+
href: brandHref,
|
|
1323
|
+
closeLabel: "Close filters",
|
|
1324
|
+
onClose: () => onOpenChange && onOpenChange(false),
|
|
1325
|
+
onBackgroundClick: () => onOpenChange && onOpenChange(false),
|
|
1326
|
+
bodyClassName: "canopy-modal__body--filters"
|
|
691
1327
|
},
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
{
|
|
695
|
-
type: "button",
|
|
696
|
-
onClick: () => onOpenChange && onOpenChange(false),
|
|
697
|
-
className: "canopy-search-filters__close"
|
|
698
|
-
},
|
|
699
|
-
"Close"
|
|
700
|
-
)), /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React14.createElement(
|
|
1328
|
+
subtitleText ? /* @__PURE__ */ React21.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitleText) : null,
|
|
1329
|
+
/* @__PURE__ */ React21.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React21.createElement(
|
|
701
1330
|
FacetSection,
|
|
702
1331
|
{
|
|
703
1332
|
key: facet.slug || facet.label,
|
|
@@ -705,7 +1334,8 @@ function SearchFiltersDialog(props = {}) {
|
|
|
705
1334
|
selected: selectedMap,
|
|
706
1335
|
onToggle
|
|
707
1336
|
}
|
|
708
|
-
))) : /* @__PURE__ */
|
|
1337
|
+
))) : /* @__PURE__ */ React21.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")),
|
|
1338
|
+
/* @__PURE__ */ React21.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React21.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React21.createElement(
|
|
709
1339
|
"button",
|
|
710
1340
|
{
|
|
711
1341
|
type: "button",
|
|
@@ -716,7 +1346,7 @@ function SearchFiltersDialog(props = {}) {
|
|
|
716
1346
|
className: "canopy-search-filters__button canopy-search-filters__button--secondary"
|
|
717
1347
|
},
|
|
718
1348
|
"Clear all"
|
|
719
|
-
), /* @__PURE__ */
|
|
1349
|
+
), /* @__PURE__ */ React21.createElement(
|
|
720
1350
|
"button",
|
|
721
1351
|
{
|
|
722
1352
|
type: "button",
|
|
@@ -724,213 +1354,12 @@ function SearchFiltersDialog(props = {}) {
|
|
|
724
1354
|
className: "canopy-search-filters__button canopy-search-filters__button--primary"
|
|
725
1355
|
},
|
|
726
1356
|
"Done"
|
|
727
|
-
)))
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// ui/src/search-form/MdxSearchFormModal.jsx
|
|
732
|
-
import React18 from "react";
|
|
733
|
-
|
|
734
|
-
// ui/src/Icons.jsx
|
|
735
|
-
import React15 from "react";
|
|
736
|
-
var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React15.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React15.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" }));
|
|
737
|
-
|
|
738
|
-
// ui/src/search/SearchPanelForm.jsx
|
|
739
|
-
import React16 from "react";
|
|
740
|
-
function readBasePath() {
|
|
741
|
-
const normalize = (val) => {
|
|
742
|
-
const raw = typeof val === "string" ? val.trim() : "";
|
|
743
|
-
if (!raw) return "";
|
|
744
|
-
return raw.replace(/\/+$/, "");
|
|
745
|
-
};
|
|
746
|
-
try {
|
|
747
|
-
if (typeof window !== "undefined" && window.CANOPY_BASE_PATH != null) {
|
|
748
|
-
const fromWindow = normalize(window.CANOPY_BASE_PATH);
|
|
749
|
-
if (fromWindow) return fromWindow;
|
|
750
|
-
}
|
|
751
|
-
} catch (_) {
|
|
752
|
-
}
|
|
753
|
-
try {
|
|
754
|
-
if (typeof globalThis !== "undefined" && globalThis.CANOPY_BASE_PATH != null) {
|
|
755
|
-
const fromGlobal = normalize(globalThis.CANOPY_BASE_PATH);
|
|
756
|
-
if (fromGlobal) return fromGlobal;
|
|
757
|
-
}
|
|
758
|
-
} catch (_) {
|
|
759
|
-
}
|
|
760
|
-
try {
|
|
761
|
-
if (typeof process !== "undefined" && process.env && process.env.CANOPY_BASE_PATH) {
|
|
762
|
-
const fromEnv = normalize(process.env.CANOPY_BASE_PATH);
|
|
763
|
-
if (fromEnv) return fromEnv;
|
|
764
|
-
}
|
|
765
|
-
} catch (_) {
|
|
766
|
-
}
|
|
767
|
-
return "";
|
|
768
|
-
}
|
|
769
|
-
function isAbsoluteUrl(href) {
|
|
770
|
-
try {
|
|
771
|
-
return /^https?:/i.test(String(href || ""));
|
|
772
|
-
} catch (_) {
|
|
773
|
-
return false;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
function resolveSearchPath(pathValue) {
|
|
777
|
-
let raw = typeof pathValue === "string" ? pathValue.trim() : "";
|
|
778
|
-
if (!raw) raw = "/search";
|
|
779
|
-
if (isAbsoluteUrl(raw)) return raw;
|
|
780
|
-
const normalizedPath = raw.startsWith("/") ? raw : `/${raw}`;
|
|
781
|
-
const base = readBasePath();
|
|
782
|
-
if (!base) return normalizedPath;
|
|
783
|
-
const baseWithLead = base.startsWith("/") ? base : `/${base}`;
|
|
784
|
-
const baseTrimmed = baseWithLead.replace(/\/+$/, "");
|
|
785
|
-
if (!baseTrimmed) return normalizedPath;
|
|
786
|
-
if (normalizedPath === baseTrimmed || normalizedPath.startsWith(`${baseTrimmed}/`)) {
|
|
787
|
-
return normalizedPath;
|
|
788
|
-
}
|
|
789
|
-
const pathTrimmed = normalizedPath.replace(/^\/+/, "");
|
|
790
|
-
return `${baseTrimmed}/${pathTrimmed}`;
|
|
791
|
-
}
|
|
792
|
-
function SearchPanelForm(props = {}) {
|
|
793
|
-
const {
|
|
794
|
-
placeholder = "Search\u2026",
|
|
795
|
-
buttonLabel = "Search",
|
|
796
|
-
label,
|
|
797
|
-
searchPath = "/search",
|
|
798
|
-
inputId: inputIdProp,
|
|
799
|
-
clearLabel = "Clear search"
|
|
800
|
-
} = props || {};
|
|
801
|
-
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
802
|
-
const action = React16.useMemo(
|
|
803
|
-
() => resolveSearchPath(searchPath),
|
|
804
|
-
[searchPath]
|
|
805
|
-
);
|
|
806
|
-
const autoId = typeof React16.useId === "function" ? React16.useId() : void 0;
|
|
807
|
-
const [fallbackId] = React16.useState(
|
|
808
|
-
() => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
|
|
809
|
-
);
|
|
810
|
-
const inputId = inputIdProp || autoId || fallbackId;
|
|
811
|
-
const inputRef = React16.useRef(null);
|
|
812
|
-
const [hasValue, setHasValue] = React16.useState(false);
|
|
813
|
-
const focusInput = React16.useCallback(() => {
|
|
814
|
-
const el = inputRef.current;
|
|
815
|
-
if (!el) return;
|
|
816
|
-
if (document.activeElement === el) return;
|
|
817
|
-
try {
|
|
818
|
-
el.focus({ preventScroll: true });
|
|
819
|
-
} catch (_) {
|
|
820
|
-
try {
|
|
821
|
-
el.focus();
|
|
822
|
-
} catch (_2) {
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
}, []);
|
|
826
|
-
const handlePointerDown = React16.useCallback(
|
|
827
|
-
(event) => {
|
|
828
|
-
const target = event.target;
|
|
829
|
-
if (target && typeof target.closest === "function") {
|
|
830
|
-
if (target.closest("[data-canopy-search-form-trigger]")) return;
|
|
831
|
-
if (target.closest("[data-canopy-search-form-clear]")) return;
|
|
832
|
-
}
|
|
833
|
-
event.preventDefault();
|
|
834
|
-
focusInput();
|
|
835
|
-
},
|
|
836
|
-
[focusInput]
|
|
837
|
-
);
|
|
838
|
-
React16.useEffect(() => {
|
|
839
|
-
const el = inputRef.current;
|
|
840
|
-
if (!el) return;
|
|
841
|
-
if (el.value && el.value.trim()) {
|
|
842
|
-
setHasValue(true);
|
|
843
|
-
}
|
|
844
|
-
}, []);
|
|
845
|
-
const handleInputChange = React16.useCallback((event) => {
|
|
846
|
-
var _a;
|
|
847
|
-
const nextHasValue = Boolean(
|
|
848
|
-
((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
|
|
849
|
-
);
|
|
850
|
-
setHasValue(nextHasValue);
|
|
851
|
-
}, []);
|
|
852
|
-
const handleClear = React16.useCallback((event) => {
|
|
853
|
-
}, []);
|
|
854
|
-
const handleClearKey = React16.useCallback(
|
|
855
|
-
(event) => {
|
|
856
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
857
|
-
event.preventDefault();
|
|
858
|
-
handleClear(event);
|
|
859
|
-
}
|
|
860
|
-
},
|
|
861
|
-
[handleClear]
|
|
862
|
-
);
|
|
863
|
-
return /* @__PURE__ */ React16.createElement(
|
|
864
|
-
"form",
|
|
865
|
-
{
|
|
866
|
-
action,
|
|
867
|
-
method: "get",
|
|
868
|
-
role: "search",
|
|
869
|
-
autoComplete: "off",
|
|
870
|
-
spellCheck: "false",
|
|
871
|
-
className: "canopy-search-form canopy-search-form-shell",
|
|
872
|
-
onPointerDown: handlePointerDown,
|
|
873
|
-
"data-has-value": hasValue ? "1" : "0"
|
|
874
|
-
},
|
|
875
|
-
/* @__PURE__ */ React16.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React16.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React16.createElement(
|
|
876
|
-
"input",
|
|
877
|
-
{
|
|
878
|
-
id: inputId,
|
|
879
|
-
type: "search",
|
|
880
|
-
name: "q",
|
|
881
|
-
inputMode: "search",
|
|
882
|
-
"data-canopy-search-form-input": true,
|
|
883
|
-
placeholder,
|
|
884
|
-
className: "canopy-search-form__input",
|
|
885
|
-
"aria-label": "Search",
|
|
886
|
-
ref: inputRef,
|
|
887
|
-
onChange: handleInputChange,
|
|
888
|
-
onInput: handleInputChange
|
|
889
|
-
}
|
|
890
|
-
)),
|
|
891
|
-
hasValue ? /* @__PURE__ */ React16.createElement(
|
|
892
|
-
"button",
|
|
893
|
-
{
|
|
894
|
-
type: "button",
|
|
895
|
-
className: "canopy-search-form__clear",
|
|
896
|
-
onClick: handleClear,
|
|
897
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
898
|
-
onKeyDown: handleClearKey,
|
|
899
|
-
"aria-label": clearLabel,
|
|
900
|
-
"data-canopy-search-form-clear": true
|
|
901
|
-
},
|
|
902
|
-
"\xD7"
|
|
903
|
-
) : null,
|
|
904
|
-
/* @__PURE__ */ React16.createElement(
|
|
905
|
-
"button",
|
|
906
|
-
{
|
|
907
|
-
type: "submit",
|
|
908
|
-
"data-canopy-search-form-trigger": "submit",
|
|
909
|
-
className: "canopy-search-form__submit"
|
|
910
|
-
},
|
|
911
|
-
/* @__PURE__ */ React16.createElement("span", null, text),
|
|
912
|
-
/* @__PURE__ */ React16.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React16.createElement("span", null, "\u2318"), /* @__PURE__ */ React16.createElement("span", null, "K"))
|
|
913
|
-
)
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
// ui/src/search/SearchPanelTeaserResults.jsx
|
|
918
|
-
import React17 from "react";
|
|
919
|
-
function SearchPanelTeaserResults(props = {}) {
|
|
920
|
-
const { style, className } = props || {};
|
|
921
|
-
const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
|
|
922
|
-
return /* @__PURE__ */ React17.createElement(
|
|
923
|
-
"div",
|
|
924
|
-
{
|
|
925
|
-
"data-canopy-search-form-panel": true,
|
|
926
|
-
className: classes || void 0,
|
|
927
|
-
style
|
|
928
|
-
},
|
|
929
|
-
/* @__PURE__ */ React17.createElement("div", { id: "cplist" })
|
|
1357
|
+
)))
|
|
930
1358
|
);
|
|
931
1359
|
}
|
|
932
1360
|
|
|
933
1361
|
// ui/src/search-form/MdxSearchFormModal.jsx
|
|
1362
|
+
import React22 from "react";
|
|
934
1363
|
function MdxSearchFormModal(props = {}) {
|
|
935
1364
|
const {
|
|
936
1365
|
placeholder = "Search\u2026",
|
|
@@ -946,30 +1375,12 @@ function MdxSearchFormModal(props = {}) {
|
|
|
946
1375
|
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
947
1376
|
const resolvedSearchPath = resolveSearchPath(searchPath);
|
|
948
1377
|
const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
|
|
949
|
-
return /* @__PURE__ */
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// ui/src/search/SearchPanel.jsx
|
|
953
|
-
import React19 from "react";
|
|
954
|
-
function SearchPanel(props = {}) {
|
|
955
|
-
const {
|
|
956
|
-
placeholder = "Search\u2026",
|
|
957
|
-
hotkey = "mod+k",
|
|
958
|
-
maxResults = 8,
|
|
959
|
-
groupOrder = ["work", "docs", "page"],
|
|
960
|
-
// Kept for backward compat; form always renders submit
|
|
961
|
-
button = true,
|
|
962
|
-
// eslint-disable-line no-unused-vars
|
|
963
|
-
buttonLabel = "Search",
|
|
964
|
-
label,
|
|
965
|
-
searchPath = "/search"
|
|
966
|
-
} = props || {};
|
|
967
|
-
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
968
|
-
const resolvedSearchPath = resolveSearchPath(searchPath);
|
|
969
|
-
const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
|
|
970
|
-
return /* @__PURE__ */ React19.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React19.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React19.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React19.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React19.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
|
|
1378
|
+
return /* @__PURE__ */ React22.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React22.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React22.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React22.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React22.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
|
|
971
1379
|
}
|
|
972
1380
|
export {
|
|
1381
|
+
CanopyBrand,
|
|
1382
|
+
CanopyHeader,
|
|
1383
|
+
CanopyModal,
|
|
973
1384
|
Card,
|
|
974
1385
|
Grid,
|
|
975
1386
|
GridItem,
|