Skip to content

Commit

Permalink
Merge pull request #681 from GetStream/message-text-component
Browse files Browse the repository at this point in the history
feat: create message-text component
  • Loading branch information
szuperaz authored Jan 16, 2025
2 parents 141e8ab + 97dfe68 commit d2b7eb7
Show file tree
Hide file tree
Showing 21 changed files with 791 additions and 476 deletions.
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"@ctrl/ngx-emoji-mart": "^8.2.0",
"@floating-ui/dom": "^1.6.3",
"@ngx-translate/core": "^14.0.0",
"@stream-io/stream-chat-css": "5.3.0",
"@stream-io/stream-chat-css": "5.6.1",
"@stream-io/transliterate": "^1.5.2",
"angular-mentions": "1.4.0",
"dayjs": "^1.11.10",
Expand Down
13 changes: 13 additions & 0 deletions projects/customizations-example/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,16 @@
<div>Latest message text: {{ latestMessageText }}</div>
<div>Latest message id: {{ latestMessage?.id }}</div>
</ng-template>

<ng-template
#messageText
let-message="message"
let-shouldTranslate="shouldTranslate"
let-isQuoted="isQuoted"
>
<app-message-text
[message]="message"
[shouldTranslate]="shouldTranslate"
[isQuoted]="isQuoted"
></app-message-text>
</ng-template>
6 changes: 6 additions & 0 deletions projects/customizations-example/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
MessageActionsService,
ChannelPreviewInfoContext,
MessageReactionsSelectorComponent,
MessageTextContext,
} from 'stream-chat-angular';
import { environment } from '../environments/environment';

Expand Down Expand Up @@ -95,6 +96,8 @@ export class AppComponent implements AfterViewInit {
private emptyMainMessageListTemplate!: TemplateRef<void>;
@ViewChild('emptyThreadMessageList')
private emptyThreadMessageListTemplate!: TemplateRef<void>;
@ViewChild('messageText')
messageTextTemplate!: TemplateRef<MessageTextContext>;

constructor(
private chatService: ChatClientService,
Expand Down Expand Up @@ -189,6 +192,9 @@ export class AppComponent implements AfterViewInit {
this.customTemplatesService.emptyThreadMessageListPlaceholder$.next(
this.emptyThreadMessageListTemplate
);
this.customTemplatesService.messageTextTemplate$.next(
this.messageTextTemplate
);
}

inviteClicked(channel: Channel) {
Expand Down
2 changes: 2 additions & 0 deletions projects/customizations-example/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PickerModule } from '@ctrl/ngx-emoji-mart';
import { MessageActionComponent } from './message-action/message-action.component';
import { ThreadHeaderComponent } from './thread-header/thread-header.component';
import { IconComponent } from './icon/icon.component';
import { MessageTextComponent } from './message-text/message-text.component';

@NgModule({
declarations: [
Expand All @@ -20,6 +21,7 @@ import { IconComponent } from './icon/icon.component';
MessageActionComponent,
ThreadHeaderComponent,
IconComponent,
MessageTextComponent,
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<ng-container *ngIf="isQuoted; else regularMessageText">
<!-- Quoted message are clamped by default, so need there -->
<stream-message-text
[message]="message"
[shouldTranslate]="shouldTranslate"
[isQuoted]="isQuoted"
></stream-message-text>
</ng-container>
<ng-template #regularMessageText>
<div class="message-text" [class.message-text-expanded]="isExpanded" #text>
<stream-message-text
[message]="message"
[shouldTranslate]="shouldTranslate"
[isQuoted]="isQuoted"
></stream-message-text>
</div>
<!-- 5px diff is due to Firefox issue -->
<button
[class.visible]="text.scrollHeight - text.clientHeight > 5 || isExpanded"
(click)="isExpanded = !isExpanded"
>
{{ "Show" + (isExpanded ? " less" : " more") }}
</button>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.message-text {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 5;
line-clamp: 5;
-webkit-box-orient: vertical;
}

.message-text.message-text-expanded {
display: block;
}

button {
display: none;

&.visible {
display: block;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, Input } from '@angular/core';
import { MessageResponseBase } from 'stream-chat';
import { DefaultStreamChatGenerics, StreamMessage } from 'stream-chat-angular';

@Component({
selector: 'app-message-text',
templateUrl: './message-text.component.html',
styleUrls: ['./message-text.component.scss'],
})
export class MessageTextComponent {
@Input() message:
| StreamMessage<DefaultStreamChatGenerics>
| undefined
| MessageResponseBase<DefaultStreamChatGenerics>;
@Input() isQuoted: boolean = false;
@Input() shouldTranslate: boolean = false;
isExpanded = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
MessageContext,
MessageReactionsContext,
MessageReactionsSelectorContext,
MessageTextContext,
ModalContext,
NotificationContext,
ReadStatusContext,
Expand All @@ -43,7 +44,7 @@ import {
*
* For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
*
* You can find the type definitions of the context that is provided for each template [on GitHub](https://github.com/GetStream/stream-chat-angular/blob/master/projects/stream-chat-angu)
* You can find the type definitions of the context that is provided for each template [on GitHub](https://github.com/GetStream/stream-chat-angular/blob/master/projects/stream-chat-angular/src/lib/types.ts)
*/
@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -358,6 +359,12 @@ export class CustomTemplatesService<
customMessageMetadataInsideBubbleTemplate$ = new BehaviorSubject<
TemplateRef<CustomMetadataContext> | undefined
>(undefined);
/**
* Template to display the text content inside the [message component](/chat/docs/sdk/angular/components/MessageComponent/). The default component is [stream-message-text](/chat/docs/sdk/angular/components/MessageTextComponent/)
*/
messageTextTemplate$ = new BehaviorSubject<
TemplateRef<MessageTextContext> | undefined
>(undefined);

constructor() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,28 @@
[attachments]="quotedMessageAttachments"
[messageId]="quotedMessage.id"
></stream-attachment-list>
<div
class="str-chat__quoted-message-text"
data-testid="quoted-message-text"
[innerHTML]="
quotedMessage.translation ||
quotedMessage.html ||
quotedMessage.text
"
></div>
<div class="str-chat__quoted-message-text">
<ng-container
*ngTemplateOutlet="
(customTemplatesService.messageTextTemplate$ | async) ||
defaultText;
context: getQuotedMessageTextContext()
"
></ng-container>
<ng-template
#defaultText
let-message="message"
let-isQuoted="isQuoted"
let-shouldTranslate="shouldTranslate"
>
<stream-message-text
[message]="message"
[isQuoted]="isQuoted"
[shouldTranslate]="shouldTranslate"
data-testid="quoted-message-text"
></stream-message-text>
</ng-template>
</div>
</div>
</div>
<ng-template
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { StreamAvatarModule } from '../stream-avatar.module';
import { VoiceRecorderService } from './voice-recorder.service';
import { CustomTemplatesService } from '../custom-templates.service';
import { MessageInputConfigService } from './message-input-config.service';
import { MessageTextComponent } from '../message-text/message-text.component';

describe('MessageInputComponent', () => {
let nativeElement: HTMLElement;
Expand Down Expand Up @@ -131,6 +132,7 @@ describe('MessageInputComponent', () => {
AutocompleteTextareaComponent,
AttachmentListComponent,
AttachmentPreviewListComponent,
MessageTextComponent,
],
providers: [
{
Expand Down Expand Up @@ -783,10 +785,15 @@ describe('MessageInputComponent', () => {
expect(avatar.location).toBe('quoted-message-sender');
expect(avatar.user).toBe(message.user!);
expect(attachments.attachments).toEqual([{ id: '1' }]);
expect(
nativeElement.querySelector('[data-testid="quoted-message-text"]')
?.innerHTML
).toContain(message.text);

const textComponent = fixture.debugElement
.query(By.css(quotedMessageContainerSelector))
.query(By.directive(MessageTextComponent))
.componentInstance as MessageTextComponent;

expect(textComponent.message).toBe(message);
expect(textComponent.isQuoted).toBe(true);
expect(textComponent.shouldTranslate).toBe(true);

mockMessageToQuote$.next(undefined);
fixture.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
CustomAttachmentUploadContext,
DefaultStreamChatGenerics,
EmojiPickerContext,
MessageTextContext,
StreamMessage,
} from '../types';
import { MessageInputConfigService } from './message-input-config.service';
Expand Down Expand Up @@ -163,7 +164,7 @@ export class MessageInputComponent
private componentFactoryResolver: ComponentFactoryResolver,
private cdRef: ChangeDetectorRef,
private emojiInputService: EmojiInputService,
private customTemplatesService: CustomTemplatesService,
readonly customTemplatesService: CustomTemplatesService,
private messageActionsService: MessageActionsService,
public readonly voiceRecorderService: VoiceRecorderService,
@Optional() public audioRecorder?: AudioRecorderService
Expand Down Expand Up @@ -494,6 +495,14 @@ export class MessageInputComponent
};
}

getQuotedMessageTextContext(): MessageTextContext {
return {
message: this.quotedMessage,
isQuoted: true,
shouldTranslate: true,
};
}

async startVoiceRecording() {
await this.audioRecorder?.start();
if (this.audioRecorder?.isRecording) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<p
[class.str-chat__quoted-message-text-value]="isQuoted"
[class.str-chat__message-text-value]="!isQuoted"
*ngIf="message?.text"
data-testid="text"
>
<ng-container *ngIf="messageTextParts; else defaultContent">
<!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->
<ng-container *ngFor="let part of messageTextParts">
<span
*ngIf="part.type === 'text'; else mention"
[innerHTML]="part.content"
></span>
<ng-template #mention>
<ng-template #defaultMention let-content="content">
<span class="str-chat__message-mention">{{ content }}</span>
</ng-template>
<ng-container
*ngTemplateOutlet="
(customTemplatesService.mentionTemplate$ | async) || defaultMention;
context: getMentionContext(part)
"
></ng-container>
</ng-template>
</ng-container>
</ng-container>
<ng-template #defaultContent>
<ng-container *ngIf="displayAs === 'text'; else asHTML">
{{ messageText || "" }}
</ng-container>
<ng-template #asHTML
><span data-testid="html-content" [innerHTML]="messageText"></span
></ng-template>
</ng-template>
</p>
Loading

0 comments on commit d2b7eb7

Please sign in to comment.