@reblu/site-blocks 0.17.1 → 0.18.0

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/dist/index.d.cts CHANGED
@@ -227,6 +227,14 @@ interface MarkdownRendererProps {
227
227
  * the page keeps a single h1.
228
228
  */
229
229
  headingOffset?: number;
230
+ /**
231
+ * Land the body's SHALLOWEST heading at `1 + headingOffset` instead of shifting every
232
+ * heading by a fixed amount, so standard Markdown (`##` sections) renders `<h2>` under
233
+ * the page `<h1>` just like the convention (`#` sections) does. Relative depth is kept
234
+ * and levels clamp at h6. Use it where the body sits directly under the page `<h1>`;
235
+ * leave it off where the body sits under its own section heading. Default `false`.
236
+ */
237
+ normalizeHeadings?: boolean;
230
238
  /**
231
239
  * Restrict and render images (REB-1075). Absent: every image the sanitiser keeps is
232
240
  * rendered as a lazy `<img>` inside its paragraph (the historical behaviour).
@@ -247,7 +255,7 @@ interface MarkdownImageOptions {
247
255
  alt: string;
248
256
  }) => React$1.ReactNode;
249
257
  }
250
- declare function MarkdownRenderer({ content, className, headingOffset, images, }: MarkdownRendererProps): react_jsx_runtime.JSX.Element | null;
258
+ declare function MarkdownRenderer({ content, className, headingOffset, normalizeHeadings, images, }: MarkdownRendererProps): react_jsx_runtime.JSX.Element | null;
251
259
  /**
252
260
  * Render an **already-sanitised** HTML string through the same token-driven
253
261
  * component map as {@link MarkdownRenderer}. Consumers pass HTML that has been run
@@ -258,8 +266,10 @@ interface SafeHtmlProps {
258
266
  html: string | null | undefined;
259
267
  className?: string;
260
268
  headingOffset?: number;
269
+ /** See {@link MarkdownRendererProps.normalizeHeadings}. Default `false`. */
270
+ normalizeHeadings?: boolean;
261
271
  }
262
- declare function SafeHtml({ html, className, headingOffset }: SafeHtmlProps): react_jsx_runtime.JSX.Element | null;
272
+ declare function SafeHtml({ html, className, headingOffset, normalizeHeadings, }: SafeHtmlProps): react_jsx_runtime.JSX.Element | null;
263
273
 
264
274
  /** A heading level a caller can configure — `h1`…`h6`. */
265
275
  type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
package/dist/index.d.ts CHANGED
@@ -227,6 +227,14 @@ interface MarkdownRendererProps {
227
227
  * the page keeps a single h1.
228
228
  */
229
229
  headingOffset?: number;
230
+ /**
231
+ * Land the body's SHALLOWEST heading at `1 + headingOffset` instead of shifting every
232
+ * heading by a fixed amount, so standard Markdown (`##` sections) renders `<h2>` under
233
+ * the page `<h1>` just like the convention (`#` sections) does. Relative depth is kept
234
+ * and levels clamp at h6. Use it where the body sits directly under the page `<h1>`;
235
+ * leave it off where the body sits under its own section heading. Default `false`.
236
+ */
237
+ normalizeHeadings?: boolean;
230
238
  /**
231
239
  * Restrict and render images (REB-1075). Absent: every image the sanitiser keeps is
232
240
  * rendered as a lazy `<img>` inside its paragraph (the historical behaviour).
@@ -247,7 +255,7 @@ interface MarkdownImageOptions {
247
255
  alt: string;
248
256
  }) => React$1.ReactNode;
249
257
  }
250
- declare function MarkdownRenderer({ content, className, headingOffset, images, }: MarkdownRendererProps): react_jsx_runtime.JSX.Element | null;
258
+ declare function MarkdownRenderer({ content, className, headingOffset, normalizeHeadings, images, }: MarkdownRendererProps): react_jsx_runtime.JSX.Element | null;
251
259
  /**
252
260
  * Render an **already-sanitised** HTML string through the same token-driven
253
261
  * component map as {@link MarkdownRenderer}. Consumers pass HTML that has been run
@@ -258,8 +266,10 @@ interface SafeHtmlProps {
258
266
  html: string | null | undefined;
259
267
  className?: string;
260
268
  headingOffset?: number;
269
+ /** See {@link MarkdownRendererProps.normalizeHeadings}. Default `false`. */
270
+ normalizeHeadings?: boolean;
261
271
  }
262
- declare function SafeHtml({ html, className, headingOffset }: SafeHtmlProps): react_jsx_runtime.JSX.Element | null;
272
+ declare function SafeHtml({ html, className, headingOffset, normalizeHeadings, }: SafeHtmlProps): react_jsx_runtime.JSX.Element | null;
263
273
 
264
274
  /** A heading level a caller can configure — `h1`…`h6`. */
265
275
  type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
package/dist/index.js CHANGED
@@ -13131,8 +13131,25 @@ function slotClassName(structural, defaults, consumer) {
13131
13131
  // src/components/markdown-renderer.tsx
13132
13132
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13133
13133
  var HTML_TO_DOM_OPTIONS = { lowerCaseAttributeNames: false };
13134
- function parse3(html5, options) {
13135
- return domToReact(htmlToDOM(html5, HTML_TO_DOM_OPTIONS), options);
13134
+ function shallowestHeadingLevel(nodes) {
13135
+ let shallowest = null;
13136
+ for (const node of nodes) {
13137
+ if (!(node instanceof Element)) continue;
13138
+ const match = /^h([1-6])$/.exec(node.name);
13139
+ const level = match ? Number(match[1]) : shallowestHeadingLevel(node.children);
13140
+ if (level !== null && (shallowest === null || level < shallowest)) shallowest = level;
13141
+ }
13142
+ return shallowest;
13143
+ }
13144
+ function headingShift(nodes, headingOffset, normalize2) {
13145
+ if (!normalize2) return headingOffset;
13146
+ const shallowest = shallowestHeadingLevel(nodes);
13147
+ return shallowest === null ? headingOffset : 1 + headingOffset - shallowest;
13148
+ }
13149
+ function parse3(html5, headingOffset, normalizeHeadings, images) {
13150
+ const nodes = htmlToDOM(html5, HTML_TO_DOM_OPTIONS);
13151
+ const shift = headingShift(nodes, headingOffset, normalizeHeadings);
13152
+ return domToReact(nodes, buildOptions(shift, images));
13136
13153
  }
13137
13154
  function isAllowedImage(src, prefixes) {
13138
13155
  if (!src) return false;
@@ -13249,7 +13266,7 @@ function buildOptions(headingOffset, images) {
13249
13266
  const author = authorAttributes(node);
13250
13267
  const headingMatch = /^h([1-6])$/.exec(name);
13251
13268
  if (headingMatch) {
13252
- const rendered = Math.min(6, Number(headingMatch[1]) + headingOffset);
13269
+ const rendered = Math.max(1, Math.min(6, Number(headingMatch[1]) + headingOffset));
13253
13270
  const Tag = `h${rendered}`;
13254
13271
  return /* @__PURE__ */ jsx(Tag, { ...author, className: HEADING_CLASSES[rendered], children: children2() });
13255
13272
  }
@@ -13380,15 +13397,21 @@ function MarkdownRenderer({
13380
13397
  content,
13381
13398
  className,
13382
13399
  headingOffset = 0,
13400
+ normalizeHeadings = false,
13383
13401
  images
13384
13402
  }) {
13385
13403
  const html5 = markdownToSafeHtml(content);
13386
13404
  if (!html5) return null;
13387
- return /* @__PURE__ */ jsx("div", { className: slotClassName("max-w-none", "", className), "data-slot": "markdown", children: parse3(html5, buildOptions(headingOffset, images)) });
13405
+ return /* @__PURE__ */ jsx("div", { className: slotClassName("max-w-none", "", className), "data-slot": "markdown", children: parse3(html5, headingOffset, normalizeHeadings, images) });
13388
13406
  }
13389
- function SafeHtml({ html: html5, className, headingOffset = 0 }) {
13407
+ function SafeHtml({
13408
+ html: html5,
13409
+ className,
13410
+ headingOffset = 0,
13411
+ normalizeHeadings = false
13412
+ }) {
13390
13413
  if (!html5) return null;
13391
- return /* @__PURE__ */ jsx("div", { className: slotClassName("max-w-none", "", className), "data-slot": "safe-html", children: parse3(html5, buildOptions(headingOffset)) });
13414
+ return /* @__PURE__ */ jsx("div", { className: slotClassName("max-w-none", "", className), "data-slot": "safe-html", children: parse3(html5, headingOffset, normalizeHeadings) });
13392
13415
  }
13393
13416
 
13394
13417
  // src/components/course-description.tsx