Skip to content

Commit 3f7be43

Browse files
hoonjicopybara-github
authored andcommitted
Enables customizing markdown renderer
PiperOrigin-RevId: 811555749
1 parent e9b20ac commit 3f7be43

File tree

9 files changed

+58
-15
lines changed

9 files changed

+58
-15
lines changed

src/app/components/chat-panel/chat-panel.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
</div>
106106
</div>
107107
} @else {
108-
<app-markdown [text]="message.text!" [thought]="message.thought"></app-markdown>
108+
<ng-container [ngComponentOutlet]="markdownComponent" [ngComponentOutletInputs]="{text: message.text!, thought: message.thought}"></ng-container>
109109
}
110110
}
111111
</div>

src/app/components/chat-panel/chat-panel.component.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {STRING_TO_COLOR_SERVICE} from '../../core/services/interfaces/string-to-
2828
import {StringToColorServiceImpl} from '../../core/services/string-to-color.service';
2929
import {MockStringToColorService} from '../../core/services/testing/mock-string-to-color.service';
3030
import {ChatPanelComponent} from './chat-panel.component';
31+
import {MARKDOWN_COMPONENT} from '../markdown/markdown.component.interface';
32+
import {MarkdownComponent} from '../markdown/markdown.component';
3133

3234
const USER_ID = 'user';
3335
const FUNC1_NAME = 'func1';
@@ -53,6 +55,7 @@ describe('ChatPanelComponent', () => {
5355
provide: STRING_TO_COLOR_SERVICE,
5456
useClass: StringToColorServiceImpl,
5557
},
58+
{provide: MARKDOWN_COMPONENT, useValue: MarkdownComponent},
5659
],
5760
})
5861
.compileComponents();

src/app/components/chat-panel/chat-panel.component.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import {TextFieldModule} from '@angular/cdk/text-field';
1919
import {CommonModule, DOCUMENT, NgClass, NgStyle} from '@angular/common';
20-
import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Inject, Input, OnChanges, Output, Renderer2, signal, SimpleChanges, ViewChild,} from '@angular/core';
20+
import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Inject, Input, OnChanges, Output, Renderer2, signal, SimpleChanges, ViewChild, Type} from '@angular/core';
2121
import {FormsModule} from '@angular/forms';
2222
import {MatButtonModule} from '@angular/material/button';
2323
import {MatCardModule} from '@angular/material/card';
@@ -34,7 +34,7 @@ import type {EvalCase} from '../../core/models/Eval';
3434
import {STRING_TO_COLOR_SERVICE} from '../../core/services/interfaces/string-to-color';
3535
import {MediaType,} from '../artifact-tab/artifact-tab.component';
3636
import {AudioPlayerComponent} from '../audio-player/audio-player.component';
37-
import {MarkdownComponent} from '../markdown/markdown.component';
37+
import {MARKDOWN_COMPONENT, MarkdownComponentInterface} from '../markdown/markdown.component.interface';
3838

3939
import {ChatPanelMessagesInjectionToken} from './chat-panel.component.i18n';
4040

@@ -49,7 +49,7 @@ const ROOT_AGENT = 'root_agent';
4949
CommonModule, FormsModule, MatIconModule, MatCardModule,
5050
MatProgressBarModule, MatButtonModule, MatInputModule, TextFieldModule,
5151
MatFormFieldModule, MatMenuModule, NgxJsonViewerModule,
52-
AudioPlayerComponent, MatTooltipModule, NgClass, NgStyle, MarkdownComponent
52+
AudioPlayerComponent, MatTooltipModule, NgClass, NgStyle,
5353
],
5454
})
5555
export class ChatPanelComponent implements OnChanges, AfterViewInit {
@@ -101,6 +101,9 @@ export class ChatPanelComponent implements OnChanges, AfterViewInit {
101101
private previousMessageCount = 0;
102102
protected readonly i18n = inject(ChatPanelMessagesInjectionToken);
103103
private readonly stringToColorService = inject(STRING_TO_COLOR_SERVICE);
104+
readonly markdownComponent: Type<MarkdownComponentInterface> = inject(
105+
MARKDOWN_COMPONENT,
106+
);
104107
readonly MediaType = MediaType;
105108

106109
constructor(

src/app/components/chat/chat.component.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ import {TRACE_SERVICE, TraceService} from '../../core/services/trace.service';
5656
import {VIDEO_SERVICE, VideoService} from '../../core/services/video.service';
5757
import {WEBSOCKET_SERVICE, WebSocketService,} from '../../core/services/websocket.service';
5858
import {Component} from '@angular/core';
59+
import {MARKDOWN_COMPONENT} from '../markdown/markdown.component.interface';
60+
import {MarkdownComponent} from '../markdown/markdown.component';
5961

6062
import {ChatPanelComponent} from '../chat-panel/chat-panel.component';
6163
import {SidePanelComponent} from '../side-panel/side-panel.component';
@@ -202,6 +204,7 @@ describe('ChatComponent', () => {
202204
{provide: Router, useValue: mockRouter},
203205
{provide: ActivatedRoute, useValue: mockActivatedRoute},
204206
{provide: Location, useValue: mockLocation},
207+
{provide: MARKDOWN_COMPONENT, useValue: MarkdownComponent},
205208
],
206209
})
207210
.compileComponents();

src/app/components/markdown/markdown.component.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
-->
1616

1717
<markdown
18-
[data]="text"
18+
[data]="text()"
1919
[ngStyle]="{
20-
'font-style': thought ? 'italic' : 'normal',
21-
color: thought ? '#9aa0a6' : 'white'
20+
'font-style': thought() ? 'italic' : 'normal',
21+
color: thought() ? '#9aa0a6' : 'white'
2222
}"
2323
></markdown>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import {Component, InjectionToken, InputSignal, Type} from '@angular/core';
19+
20+
/**
21+
* Represents a component to be used to render markdown across the app.
22+
*/
23+
export const MARKDOWN_COMPONENT = new InjectionToken<Type<MarkdownComponentInterface>>(
24+
'MARKDOWN_COMPONENT',
25+
);
26+
27+
/**
28+
* Interface for Markdown component.
29+
*/
30+
export interface MarkdownComponentInterface {
31+
text: InputSignal<string>;
32+
thought: InputSignal<boolean>;
33+
}

src/app/components/markdown/markdown.component.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('MarkdownComponent', () => {
4646
});
4747

4848
it('should display markdown text', fakeAsync(() => {
49-
component.text = '**bold**';
49+
fixture.componentRef.setInput('text', '**bold**');
5050
fixture.detectChanges();
5151
tick();
5252
const element: HTMLElement = fixture.nativeElement;
@@ -55,7 +55,7 @@ describe('MarkdownComponent', () => {
5555
}));
5656

5757
it('should apply italic style when thought is true', () => {
58-
component.thought = true;
58+
fixture.componentRef.setInput('thought', true);
5959
fixture.detectChanges();
6060
const markdownElement: HTMLElement|null =
6161
fixture.nativeElement.querySelector('markdown');
@@ -64,7 +64,7 @@ describe('MarkdownComponent', () => {
6464
});
6565

6666
it('should apply normal style when thought is false', () => {
67-
component.thought = false;
67+
fixture.componentRef.setInput('thought', false);
6868
fixture.detectChanges();
6969
const markdownElement: HTMLElement|null =
7070
fixture.nativeElement.querySelector('markdown');

src/app/components/markdown/markdown.component.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
*/
1717

1818
import {CommonModule} from '@angular/common';
19-
import {Component, Input, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
20-
19+
import {Component, input} from '@angular/core';
2120
import {MarkdownModule, provideMarkdown} from 'ngx-markdown';
2221

2322
/**
@@ -34,9 +33,8 @@ import {MarkdownModule, provideMarkdown} from 'ngx-markdown';
3433
providers: [
3534
provideMarkdown(),
3635
],
37-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
3836
})
3937
export class MarkdownComponent {
40-
@Input() text = '';
41-
@Input() thought = false;
38+
text = input('');
39+
thought = input(false);
4240
}

src/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import {StringToColorServiceImpl} from './app/core/services/string-to-color.serv
4343
import {TRACE_SERVICE, TraceService} from './app/core/services/trace.service';
4444
import {VIDEO_SERVICE, VideoService} from './app/core/services/video.service';
4545
import {WEBSOCKET_SERVICE, WebSocketService} from './app/core/services/websocket.service';
46+
import {MARKDOWN_COMPONENT} from './app/components/markdown/markdown.component.interface';
47+
import {MarkdownComponent} from './app/components/markdown/markdown.component';
4648

4749
fetch('./assets/config/runtime-config.json')
4850
.then((response) => response.json())
@@ -67,6 +69,7 @@ fetch('./assets/config/runtime-config.json')
6769
{provide: GRAPH_SERVICE, useClass: GraphService},
6870
{provide: STRING_TO_COLOR_SERVICE, useClass: StringToColorServiceImpl},
6971
{provide: SAFE_VALUES_SERVICE, useClass: SafeValuesServiceImpl},
72+
{provide: MARKDOWN_COMPONENT, useValue: MarkdownComponent},
7073
provideAnimations(),
7174
]
7275
}).catch((err) => console.error(err));

0 commit comments

Comments
 (0)