@lifecorner/angular-ui-kit 3.11.5 → 3.12.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.
@@ -13,6 +13,8 @@ var TextareaComponent = class TextareaComponent {
13
13
  required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
14
14
  requiredIndicator = input(true, ...ngDevMode ? [{ debugName: "requiredIndicator" }] : /* istanbul ignore next */ []);
15
15
  requiredAriaLabel = input("required", ...ngDevMode ? [{ debugName: "requiredAriaLabel" }] : /* istanbul ignore next */ []);
16
+ controlId = input(void 0, ...ngDevMode ? [{ debugName: "controlId" }] : /* istanbul ignore next */ []);
17
+ announceError = input(true, ...ngDevMode ? [{ debugName: "announceError" }] : /* istanbul ignore next */ []);
16
18
  readonly = input(false, ...ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []);
17
19
  placeholder = input("", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
18
20
  label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
@@ -28,9 +30,17 @@ var TextareaComponent = class TextareaComponent {
28
30
  maxRows = input(void 0, ...ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []);
29
31
  value = model("", ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
30
32
  valueChange = this.value;
31
- textareaId = `lc-textarea-${nextUniqueId++}`;
32
- errorId = `${this.textareaId}-error`;
33
- helperId = `${this.textareaId}-helper`;
33
+ generatedId = `lc-textarea-${nextUniqueId++}`;
34
+ resolvedId = computed(() => this.controlId() || this.generatedId, ...ngDevMode ? [{ debugName: "resolvedId" }] : /* istanbul ignore next */ []);
35
+ get textareaId() {
36
+ return this.resolvedId();
37
+ }
38
+ get errorId() {
39
+ return `${this.resolvedId()}-error`;
40
+ }
41
+ get helperId() {
42
+ return `${this.resolvedId()}-helper`;
43
+ }
34
44
  renderedValue = computed(() => {
35
45
  const value = this.value();
36
46
  return this.isServer && /^[\r\n]/.test(value) ? `\n${value}` : value;
@@ -184,6 +194,20 @@ var TextareaComponent = class TextareaComponent {
184
194
  isRequired: false,
185
195
  transformFunction: null
186
196
  },
197
+ controlId: {
198
+ classPropertyName: "controlId",
199
+ publicName: "controlId",
200
+ isSignal: true,
201
+ isRequired: false,
202
+ transformFunction: null
203
+ },
204
+ announceError: {
205
+ classPropertyName: "announceError",
206
+ publicName: "announceError",
207
+ isSignal: true,
208
+ isRequired: false,
209
+ transformFunction: null
210
+ },
187
211
  readonly: {
188
212
  classPropertyName: "readonly",
189
213
  publicName: "readonly",
@@ -297,8 +321,8 @@ var TextareaComponent = class TextareaComponent {
297
321
  isSignal: true
298
322
  }],
299
323
  ngImport: i0,
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",
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"],
324
+ template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\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\" [attr.role]=\"announceError() ? 'alert' : null\">{{ 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",
325
+ 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);margin-inline-start:var(--spacing-1)}\n"],
302
326
  changeDetection: i0.ChangeDetectionStrategy.OnPush
303
327
  });
304
328
  };
@@ -319,8 +343,8 @@ i0.ɵɵngDeclareClassMetadata({
319
343
  useExisting: forwardRef(() => TextareaComponent),
320
344
  multi: true
321
345
  }],
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",
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"]
346
+ template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\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\" [attr.role]=\"announceError() ? 'alert' : null\">{{ 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",
347
+ 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);margin-inline-start:var(--spacing-1)}\n"]
324
348
  }]
325
349
  }],
326
350
  ctorParameters: () => [],
@@ -385,6 +409,22 @@ i0.ɵɵngDeclareClassMetadata({
385
409
  required: false
386
410
  }]
387
411
  }],
412
+ controlId: [{
413
+ type: i0.Input,
414
+ args: [{
415
+ isSignal: true,
416
+ alias: "controlId",
417
+ required: false
418
+ }]
419
+ }],
420
+ announceError: [{
421
+ type: i0.Input,
422
+ args: [{
423
+ isSignal: true,
424
+ alias: "announceError",
425
+ required: false
426
+ }]
427
+ }],
388
428
  readonly: [{
389
429
  type: i0.Input,
390
430
  args: [{
@@ -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 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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"}
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\n/** Counter for generated ids: they follow creation order, so prerendered HTML is the same in every build. */\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 * Deprecated, no effect (it never had one in `lc-textarea`). The `*` is\n * decorative and hidden from assistive technology, because the native\n * `required` state is announced already, in the screen reader's language; a\n * name on the `*` would make the field say \"required\" twice. Kept so\n * existing bindings compile.\n * @deprecated No effect: the native `required` state is announced instead.\n * @default 'required'\n */\n readonly requiredAriaLabel = input<string>('required');\n\n /**\n * Id of the native `<textarea>`. The label's `for`, the error\n * (`<id>-error`), the helper text (`<id>-helper`) and `aria-describedby`\n * derive from it, so an error summary can link to the field\n * (`<a href=\"#contact-message\">`) and prerendered HTML is the same in every\n * build. Unique in the document, no spaces. Unset (or empty) = a generated\n * `lc-textarea-<n>`, which follows creation order (on the server it keeps\n * counting across prerendered routes): set it on prerendered pages.\n * @default generated (lc-textarea-<n>)\n */\n readonly controlId = input<string | undefined>(undefined);\n\n /**\n * Announce the error message the moment it appears (`role=\"alert\"` on the\n * message). Set `false` when an `lc-alert` error summary above the form\n * already announces the errors (a page re-rendered after a failed submit,\n * e.g. 422), so they aren't read twice. The message stays visible, stays\n * linked through `aria-describedby` (read with the field), and the control\n * keeps `aria-invalid`.\n * @default true\n */\n readonly announceError = input<boolean>(true);\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 /** Generated id, taken once per instance (also with `controlId`), so later ids don't shift. */\n private readonly generatedId = `lc-textarea-${nextUniqueId++}`;\n\n private readonly resolvedId = computed(() => this.controlId() || this.generatedId);\n\n /** Id of the native textarea: `controlId`, or the generated `lc-textarea-<n>`. Links label, error and helper text to it. */\n get textareaId(): string {\n return this.resolvedId();\n }\n\n /** Id of the error message: `<textareaId>-error`. */\n get errorId(): string {\n return `${this.resolvedId()}-error`;\n }\n\n /** Id of the helper text: `<textareaId>-helper`. */\n get helperId(): string {\n return `${this.resolvedId()}-helper`;\n }\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 <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\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\" [attr.role]=\"announceError() ? 'alert' : null\">{{ 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,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifecorner/angular-ui-kit",
3
- "version": "3.11.5",
3
+ "version": "3.12.0",
4
4
  "description": "LifeCorner Design System – Angular UI component library",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -19,7 +19,9 @@ export type AlertActionsLayout = 'inline' | 'stacked';
19
19
  * dismissed alert can be shown again
20
20
  * - Content projection for custom body
21
21
  * - Action slot for a button rendered right of the body (e.g. retry), or
22
- * several actions stacked below it (`actionsLayout="stacked"`)
22
+ * several actions stacked below it (`actionsLayout="stacked"`); 3.12: a text
23
+ * link (`<a slot="action" href="…">`) as the one way forward gets a
24
+ * 44 × 44 px target, link colour, an underline and a focus ring
23
25
  * - The variant icon is decorative unless `iconAriaLabel` names it (the
24
26
  * title and the colour carry the tone; no built-in English word)
25
27
  * - Accessible: `role="alert"` for error / warning, `role="status"` otherwise
@@ -34,6 +36,11 @@ export type AlertActionsLayout = 'inline' | 'stacked';
34
36
  * Die Liste konnte nicht geladen werden.
35
37
  * <lc-button slot="action" variant="outline" size="sm">Erneut versuchen</lc-button>
36
38
  * </lc-alert>
39
+ *
40
+ * <lc-alert variant="error" title="Senden gerade nicht möglich">
41
+ * Wir können Ihre Nachricht gerade nicht senden.
42
+ * <a slot="action" href="mailto:kontakt@beispiel.example">Schreiben Sie uns an kontakt@beispiel.example</a>
43
+ * </lc-alert>
37
44
  * ```
38
45
  */
39
46
  export declare class AlertComponent {
@@ -134,8 +134,36 @@ export declare class InputComponent implements ControlValueAccessor {
134
134
  readonly spellcheck: import("@angular/core").InputSignal<boolean | undefined>;
135
135
  /** Native `enterkeyhint`: the label of the on-screen keyboard's Enter key. Unset = no attribute. */
136
136
  readonly enterkeyhint: import("@angular/core").InputSignal<InputEnterKeyHint | undefined>;
137
- /** Accessible name of the `*` marker shown for `required` fields. */
137
+ /**
138
+ * Deprecated, no effect since 3.12. The `*` is decorative and hidden from
139
+ * assistive technology, because the native `required` state is announced
140
+ * already, in the screen reader's language; a name on the `*` made the field
141
+ * say "required" twice. Kept so existing bindings compile.
142
+ * @deprecated No effect since 3.12: the native `required` state is announced instead.
143
+ * @default 'required'
144
+ */
138
145
  readonly requiredAriaLabel: import("@angular/core").InputSignal<string>;
146
+ /**
147
+ * Id of the native `<input>`. The label's `for`, the error (`<id>-error`),
148
+ * the helper text (`<id>-helper`), the label id (`<id>-label`) and
149
+ * `aria-describedby` derive from it, so an error summary can link to the
150
+ * field (`<a href="#contact-email">`) and prerendered HTML is the same in
151
+ * every build. Unique in the document, no spaces. Unset (or empty) = a
152
+ * generated `lc-input-<n>`, which follows creation order (on the server it
153
+ * keeps counting across prerendered routes): set it on prerendered pages.
154
+ * @default generated (lc-input-<n>)
155
+ */
156
+ readonly controlId: import("@angular/core").InputSignal<string | undefined>;
157
+ /**
158
+ * Announce the error message the moment it appears (`role="alert"` on the
159
+ * message). Set `false` when an `lc-alert` error summary above the form
160
+ * already announces the errors (a page re-rendered after a failed submit,
161
+ * e.g. 422), so they aren't read twice. The message stays visible, stays
162
+ * linked through `aria-describedby` (read with the field), and the control
163
+ * keeps `aria-invalid`.
164
+ * @default true
165
+ */
166
+ readonly announceError: import("@angular/core").InputSignal<boolean>;
139
167
  /**
140
168
  * Current value (two-way bindable: `[value]` / `[(value)]`). Emits
141
169
  * `valueChange` whenever it changes — once per user keystroke, on `clear()`
@@ -154,7 +182,14 @@ export declare class InputComponent implements ControlValueAccessor {
154
182
  * Emitted when Enter key is pressed
155
183
  */
156
184
  readonly enterPressed: import("@angular/core").OutputEmitterRef<void>;
157
- readonly inputId: string;
185
+ /** Generated id, taken once per instance (also with `controlId`), so later ids don't shift. */
186
+ private readonly generatedId;
187
+ private readonly resolvedId;
188
+ /**
189
+ * Resolved id of the native control: `controlId`, or the generated
190
+ * `lc-input-<n>`. Read-only, same meaning as before 3.12.
191
+ */
192
+ get inputId(): string;
158
193
  private readonly inputElement;
159
194
  private readonly readonlyValueElement;
160
195
  private readonly _formDisabled;
@@ -332,6 +367,16 @@ export declare class InputComponent implements ControlValueAccessor {
332
367
  "required": false;
333
368
  "isSignal": true;
334
369
  };
370
+ "controlId": {
371
+ "alias": "controlId";
372
+ "required": false;
373
+ "isSignal": true;
374
+ };
375
+ "announceError": {
376
+ "alias": "announceError";
377
+ "required": false;
378
+ "isSignal": true;
379
+ };
335
380
  "value": {
336
381
  "alias": "value";
337
382
  "required": false;
@@ -57,13 +57,36 @@ export declare class TextareaComponent implements ControlValueAccessor {
57
57
  */
58
58
  readonly requiredIndicator: import("@angular/core").InputSignal<boolean>;
59
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.
60
+ * Deprecated, no effect (it never had one in `lc-textarea`). The `*` is
61
+ * decorative and hidden from assistive technology, because the native
62
+ * `required` state is announced already, in the screen reader's language; a
63
+ * name on the `*` would make the field say "required" twice. Kept so
64
+ * existing bindings compile.
65
+ * @deprecated No effect: the native `required` state is announced instead.
64
66
  * @default 'required'
65
67
  */
66
68
  readonly requiredAriaLabel: import("@angular/core").InputSignal<string>;
69
+ /**
70
+ * Id of the native `<textarea>`. The label's `for`, the error
71
+ * (`<id>-error`), the helper text (`<id>-helper`) and `aria-describedby`
72
+ * derive from it, so an error summary can link to the field
73
+ * (`<a href="#contact-message">`) and prerendered HTML is the same in every
74
+ * build. Unique in the document, no spaces. Unset (or empty) = a generated
75
+ * `lc-textarea-<n>`, which follows creation order (on the server it keeps
76
+ * counting across prerendered routes): set it on prerendered pages.
77
+ * @default generated (lc-textarea-<n>)
78
+ */
79
+ readonly controlId: import("@angular/core").InputSignal<string | undefined>;
80
+ /**
81
+ * Announce the error message the moment it appears (`role="alert"` on the
82
+ * message). Set `false` when an `lc-alert` error summary above the form
83
+ * already announces the errors (a page re-rendered after a failed submit,
84
+ * e.g. 422), so they aren't read twice. The message stays visible, stays
85
+ * linked through `aria-describedby` (read with the field), and the control
86
+ * keeps `aria-invalid`.
87
+ * @default true
88
+ */
89
+ readonly announceError: import("@angular/core").InputSignal<boolean>;
67
90
  /**
68
91
  * Whether the textarea is readonly
69
92
  * @default false
@@ -147,10 +170,15 @@ export declare class TextareaComponent implements ControlValueAccessor {
147
170
  * compiling as in 3.9. Template bindings `(valueChange)` use the model.
148
171
  */
149
172
  readonly valueChange: OutputRef<string>;
150
- /** Per-instance id: links label, error and helper text to the control. */
151
- readonly textareaId: string;
152
- readonly errorId: string;
153
- readonly helperId: string;
173
+ /** Generated id, taken once per instance (also with `controlId`), so later ids don't shift. */
174
+ private readonly generatedId;
175
+ private readonly resolvedId;
176
+ /** Id of the native textarea: `controlId`, or the generated `lc-textarea-<n>`. Links label, error and helper text to it. */
177
+ get textareaId(): string;
178
+ /** Id of the error message: `<textareaId>-error`. */
179
+ get errorId(): string;
180
+ /** Id of the helper text: `<textareaId>-helper`. */
181
+ get helperId(): string;
154
182
  /**
155
183
  * The native textarea's value. On the server a leading line break gets one
156
184
  * extra `\n`: the HTML parser drops the first line break after `<textarea>`,
@@ -231,6 +259,16 @@ export declare class TextareaComponent implements ControlValueAccessor {
231
259
  "required": false;
232
260
  "isSignal": true;
233
261
  };
262
+ "controlId": {
263
+ "alias": "controlId";
264
+ "required": false;
265
+ "isSignal": true;
266
+ };
267
+ "announceError": {
268
+ "alias": "announceError";
269
+ "required": false;
270
+ "isSignal": true;
271
+ };
234
272
  "readonly": {
235
273
  "alias": "readonly";
236
274
  "required": false;