@matechat/ng 17.1.0-alpha.0 → 17.1.0-alpha.1

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
@@ -3,7 +3,7 @@
3
3
  <img alt="MateChat Logo" src="https://matechat.gitcode.com/logo.svg" width="180" style="max-width:100%;">
4
4
  </a>
5
5
  </p>
6
- <h1 align="center">MateChat/Angular</h1>
6
+ <h1 align="center">MateChat / Angular</h1>
7
7
  <p align="center">前端智能化场景解决方案UI库,轻松构建你的AI应用。已服务于华为内部多个应用智能化改造,并助力CodeArts、InsCode AI IDE等智能化助手搭建。</p>
8
8
 
9
9
  ![example](https://matechat.gitcode.com/example1.png)
@@ -25,7 +25,7 @@
25
25
  如果你还没有新建项目,可以使用 Angular CLI 首先初始化一个`angular`项目:
26
26
 
27
27
  ```bash
28
- $ npm install -g @angular/cli
28
+ $ npm install -g @angular/cli@latest
29
29
 
30
30
  $ ng new matechat-demo
31
31
 
@@ -34,7 +34,7 @@ $ npm i @matechat/ng
34
34
 
35
35
  ### 2. 引入
36
36
 
37
- 在`app.component.ts`文件中引入模块
37
+ 在`app.ts`文件中引入模块
38
38
 
39
39
  ```ts
40
40
  import { Component } from "@angular/core";
@@ -53,7 +53,7 @@ export class AppComponent {}
53
53
 
54
54
  ### 3. 使用
55
55
 
56
- 在`app.component.html`文件中使用 MateChat 组件,如:
56
+ 在`app.html`文件中使用 MateChat 组件,如:
57
57
 
58
58
  ```html
59
59
  <mc-bubble [content]="'Hello, MateChat'" [avatarConfig]="{ name: 'matechat' }"></mc-bubble>
@@ -62,34 +62,32 @@ export class AppComponent {}
62
62
  以下为一个简单的对话界面搭建示例:
63
63
 
64
64
  ```html
65
- <template>
66
- <div class="chat-container">
67
- <div class="chat-list">
68
- <ng-container *ngFor="let msg of messages">
69
- @if (msg.from === 'user') {
70
- <mc-bubble class="user-bubble" [align]="'right'" [content]="msg.content"></mc-bubble>
71
- } @else if (msg.from === 'model') {
72
- <mc-bubble class="model-bubble" [align]="'left'">
73
- <mc-markdown-card [content]="msg.content" [enableMermaid]="true"></mc-markdown-card>
74
- </mc-bubble>
75
- }
76
- </ng-container>
77
- </div>
78
- <div class="chat-footer">
79
- <mc-input (submit)="onSubmit($event)"></mc-input>
80
- </div>
65
+ <div class="chat-container">
66
+ <div class="chat-list">
67
+ <ng-container *ngFor="let msg of messages">
68
+ @if (msg.from === 'user') {
69
+ <mc-bubble class="user-bubble" [align]="'right'" [content]="msg.content"></mc-bubble>
70
+ } @else if (msg.from === 'model') {
71
+ <mc-bubble class="model-bubble" [align]="'left'">
72
+ <mc-markdown-card [content]="msg.content" [enableMermaid]="true"></mc-markdown-card>
73
+ </mc-bubble>
74
+ }
75
+ </ng-container>
81
76
  </div>
82
- </template>
77
+ <div class="chat-footer">
78
+ <mc-input (submit)="onSubmit($event)"></mc-input>
79
+ </div>
80
+ </div>
83
81
  ```
84
82
 
85
83
 
86
84
  ```ts
87
85
  import { Component } from '@angular/core';
88
86
  import { CommonModule } from '@angular/common';
89
- import { BubbleModule, InputComponent, MarkdownCardModule } from '@matechat/ng';
87
+ import { BubbleModule, InputModule, MarkdownCardModule } from '@matechat/ng';
90
88
  @Component({
91
89
  selector: 'app-root',
92
- imports: [CommonModule, BubbleModule, InputComponent, MarkdownCardModule],
90
+ imports: [CommonModule, BubbleModule, InputModule, MarkdownCardModule],
93
91
  templateUrl: './app.html',
94
92
  styleUrl: './app.css',
95
93
  })
@@ -5,7 +5,7 @@ import { CommonModule } from '@angular/common';
5
5
  import { Subject, debounceTime } from 'rxjs';
6
6
  import * as i3 from '@angular/forms';
7
7
  import { FormsModule } from '@angular/forms';
8
- import { DiffDOM } from 'diff-dom';
8
+ import morphdom from 'morphdom';
9
9
  import markdownit from 'markdown-it';
10
10
  import { getDefaultWhiteList, getDefaultCSSWhiteList, filterXSS } from 'xss';
11
11
  import hljs from 'highlight.js';
@@ -923,7 +923,7 @@ class InputComponent extends BaseComponent {
923
923
  ngOnInit() {
924
924
  this.foundation = new InputFoundation(this.adapter);
925
925
  this.foundation.init();
926
- this.inputValue = this.value;
926
+ this.inputValue = this.value || '';
927
927
  }
928
928
  get adapter() {
929
929
  return {
@@ -1639,7 +1639,6 @@ class CodeBlockComponent extends BaseComponent {
1639
1639
  .pipe(debounceTime(300))
1640
1640
  .subscribe(() => this.copyCodeInternal());
1641
1641
  this.foundation = new CodeBlockFoundation(this.adapter);
1642
- this.diffDom = new DiffDOM();
1643
1642
  }
1644
1643
  get adapter() {
1645
1644
  return {
@@ -1653,8 +1652,7 @@ class CodeBlockComponent extends BaseComponent {
1653
1652
  const newElement = document.createElement('code');
1654
1653
  newElement.className = `hljs language-${language}`;
1655
1654
  newElement.innerHTML = highlightedCode;
1656
- const diff = this.diffDom.diff(this.codeElementRef.nativeElement, newElement);
1657
- this.diffDom.apply(this.codeElementRef.nativeElement, diff);
1655
+ morphdom(this.codeElementRef.nativeElement, newElement);
1658
1656
  }
1659
1657
  },
1660
1658
  };
@@ -1678,6 +1676,7 @@ class CodeBlockComponent extends BaseComponent {
1678
1676
  }
1679
1677
  }
1680
1678
  ngAfterViewInit() {
1679
+ this.updateHighlightedCode();
1681
1680
  if (this.isMermaid) {
1682
1681
  this.renderMermaid();
1683
1682
  }
@@ -1703,7 +1702,9 @@ class CodeBlockComponent extends BaseComponent {
1703
1702
  this.isMermaid = this.foundation.checkIsMermaid();
1704
1703
  }
1705
1704
  updateHighlightedCode() {
1706
- this.foundation.updateHighlightedCode();
1705
+ setTimeout(() => {
1706
+ this.foundation.updateHighlightedCode();
1707
+ });
1707
1708
  }
1708
1709
  zoomIn() {
1709
1710
  this.foundation.zoomIn();
@@ -1728,6 +1729,7 @@ class CodeBlockComponent extends BaseComponent {
1728
1729
  }
1729
1730
  copyCodeInternal() {
1730
1731
  this.foundation.copyCodeInternal();
1732
+ this.cdr.detectChanges();
1731
1733
  }
1732
1734
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: CodeBlockComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1733
1735
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: CodeBlockComponent, isStandalone: false, selector: "mc-code-block", inputs: { code: "code", language: "language", blockIndex: "blockIndex", theme: "theme", enableMermaid: "enableMermaid", mermaidConfig: "mermaidConfig", contentTemplate: "contentTemplate", headerTemplate: "headerTemplate", actionsTemplate: "actionsTemplate" }, viewQueries: [{ propertyName: "rootRef", first: true, predicate: ["rootRef"], descendants: true }, { propertyName: "mermaidContentRef", first: true, predicate: ["mermaidContent"], descendants: true }, { propertyName: "codeElementRef", first: true, predicate: ["codeElement"], descendants: true }, { propertyName: "codeElementTemplates", predicate: ["codeElementTemplate"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"mc-code-block\"\n [ngClass]=\"theme === 'dark' ? 'mc-code-block-dark' : 'mc-code-block-light'\"\n #rootRef\n>\n <div class=\"mc-code-block-header\" *ngIf=\"!headerTemplate\">\n <span class=\"mc-code-lang\">{{ language }}</span>\n <ng-container *ngIf=\"!actionsTemplate\">\n <div class=\"mc-code-block-actions\">\n <div *ngIf=\"isMermaid\" style=\"margin-right: 8px\">\n <ul\n class=\"mc-diagram-switch\"\n [ngClass]=\"{ 'mc-show-code': !showMermaidDiagram }\"\n >\n <li\n (click)=\"switchShowMermaid(true)\"\n [ngClass]=\"{ 'mc-diagram-switch-active': showMermaidDiagram }\"\n >\n \u56FE\u8868\n </li>\n <li\n (click)=\"switchShowMermaid(false)\"\n [ngClass]=\"{ 'mc-diagram-switch-active': !showMermaidDiagram }\"\n >\n \u4EE3\u7801\n </li>\n </ul>\n </div>\n <div\n *ngIf=\"isMermaid && showMermaidDiagram\"\n class=\"mc-action-btn mc-toggle-btn\"\n [title]=\"'Md.zoomIn' | translate\"\n (click)=\"zoomIn()\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g\n id=\"enlarge\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <path\n d=\"M7.16666667,1 C10.572409,1 13.3333333,3.76092429 13.3333333,7.16666667 C13.3333333,8.68984984 12.781084,10.0840543 11.8658888,11.1599767 L14.4225201,13.7154466 C14.6177822,13.9107088 14.6177822,14.2272912 14.4225201,14.4225534 C14.2489537,14.5961197 13.9795293,14.6154049 13.7846612,14.4804088 L13.7154133,14.4225534 L11.158968,11.8667467 C10.083183,12.7814291 8.68937384,13.3333333 7.16666667,13.3333333 C3.76092429,13.3333333 1,10.572409 1,7.16666667 C1,3.76092429 3.76092429,1 7.16666667,1 Z M7.16666667,2 C4.31320904,2 2,4.31320904 2,7.16666667 C2,10.0201243 4.31320904,12.3333333 7.16666667,12.3333333 C10.0201243,12.3333333 12.3333333,10.0201243 12.3333333,7.16666667 C12.3333333,4.31320904 10.0201243,2 7.16666667,2 Z M7.16666667,4.66666667 C7.41212656,4.66666667 7.61627504,4.84354183 7.658611,5.07679103 L7.66666667,5.16666667 L7.666,6.668 L9.16601582,6.66666666 C9.44215796,6.66630764 9.66630679,6.88987368 9.66666668,7.16601582 C9.66698576,7.4114755 9.49037648,7.61585405 9.25718258,7.65849359 L9.16731751,7.66666666 L7.666,7.668 L7.66666667,9.16666667 C7.66666667,9.44280904 7.44280904,9.66666667 7.16666667,9.66666667 C6.92120678,9.66666667 6.7170583,9.48979151 6.67472234,9.2565423 L6.66666667,9.16666667 L6.666,7.669 L5.17251751,7.67186668 C4.89637537,7.6722257 4.67222654,7.44865965 4.67186666,7.17251751 C4.67154758,6.92705783 4.84815685,6.72267929 5.08135075,6.68003974 L5.17121582,6.67186709 L6.666,6.669 L6.66666667,5.16666667 C6.66666667,4.89052429 6.89052429,4.66666667 7.16666667,4.66666667 Z\"\n id=\"\u5F62\u72B6\u7ED3\u5408\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n </div>\n <div\n *ngIf=\"isMermaid && showMermaidDiagram\"\n class=\"mc-action-btn mc-toggle-btn\"\n title=\"\u7F29\u5C0F\"\n (click)=\"zoomOut()\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g\n id=\"zoom-out\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <path\n d=\"M7.16666667,1 C10.572409,1 13.3333333,3.76092429 13.3333333,7.16666667 C13.3333333,8.68984984 12.781084,10.0840543 11.8658888,11.1599767 L14.4225201,13.7154466 C14.6177822,13.9107088 14.6177822,14.2272912 14.4225201,14.4225534 C14.2489537,14.5961197 13.9795293,14.6154049 13.7846612,14.4804088 L13.7154133,14.4225534 L11.158968,11.8667467 C10.083183,12.7814291 8.68937384,13.3333333 7.16666667,13.3333333 C3.76092429,13.3333333 1,10.572409 1,7.16666667 C1,3.76092429 3.76092429,1 7.16666667,1 Z M7.16666667,2 C4.31320904,2 2,4.31320904 2,7.16666667 C2,10.0201243 4.31320904,12.3333333 7.16666667,12.3333333 C10.0201243,12.3333333 12.3333333,10.0201243 12.3333333,7.16666667 C12.3333333,4.31320904 10.0201243,2 7.16666667,2 Z M9.16601582,6.66666666 C9.44215796,6.66630764 9.66630679,6.88987368 9.66666668,7.16601582 C9.66698576,7.4114755 9.49037648,7.61585405 9.25718258,7.65849359 L9.16731751,7.66666666 L5.17251751,7.67186668 C4.89637537,7.6722257 4.67222654,7.44865965 4.67186666,7.17251751 C4.67154758,6.92705783 4.84815685,6.72267929 5.08135075,6.68003974 L5.17121582,6.67186709 L9.16601582,6.66666666 Z\"\n id=\"\u5F62\u72B6\u7ED3\u5408\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n </div>\n <div\n *ngIf=\"isMermaid && showMermaidDiagram\"\n class=\"mc-action-btn mc-toggle-btn\"\n title=\"\u4E0B\u8F7D\"\n (click)=\"download()\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g\n id=\"\u9875\u9762-1\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <g id=\"i\u4E0B\u8F7D\">\n <path\n d=\"M14.5,14 C14.7761424,14 15,14.2238576 15,14.5 C15,14.7761424 14.7761424,15 14.5,15 L1.5,15 C1.22385763,15 1,14.7761424 1,14.5 C1,14.2238576 1.22385763,14 1.5,14 L14.5,14 Z M8,1 C8.24545989,1 8.44960837,1.17687516 8.49194433,1.41012437 L8.5,1.5 L8.5,10.793 L11.6464466,7.64644661 C11.820013,7.47288026 12.0894374,7.45359511 12.2843055,7.58859116 L12.3535534,7.64644661 C12.5271197,7.82001296 12.5464049,8.08943736 12.4114088,8.2843055 L12.3535534,8.35355339 L8.35355339,12.3535534 L8.34128643,12.3654113 C8.32881868,12.3770608 8.31575424,12.3880797 8.30214392,12.3984173 L8.35355339,12.3535534 C8.32671912,12.3803877 8.29759357,12.4035342 8.26680652,12.422993 C8.25568247,12.4299807 8.24404667,12.4367067 8.23212724,12.4429657 C8.21827569,12.4502504 8.20453886,12.4566485 8.1905951,12.4623894 C8.17802507,12.4675915 8.16473685,12.4724419 8.15119917,12.4767316 C8.13583471,12.481552 8.12047425,12.4856039 8.10498705,12.4889143 C8.09430622,12.4912471 8.08325248,12.4932298 8.07207924,12.494843 C8.05487076,12.4972949 8.03773477,12.498877 8.02056948,12.4995793 C8.01375728,12.4998604 8.00689494,12.5 8,12.5 L7.98043349,12.4996194 C7.96293275,12.4989382 7.94546098,12.4973429 7.92809589,12.4948333 L8,12.5 C7.96390296,12.5 7.92869933,12.4961748 7.89477235,12.4889078 C7.87952575,12.4856039 7.86416529,12.481552 7.84898836,12.4767587 C7.83526315,12.4724419 7.82197493,12.4675915 7.80896344,12.4622078 C7.79546114,12.4566485 7.78172431,12.4502504 7.76824181,12.443195 C7.75595333,12.4367067 7.74431753,12.4299807 7.73298968,12.422812 C7.72729809,12.4192668 7.72146362,12.4154054 7.7156945,12.4114088 L7.69785608,12.3984173 C7.68424576,12.3880797 7.67118132,12.3770608 7.65871357,12.3654113 L7.64644661,12.3535534 L3.64644661,8.35355339 C3.45118446,8.15829124 3.45118446,7.84170876 3.64644661,7.64644661 C3.82001296,7.47288026 4.08943736,7.45359511 4.2843055,7.58859116 L4.35355339,7.64644661 L7.5,10.793 L7.5,1.5 C7.5,1.22385763 7.72385763,1 8,1 Z\"\n id=\"\u5F62\u72B6\u7ED3\u5408\"\n fill=\"#71757F\"\n ></path>\n </g>\n </g>\n </svg>\n </div>\n <div\n class=\"mc-action-btn mc-toggle-btn\"\n title=\"\u5C55\u5F00/\u6298\u53E0\"\n (click)=\"toggleExpand()\"\n >\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g\n id=\"\u5168\u90E8\u6536\u8D77\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <path\n d=\"M4.715694,14.4114091 C4.910563,14.5464051 5.179987,14.5271201 5.353553,14.3535531 L5.353553,14.3535531 L7.99999988,11.7070001 L10.646447,14.3535531 L10.715694,14.4114091 C10.910563,14.5464051 11.179987,14.5271201 11.353553,14.3535531 C11.548816,14.1582911 11.548816,13.8417091 11.353553,13.6464471 L11.353553,13.6464471 L8.353553,10.6464471 L8.284306,10.5885911 C8.089437,10.4535951 7.820013,10.4728801 7.646447,10.6464471 L7.646447,10.6464471 L4.646447,13.6464471 L4.588591,13.7156941 C4.453595,13.9105631 4.47288,14.1799871 4.646447,14.3535531 L4.646447,14.3535531 L4.715694,14.4114091 Z M14.5,7.50000012 C14.776142,7.50000012 15,7.72385812 15,8.00000012 C15,8.27614212 14.776142,8.50000012 14.5,8.50000012 L1.5,8.50000012 C1.223858,8.50000012 1,8.27614212 1,8.00000012 C1,7.72385812 1.223858,7.50000012 1.5,7.50000012 L14.5,7.50000012 Z M8.284306,5.41140912 L8.353553,5.35355312 L11.353553,2.35355312 C11.548816,2.15829112 11.548816,1.84170912 11.353553,1.64644712 C11.179987,1.47288012 10.910563,1.45359512 10.715694,1.58859112 L10.646447,1.64644712 L7.99999988,4.29300012 L5.353553,1.64644712 C5.179987,1.47288012 4.910563,1.45359512 4.715694,1.58859112 L4.646447,1.64644712 C4.47288,1.82001312 4.453595,2.08943712 4.588591,2.28430612 L4.646447,2.35355312 L7.646447,5.35355312 C7.820013,5.52712012 8.089437,5.54640512 8.284306,5.41140912 Z\"\n id=\"\u5F62\u72B6\u7ED3\u5408\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n </div>\n <div\n class=\"mc-action-btn mc-copy-btn\"\n title=\"\u590D\u5236\"\n (click)=\"copyCode()\"\n >\n @if(copied) {\n <span>\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <defs>\n <polygon\n id=\"path-1\"\n points=\"6.53553391 9.77817459 12.1923882 4.12132034 13.6066017 5.53553391 6.53553391 12.6066017 3 9.07106781 4.41421356 7.65685425 6.53553391 9.77817459\"\n ></polygon>\n </defs>\n <g\n id=\"status/whiteBG/correct\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <mask id=\"mask-2\" fill=\"white\">\n <use xlink:href=\"#path-1\"></use>\n </mask>\n <use id=\"Mask\" fill=\"#3DCCA6\" xlink:href=\"#path-1\"></use>\n </g>\n </svg>\n </span>\n } @else {\n <span>\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g\n id=\"\u9875\u9762-1\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <g\n id=\"API-starter-\u56FE\u6807\u5165\u5E93\"\n transform=\"translate(-592.000000, -204.000000)\"\n >\n <g\n id=\"\u65B9\u683C\u5907\u4EFD-16\"\n transform=\"translate(560.000000, 180.000000)\"\n >\n <text\n id=\"\u56FE\u6807\"\n font-family=\"PingFangSC-Regular, PingFang SC\"\n font-size=\"12\"\n font-weight=\"normal\"\n line-spacing=\"16\"\n fill=\"#71757F\"\n >\n <tspan x=\"27.136\" y=\"61\">\u590D\u5236</tspan>\n </text>\n </g>\n <path\n d=\"M604.5,206 C605.279696,206 605.920449,206.594888 605.993133,207.35554 L606,207.5 L606,214.5 C606,215.279696 605.405112,215.920449 604.64446,215.993133 L604.5,216 L604,216 L604,216.5 C604,217.279696 603.405112,217.920449 602.64446,217.993133 L602.5,218 L595.5,218 C594.671573,218 594,217.328427 594,216.5 L594,216.5 L594,209.5 C594,208.671573 594.671573,208 595.5,208 L595.5,208 L596,208 L596,207.5 C596,206.720304 596.594888,206.079551 597.35554,206.006867 L597.5,206 L604.5,206 Z M602.5,209 L595.5,209 C595.223858,209 595,209.223858 595,209.5 L595,209.5 L595,216.5 C595,216.776142 595.223858,217 595.5,217 L595.5,217 L602.5,217 C602.776142,217 603,216.776142 603,216.5 L603,216.5 L603,209.5 C603,209.223858 602.776142,209 602.5,209 L602.5,209 Z M604.5,207 L597.5,207 C597.25454,207 597.050392,207.176875 597.008056,207.410124 L597,207.5 L597,208 L602.5,208 C603.279696,208 603.920449,208.594888 603.993133,209.35554 L604,209.5 L604,215 L604.5,215 C604.74546,215 604.949608,214.823125 604.991944,214.589876 L605,214.5 L605,207.5 C605,207.25454 604.823125,207.050392 604.589876,207.008056 L604.5,207 Z\"\n id=\"\u5F62\u72B6\u7ED3\u5408\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </g>\n </svg>\n </span>\n }\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"actionsTemplate\">\n <ng-template [ngTemplateOutlet]=\"actionsTemplate\" [ngTemplateOutletContext]=\"{ $implicit: {code, language}, codeBlockData: {code, language} }\"></ng-template>\n </ng-container>\n </div>\n <ng-container *ngIf=\"headerTemplate\">\n <ng-template [ngTemplateOutlet]=\"headerTemplate\" [ngTemplateOutletContext]=\"{ $implicit: {code, language}, codeBlockData: {code, language} }\"></ng-template>\n </ng-container>\n\n <div [ngClass]=\"{ 'mc-block-hidden': !expanded }\" >\n @if (showMermaidDiagram && isMermaid && !contentTemplate) {\n <div class=\"mc-mermaid-content\" #mermaidContent></div>\n } @else if(!contentTemplate) {\n <pre #codeElementTemplate><code #codeElement [ngClass]=\"'hljs language-' + language\" ></code></pre>\n } @else {\n <ng-container *ngIf=\"contentTemplate\">\n <ng-template [ngTemplateOutlet]=\"contentTemplate\" [ngTemplateOutletContext]=\"{ $implicit: {code, language}, codeBlockData: {code, language} }\"></ng-template>\n </ng-container>\n }\n </div>\n</div>\n", styles: [".mc-markdown-render ::ng-deep .h1,.mc-markdown-render ::ng-deep .h2,.mc-markdown-render ::ng-deep .h3,.mc-markdown-render ::ng-deep .h4,.mc-markdown-render ::ng-deep .h5,.mc-markdown-render ::ng-deep .h6,.mc-markdown-render ::ng-deep h1,.mc-markdown-render ::ng-deep h2,.mc-markdown-render ::ng-deep h3,.mc-markdown-render ::ng-deep h4,.mc-markdown-render ::ng-deep h5,.mc-markdown-render ::ng-deep h6{line-height:1.1;margin:16px 0 12px}.mc-markdown-render ::ng-deep .h1:first-child,.mc-markdown-render ::ng-deep .h2:first-child,.mc-markdown-render ::ng-deep .h3:first-child,.mc-markdown-render ::ng-deep .h4:first-child,.mc-markdown-render ::ng-deep .h5:first-child,.mc-markdown-render ::ng-deep .h6:first-child,.mc-markdown-render ::ng-deep h1:first-child,.mc-markdown-render ::ng-deep h2:first-child,.mc-markdown-render ::ng-deep h3:first-child,.mc-markdown-render ::ng-deep h4:first-child,.mc-markdown-render ::ng-deep h5:first-child,.mc-markdown-render ::ng-deep h6:first-child{margin-top:0}.mc-markdown-render ::ng-deep h1{font-size:32px;line-height:40px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep h3{line-height:28px;font-size:20px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep caption{border:1px dashed var(--devui-line, #d7d8da);border-bottom:0;padding:3px;text-align:center}.mc-markdown-render ::ng-deep p{overflow-wrap:break-word;margin:0;padding:0;line-height:24px}.mc-markdown-render ::ng-deep p:last-child{margin:0}.mc-markdown-render ::ng-deep ul,.mc-markdown-render ::ng-deep ol{margin:0;padding:0;padding-inline-start:1.75em}.mc-markdown-render ::ng-deep ul>li,.mc-markdown-render ::ng-deep ol>li{line-height:21px}.mc-markdown-render ::ng-deep ul{list-style-type:disc}.mc-markdown-render ::ng-deep ul li::marker{font-size:20px}.mc-markdown-render ::ng-deep ol{list-style-type:decimal}.mc-markdown-render ::ng-deep table{margin-bottom:10px;border-collapse:collapse;display:table}.mc-markdown-render ::ng-deep td,.mc-markdown-render ::ng-deep th{padding:5px 10px;border:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-base-bg, #ffffff)}.mc-markdown-render ::ng-deep th{border-top:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-global-bg, #f6f6f8)}.mc-markdown-render ::ng-deep td p{margin:0;padding:0}.mc-markdown-render ::ng-deep blockquote{padding:0 8px;margin:0;color:var(--devui-text-weak, #575d6c);border-left:5px solid var(--devui-dividing-line, #f2f2f3)}.mc-markdown-render ::ng-deep a{color:var(--devui-link, #526ecc);text-decoration:none;cursor:pointer}.mc-markdown-render ::ng-deep a:hover{color:var(--devui-link-active, #526ecc)}.mc-markdown-render ::ng-deep img{max-width:100%}.mc-markdown-render{font-size:var(--devui-font-size, 14px);overflow-x:auto}.mc-markdown-render.mc-markdown-render-dark{color:#ced1db}.mc-markdown-render.mc-markdown-render-light{color:#252b3a}::ng-deep .mc-think-block{color:var(--devui-aide-text, #71757f);border-left:1px solid var(--devui-line, #d7d8da);padding-left:8px;margin-bottom:1rem}::ng-deep .mc-typewriter-color{background-image:-webkit-linear-gradient(left,#191919,#5588f0,#e171ee,#f2c55c);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-gradient{background:linear-gradient(to right,var(--devui-text, #252b3a),var(--devui-base-bg, #ffffff));background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-cursor{font-weight:900;animation:typewriter .8s linear 0s infinite}@keyframes typewriter{0%{opacity:1}50%{opacity:0}to{opacity:1}}.mc-code-block-light ::ng-deep pre code.hljs{display:block;overflow-x:auto;padding:1em}.mc-code-block-light ::ng-deep code.hljs{padding:3px 5px}.mc-code-block-light ::ng-deep .hljs{background:#fefefe;color:#545454}.mc-code-block-light ::ng-deep .hljs-comment,.mc-code-block-light ::ng-deep .hljs-quote{color:#696969}.mc-code-block-light ::ng-deep .hljs-variable,.mc-code-block-light ::ng-deep .hljs-template-variable,.mc-code-block-light ::ng-deep .hljs-tag,.mc-code-block-light ::ng-deep .hljs-name,.mc-code-block-light ::ng-deep .hljs-selector-id,.mc-code-block-light ::ng-deep .hljs-selector-class,.mc-code-block-light ::ng-deep .hljs-regexp,.mc-code-block-light ::ng-deep .hljs-deletion{color:#d91e18}.mc-code-block-light ::ng-deep .hljs-number,.mc-code-block-light ::ng-deep .hljs-built_in,.mc-code-block-light ::ng-deep .hljs-literal,.mc-code-block-light ::ng-deep .hljs-type,.mc-code-block-light ::ng-deep .hljs-params,.mc-code-block-light ::ng-deep .hljs-meta,.mc-code-block-light ::ng-deep .hljs-link{color:#aa5d00}.mc-code-block-light ::ng-deep .hljs-attribute{color:#aa5d00}.mc-code-block-light ::ng-deep .hljs-string,.mc-code-block-light ::ng-deep .hljs-symbol,.mc-code-block-light ::ng-deep .hljs-bullet,.mc-code-block-light ::ng-deep .hljs-addition{color:green}.mc-code-block-light ::ng-deep .hljs-title,.mc-code-block-light ::ng-deep .hljs-section{color:#007faa}.mc-code-block-light ::ng-deep .hljs-keyword,.mc-code-block-light ::ng-deep .hljs-selector-tag{color:#7928a1}.mc-code-block-light ::ng-deep .hljs-emphasis{font-style:italic}.mc-code-block-light ::ng-deep .hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.mc-code-block-light ::ng-deep .hljs-addition,.mc-code-block-light ::ng-deep .hljs-attribute,.mc-code-block-light ::ng-deep .hljs-built_in,.mc-code-block-light ::ng-deep .hljs-bullet,.mc-code-block-light ::ng-deep .hljs-comment,.mc-code-block-light ::ng-deep .hljs-link,.mc-code-block-light ::ng-deep .hljs-literal,.mc-code-block-light ::ng-deep .hljs-meta,.mc-code-block-light ::ng-deep .hljs-number,.mc-code-block-light ::ng-deep .hljs-params,.mc-code-block-light ::ng-deep .hljs-string,.mc-code-block-light ::ng-deep .hljs-symbol,.mc-code-block-light ::ng-deep .hljs-type,.mc-code-block-light ::ng-deep .hljs-quote{color:highlight}.mc-code-block-light ::ng-deep .hljs-keyword,.mc-code-block-light ::ng-deep .hljs-selector-tag{font-weight:700}}.mc-code-block-light{border:1px solid #d7d8da}.mc-code-block-light code.hljs{padding:1em}.mc-code-block-light{background-color:#f5f5f5}.mc-code-block-light .mc-code-lang,.mc-code-block-light .mc-code-block-actions .mc-copy-btn,.mc-code-block-light .mc-code-block-actions .mc-toggle-btn{color:#252b3a}.mc-code-block-light .mc-code-block-actions .mc-copy-btn:hover,.mc-code-block-light .mc-code-block-actions .mc-toggle-btn:hover{background-color:#ebebeb}.mc-code-block-light .mc-mermaid-content{background:#fefefe}.mc-code-block-dark ::ng-deep pre code.hljs{display:block;overflow-x:auto;padding:1em}.mc-code-block-dark ::ng-deep code.hljs{padding:3px 5px}.mc-code-block-dark ::ng-deep .hljs{background:#2b2b2b;color:#f8f8f2}.mc-code-block-dark ::ng-deep .hljs-comment,.mc-code-block-dark ::ng-deep .hljs-quote{color:#d4d0ab}.mc-code-block-dark ::ng-deep .hljs-variable,.mc-code-block-dark ::ng-deep .hljs-template-variable,.mc-code-block-dark ::ng-deep .hljs-tag,.mc-code-block-dark ::ng-deep .hljs-name,.mc-code-block-dark ::ng-deep .hljs-selector-id,.mc-code-block-dark ::ng-deep .hljs-selector-class,.mc-code-block-dark ::ng-deep .hljs-regexp,.mc-code-block-dark ::ng-deep .hljs-deletion{color:#ffa07a}.mc-code-block-dark ::ng-deep .hljs-number,.mc-code-block-dark ::ng-deep .hljs-built_in,.mc-code-block-dark ::ng-deep .hljs-literal,.mc-code-block-dark ::ng-deep .hljs-type,.mc-code-block-dark ::ng-deep .hljs-params,.mc-code-block-dark ::ng-deep .hljs-meta,.mc-code-block-dark ::ng-deep .hljs-link{color:#f5ab35}.mc-code-block-dark ::ng-deep .hljs-attribute{color:gold}.mc-code-block-dark ::ng-deep .hljs-string,.mc-code-block-dark ::ng-deep .hljs-symbol,.mc-code-block-dark ::ng-deep .hljs-bullet,.mc-code-block-dark ::ng-deep .hljs-addition{color:#abe338}.mc-code-block-dark ::ng-deep .hljs-title,.mc-code-block-dark ::ng-deep .hljs-section{color:#00e0e0}.mc-code-block-dark ::ng-deep .hljs-keyword,.mc-code-block-dark ::ng-deep .hljs-selector-tag{color:#dcc6e0}.mc-code-block-dark ::ng-deep .hljs-emphasis{font-style:italic}.mc-code-block-dark ::ng-deep .hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.mc-code-block-dark ::ng-deep .hljs-addition,.mc-code-block-dark ::ng-deep .hljs-attribute,.mc-code-block-dark ::ng-deep .hljs-built_in,.mc-code-block-dark ::ng-deep .hljs-bullet,.mc-code-block-dark ::ng-deep .hljs-comment,.mc-code-block-dark ::ng-deep .hljs-link,.mc-code-block-dark ::ng-deep .hljs-literal,.mc-code-block-dark ::ng-deep .hljs-meta,.mc-code-block-dark ::ng-deep .hljs-number,.mc-code-block-dark ::ng-deep .hljs-params,.mc-code-block-dark ::ng-deep .hljs-string,.mc-code-block-dark ::ng-deep .hljs-symbol,.mc-code-block-dark ::ng-deep .hljs-type,.mc-code-block-dark ::ng-deep .hljs-quote{color:highlight}.mc-code-block-dark ::ng-deep .hljs-keyword,.mc-code-block-dark ::ng-deep .hljs-selector-tag{font-weight:700}}.mc-code-block-dark{border:1px solid #4e5057}.mc-code-block-dark code.hljs{padding:1em}.mc-code-block-dark{background-color:#34363a}.mc-code-block-dark .mc-code-lang,.mc-code-block-dark .mc-code-block-actions .mc-copy-btn,.mc-code-block-dark .mc-code-block-actions .mc-toggle-btn{color:#ced1db}.mc-code-block-dark .mc-code-block-actions .mc-copy-btn:hover,.mc-code-block-dark .mc-code-block-actions .mc-toggle-btn:hover{background-color:#393a3e}.mc-code-block-dark .mc-code-block-actions .mc-copy-btn img,.mc-code-block-dark .mc-code-block-actions .mc-toggle-btn img{filter:brightness(1.5)}.mc-code-block-dark .mc-mermaid-content{background:#2b2b2b!important}@keyframes collapse-expand{0%{opacity:0;max-height:0}to{opacity:1;max-height:1000px}}@keyframes collapse-collapse{0%{opacity:1;max-height:1000px}to{opacity:0;max-height:0}}.mc-block-hidden{display:none}.collapse-expanded{animation:collapse-expand .5s ease-out}.collapse-collapsed{animation:collapse-collapse .5s ease-in}.mc-code-block{margin:1rem 0;overflow:hidden;border-radius:14px}.mc-code-block pre{margin:0}.mc-code-block .mc-action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;box-sizing:border-box}.mc-code-block .mc-code-block-header{display:flex;justify-content:space-between;align-items:center;padding:.5rem 1rem}.mc-code-block .mc-code-block-header .mc-code-lang{font-size:14px}.mc-code-block .mc-mermaid-content{position:relative;width:100%;height:400px;overflow:hidden;background:inherit}.mc-code-block .mc-code-block-actions{display:flex;align-items:center}.mc-code-block .mc-code-block-actions .mc-copy-btn,.mc-code-block .mc-code-block-actions .mc-toggle-btn{cursor:pointer;border-radius:4px;font-size:18px;padding:4px}.mc-code-block .mc-diagram-switch{display:flex;align-items:center;list-style:none;margin:0;padding:2px;border-radius:4px;background-color:var(--devui-icon-hover-bg);position:relative;transition:all .3s ease;overflow:hidden;height:24px}.mc-code-block .mc-diagram-switch:before{content:\"\";position:absolute;top:2px;left:2px;width:calc(50% - 2px);height:calc(100% - 4px);background-color:var(--devui-base-bg);border-radius:4px;transition:transform .3s ease;box-shadow:0 1px 2px #0000001a;z-index:1}.mc-code-block .mc-diagram-switch.mc-show-code:before{transform:translate(100%)}.mc-code-block .mc-diagram-switch .mc-diagram-switch-active{text-shadow:0 0 .4px #252b3a}.mc-code-block .mc-diagram-switch li{position:relative;padding:0 8px;margin:0;font-size:12px;cursor:pointer;transition:color .3s ease;z-index:2}\n"], dependencies: [{ 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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
@@ -2039,6 +2041,26 @@ const tokensToAst = (tokens) => {
2039
2041
  }
2040
2042
  return rootNode.children;
2041
2043
  };
2044
+ /**
2045
+ * 递归查找所有层级中 className 包含 code-block-wrapper 的 DIV 节点
2046
+ * @param {Array} vnodes - 待查找的 vnode 列表
2047
+ * @returns {Array} 符合条件的节点列表
2048
+ */
2049
+ function findCodeBlockWrappers(vnodes) {
2050
+ const result = [];
2051
+ // 遍历当前层级的 vnode
2052
+ vnodes.forEach((node) => {
2053
+ // 检查当前节点是否符合条件
2054
+ if (node.nodeName === 'DIV' && node.className?.includes('code-block-wrapper')) {
2055
+ result.push(node);
2056
+ }
2057
+ // 递归处理子节点(如果存在子节点且为数组)
2058
+ if (node.childNodes?.length) {
2059
+ result.push(...findCodeBlockWrappers(node.childNodes));
2060
+ }
2061
+ });
2062
+ return result;
2063
+ }
2042
2064
  // 声明一个utils静态默认导出
2043
2065
  var MdParserUtils = {
2044
2066
  isSelfClosingTag,
@@ -2046,7 +2068,8 @@ var MdParserUtils = {
2046
2068
  tokensToAst,
2047
2069
  genTreeNode,
2048
2070
  matchHtmlToken,
2049
- isValidTagName
2071
+ isValidTagName,
2072
+ findCodeBlockWrappers,
2050
2073
  };
2051
2074
 
2052
2075
  class MarkdownCardComponent extends BaseComponent {
@@ -2064,6 +2087,7 @@ class MarkdownCardComponent extends BaseComponent {
2064
2087
  this.customXssRules = [];
2065
2088
  this.theme = 'light';
2066
2089
  this.enableMermaid = false;
2090
+ this.incrementalDom = true;
2067
2091
  this.mermaidConfig = {};
2068
2092
  this.actionsTemplate = null;
2069
2093
  this.headerTemplate = null;
@@ -2071,6 +2095,7 @@ class MarkdownCardComponent extends BaseComponent {
2071
2095
  // 组件缓存映射表,用于存储已创建的CodeBlockComponent实例
2072
2096
  this.codeBlockComponentsCache = new Map();
2073
2097
  this.afterMdtInit = new EventEmitter();
2098
+ this.mdRenderChange = new EventEmitter();
2074
2099
  this.typingStart = new EventEmitter();
2075
2100
  this.typingEvent = new EventEmitter();
2076
2101
  this.typingEnd = new EventEmitter();
@@ -2078,7 +2103,6 @@ class MarkdownCardComponent extends BaseComponent {
2078
2103
  this.isTyping = false;
2079
2104
  this.timer = null;
2080
2105
  this.parser = MdParserUtils;
2081
- this.noDiff = false;
2082
2106
  this.mdt = markdownit({
2083
2107
  breaks: true,
2084
2108
  linkify: true,
@@ -2091,24 +2115,10 @@ class MarkdownCardComponent extends BaseComponent {
2091
2115
  });
2092
2116
  this.mdCardService = new MDCardService();
2093
2117
  this.foundation = new MarkdownCardFoundation(this.adapter);
2094
- // 初始化 diffDom 实例
2095
- this.diffDom = new DiffDOM({
2096
- // 配置filterOuterDiff钩子,识别code-block-wrapper元素并直接替换
2097
- filterOuterDiff: (t1, t2, diffs) => {
2098
- // 检查是否是class为code-block-wrapper的div元素
2099
- const isTargetElement = t2.nodeName === 'DIV' &&
2100
- t2.attributes &&
2101
- t2.attributes.class &&
2102
- t2.attributes.class.includes('code-block-wrapper');
2103
- if (isTargetElement) {
2104
- t1.innerDone = true;
2105
- t2.innerDone = true;
2106
- }
2107
- },
2108
- });
2109
2118
  }
2110
2119
  ngOnInit() {
2111
2120
  this.mdCardService.setMdPlugins(this.mdPlugins || [], this.mdt);
2121
+ this.mdCardService.setCustomXssRules(this.customXssRules || []);
2112
2122
  this.parseContent();
2113
2123
  this.afterMdtInit.emit(this.mdt);
2114
2124
  }
@@ -2130,29 +2140,38 @@ class MarkdownCardComponent extends BaseComponent {
2130
2140
  }
2131
2141
  ngOnChanges(changes) {
2132
2142
  if (changes['content']) {
2133
- if (!this.typing) {
2134
- this.typingIndex = this.content?.length || 0;
2135
- this.parseContent();
2136
- return;
2137
- }
2138
- if (this.content.indexOf(changes['content']?.previousValue) === -1) {
2139
- this.typingIndex = 0;
2140
- }
2141
- // 使用setTimeout模拟Vue的nextTick行为
2142
- setTimeout(() => this.typewriterStart());
2143
+ this.contentChange(changes['content']);
2143
2144
  }
2144
- if (changes['enableThink'] || changes['thinkOptions'] || changes['theme']) {
2145
+ if (changes['customXssRules'] && !changes['customXssRules'].firstChange) {
2146
+ this.mdCardService.setCustomXssRules(this.customXssRules || []);
2145
2147
  this.parseContent();
2146
2148
  }
2147
- if (changes['customXssRules']) {
2148
- this.mdCardService.setCustomXssRules(this.customXssRules || []);
2149
+ if ((changes['enableThink'] && !changes['enableThink'].firstChange) ||
2150
+ (changes['thinkOptions'] && !changes['thinkOptions'].firstChange) ||
2151
+ (changes['theme'] && !changes['theme'].firstChange)) {
2149
2152
  this.parseContent();
2150
2153
  }
2151
- if (changes['mdPlugins']) {
2154
+ if (changes['mdPlugins'] && !changes['mdPlugins'].firstChange) {
2152
2155
  this.mdCardService.setMdPlugins(this.mdPlugins || [], this.mdt);
2153
2156
  this.parseContent();
2154
2157
  }
2155
2158
  }
2159
+ contentChange(change) {
2160
+ if (this.content.indexOf(change.previousValue) === -1) {
2161
+ this.clearCodeBlockCache();
2162
+ }
2163
+ if (!this.typing) {
2164
+ this.typingIndex = this.content?.length || 0;
2165
+ this.parseContent();
2166
+ }
2167
+ else {
2168
+ if (this.content.indexOf(change.previousValue) === -1) {
2169
+ this.typingIndex = 0;
2170
+ }
2171
+ // 使用setTimeout模拟Vue的nextTick行为
2172
+ setTimeout(() => this.typewriterStart());
2173
+ }
2174
+ }
2156
2175
  parseContent() {
2157
2176
  this.foundation.parseContent();
2158
2177
  }
@@ -2160,17 +2179,14 @@ class MarkdownCardComponent extends BaseComponent {
2160
2179
  if (!this.markdownContainer || !this.markdownContainer.element) {
2161
2180
  return;
2162
2181
  }
2163
- if (this.noDiff) {
2182
+ if (!this.incrementalDom) {
2164
2183
  this.renderContentNoDiff(vnodes);
2165
2184
  return;
2166
2185
  }
2167
2186
  const container = this.markdownContainer.element.nativeElement;
2168
2187
  const parser = new DOMParser();
2169
2188
  const newContainerDiv = parser.parseFromString(`<div></div>`, 'text/html');
2170
- const codeBlockWrappers = vnodes.filter((node) => {
2171
- return (node.nodeName === 'DIV' &&
2172
- node.className?.includes('code-block-wrapper'));
2173
- });
2189
+ const codeBlockWrappers = this.parser.findCodeBlockWrappers(vnodes);
2174
2190
  vnodes.forEach((node) => {
2175
2191
  if (node &&
2176
2192
  (node.nodeType ||
@@ -2185,8 +2201,23 @@ class MarkdownCardComponent extends BaseComponent {
2185
2201
  }
2186
2202
  });
2187
2203
  let newContainerDivHTML = newContainerDiv.body?.firstChild?.outerHTML || '';
2188
- const patches = this.diffDom.diff(container, this.mdCardService.filterHtml(newContainerDivHTML));
2189
- this.diffDom.apply(container, patches);
2204
+ const filteredHTML = this.mdCardService.filterHtml(newContainerDivHTML);
2205
+ // 使用morphdom进行DOM更新
2206
+ const newElement = document.createElement('div');
2207
+ newElement.innerHTML = filteredHTML;
2208
+ morphdom(container, filteredHTML, {
2209
+ onBeforeElUpdated: (fromEl, toEl) => {
2210
+ if (fromEl.nodeName === 'DIV' &&
2211
+ fromEl.classList.contains('code-block-wrapper') &&
2212
+ toEl.nodeName === 'DIV' &&
2213
+ toEl.classList.contains('code-block-wrapper') &&
2214
+ fromEl.getAttribute('key') === toEl.getAttribute('key') &&
2215
+ this.codeBlockComponentsCache.has(fromEl.getAttribute('key') || '')) {
2216
+ return false;
2217
+ }
2218
+ return true;
2219
+ },
2220
+ });
2190
2221
  // 将codeBlockWrappers中的每个div元素替换container中的对应key属性的元素
2191
2222
  codeBlockWrappers.forEach((newCodeBlock) => {
2192
2223
  if (newCodeBlock &&
@@ -2201,6 +2232,7 @@ class MarkdownCardComponent extends BaseComponent {
2201
2232
  }
2202
2233
  }
2203
2234
  });
2235
+ this.mdRenderChange.emit(newContainerDivHTML);
2204
2236
  }
2205
2237
  getEmptyCodeBlock(node) {
2206
2238
  const codeNode = document.createElement('div');
@@ -2420,16 +2452,18 @@ class MarkdownCardComponent extends BaseComponent {
2420
2452
  typewriterStart() {
2421
2453
  this.foundation.typewriterStart();
2422
2454
  }
2423
- // 在组件销毁时清理缓存,避免内存泄漏
2424
- ngOnDestroy() {
2425
- // 销毁所有缓存的组件实例
2455
+ clearCodeBlockCache() {
2426
2456
  this.codeBlockComponentsCache.forEach((cachedItem) => {
2427
2457
  cachedItem.componentRef.destroy();
2428
2458
  });
2429
2459
  this.codeBlockComponentsCache.clear();
2430
2460
  }
2461
+ // 在组件销毁时清理缓存,避免内存泄漏
2462
+ ngOnDestroy() {
2463
+ this.clearCodeBlockCache();
2464
+ }
2431
2465
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: MarkdownCardComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2432
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: MarkdownCardComponent, isStandalone: false, selector: "mc-markdown-card", inputs: { content: "content", typing: "typing", enableThink: "enableThink", typingOptions: "typingOptions", thinkOptions: "thinkOptions", mdOptions: "mdOptions", mdPlugins: "mdPlugins", customXssRules: "customXssRules", theme: "theme", enableMermaid: "enableMermaid", mermaidConfig: "mermaidConfig", actionsTemplate: "actionsTemplate", headerTemplate: "headerTemplate", contentTemplate: "contentTemplate" }, outputs: { afterMdtInit: "afterMdtInit", typingStart: "typingStart", typingEvent: "typingEvent", typingEnd: "typingEnd" }, viewQueries: [{ propertyName: "markdownContainer", first: true, predicate: ["markdownContainer"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"mc-markdown-render\" [ngClass]=\"theme === 'dark' ? 'mc-markdown-render-dark' : 'mc-markdown-render-light'\">\n <div #markdownContainer></div>\n</div>\n<ng-content></ng-content>", styles: [".mc-markdown-render ::ng-deep .h1,.mc-markdown-render ::ng-deep .h2,.mc-markdown-render ::ng-deep .h3,.mc-markdown-render ::ng-deep .h4,.mc-markdown-render ::ng-deep .h5,.mc-markdown-render ::ng-deep .h6,.mc-markdown-render ::ng-deep h1,.mc-markdown-render ::ng-deep h2,.mc-markdown-render ::ng-deep h3,.mc-markdown-render ::ng-deep h4,.mc-markdown-render ::ng-deep h5,.mc-markdown-render ::ng-deep h6{line-height:1.1;margin:16px 0 12px}.mc-markdown-render ::ng-deep .h1:first-child,.mc-markdown-render ::ng-deep .h2:first-child,.mc-markdown-render ::ng-deep .h3:first-child,.mc-markdown-render ::ng-deep .h4:first-child,.mc-markdown-render ::ng-deep .h5:first-child,.mc-markdown-render ::ng-deep .h6:first-child,.mc-markdown-render ::ng-deep h1:first-child,.mc-markdown-render ::ng-deep h2:first-child,.mc-markdown-render ::ng-deep h3:first-child,.mc-markdown-render ::ng-deep h4:first-child,.mc-markdown-render ::ng-deep h5:first-child,.mc-markdown-render ::ng-deep h6:first-child{margin-top:0}.mc-markdown-render ::ng-deep h1{font-size:32px;line-height:40px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep h3{line-height:28px;font-size:20px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep caption{border:1px dashed var(--devui-line, #d7d8da);border-bottom:0;padding:3px;text-align:center}.mc-markdown-render ::ng-deep p{overflow-wrap:break-word;margin:0;padding:0;line-height:24px}.mc-markdown-render ::ng-deep p:last-child{margin:0}.mc-markdown-render ::ng-deep ul,.mc-markdown-render ::ng-deep ol{margin:0;padding:0;padding-inline-start:1.75em}.mc-markdown-render ::ng-deep ul>li,.mc-markdown-render ::ng-deep ol>li{line-height:21px}.mc-markdown-render ::ng-deep ul{list-style-type:disc}.mc-markdown-render ::ng-deep ul li::marker{font-size:20px}.mc-markdown-render ::ng-deep ol{list-style-type:decimal}.mc-markdown-render ::ng-deep table{margin-bottom:10px;border-collapse:collapse;display:table}.mc-markdown-render ::ng-deep td,.mc-markdown-render ::ng-deep th{padding:5px 10px;border:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-base-bg, #ffffff)}.mc-markdown-render ::ng-deep th{border-top:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-global-bg, #f6f6f8)}.mc-markdown-render ::ng-deep td p{margin:0;padding:0}.mc-markdown-render ::ng-deep blockquote{padding:0 8px;margin:0;color:var(--devui-text-weak, #575d6c);border-left:5px solid var(--devui-dividing-line, #f2f2f3)}.mc-markdown-render ::ng-deep a{color:var(--devui-link, #526ecc);text-decoration:none;cursor:pointer}.mc-markdown-render ::ng-deep a:hover{color:var(--devui-link-active, #526ecc)}.mc-markdown-render ::ng-deep img{max-width:100%}.mc-markdown-render{font-size:var(--devui-font-size, 14px);overflow-x:auto}.mc-markdown-render.mc-markdown-render-dark{color:#ced1db}.mc-markdown-render.mc-markdown-render-light{color:#252b3a}::ng-deep .mc-think-block{color:var(--devui-aide-text, #71757f);border-left:1px solid var(--devui-line, #d7d8da);padding-left:8px;margin-bottom:1rem}::ng-deep .mc-typewriter-color{background-image:-webkit-linear-gradient(left,#191919,#5588f0,#e171ee,#f2c55c);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-gradient{background:linear-gradient(to right,var(--devui-text, #252b3a),var(--devui-base-bg, #ffffff));background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-cursor{font-weight:900;animation:typewriter .8s linear 0s infinite}@keyframes typewriter{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2466
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: MarkdownCardComponent, isStandalone: false, selector: "mc-markdown-card", inputs: { content: "content", typing: "typing", enableThink: "enableThink", typingOptions: "typingOptions", thinkOptions: "thinkOptions", mdOptions: "mdOptions", mdPlugins: "mdPlugins", customXssRules: "customXssRules", theme: "theme", enableMermaid: "enableMermaid", incrementalDom: "incrementalDom", mermaidConfig: "mermaidConfig", actionsTemplate: "actionsTemplate", headerTemplate: "headerTemplate", contentTemplate: "contentTemplate" }, outputs: { afterMdtInit: "afterMdtInit", mdRenderChange: "mdRenderChange", typingStart: "typingStart", typingEvent: "typingEvent", typingEnd: "typingEnd" }, viewQueries: [{ propertyName: "markdownContainer", first: true, predicate: ["markdownContainer"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"mc-markdown-render\" [ngClass]=\"theme === 'dark' ? 'mc-markdown-render-dark' : 'mc-markdown-render-light'\">\n <div #markdownContainer></div>\n</div>\n<ng-content></ng-content>", styles: [".mc-markdown-render ::ng-deep .h1,.mc-markdown-render ::ng-deep .h2,.mc-markdown-render ::ng-deep .h3,.mc-markdown-render ::ng-deep .h4,.mc-markdown-render ::ng-deep .h5,.mc-markdown-render ::ng-deep .h6,.mc-markdown-render ::ng-deep h1,.mc-markdown-render ::ng-deep h2,.mc-markdown-render ::ng-deep h3,.mc-markdown-render ::ng-deep h4,.mc-markdown-render ::ng-deep h5,.mc-markdown-render ::ng-deep h6{line-height:1.1;margin:16px 0 12px}.mc-markdown-render ::ng-deep .h1:first-child,.mc-markdown-render ::ng-deep .h2:first-child,.mc-markdown-render ::ng-deep .h3:first-child,.mc-markdown-render ::ng-deep .h4:first-child,.mc-markdown-render ::ng-deep .h5:first-child,.mc-markdown-render ::ng-deep .h6:first-child,.mc-markdown-render ::ng-deep h1:first-child,.mc-markdown-render ::ng-deep h2:first-child,.mc-markdown-render ::ng-deep h3:first-child,.mc-markdown-render ::ng-deep h4:first-child,.mc-markdown-render ::ng-deep h5:first-child,.mc-markdown-render ::ng-deep h6:first-child{margin-top:0}.mc-markdown-render ::ng-deep h1{font-size:32px;line-height:40px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep h3{line-height:28px;font-size:20px;overflow-wrap:break-word}.mc-markdown-render ::ng-deep caption{border:1px dashed var(--devui-line, #d7d8da);border-bottom:0;padding:3px;text-align:center}.mc-markdown-render ::ng-deep p{overflow-wrap:break-word;margin:0;padding:0;line-height:24px}.mc-markdown-render ::ng-deep p:last-child{margin:0}.mc-markdown-render ::ng-deep ul,.mc-markdown-render ::ng-deep ol{margin:0;padding:0;padding-inline-start:1.75em}.mc-markdown-render ::ng-deep ul>li,.mc-markdown-render ::ng-deep ol>li{line-height:21px}.mc-markdown-render ::ng-deep ul{list-style-type:disc}.mc-markdown-render ::ng-deep ul li::marker{font-size:20px}.mc-markdown-render ::ng-deep ol{list-style-type:decimal}.mc-markdown-render ::ng-deep table{margin-bottom:10px;border-collapse:collapse;display:table}.mc-markdown-render ::ng-deep td,.mc-markdown-render ::ng-deep th{padding:5px 10px;border:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-base-bg, #ffffff)}.mc-markdown-render ::ng-deep th{border-top:1px solid var(--devui-dividing-line, #f2f2f3);background-color:var(--devui-global-bg, #f6f6f8)}.mc-markdown-render ::ng-deep td p{margin:0;padding:0}.mc-markdown-render ::ng-deep blockquote{padding:0 8px;margin:0;color:var(--devui-text-weak, #575d6c);border-left:5px solid var(--devui-dividing-line, #f2f2f3)}.mc-markdown-render ::ng-deep a{color:var(--devui-link, #526ecc);text-decoration:none;cursor:pointer}.mc-markdown-render ::ng-deep a:hover{color:var(--devui-link-active, #526ecc)}.mc-markdown-render ::ng-deep img{max-width:100%}.mc-markdown-render{font-size:var(--devui-font-size, 14px);overflow-x:auto}.mc-markdown-render.mc-markdown-render-dark{color:#ced1db}.mc-markdown-render.mc-markdown-render-light{color:#252b3a}::ng-deep .mc-think-block{color:var(--devui-aide-text, #71757f);border-left:1px solid var(--devui-line, #d7d8da);padding-left:8px;margin-bottom:1rem}::ng-deep .mc-typewriter-color{background-image:-webkit-linear-gradient(left,#191919,#5588f0,#e171ee,#f2c55c);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-gradient{background:linear-gradient(to right,var(--devui-text, #252b3a),var(--devui-base-bg, #ffffff));background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}::ng-deep .mc-typewriter-cursor{font-weight:900;animation:typewriter .8s linear 0s infinite}@keyframes typewriter{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2433
2467
  }
2434
2468
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: MarkdownCardComponent, decorators: [{
2435
2469
  type: Component,
@@ -2454,6 +2488,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
2454
2488
  type: Input
2455
2489
  }], enableMermaid: [{
2456
2490
  type: Input
2491
+ }], incrementalDom: [{
2492
+ type: Input
2457
2493
  }], mermaidConfig: [{
2458
2494
  type: Input
2459
2495
  }], actionsTemplate: [{
@@ -2464,6 +2500,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
2464
2500
  type: Input
2465
2501
  }], afterMdtInit: [{
2466
2502
  type: Output
2503
+ }], mdRenderChange: [{
2504
+ type: Output
2467
2505
  }], typingStart: [{
2468
2506
  type: Output
2469
2507
  }], typingEvent: [{