jvetrau-ds 0.2.31 → 0.2.33

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.
@@ -50,7 +50,7 @@ export type { CardGroupProps } from './card-group/card-group';
50
50
  export { default as Breadcrumbs } from './breadcrumbs/breadcrumbs';
51
51
  export type { BreadcrumbsProps } from './breadcrumbs/breadcrumbs';
52
52
  export { default as Markdown } from './markdown/markdown';
53
- export type { MarkdownProps } from './markdown/markdown';
53
+ export type { MarkdownEmbed, MarkdownProps, } from './markdown/markdown';
54
54
  export { default as Discussion } from './discussion/discussion';
55
55
  export type { DiscussionItem, DiscussionProps, } from './discussion/discussion';
56
56
  export { default as CourseOutline } from './course-outline/course-outline';
@@ -1,2 +1,2 @@
1
1
  export { default } from './markdown';
2
- export type { MarkdownProps } from './markdown';
2
+ export type { MarkdownEmbed, MarkdownProps, } from './markdown';
@@ -2,6 +2,7 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var ReactMarkdown = require('react-markdown');
5
+ var remarkDirective = require('remark-directive');
5
6
  var remarkGfm = require('remark-gfm');
6
7
  require('./markdown.css');
7
8
  var classnames = require('../helpers/classnames');
@@ -9,6 +10,7 @@ var classnames = require('../helpers/classnames');
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
12
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
13
+ var remarkDirective__default = /*#__PURE__*/_interopDefault(remarkDirective);
12
14
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
13
15
 
14
16
  function normalizeHeadingLevelOffset(value) {
@@ -35,6 +37,55 @@ function appendNodesWithSeparator(target, nodes) {
35
37
  }
36
38
  target.push(...nodes);
37
39
  }
40
+ function getNodeText(node) {
41
+ if (typeof node.value === "string") {
42
+ return node.value;
43
+ }
44
+ return (node.children ?? []).map(getNodeText).join("");
45
+ }
46
+ function getEmbed(node) {
47
+ if (node.type !== "leafDirective" || node.name !== "embed") {
48
+ return null;
49
+ }
50
+ const src = node.attributes?.src ?? "";
51
+ const label = getNodeText(node);
52
+ if (!src.trim() || !label.trim()) {
53
+ return null;
54
+ }
55
+ return {
56
+ src,
57
+ label
58
+ };
59
+ }
60
+ function transformEmbedNodes(nodes) {
61
+ for (const node of nodes) {
62
+ if (node.type === "leafDirective" && node.name === "embed") {
63
+ const embed = getEmbed(node);
64
+ node.data = {
65
+ ...node.data,
66
+ hName: "div",
67
+ hProperties: embed ? {
68
+ "data-markdown-embed": "true",
69
+ "data-markdown-embed-src": embed.src,
70
+ "data-markdown-embed-label": embed.label
71
+ } : {
72
+ "data-markdown-embed": "invalid"
73
+ },
74
+ hChildren: []
75
+ };
76
+ continue;
77
+ }
78
+ if (node.children) {
79
+ transformEmbedNodes(node.children);
80
+ }
81
+ }
82
+ }
83
+ const remarkEmbed = () => {
84
+ return (tree) => {
85
+ const root = tree;
86
+ transformEmbedNodes(root.children);
87
+ };
88
+ };
38
89
  function flattenInlineNode(node) {
39
90
  switch (node.type) {
40
91
  case "html":
@@ -82,6 +133,12 @@ function flattenBlockNode(node) {
82
133
  value: node.value
83
134
  }
84
135
  ] : [];
136
+ case "leafDirective": {
137
+ const embed = getEmbed(node);
138
+ return embed ? [
139
+ createTextNode(embed.label)
140
+ ] : [];
141
+ }
85
142
  case "html":
86
143
  case "definition":
87
144
  case "footnoteDefinition":
@@ -142,7 +199,7 @@ const MarkdownHeading = ({
142
199
  return /* @__PURE__ */ jsxRuntime.jsx("h6", { ...props, children });
143
200
  }
144
201
  };
145
- function createDocumentComponents(headingLevelOffset) {
202
+ function createDocumentComponents(headingLevelOffset, renderEmbed) {
146
203
  return {
147
204
  h1: ({ node: _node, ...headingProps }) => /* @__PURE__ */ jsxRuntime.jsx(
148
205
  MarkdownHeading,
@@ -191,13 +248,35 @@ function createDocumentComponents(headingLevelOffset) {
191
248
  sourceLevel: 6,
192
249
  offset: headingLevelOffset
193
250
  }
194
- )
251
+ ),
252
+ div: ({
253
+ node: _node,
254
+ ...divProps
255
+ }) => {
256
+ const {
257
+ "data-markdown-embed": embedMarker,
258
+ "data-markdown-embed-src": embedSrc,
259
+ "data-markdown-embed-label": embedLabel,
260
+ ...props
261
+ } = divProps;
262
+ if (embedMarker !== void 0) {
263
+ if (embedMarker !== "true" || !embedSrc || !embedLabel || !renderEmbed) {
264
+ return null;
265
+ }
266
+ return renderEmbed({
267
+ src: embedSrc,
268
+ label: embedLabel
269
+ });
270
+ }
271
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...props });
272
+ }
195
273
  };
196
274
  }
197
275
  const Markdown = ({
198
276
  content,
199
277
  excerpt = false,
200
278
  headingLevelOffset = 0,
279
+ renderEmbed,
201
280
  className = "",
202
281
  ...props
203
282
  }) => {
@@ -218,6 +297,7 @@ const Markdown = ({
218
297
  {
219
298
  remarkPlugins: [
220
299
  remarkGfm__default.default,
300
+ remarkDirective__default.default,
221
301
  remarkExcerpt
222
302
  ],
223
303
  children: content
@@ -228,7 +308,8 @@ const Markdown = ({
228
308
  }
229
309
  const normalizedHeadingLevelOffset = normalizeHeadingLevelOffset(headingLevelOffset);
230
310
  const documentComponents = createDocumentComponents(
231
- normalizedHeadingLevelOffset
311
+ normalizedHeadingLevelOffset,
312
+ renderEmbed
232
313
  );
233
314
  return /* @__PURE__ */ jsxRuntime.jsx(
234
315
  "div",
@@ -238,7 +319,11 @@ const Markdown = ({
238
319
  children: /* @__PURE__ */ jsxRuntime.jsx(
239
320
  ReactMarkdown__default.default,
240
321
  {
241
- remarkPlugins: [remarkGfm__default.default],
322
+ remarkPlugins: [
323
+ remarkGfm__default.default,
324
+ remarkDirective__default.default,
325
+ remarkEmbed
326
+ ],
242
327
  components: documentComponents,
243
328
  children: content
244
329
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":["jsx","classnames","ReactMarkdown","remarkGfm"],"mappings":"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","file":"markdown.cjs","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNode = {\n type: string;\n value?: string;\n alt?: string | null;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":["jsx","classnames","ReactMarkdown","remarkGfm","remarkDirective"],"mappings":"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","file":"markdown.cjs","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
@@ -1,9 +1,14 @@
1
1
  import React from 'react';
2
2
  import './markdown.css';
3
+ export interface MarkdownEmbed {
4
+ src: string;
5
+ label: string;
6
+ }
3
7
  export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {
4
8
  content: string;
5
9
  excerpt?: boolean;
6
10
  headingLevelOffset?: number;
11
+ renderEmbed?: (embed: MarkdownEmbed) => React.ReactNode;
7
12
  }
8
13
  declare const Markdown: React.FC<MarkdownProps>;
9
14
  export default Markdown;
@@ -1,5 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import ReactMarkdown from 'react-markdown';
3
+ import remarkDirective from 'remark-directive';
3
4
  import remarkGfm from 'remark-gfm';
4
5
  import './markdown.css';
5
6
  import { classnames } from '../helpers/classnames';
@@ -28,6 +29,55 @@ function appendNodesWithSeparator(target, nodes) {
28
29
  }
29
30
  target.push(...nodes);
30
31
  }
32
+ function getNodeText(node) {
33
+ if (typeof node.value === "string") {
34
+ return node.value;
35
+ }
36
+ return (node.children ?? []).map(getNodeText).join("");
37
+ }
38
+ function getEmbed(node) {
39
+ if (node.type !== "leafDirective" || node.name !== "embed") {
40
+ return null;
41
+ }
42
+ const src = node.attributes?.src ?? "";
43
+ const label = getNodeText(node);
44
+ if (!src.trim() || !label.trim()) {
45
+ return null;
46
+ }
47
+ return {
48
+ src,
49
+ label
50
+ };
51
+ }
52
+ function transformEmbedNodes(nodes) {
53
+ for (const node of nodes) {
54
+ if (node.type === "leafDirective" && node.name === "embed") {
55
+ const embed = getEmbed(node);
56
+ node.data = {
57
+ ...node.data,
58
+ hName: "div",
59
+ hProperties: embed ? {
60
+ "data-markdown-embed": "true",
61
+ "data-markdown-embed-src": embed.src,
62
+ "data-markdown-embed-label": embed.label
63
+ } : {
64
+ "data-markdown-embed": "invalid"
65
+ },
66
+ hChildren: []
67
+ };
68
+ continue;
69
+ }
70
+ if (node.children) {
71
+ transformEmbedNodes(node.children);
72
+ }
73
+ }
74
+ }
75
+ const remarkEmbed = () => {
76
+ return (tree) => {
77
+ const root = tree;
78
+ transformEmbedNodes(root.children);
79
+ };
80
+ };
31
81
  function flattenInlineNode(node) {
32
82
  switch (node.type) {
33
83
  case "html":
@@ -75,6 +125,12 @@ function flattenBlockNode(node) {
75
125
  value: node.value
76
126
  }
77
127
  ] : [];
128
+ case "leafDirective": {
129
+ const embed = getEmbed(node);
130
+ return embed ? [
131
+ createTextNode(embed.label)
132
+ ] : [];
133
+ }
78
134
  case "html":
79
135
  case "definition":
80
136
  case "footnoteDefinition":
@@ -135,7 +191,7 @@ const MarkdownHeading = ({
135
191
  return /* @__PURE__ */ jsx("h6", { ...props, children });
136
192
  }
137
193
  };
138
- function createDocumentComponents(headingLevelOffset) {
194
+ function createDocumentComponents(headingLevelOffset, renderEmbed) {
139
195
  return {
140
196
  h1: ({ node: _node, ...headingProps }) => /* @__PURE__ */ jsx(
141
197
  MarkdownHeading,
@@ -184,13 +240,35 @@ function createDocumentComponents(headingLevelOffset) {
184
240
  sourceLevel: 6,
185
241
  offset: headingLevelOffset
186
242
  }
187
- )
243
+ ),
244
+ div: ({
245
+ node: _node,
246
+ ...divProps
247
+ }) => {
248
+ const {
249
+ "data-markdown-embed": embedMarker,
250
+ "data-markdown-embed-src": embedSrc,
251
+ "data-markdown-embed-label": embedLabel,
252
+ ...props
253
+ } = divProps;
254
+ if (embedMarker !== void 0) {
255
+ if (embedMarker !== "true" || !embedSrc || !embedLabel || !renderEmbed) {
256
+ return null;
257
+ }
258
+ return renderEmbed({
259
+ src: embedSrc,
260
+ label: embedLabel
261
+ });
262
+ }
263
+ return /* @__PURE__ */ jsx("div", { ...props });
264
+ }
188
265
  };
189
266
  }
190
267
  const Markdown = ({
191
268
  content,
192
269
  excerpt = false,
193
270
  headingLevelOffset = 0,
271
+ renderEmbed,
194
272
  className = "",
195
273
  ...props
196
274
  }) => {
@@ -211,6 +289,7 @@ const Markdown = ({
211
289
  {
212
290
  remarkPlugins: [
213
291
  remarkGfm,
292
+ remarkDirective,
214
293
  remarkExcerpt
215
294
  ],
216
295
  children: content
@@ -221,7 +300,8 @@ const Markdown = ({
221
300
  }
222
301
  const normalizedHeadingLevelOffset = normalizeHeadingLevelOffset(headingLevelOffset);
223
302
  const documentComponents = createDocumentComponents(
224
- normalizedHeadingLevelOffset
303
+ normalizedHeadingLevelOffset,
304
+ renderEmbed
225
305
  );
226
306
  return /* @__PURE__ */ jsx(
227
307
  "div",
@@ -231,7 +311,11 @@ const Markdown = ({
231
311
  children: /* @__PURE__ */ jsx(
232
312
  ReactMarkdown,
233
313
  {
234
- remarkPlugins: [remarkGfm],
314
+ remarkPlugins: [
315
+ remarkGfm,
316
+ remarkDirective,
317
+ remarkEmbed
318
+ ],
235
319
  components: documentComponents,
236
320
  children: content
237
321
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"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","file":"markdown.js","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNode = {\n type: string;\n value?: string;\n alt?: string | null;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"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","file":"markdown.js","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
package/index.d.ts CHANGED
@@ -58,7 +58,7 @@ export type { CardGroupProps } from './components/card-group';
58
58
  export { default as Breadcrumbs } from './components/breadcrumbs';
59
59
  export type { BreadcrumbsProps } from './components/breadcrumbs';
60
60
  export { default as Markdown } from './components/markdown';
61
- export type { MarkdownProps } from './components/markdown';
61
+ export type { MarkdownEmbed, MarkdownProps, } from './components/markdown';
62
62
  export { default as Discussion } from './components/discussion';
63
63
  export type { DiscussionItem, DiscussionProps, } from './components/discussion';
64
64
  export { default as CourseOutline } from './components/course-outline';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvetrau-ds",
3
- "version": "0.2.31",
3
+ "version": "0.2.33",
4
4
  "description": "Multi-brand React design system with semantic tokens",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -52,6 +52,7 @@
52
52
  "dependencies": {
53
53
  "hls.js": "^1.6.16",
54
54
  "react-markdown": "^10.1.0",
55
+ "remark-directive": "^4.0.0",
55
56
  "remark-gfm": "^4.0.1"
56
57
  }
57
58
  }