@memberjunction/ng-markdown 6.2.0-edge.2 → 6.2.0-edge.4

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/README.md CHANGED
@@ -83,6 +83,7 @@ export class YourModule {}
83
83
  |---------|---------|-------------|
84
84
  | Syntax highlighting | Enabled | Prism.js with Okaidia theme |
85
85
  | Mermaid diagrams | Enabled | Render mermaid code blocks as diagrams |
86
+ | Math | Enabled | TeX (`$…$` / `\(…\)` inline, `$$…$$` / `\[…\]` display), typeset as MathML by KaTeX (loaded on first use), and MathML markup, including JATS-style `<mml:math>` |
86
87
  | Code copy button | Enabled | Copy-to-clipboard on hover |
87
88
  | GitHub-style alerts | Enabled | `[!NOTE]`, `[!TIP]`, `[!WARNING]` blockquotes |
88
89
  | Smartypants typography | Enabled | Curly quotes, em/en dashes, ellipsis |
@@ -98,6 +99,7 @@ export class YourModule {}
98
99
  | `data` | `string` | `''` | Markdown content to render |
99
100
  | `enableHighlight` | `boolean` | `true` | Prism.js syntax highlighting |
100
101
  | `enableMermaid` | `boolean` | `true` | Mermaid diagram rendering |
102
+ | `EnableMath` | `boolean` | `true` | TeX math, and keeping markdown out of MathML markup (`<mml:math>` needs it; unprefixed `<math>` renders either way, since the sanitizer allows MathML). Single dollars follow Pandoc's rule, so `$5 and $10` stays text; `\$` is a literal dollar. PascalCase only: unlike the older inputs above, it has no lowercase alias |
101
103
  | `enableCodeCopy` | `boolean` | `true` | Copy button on code blocks |
102
104
  | `enableCollapsibleHeadings` | `boolean` | `false` | Collapsible heading sections |
103
105
  | `collapsibleHeadingLevel` | `1-6` | `2` | Heading level to start collapsing |
@@ -138,6 +140,7 @@ export class YourModule {}
138
140
  - `marked-smartypants` -- Typography improvements
139
141
  - `prismjs` -- Syntax highlighting
140
142
  - `mermaid` -- Diagram rendering
143
+ - `katex` -- TeX math typesetting (MathML output, so no KaTeX stylesheet or fonts are needed)
141
144
 
142
145
  ## Related Packages
143
146
 
@@ -54,6 +54,10 @@ export declare class MarkdownComponent implements OnChanges, AfterViewInit, OnDe
54
54
  set enableMermaid(value: boolean);
55
55
  /** @deprecated Use {@link EnableMermaid}. */
56
56
  get enableMermaid(): boolean;
57
+ /**
58
+ * Enable TeX math (`$…$`, `$$…$$`, `\(…\)`, `\[…\]`), typeset as MathML
59
+ */
60
+ EnableMath: boolean;
57
61
  /**
58
62
  * Enable copy button on code blocks
59
63
  */
@@ -247,6 +251,7 @@ export declare class MarkdownComponent implements OnChanges, AfterViewInit, OnDe
247
251
  get element(): ElementRef<HTMLElement>;
248
252
  private renderStartTime;
249
253
  private hasMermaid;
254
+ private hasMath;
250
255
  private hasCodeBlocks;
251
256
  private themeObserver;
252
257
  constructor(elementRef: ElementRef<HTMLElement>, sanitizer: DomSanitizer, markdownService: MarkdownService, cdr: ChangeDetectorRef);
@@ -326,6 +331,6 @@ export declare class MarkdownComponent implements OnChanges, AfterViewInit, OnDe
326
331
  /** @deprecated Use {@link ScrollToHeading}. */
327
332
  scrollToHeading(headingId: string): void;
328
333
  static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownComponent, never>;
329
- static ɵcmp: i0.ɵɵComponentDeclaration<MarkdownComponent, "mj-markdown", never, { "Data": { "alias": "Data"; "required": false; }; "data": { "alias": "data"; "required": false; }; "EnableHighlight": { "alias": "EnableHighlight"; "required": false; }; "enableHighlight": { "alias": "enableHighlight"; "required": false; }; "EnableMermaid": { "alias": "EnableMermaid"; "required": false; }; "enableMermaid": { "alias": "enableMermaid"; "required": false; }; "EnableCodeCopy": { "alias": "EnableCodeCopy"; "required": false; }; "enableCodeCopy": { "alias": "enableCodeCopy"; "required": false; }; "EnableCollapsibleHeadings": { "alias": "EnableCollapsibleHeadings"; "required": false; }; "enableCollapsibleHeadings": { "alias": "enableCollapsibleHeadings"; "required": false; }; "CollapsibleHeadingLevel": { "alias": "CollapsibleHeadingLevel"; "required": false; }; "collapsibleHeadingLevel": { "alias": "collapsibleHeadingLevel"; "required": false; }; "CollapsibleDefaultExpanded": { "alias": "CollapsibleDefaultExpanded"; "required": false; }; "collapsibleDefaultExpanded": { "alias": "collapsibleDefaultExpanded"; "required": false; }; "AutoExpandLevels": { "alias": "AutoExpandLevels"; "required": false; }; "autoExpandLevels": { "alias": "autoExpandLevels"; "required": false; }; "EnableAlerts": { "alias": "EnableAlerts"; "required": false; }; "enableAlerts": { "alias": "enableAlerts"; "required": false; }; "EnableSmartypants": { "alias": "EnableSmartypants"; "required": false; }; "enableSmartypants": { "alias": "enableSmartypants"; "required": false; }; "EnableSvgRenderer": { "alias": "EnableSvgRenderer"; "required": false; }; "enableSvgRenderer": { "alias": "enableSvgRenderer"; "required": false; }; "EnableHtml": { "alias": "EnableHtml"; "required": false; }; "enableHtml": { "alias": "enableHtml"; "required": false; }; "EnableJavaScript": { "alias": "EnableJavaScript"; "required": false; }; "enableJavaScript": { "alias": "enableJavaScript"; "required": false; }; "EnableHeadingIds": { "alias": "EnableHeadingIds"; "required": false; }; "enableHeadingIds": { "alias": "enableHeadingIds"; "required": false; }; "HeadingIdPrefix": { "alias": "HeadingIdPrefix"; "required": false; }; "headingIdPrefix": { "alias": "headingIdPrefix"; "required": false; }; "EnableLineNumbers": { "alias": "EnableLineNumbers"; "required": false; }; "enableLineNumbers": { "alias": "enableLineNumbers"; "required": false; }; "ContainerClass": { "alias": "ContainerClass"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "MermaidTheme": { "alias": "MermaidTheme"; "required": false; }; "mermaidTheme": { "alias": "mermaidTheme"; "required": false; }; "Sanitize": { "alias": "Sanitize"; "required": false; }; "sanitize": { "alias": "sanitize"; "required": false; }; }, { "Rendered": "Rendered"; "rendered": "rendered"; "HeadingClick": "HeadingClick"; "headingClick": "headingClick"; "CodeCopied": "CodeCopied"; "codeCopied": "codeCopied"; }, never, never, false, never>;
334
+ static ɵcmp: i0.ɵɵComponentDeclaration<MarkdownComponent, "mj-markdown", never, { "Data": { "alias": "Data"; "required": false; }; "data": { "alias": "data"; "required": false; }; "EnableHighlight": { "alias": "EnableHighlight"; "required": false; }; "enableHighlight": { "alias": "enableHighlight"; "required": false; }; "EnableMermaid": { "alias": "EnableMermaid"; "required": false; }; "enableMermaid": { "alias": "enableMermaid"; "required": false; }; "EnableMath": { "alias": "EnableMath"; "required": false; }; "EnableCodeCopy": { "alias": "EnableCodeCopy"; "required": false; }; "enableCodeCopy": { "alias": "enableCodeCopy"; "required": false; }; "EnableCollapsibleHeadings": { "alias": "EnableCollapsibleHeadings"; "required": false; }; "enableCollapsibleHeadings": { "alias": "enableCollapsibleHeadings"; "required": false; }; "CollapsibleHeadingLevel": { "alias": "CollapsibleHeadingLevel"; "required": false; }; "collapsibleHeadingLevel": { "alias": "collapsibleHeadingLevel"; "required": false; }; "CollapsibleDefaultExpanded": { "alias": "CollapsibleDefaultExpanded"; "required": false; }; "collapsibleDefaultExpanded": { "alias": "collapsibleDefaultExpanded"; "required": false; }; "AutoExpandLevels": { "alias": "AutoExpandLevels"; "required": false; }; "autoExpandLevels": { "alias": "autoExpandLevels"; "required": false; }; "EnableAlerts": { "alias": "EnableAlerts"; "required": false; }; "enableAlerts": { "alias": "enableAlerts"; "required": false; }; "EnableSmartypants": { "alias": "EnableSmartypants"; "required": false; }; "enableSmartypants": { "alias": "enableSmartypants"; "required": false; }; "EnableSvgRenderer": { "alias": "EnableSvgRenderer"; "required": false; }; "enableSvgRenderer": { "alias": "enableSvgRenderer"; "required": false; }; "EnableHtml": { "alias": "EnableHtml"; "required": false; }; "enableHtml": { "alias": "enableHtml"; "required": false; }; "EnableJavaScript": { "alias": "EnableJavaScript"; "required": false; }; "enableJavaScript": { "alias": "enableJavaScript"; "required": false; }; "EnableHeadingIds": { "alias": "EnableHeadingIds"; "required": false; }; "enableHeadingIds": { "alias": "enableHeadingIds"; "required": false; }; "HeadingIdPrefix": { "alias": "HeadingIdPrefix"; "required": false; }; "headingIdPrefix": { "alias": "headingIdPrefix"; "required": false; }; "EnableLineNumbers": { "alias": "EnableLineNumbers"; "required": false; }; "enableLineNumbers": { "alias": "enableLineNumbers"; "required": false; }; "ContainerClass": { "alias": "ContainerClass"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "MermaidTheme": { "alias": "MermaidTheme"; "required": false; }; "mermaidTheme": { "alias": "mermaidTheme"; "required": false; }; "Sanitize": { "alias": "Sanitize"; "required": false; }; "sanitize": { "alias": "sanitize"; "required": false; }; }, { "Rendered": "Rendered"; "rendered": "rendered"; "HeadingClick": "HeadingClick"; "headingClick": "headingClick"; "CodeCopied": "CodeCopied"; "codeCopied": "codeCopied"; }, never, never, false, never>;
330
335
  }
331
336
  //# sourceMappingURL=markdown.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from 'vitest';
1
+ import { describe, it, expect, vi } from 'vitest';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { renderComponentFixture, query, capture } from '@memberjunction/ng-test-utils';
4
4
  import { MarkdownComponent } from './markdown.component';
@@ -77,6 +77,45 @@ describe('MarkdownComponent (DOM)', () => {
77
77
  expect(events.length).toBeGreaterThanOrEqual(1);
78
78
  expect(events[events.length - 1].hasCodeBlocks).toBe(false);
79
79
  });
80
+ describe('TeX math', () => {
81
+ // postRenderProcessing awaits the lazily-imported KaTeX chunk, so wait for the typeset
82
+ // output rather than for a fixed number of microtasks.
83
+ const typesetIn = async (f) => {
84
+ const c = container(f);
85
+ await vi.waitFor(() => expect(c.querySelector('math')).not.toBeNull());
86
+ return c;
87
+ };
88
+ it('typesets inline and display math after render', async () => {
89
+ const c = await typesetIn(render({ data: 'Area $\\pi r^2$\n\n$$\n\\sum_{i=1}^n i\n$$' }));
90
+ expect(c.querySelectorAll('math').length).toBe(2);
91
+ expect(c.querySelector('math[display="block"] munderover')).not.toBeNull();
92
+ expect(c.querySelector('code.mj-math')).toBeNull();
93
+ });
94
+ it('typesets through the Angular sanitizer path too (no passthrough, no SVG renderer)', async () => {
95
+ const c = await typesetIn(render({ data: 'so $x_i + y_j$ holds', enableSvgRenderer: false }));
96
+ expect(c.querySelector('em')).toBeNull();
97
+ expect(c.querySelector('annotation')?.textContent).toBe('x_i + y_j');
98
+ });
99
+ it('renders a JATS MathML formula and fixes its styled letters', async () => {
100
+ const f = render({ data: 'Field <mml:math><mml:mi mathvariant="bold">E</mml:mi></mml:math> here' });
101
+ const c = container(f);
102
+ await vi.waitFor(() => expect(c.querySelector('mi')?.textContent).toBe('𝐄'));
103
+ expect(c.querySelector('math')?.namespaceURI).toBe('http://www.w3.org/1998/Math/MathML');
104
+ });
105
+ it('EnableMath=false leaves the dollars as text', async () => {
106
+ const f = render({ data: '$x^2$', EnableMath: false });
107
+ await Promise.resolve();
108
+ await Promise.resolve();
109
+ expect(container(f).querySelector('math, code.mj-math')).toBeNull();
110
+ expect(container(f).textContent).toContain('$x^2$');
111
+ });
112
+ it('EnableMath=false still fixes the styled letters of MathML markup', async () => {
113
+ const f = render({ data: 'Field <math><mi mathvariant="bold">E</mi></math> here', EnableMath: false });
114
+ const c = container(f);
115
+ await vi.waitFor(() => expect(c.querySelector('mi')?.textContent).toBe('𝐄'));
116
+ expect(c.querySelector('mi[mathvariant]')).toBeNull();
117
+ });
118
+ });
80
119
  /**
81
120
  * Sanitization, as seen through the component. With `enableHtml` or the default
82
121
  * `enableSvgRenderer`, Angular's sanitizer is bypassed and the HTML the service returns
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.component.dom.test.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from 'vitest';\nimport { ComponentFixture } from '@angular/core/testing';\nimport { CommonModule } from '@angular/common';\nimport { renderComponentFixture, query, capture } from '@memberjunction/ng-test-utils';\nimport { MarkdownComponent } from './markdown.component';\nimport { MarkdownRenderEvent } from '@memberjunction/markdown-core';\n\n/**\n * DOM-level spec for <mj-markdown>. The component is module-declared\n * (standalone:false), so we render it via `declarations` + `imports: [CommonModule]`\n * and configure it through `@Input`s.\n *\n * It uses the real (providedIn:'root') MarkdownService, which parses markdown\n * synchronously via marked.js. We assert on the rendered output that lands in the\n * `[innerHTML]`-bound container, plus the container-class binding and the `rendered`\n * @Output. Mermaid/Prism async post-processing is NOT asserted here (mermaid needs a\n * real browser; that's a live-test concern) — we only verify the deterministic,\n * media-free template surface.\n */\ndescribe('MarkdownComponent (DOM)', () => {\n function render(inputs: Record<string, unknown>): ComponentFixture<MarkdownComponent> {\n return renderComponentFixture(MarkdownComponent, {\n imports: [CommonModule],\n declarations: [MarkdownComponent],\n inputs,\n });\n }\n\n const container = (f: ComponentFixture<MarkdownComponent>): HTMLElement => f.nativeElement.querySelector('.mj-markdown-container') as HTMLElement;\n\n it('renders the static container element', () => {\n const f = render({ data: '' });\n expect(query(f, '.mj-markdown-container')).not.toBeNull();\n });\n\n it('renders markdown content into the innerHTML-bound container', () => {\n const f = render({ data: '# Hello World' });\n const c = container(f);\n const heading = c.querySelector('h1');\n expect(heading).not.toBeNull();\n expect(heading!.textContent).toContain('Hello World');\n });\n\n it('renders inline markdown formatting (bold) as the corresponding HTML element', () => {\n const f = render({ data: 'This is **strong** text' });\n expect(container(f).querySelector('strong')?.textContent).toBe('strong');\n });\n\n it('renders a fenced code block as a <pre><code> structure', () => {\n const f = render({ data: '```\\nconst x = 1;\\n```' });\n const c = container(f);\n expect(c.querySelector('pre')).not.toBeNull();\n expect(c.querySelector('pre code')).not.toBeNull();\n });\n\n it('renders an empty container when data is empty', () => {\n const f = render({ data: '' });\n // No data => renderedContent stays '' => no rendered child markup.\n expect(container(f).children.length).toBe(0);\n });\n\n it('applies the containerClass input to the container element', () => {\n const f = render({ data: '# X', containerClass: 'my-custom-class' });\n expect(container(f).classList.contains('my-custom-class')).toBe(true);\n });\n\n it('emits the rendered @Output with hasCodeBlocks=true for code content', async () => {\n const f = render({ data: '' });\n const events = capture<MarkdownRenderEvent>(f.componentInstance.rendered);\n\n // Setting data after first render drives ngOnChanges -> render() -> postRenderProcessing\n // is scheduled on a microtask. Use setInput (zoneless-correct), then flush the microtask.\n f.componentRef.setInput('data', '```\\nconst x = 1;\\n```');\n f.detectChanges();\n await Promise.resolve();\n await Promise.resolve();\n\n expect(events.length).toBeGreaterThanOrEqual(1);\n const last = events[events.length - 1];\n expect(last.hasCodeBlocks).toBe(true);\n expect(last.hasMermaid).toBe(false);\n });\n\n it('emits the rendered @Output with hasCodeBlocks=false for prose-only content', async () => {\n const f = render({ data: '' });\n const events = capture<MarkdownRenderEvent>(f.componentInstance.rendered);\n\n f.componentRef.setInput('data', 'Just some plain prose.');\n f.detectChanges();\n await Promise.resolve();\n await Promise.resolve();\n\n expect(events.length).toBeGreaterThanOrEqual(1);\n expect(events[events.length - 1].hasCodeBlocks).toBe(false);\n });\n\n /**\n * Sanitization, as seen through the component. With `enableHtml` or the default\n * `enableSvgRenderer`, Angular's sanitizer is bypassed and the HTML the service returns\n * (sanitized by DOMPurify in parse()) is trusted. jsdom does not execute handlers or\n * load images, so assertions are structural: the vector is gone, the layout survives.\n */\n describe('sanitization', () => {\n const attributeNamesIn = (root: HTMLElement): string[] =>\n Array.from(root.querySelectorAll('*')).flatMap((el) => Array.from(el.attributes).map((a) => a.name.toLowerCase()));\n const passthrough = (data: string) => container(render({ data, enableHtml: true }));\n\n it('removes <script> elements, including ones with a spaced end tag', () => {\n const c = passthrough('<div>before</div><script>alert(1)</script ><div>after</div>');\n expect(c.querySelector('script')).toBeNull();\n expect(c.textContent).toContain('before');\n expect(c.textContent).toContain('after');\n expect(c.textContent).not.toContain('alert(1)');\n });\n\n it('removes every on* handler, whatever its name or quoting', () => {\n const c = passthrough('<img src=\"x\" onerror=\"alert(1)\"><div onpointerrawupdate=alert(1) ONMOUSEENTER=\"alert(1)\">t</div><svg onload=\"alert(1)\"><circle r=\"1\"/></svg>');\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n expect(c.querySelector('img')).not.toBeNull();\n expect(c.querySelector('svg circle')).not.toBeNull();\n });\n\n it.each([\n ['javascript:', '<a href=\"javascript:alert(1)\">x</a>'],\n ['vbscript:', '<a href=\"vbscript:msgbox(1)\">x</a>'],\n ['data:text/html', '<a href=\"data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==\">x</a>'],\n ['data:image/svg+xml on a link', '<a href=\"data:image/svg+xml;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+PC9zdmc+\">x</a>'],\n ['whitespace inside the scheme', '<a href=\"java\\tscript:alert(1)\">x</a>'],\n ['entity inside the scheme', '<a href=\"jav&#x09;ascript:alert(1)\">x</a>'],\n ['newline inside the scheme', '<a href=\"java\\nscript:alert(1)\">x</a>'],\n ['upper-case scheme', '<a href=\"JAVASCRIPT:alert(1)\">x</a>'],\n ])('drops the link target for %s', (_label, html) => {\n const a = passthrough(html).querySelector('a');\n expect(a).not.toBeNull();\n expect(a?.hasAttribute('href')).toBe(false);\n });\n\n it('drops javascript: from a form action', () => {\n const c = passthrough('<form action=\"javascript:alert(1)\"><button>go</button></form>');\n expect(c.querySelector('form')?.hasAttribute('action')).toBe(false);\n });\n\n it.each([\n ['iframe', '<iframe src=\"https://evil.test/\"></iframe>'],\n ['iframe with srcdoc', '<iframe srcdoc=\"&lt;script&gt;alert(1)&lt;/script&gt;\"></iframe>'],\n ['object', '<object data=\"https://evil.test/x.swf\"></object>'],\n ['embed', '<embed src=\"https://evil.test/x.swf\">'],\n ['base', '<base href=\"https://evil.test/\">'],\n ])('removes %s while keeping the surrounding content', (_label, html) => {\n const c = passthrough('<p>before</p>' + html + '<p>after</p>');\n expect(c.querySelector('iframe, object, embed, base')).toBeNull();\n expect(c.textContent).toContain('before');\n expect(c.textContent).toContain('after');\n });\n\n it('removes <foreignObject> and SMIL animation from inline SVG, keeps shapes', () => {\n const c = passthrough('<svg><foreignObject><body onload=\"alert(1)\"></body></foreignObject><circle r=\"1\"><animate attributeName=\"r\" to=\"2\"/></circle></svg>');\n expect(c.querySelector('foreignObject, animate')).toBeNull();\n expect(c.querySelector('svg circle')).not.toBeNull();\n });\n\n it('keeps a same-document <use> and removes an external one', () => {\n const c = passthrough('<svg><defs><symbol id=\"ic\"><circle r=\"1\"/></symbol></defs><use href=\"#ic\"/><use href=\"https://evil.test/s.svg#x\"/></svg>');\n const uses = Array.from(c.querySelectorAll('use')).map((u) => u.getAttribute('href'));\n expect(uses).toEqual(['#ic']);\n });\n\n it('keeps layout HTML, inline styles, data attributes and data: images', () => {\n const c = passthrough(\n '<table class=\"grid\" data-role=\"report\"><tr><td style=\"color: red\">cell</td></tr></table>' +\n '<input type=\"text\" value=\"v\"><details><summary>s</summary>body</details>' +\n '<img src=\"data:image/png;base64,iVBORw0KGgo=\" alt=\"pixel\">',\n );\n expect(c.querySelector('table.grid')?.getAttribute('data-role')).toBe('report');\n expect(c.querySelector('td')?.getAttribute('style')).toContain('color');\n expect(c.querySelector('input')?.getAttribute('value')).toBe('v');\n expect(c.querySelector('details summary')?.textContent).toBe('s');\n expect(c.querySelector('img')?.getAttribute('src')).toMatch(/^data:image\\/png/);\n });\n\n it('keeps a leading <style> block (mockups start that way)', () => {\n const c = passthrough('<style>.card{color:red}</style><div class=\"card\">x</div>');\n expect(c.querySelector('style')?.textContent).toContain('.card');\n expect(c.querySelector('div.card')).not.toBeNull();\n });\n\n it('keeps target on links and enforces rel=noopener', () => {\n const c = passthrough('<a href=\"https://example.test/page\" target=\"_blank\">site</a><a href=\"#section\">local</a>');\n const [ext, local] = Array.from(c.querySelectorAll('a'));\n expect(ext.getAttribute('href')).toBe('https://example.test/page');\n expect(ext.getAttribute('target')).toBe('_blank');\n expect(ext.getAttribute('rel')).toContain('noopener');\n expect(local.getAttribute('href')).toBe('#section');\n expect(local.hasAttribute('rel')).toBe(false);\n });\n\n it('keeps heading ids that collide with document properties', () => {\n // DOMPurify's default DOM-clobbering guard would strip these; heading anchors must work.\n const c = container(render({ data: '# Title' + '\\n\\n' + '## Location' + '\\n\\n' + '## Overview' }));\n expect(c.querySelector('h1')?.id).toBe('title');\n expect(c.querySelector('h2')?.id).toBe('location');\n expect(Array.from(c.querySelectorAll('h2')).map((h) => h.id)).toEqual(['location', 'overview']);\n });\n\n it('sanitizes HTML that marked miscoded into a code block and the service unwrapped', () => {\n // A bare fenced block whose text is structural HTML is unwrapped by the service (no\n // language class), then sanitized like any other passthrough markup.\n const c = passthrough('```' + '\\n' + '<div class=\"card\"><img src=\"x\" onerror=\"alert(1)\"><p>inner</p></div>' + '\\n' + '```');\n expect(c.querySelector('pre')).toBeNull();\n expect(c.querySelector('div.card p')?.textContent).toBe('inner');\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n\n it('strips handlers and script from a rendered SVG code fence (enableSvgRenderer)', () => {\n const data = '```svg' + '\\n' + '<svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"alert(1)\"><script>alert(2)</script><circle r=\"1\"/></svg>' + '\\n' + '```';\n const c = container(render({ data, enableSvgRenderer: true }));\n expect(c.querySelector('svg')).not.toBeNull();\n expect(c.querySelector('script')).toBeNull();\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n\n it('enableJavaScript=true is the documented opt-out and leaves script elements in place', () => {\n // jsdom (as vitest configures it) executes this script and logs \"Not implemented:\n // window.alert\" to stderr. Expected here and only here.\n const c = container(render({ data: '<div>x</div><script>alert(1)</script>', enableHtml: true, enableJavaScript: true }));\n expect(c.querySelector('script')).not.toBeNull();\n });\n\n it('Angular sanitizer path (no passthrough, no SVG renderer) still strips handlers', () => {\n const c = container(render({ data: 'text <img src=\"x\" onerror=\"alert(1)\">', enableSvgRenderer: false }));\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"markdown.component.dom.test.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, vi } from 'vitest';\nimport { ComponentFixture } from '@angular/core/testing';\nimport { CommonModule } from '@angular/common';\nimport { renderComponentFixture, query, capture } from '@memberjunction/ng-test-utils';\nimport { MarkdownComponent } from './markdown.component';\nimport { MarkdownRenderEvent } from '@memberjunction/markdown-core';\n\n/**\n * DOM-level spec for <mj-markdown>. The component is module-declared\n * (standalone:false), so we render it via `declarations` + `imports: [CommonModule]`\n * and configure it through `@Input`s.\n *\n * It uses the real (providedIn:'root') MarkdownService, which parses markdown\n * synchronously via marked.js. We assert on the rendered output that lands in the\n * `[innerHTML]`-bound container, plus the container-class binding and the `rendered`\n * @Output. Mermaid/Prism async post-processing is NOT asserted here (mermaid needs a\n * real browser; that's a live-test concern) — we only verify the deterministic,\n * media-free template surface.\n */\ndescribe('MarkdownComponent (DOM)', () => {\n function render(inputs: Record<string, unknown>): ComponentFixture<MarkdownComponent> {\n return renderComponentFixture(MarkdownComponent, {\n imports: [CommonModule],\n declarations: [MarkdownComponent],\n inputs,\n });\n }\n\n const container = (f: ComponentFixture<MarkdownComponent>): HTMLElement => f.nativeElement.querySelector('.mj-markdown-container') as HTMLElement;\n\n it('renders the static container element', () => {\n const f = render({ data: '' });\n expect(query(f, '.mj-markdown-container')).not.toBeNull();\n });\n\n it('renders markdown content into the innerHTML-bound container', () => {\n const f = render({ data: '# Hello World' });\n const c = container(f);\n const heading = c.querySelector('h1');\n expect(heading).not.toBeNull();\n expect(heading!.textContent).toContain('Hello World');\n });\n\n it('renders inline markdown formatting (bold) as the corresponding HTML element', () => {\n const f = render({ data: 'This is **strong** text' });\n expect(container(f).querySelector('strong')?.textContent).toBe('strong');\n });\n\n it('renders a fenced code block as a <pre><code> structure', () => {\n const f = render({ data: '```\\nconst x = 1;\\n```' });\n const c = container(f);\n expect(c.querySelector('pre')).not.toBeNull();\n expect(c.querySelector('pre code')).not.toBeNull();\n });\n\n it('renders an empty container when data is empty', () => {\n const f = render({ data: '' });\n // No data => renderedContent stays '' => no rendered child markup.\n expect(container(f).children.length).toBe(0);\n });\n\n it('applies the containerClass input to the container element', () => {\n const f = render({ data: '# X', containerClass: 'my-custom-class' });\n expect(container(f).classList.contains('my-custom-class')).toBe(true);\n });\n\n it('emits the rendered @Output with hasCodeBlocks=true for code content', async () => {\n const f = render({ data: '' });\n const events = capture<MarkdownRenderEvent>(f.componentInstance.rendered);\n\n // Setting data after first render drives ngOnChanges -> render() -> postRenderProcessing\n // is scheduled on a microtask. Use setInput (zoneless-correct), then flush the microtask.\n f.componentRef.setInput('data', '```\\nconst x = 1;\\n```');\n f.detectChanges();\n await Promise.resolve();\n await Promise.resolve();\n\n expect(events.length).toBeGreaterThanOrEqual(1);\n const last = events[events.length - 1];\n expect(last.hasCodeBlocks).toBe(true);\n expect(last.hasMermaid).toBe(false);\n });\n\n it('emits the rendered @Output with hasCodeBlocks=false for prose-only content', async () => {\n const f = render({ data: '' });\n const events = capture<MarkdownRenderEvent>(f.componentInstance.rendered);\n\n f.componentRef.setInput('data', 'Just some plain prose.');\n f.detectChanges();\n await Promise.resolve();\n await Promise.resolve();\n\n expect(events.length).toBeGreaterThanOrEqual(1);\n expect(events[events.length - 1].hasCodeBlocks).toBe(false);\n });\n\n describe('TeX math', () => {\n // postRenderProcessing awaits the lazily-imported KaTeX chunk, so wait for the typeset\n // output rather than for a fixed number of microtasks.\n const typesetIn = async (f: ComponentFixture<MarkdownComponent>): Promise<HTMLElement> => {\n const c = container(f);\n await vi.waitFor(() => expect(c.querySelector('math')).not.toBeNull());\n return c;\n };\n\n it('typesets inline and display math after render', async () => {\n const c = await typesetIn(render({ data: 'Area $\\\\pi r^2$\\n\\n$$\\n\\\\sum_{i=1}^n i\\n$$' }));\n expect(c.querySelectorAll('math').length).toBe(2);\n expect(c.querySelector('math[display=\"block\"] munderover')).not.toBeNull();\n expect(c.querySelector('code.mj-math')).toBeNull();\n });\n\n it('typesets through the Angular sanitizer path too (no passthrough, no SVG renderer)', async () => {\n const c = await typesetIn(render({ data: 'so $x_i + y_j$ holds', enableSvgRenderer: false }));\n expect(c.querySelector('em')).toBeNull();\n expect(c.querySelector('annotation')?.textContent).toBe('x_i + y_j');\n });\n\n it('renders a JATS MathML formula and fixes its styled letters', async () => {\n const f = render({ data: 'Field <mml:math><mml:mi mathvariant=\"bold\">E</mml:mi></mml:math> here' });\n const c = container(f);\n await vi.waitFor(() => expect(c.querySelector('mi')?.textContent).toBe('𝐄'));\n expect(c.querySelector('math')?.namespaceURI).toBe('http://www.w3.org/1998/Math/MathML');\n });\n\n it('EnableMath=false leaves the dollars as text', async () => {\n const f = render({ data: '$x^2$', EnableMath: false });\n await Promise.resolve();\n await Promise.resolve();\n expect(container(f).querySelector('math, code.mj-math')).toBeNull();\n expect(container(f).textContent).toContain('$x^2$');\n });\n\n it('EnableMath=false still fixes the styled letters of MathML markup', async () => {\n const f = render({ data: 'Field <math><mi mathvariant=\"bold\">E</mi></math> here', EnableMath: false });\n const c = container(f);\n await vi.waitFor(() => expect(c.querySelector('mi')?.textContent).toBe('𝐄'));\n expect(c.querySelector('mi[mathvariant]')).toBeNull();\n });\n });\n\n /**\n * Sanitization, as seen through the component. With `enableHtml` or the default\n * `enableSvgRenderer`, Angular's sanitizer is bypassed and the HTML the service returns\n * (sanitized by DOMPurify in parse()) is trusted. jsdom does not execute handlers or\n * load images, so assertions are structural: the vector is gone, the layout survives.\n */\n describe('sanitization', () => {\n const attributeNamesIn = (root: HTMLElement): string[] =>\n Array.from(root.querySelectorAll('*')).flatMap((el) => Array.from(el.attributes).map((a) => a.name.toLowerCase()));\n const passthrough = (data: string) => container(render({ data, enableHtml: true }));\n\n it('removes <script> elements, including ones with a spaced end tag', () => {\n const c = passthrough('<div>before</div><script>alert(1)</script ><div>after</div>');\n expect(c.querySelector('script')).toBeNull();\n expect(c.textContent).toContain('before');\n expect(c.textContent).toContain('after');\n expect(c.textContent).not.toContain('alert(1)');\n });\n\n it('removes every on* handler, whatever its name or quoting', () => {\n const c = passthrough('<img src=\"x\" onerror=\"alert(1)\"><div onpointerrawupdate=alert(1) ONMOUSEENTER=\"alert(1)\">t</div><svg onload=\"alert(1)\"><circle r=\"1\"/></svg>');\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n expect(c.querySelector('img')).not.toBeNull();\n expect(c.querySelector('svg circle')).not.toBeNull();\n });\n\n it.each([\n ['javascript:', '<a href=\"javascript:alert(1)\">x</a>'],\n ['vbscript:', '<a href=\"vbscript:msgbox(1)\">x</a>'],\n ['data:text/html', '<a href=\"data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==\">x</a>'],\n ['data:image/svg+xml on a link', '<a href=\"data:image/svg+xml;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+PC9zdmc+\">x</a>'],\n ['whitespace inside the scheme', '<a href=\"java\\tscript:alert(1)\">x</a>'],\n ['entity inside the scheme', '<a href=\"jav&#x09;ascript:alert(1)\">x</a>'],\n ['newline inside the scheme', '<a href=\"java\\nscript:alert(1)\">x</a>'],\n ['upper-case scheme', '<a href=\"JAVASCRIPT:alert(1)\">x</a>'],\n ])('drops the link target for %s', (_label, html) => {\n const a = passthrough(html).querySelector('a');\n expect(a).not.toBeNull();\n expect(a?.hasAttribute('href')).toBe(false);\n });\n\n it('drops javascript: from a form action', () => {\n const c = passthrough('<form action=\"javascript:alert(1)\"><button>go</button></form>');\n expect(c.querySelector('form')?.hasAttribute('action')).toBe(false);\n });\n\n it.each([\n ['iframe', '<iframe src=\"https://evil.test/\"></iframe>'],\n ['iframe with srcdoc', '<iframe srcdoc=\"&lt;script&gt;alert(1)&lt;/script&gt;\"></iframe>'],\n ['object', '<object data=\"https://evil.test/x.swf\"></object>'],\n ['embed', '<embed src=\"https://evil.test/x.swf\">'],\n ['base', '<base href=\"https://evil.test/\">'],\n ])('removes %s while keeping the surrounding content', (_label, html) => {\n const c = passthrough('<p>before</p>' + html + '<p>after</p>');\n expect(c.querySelector('iframe, object, embed, base')).toBeNull();\n expect(c.textContent).toContain('before');\n expect(c.textContent).toContain('after');\n });\n\n it('removes <foreignObject> and SMIL animation from inline SVG, keeps shapes', () => {\n const c = passthrough('<svg><foreignObject><body onload=\"alert(1)\"></body></foreignObject><circle r=\"1\"><animate attributeName=\"r\" to=\"2\"/></circle></svg>');\n expect(c.querySelector('foreignObject, animate')).toBeNull();\n expect(c.querySelector('svg circle')).not.toBeNull();\n });\n\n it('keeps a same-document <use> and removes an external one', () => {\n const c = passthrough('<svg><defs><symbol id=\"ic\"><circle r=\"1\"/></symbol></defs><use href=\"#ic\"/><use href=\"https://evil.test/s.svg#x\"/></svg>');\n const uses = Array.from(c.querySelectorAll('use')).map((u) => u.getAttribute('href'));\n expect(uses).toEqual(['#ic']);\n });\n\n it('keeps layout HTML, inline styles, data attributes and data: images', () => {\n const c = passthrough(\n '<table class=\"grid\" data-role=\"report\"><tr><td style=\"color: red\">cell</td></tr></table>' +\n '<input type=\"text\" value=\"v\"><details><summary>s</summary>body</details>' +\n '<img src=\"data:image/png;base64,iVBORw0KGgo=\" alt=\"pixel\">',\n );\n expect(c.querySelector('table.grid')?.getAttribute('data-role')).toBe('report');\n expect(c.querySelector('td')?.getAttribute('style')).toContain('color');\n expect(c.querySelector('input')?.getAttribute('value')).toBe('v');\n expect(c.querySelector('details summary')?.textContent).toBe('s');\n expect(c.querySelector('img')?.getAttribute('src')).toMatch(/^data:image\\/png/);\n });\n\n it('keeps a leading <style> block (mockups start that way)', () => {\n const c = passthrough('<style>.card{color:red}</style><div class=\"card\">x</div>');\n expect(c.querySelector('style')?.textContent).toContain('.card');\n expect(c.querySelector('div.card')).not.toBeNull();\n });\n\n it('keeps target on links and enforces rel=noopener', () => {\n const c = passthrough('<a href=\"https://example.test/page\" target=\"_blank\">site</a><a href=\"#section\">local</a>');\n const [ext, local] = Array.from(c.querySelectorAll('a'));\n expect(ext.getAttribute('href')).toBe('https://example.test/page');\n expect(ext.getAttribute('target')).toBe('_blank');\n expect(ext.getAttribute('rel')).toContain('noopener');\n expect(local.getAttribute('href')).toBe('#section');\n expect(local.hasAttribute('rel')).toBe(false);\n });\n\n it('keeps heading ids that collide with document properties', () => {\n // DOMPurify's default DOM-clobbering guard would strip these; heading anchors must work.\n const c = container(render({ data: '# Title' + '\\n\\n' + '## Location' + '\\n\\n' + '## Overview' }));\n expect(c.querySelector('h1')?.id).toBe('title');\n expect(c.querySelector('h2')?.id).toBe('location');\n expect(Array.from(c.querySelectorAll('h2')).map((h) => h.id)).toEqual(['location', 'overview']);\n });\n\n it('sanitizes HTML that marked miscoded into a code block and the service unwrapped', () => {\n // A bare fenced block whose text is structural HTML is unwrapped by the service (no\n // language class), then sanitized like any other passthrough markup.\n const c = passthrough('```' + '\\n' + '<div class=\"card\"><img src=\"x\" onerror=\"alert(1)\"><p>inner</p></div>' + '\\n' + '```');\n expect(c.querySelector('pre')).toBeNull();\n expect(c.querySelector('div.card p')?.textContent).toBe('inner');\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n\n it('strips handlers and script from a rendered SVG code fence (enableSvgRenderer)', () => {\n const data = '```svg' + '\\n' + '<svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"alert(1)\"><script>alert(2)</script><circle r=\"1\"/></svg>' + '\\n' + '```';\n const c = container(render({ data, enableSvgRenderer: true }));\n expect(c.querySelector('svg')).not.toBeNull();\n expect(c.querySelector('script')).toBeNull();\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n\n it('enableJavaScript=true is the documented opt-out and leaves script elements in place', () => {\n // jsdom (as vitest configures it) executes this script and logs \"Not implemented:\n // window.alert\" to stderr. Expected here and only here.\n const c = container(render({ data: '<div>x</div><script>alert(1)</script>', enableHtml: true, enableJavaScript: true }));\n expect(c.querySelector('script')).not.toBeNull();\n });\n\n it('Angular sanitizer path (no passthrough, no SVG renderer) still strips handlers', () => {\n const c = container(render({ data: 'text <img src=\"x\" onerror=\"alert(1)\">', enableSvgRenderer: false }));\n expect(attributeNamesIn(c).some((n) => n.startsWith('on'))).toBe(false);\n });\n });\n});\n"]}
@@ -217,6 +217,10 @@ export class MarkdownComponent {
217
217
  * Enable Mermaid diagram rendering
218
218
  */
219
219
  this.EnableMermaid = DEFAULT_MARKDOWN_CONFIG.enableMermaid;
220
+ /**
221
+ * Enable TeX math (`$…$`, `$$…$$`, `\(…\)`, `\[…\]`), typeset as MathML
222
+ */
223
+ this.EnableMath = DEFAULT_MARKDOWN_CONFIG.enableMath;
220
224
  /**
221
225
  * Enable copy button on code blocks
222
226
  */
@@ -323,6 +327,7 @@ export class MarkdownComponent {
323
327
  this.RenderedContent = '';
324
328
  this.renderStartTime = 0;
325
329
  this.hasMermaid = false;
330
+ this.hasMath = false;
326
331
  this.hasCodeBlocks = false;
327
332
  this.themeObserver = null;
328
333
  }
@@ -331,6 +336,7 @@ export class MarkdownComponent {
331
336
  const needsRerender = changes['data'] ||
332
337
  changes['enableHighlight'] ||
333
338
  changes['enableMermaid'] ||
339
+ changes['EnableMath'] ||
334
340
  changes['enableCodeCopy'] ||
335
341
  changes['enableCollapsibleHeadings'] ||
336
342
  changes['collapsibleHeadingLevel'] ||
@@ -375,6 +381,7 @@ export class MarkdownComponent {
375
381
  const config = {
376
382
  enableHighlight: this.EnableHighlight,
377
383
  enableMermaid: this.EnableMermaid,
384
+ enableMath: this.EnableMath,
378
385
  enableCodeCopy: this.EnableCodeCopy,
379
386
  enableCollapsibleHeadings: this.EnableCollapsibleHeadings,
380
387
  collapsibleHeadingLevel: this.CollapsibleHeadingLevel,
@@ -396,6 +403,7 @@ export class MarkdownComponent {
396
403
  // Check for mermaid and code blocks
397
404
  this.hasMermaid = html.includes('language-mermaid') || html.includes('class="mermaid"');
398
405
  this.hasCodeBlocks = html.includes('<pre>') && html.includes('<code');
406
+ this.hasMath = html.includes('class="mj-math') || html.includes('<math');
399
407
  // Sanitize if enabled
400
408
  // Note: We bypass Angular's sanitizer when SVG renderer or HTML passthrough is enabled
401
409
  // because it strips SVG elements and most HTML layout tags.
@@ -405,7 +413,7 @@ export class MarkdownComponent {
405
413
  html = sanitized || '';
406
414
  }
407
415
  // When Angular's sanitizer is bypassed, the HTML has already been sanitized by
408
- // MarkdownService.parse() (DOMPurify, HTML + SVG profiles) unless enableJavaScript
416
+ // MarkdownService.parse() (DOMPurify, HTML, SVG and MathML profiles) unless enableJavaScript
409
417
  // opted out. Nothing further to do here.
410
418
  // Trust the HTML for display
411
419
  this.RenderedContent = this.sanitizer.bypassSecurityTrustHtml(html);
@@ -430,6 +438,16 @@ export class MarkdownComponent {
430
438
  this.markdownService.initializeCollapsibleHeadings(container);
431
439
  this.setupCollapsibleListeners(container);
432
440
  }
441
+ // Typeset TeX math (async: KaTeX loads on first use). With math off, MathML that arrived as
442
+ // markup still renders, so it still gets the styled-letter fix.
443
+ if (this.hasMath) {
444
+ if (this.EnableMath) {
445
+ await this.markdownService.RenderMath(container);
446
+ }
447
+ else {
448
+ this.markdownService.UseUnicodeMathLetters(container);
449
+ }
450
+ }
433
451
  // Render mermaid diagrams (async)
434
452
  if (this.EnableMermaid && this.hasMermaid) {
435
453
  await this.markdownService.renderMermaid(container);
@@ -703,16 +721,16 @@ export class MarkdownComponent {
703
721
  return this.ScrollToHeading(headingId);
704
722
  }
705
723
  static { this.ɵfac = function MarkdownComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MarkdownComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(i2.MarkdownService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
706
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MarkdownComponent, selectors: [["mj-markdown"]], inputs: { Data: "Data", data: "data", EnableHighlight: "EnableHighlight", enableHighlight: "enableHighlight", EnableMermaid: "EnableMermaid", enableMermaid: "enableMermaid", EnableCodeCopy: "EnableCodeCopy", enableCodeCopy: "enableCodeCopy", EnableCollapsibleHeadings: "EnableCollapsibleHeadings", enableCollapsibleHeadings: "enableCollapsibleHeadings", CollapsibleHeadingLevel: "CollapsibleHeadingLevel", collapsibleHeadingLevel: "collapsibleHeadingLevel", CollapsibleDefaultExpanded: "CollapsibleDefaultExpanded", collapsibleDefaultExpanded: "collapsibleDefaultExpanded", AutoExpandLevels: "AutoExpandLevels", autoExpandLevels: "autoExpandLevels", EnableAlerts: "EnableAlerts", enableAlerts: "enableAlerts", EnableSmartypants: "EnableSmartypants", enableSmartypants: "enableSmartypants", EnableSvgRenderer: "EnableSvgRenderer", enableSvgRenderer: "enableSvgRenderer", EnableHtml: "EnableHtml", enableHtml: "enableHtml", EnableJavaScript: "EnableJavaScript", enableJavaScript: "enableJavaScript", EnableHeadingIds: "EnableHeadingIds", enableHeadingIds: "enableHeadingIds", HeadingIdPrefix: "HeadingIdPrefix", headingIdPrefix: "headingIdPrefix", EnableLineNumbers: "EnableLineNumbers", enableLineNumbers: "enableLineNumbers", ContainerClass: "ContainerClass", containerClass: "containerClass", MermaidTheme: "MermaidTheme", mermaidTheme: "mermaidTheme", Sanitize: "Sanitize", sanitize: "sanitize" }, outputs: { Rendered: "Rendered", rendered: "rendered", HeadingClick: "HeadingClick", headingClick: "headingClick", CodeCopied: "CodeCopied", codeCopied: "codeCopied" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 1, vars: 3, consts: [[1, "mj-markdown-container", 3, "innerHTML"]], template: function MarkdownComponent_Template(rf, ctx) { if (rf & 1) {
724
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MarkdownComponent, selectors: [["mj-markdown"]], inputs: { Data: "Data", data: "data", EnableHighlight: "EnableHighlight", enableHighlight: "enableHighlight", EnableMermaid: "EnableMermaid", enableMermaid: "enableMermaid", EnableMath: "EnableMath", EnableCodeCopy: "EnableCodeCopy", enableCodeCopy: "enableCodeCopy", EnableCollapsibleHeadings: "EnableCollapsibleHeadings", enableCollapsibleHeadings: "enableCollapsibleHeadings", CollapsibleHeadingLevel: "CollapsibleHeadingLevel", collapsibleHeadingLevel: "collapsibleHeadingLevel", CollapsibleDefaultExpanded: "CollapsibleDefaultExpanded", collapsibleDefaultExpanded: "collapsibleDefaultExpanded", AutoExpandLevels: "AutoExpandLevels", autoExpandLevels: "autoExpandLevels", EnableAlerts: "EnableAlerts", enableAlerts: "enableAlerts", EnableSmartypants: "EnableSmartypants", enableSmartypants: "enableSmartypants", EnableSvgRenderer: "EnableSvgRenderer", enableSvgRenderer: "enableSvgRenderer", EnableHtml: "EnableHtml", enableHtml: "enableHtml", EnableJavaScript: "EnableJavaScript", enableJavaScript: "enableJavaScript", EnableHeadingIds: "EnableHeadingIds", enableHeadingIds: "enableHeadingIds", HeadingIdPrefix: "HeadingIdPrefix", headingIdPrefix: "headingIdPrefix", EnableLineNumbers: "EnableLineNumbers", enableLineNumbers: "enableLineNumbers", ContainerClass: "ContainerClass", containerClass: "containerClass", MermaidTheme: "MermaidTheme", mermaidTheme: "mermaidTheme", Sanitize: "Sanitize", sanitize: "sanitize" }, outputs: { Rendered: "Rendered", rendered: "rendered", HeadingClick: "HeadingClick", headingClick: "headingClick", CodeCopied: "CodeCopied", codeCopied: "codeCopied" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 1, vars: 3, consts: [[1, "mj-markdown-container", 3, "innerHTML"]], template: function MarkdownComponent_Template(rf, ctx) { if (rf & 1) {
707
725
  i0.ɵɵelement(0, "div", 0);
708
726
  } if (rf & 2) {
709
727
  i0.ɵɵclassMap(ctx.containerClass);
710
728
  i0.ɵɵproperty("innerHTML", ctx.renderedContent, i0.ɵɵsanitizeHtml);
711
- } }, styles: ["/**\n * MJ Markdown Component Styles\n *\n * These styles apply to rendered markdown content.\n * Using ViewEncapsulation.None so styles penetrate into dynamically generated content.\n */\n\n/* ============================================\n Container\n ============================================ */\n.mj-markdown-container {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 15px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n word-wrap: break-word;\n}\n\n/* ============================================\n Typography\n ============================================ */\n.mj-markdown-container h1,\n.mj-markdown-container h2,\n.mj-markdown-container h3,\n.mj-markdown-container h4,\n.mj-markdown-container h5,\n.mj-markdown-container h6 {\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n font-weight: 600;\n line-height: 1.25;\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container h1 { font-size: 1.75em; }\n.mj-markdown-container h2 { font-size: 1.5em; }\n.mj-markdown-container h3 { font-size: 1.25em; }\n.mj-markdown-container h4 { font-size: 1.1em; }\n.mj-markdown-container h5 { font-size: 1em; }\n.mj-markdown-container h6 { font-size: 0.9em; color: var(--mj-text-secondary); }\n\n.mj-markdown-container > h1:first-child,\n.mj-markdown-container > h2:first-child,\n.mj-markdown-container > h3:first-child {\n margin-top: 0;\n}\n\n.mj-markdown-container p {\n margin: 0 0 1em 0;\n}\n\n.mj-markdown-container > p:last-child {\n margin-bottom: 0;\n}\n\n.mj-markdown-container a {\n color: var(--mj-brand-primary);\n text-decoration: none;\n}\n\n.mj-markdown-container a:hover {\n text-decoration: underline;\n}\n\n.mj-markdown-container strong {\n font-weight: 600;\n}\n\n.mj-markdown-container em {\n font-style: italic;\n}\n\n/* ============================================\n Lists\n ============================================ */\n.mj-markdown-container ul,\n.mj-markdown-container ol {\n margin: 0 0 1em 0;\n padding-left: 2em;\n}\n\n.mj-markdown-container li {\n margin-bottom: 0.25em;\n}\n\n.mj-markdown-container li > ul,\n.mj-markdown-container li > ol {\n margin-top: 0.25em;\n margin-bottom: 0;\n}\n\n/* Task lists */\n.mj-markdown-container ul.contains-task-list {\n list-style: none;\n padding-left: 0;\n}\n\n.mj-markdown-container li.task-list-item {\n display: flex;\n align-items: flex-start;\n gap: 0.5em;\n}\n\n.mj-markdown-container li.task-list-item input[type=\"checkbox\"] {\n margin-top: 0.35em;\n}\n\n/* ============================================\n Blockquotes\n ============================================ */\n.mj-markdown-container blockquote {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 4px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.mj-markdown-container blockquote > p:last-child {\n margin-bottom: 0;\n}\n\n/* ============================================\n Code Blocks\n ============================================ */\n.mj-markdown-container code {\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Courier New', monospace;\n font-size: 0.9em;\n}\n\n/* Inline code */\n.mj-markdown-container :not(pre) > code {\n padding: 0.2em 0.4em;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n color: var(--mj-status-error);\n}\n\n/* Code blocks\n * design-token-exempt fallbacks: --mj-bg-code-block / --mj-text-code resolve to\n * Monaco-style dark editor colors when an app does not override them. Code\n * blocks intentionally use a fixed dark editor aesthetic (same exemption as\n * Monaco/CodeMirror), so the hex fallbacks here are deliberate. */\n.mj-markdown-container pre {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-code-block, #1e1e1e);\n border-radius: var(--mj-radius-md);\n overflow-x: auto;\n position: relative;\n}\n\n.mj-markdown-container pre code {\n background: transparent;\n padding: 0;\n color: var(--mj-text-code, #d4d4d4);\n font-size: 0.875em;\n line-height: 1.5;\n}\n\n/* ============================================\n Code Toolbar (copy button, language label)\n ============================================ */\n.mj-markdown-container .code-toolbar {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n}\n\n.mj-markdown-container .code-language-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n user-select: none;\n}\n\n.mj-markdown-container .code-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-disabled);\n cursor: pointer;\n transition: all 0.2s ease;\n opacity: 0;\n}\n\n.mj-markdown-container pre:hover .code-copy-btn {\n opacity: 1;\n}\n\n.mj-markdown-container .code-copy-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n}\n\n.mj-markdown-container .code-copy-btn.copied {\n background: color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n color: var(--mj-status-success);\n}\n\n.mj-markdown-container .code-copy-btn.error {\n background: color-mix(in srgb, var(--mj-status-error) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Tables\n ============================================ */\n.mj-markdown-container table {\n width: 100%;\n margin: 1em 0;\n border-collapse: collapse;\n border-spacing: 0;\n}\n\n.mj-markdown-container th,\n.mj-markdown-container td {\n padding: 0.5em 1em;\n border: 1px solid var(--mj-border-default);\n text-align: left;\n}\n\n.mj-markdown-container th {\n background: var(--mj-bg-surface-sunken);\n font-weight: 600;\n}\n\n.mj-markdown-container tr:nth-child(even) {\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================\n Horizontal Rule\n ============================================ */\n.mj-markdown-container hr {\n margin: 2em 0;\n border: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* ============================================\n Images\n ============================================ */\n.mj-markdown-container img {\n max-width: 100%;\n height: auto;\n border-radius: 4px;\n}\n\n/* ============================================\n GitHub-style Alerts (marked-alert)\n ============================================ */\n.mj-markdown-container .markdown-alert {\n margin: 1em 0;\n padding: 1em;\n border-radius: 8px;\n border-left: 4px solid;\n}\n\n.mj-markdown-container .markdown-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n margin-bottom: 0.5em;\n}\n\n.mj-markdown-container .markdown-alert > p:last-child {\n margin-bottom: 0;\n}\n\n/* Note */\n.mj-markdown-container .markdown-alert-note {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-note .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Tip */\n.mj-markdown-container .markdown-alert-tip {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-success);\n}\n\n.mj-markdown-container .markdown-alert-tip .markdown-alert-title {\n color: var(--mj-status-success);\n}\n\n/* Important */\n.mj-markdown-container .markdown-alert-important {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-important .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Warning */\n.mj-markdown-container .markdown-alert-warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.mj-markdown-container .markdown-alert-warning .markdown-alert-title {\n color: var(--mj-status-warning);\n}\n\n/* Caution */\n.mj-markdown-container .markdown-alert-caution {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-error);\n}\n\n.mj-markdown-container .markdown-alert-caution .markdown-alert-title {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Collapsible Headings\n ============================================ */\n.mj-markdown-container .collapsible-section {\n margin: 0.75em 0;\n border-left: 2px solid transparent;\n transition: border-color 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section:hover {\n border-left-color: var(--mj-border-default);\n}\n\n/* Heading wrapper - contains toggle and heading */\n.mj-markdown-container .collapsible-heading-wrapper {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.15s ease;\n user-select: none;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 3%, transparent);\n}\n\n/* The heading itself */\n.mj-markdown-container .collapsible-heading {\n margin: 0 !important;\n flex: 1;\n}\n\n/* Toggle button/icon */\n.mj-markdown-container .collapsible-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease, color 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-toggle svg {\n width: 14px;\n height: 14px;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-toggle {\n color: var(--mj-text-secondary);\n}\n\n/* Expanded state - arrow points down */\n.mj-markdown-container .collapsible-section:not(.collapsed) .collapsible-toggle {\n transform: rotate(90deg);\n}\n\n/* Collapsed state - arrow points right (default SVG orientation) */\n.mj-markdown-container .collapsible-section.collapsed .collapsible-toggle {\n transform: rotate(0deg);\n}\n\n/* Content area */\n.mj-markdown-container .collapsible-content {\n padding-left: 26px;\n overflow: hidden;\n max-height: 5000px; /* Large enough for most content */\n opacity: 1;\n transition: max-height 0.3s ease-out, opacity 0.2s ease-out, padding 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: 0;\n opacity: 0;\n padding-top: 0;\n padding-bottom: 0;\n visibility: hidden;\n}\n\n/* Nested sections - indent further */\n.mj-markdown-container .collapsible-section .collapsible-section {\n margin-left: 0;\n}\n\n/* Focus styles for accessibility */\n.mj-markdown-container .collapsible-heading-wrapper:focus-within {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.mj-markdown-container .collapsible-toggle:focus {\n outline: none;\n}\n\n/* Action buttons container - expand/collapse all */\n.mj-markdown-container .collapsible-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n padding-left: 12px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-actions {\n opacity: 1;\n}\n\n/* Individual action buttons */\n.mj-markdown-container .collapsible-action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\n}\n\n.mj-markdown-container .collapsible-action-btn:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container .collapsible-action-btn:active {\n transform: scale(0.92);\n}\n\n.mj-markdown-container .collapsible-action-btn svg {\n width: 14px;\n height: 14px;\n}\n\n/* Expand all button - double down chevron */\n.mj-markdown-container .collapsible-action-btn.expand-all:hover {\n color: var(--mj-status-success);\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n/* Collapse all button - double up chevron */\n.mj-markdown-container .collapsible-action-btn.collapse-all:hover {\n color: var(--mj-status-error);\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n/* ============================================\n Mermaid Diagrams\n ============================================ */\n.mj-markdown-container .mermaid-diagram {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow-x: auto;\n}\n\n.mj-markdown-container .mermaid-diagram svg {\n max-width: 100%;\n height: auto;\n}\n\n.mj-markdown-container .mermaid-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.mj-markdown-container .mermaid-error::before {\n content: 'Diagram rendering failed';\n display: block;\n color: var(--mj-status-error);\n font-size: 12px;\n margin-bottom: 8px;\n}\n\n/* A specific reason, when we have one \u2014 e.g. the lazily-fetched diagram engine\n never arrived, which is a different problem than bad diagram source. */\n.mj-markdown-container .mermaid-error[data-mermaid-error]::before {\n content: attr(data-mermaid-error);\n}\n\n/* ============================================\n Heading Anchors\n ============================================ */\n.mj-markdown-container h1[id],\n.mj-markdown-container h2[id],\n.mj-markdown-container h3[id],\n.mj-markdown-container h4[id],\n.mj-markdown-container h5[id],\n.mj-markdown-container h6[id] {\n scroll-margin-top: 1em;\n}\n\n.mj-markdown-container h1[id]:hover,\n.mj-markdown-container h2[id]:hover,\n.mj-markdown-container h3[id]:hover,\n.mj-markdown-container h4[id]:hover,\n.mj-markdown-container h5[id]:hover,\n.mj-markdown-container h6[id]:hover {\n cursor: pointer;\n}\n\n/* Anchor link indicator on hover */\n.mj-markdown-container h1[id]::before,\n.mj-markdown-container h2[id]::before,\n.mj-markdown-container h3[id]::before,\n.mj-markdown-container h4[id]::before,\n.mj-markdown-container h5[id]::before,\n.mj-markdown-container h6[id]::before {\n content: '#';\n position: absolute;\n left: -1.5em;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.mj-markdown-container h1[id]:hover::before,\n.mj-markdown-container h2[id]:hover::before,\n.mj-markdown-container h3[id]:hover::before,\n.mj-markdown-container h4[id]:hover::before,\n.mj-markdown-container h5[id]:hover::before,\n.mj-markdown-container h6[id]:hover::before {\n opacity: 1;\n}\n\n/* ============================================\n Line Numbers (optional)\n ============================================ */\n.mj-markdown-container pre.line-numbers {\n padding-left: 3.5em;\n counter-reset: line;\n}\n\n.mj-markdown-container pre.line-numbers code {\n display: block;\n}\n\n.mj-markdown-container pre.line-numbers code .line::before {\n counter-increment: line;\n content: counter(line);\n display: inline-block;\n width: 2em;\n margin-left: -3em;\n margin-right: 1em;\n text-align: right;\n color: var(--mj-text-muted);\n user-select: none;\n}\n\n/* ============================================\n Error State\n ============================================ */\n.mj-markdown-container .markdown-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 1em;\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n white-space: pre-wrap;\n font-family: monospace;\n}\n\n/* Dark Mode Support \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n SVG Rendered Content\n ============================================ */\n.mj-markdown-container .svg-rendered {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow: auto;\n}\n\n.mj-markdown-container .svg-rendered svg {\n max-width: 100%;\n height: auto;\n}\n\n/* Dark mode for SVG rendered content \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n Print Styles\n ============================================ */\n@media print {\n .mj-markdown-container .code-toolbar {\n display: none;\n }\n\n .mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: none;\n opacity: 1;\n visibility: visible;\n }\n\n /* design-token-exempt: print always uses light background + dark text for\n paper readability, regardless of the screen theme the user is rendering from */\n .mj-markdown-container pre {\n background: #f3f4f6 !important;\n color: #1f2937 !important;\n }\n\n .mj-markdown-container pre code {\n color: #1f2937 !important;\n }\n}\n"], encapsulation: 2, changeDetection: 0 }); }
729
+ } }, styles: ["/**\n * MJ Markdown Component Styles\n *\n * These styles apply to rendered markdown content.\n * Using ViewEncapsulation.None so styles penetrate into dynamically generated content.\n */\n\n/* ============================================\n Container\n ============================================ */\n.mj-markdown-container {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 15px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n word-wrap: break-word;\n}\n\n/* ============================================\n Typography\n ============================================ */\n.mj-markdown-container h1,\n.mj-markdown-container h2,\n.mj-markdown-container h3,\n.mj-markdown-container h4,\n.mj-markdown-container h5,\n.mj-markdown-container h6 {\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n font-weight: 600;\n line-height: 1.25;\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container h1 { font-size: 1.75em; }\n.mj-markdown-container h2 { font-size: 1.5em; }\n.mj-markdown-container h3 { font-size: 1.25em; }\n.mj-markdown-container h4 { font-size: 1.1em; }\n.mj-markdown-container h5 { font-size: 1em; }\n.mj-markdown-container h6 { font-size: 0.9em; color: var(--mj-text-secondary); }\n\n.mj-markdown-container > h1:first-child,\n.mj-markdown-container > h2:first-child,\n.mj-markdown-container > h3:first-child {\n margin-top: 0;\n}\n\n.mj-markdown-container p {\n margin: 0 0 1em 0;\n}\n\n.mj-markdown-container > p:last-child {\n margin-bottom: 0;\n}\n\n.mj-markdown-container a {\n color: var(--mj-brand-primary);\n text-decoration: none;\n}\n\n.mj-markdown-container a:hover {\n text-decoration: underline;\n}\n\n.mj-markdown-container strong {\n font-weight: 600;\n}\n\n.mj-markdown-container em {\n font-style: italic;\n}\n\n/* ============================================\n Lists\n ============================================ */\n.mj-markdown-container ul,\n.mj-markdown-container ol {\n margin: 0 0 1em 0;\n padding-left: 2em;\n}\n\n.mj-markdown-container li {\n margin-bottom: 0.25em;\n}\n\n.mj-markdown-container li > ul,\n.mj-markdown-container li > ol {\n margin-top: 0.25em;\n margin-bottom: 0;\n}\n\n/* Task lists */\n.mj-markdown-container ul.contains-task-list {\n list-style: none;\n padding-left: 0;\n}\n\n.mj-markdown-container li.task-list-item {\n display: flex;\n align-items: flex-start;\n gap: 0.5em;\n}\n\n.mj-markdown-container li.task-list-item input[type=\"checkbox\"] {\n margin-top: 0.35em;\n}\n\n/* ============================================\n Blockquotes\n ============================================ */\n.mj-markdown-container blockquote {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 4px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.mj-markdown-container blockquote > p:last-child {\n margin-bottom: 0;\n}\n\n/* ============================================\n Code Blocks\n ============================================ */\n.mj-markdown-container code {\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Courier New', monospace;\n font-size: 0.9em;\n}\n\n/* Inline code */\n.mj-markdown-container :not(pre) > code {\n padding: 0.2em 0.4em;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n color: var(--mj-status-error);\n}\n\n/* Code blocks\n * design-token-exempt fallbacks: --mj-bg-code-block / --mj-text-code resolve to\n * Monaco-style dark editor colors when an app does not override them. Code\n * blocks intentionally use a fixed dark editor aesthetic (same exemption as\n * Monaco/CodeMirror), so the hex fallbacks here are deliberate. */\n.mj-markdown-container pre {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-code-block, #1e1e1e);\n border-radius: var(--mj-radius-md);\n overflow-x: auto;\n position: relative;\n}\n\n.mj-markdown-container pre code {\n background: transparent;\n padding: 0;\n color: var(--mj-text-code, #d4d4d4);\n font-size: 0.875em;\n line-height: 1.5;\n}\n\n/* ============================================\n Code Toolbar (copy button, language label)\n ============================================ */\n.mj-markdown-container .code-toolbar {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n}\n\n.mj-markdown-container .code-language-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n user-select: none;\n}\n\n.mj-markdown-container .code-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-disabled);\n cursor: pointer;\n transition: all 0.2s ease;\n opacity: 0;\n}\n\n.mj-markdown-container pre:hover .code-copy-btn {\n opacity: 1;\n}\n\n.mj-markdown-container .code-copy-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n}\n\n.mj-markdown-container .code-copy-btn.copied {\n background: color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n color: var(--mj-status-success);\n}\n\n.mj-markdown-container .code-copy-btn.error {\n background: color-mix(in srgb, var(--mj-status-error) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Tables\n ============================================ */\n.mj-markdown-container table {\n width: 100%;\n margin: 1em 0;\n border-collapse: collapse;\n border-spacing: 0;\n}\n\n.mj-markdown-container th,\n.mj-markdown-container td {\n padding: 0.5em 1em;\n border: 1px solid var(--mj-border-default);\n text-align: left;\n}\n\n.mj-markdown-container th {\n background: var(--mj-bg-surface-sunken);\n font-weight: 600;\n}\n\n.mj-markdown-container tr:nth-child(even) {\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================\n Horizontal Rule\n ============================================ */\n.mj-markdown-container hr {\n margin: 2em 0;\n border: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* ============================================\n Images\n ============================================ */\n.mj-markdown-container img {\n max-width: 100%;\n height: auto;\n border-radius: 4px;\n}\n\n/* ============================================\n GitHub-style Alerts (marked-alert)\n ============================================ */\n.mj-markdown-container .markdown-alert {\n margin: 1em 0;\n padding: 1em;\n border-radius: 8px;\n border-left: 4px solid;\n}\n\n.mj-markdown-container .markdown-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n margin-bottom: 0.5em;\n}\n\n.mj-markdown-container .markdown-alert > p:last-child {\n margin-bottom: 0;\n}\n\n/* Note */\n.mj-markdown-container .markdown-alert-note {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-note .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Tip */\n.mj-markdown-container .markdown-alert-tip {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-success);\n}\n\n.mj-markdown-container .markdown-alert-tip .markdown-alert-title {\n color: var(--mj-status-success);\n}\n\n/* Important */\n.mj-markdown-container .markdown-alert-important {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-important .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Warning */\n.mj-markdown-container .markdown-alert-warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.mj-markdown-container .markdown-alert-warning .markdown-alert-title {\n color: var(--mj-status-warning);\n}\n\n/* Caution */\n.mj-markdown-container .markdown-alert-caution {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-error);\n}\n\n.mj-markdown-container .markdown-alert-caution .markdown-alert-title {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Collapsible Headings\n ============================================ */\n.mj-markdown-container .collapsible-section {\n margin: 0.75em 0;\n border-left: 2px solid transparent;\n transition: border-color 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section:hover {\n border-left-color: var(--mj-border-default);\n}\n\n/* Heading wrapper - contains toggle and heading */\n.mj-markdown-container .collapsible-heading-wrapper {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.15s ease;\n user-select: none;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 3%, transparent);\n}\n\n/* The heading itself */\n.mj-markdown-container .collapsible-heading {\n margin: 0 !important;\n flex: 1;\n}\n\n/* Toggle button/icon */\n.mj-markdown-container .collapsible-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease, color 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-toggle svg {\n width: 14px;\n height: 14px;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-toggle {\n color: var(--mj-text-secondary);\n}\n\n/* Expanded state - arrow points down */\n.mj-markdown-container .collapsible-section:not(.collapsed) .collapsible-toggle {\n transform: rotate(90deg);\n}\n\n/* Collapsed state - arrow points right (default SVG orientation) */\n.mj-markdown-container .collapsible-section.collapsed .collapsible-toggle {\n transform: rotate(0deg);\n}\n\n/* Content area */\n.mj-markdown-container .collapsible-content {\n padding-left: 26px;\n overflow: hidden;\n max-height: 5000px; /* Large enough for most content */\n opacity: 1;\n transition: max-height 0.3s ease-out, opacity 0.2s ease-out, padding 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: 0;\n opacity: 0;\n padding-top: 0;\n padding-bottom: 0;\n visibility: hidden;\n}\n\n/* Nested sections - indent further */\n.mj-markdown-container .collapsible-section .collapsible-section {\n margin-left: 0;\n}\n\n/* Focus styles for accessibility */\n.mj-markdown-container .collapsible-heading-wrapper:focus-within {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.mj-markdown-container .collapsible-toggle:focus {\n outline: none;\n}\n\n/* Action buttons container - expand/collapse all */\n.mj-markdown-container .collapsible-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n padding-left: 12px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-actions {\n opacity: 1;\n}\n\n/* Individual action buttons */\n.mj-markdown-container .collapsible-action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\n}\n\n.mj-markdown-container .collapsible-action-btn:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container .collapsible-action-btn:active {\n transform: scale(0.92);\n}\n\n.mj-markdown-container .collapsible-action-btn svg {\n width: 14px;\n height: 14px;\n}\n\n/* Expand all button - double down chevron */\n.mj-markdown-container .collapsible-action-btn.expand-all:hover {\n color: var(--mj-status-success);\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n/* Collapse all button - double up chevron */\n.mj-markdown-container .collapsible-action-btn.collapse-all:hover {\n color: var(--mj-status-error);\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n/* ============================================\n Math (TeX typeset as MathML by MarkdownService.RenderMath, and MathML markup)\n ============================================ */\n.mj-markdown-container .mj-math-block {\n display: block;\n margin: 1em 0;\n overflow-x: auto;\n overflow-y: hidden;\n}\n\n/* A wide display formula scrolls instead of widening the message. */\n.mj-markdown-container .katex:has(> math[display=\"block\"]) {\n display: block;\n overflow-x: auto;\n overflow-y: hidden;\n}\n\n/* Bold styles Unicode has no math letters for (Greek, text runs); Chrome ignores mathvariant. */\n.mj-markdown-container math [mathvariant*=\"bold\"] {\n font-weight: bold;\n}\n\n/* Chrome ignores MathML's columnalign too, which centres every cell and un-aligns the \"=\" signs of\n a derivation. KaTeX writes exactly \"right left\" (repeated, for alignedat) for aligned, split and\n alignedat, and \"left left\" for cases; JATS tables often say just \"left\" or \"right\". Other column\n lists (arrays) stay centred. */\n.mj-markdown-container mtable:is([columnalign=\"right left\"], [columnalign^=\"right left right left\"]) > mtr > mtd:nth-child(odd) {\n text-align: right;\n}\n\n.mj-markdown-container mtable:is([columnalign=\"right left\"], [columnalign^=\"right left right left\"]) > mtr > mtd:nth-child(even),\n.mj-markdown-container mtable:is([columnalign=\"left left\"], [columnalign=\"left\"]) > mtr > mtd {\n text-align: left;\n}\n\n.mj-markdown-container mtable[columnalign=\"right\"] > mtr > mtd {\n text-align: right;\n}\n\n/* TeX that KaTeX could not parse stays visible as source; its title says why. */\n.mj-markdown-container code.mj-math-error {\n text-decoration: underline wavy var(--mj-status-error);\n}\n\n/* ============================================\n Mermaid Diagrams\n ============================================ */\n.mj-markdown-container .mermaid-diagram {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow-x: auto;\n}\n\n.mj-markdown-container .mermaid-diagram svg {\n max-width: 100%;\n height: auto;\n}\n\n.mj-markdown-container .mermaid-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.mj-markdown-container .mermaid-error::before {\n content: 'Diagram rendering failed';\n display: block;\n color: var(--mj-status-error);\n font-size: 12px;\n margin-bottom: 8px;\n}\n\n/* A specific reason, when we have one \u2014 e.g. the lazily-fetched diagram engine\n never arrived, which is a different problem than bad diagram source. */\n.mj-markdown-container .mermaid-error[data-mermaid-error]::before {\n content: attr(data-mermaid-error);\n}\n\n/* ============================================\n Heading Anchors\n ============================================ */\n.mj-markdown-container h1[id],\n.mj-markdown-container h2[id],\n.mj-markdown-container h3[id],\n.mj-markdown-container h4[id],\n.mj-markdown-container h5[id],\n.mj-markdown-container h6[id] {\n scroll-margin-top: 1em;\n}\n\n.mj-markdown-container h1[id]:hover,\n.mj-markdown-container h2[id]:hover,\n.mj-markdown-container h3[id]:hover,\n.mj-markdown-container h4[id]:hover,\n.mj-markdown-container h5[id]:hover,\n.mj-markdown-container h6[id]:hover {\n cursor: pointer;\n}\n\n/* Anchor link indicator on hover */\n.mj-markdown-container h1[id]::before,\n.mj-markdown-container h2[id]::before,\n.mj-markdown-container h3[id]::before,\n.mj-markdown-container h4[id]::before,\n.mj-markdown-container h5[id]::before,\n.mj-markdown-container h6[id]::before {\n content: '#';\n position: absolute;\n left: -1.5em;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.mj-markdown-container h1[id]:hover::before,\n.mj-markdown-container h2[id]:hover::before,\n.mj-markdown-container h3[id]:hover::before,\n.mj-markdown-container h4[id]:hover::before,\n.mj-markdown-container h5[id]:hover::before,\n.mj-markdown-container h6[id]:hover::before {\n opacity: 1;\n}\n\n/* ============================================\n Line Numbers (optional)\n ============================================ */\n.mj-markdown-container pre.line-numbers {\n padding-left: 3.5em;\n counter-reset: line;\n}\n\n.mj-markdown-container pre.line-numbers code {\n display: block;\n}\n\n.mj-markdown-container pre.line-numbers code .line::before {\n counter-increment: line;\n content: counter(line);\n display: inline-block;\n width: 2em;\n margin-left: -3em;\n margin-right: 1em;\n text-align: right;\n color: var(--mj-text-muted);\n user-select: none;\n}\n\n/* ============================================\n Error State\n ============================================ */\n.mj-markdown-container .markdown-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 1em;\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n white-space: pre-wrap;\n font-family: monospace;\n}\n\n/* Dark Mode Support \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n SVG Rendered Content\n ============================================ */\n.mj-markdown-container .svg-rendered {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow: auto;\n}\n\n.mj-markdown-container .svg-rendered svg {\n max-width: 100%;\n height: auto;\n}\n\n/* Dark mode for SVG rendered content \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n Print Styles\n ============================================ */\n@media print {\n .mj-markdown-container .code-toolbar {\n display: none;\n }\n\n .mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: none;\n opacity: 1;\n visibility: visible;\n }\n\n /* design-token-exempt: print always uses light background + dark text for\n paper readability, regardless of the screen theme the user is rendering from */\n .mj-markdown-container pre {\n background: #f3f4f6 !important;\n color: #1f2937 !important;\n }\n\n .mj-markdown-container pre code {\n color: #1f2937 !important;\n }\n}\n"], encapsulation: 2, changeDetection: 0 }); }
712
730
  }
713
731
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MarkdownComponent, [{
714
732
  type: Component,
715
- args: [{ selector: 'mj-markdown', standalone: false, template: ` <div class="mj-markdown-container" [class]="containerClass" [innerHTML]="renderedContent"></div> `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["/**\n * MJ Markdown Component Styles\n *\n * These styles apply to rendered markdown content.\n * Using ViewEncapsulation.None so styles penetrate into dynamically generated content.\n */\n\n/* ============================================\n Container\n ============================================ */\n.mj-markdown-container {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 15px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n word-wrap: break-word;\n}\n\n/* ============================================\n Typography\n ============================================ */\n.mj-markdown-container h1,\n.mj-markdown-container h2,\n.mj-markdown-container h3,\n.mj-markdown-container h4,\n.mj-markdown-container h5,\n.mj-markdown-container h6 {\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n font-weight: 600;\n line-height: 1.25;\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container h1 { font-size: 1.75em; }\n.mj-markdown-container h2 { font-size: 1.5em; }\n.mj-markdown-container h3 { font-size: 1.25em; }\n.mj-markdown-container h4 { font-size: 1.1em; }\n.mj-markdown-container h5 { font-size: 1em; }\n.mj-markdown-container h6 { font-size: 0.9em; color: var(--mj-text-secondary); }\n\n.mj-markdown-container > h1:first-child,\n.mj-markdown-container > h2:first-child,\n.mj-markdown-container > h3:first-child {\n margin-top: 0;\n}\n\n.mj-markdown-container p {\n margin: 0 0 1em 0;\n}\n\n.mj-markdown-container > p:last-child {\n margin-bottom: 0;\n}\n\n.mj-markdown-container a {\n color: var(--mj-brand-primary);\n text-decoration: none;\n}\n\n.mj-markdown-container a:hover {\n text-decoration: underline;\n}\n\n.mj-markdown-container strong {\n font-weight: 600;\n}\n\n.mj-markdown-container em {\n font-style: italic;\n}\n\n/* ============================================\n Lists\n ============================================ */\n.mj-markdown-container ul,\n.mj-markdown-container ol {\n margin: 0 0 1em 0;\n padding-left: 2em;\n}\n\n.mj-markdown-container li {\n margin-bottom: 0.25em;\n}\n\n.mj-markdown-container li > ul,\n.mj-markdown-container li > ol {\n margin-top: 0.25em;\n margin-bottom: 0;\n}\n\n/* Task lists */\n.mj-markdown-container ul.contains-task-list {\n list-style: none;\n padding-left: 0;\n}\n\n.mj-markdown-container li.task-list-item {\n display: flex;\n align-items: flex-start;\n gap: 0.5em;\n}\n\n.mj-markdown-container li.task-list-item input[type=\"checkbox\"] {\n margin-top: 0.35em;\n}\n\n/* ============================================\n Blockquotes\n ============================================ */\n.mj-markdown-container blockquote {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 4px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.mj-markdown-container blockquote > p:last-child {\n margin-bottom: 0;\n}\n\n/* ============================================\n Code Blocks\n ============================================ */\n.mj-markdown-container code {\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Courier New', monospace;\n font-size: 0.9em;\n}\n\n/* Inline code */\n.mj-markdown-container :not(pre) > code {\n padding: 0.2em 0.4em;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n color: var(--mj-status-error);\n}\n\n/* Code blocks\n * design-token-exempt fallbacks: --mj-bg-code-block / --mj-text-code resolve to\n * Monaco-style dark editor colors when an app does not override them. Code\n * blocks intentionally use a fixed dark editor aesthetic (same exemption as\n * Monaco/CodeMirror), so the hex fallbacks here are deliberate. */\n.mj-markdown-container pre {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-code-block, #1e1e1e);\n border-radius: var(--mj-radius-md);\n overflow-x: auto;\n position: relative;\n}\n\n.mj-markdown-container pre code {\n background: transparent;\n padding: 0;\n color: var(--mj-text-code, #d4d4d4);\n font-size: 0.875em;\n line-height: 1.5;\n}\n\n/* ============================================\n Code Toolbar (copy button, language label)\n ============================================ */\n.mj-markdown-container .code-toolbar {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n}\n\n.mj-markdown-container .code-language-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n user-select: none;\n}\n\n.mj-markdown-container .code-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-disabled);\n cursor: pointer;\n transition: all 0.2s ease;\n opacity: 0;\n}\n\n.mj-markdown-container pre:hover .code-copy-btn {\n opacity: 1;\n}\n\n.mj-markdown-container .code-copy-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n}\n\n.mj-markdown-container .code-copy-btn.copied {\n background: color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n color: var(--mj-status-success);\n}\n\n.mj-markdown-container .code-copy-btn.error {\n background: color-mix(in srgb, var(--mj-status-error) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Tables\n ============================================ */\n.mj-markdown-container table {\n width: 100%;\n margin: 1em 0;\n border-collapse: collapse;\n border-spacing: 0;\n}\n\n.mj-markdown-container th,\n.mj-markdown-container td {\n padding: 0.5em 1em;\n border: 1px solid var(--mj-border-default);\n text-align: left;\n}\n\n.mj-markdown-container th {\n background: var(--mj-bg-surface-sunken);\n font-weight: 600;\n}\n\n.mj-markdown-container tr:nth-child(even) {\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================\n Horizontal Rule\n ============================================ */\n.mj-markdown-container hr {\n margin: 2em 0;\n border: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* ============================================\n Images\n ============================================ */\n.mj-markdown-container img {\n max-width: 100%;\n height: auto;\n border-radius: 4px;\n}\n\n/* ============================================\n GitHub-style Alerts (marked-alert)\n ============================================ */\n.mj-markdown-container .markdown-alert {\n margin: 1em 0;\n padding: 1em;\n border-radius: 8px;\n border-left: 4px solid;\n}\n\n.mj-markdown-container .markdown-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n margin-bottom: 0.5em;\n}\n\n.mj-markdown-container .markdown-alert > p:last-child {\n margin-bottom: 0;\n}\n\n/* Note */\n.mj-markdown-container .markdown-alert-note {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-note .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Tip */\n.mj-markdown-container .markdown-alert-tip {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-success);\n}\n\n.mj-markdown-container .markdown-alert-tip .markdown-alert-title {\n color: var(--mj-status-success);\n}\n\n/* Important */\n.mj-markdown-container .markdown-alert-important {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-important .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Warning */\n.mj-markdown-container .markdown-alert-warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.mj-markdown-container .markdown-alert-warning .markdown-alert-title {\n color: var(--mj-status-warning);\n}\n\n/* Caution */\n.mj-markdown-container .markdown-alert-caution {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-error);\n}\n\n.mj-markdown-container .markdown-alert-caution .markdown-alert-title {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Collapsible Headings\n ============================================ */\n.mj-markdown-container .collapsible-section {\n margin: 0.75em 0;\n border-left: 2px solid transparent;\n transition: border-color 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section:hover {\n border-left-color: var(--mj-border-default);\n}\n\n/* Heading wrapper - contains toggle and heading */\n.mj-markdown-container .collapsible-heading-wrapper {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.15s ease;\n user-select: none;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 3%, transparent);\n}\n\n/* The heading itself */\n.mj-markdown-container .collapsible-heading {\n margin: 0 !important;\n flex: 1;\n}\n\n/* Toggle button/icon */\n.mj-markdown-container .collapsible-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease, color 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-toggle svg {\n width: 14px;\n height: 14px;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-toggle {\n color: var(--mj-text-secondary);\n}\n\n/* Expanded state - arrow points down */\n.mj-markdown-container .collapsible-section:not(.collapsed) .collapsible-toggle {\n transform: rotate(90deg);\n}\n\n/* Collapsed state - arrow points right (default SVG orientation) */\n.mj-markdown-container .collapsible-section.collapsed .collapsible-toggle {\n transform: rotate(0deg);\n}\n\n/* Content area */\n.mj-markdown-container .collapsible-content {\n padding-left: 26px;\n overflow: hidden;\n max-height: 5000px; /* Large enough for most content */\n opacity: 1;\n transition: max-height 0.3s ease-out, opacity 0.2s ease-out, padding 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: 0;\n opacity: 0;\n padding-top: 0;\n padding-bottom: 0;\n visibility: hidden;\n}\n\n/* Nested sections - indent further */\n.mj-markdown-container .collapsible-section .collapsible-section {\n margin-left: 0;\n}\n\n/* Focus styles for accessibility */\n.mj-markdown-container .collapsible-heading-wrapper:focus-within {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.mj-markdown-container .collapsible-toggle:focus {\n outline: none;\n}\n\n/* Action buttons container - expand/collapse all */\n.mj-markdown-container .collapsible-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n padding-left: 12px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-actions {\n opacity: 1;\n}\n\n/* Individual action buttons */\n.mj-markdown-container .collapsible-action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\n}\n\n.mj-markdown-container .collapsible-action-btn:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container .collapsible-action-btn:active {\n transform: scale(0.92);\n}\n\n.mj-markdown-container .collapsible-action-btn svg {\n width: 14px;\n height: 14px;\n}\n\n/* Expand all button - double down chevron */\n.mj-markdown-container .collapsible-action-btn.expand-all:hover {\n color: var(--mj-status-success);\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n/* Collapse all button - double up chevron */\n.mj-markdown-container .collapsible-action-btn.collapse-all:hover {\n color: var(--mj-status-error);\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n/* ============================================\n Mermaid Diagrams\n ============================================ */\n.mj-markdown-container .mermaid-diagram {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow-x: auto;\n}\n\n.mj-markdown-container .mermaid-diagram svg {\n max-width: 100%;\n height: auto;\n}\n\n.mj-markdown-container .mermaid-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.mj-markdown-container .mermaid-error::before {\n content: 'Diagram rendering failed';\n display: block;\n color: var(--mj-status-error);\n font-size: 12px;\n margin-bottom: 8px;\n}\n\n/* A specific reason, when we have one \u2014 e.g. the lazily-fetched diagram engine\n never arrived, which is a different problem than bad diagram source. */\n.mj-markdown-container .mermaid-error[data-mermaid-error]::before {\n content: attr(data-mermaid-error);\n}\n\n/* ============================================\n Heading Anchors\n ============================================ */\n.mj-markdown-container h1[id],\n.mj-markdown-container h2[id],\n.mj-markdown-container h3[id],\n.mj-markdown-container h4[id],\n.mj-markdown-container h5[id],\n.mj-markdown-container h6[id] {\n scroll-margin-top: 1em;\n}\n\n.mj-markdown-container h1[id]:hover,\n.mj-markdown-container h2[id]:hover,\n.mj-markdown-container h3[id]:hover,\n.mj-markdown-container h4[id]:hover,\n.mj-markdown-container h5[id]:hover,\n.mj-markdown-container h6[id]:hover {\n cursor: pointer;\n}\n\n/* Anchor link indicator on hover */\n.mj-markdown-container h1[id]::before,\n.mj-markdown-container h2[id]::before,\n.mj-markdown-container h3[id]::before,\n.mj-markdown-container h4[id]::before,\n.mj-markdown-container h5[id]::before,\n.mj-markdown-container h6[id]::before {\n content: '#';\n position: absolute;\n left: -1.5em;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.mj-markdown-container h1[id]:hover::before,\n.mj-markdown-container h2[id]:hover::before,\n.mj-markdown-container h3[id]:hover::before,\n.mj-markdown-container h4[id]:hover::before,\n.mj-markdown-container h5[id]:hover::before,\n.mj-markdown-container h6[id]:hover::before {\n opacity: 1;\n}\n\n/* ============================================\n Line Numbers (optional)\n ============================================ */\n.mj-markdown-container pre.line-numbers {\n padding-left: 3.5em;\n counter-reset: line;\n}\n\n.mj-markdown-container pre.line-numbers code {\n display: block;\n}\n\n.mj-markdown-container pre.line-numbers code .line::before {\n counter-increment: line;\n content: counter(line);\n display: inline-block;\n width: 2em;\n margin-left: -3em;\n margin-right: 1em;\n text-align: right;\n color: var(--mj-text-muted);\n user-select: none;\n}\n\n/* ============================================\n Error State\n ============================================ */\n.mj-markdown-container .markdown-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 1em;\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n white-space: pre-wrap;\n font-family: monospace;\n}\n\n/* Dark Mode Support \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n SVG Rendered Content\n ============================================ */\n.mj-markdown-container .svg-rendered {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow: auto;\n}\n\n.mj-markdown-container .svg-rendered svg {\n max-width: 100%;\n height: auto;\n}\n\n/* Dark mode for SVG rendered content \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n Print Styles\n ============================================ */\n@media print {\n .mj-markdown-container .code-toolbar {\n display: none;\n }\n\n .mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: none;\n opacity: 1;\n visibility: visible;\n }\n\n /* design-token-exempt: print always uses light background + dark text for\n paper readability, regardless of the screen theme the user is rendering from */\n .mj-markdown-container pre {\n background: #f3f4f6 !important;\n color: #1f2937 !important;\n }\n\n .mj-markdown-container pre code {\n color: #1f2937 !important;\n }\n}\n"] }]
733
+ args: [{ selector: 'mj-markdown', standalone: false, template: ` <div class="mj-markdown-container" [class]="containerClass" [innerHTML]="renderedContent"></div> `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["/**\n * MJ Markdown Component Styles\n *\n * These styles apply to rendered markdown content.\n * Using ViewEncapsulation.None so styles penetrate into dynamically generated content.\n */\n\n/* ============================================\n Container\n ============================================ */\n.mj-markdown-container {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 15px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n word-wrap: break-word;\n}\n\n/* ============================================\n Typography\n ============================================ */\n.mj-markdown-container h1,\n.mj-markdown-container h2,\n.mj-markdown-container h3,\n.mj-markdown-container h4,\n.mj-markdown-container h5,\n.mj-markdown-container h6 {\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n font-weight: 600;\n line-height: 1.25;\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container h1 { font-size: 1.75em; }\n.mj-markdown-container h2 { font-size: 1.5em; }\n.mj-markdown-container h3 { font-size: 1.25em; }\n.mj-markdown-container h4 { font-size: 1.1em; }\n.mj-markdown-container h5 { font-size: 1em; }\n.mj-markdown-container h6 { font-size: 0.9em; color: var(--mj-text-secondary); }\n\n.mj-markdown-container > h1:first-child,\n.mj-markdown-container > h2:first-child,\n.mj-markdown-container > h3:first-child {\n margin-top: 0;\n}\n\n.mj-markdown-container p {\n margin: 0 0 1em 0;\n}\n\n.mj-markdown-container > p:last-child {\n margin-bottom: 0;\n}\n\n.mj-markdown-container a {\n color: var(--mj-brand-primary);\n text-decoration: none;\n}\n\n.mj-markdown-container a:hover {\n text-decoration: underline;\n}\n\n.mj-markdown-container strong {\n font-weight: 600;\n}\n\n.mj-markdown-container em {\n font-style: italic;\n}\n\n/* ============================================\n Lists\n ============================================ */\n.mj-markdown-container ul,\n.mj-markdown-container ol {\n margin: 0 0 1em 0;\n padding-left: 2em;\n}\n\n.mj-markdown-container li {\n margin-bottom: 0.25em;\n}\n\n.mj-markdown-container li > ul,\n.mj-markdown-container li > ol {\n margin-top: 0.25em;\n margin-bottom: 0;\n}\n\n/* Task lists */\n.mj-markdown-container ul.contains-task-list {\n list-style: none;\n padding-left: 0;\n}\n\n.mj-markdown-container li.task-list-item {\n display: flex;\n align-items: flex-start;\n gap: 0.5em;\n}\n\n.mj-markdown-container li.task-list-item input[type=\"checkbox\"] {\n margin-top: 0.35em;\n}\n\n/* ============================================\n Blockquotes\n ============================================ */\n.mj-markdown-container blockquote {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 4px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.mj-markdown-container blockquote > p:last-child {\n margin-bottom: 0;\n}\n\n/* ============================================\n Code Blocks\n ============================================ */\n.mj-markdown-container code {\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Courier New', monospace;\n font-size: 0.9em;\n}\n\n/* Inline code */\n.mj-markdown-container :not(pre) > code {\n padding: 0.2em 0.4em;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n color: var(--mj-status-error);\n}\n\n/* Code blocks\n * design-token-exempt fallbacks: --mj-bg-code-block / --mj-text-code resolve to\n * Monaco-style dark editor colors when an app does not override them. Code\n * blocks intentionally use a fixed dark editor aesthetic (same exemption as\n * Monaco/CodeMirror), so the hex fallbacks here are deliberate. */\n.mj-markdown-container pre {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-code-block, #1e1e1e);\n border-radius: var(--mj-radius-md);\n overflow-x: auto;\n position: relative;\n}\n\n.mj-markdown-container pre code {\n background: transparent;\n padding: 0;\n color: var(--mj-text-code, #d4d4d4);\n font-size: 0.875em;\n line-height: 1.5;\n}\n\n/* ============================================\n Code Toolbar (copy button, language label)\n ============================================ */\n.mj-markdown-container .code-toolbar {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n}\n\n.mj-markdown-container .code-language-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n user-select: none;\n}\n\n.mj-markdown-container .code-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-disabled);\n cursor: pointer;\n transition: all 0.2s ease;\n opacity: 0;\n}\n\n.mj-markdown-container pre:hover .code-copy-btn {\n opacity: 1;\n}\n\n.mj-markdown-container .code-copy-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n}\n\n.mj-markdown-container .code-copy-btn.copied {\n background: color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n color: var(--mj-status-success);\n}\n\n.mj-markdown-container .code-copy-btn.error {\n background: color-mix(in srgb, var(--mj-status-error) 20%, transparent);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Tables\n ============================================ */\n.mj-markdown-container table {\n width: 100%;\n margin: 1em 0;\n border-collapse: collapse;\n border-spacing: 0;\n}\n\n.mj-markdown-container th,\n.mj-markdown-container td {\n padding: 0.5em 1em;\n border: 1px solid var(--mj-border-default);\n text-align: left;\n}\n\n.mj-markdown-container th {\n background: var(--mj-bg-surface-sunken);\n font-weight: 600;\n}\n\n.mj-markdown-container tr:nth-child(even) {\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================\n Horizontal Rule\n ============================================ */\n.mj-markdown-container hr {\n margin: 2em 0;\n border: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* ============================================\n Images\n ============================================ */\n.mj-markdown-container img {\n max-width: 100%;\n height: auto;\n border-radius: 4px;\n}\n\n/* ============================================\n GitHub-style Alerts (marked-alert)\n ============================================ */\n.mj-markdown-container .markdown-alert {\n margin: 1em 0;\n padding: 1em;\n border-radius: 8px;\n border-left: 4px solid;\n}\n\n.mj-markdown-container .markdown-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n margin-bottom: 0.5em;\n}\n\n.mj-markdown-container .markdown-alert > p:last-child {\n margin-bottom: 0;\n}\n\n/* Note */\n.mj-markdown-container .markdown-alert-note {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-note .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Tip */\n.mj-markdown-container .markdown-alert-tip {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-success);\n}\n\n.mj-markdown-container .markdown-alert-tip .markdown-alert-title {\n color: var(--mj-status-success);\n}\n\n/* Important */\n.mj-markdown-container .markdown-alert-important {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.mj-markdown-container .markdown-alert-important .markdown-alert-title {\n color: var(--mj-brand-primary);\n}\n\n/* Warning */\n.mj-markdown-container .markdown-alert-warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.mj-markdown-container .markdown-alert-warning .markdown-alert-title {\n color: var(--mj-status-warning);\n}\n\n/* Caution */\n.mj-markdown-container .markdown-alert-caution {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: var(--mj-status-error);\n}\n\n.mj-markdown-container .markdown-alert-caution .markdown-alert-title {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Collapsible Headings\n ============================================ */\n.mj-markdown-container .collapsible-section {\n margin: 0.75em 0;\n border-left: 2px solid transparent;\n transition: border-color 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section:hover {\n border-left-color: var(--mj-border-default);\n}\n\n/* Heading wrapper - contains toggle and heading */\n.mj-markdown-container .collapsible-heading-wrapper {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.15s ease;\n user-select: none;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 3%, transparent);\n}\n\n/* The heading itself */\n.mj-markdown-container .collapsible-heading {\n margin: 0 !important;\n flex: 1;\n}\n\n/* Toggle button/icon */\n.mj-markdown-container .collapsible-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease, color 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-toggle svg {\n width: 14px;\n height: 14px;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-toggle {\n color: var(--mj-text-secondary);\n}\n\n/* Expanded state - arrow points down */\n.mj-markdown-container .collapsible-section:not(.collapsed) .collapsible-toggle {\n transform: rotate(90deg);\n}\n\n/* Collapsed state - arrow points right (default SVG orientation) */\n.mj-markdown-container .collapsible-section.collapsed .collapsible-toggle {\n transform: rotate(0deg);\n}\n\n/* Content area */\n.mj-markdown-container .collapsible-content {\n padding-left: 26px;\n overflow: hidden;\n max-height: 5000px; /* Large enough for most content */\n opacity: 1;\n transition: max-height 0.3s ease-out, opacity 0.2s ease-out, padding 0.2s ease;\n}\n\n.mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: 0;\n opacity: 0;\n padding-top: 0;\n padding-bottom: 0;\n visibility: hidden;\n}\n\n/* Nested sections - indent further */\n.mj-markdown-container .collapsible-section .collapsible-section {\n margin-left: 0;\n}\n\n/* Focus styles for accessibility */\n.mj-markdown-container .collapsible-heading-wrapper:focus-within {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.mj-markdown-container .collapsible-toggle:focus {\n outline: none;\n}\n\n/* Action buttons container - expand/collapse all */\n.mj-markdown-container .collapsible-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n padding-left: 12px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.mj-markdown-container .collapsible-heading-wrapper:hover .collapsible-actions {\n opacity: 1;\n}\n\n/* Individual action buttons */\n.mj-markdown-container .collapsible-action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\n}\n\n.mj-markdown-container .collapsible-action-btn:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.mj-markdown-container .collapsible-action-btn:active {\n transform: scale(0.92);\n}\n\n.mj-markdown-container .collapsible-action-btn svg {\n width: 14px;\n height: 14px;\n}\n\n/* Expand all button - double down chevron */\n.mj-markdown-container .collapsible-action-btn.expand-all:hover {\n color: var(--mj-status-success);\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n/* Collapse all button - double up chevron */\n.mj-markdown-container .collapsible-action-btn.collapse-all:hover {\n color: var(--mj-status-error);\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n/* ============================================\n Math (TeX typeset as MathML by MarkdownService.RenderMath, and MathML markup)\n ============================================ */\n.mj-markdown-container .mj-math-block {\n display: block;\n margin: 1em 0;\n overflow-x: auto;\n overflow-y: hidden;\n}\n\n/* A wide display formula scrolls instead of widening the message. */\n.mj-markdown-container .katex:has(> math[display=\"block\"]) {\n display: block;\n overflow-x: auto;\n overflow-y: hidden;\n}\n\n/* Bold styles Unicode has no math letters for (Greek, text runs); Chrome ignores mathvariant. */\n.mj-markdown-container math [mathvariant*=\"bold\"] {\n font-weight: bold;\n}\n\n/* Chrome ignores MathML's columnalign too, which centres every cell and un-aligns the \"=\" signs of\n a derivation. KaTeX writes exactly \"right left\" (repeated, for alignedat) for aligned, split and\n alignedat, and \"left left\" for cases; JATS tables often say just \"left\" or \"right\". Other column\n lists (arrays) stay centred. */\n.mj-markdown-container mtable:is([columnalign=\"right left\"], [columnalign^=\"right left right left\"]) > mtr > mtd:nth-child(odd) {\n text-align: right;\n}\n\n.mj-markdown-container mtable:is([columnalign=\"right left\"], [columnalign^=\"right left right left\"]) > mtr > mtd:nth-child(even),\n.mj-markdown-container mtable:is([columnalign=\"left left\"], [columnalign=\"left\"]) > mtr > mtd {\n text-align: left;\n}\n\n.mj-markdown-container mtable[columnalign=\"right\"] > mtr > mtd {\n text-align: right;\n}\n\n/* TeX that KaTeX could not parse stays visible as source; its title says why. */\n.mj-markdown-container code.mj-math-error {\n text-decoration: underline wavy var(--mj-status-error);\n}\n\n/* ============================================\n Mermaid Diagrams\n ============================================ */\n.mj-markdown-container .mermaid-diagram {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow-x: auto;\n}\n\n.mj-markdown-container .mermaid-diagram svg {\n max-width: 100%;\n height: auto;\n}\n\n.mj-markdown-container .mermaid-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.mj-markdown-container .mermaid-error::before {\n content: 'Diagram rendering failed';\n display: block;\n color: var(--mj-status-error);\n font-size: 12px;\n margin-bottom: 8px;\n}\n\n/* A specific reason, when we have one \u2014 e.g. the lazily-fetched diagram engine\n never arrived, which is a different problem than bad diagram source. */\n.mj-markdown-container .mermaid-error[data-mermaid-error]::before {\n content: attr(data-mermaid-error);\n}\n\n/* ============================================\n Heading Anchors\n ============================================ */\n.mj-markdown-container h1[id],\n.mj-markdown-container h2[id],\n.mj-markdown-container h3[id],\n.mj-markdown-container h4[id],\n.mj-markdown-container h5[id],\n.mj-markdown-container h6[id] {\n scroll-margin-top: 1em;\n}\n\n.mj-markdown-container h1[id]:hover,\n.mj-markdown-container h2[id]:hover,\n.mj-markdown-container h3[id]:hover,\n.mj-markdown-container h4[id]:hover,\n.mj-markdown-container h5[id]:hover,\n.mj-markdown-container h6[id]:hover {\n cursor: pointer;\n}\n\n/* Anchor link indicator on hover */\n.mj-markdown-container h1[id]::before,\n.mj-markdown-container h2[id]::before,\n.mj-markdown-container h3[id]::before,\n.mj-markdown-container h4[id]::before,\n.mj-markdown-container h5[id]::before,\n.mj-markdown-container h6[id]::before {\n content: '#';\n position: absolute;\n left: -1.5em;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.mj-markdown-container h1[id]:hover::before,\n.mj-markdown-container h2[id]:hover::before,\n.mj-markdown-container h3[id]:hover::before,\n.mj-markdown-container h4[id]:hover::before,\n.mj-markdown-container h5[id]:hover::before,\n.mj-markdown-container h6[id]:hover::before {\n opacity: 1;\n}\n\n/* ============================================\n Line Numbers (optional)\n ============================================ */\n.mj-markdown-container pre.line-numbers {\n padding-left: 3.5em;\n counter-reset: line;\n}\n\n.mj-markdown-container pre.line-numbers code {\n display: block;\n}\n\n.mj-markdown-container pre.line-numbers code .line::before {\n counter-increment: line;\n content: counter(line);\n display: inline-block;\n width: 2em;\n margin-left: -3em;\n margin-right: 1em;\n text-align: right;\n color: var(--mj-text-muted);\n user-select: none;\n}\n\n/* ============================================\n Error State\n ============================================ */\n.mj-markdown-container .markdown-error {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 1em;\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n white-space: pre-wrap;\n font-family: monospace;\n}\n\n/* Dark Mode Support \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n SVG Rendered Content\n ============================================ */\n.mj-markdown-container .svg-rendered {\n margin: 1em 0;\n padding: 1em;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n text-align: center;\n overflow: auto;\n}\n\n.mj-markdown-container .svg-rendered svg {\n max-width: 100%;\n height: auto;\n}\n\n/* Dark mode for SVG rendered content \u2014 handled automatically by --mj-* semantic tokens */\n\n/* ============================================\n Print Styles\n ============================================ */\n@media print {\n .mj-markdown-container .code-toolbar {\n display: none;\n }\n\n .mj-markdown-container .collapsible-section.collapsed .collapsible-content {\n max-height: none;\n opacity: 1;\n visibility: visible;\n }\n\n /* design-token-exempt: print always uses light background + dark text for\n paper readability, regardless of the screen theme the user is rendering from */\n .mj-markdown-container pre {\n background: #f3f4f6 !important;\n color: #1f2937 !important;\n }\n\n .mj-markdown-container pre code {\n color: #1f2937 !important;\n }\n}\n"] }]
716
734
  }], () => [{ type: i0.ElementRef }, { type: i1.DomSanitizer }, { type: i2.MarkdownService }, { type: i0.ChangeDetectorRef }], { Data: [{
717
735
  type: Input
718
736
  }], data: [{
@@ -725,6 +743,8 @@ export class MarkdownComponent {
725
743
  type: Input
726
744
  }], enableMermaid: [{
727
745
  type: Input
746
+ }], EnableMath: [{
747
+ type: Input
728
748
  }], EnableCodeCopy: [{
729
749
  type: Input
730
750
  }], enableCodeCopy: [{