@koobiq/components 21.0.1 → 21.1.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.
Files changed (180) hide show
  1. package/badge/_badge-theme.scss +31 -0
  2. package/breadcrumbs/breadcrumbs.scss +5 -1
  3. package/checkbox/_checkbox-theme.scss +0 -17
  4. package/checkbox/checkbox-tokens.scss +0 -4
  5. package/code-block/_code-block-theme.scss +7 -6
  6. package/code-block/code-block-tokens.scss +8 -4
  7. package/code-block/code-block.scss +54 -32
  8. package/content-panel/content-panel-header.scss +2 -3
  9. package/content-panel/content-panel.scss +3 -0
  10. package/core/selection/pseudo-checkbox/pseudo-checkbox-tokens.scss +0 -2
  11. package/fesm2022/koobiq-components-accordion.mjs +4 -4
  12. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  13. package/fesm2022/koobiq-components-actions-panel.mjs +10 -2
  14. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  15. package/fesm2022/koobiq-components-app-switcher.mjs +1 -1
  16. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  17. package/fesm2022/koobiq-components-badge.mjs +2 -2
  18. package/fesm2022/koobiq-components-badge.mjs.map +1 -1
  19. package/fesm2022/koobiq-components-breadcrumbs.mjs +2 -2
  20. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  21. package/fesm2022/koobiq-components-button-toggle.mjs +1 -1
  22. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  23. package/fesm2022/koobiq-components-checkbox.mjs +18 -8
  24. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  25. package/fesm2022/koobiq-components-clamped-text.mjs +78 -10
  26. package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
  27. package/fesm2022/koobiq-components-code-block.mjs +63 -379
  28. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  29. package/fesm2022/koobiq-components-content-panel.mjs +4 -4
  30. package/fesm2022/koobiq-components-content-panel.mjs.map +1 -1
  31. package/fesm2022/koobiq-components-core.mjs +300 -37
  32. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  33. package/fesm2022/koobiq-components-datepicker.mjs +151 -60
  34. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  35. package/fesm2022/koobiq-components-divider.mjs +3 -3
  36. package/fesm2022/koobiq-components-divider.mjs.map +1 -1
  37. package/fesm2022/koobiq-components-dropdown.mjs +3 -3
  38. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  39. package/fesm2022/koobiq-components-file-upload.mjs +17 -8
  40. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  41. package/fesm2022/koobiq-components-filter-bar.mjs +115 -36
  42. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  43. package/fesm2022/koobiq-components-flag.mjs +3 -3
  44. package/fesm2022/koobiq-components-flag.mjs.map +1 -1
  45. package/fesm2022/koobiq-components-form-field.mjs +90 -27
  46. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-icon.mjs +2 -2
  48. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-inline-edit.mjs +19 -2
  50. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  51. package/fesm2022/koobiq-components-input.mjs +76 -17
  52. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  53. package/fesm2022/koobiq-components-list.mjs +1 -1
  54. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  55. package/fesm2022/koobiq-components-modal.mjs +3 -3
  56. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-navbar.mjs +86 -25
  58. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  59. package/fesm2022/koobiq-components-notification-center.mjs +4 -4
  60. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  61. package/fesm2022/koobiq-components-overflow-items.mjs +116 -38
  62. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  63. package/fesm2022/koobiq-components-popover.mjs +86 -7
  64. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  65. package/fesm2022/koobiq-components-radio.mjs +41 -19
  66. package/fesm2022/koobiq-components-radio.mjs.map +1 -1
  67. package/fesm2022/koobiq-components-search-expandable.mjs +29 -17
  68. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  69. package/fesm2022/koobiq-components-select.mjs +49 -12
  70. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  71. package/fesm2022/koobiq-components-sidepanel.mjs +198 -186
  72. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  73. package/fesm2022/koobiq-components-splitter.mjs +49 -25
  74. package/fesm2022/koobiq-components-splitter.mjs.map +1 -1
  75. package/fesm2022/koobiq-components-tabs.mjs +30 -11
  76. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  77. package/fesm2022/koobiq-components-tags.mjs +1 -1
  78. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  79. package/fesm2022/koobiq-components-textarea.mjs +28 -11
  80. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  81. package/fesm2022/koobiq-components-time-range.mjs +2 -2
  82. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  83. package/fesm2022/koobiq-components-timepicker.mjs +71 -16
  84. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  85. package/fesm2022/koobiq-components-timezone.mjs +2 -2
  86. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  87. package/fesm2022/koobiq-components-toast.mjs +2 -2
  88. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  89. package/fesm2022/koobiq-components-toggle.mjs +25 -9
  90. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  91. package/fesm2022/koobiq-components-tooltip.mjs +90 -17
  92. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  93. package/fesm2022/koobiq-components-top-bar.mjs +27 -7
  94. package/fesm2022/koobiq-components-top-bar.mjs.map +1 -1
  95. package/fesm2022/koobiq-components-tree-select.mjs +4 -4
  96. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  97. package/fesm2022/koobiq-components-tree.mjs +71 -27
  98. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  99. package/file-upload/_file-upload-theme.scss +0 -12
  100. package/file-upload/file-upload-tokens.scss +0 -1
  101. package/file-upload/file-upload.scss +0 -1
  102. package/filter-bar/_filter-bar-theme.scss +7 -8
  103. package/filter-bar/filter-bar.scss +0 -1
  104. package/filter-bar/pipes/base-pipe.scss +36 -2
  105. package/filter-bar/pipes/pipe-multi-tree-select.scss +27 -0
  106. package/form-field/_fieldset-theme.scss +2 -7
  107. package/form-field/_form-field-theme.scss +9 -22
  108. package/form-field/_hint-theme.scss +20 -0
  109. package/form-field/fieldset-tokens.scss +0 -1
  110. package/form-field/fieldset.scss +0 -3
  111. package/form-field/form-field-tokens.scss +1 -1
  112. package/form-field/form-field.scss +9 -0
  113. package/form-field/hint-tokens.scss +3 -0
  114. package/modal/modal.scss +2 -0
  115. package/navbar/_navbar-item_vertical.scss +48 -2
  116. package/navbar/_navbar-theme.scss +11 -3
  117. package/navbar/navbar-item.scss +17 -0
  118. package/navbar/navbar-tokens.scss +3 -0
  119. package/package.json +4 -4
  120. package/popover/popover.scss +1 -1
  121. package/radio/_radio-theme.scss +0 -30
  122. package/radio/radio-tokens.scss +0 -2
  123. package/schematics/migrations/deprecated-icons/README.md +21 -5
  124. package/schematics/migrations/deprecated-icons/index.cjs +8 -22
  125. package/schematics/migrations/deprecated-icons/schema.json +1 -1
  126. package/schematics/migrations/icons-replacement/README.md +16 -2
  127. package/schematics/migrations/icons-replacement/index.cjs +18 -16
  128. package/schematics/migrations/icons-replacement/schema.json +12 -3
  129. package/schematics/migrations/new-icons-pack/README.md +37 -25
  130. package/schematics/migrations/new-icons-pack/index.cjs +22 -32
  131. package/schematics/migrations/new-icons-pack/replacement.json +2 -14
  132. package/schematics/migrations/new-icons-pack/schema.json +3 -3
  133. package/schematics/ng-add/index.cjs +4 -4
  134. package/schematics/utils/custom-data.cjs +64 -0
  135. package/schematics/utils/icon-migration.cjs +9 -3
  136. package/schematics/utils/messages.cjs +4 -0
  137. package/schematics/utils/package-config.cjs +19 -0
  138. package/select/select.scss +7 -0
  139. package/tabs/_tabs-common.scss +23 -0
  140. package/textarea/textarea-tokens.scss +4 -1
  141. package/toast/toast.component.scss +1 -0
  142. package/toggle/_toggle-theme.scss +0 -17
  143. package/tooltip/tooltip.scss +1 -1
  144. package/top-bar/top-bar-tokens.scss +1 -0
  145. package/top-bar/top-bar.scss +10 -0
  146. package/types/koobiq-components-accordion.d.ts +25 -0
  147. package/types/koobiq-components-button-toggle.d.ts +6 -0
  148. package/types/koobiq-components-checkbox.d.ts +30 -0
  149. package/types/koobiq-components-clamped-text.d.ts +16 -3
  150. package/types/koobiq-components-code-block.d.ts +17 -3
  151. package/types/koobiq-components-core.d.ts +226 -13
  152. package/types/koobiq-components-datepicker.d.ts +28 -1
  153. package/types/koobiq-components-divider.d.ts +28 -10
  154. package/types/koobiq-components-dropdown.d.ts +19 -0
  155. package/types/koobiq-components-filter-bar.d.ts +77 -4
  156. package/types/koobiq-components-flag.d.ts +18 -0
  157. package/types/koobiq-components-form-field.d.ts +87 -6
  158. package/types/koobiq-components-icon.d.ts +15 -0
  159. package/types/koobiq-components-inline-edit.d.ts +8 -1
  160. package/types/koobiq-components-input.d.ts +22 -3
  161. package/types/koobiq-components-list.d.ts +6 -0
  162. package/types/koobiq-components-modal.d.ts +7 -0
  163. package/types/koobiq-components-navbar.d.ts +71 -7
  164. package/types/koobiq-components-notification-center.d.ts +13 -0
  165. package/types/koobiq-components-overflow-items.d.ts +26 -2
  166. package/types/koobiq-components-popover.d.ts +38 -3
  167. package/types/koobiq-components-radio.d.ts +30 -0
  168. package/types/koobiq-components-search-expandable.d.ts +10 -0
  169. package/types/koobiq-components-select.d.ts +36 -4
  170. package/types/koobiq-components-sidepanel.d.ts +52 -1
  171. package/types/koobiq-components-splitter.d.ts +13 -4
  172. package/types/koobiq-components-tabs.d.ts +4 -0
  173. package/types/koobiq-components-tags.d.ts +6 -0
  174. package/types/koobiq-components-textarea.d.ts +9 -2
  175. package/types/koobiq-components-timepicker.d.ts +15 -0
  176. package/types/koobiq-components-toggle.d.ts +30 -0
  177. package/types/koobiq-components-tooltip.d.ts +55 -10
  178. package/types/koobiq-components-top-bar.d.ts +11 -3
  179. package/types/koobiq-components-tree-select.d.ts +12 -0
  180. package/types/koobiq-components-tree.d.ts +37 -2
@@ -1,7 +1,7 @@
1
1
  import { _IdGenerator, A11yModule } from '@angular/cdk/a11y';
2
2
  import { getSupportedInputTypes } from '@angular/cdk/platform';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, forwardRef, inject, ElementRef, Renderer2, NgZone, DestroyRef, input, booleanAttribute, signal, computed, effect, untracked, Directive, linkedSignal, NgModule } from '@angular/core';
4
+ import { InjectionToken, forwardRef, inject, ElementRef, Renderer2, NgZone, DestroyRef, input, booleanAttribute, signal, computed, effect, untracked, Directive, linkedSignal, isDevMode, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR, NgControl, NgForm, FormGroupDirective, NG_VALIDATORS, Validators, FormsModule } from '@angular/forms';
6
6
  import * as i1 from '@koobiq/components/core';
7
7
  import { ruRUFormattersData, kbqLocaleConfigurationOverrideProvider, KBQ_DEFAULT_LOCALE_ID, KBQ_DEFAULT_PRECISION_SEPARATOR, normalizeNumber, KBQ_LOCALE_SERVICE, KbqLocaleOverridesDirective, V, X, Z, NUMPAD_MINUS, DASH, FF_MINUS, DELETE, BACKSPACE, TAB, ESCAPE, ENTER, LEFT_ARROW, RIGHT_ARROW, HOME, END, isSelectAll, isCopy, isFunctionKey, isNumberKey, isNumpadKey, UP_ARROW, DOWN_ARROW, checkAndNormalizeLocalizedNumber, formatNumberWithLocale, ErrorStateMatcher, KbqErrorStateTracker, kbqInjectAutofilled } from '@koobiq/components/core';
@@ -69,6 +69,9 @@ const numberAttribute = (fallback) => (value) => coerceNumberProperty(value, fal
69
69
  function isFloat(value) {
70
70
  return /^-?\d+\.\d+$/.test(value);
71
71
  }
72
+ function isPastSafeInteger(value) {
73
+ return Math.abs(value) > Number.MAX_SAFE_INTEGER;
74
+ }
72
75
  /**
73
76
  * Number of digits after the decimal point. Exponent-aware, so `1e-7` reports `7` rather than the
74
77
  * `0` that reading `'1e-7'.split('.')` would give.
@@ -139,6 +142,12 @@ class KbqNumberInput {
139
142
  get config() {
140
143
  return this.localeConfiguration().number;
141
144
  }
145
+ get stepMin() {
146
+ return Math.max(this.min(), -Number.MAX_SAFE_INTEGER);
147
+ }
148
+ get stepMax() {
149
+ return Math.min(this.max(), Number.MAX_SAFE_INTEGER);
150
+ }
142
151
  constructor() {
143
152
  this.elementRef = inject(ElementRef);
144
153
  this.renderer = inject(Renderer2);
@@ -182,6 +191,11 @@ class KbqNumberInput {
182
191
  this.disabledInput = input(undefined, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
183
192
  transform: booleanAttribute });
184
193
  this.disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
194
+ /**
195
+ * Whether the field is read-only: the arrow keys, `kbq-stepper` and a paste leave the value as it is.
196
+ * `KbqInput` on the same element binds the native attribute. Defaults to `false`.
197
+ */
198
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
185
199
  this.focused = false;
186
200
  /**
187
201
  * An unbounded end reports no `aria-value*`: `Infinity` is not a valid ARIA attribute value.
@@ -273,8 +287,10 @@ class KbqNumberInput {
273
287
  this.focused = isFocused;
274
288
  this.stateChanges.next();
275
289
  }
276
- if (!isFocused)
290
+ if (!isFocused) {
291
+ this.clampToSafeRange();
277
292
  this.onTouched();
293
+ }
278
294
  }
279
295
  onKeyDown(event) {
280
296
  const keyCode = event.keyCode;
@@ -309,6 +325,8 @@ class KbqNumberInput {
309
325
  // Ensure that it is not a number and stop the keypress
310
326
  if (event.shiftKey || isLetter) {
311
327
  event.preventDefault();
328
+ if (this.readonly())
329
+ return;
312
330
  // process steps
313
331
  const step = event.shiftKey ? this.bigStep() : this.step();
314
332
  if (keyCode === UP_ARROW) {
@@ -327,6 +345,9 @@ class KbqNumberInput {
327
345
  // timeout must not write to a detached node nor push a change into a control the view no longer owns.
328
346
  const reformat = (correctCaret) => {
329
347
  this.pendingReformats.delete(handle);
348
+ // Past the limit the text stays as typed: the field clamps it when it loses focus.
349
+ if (this.isBeyondSafeRange(this.viewValue))
350
+ return;
330
351
  const fromPaste = event.inputType === 'insertFromPaste';
331
352
  let formattedValue;
332
353
  if (fromPaste) {
@@ -348,6 +369,9 @@ class KbqNumberInput {
348
369
  this.pendingReformats.set(handle, reformat);
349
370
  }
350
371
  onPaste(event) {
372
+ // The browser fires `paste` on a read-only input too, and the integer branch below writes the value itself.
373
+ if (this.readonly())
374
+ return;
351
375
  this.valueFromPaste = checkAndNormalizeLocalizedNumber(event.clipboardData?.getData('text'), this.localeService?.localeId());
352
376
  if (this.valueFromPaste === null || isNaN(this.valueFromPaste)) {
353
377
  event.preventDefault();
@@ -362,7 +386,11 @@ class KbqNumberInput {
362
386
  stepUp(step) {
363
387
  this.nativeElement.focus();
364
388
  this.commitPendingReformats();
365
- const res = Math.max(Math.min(add(this.value || 0, step), this.max()), this.min());
389
+ // A value set past the limit from outside is not moved down by a step up.
390
+ if (this.value !== null && this.value > Number.MAX_SAFE_INTEGER)
391
+ return;
392
+ this.clampToSafeRange();
393
+ const res = Math.max(Math.min(add(this.value || 0, step), this.stepMax), this.stepMin);
366
394
  this.setViewValue(this.formatNumber(res));
367
395
  this.valueState.set(res);
368
396
  this.cvaOnChange(res);
@@ -371,7 +399,11 @@ class KbqNumberInput {
371
399
  stepDown(step) {
372
400
  this.nativeElement.focus();
373
401
  this.commitPendingReformats();
374
- const res = Math.min(Math.max(add(this.value || 0, -step), this.min()), this.max());
402
+ // A value set below the limit from outside is not moved up by a step down.
403
+ if (this.value !== null && this.value < -Number.MAX_SAFE_INTEGER)
404
+ return;
405
+ this.clampToSafeRange();
406
+ const res = Math.min(Math.max(add(this.value || 0, -step), this.stepMin), this.stepMax);
375
407
  this.setViewValue(this.formatNumber(res));
376
408
  this.valueState.set(res);
377
409
  this.cvaOnChange(res);
@@ -412,6 +444,17 @@ class KbqNumberInput {
412
444
  this.renderer.setProperty(this.nativeElement, 'selectionEnd', cursorPosition);
413
445
  }
414
446
  }
447
+ isBeyondSafeRange(text) {
448
+ return isPastSafeInteger(Number(normalizeNumber(text, this.config)));
449
+ }
450
+ clampToSafeRange() {
451
+ const typed = Number(normalizeNumber(this.viewValue, this.config));
452
+ if (!isPastSafeInteger(typed))
453
+ return;
454
+ const formatted = this.formatNumber(Math.sign(typed) * Number.MAX_SAFE_INTEGER);
455
+ this.setViewValue(formatted);
456
+ this.viewToModelUpdate(formatted);
457
+ }
415
458
  /** Writes a value from outside the field: reformats it and reports the change. */
416
459
  setValue(value) {
417
460
  const oldValue = this.valueState();
@@ -457,13 +500,17 @@ class KbqNumberInput {
457
500
  const [intPart, fractionPart] = this.viewValue
458
501
  .split(separator)
459
502
  .map((valuePart) => normalizeNumber(valuePart, this.config));
460
- return this.createLocalizedNumberFromParts(+intPart, fractionPart);
503
+ const integer = +intPart;
504
+ // A lone sign before the decimal separator (`-,5`) is no number yet: clear the field, do not print NaN.
505
+ if (!Number.isFinite(integer))
506
+ return null;
507
+ return this.createLocalizedNumberFromParts(integer, fractionPart);
461
508
  }
462
509
  formatNumber(value) {
463
- if (value === null || value === undefined)
510
+ if (value === null || value === undefined || !Number.isFinite(value))
464
511
  return null;
465
- const [intPart, fractionPart] = value.toString().split(KBQ_DEFAULT_PRECISION_SEPARATOR);
466
- return this.createLocalizedNumberFromParts(+intPart, fractionPart);
512
+ // The whole value is formatted: `toString()` writes `1.5e-7` with an exponent that `split` would tear apart.
513
+ return this.createLocalizedNumberFromParts(value === 0 ? 0 : value);
467
514
  }
468
515
  createLocalizedNumberFromParts(intPart, fractionPart) {
469
516
  const formatOptions = {
@@ -486,7 +533,7 @@ class KbqNumberInput {
486
533
  return `${formattedIntPart}${this.fractionSeparator}${formattedFractionPart}`;
487
534
  }
488
535
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqNumberInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
489
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqNumberInput, isStandalone: true, selector: "input[kbqNumberInput]", inputs: { integer: { classPropertyName: "integer", publicName: "integer", isSignal: true, isRequired: false, transformFunction: null }, bigStep: { classPropertyName: "bigStep", publicName: "bigStep", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, withThousandSeparator: { classPropertyName: "withThousandSeparator", publicName: "withThousandSeparator", isSignal: true, isRequired: false, transformFunction: null }, startFormattingFrom: { classPropertyName: "startFormattingFrom", publicName: "startFormattingFrom", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "spinbutton" }, listeners: { "blur": "focusChanged(false)", "focus": "focusChanged(true)", "paste": "onPaste($event)", "keydown": "onKeyDown($event)", "input": "onInput($any($event))" }, properties: { "attr.inputmode": "integer() ? 'numeric' : 'decimal'", "attr.aria-valuenow": "value", "attr.aria-valuetext": "viewValue || null", "attr.aria-valuemin": "ariaValueMin()", "attr.aria-valuemax": "ariaValueMax()" } }, providers: [KBQ_NUMBER_INPUT_VALUE_ACCESSOR], exportAs: ["kbqNumberInput", "kbqNumericalInput"], hostDirectives: [{ directive: i1.KbqLocaleOverridesDirective, inputs: ["kbqLocaleOverrides", "localeOverrides"] }], ngImport: i0 }); }
536
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqNumberInput, isStandalone: true, selector: "input[kbqNumberInput]", inputs: { integer: { classPropertyName: "integer", publicName: "integer", isSignal: true, isRequired: false, transformFunction: null }, bigStep: { classPropertyName: "bigStep", publicName: "bigStep", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, withThousandSeparator: { classPropertyName: "withThousandSeparator", publicName: "withThousandSeparator", isSignal: true, isRequired: false, transformFunction: null }, startFormattingFrom: { classPropertyName: "startFormattingFrom", publicName: "startFormattingFrom", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "spinbutton" }, listeners: { "blur": "focusChanged(false)", "focus": "focusChanged(true)", "paste": "onPaste($event)", "keydown": "onKeyDown($event)", "input": "onInput($any($event))" }, properties: { "attr.inputmode": "integer() ? 'numeric' : 'decimal'", "attr.aria-valuenow": "value", "attr.aria-valuetext": "viewValue || null", "attr.aria-valuemin": "ariaValueMin()", "attr.aria-valuemax": "ariaValueMax()" } }, providers: [KBQ_NUMBER_INPUT_VALUE_ACCESSOR], exportAs: ["kbqNumberInput", "kbqNumericalInput"], hostDirectives: [{ directive: i1.KbqLocaleOverridesDirective, inputs: ["kbqLocaleOverrides", "localeOverrides"] }], ngImport: i0 }); }
490
537
  }
491
538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqNumberInput, decorators: [{
492
539
  type: Directive,
@@ -512,7 +559,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
512
559
  ],
513
560
  exportAs: 'kbqNumberInput, kbqNumericalInput'
514
561
  }]
515
- }], ctorParameters: () => [], propDecorators: { integer: [{ type: i0.Input, args: [{ isSignal: true, alias: "integer", required: false }] }], bigStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "bigStep", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], withThousandSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "withThousandSeparator", required: false }] }], startFormattingFrom: [{ type: i0.Input, args: [{ isSignal: true, alias: "startFormattingFrom", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
562
+ }], ctorParameters: () => [], propDecorators: { integer: [{ type: i0.Input, args: [{ isSignal: true, alias: "integer", required: false }] }], bigStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "bigStep", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], withThousandSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "withThousandSeparator", required: false }] }], startFormattingFrom: [{ type: i0.Input, args: [{ isSignal: true, alias: "startFormattingFrom", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }] } });
516
563
 
517
564
  const KBQ_INPUT_VALUE_ACCESSOR = new InjectionToken('KBQ_INPUT_VALUE_ACCESSOR');
518
565
 
@@ -592,6 +639,11 @@ class KbqInput {
592
639
  * @docs-private
593
640
  */
594
641
  this.disabled = computed(() => this.formDisabled() ?? this.disabledInput(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
642
+ /**
643
+ * Whether the input is read-only: its value can be selected and copied, but not changed. A read-only
644
+ * input shows no placeholder. Defaults to `false`.
645
+ */
646
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
595
647
  /** @docs-private */
596
648
  this.idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
597
649
  /**
@@ -740,7 +792,7 @@ class KbqInput {
740
792
  if (KBQ_INPUT_INVALID_TYPES.indexOf(type) > -1) {
741
793
  throw getKbqInputUnsupportedTypeError(type);
742
794
  }
743
- if (this.numberInput && type === 'number' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
795
+ if (this.numberInput && type === 'number' && isDevMode()) {
744
796
  // eslint-disable-next-line no-console
745
797
  console.warn(KBQ_NUMBER_INPUT_UNSUPPORTED_TYPE_MESSAGE);
746
798
  }
@@ -759,7 +811,7 @@ class KbqInput {
759
811
  return !this.isNeverEmpty() && !this.elementRef.nativeElement.value && !this.isBadInput();
760
812
  }
761
813
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
762
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqInput, isStandalone: true, selector: "input[kbqInput],input[kbqNumberInput]", inputs: { errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, typeInput: { classPropertyName: "typeInput", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "blur": "onBlur()", "focus": "focusChanged(true)", "input": "dirtyCheckNativeValue()" }, properties: { "attr.id": "id()", "attr.placeholder": "placeholder()", "attr.disabled": "disabled() || null", "attr.aria-invalid": "errorState()", "required": "required()" }, classAttribute: "kbq-input" }, providers: [
814
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqInput, isStandalone: true, selector: "input[kbqInput],input[kbqNumberInput]", inputs: { errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, typeInput: { classPropertyName: "typeInput", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "blur": "onBlur()", "focus": "focusChanged(true)", "input": "dirtyCheckNativeValue()" }, properties: { "attr.id": "id()", "attr.placeholder": "readonly() ? null : placeholder()", "attr.disabled": "disabled() || null", "readonly": "readonly()", "attr.aria-invalid": "errorState()", "required": "required()" }, classAttribute: "kbq-input" }, providers: [
763
815
  {
764
816
  provide: KbqFormFieldControl,
765
817
  useExisting: KbqInput
@@ -781,8 +833,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
781
833
  // Native input properties that are overwritten by Angular inputs need to be synced with
782
834
  // the native input element. Otherwise property bindings for those don't work.
783
835
  '[attr.id]': 'id()',
784
- '[attr.placeholder]': 'placeholder()',
836
+ '[attr.placeholder]': 'readonly() ? null : placeholder()',
785
837
  '[attr.disabled]': 'disabled() || null',
838
+ '[readonly]': 'readonly()',
786
839
  '[attr.aria-invalid]': 'errorState()',
787
840
  '[required]': 'required()',
788
841
  '(blur)': 'onBlur()',
@@ -791,7 +844,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
791
844
  },
792
845
  exportAs: 'kbqInput'
793
846
  }]
794
- }], ctorParameters: () => [], propDecorators: { errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], typeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }] } });
847
+ }], ctorParameters: () => [], propDecorators: { errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], typeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }] } });
795
848
  class KbqInputMono {
796
849
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqInputMono, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
797
850
  /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqInputMono, isStandalone: true, selector: "input[kbqInputMonospace]", host: { classAttribute: "kbq-input_monospace" }, exportAs: ["kbqInputMonospace", "KbqInputMonospace"], ngImport: i0 }); }
@@ -968,6 +1021,11 @@ class KbqInputPassword {
968
1021
  * @docs-private
969
1022
  */
970
1023
  this.disabled = computed(() => this.formDisabled() ?? this.disabledInput(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1024
+ /**
1025
+ * Whether the input is read-only: its value can be selected and copied, but not changed. A read-only
1026
+ * input shows no placeholder. Defaults to `false`.
1027
+ */
1028
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
971
1029
  /** @docs-private */
972
1030
  this.idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
973
1031
  /**
@@ -1098,7 +1156,7 @@ class KbqInputPassword {
1098
1156
  return !this.elementRef.nativeElement.value && !this.isBadInput();
1099
1157
  }
1100
1158
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqInputPassword, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1101
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqInputPassword, isStandalone: true, selector: "input[kbqInputPassword]", inputs: { errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "blur": "onBlur()", "focus": "focusChanged(true)", "input": "dirtyCheckNativeValue()" }, properties: { "attr.id": "id()", "attr.type": "elementType()", "attr.placeholder": "placeholder()", "attr.disabled": "disabled() || null", "attr.aria-invalid": "errorState()", "required": "required()" }, classAttribute: "kbq-input kbq-input-password" }, providers: [
1159
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqInputPassword, isStandalone: true, selector: "input[kbqInputPassword]", inputs: { errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "blur": "onBlur()", "focus": "focusChanged(true)", "input": "dirtyCheckNativeValue()" }, properties: { "attr.id": "id()", "attr.type": "elementType()", "attr.placeholder": "readonly() ? null : placeholder()", "attr.disabled": "disabled() || null", "readonly": "readonly()", "attr.aria-invalid": "errorState()", "required": "required()" }, classAttribute: "kbq-input kbq-input-password" }, providers: [
1102
1160
  {
1103
1161
  provide: KbqFormFieldControl,
1104
1162
  useExisting: KbqInputPassword
@@ -1121,8 +1179,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
1121
1179
  // the native input element. Otherwise property bindings for those don't work.
1122
1180
  '[attr.id]': 'id()',
1123
1181
  '[attr.type]': 'elementType()',
1124
- '[attr.placeholder]': 'placeholder()',
1182
+ '[attr.placeholder]': 'readonly() ? null : placeholder()',
1125
1183
  '[attr.disabled]': 'disabled() || null',
1184
+ '[readonly]': 'readonly()',
1126
1185
  '[attr.aria-invalid]': 'errorState()',
1127
1186
  '[required]': 'required()',
1128
1187
  '(blur)': 'onBlur()',
@@ -1131,7 +1190,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
1131
1190
  },
1132
1191
  exportAs: 'kbqInputPassword'
1133
1192
  }]
1134
- }], ctorParameters: () => [], propDecorators: { errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }] } });
1193
+ }], ctorParameters: () => [], propDecorators: { errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }] } });
1135
1194
 
1136
1195
  class KbqInputModule {
1137
1196
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }