@canopy-iiif/app 0.7.16 → 0.7.18

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.
@@ -150,7 +150,6 @@ async function buildSearchPage() {
150
150
  head = rendered && rendered.head ? rendered.head : '';
151
151
  if (!body) throw new Error('Search: content/search/_layout.mdx produced empty output');
152
152
  const importMap = '';
153
- const cssRel = path.relative(path.dirname(outPath), path.join(OUT_DIR, 'styles', 'styles.css')).split(path.sep).join('/');
154
153
  const jsAbs = path.join(OUT_DIR, 'scripts', 'search.js');
155
154
  let jsRel = path.relative(path.dirname(outPath), jsAbs).split(path.sep).join('/');
156
155
  let v = '';
@@ -166,7 +165,14 @@ async function buildSearchPage() {
166
165
  return rel;
167
166
  }
168
167
  const vendorTags = `<script src="${verRel(vendorReactAbs)}"></script><script src="${verRel(vendorFlexAbs)}"></script><script src="${verRel(vendorCommandAbs)}"></script>`;
169
- let html = htmlShell({ title: 'Search', body, cssHref: cssRel || 'styles.css', scriptHref: jsRel, headExtra: vendorTags + head + importMap });
168
+ let headExtra = vendorTags + head + importMap;
169
+ try {
170
+ const { BASE_PATH } = require('../common');
171
+ if (BASE_PATH) {
172
+ headExtra = `<script>window.CANOPY_BASE_PATH=${JSON.stringify(BASE_PATH)}</script>` + headExtra;
173
+ }
174
+ } catch (_) {}
175
+ let html = htmlShell({ title: 'Search', body, cssHref: null, scriptHref: jsRel, headExtra });
170
176
  try { html = require('./common').applyBaseToHtml(html); } catch (_) {}
171
177
  await fsp.writeFile(outPath, html, 'utf8');
172
178
  console.log('Search: Built', path.relative(process.cwd(), outPath));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.7.16",
3
+ "version": "0.7.18",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
@@ -14,14 +14,21 @@
14
14
  "./ui/styles/index.css": "./ui/styles/index.css",
15
15
  "./ui/canopy-iiif-plugin": "./ui/tailwind-canopy-iiif-plugin.js",
16
16
  "./ui/canopy-iiif-preset": "./ui/tailwind-canopy-iiif-preset.js",
17
- "./lib/components/*": "./lib/components/*"
17
+ "./lib/components/*": "./lib/components/*",
18
+ "./head": "./lib/head.js",
19
+ "./orchestrator": {
20
+ "types": "./types/orchestrator.d.ts",
21
+ "require": "./lib/orchestrator.js",
22
+ "default": "./lib/orchestrator.js"
23
+ }
18
24
  },
19
25
  "files": [
20
26
  "lib/**",
21
27
  "ui/dist/**",
22
28
  "ui/styles/**",
23
29
  "ui/tailwind-canopy-iiif-plugin.js",
24
- "ui/tailwind-canopy-iiif-preset.js"
30
+ "ui/tailwind-canopy-iiif-preset.js",
31
+ "types/**"
25
32
  ],
26
33
  "publishConfig": {
27
34
  "access": "public"
@@ -0,0 +1,18 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+
3
+ export type Mode = 'build' | 'dev';
4
+
5
+ export interface LibraryApi {
6
+ build?: () => Promise<void> | void;
7
+ dev?: () => Promise<void> | void;
8
+ }
9
+
10
+ export type NullableChildProcess = ChildProcess | null;
11
+
12
+ export interface OrchestratorOptions {
13
+ argv?: string[];
14
+ env?: NodeJS.ProcessEnv;
15
+ }
16
+
17
+ export declare function orchestrate(options?: OrchestratorOptions): Promise<void>;
18
+ export declare function verifyBuildOutput(outDir?: string): void;
package/ui/dist/index.mjs CHANGED
@@ -377,40 +377,233 @@ function SearchResults({
377
377
 
378
378
  // ui/src/search/SearchTabs.jsx
379
379
  import React11 from "react";
380
- function SearchTabs({ type = "all", onTypeChange, types = [], counts = {} }) {
380
+ function SearchTabs({
381
+ type = "all",
382
+ onTypeChange,
383
+ types = [],
384
+ counts = {},
385
+ onOpenFilters,
386
+ activeFilterCount = 0,
387
+ filtersLabel = "Filters",
388
+ filtersOpen = false
389
+ }) {
381
390
  const orderedTypes = Array.isArray(types) ? types : [];
382
391
  const toLabel = (t) => t && t.length ? t.charAt(0).toUpperCase() + t.slice(1) : "";
383
- return /* @__PURE__ */ React11.createElement("div", { role: "tablist", "aria-label": "Search types", className: "flex items-center gap-2 border-b border-slate-200" }, orderedTypes.map((t) => {
384
- const active = String(type).toLowerCase() === String(t).toLowerCase();
385
- const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
386
- const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
387
- return /* @__PURE__ */ React11.createElement(
392
+ const hasFilters = typeof onOpenFilters === "function";
393
+ const filterBadge = activeFilterCount > 0 ? ` (${activeFilterCount})` : "";
394
+ return /* @__PURE__ */ React11.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 pb-1" }, /* @__PURE__ */ React11.createElement(
395
+ "div",
396
+ {
397
+ role: "tablist",
398
+ "aria-label": "Search types",
399
+ className: "flex items-center gap-2"
400
+ },
401
+ orderedTypes.map((t) => {
402
+ const active = String(type).toLowerCase() === String(t).toLowerCase();
403
+ const cRaw = counts && Object.prototype.hasOwnProperty.call(counts, t) ? counts[t] : void 0;
404
+ const c = Number.isFinite(Number(cRaw)) ? Number(cRaw) : 0;
405
+ return /* @__PURE__ */ React11.createElement(
406
+ "button",
407
+ {
408
+ key: t,
409
+ role: "tab",
410
+ "aria-selected": active,
411
+ type: "button",
412
+ onClick: () => onTypeChange && onTypeChange(t),
413
+ className: "px-3 py-2 text-sm rounded-t-md border-b-2 -mb-px transition-colors " + (active ? "border-brand-600 text-brand-700" : "border-transparent text-slate-600 hover:text-slate-900 hover:border-slate-300")
414
+ },
415
+ toLabel(t),
416
+ " (",
417
+ c,
418
+ ")"
419
+ );
420
+ })
421
+ ), hasFilters ? /* @__PURE__ */ React11.createElement(
422
+ "button",
423
+ {
424
+ type: "button",
425
+ onClick: () => onOpenFilters && onOpenFilters(),
426
+ "aria-expanded": filtersOpen ? "true" : "false",
427
+ 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"
428
+ },
429
+ /* @__PURE__ */ React11.createElement("span", null, filtersLabel, filterBadge)
430
+ ) : null);
431
+ }
432
+
433
+ // ui/src/search/SearchFiltersDialog.jsx
434
+ import React12 from "react";
435
+ function toArray(input) {
436
+ if (!input) return [];
437
+ if (Array.isArray(input)) return input;
438
+ return [input];
439
+ }
440
+ function normalizeSelected(selected = {}) {
441
+ const map = /* @__PURE__ */ new Map();
442
+ if (selected && typeof selected === "object") {
443
+ Object.keys(selected).forEach((key) => {
444
+ const vals = new Set(toArray(selected[key]).map((v) => String(v)));
445
+ if (vals.size) map.set(String(key), vals);
446
+ });
447
+ }
448
+ return map;
449
+ }
450
+ function facetMatches(values = [], query) {
451
+ const q = String(query || "").trim().toLowerCase();
452
+ if (!q) return values;
453
+ const starts = [];
454
+ const contains = [];
455
+ values.forEach((entry) => {
456
+ if (!entry || !entry.value) return;
457
+ const value = String(entry.value);
458
+ const slug = String(entry.slug || entry.value || "");
459
+ const match = value.toLowerCase();
460
+ if (match.startsWith(q))
461
+ starts.push({ value, slug, doc_count: entry.doc_count });
462
+ else if (match.includes(q))
463
+ contains.push({ value, slug, doc_count: entry.doc_count });
464
+ });
465
+ return [...starts, ...contains].slice(0, 10);
466
+ }
467
+ function FacetSection({ facet, selected, onToggle }) {
468
+ if (!facet || !facet.label || !Array.isArray(facet.values)) return null;
469
+ const { label, slug, values } = facet;
470
+ const selectedValues = selected.get(String(slug)) || /* @__PURE__ */ new Set();
471
+ const checkboxId = (valueSlug) => `filter-${slug}-${valueSlug}`;
472
+ const hasSelection = selectedValues.size > 0;
473
+ const [quickQuery, setQuickQuery] = React12.useState("");
474
+ const hasQuery = quickQuery.trim().length > 0;
475
+ const filteredValues = React12.useMemo(
476
+ () => facetMatches(values, quickQuery),
477
+ [values, quickQuery]
478
+ );
479
+ return /* @__PURE__ */ React12.createElement(
480
+ "details",
481
+ {
482
+ className: "rounded-lg border border-slate-200 bg-slate-50",
483
+ open: hasSelection
484
+ },
485
+ /* @__PURE__ */ React12.createElement("summary", { className: "flex cursor-pointer items-center justify-between gap-3 px-4 py-3 text-sm font-medium text-slate-900" }, /* @__PURE__ */ React12.createElement("span", null, label), /* @__PURE__ */ React12.createElement("span", { className: "text-xs font-normal text-slate-500" }, values.length)),
486
+ /* @__PURE__ */ React12.createElement("div", { className: "max-h-60 overflow-y-auto border-t border-slate-200 bg-white px-4 py-3 text-sm text-slate-700" }, /* @__PURE__ */ React12.createElement("div", { className: "mb-3 flex items-center gap-2" }, /* @__PURE__ */ React12.createElement(
487
+ "input",
488
+ {
489
+ type: "search",
490
+ value: quickQuery,
491
+ onChange: (event) => setQuickQuery(event.target.value),
492
+ placeholder: "Search values",
493
+ className: "flex-1 rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand",
494
+ "aria-label": `Filter ${label} values`
495
+ }
496
+ ), quickQuery ? /* @__PURE__ */ React12.createElement(
388
497
  "button",
389
498
  {
390
- key: t,
391
- role: "tab",
392
- "aria-selected": active,
393
499
  type: "button",
394
- onClick: () => onTypeChange && onTypeChange(t),
395
- className: "px-3 py-1.5 text-sm rounded-t-md border-b-2 -mb-px transition-colors " + (active ? "border-brand-600 text-brand-700" : "border-transparent text-slate-600 hover:text-slate-900 hover:border-slate-300")
500
+ onClick: () => setQuickQuery(""),
501
+ className: "rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 transition hover:bg-slate-100"
396
502
  },
397
- toLabel(t),
398
- " (",
399
- c,
400
- ")"
401
- );
402
- }));
503
+ "Clear"
504
+ ) : null), hasQuery && !filteredValues.length ? /* @__PURE__ */ React12.createElement("p", { className: "mb-3 text-xs text-slate-400" }, "No matches found.") : null, /* @__PURE__ */ React12.createElement("ul", { className: "space-y-2", style: { padding: 0 } }, filteredValues.map((entry) => {
505
+ const valueSlug = String(entry.slug || entry.value || "");
506
+ const isChecked = selectedValues.has(valueSlug);
507
+ const inputId = checkboxId(valueSlug);
508
+ return /* @__PURE__ */ React12.createElement("li", { key: valueSlug, className: "flex items-start gap-2" }, /* @__PURE__ */ React12.createElement(
509
+ "input",
510
+ {
511
+ id: inputId,
512
+ type: "checkbox",
513
+ className: "mt-1 h-4 w-4 rounded border-slate-300 text-brand focus:ring-brand",
514
+ checked: isChecked,
515
+ onChange: (event) => {
516
+ const nextChecked = !!event.target.checked;
517
+ if (onToggle) onToggle(slug, valueSlug, nextChecked);
518
+ }
519
+ }
520
+ ), /* @__PURE__ */ React12.createElement(
521
+ "label",
522
+ {
523
+ htmlFor: inputId,
524
+ className: "flex flex-1 flex-col gap-0.5"
525
+ },
526
+ /* @__PURE__ */ React12.createElement("span", null, entry.value, " ", Number.isFinite(entry.doc_count) ? /* @__PURE__ */ React12.createElement("span", { className: "text-xs text-slate-500" }, "(", entry.doc_count, ")") : null)
527
+ ));
528
+ }), !filteredValues.length && !hasQuery ? /* @__PURE__ */ React12.createElement("li", { className: "text-xs text-slate-400" }, "No values available.") : null))
529
+ );
530
+ }
531
+ function SearchFiltersDialog(props = {}) {
532
+ const {
533
+ open = false,
534
+ onOpenChange,
535
+ facets = [],
536
+ selected = {},
537
+ onToggle,
538
+ onClear,
539
+ title = "Filters",
540
+ subtitle = "Refine results by metadata"
541
+ } = props;
542
+ const selectedMap = normalizeSelected(selected);
543
+ const activeCount = Array.from(selectedMap.values()).reduce(
544
+ (total, set) => total + set.size,
545
+ 0
546
+ );
547
+ if (!open) return null;
548
+ return /* @__PURE__ */ React12.createElement(
549
+ "div",
550
+ {
551
+ role: "dialog",
552
+ "aria-modal": "true",
553
+ className: "fixed inset-0 z-50 flex items-start justify-center bg-slate-900/50 px-4 py-8",
554
+ onClick: (event) => {
555
+ if (event.target === event.currentTarget && onOpenChange)
556
+ onOpenChange(false);
557
+ }
558
+ },
559
+ /* @__PURE__ */ React12.createElement("div", { className: "w-full max-w-3xl overflow-hidden rounded-xl bg-white shadow-2xl" }, /* @__PURE__ */ React12.createElement("header", { className: "flex items-start justify-between gap-4 border-b border-slate-200 px-6 py-4" }, /* @__PURE__ */ React12.createElement("div", null, /* @__PURE__ */ React12.createElement("h2", { className: "text-lg font-semibold text-slate-900" }, title), /* @__PURE__ */ React12.createElement("p", { className: "text-sm text-slate-500" }, subtitle)), /* @__PURE__ */ React12.createElement(
560
+ "button",
561
+ {
562
+ type: "button",
563
+ onClick: () => onOpenChange && onOpenChange(false),
564
+ className: "rounded-md border border-transparent px-2 py-1 text-sm text-slate-600 transition hover:bg-slate-100 hover:text-slate-900"
565
+ },
566
+ "Close"
567
+ )), /* @__PURE__ */ React12.createElement("div", { className: "grid gap-4 px-6 py-6" }, Array.isArray(facets) && facets.length ? /* @__PURE__ */ React12.createElement("div", { className: "space-y-3" }, facets.map((facet) => /* @__PURE__ */ React12.createElement(
568
+ FacetSection,
569
+ {
570
+ key: facet.slug || facet.label,
571
+ facet,
572
+ selected: selectedMap,
573
+ onToggle
574
+ }
575
+ ))) : /* @__PURE__ */ React12.createElement("p", { className: "text-sm text-slate-500" }, "No filters are available for this collection.")), /* @__PURE__ */ React12.createElement("footer", { className: "flex items-center justify-between gap-4 border-t border-slate-200 px-6 py-4" }, /* @__PURE__ */ React12.createElement("div", { className: "text-sm text-slate-500" }, activeCount ? `${activeCount} filter${activeCount === 1 ? "" : "s"} applied` : "No filters applied"), /* @__PURE__ */ React12.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React12.createElement(
576
+ "button",
577
+ {
578
+ type: "button",
579
+ onClick: () => {
580
+ if (onClear) onClear();
581
+ },
582
+ disabled: !activeCount,
583
+ className: "rounded-md border border-slate-200 px-3 py-1.5 text-sm text-slate-600 transition disabled:cursor-not-allowed disabled:text-slate-400 hover:bg-slate-100"
584
+ },
585
+ "Clear all"
586
+ ), /* @__PURE__ */ React12.createElement(
587
+ "button",
588
+ {
589
+ type: "button",
590
+ onClick: () => onOpenChange && onOpenChange(false),
591
+ className: "rounded-md bg-brand px-4 py-1.5 text-sm font-semibold text-white shadow-sm transition hover:bg-brand-700"
592
+ },
593
+ "Done"
594
+ ))))
595
+ );
403
596
  }
404
597
 
405
598
  // ui/src/command/MdxCommandPalette.jsx
406
- import React15 from "react";
599
+ import React16 from "react";
407
600
 
408
601
  // ui/src/Icons.jsx
409
- import React12 from "react";
410
- var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React12.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React12.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" }));
602
+ import React13 from "react";
603
+ var MagnifyingGlassIcon = (props) => /* @__PURE__ */ React13.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", ...props }, /* @__PURE__ */ React13.createElement("path", { d: "M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z" }));
411
604
 
412
605
  // ui/src/search/SearchPanelForm.jsx
413
- import React13 from "react";
606
+ import React14 from "react";
414
607
  function readBasePath() {
415
608
  const normalize = (val) => {
416
609
  const raw = typeof val === "string" ? val.trim() : "";
@@ -468,14 +661,42 @@ function SearchPanelForm(props = {}) {
468
661
  placeholder = "Search\u2026",
469
662
  buttonLabel = "Search",
470
663
  label,
471
- searchPath = "/search"
664
+ searchPath = "/search",
665
+ inputId: inputIdProp
472
666
  } = props || {};
473
667
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
474
- const action = React13.useMemo(
668
+ const action = React14.useMemo(
475
669
  () => resolveSearchPath(searchPath),
476
670
  [searchPath]
477
671
  );
478
- return /* @__PURE__ */ React13.createElement(
672
+ const autoId = typeof React14.useId === "function" ? React14.useId() : void 0;
673
+ const [fallbackId] = React14.useState(
674
+ () => `canopy-cmdk-${Math.random().toString(36).slice(2, 10)}`
675
+ );
676
+ const inputId = inputIdProp || autoId || fallbackId;
677
+ const inputRef = React14.useRef(null);
678
+ const focusInput = React14.useCallback(() => {
679
+ const el = inputRef.current;
680
+ if (!el) return;
681
+ if (document.activeElement === el) return;
682
+ try {
683
+ el.focus({ preventScroll: true });
684
+ } catch (_) {
685
+ try {
686
+ el.focus();
687
+ } catch (_2) {
688
+ }
689
+ }
690
+ }, []);
691
+ const handlePointerDown = React14.useCallback((event) => {
692
+ const target = event.target;
693
+ if (target && typeof target.closest === "function") {
694
+ if (target.closest("[data-canopy-command-trigger]")) return;
695
+ }
696
+ event.preventDefault();
697
+ focusInput();
698
+ }, [focusInput]);
699
+ return /* @__PURE__ */ React14.createElement(
479
700
  "form",
480
701
  {
481
702
  action,
@@ -483,36 +704,47 @@ function SearchPanelForm(props = {}) {
483
704
  role: "search",
484
705
  autoComplete: "off",
485
706
  spellCheck: "false",
486
- className: "group flex items-center gap-2 px-2 py-1.5 rounded-lg border border-slate-300 bg-white/95 backdrop-blur text-slate-700 shadow-sm hover:shadow transition w-full focus-within:ring-2 focus-within:ring-brand-500"
707
+ className: "group flex items-center gap-2 rounded-lg border border-slate-300 text-slate-700 shadow-sm transition focus-within:ring-2 focus-within:ring-brand-500 canopy-cmdk-form",
708
+ onPointerDown: handlePointerDown,
709
+ "data-placeholder": placeholder || ""
487
710
  },
488
- /* @__PURE__ */ React13.createElement(MagnifyingGlassIcon, { className: "w-5 h-5 text-slate-400 group-focus-within:text-brand-500" }),
489
- /* @__PURE__ */ React13.createElement(
490
- "input",
711
+ /* @__PURE__ */ React14.createElement(
712
+ "label",
491
713
  {
492
- type: "search",
493
- name: "q",
494
- inputMode: "search",
495
- "data-canopy-command-input": true,
496
- placeholder,
497
- className: "flex-1 bg-transparent outline-none placeholder:text-slate-400 py-0.5 min-w-0",
498
- "aria-label": "Search"
499
- }
714
+ htmlFor: inputId,
715
+ className: "flex items-center gap-2 flex-1 min-w-0 cursor-text canopy-cmdk-label"
716
+ },
717
+ /* @__PURE__ */ React14.createElement(MagnifyingGlassIcon, { className: "w-5 h-5 text-slate-400 group-focus-within:text-brand-500 pointer-events-none" }),
718
+ /* @__PURE__ */ React14.createElement(
719
+ "input",
720
+ {
721
+ id: inputId,
722
+ type: "search",
723
+ name: "q",
724
+ inputMode: "search",
725
+ "data-canopy-command-input": true,
726
+ placeholder,
727
+ className: "flex-1 bg-transparent outline-none placeholder:text-slate-400 py-1 min-w-0",
728
+ "aria-label": "Search",
729
+ ref: inputRef
730
+ }
731
+ )
500
732
  ),
501
- /* @__PURE__ */ React13.createElement(
733
+ /* @__PURE__ */ React14.createElement(
502
734
  "button",
503
735
  {
504
- type: "button",
505
- "data-canopy-command-trigger": true,
736
+ type: "submit",
737
+ "data-canopy-command-trigger": "submit",
506
738
  className: "inline-flex items-center gap-2 rounded-md border border-transparent bg-brand px-2 py-1 text-sm font-medium text-white shadow-sm transition hover:bg-brand-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2"
507
739
  },
508
- /* @__PURE__ */ React13.createElement("span", null, text),
509
- /* @__PURE__ */ React13.createElement("span", { "aria-hidden": true, className: "hidden sm:inline-flex items-center gap-1 rounded border border-white/40 bg-white/20 px-1.5 py-0.5 text-xs font-semibold" }, /* @__PURE__ */ React13.createElement("span", null, "\u2318"), /* @__PURE__ */ React13.createElement("span", null, "K"))
740
+ /* @__PURE__ */ React14.createElement("span", null, text),
741
+ /* @__PURE__ */ React14.createElement("span", { "aria-hidden": true, className: "hidden sm:inline-flex items-center gap-1 text-xs font-semibold canopy-cmdk-shortcut" }, /* @__PURE__ */ React14.createElement("span", null, "\u2318"), /* @__PURE__ */ React14.createElement("span", null, "K"))
510
742
  )
511
743
  );
512
744
  }
513
745
 
514
746
  // ui/src/search/SearchPanelTeaserResults.jsx
515
- import React14 from "react";
747
+ import React15 from "react";
516
748
  function SearchPanelTeaserResults(props = {}) {
517
749
  const { style } = props || {};
518
750
  const baseStyle = {
@@ -529,7 +761,7 @@ function SearchPanelTeaserResults(props = {}) {
529
761
  overflow: "auto",
530
762
  maxHeight: "60vh"
531
763
  };
532
- return /* @__PURE__ */ React14.createElement("div", { "data-canopy-command-panel": true, style: { ...baseStyle, ...style || {} } }, /* @__PURE__ */ React14.createElement("div", { id: "cplist" }));
764
+ return /* @__PURE__ */ React15.createElement("div", { "data-canopy-command-panel": true, style: { ...baseStyle, ...style || {} } }, /* @__PURE__ */ React15.createElement("div", { id: "cplist" }));
533
765
  }
534
766
 
535
767
  // ui/src/command/MdxCommandPalette.jsx
@@ -548,17 +780,17 @@ function MdxCommandPalette(props = {}) {
548
780
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
549
781
  const resolvedSearchPath = resolveSearchPath(searchPath);
550
782
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
551
- return /* @__PURE__ */ React15.createElement("div", { "data-canopy-command": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React15.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React15.createElement("style", null, `.relative[data-canopy-panel-auto='1']:focus-within [data-canopy-command-panel]{display:block}`), /* @__PURE__ */ React15.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React15.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React15.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
783
+ return /* @__PURE__ */ React16.createElement("div", { "data-canopy-command": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React16.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React16.createElement("style", null, `.relative[data-canopy-panel-auto='1']:focus-within [data-canopy-command-panel]{display:block}`), /* @__PURE__ */ React16.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React16.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
552
784
  }
553
785
 
554
786
  // ui/src/search/SearchPanel.jsx
555
- import React16 from "react";
787
+ import React17 from "react";
556
788
  function SearchPanel(props = {}) {
557
789
  const {
558
790
  placeholder = "Search\u2026",
559
791
  hotkey = "mod+k",
560
792
  maxResults = 8,
561
- groupOrder = ["work", "page"],
793
+ groupOrder = ["work", "docs", "page"],
562
794
  // Kept for backward compat; form always renders submit
563
795
  button = true,
564
796
  // eslint-disable-line no-unused-vars
@@ -569,7 +801,7 @@ function SearchPanel(props = {}) {
569
801
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
570
802
  const resolvedSearchPath = resolveSearchPath(searchPath);
571
803
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
572
- return /* @__PURE__ */ React16.createElement("div", { "data-canopy-command": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React16.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React16.createElement("style", null, `.relative[data-canopy-panel-auto='1']:focus-within [data-canopy-command-panel]{display:block}`), /* @__PURE__ */ React16.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React16.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React16.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
804
+ return /* @__PURE__ */ React17.createElement("div", { "data-canopy-command": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React17.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React17.createElement("style", null, `.relative[data-canopy-panel-auto='1']:focus-within [data-canopy-command-panel]{display:block}`), /* @__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) } }));
573
805
  }
574
806
  export {
575
807
  Card,
@@ -578,6 +810,7 @@ export {
578
810
  GridItem,
579
811
  HelloWorld,
580
812
  MdxRelatedItems as RelatedItems,
813
+ SearchFiltersDialog,
581
814
  SearchPanel,
582
815
  SearchPanelForm,
583
816
  SearchPanelTeaserResults,