Skip to content

Commit d1d59f5

Browse files
refactor(chat-messages): use CdkTextareaAutosize for chat input
Replace the hand-rolled textarea auto-resize logic in SiChatInputComponent with Angular CDK's CdkTextareaAutosize directive (cdkAutosizeMinRows="1", cdkAutosizeMaxRows="8"). The 30vh viewport cap is preserved via CSS (max-block-size + overflow-y: auto) instead of JS. Removes setTextareaHeight/adjustTextareaHeight and the (input) handler; behavior (min 1 row, max 8 rows, capped at 30% viewport) is unchanged.
1 parent 364fe8e commit d1d59f5

3 files changed

Lines changed: 12 additions & 35 deletions

File tree

projects/element-ng/chat-messages/si-chat-input.component.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<label class="form-label d-none" [for]="id">{{ label() | translate }}</label>
2020
<textarea
2121
#textInput
22+
cdkTextareaAutosize
23+
cdkAutosizeMinRows="1"
24+
cdkAutosizeMaxRows="8"
2225
class="chat-textarea w-100 border-0"
2326
rows="1"
2427
[id]="id"
@@ -27,7 +30,6 @@
2730
[maxlength]="maxLength() || null"
2831
[(ngModel)]="value"
2932
(keydown)="onKeyDown($event)"
30-
(input)="adjustTextareaHeight($event)"
3133
></textarea>
3234
</div>
3335

projects/element-ng/chat-messages/si-chat-input.component.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
.chat-textarea {
3030
// Prevent layout shift on first input
3131
min-block-size: 1lh;
32+
max-block-size: 30vh;
3233
font-family: inherit;
3334
padding-block: 0;
3435
display: block;
3536
outline: none;
3637
resize: none;
38+
overflow-y: auto;
3739
background-color: transparent;
3840

3941
&::placeholder {

projects/element-ng/chat-messages/si-chat-input.component.ts

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* SPDX-License-Identifier: MIT
44
*/
55
import { CdkMenuTrigger } from '@angular/cdk/menu';
6+
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
67
import {
78
AfterViewInit,
89
booleanAttribute,
@@ -80,6 +81,7 @@ export interface ChatInputAttachment extends Attachment {
8081
selector: 'si-chat-input',
8182
imports: [
8283
CdkMenuTrigger,
84+
CdkTextareaAutosize,
8385
FormsModule,
8486
SiIconComponent,
8587
SiTranslatePipe,
@@ -436,23 +438,14 @@ export class SiChatInputComponent implements AfterViewInit {
436438

437439
ngAfterViewInit(): void {
438440
const textarea = this.textInput();
439-
if (textarea?.nativeElement) {
440-
this.setTextareaHeight(textarea.nativeElement);
441-
442-
if (this.autoFocus()) {
443-
// Use setTimeout to ensure the element is fully rendered
444-
setTimeout(() => {
445-
textarea.nativeElement.focus();
446-
}, 0);
447-
}
441+
if (textarea?.nativeElement && this.autoFocus()) {
442+
// Use setTimeout to ensure the element is fully rendered
443+
setTimeout(() => {
444+
textarea.nativeElement.focus();
445+
}, 0);
448446
}
449447
}
450448

451-
protected adjustTextareaHeight(event: Event): void {
452-
const textarea = event.target as HTMLTextAreaElement;
453-
this.setTextareaHeight(textarea);
454-
}
455-
456449
/**
457450
* Focus the textarea input
458451
*/
@@ -487,24 +480,4 @@ export class SiChatInputComponent implements AfterViewInit {
487480
event.stopPropagation();
488481
this.dragOver = true;
489482
}
490-
491-
private setTextareaHeight(textarea: HTMLTextAreaElement): void {
492-
textarea.style.blockSize = 'auto';
493-
494-
const computedStyle = window.getComputedStyle(textarea);
495-
const lineHeight =
496-
parseInt(computedStyle.lineHeight, 10) || parseInt(computedStyle.fontSize, 10) * 1.2;
497-
const paddingTop = parseInt(computedStyle.paddingBlockStart, 10) || 0;
498-
const paddingBottom = parseInt(computedStyle.paddingBlockEnd, 10) || 0;
499-
const minHeight = lineHeight + paddingTop + paddingBottom;
500-
501-
const viewportHeight = window.innerHeight;
502-
const maxViewportHeight = viewportHeight * 0.3;
503-
const maxLinesHeight = lineHeight * 8;
504-
const maxHeight = Math.min(maxViewportHeight, maxLinesHeight) + paddingTop + paddingBottom;
505-
506-
const scrollHeight = textarea.scrollHeight;
507-
const finalHeight = Math.max(Math.min(scrollHeight, maxHeight), minHeight);
508-
textarea.style.height = finalHeight + 'px';
509-
}
510483
}

0 commit comments

Comments
 (0)