markstream-angular 0.0.9-beta.2 → 0.0.10

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.
@@ -622,22 +622,35 @@ async function getUseMonaco() {
622
622
  if (importAttempted$2)
623
623
  return null;
624
624
  pendingImport$3 = (async () => {
625
- try {
626
- const imported = await import('stream-monaco');
627
- monacoModule = imported?.default ?? imported;
628
- await preloadWorkers(monacoModule);
629
- const ready = await warmupShikiTokenizer(monacoModule);
630
- if (!ready) {
631
- monacoModule = null;
632
- importAttempted$2 = true;
633
- return null;
625
+ // Prefer `stream-diffs`: smaller runtime without the heavy
626
+ // `monaco-editor` dependency. `stream-monaco` remains supported as a
627
+ // fallback for consumers who install it.
628
+ const candidates = [
629
+ async () => (await import('stream-diffs')),
630
+ async () => (await import('stream-monaco')),
631
+ ];
632
+ for (const load of candidates) {
633
+ try {
634
+ const candidate = await load();
635
+ const resolved = candidate?.default ?? candidate;
636
+ if (typeof resolved?.useMonaco !== 'function')
637
+ continue;
638
+ monacoModule = resolved;
639
+ await preloadWorkers(monacoModule);
640
+ const ready = await warmupShikiTokenizer(monacoModule);
641
+ if (!ready) {
642
+ monacoModule = null;
643
+ importAttempted$2 = true;
644
+ return null;
645
+ }
646
+ return monacoModule;
647
+ }
648
+ catch {
649
+ // Try the next candidate runtime.
634
650
  }
635
- return monacoModule;
636
- }
637
- catch {
638
- importAttempted$2 = true;
639
- return null;
640
651
  }
652
+ importAttempted$2 = true;
653
+ return null;
641
654
  })();
642
655
  try {
643
656
  return await pendingImport$3;
@@ -647,47 +660,23 @@ async function getUseMonaco() {
647
660
  }
648
661
  }
649
662
 
650
- const DEFAULT_ICON = `
651
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
652
- <path d="M14 3h5a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5" />
653
- <path d="M8 11l-3 3l3 3" />
654
- <path d="M16 11l3 3l-3 3" />
655
- <path d="M13 9l-2 10" />
656
- </svg>`;
657
- const MERMAID_ICON = `
658
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
659
- <rect x="3" y="4" width="7" height="5" rx="1.5" />
660
- <rect x="14" y="4" width="7" height="5" rx="1.5" />
661
- <rect x="8.5" y="15" width="7" height="5" rx="1.5" />
662
- <path d="M10 6.5h4" />
663
- <path d="M12 9v2.5" />
664
- <path d="M12 11.5l-3.5 3.5" />
665
- <path d="M12 11.5l3.5 3.5" />
666
- </svg>`;
667
- const HTML_ICON = `
668
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
669
- <path d="M8 7l-4 5l4 5" />
670
- <path d="M16 7l4 5l-4 5" />
671
- <path d="M14 4l-4 16" />
672
- </svg>`;
673
- const MARKDOWN_ICON = `
674
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
675
- <rect x="3" y="4" width="18" height="16" rx="2" />
676
- <path d="M7 15V9l3 3l3-3v6" />
677
- <path d="M16 9v6" />
678
- <path d="M14 13l2 2l2-2" />
679
- </svg>`;
680
- const JSON_ICON = `
681
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
682
- <path d="M9 4c-2 0-3 1.5-3 3.5v2c0 1.1-.4 1.8-1.5 2.5C5.6 12.7 6 13.4 6 14.5v2C6 18.5 7 20 9 20" />
683
- <path d="M15 4c2 0 3 1.5 3 3.5v2c0 1.1.4 1.8 1.5 2.5c-1.1.7-1.5 1.4-1.5 2.5v2c0 2-1 3.5-3 3.5" />
684
- </svg>`;
685
- const TEXT_ICON = `
686
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
687
- <path d="M5 6h14" />
688
- <path d="M12 6v12" />
689
- <path d="M8 18h8" />
690
- </svg>`;
663
+ // Keep Angular's default language icons visually identical to the Vue 3 Material theme.
664
+ const MATERIAL_FALLBACK_ICON = '<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#ff7043" d="M2 2a1 1 0 0 0-1 1v10c0 .554.446 1 1 1h12c.554 0 1-.446 1-1V3a1 1 0 0 0-1-1zm0 3h12v8H2zm1 2 2 2-2 2 1 1 3-3-3-3zm5 3.5V12h5v-1.5z"/></svg>';
665
+ const MATERIAL_TEXT_ICON = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path d="M0 0h24v24H0z"/><path fill="#42a5f5" d="M8 16h8v2H8zm0-4h8v2H8zm6-10H6c-1.1 0-2 .9-2 2v16c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zm4 18H6V4h7v5h5z"/></svg>';
666
+ const MATERIAL_PLAIN_ICON = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path d="M0 0h24v24H0z"/><path fill="#42a5f5" d="M8 16h8v2H8zm0-4h8v2H8zm6-10H6c-1.1 0-2 .9-2 2v16c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zm4 18H6V4h7v5h5z"/></svg>';
667
+ const MATERIAL_HTML_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#e65100" d="m4 4 2 22 10 2 10-2 2-22Zm19.72 7H11.28l.29 3h11.86l-.802 9.335L15.99 25l-6.635-1.646L8.93 19h3.02l.19 2 3.86.77 3.84-.77.29-4H8.84L8 8h16Z"/></svg>';
668
+ const MATERIAL_CSS_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#7e57c2" d="M20 18h-2v-2h-2v2c0 .193 0 .703 1.254 1.033A3.345 3.345 0 0 1 20 22h2v2h2v-2c0-.388-.562-.851-1.254-1.034C20.356 20.34 20 18.84 20 18m-3.254 2.966C14.356 20.34 14 18.84 14 18h-2v-2h-2v8h2v-2h4v2h2v-2c0-.388-.562-.851-1.254-1.034"/><path fill="#7e57c2" d="M24 4H4v20a4 4 0 0 0 4 4h16.16A3.84 3.84 0 0 0 28 24.16V8a4 4 0 0 0-4-4m2 14h-2v-2h-2v2c0 .193 0 .703 1.254 1.033A3.345 3.345 0 0 1 26 22v2a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2 2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2 2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2 2 2 0 0 1 2-2h2a2 2 0 0 1 2 2 2 2 0 0 1 2-2h2a2 2 0 0 1 2 2Z"/></svg>';
669
+ const MATERIAL_JAVASCRIPT_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#ffca28" d="M2 2v12h12V2zm6 6h1v4a1.003 1.003 0 0 1-1 1H7a1.003 1.003 0 0 1-1-1v-1h1v1h1zm3 0h2v1h-2v1h1a1.003 1.003 0 0 1 1 1v1a1.003 1.003 0 0 1-1 1h-2v-1h2v-1h-1a1.003 1.003 0 0 1-1-1V9a1.003 1.003 0 0 1 1-1"/></svg>';
670
+ const MATERIAL_TYPESCRIPT_ICON = '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 16 16"><path fill="#0288d1" d="M2 2v12h12V2zm4 6h3v1H8v4H7V9H6zm5 0h2v1h-2v1h1a1.003 1.003 0 0 1 1 1v1a1.003 1.003 0 0 1-1 1h-2v-1h2v-1h-1a1.003 1.003 0 0 1-1-1V9a1.003 1.003 0 0 1 1-1"/></svg>';
671
+ const MATERIAL_JSX_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#00bcd4" d="M16 12c7.444 0 12 2.59 12 4s-4.556 4-12 4-12-2.59-12-4 4.556-4 12-4m0-2c-7.732 0-14 2.686-14 6s6.268 6 14 6 14-2.686 14-6-6.268-6-14-6"/><path fill="#00bcd4" d="M16 14a2 2 0 1 0 2 2 2 2 0 0 0-2-2"/><path fill="#00bcd4" d="M10.458 5.507c2.017 0 5.937 3.177 9.006 8.493 3.722 6.447 3.757 11.687 2.536 12.392a.9.9 0 0 1-.457.1c-2.017 0-5.938-3.176-9.007-8.492C8.814 11.553 8.779 6.313 10 5.608a.9.9 0 0 1 .458-.1m-.001-2A2.87 2.87 0 0 0 9 3.875C6.13 5.532 6.938 12.304 10.804 19c3.284 5.69 7.72 9.493 10.74 9.493A2.87 2.87 0 0 0 23 28.124c2.87-1.656 2.062-8.428-1.804-15.124-3.284-5.69-7.72-9.493-10.74-9.493Z"/><path fill="#00bcd4" d="M21.543 5.507a.9.9 0 0 1 .457.1c1.221.706 1.186 5.946-2.536 12.393-3.07 5.316-6.99 8.493-9.007 8.493a.9.9 0 0 1-.457-.1C8.779 25.686 8.814 20.446 12.536 14c3.07-5.316 6.99-8.493 9.007-8.493m0-2c-3.02 0-7.455 3.804-10.74 9.493C6.939 19.696 6.13 26.468 9 28.124a2.87 2.87 0 0 0 1.457.369c3.02 0 7.455-3.804 10.74-9.493C25.061 12.304 25.87 5.532 23 3.876a2.87 2.87 0 0 0-1.457-.369"/></svg>';
672
+ const MATERIAL_TSX_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#0288d1" d="M16 12c7.444 0 12 2.59 12 4s-4.556 4-12 4-12-2.59-12-4 4.556-4 12-4m0-2c-7.732 0-14 2.686-14 6s6.268 6 14 6 14-2.686 14-6-6.268-6-14-6"/><path fill="#0288d1" d="M16 14a2 2 0 1 0 2 2 2 2 0 0 0-2-2"/><path fill="#0288d1" d="M10.458 5.507c2.017 0 5.937 3.177 9.006 8.493 3.722 6.447 3.757 11.687 2.536 12.392a.9.9 0 0 1-.457.1c-2.017 0-5.938-3.176-9.007-8.492C8.814 11.553 8.779 6.313 10 5.608a.9.9 0 0 1 .458-.1m-.001-2A2.87 2.87 0 0 0 9 3.875C6.13 5.532 6.938 12.304 10.804 19c3.284 5.69 7.72 9.493 10.74 9.493A2.87 2.87 0 0 0 23 28.124c2.87-1.656 2.062-8.428-1.804-15.124-3.284-5.69-7.72-9.493-10.74-9.493Z"/><path fill="#0288d1" d="M21.543 5.507a.9.9 0 0 1 .457.1c1.221.706 1.186 5.946-2.536 12.393-3.07 5.316-6.99 8.493-9.007 8.493a.9.9 0 0 1-.457-.1C8.779 25.686 8.814 20.446 12.536 14c3.07-5.316 6.99-8.493 9.007-8.493m0-2c-3.02 0-7.455 3.804-10.74 9.493C6.939 19.696 6.13 26.468 9 28.124a2.87 2.87 0 0 0 1.457.369c3.02 0 7.455-3.804 10.74-9.493C25.061 12.304 25.87 5.532 23 3.876a2.87 2.87 0 0 0-1.457-.369"/></svg>';
673
+ const MATERIAL_JSON_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="#f9a825" d="M560-160v-80h120q17 0 28.5-11.5T720-280v-80q0-38 22-69t58-44v-14q-36-13-58-44t-22-69v-80q0-17-11.5-28.5T680-720H560v-80h120q50 0 85 35t35 85v80q0 17 11.5 28.5T840-560h40v160h-40q-17 0-28.5 11.5T800-360v80q0 50-35 85t-85 35zm-280 0q-50 0-85-35t-35-85v-80q0-17-11.5-28.5T120-400H80v-160h40q17 0 28.5-11.5T160-600v-80q0-50 35-85t85-35h120v80H280q-17 0-28.5 11.5T240-680v80q0 38-22 69t-58 44v14q36 13 58 44t22 69v80q0 17 11.5 28.5T280-240h120v80z"/></svg>';
674
+ const MATERIAL_MARKDOWN_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#42a5f5" d="m14 10-4 3.5L6 10H4v12h4v-6l2 2 2-2v6h4V10zm12 6v-6h-4v6h-4l6 8 6-8z"/></svg>';
675
+ const MATERIAL_MERMAID_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="none" stroke="#26c6da" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M3 5c0 12 4.5 11.5 8 14 1.66 1.33 2.34 4 2 8h6c-.34-4 .34-6.67 2-8 3.5-2.5 8-2 8-14-4 0-8 1-12 9-4-8-8-9-12-9z"/></svg>';
676
+ const MATERIAL_PYTHON_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#0288d1" d="M9.86 2A2.86 2.86 0 0 0 7 4.86v1.68h4.29c.39 0 .71.57.71.96H4.86A2.86 2.86 0 0 0 2 10.36v3.781a2.86 2.86 0 0 0 2.86 2.86h1.18v-2.68a2.85 2.85 0 0 1 2.85-2.86h5.25c1.58 0 2.86-1.271 2.86-2.851V4.86A2.86 2.86 0 0 0 14.14 2zm-.72 1.61c.4 0 .72.12.72.71s-.32.891-.72.891c-.39 0-.71-.3-.71-.89s.32-.711.71-.711"/><path fill="#fdd835" d="M17.959 7v2.68a2.85 2.85 0 0 1-2.85 2.859H9.86A2.85 2.85 0 0 0 7 15.389v3.75a2.86 2.86 0 0 0 2.86 2.86h4.28A2.86 2.86 0 0 0 17 19.14v-1.68h-4.291c-.39 0-.709-.57-.709-.96h7.14A2.86 2.86 0 0 0 22 13.64V9.86A2.86 2.86 0 0 0 19.14 7zM8.32 11.513l-.004.004.038-.004zm6.54 7.276c.39 0 .71.3.71.89a.71.71 0 0 1-.71.71c-.4 0-.72-.12-.72-.71s.32-.89.72-.89"/></svg>';
677
+ const MATERIAL_SHELL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#ff7043" d="M2 2a1 1 0 0 0-1 1v10c0 .554.446 1 1 1h12c.554 0 1-.446 1-1V3a1 1 0 0 0-1-1zm0 3h12v8H2zm1 2 2 2-2 2 1 1 3-3-3-3zm5 3.5V12h5v-1.5z"/></svg>';
678
+ const MATERIAL_SVG_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#8bc34a" d="M13 9h5.5L13 3.5zM6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m.12 13.5 3.74 3.74 1.42-1.41-2.33-2.33 2.33-2.33-1.42-1.41zm11.16 0-3.74-3.74-1.42 1.41 2.33 2.33-2.33 2.33 1.42 1.41z"/></svg>';
679
+ const MATERIAL_VUE_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#41b883" d="M1.791 3.851 12 21.471 22.209 3.936V3.85H18.24l-6.18 10.616L5.906 3.851z"/><path fill="#35495e" d="m5.907 3.851 6.152 10.617L18.24 3.851h-3.723L12.084 8.03 9.66 3.85z"/></svg>';
691
680
  const LANGUAGE_ALIAS_MAP = {
692
681
  '': '',
693
682
  'cjs': 'javascript',
@@ -724,19 +713,21 @@ const LANGUAGE_LABEL_MAP = {
724
713
  'vue': 'Vue',
725
714
  };
726
715
  const LANGUAGE_ICON_MAP = {
727
- '': TEXT_ICON,
728
- 'html': HTML_ICON,
729
- 'javascript': DEFAULT_ICON,
730
- 'json': JSON_ICON,
731
- 'jsx': DEFAULT_ICON,
732
- 'markdown': MARKDOWN_ICON,
733
- 'mermaid': MERMAID_ICON,
734
- 'plain': TEXT_ICON,
735
- 'python': DEFAULT_ICON,
736
- 'shell': DEFAULT_ICON,
737
- 'svg': HTML_ICON,
738
- 'tsx': DEFAULT_ICON,
739
- 'typescript': DEFAULT_ICON,
716
+ '': MATERIAL_TEXT_ICON,
717
+ 'css': MATERIAL_CSS_ICON,
718
+ 'html': MATERIAL_HTML_ICON,
719
+ 'javascript': MATERIAL_JAVASCRIPT_ICON,
720
+ 'json': MATERIAL_JSON_ICON,
721
+ 'jsx': MATERIAL_JSX_ICON,
722
+ 'markdown': MATERIAL_MARKDOWN_ICON,
723
+ 'mermaid': MATERIAL_MERMAID_ICON,
724
+ 'plain': MATERIAL_PLAIN_ICON,
725
+ 'python': MATERIAL_PYTHON_ICON,
726
+ 'shell': MATERIAL_SHELL_ICON,
727
+ 'svg': MATERIAL_SVG_ICON,
728
+ 'tsx': MATERIAL_TSX_ICON,
729
+ 'typescript': MATERIAL_TYPESCRIPT_ICON,
730
+ 'vue': MATERIAL_VUE_ICON,
740
731
  };
741
732
  let userLanguageIconResolver = null;
742
733
  function extractLanguageToken(lang) {
@@ -775,17 +766,49 @@ function getLanguageIcon(lang) {
775
766
  return hit;
776
767
  }
777
768
  const normalized = normalizeLanguageIdentifier(lang);
778
- return LANGUAGE_ICON_MAP[normalized] || DEFAULT_ICON;
769
+ return LANGUAGE_ICON_MAP[normalized] || MATERIAL_FALLBACK_ICON;
779
770
  }
780
771
  const languageMap = LANGUAGE_LABEL_MAP;
781
772
 
773
+ function countCodeLines(code) {
774
+ let count = 1;
775
+ for (let index = 0; index < code.length; index++) {
776
+ if (code[index] === '\n') {
777
+ count++;
778
+ }
779
+ else if (code[index] === '\r') {
780
+ count++;
781
+ if (code[index + 1] === '\n')
782
+ index++;
783
+ }
784
+ }
785
+ return count;
786
+ }
787
+ function getDisplayCode(code, loading) {
788
+ const value = getString$1(code);
789
+ return loading ? value : value.replace(/\r\n$|\n$|\r$/, '');
790
+ }
782
791
  class PreCodeNodeComponent {
792
+ constructor() {
793
+ this.showLineNumbers = false;
794
+ // ─── Line-count caching (mirrors the vue3 PreCodeNode) ─────────────────────
795
+ this.cachedCode = '';
796
+ this.cachedCount = 1;
797
+ this.textCount = 0;
798
+ this.textCache = '';
799
+ }
783
800
  get language() {
784
801
  return normalizeCodeLanguage(this.node?.language);
785
802
  }
786
803
  get languageClass() {
787
804
  return `language-${this.language}`;
788
805
  }
806
+ get preClasses() {
807
+ return {
808
+ [this.languageClass]: true,
809
+ 'markstream-pre--line-numbers': this.showLineNumbers === true,
810
+ };
811
+ }
789
812
  get ariaLabel() {
790
813
  return this.language ? `Code block: ${this.language}` : 'Code block';
791
814
  }
@@ -795,20 +818,74 @@ class PreCodeNodeComponent {
795
818
  get loading() {
796
819
  return this.node?.loading === true;
797
820
  }
821
+ get displayCode() {
822
+ return getDisplayCode(this.node?.code, this.loading);
823
+ }
824
+ get codeLineCount() {
825
+ const code = this.displayCode;
826
+ if (code === this.cachedCode)
827
+ return this.cachedCount;
828
+ this.cachedCount = countCodeLines(code);
829
+ this.cachedCode = code;
830
+ return this.cachedCount;
831
+ }
832
+ get lineNumbersText() {
833
+ const count = this.codeLineCount;
834
+ if (count < this.textCount) {
835
+ this.textCount = 0;
836
+ this.textCache = '';
837
+ }
838
+ for (let line = this.textCount + 1; line <= count; line++)
839
+ this.textCache += `${this.textCache ? '\n' : ''}${line}`;
840
+ this.textCount = count;
841
+ return this.textCache;
842
+ }
843
+ get lineNumberLayoutStyle() {
844
+ if (this.showLineNumbers !== true)
845
+ return null;
846
+ const maximumLineNumber = this.codeLineCount;
847
+ const width = `${Math.max(4, String(maximumLineNumber).length)}ch`;
848
+ return {
849
+ '--markstream-pre-line-number-width': width,
850
+ '--markstream-pre-diff-line-number-width': width,
851
+ '--markstream-code-padding-left': 'calc(var(--markstream-pre-line-number-padding-left, 2ch) + var(--markstream-pre-line-number-width, 2ch) + var(--markstream-pre-line-number-padding-right, 1ch) + var(--markstream-pre-line-number-separator-width, 2px) + var(--markstream-pre-line-number-gap-to-code, 1ch))',
852
+ };
853
+ }
798
854
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.26", ngImport: i0, type: PreCodeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
799
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.26", type: PreCodeNodeComponent, isStandalone: true, selector: "markstream-angular-pre-code-node", inputs: { node: "node" }, ngImport: i0, template: `<pre [class]="languageClass" [attr.aria-busy]="loading" [attr.aria-label]="ariaLabel" [attr.data-language]="language" tabindex="0"><code translate="no" [textContent]="code"></code></pre>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
855
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.26", type: PreCodeNodeComponent, isStandalone: true, selector: "markstream-angular-pre-code-node", inputs: { node: "node", showLineNumbers: "showLineNumbers" }, ngImport: i0, template: `<pre
856
+ [ngClass]="preClasses"
857
+ [ngStyle]="lineNumberLayoutStyle"
858
+ [attr.aria-busy]="loading"
859
+ [attr.aria-label]="ariaLabel"
860
+ [attr.data-language]="language"
861
+ [attr.data-markstream-line-numbers]="showLineNumbers ? '1' : null"
862
+ data-markstream-pre="1"
863
+ tabindex="0"
864
+ ><ng-container *ngIf="showLineNumbers"><span class="markstream-pre__line-numbers" aria-hidden="true"><span class="markstream-pre__line-numbers-text">{{ lineNumbersText }}</span></span></ng-container><code translate="no" class="markstream-pre__code" [textContent]="displayCode"></code></pre>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
800
865
  }
801
866
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImport: i0, type: PreCodeNodeComponent, decorators: [{
802
867
  type: Component,
803
868
  args: [{
804
869
  selector: 'markstream-angular-pre-code-node',
805
870
  standalone: true,
806
- template: `<pre [class]="languageClass" [attr.aria-busy]="loading" [attr.aria-label]="ariaLabel" [attr.data-language]="language" tabindex="0"><code translate="no" [textContent]="code"></code></pre>`,
871
+ imports: [CommonModule],
872
+ template: `<pre
873
+ [ngClass]="preClasses"
874
+ [ngStyle]="lineNumberLayoutStyle"
875
+ [attr.aria-busy]="loading"
876
+ [attr.aria-label]="ariaLabel"
877
+ [attr.data-language]="language"
878
+ [attr.data-markstream-line-numbers]="showLineNumbers ? '1' : null"
879
+ data-markstream-pre="1"
880
+ tabindex="0"
881
+ ><ng-container *ngIf="showLineNumbers"><span class="markstream-pre__line-numbers" aria-hidden="true"><span class="markstream-pre__line-numbers-text">{{ lineNumbersText }}</span></span></ng-container><code translate="no" class="markstream-pre__code" [textContent]="displayCode"></code></pre>`,
807
882
  changeDetection: ChangeDetectionStrategy.OnPush,
808
883
  }]
809
884
  }], propDecorators: { node: [{
810
885
  type: Input,
811
886
  args: [{ required: true }]
887
+ }], showLineNumbers: [{
888
+ type: Input
812
889
  }] } });
813
890
 
814
891
  const isDevEnv = typeof globalThis !== 'undefined' && globalThis.ngDevMode !== false;
@@ -975,6 +1052,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImpo
975
1052
  type: Input
976
1053
  }] } });
977
1054
 
1055
+ const defaultCodeFontFamily = '"SF Mono", Monaco, Consolas, "Ubuntu Mono", "Liberation Mono", "Courier New", monospace';
1056
+ const defaultCodeFontSize = 12;
1057
+ const defaultCodeLineHeight = 18;
1058
+ function readPositiveCodeMetric(value) {
1059
+ return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined;
1060
+ }
1061
+ function parseCodeFenceInfo(raw) {
1062
+ const firstLine = String(raw ?? '').split(/\r?\n/, 1)[0]?.trim() ?? '';
1063
+ if (firstLine.length < 3)
1064
+ return '';
1065
+ const marker = firstLine[0];
1066
+ if ((marker !== '`' && marker !== '~') || firstLine[1] !== marker || firstLine[2] !== marker)
1067
+ return '';
1068
+ let index = 3;
1069
+ while (firstLine[index] === marker)
1070
+ index += 1;
1071
+ return firstLine.slice(index).trim();
1072
+ }
1073
+ function extractCodeBlockFileLabel(raw) {
1074
+ const info = parseCodeFenceInfo(getString$1(raw));
1075
+ if (!info)
1076
+ return '';
1077
+ const tokens = info.split(/\s+/).filter(Boolean);
1078
+ if (!tokens.length)
1079
+ return '';
1080
+ const candidates = tokens[0] === 'diff' ? tokens.slice(1) : tokens;
1081
+ for (const token of candidates) {
1082
+ const value = token.includes(':')
1083
+ ? token.slice(token.indexOf(':') + 1)
1084
+ : token;
1085
+ if (value && /[./\\-]/.test(value))
1086
+ return value;
1087
+ }
1088
+ return '';
1089
+ }
978
1090
  class CodeBlockNodeComponent {
979
1091
  constructor() {
980
1092
  this.cdr = inject(ChangeDetectorRef);
@@ -985,12 +1097,15 @@ class CodeBlockNodeComponent {
985
1097
  this.expanded = false;
986
1098
  this.inlinePreviewOpen = false;
987
1099
  this.editorReady = false;
988
- this.defaultFontSize = 14;
989
- this.fontSize = 14;
1100
+ this.defaultFontSize = defaultCodeFontSize;
1101
+ this.fontSize = defaultCodeFontSize;
990
1102
  this.helpers = null;
1103
+ this.runtimeMonacoOptions = null;
991
1104
  this.createPromise = null;
992
1105
  this.syncPromise = null;
993
1106
  this.editorKind = null;
1107
+ this.editorStreamMode = null;
1108
+ this.lifecycleId = 0;
994
1109
  this.viewReady = false;
995
1110
  this.destroyed = false;
996
1111
  this.copyTimer = null;
@@ -1122,10 +1237,19 @@ class CodeBlockNodeComponent {
1122
1237
  : this.t('artifacts.svgPreviewTitle');
1123
1238
  }
1124
1239
  get headerForeground() {
1125
- return `var(--vscode-editor-foreground, ${this.resolvedIsDark ? '#e5e7eb' : '#111827'})`;
1240
+ return 'var(--code-action-fg, var(--code-fg))';
1126
1241
  }
1127
1242
  get headerBackground() {
1128
- return `var(--vscode-editor-background, ${this.resolvedIsDark ? '#111827' : '#ffffff'})`;
1243
+ return 'var(--code-header-bg, var(--code-bg))';
1244
+ }
1245
+ get headerTitle() {
1246
+ return this.fileLabel || this.displayLanguage;
1247
+ }
1248
+ get headerCaption() {
1249
+ return this.fileLabel ? (this.isDiff ? `Diff / ${this.displayLanguage}` : this.displayLanguage) : '';
1250
+ }
1251
+ get fileLabel() {
1252
+ return extractCodeBlockFileLabel(this.node?.raw);
1129
1253
  }
1130
1254
  get ariaLabel() {
1131
1255
  return `Code block: ${this.displayLanguage}`;
@@ -1146,6 +1270,31 @@ class CodeBlockNodeComponent {
1146
1270
  style.maxWidth = max;
1147
1271
  return style;
1148
1272
  }
1273
+ get preFallbackStyle() {
1274
+ const options = this.resolvedMonacoOptions;
1275
+ const fontSize = readPositiveCodeMetric(this.fontSize) ?? defaultCodeFontSize;
1276
+ const lineHeight = readPositiveCodeMetric(options.lineHeight)
1277
+ ?? (fontSize === defaultCodeFontSize ? defaultCodeLineHeight : Math.max(12, Math.round(fontSize * 1.5)));
1278
+ const padding = options.padding && typeof options.padding === 'object'
1279
+ ? options.padding
1280
+ : null;
1281
+ const defaultPadding = this.isDiff ? 0 : 8;
1282
+ const paddingTop = readPositiveCodeMetric(padding?.top) ?? (padding?.top === 0 ? 0 : defaultPadding);
1283
+ const paddingBottom = readPositiveCodeMetric(padding?.bottom) ?? (padding?.bottom === 0 ? 0 : defaultPadding);
1284
+ const fontFamily = typeof options.fontFamily === 'string' && options.fontFamily.trim()
1285
+ ? options.fontFamily.trim()
1286
+ : defaultCodeFontFamily;
1287
+ return {
1288
+ '--markstream-code-font-family': fontFamily,
1289
+ '--markstream-code-padding-y': `${paddingTop}px`,
1290
+ '--markstream-code-padding-bottom': `${paddingBottom}px`,
1291
+ '--vscode-editor-font-size': `${fontSize}px`,
1292
+ '--vscode-editor-line-height': `${lineHeight}px`,
1293
+ 'font-family': fontFamily,
1294
+ 'font-size': `${fontSize}px`,
1295
+ 'line-height': `${lineHeight}px`,
1296
+ };
1297
+ }
1149
1298
  ngAfterViewInit() {
1150
1299
  this.viewReady = true;
1151
1300
  this.applyInitialFontSize();
@@ -1159,6 +1308,7 @@ class CodeBlockNodeComponent {
1159
1308
  }
1160
1309
  ngOnDestroy() {
1161
1310
  this.destroyed = true;
1311
+ this.lifecycleId += 1;
1162
1312
  if (this.copyTimer != null && typeof window !== 'undefined')
1163
1313
  window.clearTimeout(this.copyTimer);
1164
1314
  this.cancelDeferredHeightSync();
@@ -1233,12 +1383,15 @@ class CodeBlockNodeComponent {
1233
1383
  this.cdr.markForCheck();
1234
1384
  }
1235
1385
  applyInitialFontSize() {
1386
+ const previousDefault = this.defaultFontSize;
1236
1387
  const initial = Number(this.resolvedMonacoOptions.fontSize);
1237
- this.defaultFontSize = Number.isFinite(initial) && initial > 0 ? initial : 14;
1238
- if (!(typeof this.fontSize === 'number' && Number.isFinite(this.fontSize) && this.fontSize > 0))
1239
- this.fontSize = this.defaultFontSize;
1240
- if (this.fontSize < 10 || this.fontSize > 36)
1388
+ this.defaultFontSize = Number.isFinite(initial) && initial > 0 ? initial : defaultCodeFontSize;
1389
+ if (!(typeof this.fontSize === 'number' && Number.isFinite(this.fontSize) && this.fontSize > 0)
1390
+ || this.fontSize === previousDefault
1391
+ || this.fontSize < 10
1392
+ || this.fontSize > 36) {
1241
1393
  this.fontSize = this.defaultFontSize;
1394
+ }
1242
1395
  }
1243
1396
  async syncEditorState() {
1244
1397
  if (this.destroyed || !this.viewReady)
@@ -1263,16 +1416,20 @@ class CodeBlockNodeComponent {
1263
1416
  this.syncPromise = (async () => {
1264
1417
  try {
1265
1418
  const desiredKind = this.isDiff && typeof this.helpers?.createDiffEditor === 'function' ? 'diff' : 'single';
1266
- if (this.editorKind !== desiredKind) {
1267
- await this.recreateEditor(desiredKind);
1419
+ const desiredStreamMode = this.resolvedLoading !== false;
1420
+ if (this.editorKind !== desiredKind
1421
+ || this.editorStreamMode !== desiredStreamMode
1422
+ || !this.hasRenderedEditorDom(desiredKind)) {
1423
+ await this.recreateEditor(desiredKind, desiredStreamMode);
1268
1424
  }
1269
1425
  else {
1270
1426
  await this.updateEditor();
1271
1427
  }
1272
1428
  await Promise.resolve(this.helpers?.setTheme?.(this.resolvedIsDark ? this.resolvedDarkTheme : this.resolvedLightTheme));
1273
1429
  this.applyEditorFontSize();
1274
- if (this.expanded || !this.resolvedLoading || !this.editorReady)
1275
- this.applyEditorHeight();
1430
+ const creationId = this.lifecycleId;
1431
+ if (!await this.prepareEditorHandoff(desiredKind, creationId))
1432
+ return;
1276
1433
  this.editorReady = true;
1277
1434
  this.scheduleDeferredHeightSync();
1278
1435
  }
@@ -1299,19 +1456,32 @@ class CodeBlockNodeComponent {
1299
1456
  this.useFallback = true;
1300
1457
  return;
1301
1458
  }
1459
+ const configuredUnsafeCSS = typeof this.resolvedMonacoOptions.unsafeCSS === 'string'
1460
+ ? this.resolvedMonacoOptions.unsafeCSS
1461
+ : '';
1302
1462
  const options = {
1303
1463
  wordWrap: 'on',
1464
+ stream: this.resolvedLoading !== false,
1304
1465
  wrappingIndent: 'same',
1305
1466
  readOnly: true,
1306
1467
  minimap: { enabled: false },
1307
1468
  lineNumbers: 'on',
1308
1469
  revealDebounceMs: 75,
1309
1470
  MAX_HEIGHT: 500,
1471
+ fontFamily: defaultCodeFontFamily,
1310
1472
  fontSize: this.defaultFontSize,
1473
+ lineHeight: defaultCodeLineHeight,
1474
+ padding: this.isDiff ? { top: 0, bottom: 0 } : { top: 8, bottom: 8 },
1311
1475
  themes: this.resolvedThemes,
1312
1476
  theme: this.resolvedIsDark ? this.resolvedDarkTheme : this.resolvedLightTheme,
1313
1477
  ...(this.resolvedMonacoOptions || {}),
1478
+ // The Angular shell already owns the language/file header. Keep the
1479
+ // enhanced surface headerless so it matches the Vue 3 handoff contract.
1480
+ disableFileHeader: true,
1481
+ unsafeCSS: `[data-file], [data-diff] { --diffs-min-number-column-width-default: 4ch !important; }
1482
+ ${configuredUnsafeCSS}`.trim(),
1314
1483
  };
1484
+ this.runtimeMonacoOptions = options;
1315
1485
  this.helpers = monacoModule.useMonaco(options);
1316
1486
  })();
1317
1487
  try {
@@ -1321,18 +1491,47 @@ class CodeBlockNodeComponent {
1321
1491
  this.createPromise = null;
1322
1492
  }
1323
1493
  }
1324
- async recreateEditor(kind) {
1494
+ async recreateEditor(kind, streamMode) {
1325
1495
  const host = this.editorHost?.nativeElement;
1326
1496
  if (!host || !this.helpers)
1327
1497
  return;
1498
+ this.editorReady = false;
1499
+ this.lifecycleId += 1;
1328
1500
  this.cleanupEditor();
1329
1501
  host.innerHTML = '';
1330
1502
  this.editorKind = kind;
1503
+ this.editorStreamMode = streamMode;
1504
+ if (this.runtimeMonacoOptions)
1505
+ this.runtimeMonacoOptions.stream = streamMode;
1331
1506
  if (kind === 'diff') {
1332
1507
  await Promise.resolve(this.helpers.createDiffEditor?.(host, this.originalCode, this.resolvedCode, this.monacoLanguage));
1508
+ this.syncEditorGeometryVars();
1333
1509
  return;
1334
1510
  }
1335
1511
  await Promise.resolve(this.helpers.createEditor?.(host, this.resolvedCode, this.monacoLanguage));
1512
+ this.syncEditorGeometryVars();
1513
+ }
1514
+ // Align the enhanced surface with the pre-fallback geometry. stream-diffs /
1515
+ // pierre honor these CSS variables on the editor host (custom properties
1516
+ // inherit across the pierre shadow boundary):
1517
+ // - `--diffs-tab-size`: fallback defaults to 4, pierre defaults to 2.
1518
+ // - `--diffs-gap-block`: only set when padding is present; the default 8px
1519
+ // gap already matches the fallback.
1520
+ syncEditorGeometryVars() {
1521
+ const host = this.editorHost?.nativeElement;
1522
+ if (!host)
1523
+ return;
1524
+ const tabSize = readPositiveCodeMetric(this.resolvedMonacoOptions.tabSize) ?? 4;
1525
+ host.style.setProperty('--diffs-tab-size', String(tabSize));
1526
+ const rawPadding = this.resolvedMonacoOptions.padding;
1527
+ const hasConfiguredPadding = Boolean(rawPadding && typeof rawPadding === 'object');
1528
+ if (hasConfiguredPadding) {
1529
+ const top = readPositiveCodeMetric(rawPadding.top) ?? 0;
1530
+ host.style.setProperty('--diffs-gap-block', `${top}px`);
1531
+ }
1532
+ else {
1533
+ host.style.removeProperty('--diffs-gap-block');
1534
+ }
1336
1535
  }
1337
1536
  async updateEditor() {
1338
1537
  if (!this.helpers)
@@ -1343,6 +1542,66 @@ class CodeBlockNodeComponent {
1343
1542
  }
1344
1543
  await Promise.resolve(this.helpers.updateCode?.(this.resolvedCode, this.monacoLanguage));
1345
1544
  }
1545
+ hasRenderedEditorDom(kind) {
1546
+ const host = this.editorHost?.nativeElement;
1547
+ if (!host)
1548
+ return false;
1549
+ const monacoSelector = kind === 'diff' ? '.monaco-diff-editor' : '.monaco-editor';
1550
+ return !!host.querySelector([
1551
+ monacoSelector,
1552
+ 'diffs-container',
1553
+ '.stream-diffs-shell',
1554
+ '[data-stream-diffs-state]',
1555
+ ].join(','));
1556
+ }
1557
+ getVisualEditorSurface() {
1558
+ return this.editorHost?.nativeElement.querySelector([
1559
+ '.monaco-diff-editor',
1560
+ '.monaco-editor',
1561
+ 'diffs-container',
1562
+ '[data-stream-diffs-state]',
1563
+ '.stream-diffs-shell',
1564
+ ].join(',')) ?? null;
1565
+ }
1566
+ isEditorVisuallyReady(kind) {
1567
+ const host = this.editorHost?.nativeElement;
1568
+ if (!host || !this.hasRenderedEditorDom(kind) || typeof window === 'undefined')
1569
+ return false;
1570
+ const surface = this.getVisualEditorSurface();
1571
+ if (!surface)
1572
+ return false;
1573
+ const rect = surface.getBoundingClientRect();
1574
+ if (rect.width <= 0 || rect.height <= 0)
1575
+ return false;
1576
+ const style = window.getComputedStyle(surface);
1577
+ return style.display !== 'none'
1578
+ && Number.parseFloat(style.opacity || '1') > 0.01;
1579
+ }
1580
+ async prepareEditorHandoff(kind, creationId) {
1581
+ // Time-box the handoff: if visual readiness can't be confirmed (e.g. a
1582
+ // hidden/zero-size container), reveal the editor anyway once its DOM is
1583
+ // mounted so the block never strands in the pre-fallback forever.
1584
+ const deadline = Date.now() + 1500;
1585
+ let attempt = 0;
1586
+ while (Date.now() < deadline && attempt < 30) {
1587
+ attempt += 1;
1588
+ if (this.destroyed || creationId !== this.lifecycleId)
1589
+ return false;
1590
+ this.applyEditorHeight(true);
1591
+ await this.nextAnimationFrame();
1592
+ if (this.isEditorVisuallyReady(kind)) {
1593
+ this.applyEditorHeight(true);
1594
+ await this.nextAnimationFrame();
1595
+ return this.isEditorVisuallyReady(kind);
1596
+ }
1597
+ }
1598
+ return !this.destroyed && creationId === this.lifecycleId && this.hasRenderedEditorDom(kind);
1599
+ }
1600
+ nextAnimationFrame() {
1601
+ if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function')
1602
+ return Promise.resolve();
1603
+ return new Promise(resolve => window.requestAnimationFrame(() => resolve()));
1604
+ }
1346
1605
  applyEditorFontSize() {
1347
1606
  const view = this.editorKind === 'diff'
1348
1607
  ? this.helpers?.getDiffEditorView?.()
@@ -1354,7 +1613,7 @@ class CodeBlockNodeComponent {
1354
1613
  }
1355
1614
  catch { }
1356
1615
  }
1357
- applyEditorHeight() {
1616
+ applyEditorHeight(_preparing = false) {
1358
1617
  const host = this.editorHost?.nativeElement;
1359
1618
  if (!host)
1360
1619
  return;
@@ -1449,6 +1708,7 @@ class CodeBlockNodeComponent {
1449
1708
  });
1450
1709
  }
1451
1710
  cleanupEditor() {
1711
+ this.cancelDeferredHeightSync();
1452
1712
  try {
1453
1713
  this.helpers?.safeClean?.();
1454
1714
  }
@@ -1504,7 +1764,10 @@ class CodeBlockNodeComponent {
1504
1764
  <span class="icon-slot code-block-language-icon">
1505
1765
  <img class="code-block-language-icon__image" [src]="languageIconDataUrl" alt="" />
1506
1766
  </span>
1507
- <span class="code-block-header__label">{{ displayLanguage }}</span>
1767
+ <span class="code-header-copy">
1768
+ <span class="code-header-title">{{ headerTitle }}</span>
1769
+ <span *ngIf="headerCaption" class="code-header-caption">{{ headerCaption }}</span>
1770
+ </span>
1508
1771
  </div>
1509
1772
  <div class="code-block-header__actions">
1510
1773
  <button
@@ -1626,13 +1889,28 @@ class CodeBlockNodeComponent {
1626
1889
  [class.code-block-body--expanded]="expanded"
1627
1890
  >
1628
1891
  <ng-container *ngIf="!showLoadingPlaceholder; else loadingTpl">
1629
- <markstream-angular-pre-code-node *ngIf="useFallback; else editorTpl" [node]="node" />
1892
+ <markstream-angular-pre-code-node
1893
+ *ngIf="useFallback; else editorTpl"
1894
+ class="code-editor-fallback-surface"
1895
+ [node]="node"
1896
+ [ngStyle]="preFallbackStyle"
1897
+ [showLineNumbers]="true"
1898
+ />
1630
1899
 
1631
1900
  <ng-template #editorTpl>
1632
- <div #editorHost class="code-editor-container" [style.visibility]="editorReady ? 'visible' : 'hidden'"></div>
1633
- <div *ngIf="!editorReady" style="position:absolute; inset:0; overflow:auto; padding:1rem;">
1634
- <pre class="code-fallback-plain m-0" [attr.aria-busy]="resolvedLoading" [attr.aria-label]="ariaLabel" tabindex="0"><code translate="no" [style.fontSize.px]="fontSize" [textContent]="resolvedCode"></code></pre>
1635
- </div>
1901
+ <div
1902
+ #editorHost
1903
+ class="code-editor-container"
1904
+ [style.visibility]="editorReady ? 'visible' : 'hidden'"
1905
+ [attr.aria-hidden]="editorReady ? null : 'true'"
1906
+ ></div>
1907
+ <markstream-angular-pre-code-node
1908
+ *ngIf="!editorReady"
1909
+ class="code-editor-fallback-surface"
1910
+ [node]="node"
1911
+ [ngStyle]="preFallbackStyle"
1912
+ [showLineNumbers]="true"
1913
+ />
1636
1914
  </ng-template>
1637
1915
  </ng-container>
1638
1916
  </div>
@@ -1659,7 +1937,7 @@ class CodeBlockNodeComponent {
1659
1937
  </div>
1660
1938
  </div>
1661
1939
  </ng-template>
1662
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: PreCodeNodeComponent, selector: "markstream-angular-pre-code-node", inputs: ["node"] }, { kind: "component", type: HtmlPreviewFrameComponent, selector: "markstream-angular-html-preview-frame", inputs: ["code", "isDark", "htmlPreviewAllowScripts", "htmlPreviewSandbox", "title", "onClose"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1940
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: PreCodeNodeComponent, selector: "markstream-angular-pre-code-node", inputs: ["node", "showLineNumbers"] }, { kind: "component", type: HtmlPreviewFrameComponent, selector: "markstream-angular-html-preview-frame", inputs: ["code", "isDark", "htmlPreviewAllowScripts", "htmlPreviewSandbox", "title", "onClose"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1663
1941
  }
1664
1942
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImport: i0, type: CodeBlockNodeComponent, decorators: [{
1665
1943
  type: Component,
@@ -1687,7 +1965,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImpo
1687
1965
  <span class="icon-slot code-block-language-icon">
1688
1966
  <img class="code-block-language-icon__image" [src]="languageIconDataUrl" alt="" />
1689
1967
  </span>
1690
- <span class="code-block-header__label">{{ displayLanguage }}</span>
1968
+ <span class="code-header-copy">
1969
+ <span class="code-header-title">{{ headerTitle }}</span>
1970
+ <span *ngIf="headerCaption" class="code-header-caption">{{ headerCaption }}</span>
1971
+ </span>
1691
1972
  </div>
1692
1973
  <div class="code-block-header__actions">
1693
1974
  <button
@@ -1809,13 +2090,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImpo
1809
2090
  [class.code-block-body--expanded]="expanded"
1810
2091
  >
1811
2092
  <ng-container *ngIf="!showLoadingPlaceholder; else loadingTpl">
1812
- <markstream-angular-pre-code-node *ngIf="useFallback; else editorTpl" [node]="node" />
2093
+ <markstream-angular-pre-code-node
2094
+ *ngIf="useFallback; else editorTpl"
2095
+ class="code-editor-fallback-surface"
2096
+ [node]="node"
2097
+ [ngStyle]="preFallbackStyle"
2098
+ [showLineNumbers]="true"
2099
+ />
1813
2100
 
1814
2101
  <ng-template #editorTpl>
1815
- <div #editorHost class="code-editor-container" [style.visibility]="editorReady ? 'visible' : 'hidden'"></div>
1816
- <div *ngIf="!editorReady" style="position:absolute; inset:0; overflow:auto; padding:1rem;">
1817
- <pre class="code-fallback-plain m-0" [attr.aria-busy]="resolvedLoading" [attr.aria-label]="ariaLabel" tabindex="0"><code translate="no" [style.fontSize.px]="fontSize" [textContent]="resolvedCode"></code></pre>
1818
- </div>
2102
+ <div
2103
+ #editorHost
2104
+ class="code-editor-container"
2105
+ [style.visibility]="editorReady ? 'visible' : 'hidden'"
2106
+ [attr.aria-hidden]="editorReady ? null : 'true'"
2107
+ ></div>
2108
+ <markstream-angular-pre-code-node
2109
+ *ngIf="!editorReady"
2110
+ class="code-editor-fallback-surface"
2111
+ [node]="node"
2112
+ [ngStyle]="preFallbackStyle"
2113
+ [showLineNumbers]="true"
2114
+ />
1819
2115
  </ng-template>
1820
2116
  </ng-container>
1821
2117
  </div>
@@ -7942,6 +8238,7 @@ class NodeOutletComponent {
7942
8238
  <markstream-angular-pre-code-node
7943
8239
  *ngIf="codeMode === 'pre'; else enhancedCode"
7944
8240
  [node]="node"
8241
+ [showLineNumbers]="true"
7945
8242
  />
7946
8243
  </ng-template>
7947
8244
  <ng-template #enhancedCode>
@@ -7952,7 +8249,7 @@ class NodeOutletComponent {
7952
8249
  <markstream-angular-fallback-node *ngSwitchDefault [node]="fallbackNode" [context]="context" [indexKey]="indexKey" />
7953
8250
  </ng-container>
7954
8251
  </ng-template>
7955
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitch), selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitchCase), selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitchDefault), selector: "[ngSwitchDefault]" }, { kind: "component", type: i0.forwardRef(() => AdmonitionNodeComponent), selector: "markstream-angular-admonition-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => BlockquoteNodeComponent), selector: "markstream-angular-blockquote-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => CheckboxNodeComponent), selector: "markstream-angular-checkbox-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => CodeBlockNodeComponent), selector: "markstream-angular-code-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => D2BlockNodeComponent), selector: "markstream-angular-d2-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => DefinitionListNodeComponent), selector: "markstream-angular-definition-list-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => DynamicNodeHostComponent), selector: "markstream-angular-dynamic-node-host", inputs: ["component", "node", "context", "indexKey", "inputs"] }, { kind: "component", type: i0.forwardRef(() => EmojiNodeComponent), selector: "markstream-angular-emoji-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => EmphasisNodeComponent), selector: "markstream-angular-emphasis-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FallbackComponent), selector: "markstream-angular-fallback-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FootnoteAnchorNodeComponent), selector: "markstream-angular-footnote-anchor-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => FootnoteNodeComponent), selector: "markstream-angular-footnote-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FootnoteReferenceNodeComponent), selector: "markstream-angular-footnote-reference-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => HardBreakNodeComponent), selector: "markstream-angular-hardbreak-node" }, { kind: "component", type: i0.forwardRef(() => HeadingNodeComponent), selector: "markstream-angular-heading-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => HighlightNodeComponent), selector: "markstream-angular-highlight-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => HtmlBlockNodeComponent), selector: "markstream-angular-html-block-node", inputs: ["node", "context"] }, { kind: "component", type: i0.forwardRef(() => HtmlInlineNodeComponent), selector: "markstream-angular-html-inline-node", inputs: ["node", "context"] }, { kind: "component", type: i0.forwardRef(() => ImageNodeComponent), selector: "markstream-angular-image-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => InfographicBlockNodeComponent), selector: "markstream-angular-infographic-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => InlineCodeNodeComponent), selector: "markstream-angular-inline-code-node", inputs: ["node", "context", "indexKey", "typewriter", "fade"] }, { kind: "component", type: i0.forwardRef(() => InsertNodeComponent), selector: "markstream-angular-insert-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => LinkNodeComponent), selector: "markstream-angular-link-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => ListItemNodeComponent), selector: "markstream-angular-list-item-node", inputs: ["node", "context", "indexKey", "value"] }, { kind: "component", type: i0.forwardRef(() => ListNodeComponent), selector: "markstream-angular-list-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => MathBlockNodeComponent), selector: "markstream-angular-math-block-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => MathInlineNodeComponent), selector: "markstream-angular-math-inline-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => MermaidBlockNodeComponent), selector: "markstream-angular-mermaid-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => ParagraphNodeComponent), selector: "markstream-angular-paragraph-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => PreCodeNodeComponent), selector: "markstream-angular-pre-code-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => ReferenceNodeComponent), selector: "markstream-angular-reference-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => StrikethroughNodeComponent), selector: "markstream-angular-strikethrough-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => StrongNodeComponent), selector: "markstream-angular-strong-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => SubscriptNodeComponent), selector: "markstream-angular-subscript-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => SuperscriptNodeComponent), selector: "markstream-angular-superscript-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => TableNodeComponent), selector: "markstream-angular-table-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => TextNodeComponent), selector: "markstream-angular-text-node", inputs: ["node", "context", "indexKey", "typewriter", "fade"] }, { kind: "component", type: i0.forwardRef(() => ThematicBreakNodeComponent), selector: "markstream-angular-thematic-break-node" }, { kind: "component", type: i0.forwardRef(() => VmrContainerNodeComponent), selector: "markstream-angular-vmr-container-node", inputs: ["node", "context", "indexKey"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8252
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitch), selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitchCase), selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgSwitchDefault), selector: "[ngSwitchDefault]" }, { kind: "component", type: i0.forwardRef(() => AdmonitionNodeComponent), selector: "markstream-angular-admonition-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => BlockquoteNodeComponent), selector: "markstream-angular-blockquote-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => CheckboxNodeComponent), selector: "markstream-angular-checkbox-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => CodeBlockNodeComponent), selector: "markstream-angular-code-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => D2BlockNodeComponent), selector: "markstream-angular-d2-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => DefinitionListNodeComponent), selector: "markstream-angular-definition-list-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => DynamicNodeHostComponent), selector: "markstream-angular-dynamic-node-host", inputs: ["component", "node", "context", "indexKey", "inputs"] }, { kind: "component", type: i0.forwardRef(() => EmojiNodeComponent), selector: "markstream-angular-emoji-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => EmphasisNodeComponent), selector: "markstream-angular-emphasis-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FallbackComponent), selector: "markstream-angular-fallback-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FootnoteAnchorNodeComponent), selector: "markstream-angular-footnote-anchor-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => FootnoteNodeComponent), selector: "markstream-angular-footnote-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => FootnoteReferenceNodeComponent), selector: "markstream-angular-footnote-reference-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => HardBreakNodeComponent), selector: "markstream-angular-hardbreak-node" }, { kind: "component", type: i0.forwardRef(() => HeadingNodeComponent), selector: "markstream-angular-heading-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => HighlightNodeComponent), selector: "markstream-angular-highlight-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => HtmlBlockNodeComponent), selector: "markstream-angular-html-block-node", inputs: ["node", "context"] }, { kind: "component", type: i0.forwardRef(() => HtmlInlineNodeComponent), selector: "markstream-angular-html-inline-node", inputs: ["node", "context"] }, { kind: "component", type: i0.forwardRef(() => ImageNodeComponent), selector: "markstream-angular-image-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => InfographicBlockNodeComponent), selector: "markstream-angular-infographic-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => InlineCodeNodeComponent), selector: "markstream-angular-inline-code-node", inputs: ["node", "context", "indexKey", "typewriter", "fade"] }, { kind: "component", type: i0.forwardRef(() => InsertNodeComponent), selector: "markstream-angular-insert-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => LinkNodeComponent), selector: "markstream-angular-link-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => ListItemNodeComponent), selector: "markstream-angular-list-item-node", inputs: ["node", "context", "indexKey", "value"] }, { kind: "component", type: i0.forwardRef(() => ListNodeComponent), selector: "markstream-angular-list-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => MathBlockNodeComponent), selector: "markstream-angular-math-block-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => MathInlineNodeComponent), selector: "markstream-angular-math-inline-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => MermaidBlockNodeComponent), selector: "markstream-angular-mermaid-block-node", inputs: ["node", "context", "props"] }, { kind: "component", type: i0.forwardRef(() => ParagraphNodeComponent), selector: "markstream-angular-paragraph-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => PreCodeNodeComponent), selector: "markstream-angular-pre-code-node", inputs: ["node", "showLineNumbers"] }, { kind: "component", type: i0.forwardRef(() => ReferenceNodeComponent), selector: "markstream-angular-reference-node", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => StrikethroughNodeComponent), selector: "markstream-angular-strikethrough-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => StrongNodeComponent), selector: "markstream-angular-strong-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => SubscriptNodeComponent), selector: "markstream-angular-subscript-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => SuperscriptNodeComponent), selector: "markstream-angular-superscript-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => TableNodeComponent), selector: "markstream-angular-table-node", inputs: ["node", "context", "indexKey"] }, { kind: "component", type: i0.forwardRef(() => TextNodeComponent), selector: "markstream-angular-text-node", inputs: ["node", "context", "indexKey", "typewriter", "fade"] }, { kind: "component", type: i0.forwardRef(() => ThematicBreakNodeComponent), selector: "markstream-angular-thematic-break-node" }, { kind: "component", type: i0.forwardRef(() => VmrContainerNodeComponent), selector: "markstream-angular-vmr-container-node", inputs: ["node", "context", "indexKey"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7956
8253
  }
7957
8254
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImport: i0, type: NodeOutletComponent, decorators: [{
7958
8255
  type: Component,
@@ -8083,6 +8380,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.26", ngImpo
8083
8380
  <markstream-angular-pre-code-node
8084
8381
  *ngIf="codeMode === 'pre'; else enhancedCode"
8085
8382
  [node]="node"
8383
+ [showLineNumbers]="true"
8086
8384
  />
8087
8385
  </ng-template>
8088
8386
  <ng-template #enhancedCode>
@@ -8805,6 +9103,11 @@ async function renderMonaco(root, cleanupFns, options, isActive) {
8805
9103
  }
8806
9104
  const originalPre = pre.cloneNode(true);
8807
9105
  pre.replaceWith(shell.wrapper);
9106
+ const configuredUnsafeCSS = typeof options.monacoOptions?.unsafeCSS === 'string'
9107
+ ? options.monacoOptions.unsafeCSS
9108
+ : '';
9109
+ const runtimeUnsafeCSS = `[data-file], [data-diff] { --diffs-min-number-column-width-default: 4ch !important; }
9110
+ ${configuredUnsafeCSS}`.trim();
8808
9111
  const helpers = monacoModule.useMonaco({
8809
9112
  themes: ['vitesse-dark', 'vitesse-light'],
8810
9113
  languages: Array.from(new Set([monacoLanguage, 'plaintext'])),
@@ -8821,6 +9124,10 @@ async function renderMonaco(root, cleanupFns, options, isActive) {
8821
9124
  ? { padding: { top: paddingTop ?? 0, bottom: paddingBottom ?? 0 } }
8822
9125
  : {}),
8823
9126
  ...(options.monacoOptions || {}),
9127
+ // createEnhancedBlockShell already renders the code header. Prevent the
9128
+ // enhanced runtime from adding a second `code.<language>` file header.
9129
+ disableFileHeader: true,
9130
+ unsafeCSS: runtimeUnsafeCSS,
8824
9131
  });
8825
9132
  try {
8826
9133
  if (diff && typeof helpers.createDiffEditor === 'function') {