@canopy-iiif/app 0.12.1 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/build/mdx.js CHANGED
@@ -81,6 +81,21 @@ function parseFrontmatter(src) {
81
81
  return {data, content};
82
82
  }
83
83
 
84
+ function isRoadmapEntry(frontmatterData) {
85
+ if (!frontmatterData || typeof frontmatterData !== "object") return false;
86
+ if (!Object.prototype.hasOwnProperty.call(frontmatterData, "roadmap")) return false;
87
+ const raw = frontmatterData.roadmap;
88
+ if (typeof raw === "boolean") return raw;
89
+ if (typeof raw === "number") return raw !== 0;
90
+ if (typeof raw === "string") {
91
+ const normalized = raw.trim().toLowerCase();
92
+ if (!normalized) return false;
93
+ if (["false", "0", "no", "off", "none"].includes(normalized)) return false;
94
+ return true;
95
+ }
96
+ return !!raw;
97
+ }
98
+
84
99
  // ESM-only in v3; load dynamically from CJS
85
100
  let MDXProviderCached = null;
86
101
  async function getMdxProvider() {
@@ -1159,6 +1174,7 @@ module.exports = {
1159
1174
  extractMarkdownSummary,
1160
1175
  isReservedFile,
1161
1176
  parseFrontmatter,
1177
+ isRoadmapEntry,
1162
1178
  compileMdxFile,
1163
1179
  compileMdxToComponent,
1164
1180
  loadCustomLayout,
@@ -77,8 +77,9 @@ function mapContentPathToOutput(filePath) {
77
77
  return path.join(OUT_DIR, outRel);
78
78
  }
79
79
 
80
- async function renderContentMdxToHtml(filePath, outPath, extraProps = {}) {
81
- const source = await fsp.readFile(filePath, 'utf8');
80
+ async function renderContentMdxToHtml(filePath, outPath, extraProps = {}, sourceOverride = null) {
81
+ const sourceRaw = sourceOverride != null ? sourceOverride : await fsp.readFile(filePath, 'utf8');
82
+ const source = typeof sourceRaw === 'string' ? sourceRaw : String(sourceRaw || '');
82
83
  const title = mdx.extractTitle(source);
83
84
  const relContentPath = path.relative(CONTENT_DIR, filePath);
84
85
  const normalizedRel = navigation.normalizeRelativePath(relContentPath);
@@ -259,12 +260,27 @@ async function processContentEntry(absPath, pagesMetadata = []) {
259
260
  if (/\.mdx$/i.test(absPath)) {
260
261
  if (mdx.isReservedFile(absPath)) return;
261
262
  const outPath = mapContentPathToOutput(absPath);
262
- ensureDirSync(path.dirname(outPath));
263
263
  try {
264
+ const source = await fsp.readFile(absPath, 'utf8');
265
+ const frontmatter = typeof mdx.parseFrontmatter === 'function'
266
+ ? mdx.parseFrontmatter(source)
267
+ : { data: null };
268
+ const frontmatterData = frontmatter && isPlainObject(frontmatter.data) ? frontmatter.data : null;
269
+ const isRoadmap = frontmatterData && typeof mdx.isRoadmapEntry === 'function'
270
+ ? mdx.isRoadmapEntry(frontmatterData)
271
+ : false;
272
+ if (isRoadmap) {
273
+ try { await fsp.rm(outPath, { force: true }); } catch (_) {}
274
+ try {
275
+ log(`• Skipped roadmap page ${path.relative(process.cwd(), absPath)}\n`, 'yellow', { dim: true });
276
+ } catch (_) {}
277
+ return;
278
+ }
279
+ ensureDirSync(path.dirname(outPath));
264
280
  try { log(`• Processing MDX ${absPath}\n`, 'blue'); } catch (_) {}
265
281
  const base = path.basename(absPath);
266
282
  const extra = base.toLowerCase() === 'sitemap.mdx' ? { pages: pagesMetadata } : {};
267
- const html = await renderContentMdxToHtml(absPath, outPath, extra);
283
+ const html = await renderContentMdxToHtml(absPath, outPath, extra, source);
268
284
  await fsp.writeFile(outPath, html || '', 'utf8');
269
285
  try { log(`✓ Built ${path.relative(process.cwd(), outPath)}\n`, 'green'); } catch (_) {}
270
286
  } catch (err) {
@@ -88,6 +88,20 @@ function collectPagesSync() {
88
88
  } catch (_) {
89
89
  raw = "";
90
90
  }
91
+ let frontmatterData = null;
92
+ if (raw && typeof mdx.parseFrontmatter === "function") {
93
+ try {
94
+ const parsed = mdx.parseFrontmatter(raw);
95
+ if (parsed && parsed.data && typeof parsed.data === "object") {
96
+ frontmatterData = parsed.data;
97
+ }
98
+ } catch (_) {
99
+ frontmatterData = null;
100
+ }
101
+ }
102
+ const isRoadmap = frontmatterData && typeof mdx.isRoadmapEntry === "function"
103
+ ? mdx.isRoadmapEntry(frontmatterData)
104
+ : false;
91
105
  const {
92
106
  slug,
93
107
  segments: slugSegments,
@@ -114,6 +128,7 @@ function collectPagesSync() {
114
128
  fallbackTitle,
115
129
  sortKey: pageSortKey(normalizedRel),
116
130
  topSegment: slugSegments[0] || firstSegment || "",
131
+ isRoadmap,
117
132
  };
118
133
  pages.push(page);
119
134
  }
@@ -138,6 +153,7 @@ function createNode(slug) {
138
153
  sortKey: slug || name,
139
154
  sourcePage: null,
140
155
  children: [],
156
+ isRoadmap: false,
141
157
  };
142
158
  }
143
159
 
@@ -173,6 +189,7 @@ function getNavigationCache() {
173
189
  node.relativePath = page.relativePath;
174
190
  node.sortKey = page.sortKey || node.sortKey;
175
191
  node.hasContent = true;
192
+ node.isRoadmap = !!page.isRoadmap;
176
193
  }
177
194
  }
178
195
 
@@ -240,6 +257,7 @@ function cloneNode(node, currentSlug) {
240
257
  hasContent: node.hasContent,
241
258
  relativePath: node.relativePath,
242
259
  children,
260
+ isRoadmap: !!node.isRoadmap,
243
261
  };
244
262
  }
245
263
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
@@ -358,6 +358,7 @@ __export(interstitials_exports, {
358
358
  // ui/src/interstitials/Hero.jsx
359
359
  import React9 from "react";
360
360
  import helpers from "@canopy-iiif/app/lib/components/featured.js";
361
+ import navigationHelpers from "@canopy-iiif/app/lib/components/navigation.js";
361
362
 
362
363
  // ui/src/interstitials/hero-utils.js
363
364
  function computeHeroHeightStyle(height) {
@@ -520,11 +521,26 @@ function normalizeBackground(value) {
520
521
  return "theme";
521
522
  }
522
523
  }
524
+ function findNodePathBySlug(node, targetSlug) {
525
+ if (!node || !targetSlug) return null;
526
+ const normalizedTarget = String(targetSlug || "");
527
+ if (!normalizedTarget) return null;
528
+ if (node.slug === normalizedTarget) return [node];
529
+ const children = Array.isArray(node.children) ? node.children : [];
530
+ for (const child of children) {
531
+ const path = findNodePathBySlug(child, normalizedTarget);
532
+ if (path && path.length) {
533
+ return [node, ...path];
534
+ }
535
+ }
536
+ return null;
537
+ }
523
538
  function normalizeVariant(value) {
524
539
  try {
525
540
  const raw = value == null ? "" : String(value);
526
541
  const normalized = raw.trim().toLowerCase();
527
- return normalized === "text" ? "text" : "featured";
542
+ if (normalized === "breadcrumb" || normalized === "text") return "breadcrumb";
543
+ return "featured";
528
544
  } catch (_) {
529
545
  return "featured";
530
546
  }
@@ -542,12 +558,15 @@ function Hero({
542
558
  style = {},
543
559
  background = "theme",
544
560
  variant = "featured",
561
+ homeLabel = "Home",
545
562
  ...rest
546
563
  }) {
547
564
  const normalizedVariant = normalizeVariant(variant);
548
- const isTextVariant = normalizedVariant === "text";
565
+ const isBreadcrumbVariant = normalizedVariant === "breadcrumb";
566
+ const PageContext = navigationHelpers && typeof navigationHelpers.getPageContext === "function" ? navigationHelpers.getPageContext() : null;
567
+ const pageContext = PageContext ? React9.useContext(PageContext) : null;
549
568
  let orderedSlides = [];
550
- if (!isTextVariant) {
569
+ if (!isBreadcrumbVariant) {
551
570
  const resolved = resolveFeaturedItem({ item, index, random });
552
571
  const helpersList = helpers && helpers.readFeaturedFromCacheSync ? helpers.readFeaturedFromCacheSync() : [];
553
572
  const slides = [];
@@ -582,15 +601,15 @@ function Hero({
582
601
  }
583
602
  const heroHeight = computeHeroHeightStyle(height);
584
603
  const heroStyles = { ...style || {} };
585
- if (heroHeight && heroHeight.height && !isTextVariant) {
604
+ if (heroHeight && heroHeight.height && !isBreadcrumbVariant) {
586
605
  heroStyles["--hero-height"] = heroHeight.height;
587
606
  }
588
- if (isTextVariant) {
607
+ if (isBreadcrumbVariant) {
589
608
  heroStyles["--hero-height"] = "auto";
590
609
  }
591
610
  const derivedDescription = description ? String(description) : "";
592
611
  const normalizedLinks = normalizeLinks(links);
593
- const primarySlide = !isTextVariant ? orderedSlides[0] || null : null;
612
+ const primarySlide = !isBreadcrumbVariant ? orderedSlides[0] || null : null;
594
613
  const overlayTitle = headline || primarySlide && primarySlide.title || "";
595
614
  const defaultLinkHref = applyBasePath(
596
615
  primarySlide && primarySlide.href ? primarySlide.href : "#"
@@ -602,10 +621,46 @@ function Hero({
602
621
  type: "primary"
603
622
  }
604
623
  ].filter(Boolean);
605
- const finalOverlayLinks = isTextVariant ? normalizedLinks : overlayLinks;
624
+ const finalOverlayLinks = isBreadcrumbVariant ? normalizedLinks : overlayLinks;
625
+ const breadcrumbItems = React9.useMemo(() => {
626
+ if (!isBreadcrumbVariant) return [];
627
+ const items = [];
628
+ const label = typeof homeLabel === "string" ? homeLabel.trim() : "";
629
+ if (label) {
630
+ items.push({ title: label, href: applyBasePath("/") });
631
+ }
632
+ const navigation = pageContext && pageContext.navigation ? pageContext.navigation : null;
633
+ const page = pageContext && pageContext.page ? pageContext.page : null;
634
+ const slug = page && page.slug || navigation && navigation.currentSlug || "";
635
+ const rootNode = navigation && navigation.root ? navigation.root : null;
636
+ if (!slug || !rootNode) return items;
637
+ const path = findNodePathBySlug(rootNode, slug);
638
+ if (!path || !path.length) return items;
639
+ path.forEach((node) => {
640
+ if (!node) return;
641
+ const title = node.title || node.slug || "";
642
+ if (!title) return;
643
+ const href = node.href ? applyBasePath(node.href) : null;
644
+ items.push({ title, href });
645
+ });
646
+ return items;
647
+ }, [isBreadcrumbVariant, pageContext, homeLabel]);
648
+ const breadcrumbNode = isBreadcrumbVariant && breadcrumbItems.length ? /* @__PURE__ */ React9.createElement("nav", { className: "canopy-interstitial__breadcrumb", "aria-label": "Breadcrumb" }, breadcrumbItems.map((item2, idx) => {
649
+ const isLast = idx === breadcrumbItems.length - 1;
650
+ const key = `${item2.title || idx}-${idx}`;
651
+ const content = !isLast && item2.href ? /* @__PURE__ */ React9.createElement("a", { href: item2.href }, item2.title) : /* @__PURE__ */ React9.createElement("span", { className: "canopy-interstitial__breadcrumb-current" }, item2.title);
652
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, { key }, idx > 0 ? /* @__PURE__ */ React9.createElement(
653
+ "span",
654
+ {
655
+ className: "canopy-interstitial__breadcrumb-separator",
656
+ "aria-hidden": "true"
657
+ },
658
+ ">"
659
+ ) : null, content);
660
+ })) : null;
606
661
  const normalizedBackground = normalizeBackground(background);
607
662
  const backgroundClassName = normalizedBackground === "transparent" ? "canopy-interstitial--bg-transparent" : "";
608
- const variantClassName = isTextVariant ? "canopy-interstitial--hero-text" : "canopy-interstitial--hero-featured";
663
+ const variantClassName = isBreadcrumbVariant ? "canopy-interstitial--hero-breadcrumb" : "canopy-interstitial--hero-featured";
609
664
  const containerClassName = [
610
665
  "canopy-interstitial",
611
666
  "canopy-interstitial--hero",
@@ -704,20 +759,21 @@ function Hero({
704
759
  style: heroStyles,
705
760
  ...cleanedProps
706
761
  };
707
- if (!isTextVariant) {
762
+ if (!isBreadcrumbVariant) {
708
763
  sectionProps["data-canopy-hero-slider"] = "1";
709
764
  sectionProps["data-transition"] = normalizedTransition;
710
765
  } else {
711
- sectionProps["data-canopy-hero-variant"] = "text";
766
+ sectionProps["data-canopy-hero-variant"] = "breadcrumb";
712
767
  }
713
- return /* @__PURE__ */ React9.createElement("section", { ...sectionProps }, isTextVariant ? /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__layout canopy-interstitial__layout--text" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__body" }, overlayContent))) : /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__layout" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__body" }, overlayContent)), /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__media-group" }, renderSlider({ showVeil: false, captionVariant: "static" }))));
768
+ return /* @__PURE__ */ React9.createElement("section", { ...sectionProps }, isBreadcrumbVariant ? /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__layout canopy-interstitial__layout--breadcrumb" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__body" }, breadcrumbNode, overlayContent))) : /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__layout" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__panel" }, /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__body" }, overlayContent)), /* @__PURE__ */ React9.createElement("div", { className: "canopy-interstitial__media-group" }, renderSlider({ showVeil: false, captionVariant: "static" }))));
714
769
  }
715
770
 
716
771
  // ui/src/layout/SubNavigation.jsx
717
772
  import React10 from "react";
718
- import navigationHelpers from "@canopy-iiif/app/lib/components/navigation.js";
773
+ import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
719
774
  function resolveRelativeCandidate(page, current) {
720
- if (page && typeof page.relativePath === "string" && page.relativePath) return page.relativePath;
775
+ if (page && typeof page.relativePath === "string" && page.relativePath)
776
+ return page.relativePath;
721
777
  if (page && typeof page.slug === "string" && page.slug) return page.slug;
722
778
  if (typeof current === "string" && current) return current;
723
779
  return "";
@@ -731,32 +787,33 @@ function renderNodes(nodes, parentKey = "node") {
731
787
  const showChildren = hasChildren && (node.isExpanded || node.depth === 0);
732
788
  const depth = typeof node.depth === "number" ? Math.max(0, node.depth) : 0;
733
789
  const depthClass = `depth-${Math.min(depth, 5)}`;
734
- const classes = [
735
- "canopy-sub-navigation__link",
736
- depthClass
737
- ];
738
- if (!node.href) classes.push("is-label");
790
+ const isRoadmap = !!node.isRoadmap;
791
+ const isInteractive = !!(node.href && !isRoadmap);
792
+ const classes = ["canopy-sub-navigation__link", depthClass];
793
+ if (!node.href && !isRoadmap) classes.push("is-label");
794
+ if (isRoadmap) classes.push("is-disabled");
739
795
  if (node.isActive) classes.push("is-active");
740
796
  const linkClass = classes.join(" ");
741
- const Tag = node.href ? "a" : "span";
742
- return /* @__PURE__ */ React10.createElement(
743
- "li",
797
+ const Tag = isInteractive ? "a" : "span";
798
+ const badge = isRoadmap ? /* @__PURE__ */ React10.createElement("span", { className: "canopy-sub-navigation__badge" }, "Beta") : null;
799
+ return /* @__PURE__ */ React10.createElement("li", { key, className: "canopy-sub-navigation__item", "data-depth": depth }, /* @__PURE__ */ React10.createElement(
800
+ Tag,
744
801
  {
745
- key,
746
- className: "canopy-sub-navigation__item",
747
- "data-depth": depth
802
+ className: linkClass,
803
+ href: isInteractive ? node.href : void 0,
804
+ "aria-current": node.isActive ? "page" : void 0,
805
+ tabIndex: isInteractive ? void 0 : -1
748
806
  },
749
- /* @__PURE__ */ React10.createElement(
750
- Tag,
751
- {
752
- className: linkClass,
753
- href: node.href || void 0,
754
- "aria-current": node.isActive ? "page" : void 0
755
- },
756
- node.title || node.slug
757
- ),
758
- showChildren ? /* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested", role: "list" }, renderNodes(node.children, key)) : null
759
- );
807
+ node.title || node.slug,
808
+ badge
809
+ ), showChildren ? /* @__PURE__ */ React10.createElement(
810
+ "ul",
811
+ {
812
+ className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
813
+ role: "list"
814
+ },
815
+ renderNodes(node.children, key)
816
+ ) : null);
760
817
  });
761
818
  }
762
819
  function SubNavigation({
@@ -768,20 +825,21 @@ function SubNavigation({
768
825
  heading,
769
826
  ariaLabel
770
827
  }) {
771
- const PageContext = navigationHelpers && navigationHelpers.getPageContext ? navigationHelpers.getPageContext() : null;
828
+ const PageContext = navigationHelpers2 && navigationHelpers2.getPageContext ? navigationHelpers2.getPageContext() : null;
772
829
  const context = PageContext ? React10.useContext(PageContext) : null;
773
830
  const contextNavigation = context && context.navigation ? context.navigation : null;
774
831
  const contextPage = context && context.page ? context.page : null;
775
832
  const effectiveNavigation = navigationProp || contextNavigation;
776
833
  const effectivePage = page || contextPage;
777
834
  const resolvedNavigation = React10.useMemo(() => {
778
- if (effectiveNavigation && effectiveNavigation.root) return effectiveNavigation;
835
+ if (effectiveNavigation && effectiveNavigation.root)
836
+ return effectiveNavigation;
779
837
  const candidate = resolveRelativeCandidate(effectivePage, current);
780
838
  if (!candidate) return effectiveNavigation || null;
781
- const helpers2 = navigationHelpers && navigationHelpers.buildNavigationForFile ? navigationHelpers : null;
839
+ const helpers2 = navigationHelpers2 && navigationHelpers2.buildNavigationForFile ? navigationHelpers2 : null;
782
840
  if (!helpers2) return effectiveNavigation || null;
783
841
  try {
784
- const normalized = navigationHelpers.normalizeRelativePath ? navigationHelpers.normalizeRelativePath(candidate) : candidate;
842
+ const normalized = navigationHelpers2.normalizeRelativePath ? navigationHelpers2.normalizeRelativePath(candidate) : candidate;
785
843
  const built = helpers2.buildNavigationForFile(normalized);
786
844
  if (built) return built;
787
845
  } catch (_) {
@@ -798,12 +856,21 @@ function SubNavigation({
798
856
  if (!Object.prototype.hasOwnProperty.call(inlineStyle, "--sub-nav-indent")) {
799
857
  inlineStyle["--sub-nav-indent"] = "0.85rem";
800
858
  }
801
- return /* @__PURE__ */ React10.createElement("nav", { className: combinedClassName, style: inlineStyle, "aria-label": navLabel }, finalHeading ? /* @__PURE__ */ React10.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null, /* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root")));
859
+ return /* @__PURE__ */ React10.createElement(
860
+ "nav",
861
+ {
862
+ className: combinedClassName,
863
+ style: inlineStyle,
864
+ "aria-label": navLabel
865
+ },
866
+ finalHeading ? /* @__PURE__ */ React10.createElement("div", { className: "canopy-sub-navigation__heading" }, finalHeading) : null,
867
+ /* @__PURE__ */ React10.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, renderNodes([rootNode], rootNode.slug || "root"))
868
+ );
802
869
  }
803
870
 
804
871
  // ui/src/layout/Layout.jsx
805
872
  import React12 from "react";
806
- import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
873
+ import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
807
874
 
808
875
  // ui/src/layout/ContentNavigation.jsx
809
876
  import React11 from "react";
@@ -1203,7 +1270,7 @@ function Layout({
1203
1270
  contentNavigationClassName = "",
1204
1271
  ...rest
1205
1272
  }) {
1206
- const PageContext = navigationHelpers2 && typeof navigationHelpers2.getPageContext === "function" ? navigationHelpers2.getPageContext() : null;
1273
+ const PageContext = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
1207
1274
  const context = PageContext ? React12.useContext(PageContext) : null;
1208
1275
  const pageHeadings = React12.useMemo(() => {
1209
1276
  const headings = context && context.page ? context.page.headings : null;
@@ -2018,7 +2085,7 @@ function Container({
2018
2085
 
2019
2086
  // ui/src/content/ReferencedItems.jsx
2020
2087
  import React23 from "react";
2021
- import navigationHelpers3 from "@canopy-iiif/app/lib/components/navigation.js";
2088
+ import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
2022
2089
 
2023
2090
  // ui/src/layout/Card.jsx
2024
2091
  import React22, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
@@ -2125,7 +2192,7 @@ function Card({
2125
2192
  // ui/src/content/ReferencedItems.jsx
2126
2193
  function useReferencedItems(itemsProp) {
2127
2194
  if (Array.isArray(itemsProp)) return itemsProp;
2128
- const PageContext = navigationHelpers3 && typeof navigationHelpers3.getPageContext === "function" ? navigationHelpers3.getPageContext() : null;
2195
+ const PageContext = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
2129
2196
  if (!PageContext) return [];
2130
2197
  const context = React23.useContext(PageContext);
2131
2198
  const items = context && context.page ? context.page.referencedItems : null;
@@ -2171,13 +2238,13 @@ function ReferencedItems({
2171
2238
 
2172
2239
  // ui/src/content/References.jsx
2173
2240
  import React24 from "react";
2174
- import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
2241
+ import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
2175
2242
  function getPageContext() {
2176
- if (!navigationHelpers4 || typeof navigationHelpers4.getPageContext !== "function") {
2243
+ if (!navigationHelpers5 || typeof navigationHelpers5.getPageContext !== "function") {
2177
2244
  return null;
2178
2245
  }
2179
2246
  try {
2180
- return navigationHelpers4.getPageContext();
2247
+ return navigationHelpers5.getPageContext();
2181
2248
  } catch (_) {
2182
2249
  return null;
2183
2250
  }
@@ -2437,6 +2504,7 @@ function DocsCodeBlock(props = {}) {
2437
2504
  display: "inline"
2438
2505
  };
2439
2506
  const showFilename = Boolean(filename);
2507
+ const showHeader = showFilename || enableCopy;
2440
2508
  const { style: preStyleOverride, className: preClassName, ...preRest } = rest;
2441
2509
  const mergedPreStyle = Object.assign({}, preStyle, preStyleOverride || {});
2442
2510
  const lineElements = lines.map((line, index) => {
@@ -2453,7 +2521,7 @@ function DocsCodeBlock(props = {}) {
2453
2521
  return React30.createElement(
2454
2522
  "div",
2455
2523
  { style: containerStyle },
2456
- React30.createElement(
2524
+ showHeader ? React30.createElement(
2457
2525
  "div",
2458
2526
  { style: headerStyle },
2459
2527
  React30.createElement("span", null, showFilename ? filename : null),
@@ -2475,7 +2543,7 @@ function DocsCodeBlock(props = {}) {
2475
2543
  },
2476
2544
  copied ? "Copied" : "Copy"
2477
2545
  ) : null
2478
- ),
2546
+ ) : null,
2479
2547
  React30.createElement(
2480
2548
  "pre",
2481
2549
  { ...preRest, className: preClassName, style: mergedPreStyle },