@lifecorner/angular-ui-kit 3.9.0 → 3.10.0
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.
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ChangeDetectionStrategy, Component, afterRenderEffect, computed, forwardRef, input,
|
|
2
|
+
import { ChangeDetectionStrategy, Component, PLATFORM_ID, afterRenderEffect, computed, forwardRef, inject, input, model, signal, viewChild } from "@angular/core";
|
|
3
|
+
import { isPlatformServer } from "@angular/common";
|
|
3
4
|
import { NG_VALUE_ACCESSOR } from "@angular/forms";
|
|
4
5
|
let nextUniqueId = 0;
|
|
5
6
|
var TextareaComponent = class TextareaComponent {
|
|
6
7
|
textareaElement = viewChild("textarea", ...ngDevMode ? [{ debugName: "textareaElement" }] : /* istanbul ignore next */ []);
|
|
8
|
+
isServer = isPlatformServer(inject(PLATFORM_ID));
|
|
7
9
|
variant = input("outline", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
8
10
|
size = input("md", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
|
|
9
11
|
disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
|
|
10
12
|
error = input(false, ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
|
|
11
13
|
required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
|
|
14
|
+
requiredIndicator = input(true, ...ngDevMode ? [{ debugName: "requiredIndicator" }] : /* istanbul ignore next */ []);
|
|
15
|
+
requiredAriaLabel = input("required", ...ngDevMode ? [{ debugName: "requiredAriaLabel" }] : /* istanbul ignore next */ []);
|
|
12
16
|
readonly = input(false, ...ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []);
|
|
13
17
|
placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
|
|
14
18
|
label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
15
19
|
helperText = input("", ...ngDevMode ? [{ debugName: "helperText" }] : /* istanbul ignore next */ []);
|
|
16
20
|
errorMessage = input("", ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
17
21
|
ariaLabel = input(void 0, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
22
|
+
name = input(...ngDevMode ? [void 0, { debugName: "name" }] : /* istanbul ignore next */ []);
|
|
18
23
|
rows = input(3, ...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
|
|
19
24
|
maxLength = input(void 0, ...ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []);
|
|
20
25
|
showCharacterCount = input(false, ...ngDevMode ? [{ debugName: "showCharacterCount" }] : /* istanbul ignore next */ []);
|
|
21
26
|
autoResize = input(false, ...ngDevMode ? [{ debugName: "autoResize" }] : /* istanbul ignore next */ []);
|
|
22
27
|
minRows = input(3, ...ngDevMode ? [{ debugName: "minRows" }] : /* istanbul ignore next */ []);
|
|
23
28
|
maxRows = input(void 0, ...ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []);
|
|
24
|
-
|
|
29
|
+
value = model("", ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
|
|
30
|
+
valueChange = this.value;
|
|
25
31
|
textareaId = `lc-textarea-${nextUniqueId++}`;
|
|
26
32
|
errorId = `${this.textareaId}-error`;
|
|
27
33
|
helperId = `${this.textareaId}-helper`;
|
|
28
|
-
|
|
34
|
+
renderedValue = computed(() => {
|
|
35
|
+
const value = this.value();
|
|
36
|
+
return this.isServer && /^[\r\n]/.test(value) ? `\n${value}` : value;
|
|
37
|
+
}, ...ngDevMode ? [{ debugName: "renderedValue" }] : /* istanbul ignore next */ []);
|
|
29
38
|
formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
|
|
30
39
|
isDisabled = computed(() => this.disabled() || this.formDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
|
|
31
40
|
currentCharacterCount = computed(() => this.value().length, ...ngDevMode ? [{ debugName: "currentCharacterCount" }] : /* istanbul ignore next */ []);
|
|
@@ -72,7 +81,6 @@ var TextareaComponent = class TextareaComponent {
|
|
|
72
81
|
if (this.isDisabled() || this.readonly()) return;
|
|
73
82
|
this.value.set(value);
|
|
74
83
|
this.onChange(value);
|
|
75
|
-
this.valueChange.emit(value);
|
|
76
84
|
}
|
|
77
85
|
onBlur() {
|
|
78
86
|
this.onTouched();
|
|
@@ -162,6 +170,20 @@ var TextareaComponent = class TextareaComponent {
|
|
|
162
170
|
isRequired: false,
|
|
163
171
|
transformFunction: null
|
|
164
172
|
},
|
|
173
|
+
requiredIndicator: {
|
|
174
|
+
classPropertyName: "requiredIndicator",
|
|
175
|
+
publicName: "requiredIndicator",
|
|
176
|
+
isSignal: true,
|
|
177
|
+
isRequired: false,
|
|
178
|
+
transformFunction: null
|
|
179
|
+
},
|
|
180
|
+
requiredAriaLabel: {
|
|
181
|
+
classPropertyName: "requiredAriaLabel",
|
|
182
|
+
publicName: "requiredAriaLabel",
|
|
183
|
+
isSignal: true,
|
|
184
|
+
isRequired: false,
|
|
185
|
+
transformFunction: null
|
|
186
|
+
},
|
|
165
187
|
readonly: {
|
|
166
188
|
classPropertyName: "readonly",
|
|
167
189
|
publicName: "readonly",
|
|
@@ -204,6 +226,13 @@ var TextareaComponent = class TextareaComponent {
|
|
|
204
226
|
isRequired: false,
|
|
205
227
|
transformFunction: null
|
|
206
228
|
},
|
|
229
|
+
name: {
|
|
230
|
+
classPropertyName: "name",
|
|
231
|
+
publicName: "name",
|
|
232
|
+
isSignal: true,
|
|
233
|
+
isRequired: false,
|
|
234
|
+
transformFunction: null
|
|
235
|
+
},
|
|
207
236
|
rows: {
|
|
208
237
|
classPropertyName: "rows",
|
|
209
238
|
publicName: "rows",
|
|
@@ -245,9 +274,16 @@ var TextareaComponent = class TextareaComponent {
|
|
|
245
274
|
isSignal: true,
|
|
246
275
|
isRequired: false,
|
|
247
276
|
transformFunction: null
|
|
277
|
+
},
|
|
278
|
+
value: {
|
|
279
|
+
classPropertyName: "value",
|
|
280
|
+
publicName: "value",
|
|
281
|
+
isSignal: true,
|
|
282
|
+
isRequired: false,
|
|
283
|
+
transformFunction: null
|
|
248
284
|
}
|
|
249
285
|
},
|
|
250
|
-
outputs: {
|
|
286
|
+
outputs: { value: "valueChange" },
|
|
251
287
|
providers: [{
|
|
252
288
|
provide: NG_VALUE_ACCESSOR,
|
|
253
289
|
useExisting: forwardRef(() => TextareaComponent),
|
|
@@ -261,7 +297,7 @@ var TextareaComponent = class TextareaComponent {
|
|
|
261
297
|
isSignal: true
|
|
262
298
|
}],
|
|
263
299
|
ngImport: i0,
|
|
264
|
-
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"
|
|
300
|
+
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required() && requiredIndicator()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" role=\"alert\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n",
|
|
265
301
|
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only){border-color:var(--color-primary-400)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:transparent}.lc-textarea--filled:hover:not(:disabled):not(:read-only){background-color:var(--color-surface-hover)}.lc-textarea--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--disabled{cursor:not-allowed;opacity:.6;background-color:var(--color-surface-muted);color:var(--color-text-tertiary)}.lc-textarea--readonly{cursor:default;background-color:var(--color-surface-muted)}.lc-textarea--error{border-color:var(--color-error-600)}.lc-textarea--error:focus{border-color:var(--color-error-600);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-error-600) 20%,transparent)}.lc-textarea--auto-resize{resize:none;overflow:hidden}.lc-textarea-helper-text{font-size:var(--font-size-xs);color:var(--color-text-secondary)}.lc-textarea-error-message{font-size:var(--font-size-xs);color:var(--color-text-error)}.lc-textarea-char-count,.lc-textarea-character-count{font-size:var(--font-size-xs);color:var(--color-text-tertiary);text-align:right}.lc-textarea-char-count--warning,.lc-textarea-character-count--warning{color:var(--color-warning-600)}.lc-textarea-char-count--error,.lc-textarea-char-count--over-limit,.lc-textarea-character-count--error,.lc-textarea-character-count--over-limit{color:var(--color-text-error)}.lc-textarea-footer{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-textarea-messages{flex:1}.lc-textarea-input-wrapper{position:relative;width:100%}.lc-textarea-required-indicator{color:var(--color-text-error)}\n"],
|
|
266
302
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
267
303
|
});
|
|
@@ -283,7 +319,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
283
319
|
useExisting: forwardRef(() => TextareaComponent),
|
|
284
320
|
multi: true
|
|
285
321
|
}],
|
|
286
|
-
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"
|
|
322
|
+
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required() && requiredIndicator()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" role=\"alert\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n",
|
|
287
323
|
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only){border-color:var(--color-primary-400)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:transparent}.lc-textarea--filled:hover:not(:disabled):not(:read-only){background-color:var(--color-surface-hover)}.lc-textarea--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--disabled{cursor:not-allowed;opacity:.6;background-color:var(--color-surface-muted);color:var(--color-text-tertiary)}.lc-textarea--readonly{cursor:default;background-color:var(--color-surface-muted)}.lc-textarea--error{border-color:var(--color-error-600)}.lc-textarea--error:focus{border-color:var(--color-error-600);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-error-600) 20%,transparent)}.lc-textarea--auto-resize{resize:none;overflow:hidden}.lc-textarea-helper-text{font-size:var(--font-size-xs);color:var(--color-text-secondary)}.lc-textarea-error-message{font-size:var(--font-size-xs);color:var(--color-text-error)}.lc-textarea-char-count,.lc-textarea-character-count{font-size:var(--font-size-xs);color:var(--color-text-tertiary);text-align:right}.lc-textarea-char-count--warning,.lc-textarea-character-count--warning{color:var(--color-warning-600)}.lc-textarea-char-count--error,.lc-textarea-char-count--over-limit,.lc-textarea-character-count--error,.lc-textarea-character-count--over-limit{color:var(--color-text-error)}.lc-textarea-footer{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-textarea-messages{flex:1}.lc-textarea-input-wrapper{position:relative;width:100%}.lc-textarea-required-indicator{color:var(--color-text-error)}\n"]
|
|
288
324
|
}]
|
|
289
325
|
}],
|
|
@@ -333,6 +369,22 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
333
369
|
required: false
|
|
334
370
|
}]
|
|
335
371
|
}],
|
|
372
|
+
requiredIndicator: [{
|
|
373
|
+
type: i0.Input,
|
|
374
|
+
args: [{
|
|
375
|
+
isSignal: true,
|
|
376
|
+
alias: "requiredIndicator",
|
|
377
|
+
required: false
|
|
378
|
+
}]
|
|
379
|
+
}],
|
|
380
|
+
requiredAriaLabel: [{
|
|
381
|
+
type: i0.Input,
|
|
382
|
+
args: [{
|
|
383
|
+
isSignal: true,
|
|
384
|
+
alias: "requiredAriaLabel",
|
|
385
|
+
required: false
|
|
386
|
+
}]
|
|
387
|
+
}],
|
|
336
388
|
readonly: [{
|
|
337
389
|
type: i0.Input,
|
|
338
390
|
args: [{
|
|
@@ -381,6 +433,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
381
433
|
required: false
|
|
382
434
|
}]
|
|
383
435
|
}],
|
|
436
|
+
name: [{
|
|
437
|
+
type: i0.Input,
|
|
438
|
+
args: [{
|
|
439
|
+
isSignal: true,
|
|
440
|
+
alias: "name",
|
|
441
|
+
required: false
|
|
442
|
+
}]
|
|
443
|
+
}],
|
|
384
444
|
rows: [{
|
|
385
445
|
type: i0.Input,
|
|
386
446
|
args: [{
|
|
@@ -429,7 +489,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
429
489
|
required: false
|
|
430
490
|
}]
|
|
431
491
|
}],
|
|
432
|
-
|
|
492
|
+
value: [{
|
|
493
|
+
type: i0.Input,
|
|
494
|
+
args: [{
|
|
495
|
+
isSignal: true,
|
|
496
|
+
alias: "value",
|
|
497
|
+
required: false
|
|
498
|
+
}]
|
|
499
|
+
}, {
|
|
433
500
|
type: i0.Output,
|
|
434
501
|
args: ["valueChange"]
|
|
435
502
|
}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-textarea.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.ts","../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ElementRef,\n afterRenderEffect,\n computed,\n forwardRef,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nlet nextUniqueId = 0;\n\n/**\n * Textarea component for multi-line text input.\n *\n * Features:\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Auto-resize with configurable min/max rows\n * - Character count display with maxLength\n * - Validation error message and helper text\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n *\n * @example\n * ```html\n * <lc-textarea placeholder=\"Enter message\" [autoResize]=\"true\" [(ngModel)]=\"message\" />\n * ```\n */\n@Component({\n selector: 'lc-textarea',\n standalone: true,\n imports: [],\n templateUrl: './textarea.component.html',\n styleUrl: './textarea.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TextareaComponent),\n multi: true,\n },\n ],\n})\nexport class TextareaComponent implements ControlValueAccessor {\n private readonly textareaElement = viewChild<ElementRef<HTMLTextAreaElement>>('textarea');\n\n /**\n * Visual variant of the textarea\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the textarea\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the textarea is disabled\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the textarea is in error state\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the textarea is required\n */\n readonly required = input<boolean>(false);\n\n /**\n * Whether the textarea is readonly\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n */\n readonly placeholder = input<string>('');\n\n /**\n * Label text displayed above the textarea\n */\n readonly label = input<string>('');\n\n /**\n * Helper text displayed below the textarea\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Number of visible text rows\n */\n readonly rows = input<number>(3);\n\n /**\n * Maximum number of characters allowed\n */\n readonly maxLength = input<number | undefined>(undefined);\n\n /**\n * Whether to show character count\n */\n readonly showCharacterCount = input<boolean>(false);\n\n /**\n * Whether to automatically resize based on content\n */\n readonly autoResize = input<boolean>(false);\n\n /**\n * Minimum number of rows for auto-resize\n */\n readonly minRows = input<number>(3);\n\n /**\n * Maximum number of rows for auto-resize\n */\n readonly maxRows = input<number | undefined>(undefined);\n\n /**\n * Emitted when value changes\n */\n readonly valueChange = output<string>();\n\n /** Per-instance id: links label, error and helper text to the control. */\n readonly textareaId = `lc-textarea-${nextUniqueId++}`;\n readonly errorId = `${this.textareaId}-error`;\n readonly helperId = `${this.textareaId}-helper`;\n\n // Internal state\n readonly value = signal<string>('');\n\n // Internal disabled state (for ControlValueAccessor)\n private readonly formDisabled = signal<boolean>(false);\n\n /**\n * Computed disabled state from both input and form control\n */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly currentCharacterCount = computed(() => this.value().length);\n\n readonly characterCountText = computed(() => {\n const current = this.currentCharacterCount();\n const max = this.maxLength();\n return max !== undefined ? `${current} / ${max}` : `${current}`;\n });\n\n readonly isOverLimit = computed(() => {\n const max = this.maxLength();\n return max !== undefined && this.currentCharacterCount() > max;\n });\n\n /** Whether an error message is shown (drives aria-describedby) */\n readonly showsError = computed(() => this.error() && !!this.errorMessage());\n\n /** Whether the helper text is shown (error message takes precedence) */\n readonly showsHelper = computed(() => !this.showsError() && !!this.helperText());\n\n readonly describedBy = computed(() => {\n const ids: string[] = [];\n if (this.showsError()) ids.push(this.errorId);\n if (this.showsHelper()) ids.push(this.helperId);\n return ids.length ? ids.join(' ') : null;\n });\n\n /**\n * Computed classes for the textarea element\n */\n readonly textareaClasses = computed(() => {\n const classes = ['lc-textarea', `lc-textarea--${this.variant()}`, `lc-textarea--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-textarea--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-textarea--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-textarea--readonly');\n }\n\n if (this.autoResize()) {\n classes.push('lc-textarea--auto-resize');\n }\n\n return classes.join(' ');\n });\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: string) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n constructor() {\n // Re-measure after every render in which the value or the resize\n // constraints changed — this covers typing, form writes and input changes\n // without timers, and runs once the DOM already holds the new value.\n afterRenderEffect(() => {\n this.value();\n this.minRows();\n this.maxRows();\n if (this.autoResize()) {\n this.adjustHeight();\n }\n });\n }\n\n /**\n * Handle input changes\n */\n onInput(value: string): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n this.value.set(value);\n this.onChange(value);\n this.valueChange.emit(value);\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: string | null | undefined): void {\n this.value.set(value || '');\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private adjustHeight(): void {\n const textarea = this.textareaElement()?.nativeElement;\n if (!textarea) {\n return;\n }\n\n // Reset height to get accurate scrollHeight\n textarea.style.height = 'auto';\n\n const minHeight = this.rowsToHeight(textarea, this.minRows());\n const maxHeight = this.rowsToHeight(textarea, this.maxRows());\n let newHeight = textarea.scrollHeight;\n\n // Apply constraints\n if (minHeight !== undefined) {\n newHeight = Math.max(newHeight, minHeight);\n }\n if (maxHeight !== undefined) {\n newHeight = Math.min(newHeight, maxHeight);\n }\n\n textarea.style.height = `${newHeight}px`;\n }\n\n /** Pixel height for `rows` lines incl. vertical padding; undefined when it cannot be measured. */\n private rowsToHeight(textarea: HTMLTextAreaElement, rows: number | undefined): number | undefined {\n if (rows === undefined) {\n return undefined;\n }\n\n const style = getComputedStyle(textarea);\n const lineHeight = parseFloat(style.lineHeight);\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n\n // 'normal' / unmeasurable line-height (e.g. jsdom) → no constraint\n if (!Number.isFinite(lineHeight)) {\n return undefined;\n }\n\n return lineHeight * rows + paddingTop + paddingBottom;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLTextAreaElement).value;\n }\n}\n","<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"value()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" role=\"alert\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-textarea.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.ts","../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ElementRef,\n OutputRef,\n PLATFORM_ID,\n afterRenderEffect,\n computed,\n forwardRef,\n inject,\n input,\n model,\n signal,\n viewChild,\n} from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nlet nextUniqueId = 0;\n\n/**\n * Textarea component for multi-line text input.\n *\n * Features:\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Auto-resize with configurable min/max rows\n * - Character count display with maxLength\n * - Validation error message and helper text\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n * - Plain form posts without JavaScript: `name`, and a `value` that is\n * prerendered into the native `<textarea>`\n *\n * @example\n * ```html\n * <lc-textarea placeholder=\"Enter message\" [autoResize]=\"true\" [(ngModel)]=\"message\" />\n * <lc-textarea label=\"Message\" name=\"message\" [required]=\"true\" [value]=\"draft\" />\n * ```\n */\n@Component({\n selector: 'lc-textarea',\n standalone: true,\n imports: [],\n templateUrl: './textarea.component.html',\n styleUrl: './textarea.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TextareaComponent),\n multi: true,\n },\n ],\n})\nexport class TextareaComponent implements ControlValueAccessor {\n private readonly textareaElement = viewChild<ElementRef<HTMLTextAreaElement>>('textarea');\n\n private readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n /**\n * Visual variant of the textarea\n * @default 'outline'\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the textarea\n * @default 'md'\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the textarea is disabled\n * @default false\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the textarea is in error state\n * @default false\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the textarea is required\n * @default false\n */\n readonly required = input<boolean>(false);\n\n /**\n * Show the `*` after the label of a `required` field. `false` keeps the\n * required semantics (`required`, `aria-required`) without the asterisk —\n * for forms where every field is required.\n * @default true\n */\n readonly requiredIndicator = input<boolean>(true);\n\n /**\n * Accessible name of the `*` marker, for API parity with `lc-input`.\n * `lc-textarea` hides the `*` from assistive technology, because the native\n * `required` state is announced already and naming the `*` would say\n * \"required\" twice.\n * @default 'required'\n */\n readonly requiredAriaLabel = input<string>('required');\n\n /**\n * Whether the textarea is readonly\n * @default false\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n * @default ''\n */\n readonly placeholder = input<string>('');\n\n /**\n * Label text displayed above the textarea\n * @default ''\n */\n readonly label = input<string>('');\n\n /**\n * Helper text displayed below the textarea\n * @default ''\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n * @default ''\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n * @default undefined\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Native `name` of the inner `<textarea>`, so a form posts the text without\n * JavaScript. Unset = no attribute. A `disabled` textarea is not posted\n * (HTML); use `readonly` to post a fixed text.\n * @default undefined\n */\n readonly name = input<string>();\n\n /**\n * Number of visible text rows\n * @default 3\n */\n readonly rows = input<number>(3);\n\n /**\n * Maximum number of characters allowed\n * @default undefined\n */\n readonly maxLength = input<number | undefined>(undefined);\n\n /**\n * Whether to show character count\n * @default false\n */\n readonly showCharacterCount = input<boolean>(false);\n\n /**\n * Whether to automatically resize based on content\n * @default false\n */\n readonly autoResize = input<boolean>(false);\n\n /**\n * Minimum number of rows for auto-resize\n * @default 3\n */\n readonly minRows = input<number>(3);\n\n /**\n * Maximum number of rows for auto-resize\n * @default undefined\n */\n readonly maxRows = input<number | undefined>(undefined);\n\n /**\n * Current text, two-way bindable (`[value]` / `[(value)]`). It pre-fills the\n * native textarea, in prerendered HTML too, so a server-rendered page can\n * keep a visitor's text. Emits `valueChange` whenever it changes: once per\n * keystroke that changes the text, and when a bound form control or code\n * sets a different text. With a form control, the control's value wins;\n * don't bind both.\n * @default ''\n */\n readonly value = model<string>('');\n\n /**\n * The model's change output as a class property, so code that subscribes to\n * it (`textarea.valueChange.subscribe(…)`, `outputToObservable(…)`) keeps\n * compiling as in 3.9. Template bindings `(valueChange)` use the model.\n */\n readonly valueChange: OutputRef<string> = this.value;\n\n /** Per-instance id: links label, error and helper text to the control. */\n readonly textareaId = `lc-textarea-${nextUniqueId++}`;\n readonly errorId = `${this.textareaId}-error`;\n readonly helperId = `${this.textareaId}-helper`;\n\n /**\n * The native textarea's value. On the server a leading line break gets one\n * extra `\\n`: the HTML parser drops the first line break after `<textarea>`,\n * and the server's DOM serialiser doesn't add the one the HTML\n * serialisation rules require, so the prerendered page would lose it.\n */\n protected readonly renderedValue = computed(() => {\n const value = this.value();\n return this.isServer && /^[\\r\\n]/.test(value) ? `\\n${value}` : value;\n });\n\n // Internal disabled state (for ControlValueAccessor)\n private readonly formDisabled = signal<boolean>(false);\n\n /**\n * Computed disabled state from both input and form control\n */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly currentCharacterCount = computed(() => this.value().length);\n\n readonly characterCountText = computed(() => {\n const current = this.currentCharacterCount();\n const max = this.maxLength();\n return max !== undefined ? `${current} / ${max}` : `${current}`;\n });\n\n readonly isOverLimit = computed(() => {\n const max = this.maxLength();\n return max !== undefined && this.currentCharacterCount() > max;\n });\n\n /** Whether an error message is shown (drives aria-describedby) */\n readonly showsError = computed(() => this.error() && !!this.errorMessage());\n\n /** Whether the helper text is shown (error message takes precedence) */\n readonly showsHelper = computed(() => !this.showsError() && !!this.helperText());\n\n readonly describedBy = computed(() => {\n const ids: string[] = [];\n if (this.showsError()) ids.push(this.errorId);\n if (this.showsHelper()) ids.push(this.helperId);\n return ids.length ? ids.join(' ') : null;\n });\n\n /**\n * Computed classes for the textarea element\n */\n readonly textareaClasses = computed(() => {\n const classes = ['lc-textarea', `lc-textarea--${this.variant()}`, `lc-textarea--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-textarea--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-textarea--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-textarea--readonly');\n }\n\n if (this.autoResize()) {\n classes.push('lc-textarea--auto-resize');\n }\n\n return classes.join(' ');\n });\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: string) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n constructor() {\n // Re-measure after every render in which the value or the resize\n // constraints changed — this covers typing, form writes and input changes\n // without timers, and runs once the DOM already holds the new value.\n afterRenderEffect(() => {\n this.value();\n this.minRows();\n this.maxRows();\n if (this.autoResize()) {\n this.adjustHeight();\n }\n });\n }\n\n /**\n * Handle input changes\n */\n onInput(value: string): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n // model.set() emits `valueChange` exactly once per actual change\n this.value.set(value);\n this.onChange(value);\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: string | null | undefined): void {\n this.value.set(value || '');\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private adjustHeight(): void {\n const textarea = this.textareaElement()?.nativeElement;\n if (!textarea) {\n return;\n }\n\n // Reset height to get accurate scrollHeight\n textarea.style.height = 'auto';\n\n const minHeight = this.rowsToHeight(textarea, this.minRows());\n const maxHeight = this.rowsToHeight(textarea, this.maxRows());\n let newHeight = textarea.scrollHeight;\n\n // Apply constraints\n if (minHeight !== undefined) {\n newHeight = Math.max(newHeight, minHeight);\n }\n if (maxHeight !== undefined) {\n newHeight = Math.min(newHeight, maxHeight);\n }\n\n textarea.style.height = `${newHeight}px`;\n }\n\n /** Pixel height for `rows` lines incl. vertical padding; undefined when it cannot be measured. */\n private rowsToHeight(textarea: HTMLTextAreaElement, rows: number | undefined): number | undefined {\n if (rows === undefined) {\n return undefined;\n }\n\n const style = getComputedStyle(textarea);\n const lineHeight = parseFloat(style.lineHeight);\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n\n // 'normal' / unmeasurable line-height (e.g. jsdom) → no constraint\n if (!Number.isFinite(lineHeight)) {\n return undefined;\n }\n\n return lineHeight * rows + paddingTop + paddingBottom;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLTextAreaElement).value;\n }\n}\n","<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}\n @if (required() && requiredIndicator()) {\n <span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" role=\"alert\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ControlValueAccessor } from "@angular/forms";
|
|
2
1
|
import * as i0 from "@angular/core";
|
|
2
|
+
import { OutputRef } from "@angular/core";
|
|
3
|
+
import { ControlValueAccessor } from "@angular/forms";
|
|
3
4
|
/**
|
|
4
5
|
* Textarea component for multi-line text input.
|
|
5
6
|
*
|
|
@@ -11,91 +12,152 @@ import * as i0 from "@angular/core";
|
|
|
11
12
|
* - Validation error message and helper text
|
|
12
13
|
* - Disabled and readonly states
|
|
13
14
|
* - ControlValueAccessor integration for reactive forms
|
|
15
|
+
* - Plain form posts without JavaScript: `name`, and a `value` that is
|
|
16
|
+
* prerendered into the native `<textarea>`
|
|
14
17
|
*
|
|
15
18
|
* @example
|
|
16
19
|
* ```html
|
|
17
20
|
* <lc-textarea placeholder="Enter message" [autoResize]="true" [(ngModel)]="message" />
|
|
21
|
+
* <lc-textarea label="Message" name="message" [required]="true" [value]="draft" />
|
|
18
22
|
* ```
|
|
19
23
|
*/
|
|
20
24
|
export declare class TextareaComponent implements ControlValueAccessor {
|
|
21
25
|
private readonly textareaElement;
|
|
26
|
+
private readonly isServer;
|
|
22
27
|
/**
|
|
23
28
|
* Visual variant of the textarea
|
|
29
|
+
* @default 'outline'
|
|
24
30
|
*/
|
|
25
31
|
readonly variant: import("@angular/core").InputSignal<"outline" | "filled">;
|
|
26
32
|
/**
|
|
27
33
|
* Size of the textarea
|
|
34
|
+
* @default 'md'
|
|
28
35
|
*/
|
|
29
36
|
readonly size: import("@angular/core").InputSignal<"xs" | "sm" | "md" | "lg">;
|
|
30
37
|
/**
|
|
31
38
|
* Whether the textarea is disabled
|
|
39
|
+
* @default false
|
|
32
40
|
*/
|
|
33
41
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
34
42
|
/**
|
|
35
43
|
* Whether the textarea is in error state
|
|
44
|
+
* @default false
|
|
36
45
|
*/
|
|
37
46
|
readonly error: import("@angular/core").InputSignal<boolean>;
|
|
38
47
|
/**
|
|
39
48
|
* Whether the textarea is required
|
|
49
|
+
* @default false
|
|
40
50
|
*/
|
|
41
51
|
readonly required: import("@angular/core").InputSignal<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Show the `*` after the label of a `required` field. `false` keeps the
|
|
54
|
+
* required semantics (`required`, `aria-required`) without the asterisk —
|
|
55
|
+
* for forms where every field is required.
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
58
|
+
readonly requiredIndicator: import("@angular/core").InputSignal<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Accessible name of the `*` marker, for API parity with `lc-input`.
|
|
61
|
+
* `lc-textarea` hides the `*` from assistive technology, because the native
|
|
62
|
+
* `required` state is announced already and naming the `*` would say
|
|
63
|
+
* "required" twice.
|
|
64
|
+
* @default 'required'
|
|
65
|
+
*/
|
|
66
|
+
readonly requiredAriaLabel: import("@angular/core").InputSignal<string>;
|
|
42
67
|
/**
|
|
43
68
|
* Whether the textarea is readonly
|
|
69
|
+
* @default false
|
|
44
70
|
*/
|
|
45
71
|
readonly readonly: import("@angular/core").InputSignal<boolean>;
|
|
46
72
|
/**
|
|
47
73
|
* Placeholder text
|
|
74
|
+
* @default ''
|
|
48
75
|
*/
|
|
49
76
|
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
50
77
|
/**
|
|
51
78
|
* Label text displayed above the textarea
|
|
79
|
+
* @default ''
|
|
52
80
|
*/
|
|
53
81
|
readonly label: import("@angular/core").InputSignal<string>;
|
|
54
82
|
/**
|
|
55
83
|
* Helper text displayed below the textarea
|
|
84
|
+
* @default ''
|
|
56
85
|
*/
|
|
57
86
|
readonly helperText: import("@angular/core").InputSignal<string>;
|
|
58
87
|
/**
|
|
59
88
|
* Error message displayed when error is true
|
|
89
|
+
* @default ''
|
|
60
90
|
*/
|
|
61
91
|
readonly errorMessage: import("@angular/core").InputSignal<string>;
|
|
62
92
|
/**
|
|
63
93
|
* ARIA label for accessibility
|
|
94
|
+
* @default undefined
|
|
64
95
|
*/
|
|
65
96
|
readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
|
|
97
|
+
/**
|
|
98
|
+
* Native `name` of the inner `<textarea>`, so a form posts the text without
|
|
99
|
+
* JavaScript. Unset = no attribute. A `disabled` textarea is not posted
|
|
100
|
+
* (HTML); use `readonly` to post a fixed text.
|
|
101
|
+
* @default undefined
|
|
102
|
+
*/
|
|
103
|
+
readonly name: import("@angular/core").InputSignal<string | undefined>;
|
|
66
104
|
/**
|
|
67
105
|
* Number of visible text rows
|
|
106
|
+
* @default 3
|
|
68
107
|
*/
|
|
69
108
|
readonly rows: import("@angular/core").InputSignal<number>;
|
|
70
109
|
/**
|
|
71
110
|
* Maximum number of characters allowed
|
|
111
|
+
* @default undefined
|
|
72
112
|
*/
|
|
73
113
|
readonly maxLength: import("@angular/core").InputSignal<number | undefined>;
|
|
74
114
|
/**
|
|
75
115
|
* Whether to show character count
|
|
116
|
+
* @default false
|
|
76
117
|
*/
|
|
77
118
|
readonly showCharacterCount: import("@angular/core").InputSignal<boolean>;
|
|
78
119
|
/**
|
|
79
120
|
* Whether to automatically resize based on content
|
|
121
|
+
* @default false
|
|
80
122
|
*/
|
|
81
123
|
readonly autoResize: import("@angular/core").InputSignal<boolean>;
|
|
82
124
|
/**
|
|
83
125
|
* Minimum number of rows for auto-resize
|
|
126
|
+
* @default 3
|
|
84
127
|
*/
|
|
85
128
|
readonly minRows: import("@angular/core").InputSignal<number>;
|
|
86
129
|
/**
|
|
87
130
|
* Maximum number of rows for auto-resize
|
|
131
|
+
* @default undefined
|
|
88
132
|
*/
|
|
89
133
|
readonly maxRows: import("@angular/core").InputSignal<number | undefined>;
|
|
90
134
|
/**
|
|
91
|
-
*
|
|
135
|
+
* Current text, two-way bindable (`[value]` / `[(value)]`). It pre-fills the
|
|
136
|
+
* native textarea, in prerendered HTML too, so a server-rendered page can
|
|
137
|
+
* keep a visitor's text. Emits `valueChange` whenever it changes: once per
|
|
138
|
+
* keystroke that changes the text, and when a bound form control or code
|
|
139
|
+
* sets a different text. With a form control, the control's value wins;
|
|
140
|
+
* don't bind both.
|
|
141
|
+
* @default ''
|
|
142
|
+
*/
|
|
143
|
+
readonly value: import("@angular/core").ModelSignal<string>;
|
|
144
|
+
/**
|
|
145
|
+
* The model's change output as a class property, so code that subscribes to
|
|
146
|
+
* it (`textarea.valueChange.subscribe(…)`, `outputToObservable(…)`) keeps
|
|
147
|
+
* compiling as in 3.9. Template bindings `(valueChange)` use the model.
|
|
92
148
|
*/
|
|
93
|
-
readonly valueChange:
|
|
149
|
+
readonly valueChange: OutputRef<string>;
|
|
94
150
|
/** Per-instance id: links label, error and helper text to the control. */
|
|
95
151
|
readonly textareaId: string;
|
|
96
152
|
readonly errorId: string;
|
|
97
153
|
readonly helperId: string;
|
|
98
|
-
|
|
154
|
+
/**
|
|
155
|
+
* The native textarea's value. On the server a leading line break gets one
|
|
156
|
+
* extra `\n`: the HTML parser drops the first line break after `<textarea>`,
|
|
157
|
+
* and the server's DOM serialiser doesn't add the one the HTML
|
|
158
|
+
* serialisation rules require, so the prerendered page would lose it.
|
|
159
|
+
*/
|
|
160
|
+
protected readonly renderedValue: import("@angular/core").Signal<string>;
|
|
99
161
|
private readonly formDisabled;
|
|
100
162
|
/**
|
|
101
163
|
* Computed disabled state from both input and form control
|
|
@@ -159,6 +221,16 @@ export declare class TextareaComponent implements ControlValueAccessor {
|
|
|
159
221
|
"required": false;
|
|
160
222
|
"isSignal": true;
|
|
161
223
|
};
|
|
224
|
+
"requiredIndicator": {
|
|
225
|
+
"alias": "requiredIndicator";
|
|
226
|
+
"required": false;
|
|
227
|
+
"isSignal": true;
|
|
228
|
+
};
|
|
229
|
+
"requiredAriaLabel": {
|
|
230
|
+
"alias": "requiredAriaLabel";
|
|
231
|
+
"required": false;
|
|
232
|
+
"isSignal": true;
|
|
233
|
+
};
|
|
162
234
|
"readonly": {
|
|
163
235
|
"alias": "readonly";
|
|
164
236
|
"required": false;
|
|
@@ -189,6 +261,11 @@ export declare class TextareaComponent implements ControlValueAccessor {
|
|
|
189
261
|
"required": false;
|
|
190
262
|
"isSignal": true;
|
|
191
263
|
};
|
|
264
|
+
"name": {
|
|
265
|
+
"alias": "name";
|
|
266
|
+
"required": false;
|
|
267
|
+
"isSignal": true;
|
|
268
|
+
};
|
|
192
269
|
"rows": {
|
|
193
270
|
"alias": "rows";
|
|
194
271
|
"required": false;
|
|
@@ -219,7 +296,12 @@ export declare class TextareaComponent implements ControlValueAccessor {
|
|
|
219
296
|
"required": false;
|
|
220
297
|
"isSignal": true;
|
|
221
298
|
};
|
|
299
|
+
"value": {
|
|
300
|
+
"alias": "value";
|
|
301
|
+
"required": false;
|
|
302
|
+
"isSignal": true;
|
|
303
|
+
};
|
|
222
304
|
}, {
|
|
223
|
-
"
|
|
305
|
+
"value": "valueChange";
|
|
224
306
|
}, never, never, true, never>;
|
|
225
307
|
}
|