@canopy-iiif/app 0.8.5 → 0.8.6

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 CHANGED
@@ -1144,7 +1144,8 @@ async function buildIiifCollectionPages(CONFIG) {
1144
1144
  React.createElement(app.Head)
1145
1145
  )
1146
1146
  : "";
1147
- const needsHydrateViewer = body.includes("data-canopy-viewer");
1147
+ const needsHydrateViewer =
1148
+ body.includes("data-canopy-viewer") || body.includes("data-canopy-scroll");
1148
1149
  const needsRelated = body.includes("data-canopy-related-items");
1149
1150
  const needsHero = body.includes("data-canopy-hero");
1150
1151
  const needsSearchForm = body.includes("data-canopy-search-form");
package/lib/build/mdx.js CHANGED
@@ -358,6 +358,7 @@ async function ensureClientRuntime() {
358
358
  const outFile = path.join(scriptsDir, "canopy-viewer.js");
359
359
  const entry = `
360
360
  import CloverViewer from '@samvera/clover-iiif/viewer';
361
+ import CloverScroll from '@samvera/clover-iiif/scroll';
361
362
 
362
363
  function ready(fn) {
363
364
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn, { once: true });
@@ -373,22 +374,29 @@ async function ensureClientRuntime() {
373
374
  } catch (_) { return {}; }
374
375
  }
375
376
 
376
- ready(function() {
377
+ function mountAll(selector, Component) {
377
378
  try {
378
- const nodes = document.querySelectorAll('[data-canopy-viewer]');
379
- if (!nodes || !nodes.length) return;
379
+ const nodes = document.querySelectorAll(selector);
380
+ if (!nodes || !nodes.length || !Component) return;
381
+ const React = (window && window.React) || null;
382
+ const ReactDOMClient = (window && window.ReactDOMClient) || null;
383
+ const createRoot = ReactDOMClient && ReactDOMClient.createRoot;
384
+ if (!React || !createRoot) return;
380
385
  for (const el of nodes) {
381
386
  try {
387
+ if (el.__canopyHydrated) continue;
382
388
  const props = parseProps(el);
383
- const React = (window && window.React) || null;
384
- const ReactDOMClient = (window && window.ReactDOMClient) || null;
385
- const createRoot = ReactDOMClient && ReactDOMClient.createRoot;
386
- if (!React || !createRoot) continue;
387
389
  const root = createRoot(el);
388
- root.render(React.createElement(CloverViewer, props));
390
+ root.render(React.createElement(Component, props));
391
+ el.__canopyHydrated = true;
389
392
  } catch (_) { /* skip */ }
390
393
  }
391
394
  } catch (_) { /* no-op */ }
395
+ }
396
+
397
+ ready(function() {
398
+ mountAll('[data-canopy-viewer]', CloverViewer);
399
+ mountAll('[data-canopy-scroll]', CloverScroll);
392
400
  });
393
401
  `;
394
402
  const reactShim = `
@@ -59,7 +59,8 @@ async function renderContentMdxToHtml(filePath, outPath, extraProps = {}) {
59
59
  mergedProps.navigation = navData;
60
60
  }
61
61
  const { body, head } = await mdx.compileMdxFile(filePath, outPath, null, mergedProps);
62
- const needsHydrateViewer = body.includes('data-canopy-viewer');
62
+ const needsHydrateViewer =
63
+ body.includes('data-canopy-viewer') || body.includes('data-canopy-scroll');
63
64
  const needsHydrateSlider = body.includes('data-canopy-slider');
64
65
  const needsSearchForm = true; // search form runtime is global
65
66
  const needsFacets = body.includes('data-canopy-related-items');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
package/ui/dist/index.mjs CHANGED
@@ -332,8 +332,45 @@ var Slider = (props) => {
332
332
  return /* @__PURE__ */ React6.createElement(CloverSlider, { ...props });
333
333
  };
334
334
 
335
+ // ui/src/iiif/Scroll.jsx
336
+ import React7, { useEffect as useEffect4, useState as useState4 } from "react";
337
+ var Scroll = (props) => {
338
+ const [CloverScroll, setCloverScroll] = useState4(null);
339
+ useEffect4(() => {
340
+ let mounted = true;
341
+ const canUseDom = typeof window !== "undefined" && typeof document !== "undefined";
342
+ if (canUseDom) {
343
+ import("@samvera/clover-iiif/scroll").then((mod) => {
344
+ if (!mounted) return;
345
+ const Comp = mod && (mod.default || mod.Scroll || mod);
346
+ setCloverScroll(() => Comp);
347
+ }).catch(() => {
348
+ });
349
+ }
350
+ return () => {
351
+ mounted = false;
352
+ };
353
+ }, []);
354
+ if (!CloverScroll) {
355
+ let json = "{}";
356
+ try {
357
+ json = JSON.stringify(props || {});
358
+ } catch (_) {
359
+ json = "{}";
360
+ }
361
+ return /* @__PURE__ */ React7.createElement("div", { "data-canopy-scroll": "1", className: "not-prose" }, /* @__PURE__ */ React7.createElement(
362
+ "script",
363
+ {
364
+ type: "application/json",
365
+ dangerouslySetInnerHTML: { __html: json }
366
+ }
367
+ ));
368
+ }
369
+ return /* @__PURE__ */ React7.createElement(CloverScroll, { ...props });
370
+ };
371
+
335
372
  // ui/src/iiif/MdxRelatedItems.jsx
336
- import React7 from "react";
373
+ import React8 from "react";
337
374
  function MdxRelatedItems(props) {
338
375
  let json = "{}";
339
376
  try {
@@ -341,11 +378,11 @@ function MdxRelatedItems(props) {
341
378
  } catch (_) {
342
379
  json = "{}";
343
380
  }
344
- return /* @__PURE__ */ React7.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React7.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
381
+ return /* @__PURE__ */ React8.createElement("div", { "data-canopy-related-items": "1", className: "not-prose" }, /* @__PURE__ */ React8.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
345
382
  }
346
383
 
347
384
  // ui/src/search/MdxSearchResults.jsx
348
- import React8 from "react";
385
+ import React9 from "react";
349
386
  function MdxSearchResults(props) {
350
387
  let json = "{}";
351
388
  try {
@@ -353,11 +390,11 @@ function MdxSearchResults(props) {
353
390
  } catch (_) {
354
391
  json = "{}";
355
392
  }
356
- return /* @__PURE__ */ React8.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React8.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
393
+ return /* @__PURE__ */ React9.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React9.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
357
394
  }
358
395
 
359
396
  // ui/src/search/SearchSummary.jsx
360
- import React9 from "react";
397
+ import React10 from "react";
361
398
  function SearchSummary(props) {
362
399
  let json = "{}";
363
400
  try {
@@ -365,11 +402,11 @@ function SearchSummary(props) {
365
402
  } catch (_) {
366
403
  json = "{}";
367
404
  }
368
- return /* @__PURE__ */ React9.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React9.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
405
+ return /* @__PURE__ */ React10.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React10.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
369
406
  }
370
407
 
371
408
  // ui/src/search/MdxSearchTabs.jsx
372
- import React10 from "react";
409
+ import React11 from "react";
373
410
  function MdxSearchTabs(props) {
374
411
  let json = "{}";
375
412
  try {
@@ -377,11 +414,11 @@ function MdxSearchTabs(props) {
377
414
  } catch (_) {
378
415
  json = "{}";
379
416
  }
380
- return /* @__PURE__ */ React10.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React10.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
417
+ return /* @__PURE__ */ React11.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React11.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
381
418
  }
382
419
 
383
420
  // ui/src/search/SearchResults.jsx
384
- import React11 from "react";
421
+ import React12 from "react";
385
422
  function SearchResults({
386
423
  results = [],
387
424
  type = "all",
@@ -389,13 +426,13 @@ function SearchResults({
389
426
  query = ""
390
427
  }) {
391
428
  if (!results.length) {
392
- return /* @__PURE__ */ React11.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React11.createElement("em", null, "No results"));
429
+ return /* @__PURE__ */ React12.createElement("div", { className: "text-slate-600" }, /* @__PURE__ */ React12.createElement("em", null, "No results"));
393
430
  }
394
431
  const isAnnotationView = String(type).toLowerCase() === "annotation";
395
432
  if (isAnnotationView) {
396
- return /* @__PURE__ */ React11.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
433
+ return /* @__PURE__ */ React12.createElement("div", { id: "search-results", className: "space-y-4" }, results.map((r, i) => {
397
434
  if (!r || !r.annotation) return null;
398
- return /* @__PURE__ */ React11.createElement(
435
+ return /* @__PURE__ */ React12.createElement(
399
436
  AnnotationCard,
400
437
  {
401
438
  key: r.id || i,
@@ -410,17 +447,17 @@ function SearchResults({
410
447
  }));
411
448
  }
412
449
  if (layout === "list") {
413
- return /* @__PURE__ */ React11.createElement("ul", { id: "search-results", className: "space-y-3" }, results.map((r, i) => {
450
+ return /* @__PURE__ */ React12.createElement("ul", { id: "search-results", className: "space-y-3" }, results.map((r, i) => {
414
451
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
415
452
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
416
- return /* @__PURE__ */ React11.createElement(
453
+ return /* @__PURE__ */ React12.createElement(
417
454
  "li",
418
455
  {
419
456
  key: i,
420
457
  className: `search-result ${r.type}`,
421
458
  "data-thumbnail-aspect-ratio": aspect
422
459
  },
423
- /* @__PURE__ */ React11.createElement(
460
+ /* @__PURE__ */ React12.createElement(
424
461
  Card,
425
462
  {
426
463
  href: r.href,
@@ -434,17 +471,17 @@ function SearchResults({
434
471
  );
435
472
  }));
436
473
  }
437
- return /* @__PURE__ */ React11.createElement("div", { id: "search-results" }, /* @__PURE__ */ React11.createElement(Grid, null, results.map((r, i) => {
474
+ return /* @__PURE__ */ React12.createElement("div", { id: "search-results" }, /* @__PURE__ */ React12.createElement(Grid, null, results.map((r, i) => {
438
475
  const hasDims = Number.isFinite(Number(r.thumbnailWidth)) && Number(r.thumbnailWidth) > 0 && Number.isFinite(Number(r.thumbnailHeight)) && Number(r.thumbnailHeight) > 0;
439
476
  const aspect = hasDims ? Number(r.thumbnailWidth) / Number(r.thumbnailHeight) : void 0;
440
- return /* @__PURE__ */ React11.createElement(
477
+ return /* @__PURE__ */ React12.createElement(
441
478
  GridItem,
442
479
  {
443
480
  key: i,
444
481
  className: `search-result ${r.type}`,
445
482
  "data-thumbnail-aspect-ratio": aspect
446
483
  },
447
- /* @__PURE__ */ React11.createElement(
484
+ /* @__PURE__ */ React12.createElement(
448
485
  Card,
449
486
  {
450
487
  href: r.href,
@@ -460,7 +497,7 @@ function SearchResults({
460
497
  }
461
498
 
462
499
  // ui/src/search/SearchTabs.jsx
463
- import React12 from "react";
500
+ import React13 from "react";
464
501
  function SearchTabs({
465
502
  type = "all",
466
503
  onTypeChange,
@@ -475,7 +512,7 @@ function SearchTabs({
475
512
  const toLabel = (t) => t && t.length ? t.charAt(0).toUpperCase() + t.slice(1) : "";
476
513
  const hasFilters = typeof onOpenFilters === "function";
477
514
  const filterBadge = activeFilterCount > 0 ? ` (${activeFilterCount})` : "";
478
- return /* @__PURE__ */ React12.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React12.createElement(
515
+ return /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-tabs-wrapper" }, /* @__PURE__ */ React13.createElement(
479
516
  "div",
480
517
  {
481
518
  role: "tablist",
@@ -486,7 +523,7 @@ function SearchTabs({
486
523
  const active = String(type).toLowerCase() === String(t).toLowerCase();
487
524
  const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
488
525
  const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
489
- return /* @__PURE__ */ React12.createElement(
526
+ return /* @__PURE__ */ React13.createElement(
490
527
  "button",
491
528
  {
492
529
  key: t,
@@ -501,7 +538,7 @@ function SearchTabs({
501
538
  ")"
502
539
  );
503
540
  })
504
- ), hasFilters ? /* @__PURE__ */ React12.createElement(
541
+ ), hasFilters ? /* @__PURE__ */ React13.createElement(
505
542
  "button",
506
543
  {
507
544
  type: "button",
@@ -509,12 +546,12 @@ function SearchTabs({
509
546
  "aria-expanded": filtersOpen ? "true" : "false",
510
547
  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"
511
548
  },
512
- /* @__PURE__ */ React12.createElement("span", null, filtersLabel, filterBadge)
549
+ /* @__PURE__ */ React13.createElement("span", null, filtersLabel, filterBadge)
513
550
  ) : null);
514
551
  }
515
552
 
516
553
  // ui/src/search/SearchFiltersDialog.jsx
517
- import React13 from "react";
554
+ import React14 from "react";
518
555
  function toArray(input) {
519
556
  if (!input) return [];
520
557
  if (Array.isArray(input)) return input;
@@ -553,20 +590,20 @@ function FacetSection({ facet, selected, onToggle }) {
553
590
  const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
554
591
  const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
555
592
  const hasSelection = selectedValues.size > 0;
556
- const [quickQuery, setQuickQuery] = React13.useState("");
593
+ const [quickQuery, setQuickQuery] = React14.useState("");
557
594
  const hasQuery = quickQuery.trim().length > 0;
558
- const filteredValues = React13.useMemo(
595
+ const filteredValues = React14.useMemo(
559
596
  () => facetMatches(values, quickQuery),
560
597
  [values, quickQuery]
561
598
  );
562
- return /* @__PURE__ */ React13.createElement(
599
+ return /* @__PURE__ */ React14.createElement(
563
600
  "details",
564
601
  {
565
602
  className: "canopy-search-filters__facet",
566
603
  open: hasSelection
567
604
  },
568
- /* @__PURE__ */ React13.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React13.createElement("span", null, label), /* @__PURE__ */ React13.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
569
- /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React13.createElement(
605
+ /* @__PURE__ */ React14.createElement("summary", { className: "canopy-search-filters__facet-summary" }, /* @__PURE__ */ React14.createElement("span", null, label), /* @__PURE__ */ React14.createElement("span", { className: "canopy-search-filters__facet-count" }, values.length)),
606
+ /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters__facet-content" }, /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters__quick" }, /* @__PURE__ */ React14.createElement(
570
607
  "input",
571
608
  {
572
609
  type: "search",
@@ -576,7 +613,7 @@ function FacetSection({ facet, selected, onToggle }) {
576
613
  className: "canopy-search-filters__quick-input",
577
614
  "aria-label": `Filter ${label} values`
578
615
  }
579
- ), quickQuery ? /* @__PURE__ */ React13.createElement(
616
+ ), quickQuery ? /* @__PURE__ */ React14.createElement(
580
617
  "button",
581
618
  {
582
619
  type: "button",
@@ -584,11 +621,11 @@ function FacetSection({ facet, selected, onToggle }) {
584
621
  className: "canopy-search-filters__quick-clear"
585
622
  },
586
623
  "Clear"
587
- ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React13.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React13.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
624
+ ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React14.createElement("p", { className: "canopy-search-filters__facet-notice" }, "No matches found.") : null, /* @__PURE__ */ React14.createElement("ul", { className: "canopy-search-filters__facet-list" }, filteredValues.map((entry) => {
588
625
  const valueSlug = String(entry.slug || entry.value || "");
589
626
  const isChecked = selectedValues.has(valueSlug);
590
627
  const inputId = checkboxId(valueSlug);
591
- return /* @__PURE__ */ React13.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React13.createElement(
628
+ return /* @__PURE__ */ React14.createElement("li", { key: valueSlug, className: "canopy-search-filters__facet-item" }, /* @__PURE__ */ React14.createElement(
592
629
  "input",
593
630
  {
594
631
  id: inputId,
@@ -600,15 +637,15 @@ function FacetSection({ facet, selected, onToggle }) {
600
637
  if (onToggle) onToggle(slug, valueSlug, nextChecked);
601
638
  }
602
639
  }
603
- ), /* @__PURE__ */ React13.createElement(
640
+ ), /* @__PURE__ */ React14.createElement(
604
641
  "label",
605
642
  {
606
643
  htmlFor: inputId,
607
644
  className: "canopy-search-filters__facet-label"
608
645
  },
609
- /* @__PURE__ */ React13.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React13.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
646
+ /* @__PURE__ */ React14.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React14.createElement("span", { className: "canopy-search-filters__facet-count" }, "(", entry.doc_count, ")") : null)
610
647
  ));
611
- }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React13.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
648
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React14.createElement("li", { className: "canopy-search-filters__facet-empty" }, "No values available.") : null))
612
649
  );
613
650
  }
614
651
  function SearchFiltersDialog(props = {}) {
@@ -628,7 +665,7 @@ function SearchFiltersDialog(props = {}) {
628
665
  0
629
666
  );
630
667
  if (!open) return null;
631
- return /* @__PURE__ */ React13.createElement(
668
+ return /* @__PURE__ */ React14.createElement(
632
669
  "div",
633
670
  {
634
671
  role: "dialog",
@@ -639,7 +676,7 @@ function SearchFiltersDialog(props = {}) {
639
676
  onOpenChange(false);
640
677
  }
641
678
  },
642
- /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters" }, /* @__PURE__ */ React13.createElement("header", { className: "canopy-search-filters__header" }, /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("h2", { className: "canopy-search-filters__title" }, title), /* @__PURE__ */ React13.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitle)), /* @__PURE__ */ React13.createElement(
679
+ /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters" }, /* @__PURE__ */ React14.createElement("header", { className: "canopy-search-filters__header" }, /* @__PURE__ */ React14.createElement("div", null, /* @__PURE__ */ React14.createElement("h2", { className: "canopy-search-filters__title" }, title), /* @__PURE__ */ React14.createElement("p", { className: "canopy-search-filters__subtitle" }, subtitle)), /* @__PURE__ */ React14.createElement(
643
680
  "button",
644
681
  {
645
682
  type: "button",
@@ -647,7 +684,7 @@ function SearchFiltersDialog(props = {}) {
647
684
  className: "canopy-search-filters__close"
648
685
  },
649
686
  "Close"
650
- )), /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters__body" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters__facets" }, facets.map((facet) => /* @__PURE__ */ React13.createElement(
687
+ )), /* @__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(
651
688
  FacetSection,
652
689
  {
653
690
  key: facet.slug || facet.label,
@@ -655,7 +692,7 @@ function SearchFiltersDialog(props = {}) {
655
692
  selected: selectedMap,
656
693
  onToggle
657
694
  }
658
- ))) : /* @__PURE__ */ React13.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")), /* @__PURE__ */ React13.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React13.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React13.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React13.createElement(
695
+ ))) : /* @__PURE__ */ React14.createElement("p", { className: "canopy-search-filters__empty" }, "No filters are available for this collection.")), /* @__PURE__ */ React14.createElement("footer", { className: "canopy-search-filters__footer" }, /* @__PURE__ */ React14.createElement("div", null, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React14.createElement("div", { className: "canopy-search-filters__footer-actions" }, /* @__PURE__ */ React14.createElement(
659
696
  "button",
660
697
  {
661
698
  type: "button",
@@ -666,7 +703,7 @@ function SearchFiltersDialog(props = {}) {
666
703
  className: "canopy-search-filters__button canopy-search-filters__button--secondary"
667
704
  },
668
705
  "Clear all"
669
- ), /* @__PURE__ */ React13.createElement(
706
+ ), /* @__PURE__ */ React14.createElement(
670
707
  "button",
671
708
  {
672
709
  type: "button",
@@ -679,14 +716,14 @@ function SearchFiltersDialog(props = {}) {
679
716
  }
680
717
 
681
718
  // ui/src/search-form/MdxSearchFormModal.jsx
682
- import React17 from "react";
719
+ import React18 from "react";
683
720
 
684
721
  // ui/src/Icons.jsx
685
- import React14 from "react";
686
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React14.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
722
+ import React15 from "react";
723
+ 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" }));
687
724
 
688
725
  // ui/src/search/SearchPanelForm.jsx
689
- import React15 from "react";
726
+ import React16 from "react";
690
727
  function readBasePath() {
691
728
  const normalize = (val) => {
692
729
  const raw = typeof val === "string" ? val.trim() : "";
@@ -749,18 +786,18 @@ function SearchPanelForm(props = {}) {
749
786
  clearLabel = "Clear search"
750
787
  } = props || {};
751
788
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
752
- const action = React15.useMemo(
789
+ const action = React16.useMemo(
753
790
  () => resolveSearchPath(searchPath),
754
791
  [searchPath]
755
792
  );
756
- const autoId = typeof React15.useId === "function" ? React15.useId() : void 0;
757
- const [fallbackId] = React15.useState(
793
+ const autoId = typeof React16.useId === "function" ? React16.useId() : void 0;
794
+ const [fallbackId] = React16.useState(
758
795
  () => `canopy-search-form-${Math.random().toString(36).slice(2, 10)}`
759
796
  );
760
797
  const inputId = inputIdProp || autoId || fallbackId;
761
- const inputRef = React15.useRef(null);
762
- const [hasValue, setHasValue] = React15.useState(false);
763
- const focusInput = React15.useCallback(() => {
798
+ const inputRef = React16.useRef(null);
799
+ const [hasValue, setHasValue] = React16.useState(false);
800
+ const focusInput = React16.useCallback(() => {
764
801
  const el = inputRef.current;
765
802
  if (!el) return;
766
803
  if (document.activeElement === el) return;
@@ -773,7 +810,7 @@ function SearchPanelForm(props = {}) {
773
810
  }
774
811
  }
775
812
  }, []);
776
- const handlePointerDown = React15.useCallback(
813
+ const handlePointerDown = React16.useCallback(
777
814
  (event) => {
778
815
  const target = event.target;
779
816
  if (target && typeof target.closest === "function") {
@@ -785,23 +822,23 @@ function SearchPanelForm(props = {}) {
785
822
  },
786
823
  [focusInput]
787
824
  );
788
- React15.useEffect(() => {
825
+ React16.useEffect(() => {
789
826
  const el = inputRef.current;
790
827
  if (!el) return;
791
828
  if (el.value && el.value.trim()) {
792
829
  setHasValue(true);
793
830
  }
794
831
  }, []);
795
- const handleInputChange = React15.useCallback((event) => {
832
+ const handleInputChange = React16.useCallback((event) => {
796
833
  var _a;
797
834
  const nextHasValue = Boolean(
798
835
  ((_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value) && event.target.value.trim()
799
836
  );
800
837
  setHasValue(nextHasValue);
801
838
  }, []);
802
- const handleClear = React15.useCallback((event) => {
839
+ const handleClear = React16.useCallback((event) => {
803
840
  }, []);
804
- const handleClearKey = React15.useCallback(
841
+ const handleClearKey = React16.useCallback(
805
842
  (event) => {
806
843
  if (event.key === "Enter" || event.key === " ") {
807
844
  event.preventDefault();
@@ -810,7 +847,7 @@ function SearchPanelForm(props = {}) {
810
847
  },
811
848
  [handleClear]
812
849
  );
813
- return /* @__PURE__ */ React15.createElement(
850
+ return /* @__PURE__ */ React16.createElement(
814
851
  "form",
815
852
  {
816
853
  action,
@@ -822,7 +859,7 @@ function SearchPanelForm(props = {}) {
822
859
  onPointerDown: handlePointerDown,
823
860
  "data-has-value": hasValue ? "1" : "0"
824
861
  },
825
- /* @__PURE__ */ React15.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React15.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React15.createElement(
862
+ /* @__PURE__ */ React16.createElement("label", { htmlFor: inputId, className: "canopy-search-form__label" }, /* @__PURE__ */ React16.createElement(MagnifyingGlassIcon, { className: "canopy-search-form__icon" }), /* @__PURE__ */ React16.createElement(
826
863
  "input",
827
864
  {
828
865
  id: inputId,
@@ -838,7 +875,7 @@ function SearchPanelForm(props = {}) {
838
875
  onInput: handleInputChange
839
876
  }
840
877
  )),
841
- hasValue ? /* @__PURE__ */ React15.createElement(
878
+ hasValue ? /* @__PURE__ */ React16.createElement(
842
879
  "button",
843
880
  {
844
881
  type: "button",
@@ -851,32 +888,32 @@ function SearchPanelForm(props = {}) {
851
888
  },
852
889
  "\xD7"
853
890
  ) : null,
854
- /* @__PURE__ */ React15.createElement(
891
+ /* @__PURE__ */ React16.createElement(
855
892
  "button",
856
893
  {
857
894
  type: "submit",
858
895
  "data-canopy-search-form-trigger": "submit",
859
896
  className: "canopy-search-form__submit"
860
897
  },
861
- /* @__PURE__ */ React15.createElement("span", null, text),
862
- /* @__PURE__ */ React15.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React15.createElement("span", null, "\u2318"), /* @__PURE__ */ React15.createElement("span", null, "K"))
898
+ /* @__PURE__ */ React16.createElement("span", null, text),
899
+ /* @__PURE__ */ React16.createElement("span", { "aria-hidden": true, className: "canopy-search-form__shortcut" }, /* @__PURE__ */ React16.createElement("span", null, "\u2318"), /* @__PURE__ */ React16.createElement("span", null, "K"))
863
900
  )
864
901
  );
865
902
  }
866
903
 
867
904
  // ui/src/search/SearchPanelTeaserResults.jsx
868
- import React16 from "react";
905
+ import React17 from "react";
869
906
  function SearchPanelTeaserResults(props = {}) {
870
907
  const { style, className } = props || {};
871
908
  const classes = ["canopy-search-teaser", className].filter(Boolean).join(" ");
872
- return /* @__PURE__ */ React16.createElement(
909
+ return /* @__PURE__ */ React17.createElement(
873
910
  "div",
874
911
  {
875
912
  "data-canopy-search-form-panel": true,
876
913
  className: classes || void 0,
877
914
  style
878
915
  },
879
- /* @__PURE__ */ React16.createElement("div", { id: "cplist" })
916
+ /* @__PURE__ */ React17.createElement("div", { id: "cplist" })
880
917
  );
881
918
  }
882
919
 
@@ -896,11 +933,11 @@ function MdxSearchFormModal(props = {}) {
896
933
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
897
934
  const resolvedSearchPath = resolveSearchPath(searchPath);
898
935
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
899
- return /* @__PURE__ */ React17.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React17.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React17.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React17.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React17.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
936
+ return /* @__PURE__ */ React18.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React18.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React18.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React18.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React18.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
900
937
  }
901
938
 
902
939
  // ui/src/search/SearchPanel.jsx
903
- import React18 from "react";
940
+ import React19 from "react";
904
941
  function SearchPanel(props = {}) {
905
942
  const {
906
943
  placeholder = "Search\u2026",
@@ -917,7 +954,7 @@ function SearchPanel(props = {}) {
917
954
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
918
955
  const resolvedSearchPath = resolveSearchPath(searchPath);
919
956
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
920
- return /* @__PURE__ */ React18.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React18.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React18.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React18.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React18.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
957
+ 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) } }));
921
958
  }
922
959
  export {
923
960
  AnnotationCard,
@@ -926,6 +963,7 @@ export {
926
963
  GridItem,
927
964
  HelloWorld,
928
965
  MdxRelatedItems as RelatedItems,
966
+ Scroll,
929
967
  SearchFiltersDialog,
930
968
  MdxSearchFormModal as SearchFormModal,
931
969
  SearchPanel,