diff --git a/packages/ng/forms/textarea-input/textarea-input.component.html b/packages/ng/forms/textarea-input/textarea-input.component.html
index bf1d83b363..965af4d71a 100644
--- a/packages/ng/forms/textarea-input/textarea-input.component.html
+++ b/packages/ng/forms/textarea-input/textarea-input.component.html
@@ -1,11 +1,16 @@
-
+
+ @if (autoResize) {
+
+ }
diff --git a/packages/ng/forms/textarea-input/textarea-input.component.ts b/packages/ng/forms/textarea-input/textarea-input.component.ts
index 562061b9b9..7798881996 100644
--- a/packages/ng/forms/textarea-input/textarea-input.component.ts
+++ b/packages/ng/forms/textarea-input/textarea-input.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
+import { booleanAttribute, ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, ViewEncapsulation } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { InputDirective } from '@lucca-front/ng/form-field';
import { injectNgControl } from '../inject-ng-control';
@@ -14,6 +14,9 @@ import { NoopValueAccessorDirective } from '../noop-value-accessor.directive';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TextareaInputComponent {
+ @ViewChild('textarea', { read: ElementRef, static: true })
+ textarea: ElementRef
;
+
ngControl = injectNgControl();
@Input()
@@ -21,4 +24,20 @@ export class TextareaInputComponent {
@Input()
rows?: number;
+
+ @Input({
+ transform: booleanAttribute,
+ })
+ autoResize = false;
+
+ @Input({
+ transform: booleanAttribute,
+ })
+ scrollIntoViewOnAutoResizing = false;
+
+ updateScroll() {
+ if (this.scrollIntoViewOnAutoResizing) {
+ this.textarea.nativeElement.scrollIntoView();
+ }
+ }
}
diff --git a/packages/scss/src/components/textField/component.scss b/packages/scss/src/components/textField/component.scss
index 0b4c284fc1..67ceefcf81 100644
--- a/packages/scss/src/components/textField/component.scss
+++ b/packages/scss/src/components/textField/component.scss
@@ -55,6 +55,7 @@
}
}
+ .textField-input-valueClone,
.textField-input-value {
border: 0;
outline: 0;
diff --git a/packages/scss/src/components/textField/index.scss b/packages/scss/src/components/textField/index.scss
index 3ba2234d8c..3d198b2ec0 100644
--- a/packages/scss/src/components/textField/index.scss
+++ b/packages/scss/src/components/textField/index.scss
@@ -25,4 +25,8 @@
&:has(.textField-input-value:disabled) {
@include disabled;
}
+
+ &.mod-autoResize {
+ @include autoResize;
+ }
}
diff --git a/packages/scss/src/components/textField/mods.scss b/packages/scss/src/components/textField/mods.scss
index eb7ee35165..df507b6f6c 100644
--- a/packages/scss/src/components/textField/mods.scss
+++ b/packages/scss/src/components/textField/mods.scss
@@ -44,3 +44,28 @@
text-align: right;
}
}
+
+@mixin autoResize {
+ .textField-input {
+ display: grid;
+ align-items: normal;
+ min-width: 0;
+ }
+
+ .textField-input-valueClone,
+ .textField-input-value {
+ white-space: pre-wrap;
+ overflow-wrap: break-word;
+ grid-area: 1 / 1 / 2 / 2;
+ resize: none;
+ min-width: 0;
+ }
+
+ .textField-input-valueClone {
+ visibility: hidden;
+
+ &::after {
+ content: ' ';
+ }
+ }
+}
diff --git a/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts b/stories/documentation/forms/fields/textarea/angular/textareafield.stories.ts
similarity index 79%
rename from stories/documentation/forms/fields/textarea/angular/textarea.stories.ts
rename to stories/documentation/forms/fields/textarea/angular/textareafield.stories.ts
index b29f5252fa..6be6d4b882 100644
--- a/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts
+++ b/stories/documentation/forms/fields/textarea/angular/textareafield.stories.ts
@@ -35,15 +35,22 @@ export default {
counter: {
description: '[v17.4]',
},
+ autoResize: {
+ type: 'boolean',
+ },
+ scrollIntoViewOnAutoResizing: {
+ type: 'boolean',
+ if: { arg: 'autoResize', truthy: true },
+ },
hiddenLabel: {
- description: 'Masque le label en le conservant dans le DOM pour les lecteurs d\'écrans',
+ description: "Masque le label en le conservant dans le DOM pour les lecteurs d'écrans",
},
},
} as Meta;
export const Basic: StoryObj = {
render: (args, { argTypes }) => {
- const { label, hiddenLabel, tooltip, inlineMessage, inlineMessageState, size, counter, ...inputArgs } = args;
+ const { label, hiddenLabel, tooltip, inlineMessage, inlineMessageState, size, counter, autoResize, scrollIntoViewOnAutoResizing, ...inputArgs } = args;
return {
template: cleanupTemplate(`
-
-
-
-
-{{example}}`),
+`),
moduleMetadata: {
imports: [TextareaInputComponent, FormFieldComponent, FormsModule, BrowserAnimationsModule],
},
@@ -81,6 +85,8 @@ export const Basic: StoryObj ' : '';
+ let input = '';
+ if (args.autoResize) {
+ if (args.scrollIntoViewOnAutoResizing) {
+ input = 'onInput="this.previousElementSibling.dataset.contentBefore = this.value; this.scrollIntoViewOnAutoResizing"';
+ } else {
+ input = 'onInput="this.previousElementSibling.dataset.contentBefore = this.value"';
+ }
+ }
+
return `