@canopy-iiif/app 0.12.4 → 0.12.5

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.
@@ -2062,8 +2062,51 @@ function CanopyFooter({ className = "", children }) {
2062
2062
  return /* @__PURE__ */ React20.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React20.createElement("div", { className: "canopy-footer__inner" }, children));
2063
2063
  }
2064
2064
 
2065
- // ui/src/layout/Container.jsx
2065
+ // ui/src/layout/TeaserCard.jsx
2066
2066
  import React21 from "react";
2067
+ function TeaserCard({
2068
+ href = "",
2069
+ title = "",
2070
+ metadata = [],
2071
+ summary = "",
2072
+ thumbnail = null,
2073
+ type = "work",
2074
+ className = "",
2075
+ ...rest
2076
+ }) {
2077
+ const Tag = href ? "a" : "div";
2078
+ const classes = [
2079
+ "canopy-card",
2080
+ "canopy-card--teaser",
2081
+ "canopy-search-teaser__item",
2082
+ "canopy-teaser-card",
2083
+ className
2084
+ ].filter(Boolean).join(" ");
2085
+ const showThumb = type === "work" && thumbnail;
2086
+ const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
2087
+ return /* @__PURE__ */ React21.createElement(
2088
+ Tag,
2089
+ {
2090
+ className: classes,
2091
+ href: href || void 0,
2092
+ "data-canopy-item": href ? "" : void 0,
2093
+ ...rest
2094
+ },
2095
+ showThumb ? /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React21.createElement(
2096
+ "img",
2097
+ {
2098
+ src: thumbnail,
2099
+ alt: "",
2100
+ loading: "lazy",
2101
+ className: "canopy-search-teaser__thumb-img"
2102
+ }
2103
+ )) : null,
2104
+ /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
2105
+ );
2106
+ }
2107
+
2108
+ // ui/src/layout/Container.jsx
2109
+ import React22 from "react";
2067
2110
  function Container({
2068
2111
  className = "",
2069
2112
  variant = "content",
@@ -2072,7 +2115,7 @@ function Container({
2072
2115
  }) {
2073
2116
  const variantClass = variant === "wide" ? "max-w-wide" : "max-w-content";
2074
2117
  const classes = ["mx-auto", variantClass, "w-full", className].filter(Boolean).join(" ");
2075
- return /* @__PURE__ */ React21.createElement(
2118
+ return /* @__PURE__ */ React22.createElement(
2076
2119
  "div",
2077
2120
  {
2078
2121
  className: classes,
@@ -2084,11 +2127,11 @@ function Container({
2084
2127
  }
2085
2128
 
2086
2129
  // ui/src/content/ReferencedItems.jsx
2087
- import React23 from "react";
2130
+ import React24 from "react";
2088
2131
  import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
2089
2132
 
2090
2133
  // ui/src/layout/Card.jsx
2091
- import React22, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
2134
+ import React23, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
2092
2135
  function Card({
2093
2136
  href,
2094
2137
  src,
@@ -2146,8 +2189,8 @@ function Card({
2146
2189
  const h = Number(imgHeight);
2147
2190
  const ratio = Number.isFinite(Number(aspectRatio)) && Number(aspectRatio) > 0 ? Number(aspectRatio) : Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0 ? w / h : void 0;
2148
2191
  const paddingPercent = ratio ? 100 / ratio : 100;
2149
- const caption = /* @__PURE__ */ React22.createElement("figcaption", null, title && /* @__PURE__ */ React22.createElement("span", null, title), subtitle && /* @__PURE__ */ React22.createElement("span", null, subtitle), children);
2150
- return /* @__PURE__ */ React22.createElement(
2192
+ const caption = /* @__PURE__ */ React23.createElement("figcaption", null, title && /* @__PURE__ */ React23.createElement("span", null, title), subtitle && /* @__PURE__ */ React23.createElement("span", null, subtitle), children);
2193
+ return /* @__PURE__ */ React23.createElement(
2151
2194
  "a",
2152
2195
  {
2153
2196
  href,
@@ -2159,13 +2202,13 @@ function Card({
2159
2202
  "data-image-loaded": imageLoaded ? "true" : "false",
2160
2203
  ...rest
2161
2204
  },
2162
- /* @__PURE__ */ React22.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React22.createElement(
2205
+ /* @__PURE__ */ React23.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React23.createElement(
2163
2206
  "div",
2164
2207
  {
2165
2208
  className: "canopy-card-media",
2166
2209
  style: { "--canopy-card-padding": `${paddingPercent}%` }
2167
2210
  },
2168
- inView ? /* @__PURE__ */ React22.createElement(
2211
+ inView ? /* @__PURE__ */ React23.createElement(
2169
2212
  "img",
2170
2213
  {
2171
2214
  src,
@@ -2175,7 +2218,7 @@ function Card({
2175
2218
  onError: () => setImageLoaded(true)
2176
2219
  }
2177
2220
  ) : null
2178
- ) : /* @__PURE__ */ React22.createElement(
2221
+ ) : /* @__PURE__ */ React23.createElement(
2179
2222
  "img",
2180
2223
  {
2181
2224
  src,
@@ -2194,7 +2237,7 @@ function useReferencedItems(itemsProp) {
2194
2237
  if (Array.isArray(itemsProp)) return itemsProp;
2195
2238
  const PageContext = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
2196
2239
  if (!PageContext) return [];
2197
- const context = React23.useContext(PageContext);
2240
+ const context = React24.useContext(PageContext);
2198
2241
  const items = context && context.page ? context.page.referencedItems : null;
2199
2242
  return Array.isArray(items) ? items : [];
2200
2243
  }
@@ -2214,13 +2257,13 @@ function ReferencedItems({
2214
2257
  "referenced-items--empty",
2215
2258
  className
2216
2259
  ].filter(Boolean).join(" ");
2217
- return /* @__PURE__ */ React23.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
2260
+ return /* @__PURE__ */ React24.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
2218
2261
  }
2219
2262
  const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
2220
- return /* @__PURE__ */ React23.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React23.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
2263
+ return /* @__PURE__ */ React24.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React24.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
2221
2264
  if (!item) return null;
2222
2265
  const key = item.href || item.slug || item.id;
2223
- return /* @__PURE__ */ React23.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React23.createElement(
2266
+ return /* @__PURE__ */ React24.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React24.createElement(
2224
2267
  Card,
2225
2268
  {
2226
2269
  href: item.href,
@@ -2237,7 +2280,7 @@ function ReferencedItems({
2237
2280
  }
2238
2281
 
2239
2282
  // ui/src/content/References.jsx
2240
- import React24 from "react";
2283
+ import React25 from "react";
2241
2284
  import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
2242
2285
  function getPageContext() {
2243
2286
  if (!navigationHelpers5 || typeof navigationHelpers5.getPageContext !== "function") {
@@ -2267,7 +2310,7 @@ function References({
2267
2310
  ...rest
2268
2311
  }) {
2269
2312
  const PageContext = getPageContext();
2270
- const context = PageContext ? React24.useContext(PageContext) : null;
2313
+ const context = PageContext ? React25.useContext(PageContext) : null;
2271
2314
  const contextPage = context && context.page ? context.page : null;
2272
2315
  const manifestId = id || contextPage && contextPage.manifestId || "";
2273
2316
  const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
@@ -2276,11 +2319,777 @@ function References({
2276
2319
  const entries = references && references.length ? references : null;
2277
2320
  if (!entries || !entries.length) return null;
2278
2321
  const containerClass = ["references", className].filter(Boolean).join(" ");
2279
- return /* @__PURE__ */ React24.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React24.createElement("div", { className: "references__group" }, /* @__PURE__ */ React24.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React24.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React24.createElement("a", { href: entry.href }, entry.title || entry.href)))));
2322
+ return /* @__PURE__ */ React25.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React25.createElement("div", { className: "references__group" }, /* @__PURE__ */ React25.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React25.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React25.createElement("a", { href: entry.href }, entry.title || entry.href)))));
2323
+ }
2324
+
2325
+ // ui/src/content/timeline/MdxTimeline.jsx
2326
+ import React27 from "react";
2327
+ import ReactDOMServer from "react-dom/server";
2328
+
2329
+ // ui/src/content/timeline/Timeline.jsx
2330
+ import React26 from "react";
2331
+
2332
+ // ui/src/content/timeline/date-utils.js
2333
+ var FALLBACK_LOCALE = (() => {
2334
+ try {
2335
+ return new Intl.Locale("en-US");
2336
+ } catch (_) {
2337
+ return "en-US";
2338
+ }
2339
+ })();
2340
+ function createLocale(localeValue) {
2341
+ if (!localeValue) return FALLBACK_LOCALE;
2342
+ if (typeof Intl !== "undefined" && localeValue instanceof Intl.Locale)
2343
+ return localeValue;
2344
+ try {
2345
+ return new Intl.Locale(localeValue);
2346
+ } catch (_) {
2347
+ return FALLBACK_LOCALE;
2348
+ }
2349
+ }
2350
+ function parseMonthIndex(name = "", locale = FALLBACK_LOCALE) {
2351
+ const localeId = typeof locale === "string" ? locale : locale && locale.baseName ? locale.baseName : "en-US";
2352
+ const normalized = String(name || "").trim().toLocaleLowerCase(localeId);
2353
+ if (!normalized) return 0;
2354
+ const months = [
2355
+ "january",
2356
+ "february",
2357
+ "march",
2358
+ "april",
2359
+ "may",
2360
+ "june",
2361
+ "july",
2362
+ "august",
2363
+ "september",
2364
+ "october",
2365
+ "november",
2366
+ "december"
2367
+ ];
2368
+ const idx = months.indexOf(normalized);
2369
+ return idx === -1 ? 0 : idx;
2370
+ }
2371
+ function parseStructuredInput(value) {
2372
+ if (!value || typeof value !== "object") return null;
2373
+ const { year, month, day } = value;
2374
+ if (!Number.isFinite(Number(year))) return null;
2375
+ const y = Number(year);
2376
+ const m = Number.isFinite(Number(month)) ? Number(month) - 1 : 0;
2377
+ const d = Number.isFinite(Number(day)) ? Number(day) : 1;
2378
+ return new Date(Date.UTC(y, Math.max(0, Math.min(11, m)), Math.max(1, Math.min(31, d))));
2379
+ }
2380
+ function createDateFromInput(value, { locale } = {}) {
2381
+ const loc = createLocale(locale);
2382
+ if (value instanceof Date) return new Date(value.getTime());
2383
+ if (Number.isFinite(Number(value))) {
2384
+ const year = Number(value);
2385
+ return new Date(Date.UTC(year, 0, 1));
2386
+ }
2387
+ if (value && typeof value === "object") {
2388
+ const structured = parseStructuredInput(value);
2389
+ if (structured) return structured;
2390
+ }
2391
+ const text = typeof value === "string" ? value.trim() : "";
2392
+ if (!text) return null;
2393
+ const isoYear = text.match(/^(\d{4})$/);
2394
+ if (isoYear) {
2395
+ return new Date(Date.UTC(Number(isoYear[1]), 0, 1));
2396
+ }
2397
+ const isoYearMonth = text.match(/^(\d{4})-(\d{2})$/);
2398
+ if (isoYearMonth) {
2399
+ return new Date(
2400
+ Date.UTC(Number(isoYearMonth[1]), Number(isoYearMonth[2]) - 1, 1)
2401
+ );
2402
+ }
2403
+ const isoDate = text.match(/^(\d{4})-(\d{2})-(\d{2})$/);
2404
+ if (isoDate) {
2405
+ return new Date(
2406
+ Date.UTC(
2407
+ Number(isoDate[1]),
2408
+ Number(isoDate[2]) - 1,
2409
+ Number(isoDate[3])
2410
+ )
2411
+ );
2412
+ }
2413
+ const monthDayYear = text.match(/^([A-Za-z]+)\s+(\d{1,2})(?:,)?\s*(\d{4})$/);
2414
+ if (monthDayYear) {
2415
+ const month = parseMonthIndex(monthDayYear[1], loc);
2416
+ const day = Number(monthDayYear[2]);
2417
+ const year = Number(monthDayYear[3]);
2418
+ return new Date(Date.UTC(year, month, day));
2419
+ }
2420
+ const monthYear = text.match(/^([A-Za-z]+)\s+(\d{4})$/);
2421
+ if (monthYear) {
2422
+ const month = parseMonthIndex(monthYear[1], loc);
2423
+ const year = Number(monthYear[2]);
2424
+ return new Date(Date.UTC(year, month, 1));
2425
+ }
2426
+ const fallback = new Date(text);
2427
+ if (!Number.isNaN(fallback.getTime())) return fallback;
2428
+ const alt = new Date(Date.parse(text));
2429
+ if (!Number.isNaN(alt.getTime())) return alt;
2430
+ return null;
2431
+ }
2432
+ function formatDateLabel(date, { granularity = "day", locale } = {}) {
2433
+ if (!(date instanceof Date) || Number.isNaN(date.getTime())) return "";
2434
+ const loc = createLocale(locale);
2435
+ const baseName = typeof loc === "string" ? loc : loc.baseName || "en-US";
2436
+ const options = { year: "numeric" };
2437
+ if (granularity === "month" || granularity === "day") {
2438
+ options.month = "long";
2439
+ }
2440
+ if (granularity === "day") {
2441
+ options.day = "numeric";
2442
+ }
2443
+ options.timeZone = "UTC";
2444
+ try {
2445
+ const formatter = new Intl.DateTimeFormat(baseName, options);
2446
+ return formatter.format(date);
2447
+ } catch (_) {
2448
+ return date.toISOString().slice(0, 10);
2449
+ }
2450
+ }
2451
+ function normalizeRange(range = {}) {
2452
+ const { start, end, granularity = "year", locale } = range || {};
2453
+ const loc = createLocale(locale);
2454
+ const startDate = createDateFromInput(start || /* @__PURE__ */ new Date(), { locale: loc }) || new Date(Date.UTC(0, 0, 1));
2455
+ let endDate = createDateFromInput(end, { locale: loc });
2456
+ if (!endDate) {
2457
+ const copy = new Date(startDate.getTime());
2458
+ copy.setUTCFullYear(copy.getUTCFullYear() + 1);
2459
+ endDate = copy;
2460
+ }
2461
+ if (endDate <= startDate) {
2462
+ const nextDay = new Date(startDate.getTime());
2463
+ nextDay.setUTCDate(nextDay.getUTCDate() + 1);
2464
+ endDate = nextDay;
2465
+ }
2466
+ const span = Math.max(1, endDate - startDate);
2467
+ return {
2468
+ startDate,
2469
+ endDate,
2470
+ span,
2471
+ granularity: granularity === "month" || granularity === "day" ? granularity : "year",
2472
+ locale: loc
2473
+ };
2474
+ }
2475
+ function buildPointMetadata({ value, granularity, locale }) {
2476
+ const date = createDateFromInput(value, { locale });
2477
+ return {
2478
+ date,
2479
+ label: formatDateLabel(date, { granularity, locale }),
2480
+ timestamp: date ? date.getTime() : null
2481
+ };
2482
+ }
2483
+ function clampProgress(value) {
2484
+ if (!Number.isFinite(value)) return 0;
2485
+ if (value < 0) return 0;
2486
+ if (value > 1) return 1;
2487
+ return value;
2488
+ }
2489
+
2490
+ // ui/src/content/timeline/Timeline.jsx
2491
+ var DAY_MS = 24 * 60 * 60 * 1e3;
2492
+ function getThresholdMs(threshold, granularity) {
2493
+ const value = Number(threshold);
2494
+ if (!Number.isFinite(value) || value <= 0) return 0;
2495
+ if (granularity === "day") return value * DAY_MS;
2496
+ if (granularity === "month") return value * 30 * DAY_MS;
2497
+ return value * 365 * DAY_MS;
2498
+ }
2499
+ function buildGroupedEntries(points, thresholdMs, options) {
2500
+ if (!Array.isArray(points) || !points.length) return [];
2501
+ if (!thresholdMs) return points.map((point) => ({ type: "point", point }));
2502
+ const entries = [];
2503
+ let currentGroup = null;
2504
+ let groupCounter = 0;
2505
+ function flush() {
2506
+ if (!currentGroup) return;
2507
+ if (currentGroup.points.length > 1) {
2508
+ const firstPoint = currentGroup.points[0];
2509
+ entries.push({
2510
+ type: "group",
2511
+ id: `canopy-timeline-group-${groupCounter}-${currentGroup.start}`,
2512
+ points: currentGroup.points,
2513
+ progress: firstPoint.progress,
2514
+ side: firstPoint.side,
2515
+ label: formatGroupLabel(currentGroup.start, currentGroup.end, options),
2516
+ count: currentGroup.points.length
2517
+ });
2518
+ groupCounter += 1;
2519
+ } else {
2520
+ entries.push({ type: "point", point: currentGroup.points[0] });
2521
+ }
2522
+ currentGroup = null;
2523
+ }
2524
+ points.forEach((point) => {
2525
+ const timestamp = point && point.meta ? point.meta.timestamp : null;
2526
+ if (!Number.isFinite(timestamp)) {
2527
+ flush();
2528
+ if (point) entries.push({ type: "point", point });
2529
+ return;
2530
+ }
2531
+ if (!currentGroup) {
2532
+ currentGroup = {
2533
+ points: [point],
2534
+ start: timestamp,
2535
+ end: timestamp,
2536
+ last: timestamp
2537
+ };
2538
+ return;
2539
+ }
2540
+ const diff = Math.abs(timestamp - currentGroup.last);
2541
+ if (diff <= thresholdMs) {
2542
+ currentGroup.points.push(point);
2543
+ currentGroup.last = timestamp;
2544
+ if (timestamp < currentGroup.start) currentGroup.start = timestamp;
2545
+ if (timestamp > currentGroup.end) currentGroup.end = timestamp;
2546
+ } else {
2547
+ flush();
2548
+ currentGroup = {
2549
+ points: [point],
2550
+ start: timestamp,
2551
+ end: timestamp,
2552
+ last: timestamp
2553
+ };
2554
+ }
2555
+ });
2556
+ flush();
2557
+ return entries;
2558
+ }
2559
+ function formatGroupLabel(startTs, endTs, options) {
2560
+ if (!Number.isFinite(startTs) || !Number.isFinite(endTs)) return "";
2561
+ const startLabel = formatDateLabel(new Date(startTs), options);
2562
+ const endLabel = formatDateLabel(new Date(endTs), options);
2563
+ if (!startLabel || !endLabel) return "";
2564
+ return startLabel === endLabel ? startLabel : `${startLabel} \u2013 ${endLabel}`;
2565
+ }
2566
+ function deriveRangeOverrides(points, range) {
2567
+ const timestamps = points.map((point) => point && point.meta ? point.meta.timestamp : null).filter((timestamp) => Number.isFinite(timestamp));
2568
+ if (!timestamps.length) return range || {};
2569
+ const earliest = Math.min(...timestamps);
2570
+ const latest = Math.max(...timestamps);
2571
+ return {
2572
+ ...range,
2573
+ start: range && range.start ? range.start : new Date(earliest),
2574
+ end: range && range.end ? range.end : new Date(latest)
2575
+ };
2576
+ }
2577
+ function getActivePointId(points) {
2578
+ const highlighted = points.find((point) => point && point.highlight);
2579
+ if (highlighted) return highlighted.id;
2580
+ return points.length ? points[0].id : null;
2581
+ }
2582
+ function formatRangeLabel(rangeInfo) {
2583
+ if (!rangeInfo) return "";
2584
+ const startLabel = formatDateLabel(rangeInfo.startDate, {
2585
+ granularity: rangeInfo.granularity,
2586
+ locale: rangeInfo.locale
2587
+ });
2588
+ const endLabel = formatDateLabel(rangeInfo.endDate, {
2589
+ granularity: rangeInfo.granularity,
2590
+ locale: rangeInfo.locale
2591
+ });
2592
+ if (!startLabel || !endLabel) return "";
2593
+ if (startLabel === endLabel) return startLabel;
2594
+ return `${startLabel} \u2013 ${endLabel}`;
2595
+ }
2596
+ function sanitizePoints(points) {
2597
+ if (!Array.isArray(points)) return [];
2598
+ return points.map((point, index) => {
2599
+ if (!point) return null;
2600
+ const meta = point.meta || {};
2601
+ const timestamp = Number(meta.timestamp);
2602
+ const manifests = Array.isArray(point.manifests) ? point.manifests.map((manifest) => manifest ? { ...manifest } : null).filter(Boolean) : [];
2603
+ const resources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2604
+ return {
2605
+ ...point,
2606
+ id: point.id || `timeline-point-${index}`,
2607
+ title: point.title || point.label || `Point ${index + 1}`,
2608
+ summary: point.summary || point.description || "",
2609
+ detailsHtml: point.detailsHtml || "",
2610
+ highlight: !!point.highlight,
2611
+ side: point.side === "left" || point.side === "right" ? point.side : null,
2612
+ meta: {
2613
+ label: meta.label || "",
2614
+ timestamp: Number.isFinite(timestamp) ? timestamp : null
2615
+ },
2616
+ manifests,
2617
+ resources
2618
+ };
2619
+ }).filter(Boolean);
2620
+ }
2621
+ function TimelineConnector({ side, isActive, highlight }) {
2622
+ const connectorClasses = [
2623
+ "canopy-timeline__connector",
2624
+ side === "left" ? "canopy-timeline__connector--left" : "canopy-timeline__connector--right"
2625
+ ].filter(Boolean).join(" ");
2626
+ const dotClasses = [
2627
+ "canopy-timeline__connector-dot",
2628
+ highlight || isActive ? "is-active" : ""
2629
+ ].filter(Boolean).join(" ");
2630
+ return /* @__PURE__ */ React26.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React26.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("span", { className: dotClasses }), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__connector-line" })));
2631
+ }
2632
+ function renderResourceSection(point) {
2633
+ if (!point) return null;
2634
+ const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
2635
+ const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
2636
+ if (!manifestCards.length && !legacyResources.length) return null;
2637
+ return /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React26.createElement("ul", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React26.createElement("li", { key: manifest.id || manifest.href }, /* @__PURE__ */ React26.createElement(
2638
+ TeaserCard,
2639
+ {
2640
+ href: manifest.href,
2641
+ title: manifest.title || manifest.href,
2642
+ summary: manifest.summary,
2643
+ metadata: Array.isArray(manifest.metadata) && manifest.metadata.length ? manifest.metadata : manifest.summary ? [manifest.summary] : [],
2644
+ thumbnail: manifest.thumbnail,
2645
+ type: manifest.type || "work"
2646
+ }
2647
+ ))), legacyResources.map((resource, idx) => /* @__PURE__ */ React26.createElement("li", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React26.createElement(
2648
+ TeaserCard,
2649
+ {
2650
+ href: resource.href,
2651
+ title: resource.label || resource.title || resource.href,
2652
+ summary: resource.summary,
2653
+ thumbnail: resource.thumbnail,
2654
+ type: resource.type || "resource"
2655
+ }
2656
+ )))));
2657
+ }
2658
+ function Timeline({
2659
+ className = "",
2660
+ title,
2661
+ description,
2662
+ range: rangeProp,
2663
+ locale: localeProp = "en-US",
2664
+ height = 640,
2665
+ threshold: thresholdProp = null,
2666
+ steps = null,
2667
+ points: pointsProp,
2668
+ __canopyTimeline: payload = null,
2669
+ ...rest
2670
+ }) {
2671
+ const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
2672
+ const rawPoints = React26.useMemo(() => {
2673
+ if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
2674
+ if (payloadPoints && payloadPoints.length) return payloadPoints;
2675
+ return [];
2676
+ }, [pointsProp, payloadPoints]);
2677
+ const sanitizedPoints = React26.useMemo(
2678
+ () => sanitizePoints(rawPoints),
2679
+ [rawPoints]
2680
+ );
2681
+ const localeValue = payload && payload.locale ? payload.locale : localeProp;
2682
+ const baseLocale = React26.useMemo(() => createLocale(localeValue), [localeValue]);
2683
+ const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
2684
+ const rangeOverrides = React26.useMemo(
2685
+ () => deriveRangeOverrides(sanitizedPoints, rangeInput),
2686
+ [sanitizedPoints, rangeInput]
2687
+ );
2688
+ const effectiveRange = React26.useMemo(
2689
+ () => normalizeRange({
2690
+ ...rangeOverrides,
2691
+ locale: baseLocale
2692
+ }),
2693
+ [rangeOverrides, baseLocale]
2694
+ );
2695
+ const spanStart = effectiveRange.startDate.getTime();
2696
+ const span = effectiveRange.span;
2697
+ const pointsWithPosition = React26.useMemo(() => {
2698
+ if (!sanitizedPoints.length) return [];
2699
+ return sanitizedPoints.map((point, index) => {
2700
+ const timestamp = point.meta.timestamp;
2701
+ const fallbackProgress = sanitizedPoints.length > 1 ? index / (sanitizedPoints.length - 1) : 0;
2702
+ const progress = Number.isFinite(timestamp) ? clampProgress((timestamp - spanStart) / span) : fallbackProgress;
2703
+ const side = point.side || (index % 2 === 0 ? "left" : "right");
2704
+ return {
2705
+ ...point,
2706
+ progress,
2707
+ side
2708
+ };
2709
+ });
2710
+ }, [sanitizedPoints, spanStart, span]);
2711
+ const [activeId, setActiveId] = React26.useState(
2712
+ () => getActivePointId(pointsWithPosition)
2713
+ );
2714
+ React26.useEffect(() => {
2715
+ setActiveId(getActivePointId(pointsWithPosition));
2716
+ }, [pointsWithPosition]);
2717
+ const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
2718
+ const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
2719
+ const thresholdMs = React26.useMemo(
2720
+ () => getThresholdMs(thresholdValue, effectiveRange.granularity),
2721
+ [thresholdValue, effectiveRange.granularity]
2722
+ );
2723
+ const groupedEntries = React26.useMemo(
2724
+ () => buildGroupedEntries(pointsWithPosition, thresholdMs, {
2725
+ granularity: effectiveRange.granularity,
2726
+ locale: baseLocale
2727
+ }),
2728
+ [pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
2729
+ );
2730
+ const [expandedGroupIds, setExpandedGroupIds] = React26.useState(() => /* @__PURE__ */ new Set());
2731
+ React26.useEffect(() => {
2732
+ setExpandedGroupIds((prev) => {
2733
+ if (!prev || prev.size === 0) return prev;
2734
+ const validIds = new Set(
2735
+ groupedEntries.filter((entry) => entry.type === "group").map((entry) => entry.id)
2736
+ );
2737
+ const next = /* @__PURE__ */ new Set();
2738
+ let changed = false;
2739
+ prev.forEach((id) => {
2740
+ if (validIds.has(id)) next.add(id);
2741
+ else changed = true;
2742
+ });
2743
+ return changed ? next : prev;
2744
+ });
2745
+ }, [groupedEntries]);
2746
+ const toggleGroup = React26.useCallback((groupId) => {
2747
+ setExpandedGroupIds((prev) => {
2748
+ const next = new Set(prev || []);
2749
+ if (next.has(groupId)) next.delete(groupId);
2750
+ else next.add(groupId);
2751
+ return next;
2752
+ });
2753
+ }, []);
2754
+ const resolvedHeight = Number.isFinite(Number(height)) ? Number(height) : 640;
2755
+ const trackHeight = Math.max(resolvedHeight, pointsWithPosition.length * 220);
2756
+ const containerClasses = ["canopy-timeline", className].filter(Boolean).join(" ");
2757
+ const rangeLabel = formatRangeLabel(effectiveRange);
2758
+ function renderPointEntry(point) {
2759
+ if (!point) return null;
2760
+ const wrapperClasses = [
2761
+ "canopy-timeline__point-wrapper",
2762
+ point.side === "left" ? "canopy-timeline__point-wrapper--left" : "canopy-timeline__point-wrapper--right"
2763
+ ].filter(Boolean).join(" ");
2764
+ const wrapperStyle = { top: `calc(${point.progress * 100}% - 1rem)` };
2765
+ const cardClasses = [
2766
+ "canopy-timeline__point",
2767
+ point.id === activeId ? "is-active" : "",
2768
+ point.highlight ? "is-highlighted" : ""
2769
+ ].filter(Boolean).join(" ");
2770
+ const connector = /* @__PURE__ */ React26.createElement(
2771
+ TimelineConnector,
2772
+ {
2773
+ side: point.side,
2774
+ isActive: point.id === activeId,
2775
+ highlight: point.highlight
2776
+ }
2777
+ );
2778
+ const body = /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
2779
+ const resourceSection = renderResourceSection(point);
2780
+ return /* @__PURE__ */ React26.createElement(
2781
+ "div",
2782
+ {
2783
+ key: point.id,
2784
+ className: wrapperClasses,
2785
+ style: wrapperStyle,
2786
+ role: "listitem"
2787
+ },
2788
+ point.side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, connector, /* @__PURE__ */ React26.createElement("div", { className: cardClasses }, body, resourceSection))
2789
+ );
2790
+ }
2791
+ function renderGroupEntry(entry) {
2792
+ const wrapperClasses = [
2793
+ "canopy-timeline__point-wrapper",
2794
+ entry.side === "left" ? "canopy-timeline__point-wrapper--left" : "canopy-timeline__point-wrapper--right"
2795
+ ].filter(Boolean).join(" ");
2796
+ const wrapperStyle = { top: `calc(${entry.progress * 100}% - 1rem)` };
2797
+ const isExpanded = expandedGroupIds.has(entry.id);
2798
+ const hasActivePoint = entry.points.some((point) => point.id === activeId);
2799
+ const connector = /* @__PURE__ */ React26.createElement(
2800
+ TimelineConnector,
2801
+ {
2802
+ side: entry.side,
2803
+ isActive: hasActivePoint,
2804
+ highlight: hasActivePoint
2805
+ }
2806
+ );
2807
+ const groupClasses = [
2808
+ "canopy-timeline__group",
2809
+ isExpanded ? "is-expanded" : "",
2810
+ hasActivePoint ? "is-active" : ""
2811
+ ].filter(Boolean).join(" ");
2812
+ const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
2813
+ const header = /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-count" }, countLabel), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-range" }, entry.label)), /* @__PURE__ */ React26.createElement(
2814
+ "button",
2815
+ {
2816
+ type: "button",
2817
+ className: "canopy-timeline__group-toggle",
2818
+ "aria-expanded": isExpanded ? "true" : "false",
2819
+ onClick: () => toggleGroup(entry.id)
2820
+ },
2821
+ isExpanded ? "Hide details" : "Show details"
2822
+ ));
2823
+ const groupPoints = isExpanded ? /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React26.createElement(
2824
+ "button",
2825
+ {
2826
+ key: point.id,
2827
+ type: "button",
2828
+ className: [
2829
+ "canopy-timeline__group-point",
2830
+ point.id === activeId ? "is-active" : ""
2831
+ ].filter(Boolean).join(" "),
2832
+ onClick: () => setActiveId(point.id)
2833
+ },
2834
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-point-date" }, point.meta.label),
2835
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
2836
+ ))) : null;
2837
+ const groupCard = /* @__PURE__ */ React26.createElement("div", { className: groupClasses }, header, groupPoints);
2838
+ return /* @__PURE__ */ React26.createElement(
2839
+ "div",
2840
+ {
2841
+ key: entry.id,
2842
+ className: wrapperClasses,
2843
+ style: wrapperStyle,
2844
+ role: "listitem"
2845
+ },
2846
+ entry.side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, groupCard, connector) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, connector, groupCard)
2847
+ );
2848
+ }
2849
+ return /* @__PURE__ */ React26.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React26.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React26.createElement(
2850
+ "div",
2851
+ {
2852
+ className: "canopy-timeline__list",
2853
+ role: "list",
2854
+ style: { minHeight: `${trackHeight}px` }
2855
+ },
2856
+ /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
2857
+ renderSteps(stepsValue, effectiveRange),
2858
+ groupedEntries.map((entry) => {
2859
+ if (entry.type === "group") return renderGroupEntry(entry);
2860
+ return renderPointEntry(entry.point);
2861
+ })
2862
+ )));
2863
+ }
2864
+ function renderSteps(stepSize, range) {
2865
+ if (!Number.isFinite(stepSize) || stepSize <= 0 || !range) return null;
2866
+ const startYear = range.startDate.getUTCFullYear();
2867
+ const endYear = range.endDate.getUTCFullYear();
2868
+ const markers = [];
2869
+ if (startYear < endYear) {
2870
+ markers.push(
2871
+ /* @__PURE__ */ React26.createElement(
2872
+ "span",
2873
+ {
2874
+ key: "timeline-step-start",
2875
+ className: "canopy-timeline__step canopy-timeline__step--edge",
2876
+ style: { top: "0%" },
2877
+ "aria-hidden": "true"
2878
+ },
2879
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
2880
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
2881
+ )
2882
+ );
2883
+ markers.push(
2884
+ /* @__PURE__ */ React26.createElement(
2885
+ "span",
2886
+ {
2887
+ key: "timeline-step-end",
2888
+ className: "canopy-timeline__step canopy-timeline__step--edge",
2889
+ style: { top: "calc(100% - 1px)" },
2890
+ "aria-hidden": "true"
2891
+ },
2892
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
2893
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
2894
+ )
2895
+ );
2896
+ }
2897
+ const baseYear = Math.ceil(startYear / stepSize) * stepSize;
2898
+ for (let year = baseYear; year <= endYear; year += stepSize) {
2899
+ const timestamp = Date.UTC(year, 0, 1);
2900
+ const progress = (timestamp - range.startDate.getTime()) / range.span;
2901
+ if (progress <= 0 || progress >= 1) continue;
2902
+ markers.push(
2903
+ /* @__PURE__ */ React26.createElement(
2904
+ "span",
2905
+ {
2906
+ key: `timeline-step-${year}`,
2907
+ className: "canopy-timeline__step",
2908
+ style: { top: `calc(${progress * 100}% - 0.5px)` },
2909
+ "aria-hidden": "true"
2910
+ },
2911
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
2912
+ /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, year)
2913
+ )
2914
+ );
2915
+ }
2916
+ return markers.length ? markers : null;
2917
+ }
2918
+
2919
+ // ui/src/content/timeline/TimelinePoint.jsx
2920
+ function TimelinePoint() {
2921
+ return null;
2922
+ }
2923
+ TimelinePoint.displayName = "TimelinePoint";
2924
+
2925
+ // ui/src/content/timeline/MdxTimeline.jsx
2926
+ import navigationHelpers6 from "@canopy-iiif/app/lib/components/navigation.js";
2927
+ function normalizeManifestId(raw) {
2928
+ if (!raw) return "";
2929
+ try {
2930
+ const url = new URL(String(raw));
2931
+ url.hash = "";
2932
+ const params = Array.from(url.searchParams.entries()).sort(
2933
+ (a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1])
2934
+ );
2935
+ url.search = "";
2936
+ params.forEach(([key, value]) => url.searchParams.append(key, value));
2937
+ return url.toString();
2938
+ } catch (_) {
2939
+ return String(raw || "").trim();
2940
+ }
2941
+ }
2942
+ var PageContextFallback = React27.createContext(null);
2943
+ function useReferencedManifestMap() {
2944
+ var _a, _b;
2945
+ const PageContext = ((_b = (_a = navigationHelpers6) == null ? void 0 : _a.getPageContext) == null ? void 0 : _b.call(_a)) || PageContextFallback;
2946
+ const pageContext = React27.useContext(PageContext);
2947
+ const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
2948
+ return React27.useMemo(() => {
2949
+ const map = /* @__PURE__ */ new Map();
2950
+ referencedItems.forEach((item) => {
2951
+ if (!item) return;
2952
+ const id = item.id || item.href;
2953
+ if (!id) return;
2954
+ const normalized = normalizeManifestId(id);
2955
+ map.set(normalized, item);
2956
+ map.set(String(id), item);
2957
+ });
2958
+ return map;
2959
+ }, [referencedItems]);
2960
+ }
2961
+ function normalizeResource(resource, index) {
2962
+ if (!resource) return null;
2963
+ const href = resource.href || resource.id || "";
2964
+ const label = resource.label || resource.title || href || `Resource ${index + 1}`;
2965
+ return {
2966
+ id: resource.id || href || `timeline-resource-${index}`,
2967
+ href,
2968
+ label,
2969
+ type: resource.type || "IIIF",
2970
+ thumbnail: resource.thumbnail || null,
2971
+ summary: resource.summary || null
2972
+ };
2973
+ }
2974
+ function normalizePoint(child, index, options) {
2975
+ var _a, _b, _c, _d, _e, _f;
2976
+ if (!React27.isValidElement(child)) return null;
2977
+ if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
2978
+ return null;
2979
+ const props = child.props || {};
2980
+ const id = props.id || `timeline-point-${index}`;
2981
+ const granularity = props.precision || props.granularity || options && options.range && options.range.granularity || "year";
2982
+ const value = (_f = (_e = (_d = (_c = (_b = props.date) != null ? _b : props.value) != null ? _c : props.timestamp) != null ? _d : props.year) != null ? _e : props.label) != null ? _f : props.title;
2983
+ const meta = buildPointMetadata({
2984
+ value,
2985
+ granularity,
2986
+ locale: options.locale
2987
+ });
2988
+ let detailsHtml = "";
2989
+ try {
2990
+ if (props.children) {
2991
+ detailsHtml = ReactDOMServer.renderToStaticMarkup(
2992
+ React27.createElement(React27.Fragment, null, props.children)
2993
+ );
2994
+ }
2995
+ } catch (_) {
2996
+ detailsHtml = "";
2997
+ }
2998
+ const resources = Array.isArray(props.iiifResources) ? props.iiifResources.map(normalizeResource).filter(Boolean) : [];
2999
+ const manifestValues = Array.isArray(props.referencedManifests) ? props.referencedManifests : props.manifest ? [props.manifest] : Array.isArray(props.manifests) ? props.manifests : [];
3000
+ const manifests = resolveManifestReferences(manifestValues, options.manifestMap);
3001
+ return {
3002
+ id,
3003
+ title: props.title || props.label || `Point ${index + 1}`,
3004
+ summary: props.summary || props.description || "",
3005
+ description: props.description || "",
3006
+ highlight: props.highlight === true || props.highlight === "true",
3007
+ side: props.side || props.align || props.alignment || null,
3008
+ meta: {
3009
+ label: meta.label,
3010
+ timestamp: meta.timestamp
3011
+ },
3012
+ detailsHtml,
3013
+ resources,
3014
+ manifests
3015
+ };
3016
+ }
3017
+ function resolveManifestReferences(ids, manifestMap) {
3018
+ if (!Array.isArray(ids) || !ids.length || !manifestMap) return [];
3019
+ const seen = /* @__PURE__ */ new Set();
3020
+ const out = [];
3021
+ ids.forEach((value) => {
3022
+ if (!value) return;
3023
+ const normalized = normalizeManifestId(value);
3024
+ if (!normalized || seen.has(normalized)) return;
3025
+ seen.add(normalized);
3026
+ const record = manifestMap.get(normalized);
3027
+ if (!record) return;
3028
+ out.push({
3029
+ id: record.id || value,
3030
+ href: record.href || null,
3031
+ title: record.title || record.href || value,
3032
+ summary: record.summary || "",
3033
+ thumbnail: record.thumbnail || null,
3034
+ thumbnailWidth: record.thumbnailWidth,
3035
+ thumbnailHeight: record.thumbnailHeight,
3036
+ type: record.type || "work",
3037
+ metadata: Array.isArray(record.metadata) && record.metadata.length ? record.metadata : record.summary ? [record.summary] : []
3038
+ });
3039
+ });
3040
+ return out;
3041
+ }
3042
+ function serializeProps(props, payload, locale) {
3043
+ const clone = {};
3044
+ Object.keys(props || {}).forEach((key) => {
3045
+ if (key === "children") return;
3046
+ const value = props[key];
3047
+ if (typeof value === "function" || typeof value === "symbol") return;
3048
+ clone[key] = value;
3049
+ });
3050
+ clone.locale = locale;
3051
+ clone.__canopyTimeline = payload;
3052
+ return clone;
3053
+ }
3054
+ function serializeForScript(data) {
3055
+ try {
3056
+ return JSON.stringify(data).replace(/</g, "\\u003c");
3057
+ } catch (_) {
3058
+ return "{}";
3059
+ }
3060
+ }
3061
+ function MdxTimeline({ children, ...rest }) {
3062
+ const localeValue = rest.locale || "en-US";
3063
+ const localeObj = createLocale(localeValue);
3064
+ const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
3065
+ const manifestMap = useReferencedManifestMap();
3066
+ const childArray = React27.Children.toArray(children);
3067
+ const points = childArray.map(
3068
+ (child, index) => normalizePoint(child, index, {
3069
+ range: rest.range || {},
3070
+ locale: localeObj,
3071
+ manifestMap
3072
+ })
3073
+ ).filter(Boolean);
3074
+ const payload = {
3075
+ points,
3076
+ locale: localeBase,
3077
+ range: rest.range || null,
3078
+ threshold: rest.threshold != null ? rest.threshold : null,
3079
+ steps: rest.steps != null ? rest.steps : null
3080
+ };
3081
+ const json = serializeForScript(serializeProps(rest, payload, localeBase));
3082
+ return /* @__PURE__ */ React27.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React27.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React27.createElement(
3083
+ "script",
3084
+ {
3085
+ type: "application/json",
3086
+ dangerouslySetInnerHTML: { __html: json }
3087
+ }
3088
+ ));
2280
3089
  }
2281
3090
 
2282
3091
  // ui/src/search/MdxSearchResults.jsx
2283
- import React25 from "react";
3092
+ import React28 from "react";
2284
3093
  function MdxSearchResults(props) {
2285
3094
  let json = "{}";
2286
3095
  try {
@@ -2288,11 +3097,11 @@ function MdxSearchResults(props) {
2288
3097
  } catch (_) {
2289
3098
  json = "{}";
2290
3099
  }
2291
- return /* @__PURE__ */ React25.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React25.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3100
+ return /* @__PURE__ */ React28.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React28.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
2292
3101
  }
2293
3102
 
2294
3103
  // ui/src/search/SearchSummary.jsx
2295
- import React26 from "react";
3104
+ import React29 from "react";
2296
3105
  function SearchSummary(props) {
2297
3106
  let json = "{}";
2298
3107
  try {
@@ -2300,11 +3109,11 @@ function SearchSummary(props) {
2300
3109
  } catch (_) {
2301
3110
  json = "{}";
2302
3111
  }
2303
- return /* @__PURE__ */ React26.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React26.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3112
+ return /* @__PURE__ */ React29.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React29.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
2304
3113
  }
2305
3114
 
2306
3115
  // ui/src/search/MdxSearchTabs.jsx
2307
- import React27 from "react";
3116
+ import React30 from "react";
2308
3117
  function MdxSearchTabs(props) {
2309
3118
  let json = "{}";
2310
3119
  try {
@@ -2312,11 +3121,11 @@ function MdxSearchTabs(props) {
2312
3121
  } catch (_) {
2313
3122
  json = "{}";
2314
3123
  }
2315
- return /* @__PURE__ */ React27.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React27.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
3124
+ return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
2316
3125
  }
2317
3126
 
2318
3127
  // ui/src/search-form/MdxSearchFormModal.jsx
2319
- import React28 from "react";
3128
+ import React31 from "react";
2320
3129
  function MdxSearchFormModal(props = {}) {
2321
3130
  const {
2322
3131
  placeholder = "Search\u2026",
@@ -2332,11 +3141,11 @@ function MdxSearchFormModal(props = {}) {
2332
3141
  const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
2333
3142
  const resolvedSearchPath = resolveSearchPath(searchPath);
2334
3143
  const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
2335
- return /* @__PURE__ */ React28.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React28.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React28.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React28.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React28.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
3144
+ return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React31.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React31.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React31.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
2336
3145
  }
2337
3146
 
2338
3147
  // ui/src/iiif/ManifestPrimitives.jsx
2339
- import React29 from "react";
3148
+ import React32 from "react";
2340
3149
  import {
2341
3150
  Label as CloverLabel,
2342
3151
  Metadata as CloverMetadata,
@@ -2361,28 +3170,28 @@ function ensureMetadata(items) {
2361
3170
  function Label({ manifest, label, ...rest }) {
2362
3171
  const intl = label || manifest && manifest.label;
2363
3172
  if (!hasInternationalValue(intl)) return null;
2364
- return /* @__PURE__ */ React29.createElement(CloverLabel, { label: intl, ...rest });
3173
+ return /* @__PURE__ */ React32.createElement(CloverLabel, { label: intl, ...rest });
2365
3174
  }
2366
3175
  function Summary({ manifest, summary, ...rest }) {
2367
3176
  const intl = summary || manifest && manifest.summary;
2368
3177
  if (!hasInternationalValue(intl)) return null;
2369
- return /* @__PURE__ */ React29.createElement(CloverSummary, { summary: intl, ...rest });
3178
+ return /* @__PURE__ */ React32.createElement(CloverSummary, { summary: intl, ...rest });
2370
3179
  }
2371
3180
  function Metadata({ manifest, metadata, ...rest }) {
2372
3181
  const items = ensureMetadata(metadata || manifest && manifest.metadata);
2373
3182
  if (!items.length) return null;
2374
- return /* @__PURE__ */ React29.createElement(CloverMetadata, { metadata: items, ...rest });
3183
+ return /* @__PURE__ */ React32.createElement(CloverMetadata, { metadata: items, ...rest });
2375
3184
  }
2376
3185
  function RequiredStatement({ manifest, requiredStatement, ...rest }) {
2377
3186
  const stmt = requiredStatement || manifest && manifest.requiredStatement;
2378
3187
  if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
2379
3188
  return null;
2380
3189
  }
2381
- return /* @__PURE__ */ React29.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
3190
+ return /* @__PURE__ */ React32.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
2382
3191
  }
2383
3192
 
2384
3193
  // ui/src/docs/CodeBlock.jsx
2385
- import React30 from "react";
3194
+ import React33 from "react";
2386
3195
  function parseHighlightAttr(attr) {
2387
3196
  if (!attr) return /* @__PURE__ */ new Set();
2388
3197
  const cleaned = String(attr || "").trim();
@@ -2428,10 +3237,10 @@ var highlightBaseStyle = {
2428
3237
  };
2429
3238
  function DocsCodeBlock(props = {}) {
2430
3239
  const { children, ...rest } = props;
2431
- const childArray = React30.Children.toArray(children);
2432
- const codeElement = childArray.find((el) => React30.isValidElement(el));
3240
+ const childArray = React33.Children.toArray(children);
3241
+ const codeElement = childArray.find((el) => React33.isValidElement(el));
2433
3242
  if (!codeElement || !codeElement.props) {
2434
- return React30.createElement("pre", props);
3243
+ return React33.createElement("pre", props);
2435
3244
  }
2436
3245
  const {
2437
3246
  className = "",
@@ -2446,8 +3255,8 @@ function DocsCodeBlock(props = {}) {
2446
3255
  const highlightSet = parseHighlightAttr(highlightAttr);
2447
3256
  const copyAttr = codeProps["data-copy"];
2448
3257
  const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
2449
- const [copied, setCopied] = React30.useState(false);
2450
- const handleCopy = React30.useCallback(async () => {
3258
+ const [copied, setCopied] = React33.useState(false);
3259
+ const handleCopy = React33.useCallback(async () => {
2451
3260
  const text = rawCode;
2452
3261
  try {
2453
3262
  if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
@@ -2512,20 +3321,20 @@ function DocsCodeBlock(props = {}) {
2512
3321
  const highlight = highlightSet.has(lineNumber);
2513
3322
  const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
2514
3323
  const displayLine = line === "" ? " " : line;
2515
- return React30.createElement(
3324
+ return React33.createElement(
2516
3325
  "span",
2517
3326
  { key: lineNumber, style },
2518
- React30.createElement("span", { style: lineContentStyle }, displayLine)
3327
+ React33.createElement("span", { style: lineContentStyle }, displayLine)
2519
3328
  );
2520
3329
  });
2521
- return React30.createElement(
3330
+ return React33.createElement(
2522
3331
  "div",
2523
3332
  { style: containerStyle },
2524
- showHeader ? React30.createElement(
3333
+ showHeader ? React33.createElement(
2525
3334
  "div",
2526
3335
  { style: headerStyle },
2527
- React30.createElement("span", null, showFilename ? filename : null),
2528
- enableCopy ? React30.createElement(
3336
+ React33.createElement("span", null, showFilename ? filename : null),
3337
+ enableCopy ? React33.createElement(
2529
3338
  "button",
2530
3339
  {
2531
3340
  type: "button",
@@ -2544,29 +3353,29 @@ function DocsCodeBlock(props = {}) {
2544
3353
  copied ? "Copied" : "Copy"
2545
3354
  ) : null
2546
3355
  ) : null,
2547
- React30.createElement(
3356
+ React33.createElement(
2548
3357
  "pre",
2549
3358
  { ...preRest, className: preClassName, style: mergedPreStyle },
2550
- React30.createElement("code", { style: codeStyle }, lineElements)
3359
+ React33.createElement("code", { style: codeStyle }, lineElements)
2551
3360
  )
2552
3361
  );
2553
3362
  }
2554
3363
 
2555
3364
  // ui/src/docs/MarkdownTable.jsx
2556
- import React31 from "react";
3365
+ import React34 from "react";
2557
3366
  function MarkdownTable({ className = "", ...rest }) {
2558
3367
  const merged = ["markdown-table", className].filter(Boolean).join(" ");
2559
- return /* @__PURE__ */ React31.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React31.createElement("table", { className: merged, ...rest }));
3368
+ return /* @__PURE__ */ React34.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React34.createElement("table", { className: merged, ...rest }));
2560
3369
  }
2561
3370
 
2562
3371
  // ui/src/docs/Diagram.jsx
2563
- import React32 from "react";
3372
+ import React35 from "react";
2564
3373
  function CanopyDiagram() {
2565
- return /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React32.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Collection A"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React32.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React32.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Collection B"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React32.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React32.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React32.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Automated content"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React32.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React32.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React32.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React32.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Search index"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React32.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React32.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React32.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React32.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React32.createElement("span", { className: "canopy-diagram__section-summary" }, "The output is a lightweight bundle of HTML, CSS, JS, and JSON assets that can deploy anywhere."), /* @__PURE__ */ React32.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Work pages"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React32.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React32.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React32.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React32.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React32.createElement("article", null, /* @__PURE__ */ React32.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React32.createElement("ul", null, /* @__PURE__ */ React32.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React32.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React32.createElement("li", null, "Optional annotation dataset"))))));
3374
+ return /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React35.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Collection A"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React35.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React35.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Collection B"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React35.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React35.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React35.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Automated content"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React35.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React35.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React35.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React35.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Search index"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React35.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React35.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React35.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "The output is a lightweight bundle of HTML, CSS, JS, and JSON assets that can deploy anywhere."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Work pages"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React35.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React35.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React35.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React35.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React35.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React35.createElement("li", null, "Optional annotation dataset"))))));
2566
3375
  }
2567
3376
 
2568
3377
  // ui/src/docs/ThemeShowcase.jsx
2569
- import React33 from "react";
3378
+ import React36 from "react";
2570
3379
 
2571
3380
  // ../../node_modules/@radix-ui/colors/index.mjs
2572
3381
  var colors_exports = {};
@@ -6399,21 +7208,21 @@ var ACCENT_COLOR_NAMES = [
6399
7208
  "sky"
6400
7209
  ];
6401
7210
  var GRAY_COLOR_NAMES = ["gray", "mauve", "slate", "sage", "olive", "sand"];
6402
- var Section = ({ title, description, children }) => /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React33.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React33.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
6403
- var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React33.createElement("strong", null, label)), /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React33.createElement(
7211
+ var Section = ({ title, description, children }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React36.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
7212
+ var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React36.createElement("strong", null, label)), /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React36.createElement(
6404
7213
  "div",
6405
7214
  {
6406
7215
  key: `${label}-${stop}`,
6407
7216
  className: "canopy-theme-showcase__scale-stop"
6408
7217
  },
6409
- /* @__PURE__ */ React33.createElement(
7218
+ /* @__PURE__ */ React36.createElement(
6410
7219
  "span",
6411
7220
  {
6412
7221
  className: "canopy-theme-showcase__scale-chip",
6413
7222
  style: { backgroundColor: `var(${prefix}-${stop})` }
6414
7223
  }
6415
7224
  ),
6416
- /* @__PURE__ */ React33.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
7225
+ /* @__PURE__ */ React36.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
6417
7226
  ))));
6418
7227
  function ThemeShowcase() {
6419
7228
  const accentColors = ACCENT_COLOR_NAMES;
@@ -6424,15 +7233,15 @@ function ThemeShowcase() {
6424
7233
  if (!scale) return null;
6425
7234
  return scale[`${name}9`] || Object.values(scale)[8];
6426
7235
  };
6427
- const ColorsLabeled = ({ colors }) => /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
7236
+ const ColorsLabeled = ({ colors }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
6428
7237
  const colorValue = getRadixSwatch(name);
6429
- return /* @__PURE__ */ React33.createElement("div", { key: name, className: "canopy-theme-showcase__swatch" }, /* @__PURE__ */ React33.createElement(
7238
+ return /* @__PURE__ */ React36.createElement("div", { key: name, className: "canopy-theme-showcase__swatch" }, /* @__PURE__ */ React36.createElement(
6430
7239
  "div",
6431
7240
  {
6432
7241
  className: "canopy-theme-showcase__swatch-chip",
6433
7242
  style: { background: colorValue || "var(--color-gray-200)" }
6434
7243
  }
6435
- ), /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase__swatch-label" }, name));
7244
+ ), /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__swatch-label" }, name));
6436
7245
  }));
6437
7246
  const styles = `
6438
7247
  .canopy-theme-showcase__section {
@@ -6516,13 +7325,13 @@ function ThemeShowcase() {
6516
7325
  font-weight: 300;
6517
7326
  }
6518
7327
  `;
6519
- return /* @__PURE__ */ React33.createElement("div", { className: "canopy-theme-showcase" }, /* @__PURE__ */ React33.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React33.createElement(
7328
+ return /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase" }, /* @__PURE__ */ React36.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React36.createElement(
6520
7329
  Section,
6521
7330
  {
6522
7331
  title: "Color scales",
6523
7332
  description: "Accent and gray ramps from the active theme."
6524
7333
  },
6525
- /* @__PURE__ */ React33.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React33.createElement(
7334
+ /* @__PURE__ */ React36.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React36.createElement(
6526
7335
  ColorScaleRow,
6527
7336
  {
6528
7337
  key: scale.label,
@@ -6530,20 +7339,20 @@ function ThemeShowcase() {
6530
7339
  prefix: scale.prefix
6531
7340
  }
6532
7341
  )))
6533
- ), /* @__PURE__ */ React33.createElement(
7342
+ ), /* @__PURE__ */ React36.createElement(
6534
7343
  Section,
6535
7344
  {
6536
7345
  title: "Accent palette options",
6537
7346
  description: "All accent color families available via Radix Themes."
6538
7347
  },
6539
- /* @__PURE__ */ React33.createElement(ColorsLabeled, { colors: accentColors })
6540
- ), /* @__PURE__ */ React33.createElement(
7348
+ /* @__PURE__ */ React36.createElement(ColorsLabeled, { colors: accentColors })
7349
+ ), /* @__PURE__ */ React36.createElement(
6541
7350
  Section,
6542
7351
  {
6543
7352
  title: "Gray palette options",
6544
7353
  description: "Neutral ramps you can assign via the theme block."
6545
7354
  },
6546
- /* @__PURE__ */ React33.createElement(ColorsLabeled, { colors: grayColors })
7355
+ /* @__PURE__ */ React36.createElement(ColorsLabeled, { colors: grayColors })
6547
7356
  ));
6548
7357
  }
6549
7358
  export {
@@ -6578,7 +7387,10 @@ export {
6578
7387
  Slider,
6579
7388
  SubNavigation,
6580
7389
  Summary,
7390
+ TeaserCard,
6581
7391
  ThemeShowcase,
7392
+ MdxTimeline as Timeline,
7393
+ TimelinePoint,
6582
7394
  Viewer
6583
7395
  };
6584
7396
  //# sourceMappingURL=server.mjs.map