@koobiq/components 20.2.0 → 20.3.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 (212) hide show
  1. package/accordion/_accordion-theme.scss +5 -1
  2. package/accordion/accordion-tokens.scss +2 -0
  3. package/accordion/accordion-trigger.scss +6 -0
  4. package/accordion/accordion.scss +21 -0
  5. package/accordion/index.d.ts +55 -8
  6. package/actions-panel/index.d.ts +25 -13
  7. package/app-switcher/app-switcher-dropdown-app.scss +7 -5
  8. package/app-switcher/app-switcher-dropdown-site.scss +6 -4
  9. package/app-switcher/index.d.ts +41 -4
  10. package/app-switcher/kbq-app-switcher-list-item.scss +6 -8
  11. package/autocomplete/index.d.ts +24 -9
  12. package/breadcrumbs/index.d.ts +1 -1
  13. package/button/index.d.ts +2 -2
  14. package/button-toggle/button-toggle-tokens.scss +2 -0
  15. package/button-toggle/button-toggle.scss +9 -0
  16. package/button-toggle/index.d.ts +5 -0
  17. package/checkbox/index.d.ts +33 -29
  18. package/clamped-text/index.d.ts +1 -1
  19. package/code-block/index.d.ts +24 -19
  20. package/content-panel/index.d.ts +1 -1
  21. package/core/index.d.ts +1125 -199
  22. package/core/option/_action-container-mixins.scss +28 -0
  23. package/core/option/_option-theme.scss +24 -0
  24. package/core/option/action.scss +7 -0
  25. package/core/styles/_koobiq-theme.scss +2 -0
  26. package/core/styles/_tokens.scss +1 -0
  27. package/core/styles/common/_connected-overlay.scss +6 -3
  28. package/core/styles/common/_select.scss +12 -0
  29. package/core/styles/common/_tokens.scss +0 -9
  30. package/core/styles/theming/_index.scss +0 -1
  31. package/core/styles/theming/_theming.scss +34 -5
  32. package/datepicker/index.d.ts +46 -15
  33. package/dl/dl.scss +26 -0
  34. package/dl/index.d.ts +8 -1
  35. package/dropdown/_dropdown-theme.scss +28 -2
  36. package/dropdown/dropdown-item.scss +13 -0
  37. package/dropdown/dropdown.scss +7 -1
  38. package/dropdown/index.d.ts +264 -17
  39. package/dynamic-translation/index.d.ts +1 -1
  40. package/fesm2022/koobiq-components-accordion.mjs +106 -46
  41. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  42. package/fesm2022/koobiq-components-actions-panel.mjs +57 -46
  43. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  44. package/fesm2022/koobiq-components-alert.mjs +16 -16
  45. package/fesm2022/koobiq-components-app-switcher.mjs +233 -38
  46. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-autocomplete.mjs +54 -31
  48. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-badge.mjs +13 -13
  50. package/fesm2022/koobiq-components-breadcrumbs.mjs +25 -25
  51. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  52. package/fesm2022/koobiq-components-button-toggle.mjs +17 -12
  53. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  54. package/fesm2022/koobiq-components-button.mjs +25 -25
  55. package/fesm2022/koobiq-components-checkbox.mjs +69 -92
  56. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-clamped-text.mjs +13 -13
  58. package/fesm2022/koobiq-components-code-block.mjs +56 -69
  59. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  60. package/fesm2022/koobiq-components-content-panel.mjs +29 -29
  61. package/fesm2022/koobiq-components-core.mjs +2445 -789
  62. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  63. package/fesm2022/koobiq-components-datepicker.mjs +160 -121
  64. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  65. package/fesm2022/koobiq-components-divider.mjs +7 -7
  66. package/fesm2022/koobiq-components-dl.mjs +23 -15
  67. package/fesm2022/koobiq-components-dl.mjs.map +1 -1
  68. package/fesm2022/koobiq-components-dropdown.mjs +754 -155
  69. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  70. package/fesm2022/koobiq-components-dynamic-translation.mjs +13 -13
  71. package/fesm2022/koobiq-components-ellipsis-center.mjs +7 -7
  72. package/fesm2022/koobiq-components-empty-state.mjs +19 -19
  73. package/fesm2022/koobiq-components-file-upload.mjs +74 -42
  74. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  75. package/fesm2022/koobiq-components-filter-bar.mjs +605 -192
  76. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  77. package/fesm2022/koobiq-components-flag.mjs +7 -7
  78. package/fesm2022/koobiq-components-form-field.mjs +346 -158
  79. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  80. package/fesm2022/koobiq-components-icon.mjs +39 -21
  81. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  82. package/fesm2022/koobiq-components-inline-edit.mjs +172 -27
  83. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  84. package/fesm2022/koobiq-components-input.mjs +41 -24
  85. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  86. package/fesm2022/koobiq-components-link.mjs +8 -8
  87. package/fesm2022/koobiq-components-list.mjs +657 -143
  88. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  89. package/fesm2022/koobiq-components-loader-overlay.mjs +16 -16
  90. package/fesm2022/koobiq-components-markdown.mjs +14 -11
  91. package/fesm2022/koobiq-components-markdown.mjs.map +1 -1
  92. package/fesm2022/koobiq-components-modal.mjs +59 -35
  93. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  94. package/fesm2022/koobiq-components-navbar.mjs +69 -54
  95. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  96. package/fesm2022/koobiq-components-notification-center.mjs +23 -22
  97. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  98. package/fesm2022/koobiq-components-overflow-items.mjs +16 -17
  99. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  100. package/fesm2022/koobiq-components-popover.mjs +26 -21
  101. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  102. package/fesm2022/koobiq-components-progress-bar.mjs +13 -13
  103. package/fesm2022/koobiq-components-progress-spinner.mjs +13 -13
  104. package/fesm2022/koobiq-components-radio.mjs +10 -10
  105. package/fesm2022/koobiq-components-resizer.mjs +33 -14
  106. package/fesm2022/koobiq-components-resizer.mjs.map +1 -1
  107. package/fesm2022/koobiq-components-scrollbar.mjs +10 -10
  108. package/fesm2022/koobiq-components-search-expandable.mjs +7 -7
  109. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  110. package/fesm2022/koobiq-components-select.mjs +419 -106
  111. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  112. package/fesm2022/koobiq-components-sidebar.mjs +14 -14
  113. package/fesm2022/koobiq-components-sidepanel.mjs +26 -26
  114. package/fesm2022/koobiq-components-skeleton.mjs +10 -10
  115. package/fesm2022/koobiq-components-split-button.mjs +7 -7
  116. package/fesm2022/koobiq-components-splitter.mjs +17 -17
  117. package/fesm2022/koobiq-components-table.mjs +15 -13
  118. package/fesm2022/koobiq-components-table.mjs.map +1 -1
  119. package/fesm2022/koobiq-components-tabs.mjs +54 -54
  120. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  121. package/fesm2022/koobiq-components-tags.mjs +283 -122
  122. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  123. package/fesm2022/koobiq-components-textarea.mjs +13 -8
  124. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  125. package/fesm2022/koobiq-components-time-range.mjs +29 -24
  126. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  127. package/fesm2022/koobiq-components-timepicker.mjs +58 -26
  128. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  129. package/fesm2022/koobiq-components-timezone.mjs +76 -39
  130. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  131. package/fesm2022/koobiq-components-title.mjs +7 -7
  132. package/fesm2022/koobiq-components-toast.mjs +51 -26
  133. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  134. package/fesm2022/koobiq-components-toggle.mjs +72 -64
  135. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  136. package/fesm2022/koobiq-components-tooltip.mjs +115 -36
  137. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  138. package/fesm2022/koobiq-components-top-bar.mjs +13 -13
  139. package/fesm2022/koobiq-components-tree-select.mjs +189 -55
  140. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  141. package/fesm2022/koobiq-components-tree.mjs +302 -81
  142. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  143. package/fesm2022/koobiq-components-username.mjs +27 -27
  144. package/file-upload/index.d.ts +25 -6
  145. package/file-upload/multiple-file-upload.component.scss +14 -0
  146. package/filter-bar/_filter-bar-theme.scss +0 -6
  147. package/filter-bar/index.d.ts +222 -9
  148. package/filter-bar/pipes/pipe-multi-tree-select.scss +0 -6
  149. package/filter-bar/pipes/pipe-multiselect.scss +0 -6
  150. package/filter-bar/pipes/pipe-tree-select.scss +0 -6
  151. package/form-field/_form-field-theme.scss +76 -20
  152. package/form-field/fieldset.scss +10 -0
  153. package/form-field/form-field-tokens.scss +15 -1
  154. package/form-field/form-field.scss +15 -19
  155. package/form-field/index.d.ts +147 -65
  156. package/icon/index.d.ts +31 -6
  157. package/inline-edit/index.d.ts +57 -4
  158. package/inline-edit/inline-edit.scss +10 -0
  159. package/input/index.d.ts +17 -2
  160. package/list/_list-theme.scss +42 -10
  161. package/list/index.d.ts +326 -79
  162. package/list/list-tokens.scss +43 -8
  163. package/list/list.scss +186 -12
  164. package/markdown/index.d.ts +1 -1
  165. package/modal/index.d.ts +21 -4
  166. package/modal/modal-tokens.scss +1 -1
  167. package/navbar/index.d.ts +16 -1
  168. package/navbar/navbar-brand.scss +6 -0
  169. package/navbar/vertical-navbar.scss +6 -0
  170. package/notification-center/notification-item.scss +6 -0
  171. package/package.json +3 -6
  172. package/popover/index.d.ts +2 -2
  173. package/prebuilt-themes/dark-theme.css +1 -1
  174. package/prebuilt-themes/light-theme.css +1 -1
  175. package/prebuilt-themes/theme.css +1 -1
  176. package/resizer/index.d.ts +12 -0
  177. package/schematics/migrations/deprecated-icons/README.md +29 -4
  178. package/schematics/migrations/deprecated-icons/data.js +7 -0
  179. package/schematics/migrations/deprecated-icons/index.js +62 -35
  180. package/schematics/migrations/new-icons-pack/README.md +37 -2
  181. package/schematics/migrations/new-icons-pack/data.js +8 -0
  182. package/schematics/migrations/new-icons-pack/index.js +144 -53
  183. package/schematics/ng-add/index.js +3 -3
  184. package/schematics/utils/angular-parsing.js +30 -12
  185. package/schematics/utils/ast.js +31 -0
  186. package/schematics/utils/icon-migration.js +530 -0
  187. package/schematics/utils/typescript.js +44 -0
  188. package/scrollbar/index.d.ts +1 -1
  189. package/select/index.d.ts +163 -18
  190. package/select/select-tokens.scss +0 -1
  191. package/select/select.scss +0 -2
  192. package/splitter/index.d.ts +1 -1
  193. package/table/_table-theme.scss +4 -0
  194. package/table/index.d.ts +2 -1
  195. package/table/table.scss +8 -0
  196. package/tags/index.d.ts +128 -29
  197. package/textarea/index.d.ts +5 -0
  198. package/time-range/index.d.ts +1 -1
  199. package/timepicker/index.d.ts +4 -0
  200. package/timezone/index.d.ts +9 -5
  201. package/toast/index.d.ts +26 -3
  202. package/toggle/index.d.ts +34 -14
  203. package/tooltip/index.d.ts +54 -11
  204. package/tree/_tree-theme.scss +25 -5
  205. package/tree/index.d.ts +71 -3
  206. package/tree/tree-option.scss +2 -8
  207. package/tree-select/_tree-select-theme.scss +22 -0
  208. package/tree-select/index.d.ts +83 -16
  209. package/core/styles/_tokens.kbq.import.scss +0 -4
  210. package/core/styles/theming/_components-theming.scss +0 -1927
  211. package/filter-bar/pipes/pipe-select.scss +0 -5
  212. package/overflow-items/overflow-items.scss +0 -20
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { AfterViewInit, ChangeDetectorRef, DestroyRef, ElementRef, TemplateRef, InjectionToken, ModelSignal, Signal, OutputEmitterRef, Type, Provider, OnInit, AfterContentInit } from '@angular/core';
3
3
  import * as _koobiq_components_core from '@koobiq/components/core';
4
- import { PopUpPlacements, KbqComponentColors, PopUpSizes, KbqOption, DateAdapter, DateFormatter, KbqPseudoCheckboxState } from '@koobiq/components/core';
4
+ import { KbqPanelMaxHeight, PopUpPlacements, KbqComponentColors, PopUpSizes, KbqOption, DateAdapter, DateFormatter, KbqPseudoCheckboxState } from '@koobiq/components/core';
5
5
  import { Subject, BehaviorSubject, Observable } from 'rxjs';
6
6
  import { FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';
7
7
  import { FormControl, FormGroup } from '@angular/forms';
@@ -36,8 +36,6 @@ declare abstract class KbqBasePipe<V> implements AfterViewInit {
36
36
  protected readonly elementRef: ElementRef<HTMLElement>;
37
37
  private readonly inputModalityDetector;
38
38
  private readonly document;
39
- /** Last known focus origin within the pipe. Used to preserve the keyboard focus ring on restore. */
40
- private focusOrigin;
41
39
  /**
42
40
  * Whether this pipe has been destroyed. Guards deferred (`setTimeout`) work that could otherwise
43
41
  * read view queries or mutate `data` after the pipe was removed or the filter switched.
@@ -54,6 +52,17 @@ declare abstract class KbqBasePipe<V> implements AfterViewInit {
54
52
  * own id-based `compareByValue`.
55
53
  */
56
54
  protected optionCompareWith?: (o1: KbqSelectValue | null | undefined, o2: KbqSelectValue | null | undefined) => boolean;
55
+ /**
56
+ * Values forwarded from the pipe template whose selection the user cannot remove. Only consumed by
57
+ * the multi-select pipe components; other pipe types ignore it.
58
+ */
59
+ protected lockedValues?: unknown[];
60
+ /**
61
+ * Maximum height of the dropdown panel's scrollable list, forwarded from the pipe template to the
62
+ * underlying `kbq-select` / `kbq-tree-select`. Only consumed by the select-family pipe components;
63
+ * `undefined` leaves the list at the select-family default of 256px.
64
+ */
65
+ protected panelMaxHeight?: KbqPanelMaxHeight;
57
66
  /**
58
67
  * Whether the current platform is a Mac.
59
68
  *
@@ -80,10 +89,33 @@ declare abstract class KbqBasePipe<V> implements AfterViewInit {
80
89
  onRemove(): void;
81
90
  /** clears the pipe and triggers changes */
82
91
  onClear(): void;
92
+ /**
93
+ * Value a cleared pipe is left with. Overridden by pipes that keep part of their value across a clear
94
+ * — the multi-select pipes hold on to their locked options.
95
+ *
96
+ * @docs-private
97
+ */
98
+ protected clearedValue(): V | null;
99
+ /**
100
+ * Focus origin to hand to {@link FocusMonitor} whenever this pipe moves focus programmatically, so the
101
+ * `.cdk-keyboard-focused` ring is painted for keyboard navigation only and never for a mouse-driven one.
102
+ *
103
+ * `InputModalityDetector.mostRecentModality` reflects what the user is doing *right now*, and is the
104
+ * only source that stays correct while a panel is open: panel content lives in the CDK overlay
105
+ * container, which is not a DOM descendant of the pipe host, so a focus origin captured on the host
106
+ * itself would freeze at "how the trigger was focused" and couldn't tell a click inside the panel apart
107
+ * from the keypress that opened it. The detector reacts only to `keydown`/`mousedown`/`touchstart`
108
+ * (never to hover or scroll), so merely moving the mouse cannot strip a keyboard user's ring, and it
109
+ * maps a screen reader's synthetic mousedown to `keyboard`. It falls back to `'program'` only before any
110
+ * such interaction has ever occurred on the page — at which point no ring should be shown anyway.
111
+ *
112
+ * @docs-private
113
+ */
114
+ protected get currentFocusOrigin(): NonNullable<FocusOrigin>;
83
115
  /**
84
116
  * Restores focus to the pipe's trigger button after a value is chosen or the panel closes.
85
- * Focuses via {@link FocusMonitor} with the captured origin so a keyboard-driven interaction
86
- * keeps its focus ring, while a mouse-driven one does not.
117
+ * Focuses via {@link FocusMonitor} with `currentFocusOrigin` so a keyboard-driven interaction keeps
118
+ * its focus ring, while a mouse-driven one does not.
87
119
  *
88
120
  * @docs-private
89
121
  */
@@ -166,6 +198,8 @@ declare const KBQ_FILTER_BAR_DEFAULT_CONFIGURATION: {
166
198
  customPeriodFrom: string;
167
199
  customPeriodTo: string;
168
200
  customPeriodErrorHint: string;
201
+ customPeriodMinIntervalErrorHint: string;
202
+ customPeriodMaxIntervalErrorHint: string;
169
203
  backToPeriodSelection: string;
170
204
  };
171
205
  };
@@ -218,6 +252,8 @@ declare const KBQ_FILTER_BAR_CONFIGURATION: InjectionToken<{
218
252
  customPeriodFrom: string;
219
253
  customPeriodTo: string;
220
254
  customPeriodErrorHint: string;
255
+ customPeriodMinIntervalErrorHint: string;
256
+ customPeriodMaxIntervalErrorHint: string;
221
257
  backToPeriodSelection: string;
222
258
  };
223
259
  }>;
@@ -342,6 +378,59 @@ interface KbqPipeTemplate extends Omit<KbqPipe, 'value'> {
342
378
  * is used. Ignored by other pipe types.
343
379
  */
344
380
  compareWith?: (o1: KbqSelectValue | null | undefined, o2: KbqSelectValue | null | undefined) => boolean;
381
+ /**
382
+ * Options whose selection cannot be removed by the user: they are always selected, render as
383
+ * `disabled` with a checked checkbox, and survive both "select all" toggling and clearing the pipe.
384
+ *
385
+ * Entries have the same shape as the entries of the owning pipe's `value`: `KbqSelectValue` objects
386
+ * for the `multiselect` pipe (matched with `compareWith`, falling back to the pipe's id-based
387
+ * comparator), and raw node values for the `multi-tree-select` pipe. Locking a tree branch locks its
388
+ * whole subtree. Ignored by other pipe types.
389
+ */
390
+ lockedValues?: unknown[];
391
+ /**
392
+ * Maximum height of the dropdown panel's scrollable list, in pixels, forwarded to the underlying
393
+ * `kbq-select` / `kbq-tree-select` of the `select`, `multiselect`, `tree-select` and `multi-tree-select`
394
+ * pipes. Omitting it — or passing `null` — keeps the select-family default of 256px, i.e. exactly eight
395
+ * 32px options.
396
+ *
397
+ * The cap covers the scrollable list only, and the list's own padding is added on top of it, so a
398
+ * multiple of the option height fits without a scrollbar. The pipe's search field is rendered above the
399
+ * list and adds to the panel's total height, while the "select all" row scrolls with the options and is
400
+ * counted by the cap. A value taller than the room left in the viewport is clipped by the overlay rather
401
+ * than scrolled. Ignored by other pipe types.
402
+ */
403
+ panelMaxHeight?: KbqPanelMaxHeight;
404
+ /**
405
+ * Earliest selectable instant for the `date` / `datetime` pipe custom period. Accepts any value the
406
+ * configured `DateAdapter` can deserialize (with the default Luxon adapter: an ISO-8601 string, a
407
+ * `Date`, or a `DateTime`). The `date` pipe uses only its day (pinned to the start of day). Ignored by
408
+ * other pipe types.
409
+ */
410
+ minDateTime?: unknown;
411
+ /**
412
+ * Latest selectable instant for the `date` / `datetime` pipe custom period. See
413
+ * {@link KbqPipeTemplate.minDateTime}. The `date` pipe uses only its day (pinned to the end of day).
414
+ * Ignored by other pipe types.
415
+ */
416
+ maxDateTime?: unknown;
417
+ /**
418
+ * Minimum length of the `date` / `datetime` pipe custom period (`end − start`), as a Luxon
419
+ * duration-like object, e.g. `{ days: 1 }` or `{ hours: 2 }`. When the selected period is shorter, the
420
+ * editor shows an error and disables Apply. Ignored by other pipe types.
421
+ *
422
+ * Unlike {@link KbqPipeTemplate.minDateTime}, this value is NOT deserialized through the configured
423
+ * `DateAdapter` — it is applied directly via the date value's own `.plus()`, so this option currently
424
+ * assumes the default Luxon adapter and is not portable to other `DateAdapter` implementations (e.g.
425
+ * the Moment adapter).
426
+ */
427
+ minInterval?: unknown;
428
+ /**
429
+ * Maximum length of the `date` / `datetime` pipe custom period (`end − start`). See
430
+ * {@link KbqPipeTemplate.minInterval}. When the selected period is longer, the editor shows an error and
431
+ * disables Apply. Ignored by other pipe types.
432
+ */
433
+ maxInterval?: unknown;
345
434
  }
346
435
  interface KbqSaveFilterError {
347
436
  text?: string;
@@ -403,6 +492,8 @@ declare class KbqFilterReset {
403
492
  */
404
493
  declare class KbqFilterSavePopover implements AfterViewInit {
405
494
  private readonly changeDetectorRef;
495
+ private readonly focusMonitor;
496
+ private readonly inputModalityDetector;
406
497
  /** Popover trigger owned by the parent (`KbqFilters` main button). */
407
498
  readonly popoverTrigger: _angular_core.InputSignal<KbqPopoverTrigger>;
408
499
  /** Filter bar, used for the save payload, the current filter and localized strings. */
@@ -666,6 +757,8 @@ declare class KbqFilterBar implements KbqFilterBarHost {
666
757
  customPeriodFrom: string;
667
758
  customPeriodTo: string;
668
759
  customPeriodErrorHint: string;
760
+ customPeriodMinIntervalErrorHint: string;
761
+ customPeriodMaxIntervalErrorHint: string;
669
762
  backToPeriodSelection: string;
670
763
  };
671
764
  } | null;
@@ -813,6 +906,8 @@ declare class KbqFilterRefresher {
813
906
  customPeriodFrom: string;
814
907
  customPeriodTo: string;
815
908
  customPeriodErrorHint: string;
909
+ customPeriodMinIntervalErrorHint: string;
910
+ customPeriodMaxIntervalErrorHint: string;
816
911
  backToPeriodSelection: string;
817
912
  };
818
913
  };
@@ -929,12 +1024,53 @@ declare abstract class KbqPipeDateBaseComponent<D> extends KbqBasePipe<KbqDateTi
929
1024
  protected showStartCalendar: boolean;
930
1025
  /** @docs-private */
931
1026
  protected showEndCalendar: boolean;
1027
+ /**
1028
+ * Lower bound instant applied to the calendars, date inputs and (datetime) timepickers.
1029
+ * @docs-private
1030
+ */
1031
+ protected min: any;
1032
+ /**
1033
+ * Upper bound instant applied to the calendars, date inputs and (datetime) timepickers.
1034
+ * @docs-private
1035
+ */
1036
+ protected max: any;
1037
+ /** Minimum length of the custom period (`end − start`), resolved from the template as a duration-like object. */
1038
+ private minInterval?;
1039
+ /** Maximum length of the custom period (`end − start`), resolved from the template as a duration-like object. */
1040
+ private maxInterval?;
1041
+ /** Canonical duration units (largest-first) used to render an interval limit faithfully to its config. */
1042
+ private static readonly INTERVAL_UNITS;
932
1043
  /** @docs-private */
933
1044
  readonly popover: _angular_core.Signal<KbqPopoverTrigger>;
934
1045
  /** @docs-private */
935
- readonly listSelection: _angular_core.Signal<KbqListSelection | undefined>;
1046
+ readonly listSelection: _angular_core.Signal<KbqListSelection<any> | undefined>;
936
1047
  /** @docs-private */
937
1048
  readonly returnButton: _angular_core.Signal<KbqButton>;
1049
+ /** Resolves the `minDateTime` / `maxDateTime` bounds from the pipe template matching this pipe. */
1050
+ private updateDateBounds;
1051
+ /**
1052
+ * Deserializes a `minDateTime` / `maxDateTime` template value, treating an unset (`null`/`undefined`)
1053
+ * value and an unparseable one alike as "no bound", so call sites need no own null-check.
1054
+ */
1055
+ private toValidDate;
1056
+ /**
1057
+ * Validates a `minInterval` / `maxInterval` template value, treating anything that isn't a genuine
1058
+ * duration-like object — or that resolves to an invalid or sub-second span — as "no constraint"
1059
+ * instead of letting it crash `validateInterval`/`formatInterval` downstream (both call `.plus()` on
1060
+ * it directly). A bare number is rejected too: Luxon would silently read it as milliseconds, which
1061
+ * would otherwise disable the constraint without any error (e.g. a `{ days: 5 }` typo'd as `5`).
1062
+ */
1063
+ private toValidInterval;
1064
+ /** Clamps `value` into the configured `[min, max]` bounds using full-instant comparison. */
1065
+ private clampToBounds;
1066
+ /**
1067
+ * Cross-field validator flagging the custom period when its length (`end − start`) is outside the
1068
+ * configured `[minInterval, maxInterval]`. Intervals are applied via `DateTime.plus`, so calendar units
1069
+ * (months/years) are respected; unset intervals impose no constraint.
1070
+ */
1071
+ private validateInterval;
1072
+ /** Formats a duration-like interval as a locale-aware human string via the formatter, e.g. "7 дней". */
1073
+ private formatInterval;
938
1074
  /** formatted value for period */
939
1075
  get formattedValue(): string;
940
1076
  /** Whether the current pipe is disabled. */
@@ -947,6 +1083,42 @@ declare abstract class KbqPipeDateBaseComponent<D> extends KbqBasePipe<KbqDateTi
947
1083
  get end(): D;
948
1084
  /** default object for end */
949
1085
  get defaultEnd(): D;
1086
+ /**
1087
+ * Computes the default `start`/`end` pair used when the pipe has no stored value, clamped into
1088
+ * `[min, max]` and, unlike a plain clamp, also reconciled against `[minInterval, maxInterval]`: `end`
1089
+ * is extended or shrunk to fit, falling back to pulling `start` back when `[min, max]` doesn't leave
1090
+ * enough room past `start` to satisfy `minInterval`. If `[min, max]` is itself narrower than
1091
+ * `minInterval`, the result may still violate it — that's a contradictory host configuration (the
1092
+ * same class of issue as `min` configured later than `max`), not something to further engineer around.
1093
+ */
1094
+ private computeDefaultRange;
1095
+ /**
1096
+ * Upper bound for the START date input: the earlier of the END value and the configured `max`.
1097
+ * @docs-private
1098
+ */
1099
+ get startMax(): any;
1100
+ /**
1101
+ * Whether the period is invalid specifically because it runs backwards (`start` later than `end`) —
1102
+ * the one case `customPeriodErrorHint` actually describes. Deliberately compares the values rather
1103
+ * than keying off the START control's `kbqDatepickerMax` error: `startMax` is `min(max, end)`, so that
1104
+ * error fires both for a backwards period AND for a start beyond the configured `max`, and cannot
1105
+ * tell them apart. Everything else that can invalidate a control here — a value outside
1106
+ * `[min, max]` (`kbqDatepickerMin`/`kbqDatepickerMax`, `kbqTimepickerLowerThenMin`/
1107
+ * `kbqTimepickerHigherThenMax`) or unparseable typed text (`kbqDatepickerParse`/`kbqTimepickerParse`)
1108
+ * — is left to the field's own error styling instead of being mislabelled as an ordering problem.
1109
+ * @docs-private
1110
+ */
1111
+ protected get isPeriodInverted(): boolean;
1112
+ /**
1113
+ * Localized "period too short" hint with the `minInterval` limit interpolated and locale-formatted.
1114
+ * @docs-private
1115
+ */
1116
+ get minIntervalErrorHint(): string;
1117
+ /**
1118
+ * Localized "period too long" hint with the `maxInterval` limit interpolated and locale-formatted.
1119
+ * @docs-private
1120
+ */
1121
+ get maxIntervalErrorHint(): string;
950
1122
  /** Whether the current pipe is empty. */
951
1123
  get isEmpty(): boolean;
952
1124
  ngAfterViewInit(): void;
@@ -964,6 +1136,11 @@ declare abstract class KbqPipeDateBaseComponent<D> extends KbqBasePipe<KbqDateTi
964
1136
  onFocusStartInput(): void;
965
1137
  onFocusEndInput(): void;
966
1138
  hideCalendars(): void;
1139
+ /**
1140
+ * Whether this pipe edits the time part (`datetime`) or only the date (`date`). Gates whether the
1141
+ * `minDateTime` / `maxDateTime` bounds keep their time or are pinned to day edges.
1142
+ */
1143
+ protected abstract usesTime(): boolean;
967
1144
  /** Formats the selected range for display. */
968
1145
  protected abstract formatRange(start: D, end: D): string;
969
1146
  /** Default start value used when the pipe has no stored `start`. */
@@ -976,6 +1153,7 @@ declare abstract class KbqPipeDateBaseComponent<D> extends KbqBasePipe<KbqDateTi
976
1153
  }
977
1154
 
978
1155
  declare class KbqPipeDateComponent<D> extends KbqPipeDateBaseComponent<D> {
1156
+ protected usesTime(): boolean;
979
1157
  protected formatRange(start: D, end: D): string;
980
1158
  protected getDefaultStart(): D;
981
1159
  protected getDefaultEnd(): D;
@@ -984,6 +1162,7 @@ declare class KbqPipeDateComponent<D> extends KbqPipeDateBaseComponent<D> {
984
1162
  }
985
1163
 
986
1164
  declare class KbqPipeDatetimeComponent<D> extends KbqPipeDateBaseComponent<D> {
1165
+ protected usesTime(): boolean;
987
1166
  protected formatRange(start: D, end: D): string;
988
1167
  protected getDefaultStart(): D;
989
1168
  protected getDefaultEnd(): D;
@@ -997,9 +1176,9 @@ declare class KbqPipeInputComponent extends KbqBasePipe<string | null> implement
997
1176
  /**
998
1177
  * Input control.
999
1178
  *
1000
- * Must stay nullable: `reset()` all `KbqFormField.clearValue()` and its Escape handler ever call —
1001
- * resolves to `defaultValue`, which is `null` only while `nonNullable` is unset. `{ nonNullable: true }`
1002
- * would make `reset()` yield `''` and silently break the cleaner bridge below.
1179
+ * Must stay nullable: `KbqCleaner` resets the control, and `reset()` resolves to `defaultValue`, which is
1180
+ * `null` only while `nonNullable` is unset. `{ nonNullable: true }` would make `reset()` yield `''` and silently
1181
+ * break the cleaner bridge below.
1003
1182
  */
1004
1183
  readonly control: FormControl<string | null>;
1005
1184
  /**
@@ -1048,15 +1227,24 @@ declare class KbqPipeMultiSelectComponent extends KbqBasePipe<KbqSelectValue[]>
1048
1227
  get allVisibleOptionsSelected(): boolean;
1049
1228
  /** true if all options selected */
1050
1229
  get allOptionsSelected(): boolean;
1230
+ /**
1231
+ * Selection tally restricted to the options the user can actually toggle — the one place the
1232
+ * "ignore the locked options" rule of "select all" is expressed. `null` while there is nothing to
1233
+ * tally: no options came from the pipe template yet, or the view is not up.
1234
+ */
1235
+ private get unlockedTally();
1051
1236
  get selectedAllEqualsSelectedNothing(): boolean;
1052
1237
  private get visibleOptions();
1053
1238
  private selectionAllInProgress;
1054
1239
  private readonly multiSelect;
1240
+ constructor();
1055
1241
  /** @docs-private */
1056
1242
  ngOnInit(): void;
1057
1243
  ngAfterViewInit(): void;
1058
1244
  /** @docs-private */
1059
1245
  onSelect(item: KbqSelectValue[]): void;
1246
+ /** Whether the option cannot be deselected by the user. Template-only. */
1247
+ protected isLocked(item: KbqSelectValue): boolean;
1060
1248
  /** @docs-private */
1061
1249
  onClear(): void;
1062
1250
  /** @docs-private */
@@ -1124,12 +1312,27 @@ declare class KbqPipeMultiTreeSelectComponent extends KbqTreeSelectPipeBase<KbqS
1124
1312
  get numberOfSelectedLeaves(): number;
1125
1313
  /** true if all options selected */
1126
1314
  get allOptionsSelected(): boolean;
1315
+ /**
1316
+ * Selection tally restricted to the nodes the user can actually toggle — the one place the "ignore the
1317
+ * locked nodes" rule of "select all" is expressed. `null` until the tree data has been built.
1318
+ *
1319
+ * `triggerValues` is derived from the very same selection model as `selected`, so either would do.
1320
+ */
1321
+ private get unlockedTally();
1127
1322
  get selectedAllEqualsSelectedNothing(): boolean;
1128
1323
  /** true if all visible options selected */
1129
1324
  get allVisibleOptionsSelected(): boolean;
1325
+ /** Flat nodes whose selection the user cannot remove, the subtree of a locked branch included. */
1326
+ private get lockedDataNodes();
1327
+ /**
1328
+ * Values of every locked node, the subtree of a locked branch included. Resolved once per template
1329
+ * change rather than on demand — `isEmpty` reads it on every change-detection pass.
1330
+ */
1331
+ private lockedNodeValues;
1130
1332
  private readonly multiSelect;
1131
1333
  constructor();
1132
1334
  ngOnInit(): void;
1335
+ ngAfterViewInit(): void;
1133
1336
  isNodeSelectAll(_: number, nodeData: KbqTreeSelectFlatNode): boolean;
1134
1337
  onSelect({ value: option }: {
1135
1338
  value: any;
@@ -1143,10 +1346,20 @@ declare class KbqPipeMultiTreeSelectComponent extends KbqTreeSelectPipeBase<KbqS
1143
1346
  */
1144
1347
  updateTemplates: (templates: KbqPipeTemplate[] | null) => void;
1145
1348
  onClear(): void;
1349
+ /** Clearing keeps the locked values; with none configured the pipe resets to `null` as before. */
1350
+ protected clearedValue(): KbqSelectValue[] | null;
1146
1351
  /** @docs-private */
1147
1352
  onClose(): void;
1148
1353
  /** handler for select all options in select */
1149
1354
  selectAllHandler: (event: KeyboardEvent) => void;
1355
+ /**
1356
+ * Whether the node cannot be deselected: either its own value is locked, or it descends from a locked
1357
+ * branch. Locking a branch has to lock its subtree — deselecting a child would otherwise switch the
1358
+ * locked parent's own checkbox off.
1359
+ */
1360
+ private isLockedNode;
1361
+ /** Puts back every locked node the tree's own cascades may have deselected. */
1362
+ private enforceLockedNodes;
1150
1363
  private toggleParents;
1151
1364
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqPipeMultiTreeSelectComponent, never>;
1152
1365
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqPipeMultiTreeSelectComponent, "kbq-pipe-multi-tree-select", never, {}, {}, never, never, true, never>;
@@ -1,5 +1,3 @@
1
- @use '../filter-bar-theme' as *;
2
-
3
1
  .kbq-pipe__multi-tree-select {
4
2
  .kbq-pipe__value {
5
3
  margin-inline-start: var(--kbq-size-xxs);
@@ -15,7 +13,3 @@
15
13
  height: unset;
16
14
  }
17
15
  }
18
-
19
- .kbq-pipe-multi-tree-select__panel .kbq-select__content {
20
- @include kbq-filter-bar-panel-content-max-height();
21
- }
@@ -1,5 +1,3 @@
1
- @use '../filter-bar-theme' as *;
2
-
3
1
  .kbq-pipe__multiselect {
4
2
  .kbq-pipe__value {
5
3
  margin-inline-start: var(--kbq-size-xxs);
@@ -11,7 +9,3 @@
11
9
  margin-inline-start: var(--kbq-size-xs);
12
10
  }
13
11
  }
14
-
15
- .kbq-pipe-multiselect__panel .kbq-select__content {
16
- @include kbq-filter-bar-panel-content-max-height();
17
- }
@@ -1,9 +1,3 @@
1
- @use '../filter-bar-theme' as *;
2
-
3
- .kbq-pipe-tree-select__panel .kbq-tree-select__content {
4
- @include kbq-filter-bar-panel-content-max-height();
5
- }
6
-
7
1
  .kbq-pipe__tree-select {
8
2
  .kbq-select__trigger {
9
3
  height: unset;
@@ -22,7 +22,18 @@
22
22
  .kbq-input,
23
23
  .kbq-tag-input,
24
24
  .kbq-textarea {
25
- color: var(--kbq-form-field-#{$state-name}-text);
25
+ // Private, and only for the autofill rule near the bottom of this file. The browser forces
26
+ // `color` on an autofilled control with a UA `!important` rule, so that rule has to repaint
27
+ // through `-webkit-text-fill-color` — and to do that it has to know what *this* state
28
+ // wanted. Declared in the same rule as the `color` that reads it, so one cascade decides
29
+ // both and they cannot drift apart.
30
+ // Published as a variable rather than emitting an autofill rule per state: this mixin runs
31
+ // five times, once of them nested under eight `kbq-form-field-type-*` classes, so the
32
+ // per-state form compiled to 84 selectors for two declarations — and gave a text colour a
33
+ // specificity of (0,7,0), which no consumer could override without `!important`.
34
+ --kbq-form-field-resolved-text: var(--kbq-form-field-#{$state-name}-text);
35
+
36
+ color: var(--kbq-form-field-resolved-text);
26
37
 
27
38
  &::placeholder {
28
39
  color: var(--kbq-form-field-#{$state-name}-placeholder);
@@ -42,21 +53,47 @@
42
53
  .kbq-form-field {
43
54
  @include _kbq-form-field-state(default);
44
55
 
56
+ // `color-scheme` is what stops the browser painting its own autofill highlight from the
57
+ // light palette in a dark application. It is declared once for the whole theme in
58
+ // `kbq-core-theme()`, not here: scoping it to the form field inverted nested themes, since
59
+ // both the base and the dark rule land on the same specificity and the dark one then won on
60
+ // source order under any `.kbq-dark` ancestor, however near a `.kbq-light` was.
61
+
62
+ // The browser paints its own background on an autofilled control with a UA `!important`
63
+ // declaration that no author rule can out-rank. It is suppressed rather than painted over:
64
+ // a running transition sits *above* important-UA in the cascade, so animating
65
+ // `background-color` over an absurd duration parks its used value at the control's own
66
+ // transparent background — every control here is already transparent, `.kbq-input` and
67
+ // `.kbq-tag-input` through `kbq-reset-input`, `.kbq-textarea` in its own stylesheet — and
68
+ // the container's tint shows through untouched.
69
+ // https://css-tricks.com/almanac/selectors/a/autofill/
70
+
71
+ // Painting over it instead would be wrong: the tint token is translucent, so a second coat
72
+ // on the control would make its rectangle visibly darker than the container's padding
73
+ // around it, and would still not hide the UA colour underneath.
45
74
  & .kbq-input,
46
- & .kbq-tag-input {
47
- //https://css-tricks.com/almanac/selectors/a/autofill/
48
- &:-webkit-autofill,
49
- &:-webkit-autofill:hover,
50
- &:-webkit-autofill:focus {
51
- // set as transparent to not override container background-color;
52
- --kbq-form-field-states-autofill-background: var(--kbq-background-transparent);
53
- -webkit-box-shadow: inset 0 0 0 40rem var(--kbq-form-field-states-autofill-background);
54
- -webkit-text-fill-color: var(--kbq-form-field-states-autofill-text);
55
- caret-color: var(--kbq-form-field-states-autofill-text);
56
-
57
- /* hide browser default autofill background, no matter what background color set */
58
- transition: background-color 5000s ease-in-out;
59
- background-color: var(--kbq-background-transparent) !important;
75
+ & .kbq-tag-input,
76
+ & .kbq-textarea {
77
+ // `:is()` takes a forgiving selector list, so every browser keeps whichever of the two
78
+ // spellings it knows. A plain comma list would not: one unknown pseudo-class
79
+ // invalidates the whole list.
80
+ &:is(:autofill, :-webkit-autofill) {
81
+ // Longhands rather than the shorthand, which would also reset `transition-delay`
82
+ // and `transition-timing-function`. Nothing transitions on these controls today,
83
+ // but the next thing that does should not break here.
84
+ // The duration has to outlast the page, not merely be large: a transition that
85
+ // *finishes* lands on its end value, which is the browser's own background, and
86
+ // there is no recovering it without a reload. At 5000s that happened after 83
87
+ // minutes a dashboard left open over lunch.
88
+ transition-property: background-color;
89
+ transition-duration: 600000s;
90
+
91
+ // Repaints what the state cascade resolved above, so an autofilled control that is
92
+ // also invalid or disabled still gets that state's text colour. The fallback covers
93
+ // a control outside any state block, which cannot happen today because `default`
94
+ // always runs.
95
+ -webkit-text-fill-color: var(--kbq-form-field-resolved-text, var(--kbq-form-field-default-text));
96
+ caret-color: var(--kbq-form-field-resolved-text, var(--kbq-form-field-default-text));
60
97
  }
61
98
  }
62
99
 
@@ -68,6 +105,7 @@
68
105
  }
69
106
 
70
107
  &.kbq-form-field-type-input,
108
+ &.kbq-form-field-type-input-number,
71
109
  &.kbq-form-field-type-textarea,
72
110
  &.kbq-form-field-type-timepicker,
73
111
  &.kbq-form-field-type-datepicker,
@@ -107,11 +145,29 @@
107
145
  color: var(--kbq-form-field-label-color);
108
146
  }
109
147
 
110
- // todo quick fix for bug DS-4060. Technical debt DS-4096
111
- & .kbq-form-field__container:has(:is(.kbq-input, .kbq-tag-input):-webkit-autofill),
112
- & .kbq-form-field__container:has(:is(.kbq-input, .kbq-tag-input):-webkit-autofill:hover),
113
- & .kbq-form-field__container:has(:is(.kbq-input, .kbq-tag-input):-webkit-autofill:focus) {
114
- background-color: var(--kbq-form-field-states-autofill-background) !important;
148
+ // Autofill says "the browser filled this in" and nothing more, so it contributes a tint and
149
+ // leaves every other channel — border, focus ring, text colour — to the state the field is
150
+ // actually in.
151
+
152
+ // The tint goes into `background-image` rather than `background-color`, and that is what
153
+ // makes the sentence above true. The state keeps ownership of `background-color`, the tint
154
+ // composites over whatever it resolved, and no priority conflict is possible: an invalid
155
+ // field stays error-red *and* tinted, a field in an overlay keeps its card background.
156
+ // Painting `background-color` instead is what DS-4060 did, and it needed `!important` to
157
+ // land — which is exactly why it then out-ranked error, disabled and the overlay.
158
+
159
+ // One arm, not three. The rule this replaces spelled out `:-webkit-autofill`,
160
+ // `:-webkit-autofill:hover` and `:-webkit-autofill:focus`, mirroring the UA's own selector
161
+ // list — but the extra two match the same elements as the bare pseudo-class, and nothing in
162
+ // the UA styles this container. The control rule above dropped them for the same reason.
163
+ &
164
+ .kbq-form-field__container:has(
165
+ :is(.kbq-input, .kbq-tag-input, .kbq-textarea):is(:autofill, :-webkit-autofill)
166
+ ) {
167
+ background-image: linear-gradient(
168
+ var(--kbq-form-field-states-autofill-background),
169
+ var(--kbq-form-field-states-autofill-background)
170
+ );
115
171
  }
116
172
 
117
173
  &.kbq-disabled {
@@ -20,6 +20,16 @@
20
20
  }
21
21
 
22
22
  .kbq-form-field {
23
+ // Force a single-token height, matching how the button computes its own height, so both
24
+ // round to the same pixel value. Without this, form-field's height is the sum of independently
25
+ // rounded border/padding/line-height values, which can drift 1px from the button's height after
26
+ // a resize-triggered subpixel layout recalculation, breaking the merged border line.
27
+ height: var(--kbq-form-field-size-height);
28
+
29
+ .kbq-form-field__content {
30
+ height: 100%;
31
+ }
32
+
23
33
  // set selector specifity to 0 , so focused state will override z-index
24
34
  :where(&.kbq-form-field_invalid, &.kbq-form-field_has-validate-directive.ng-invalid) {
25
35
  z-index: 2;
@@ -36,9 +36,23 @@
36
36
  --kbq-form-field-states-error-placeholder: var(--kbq-foreground-error-tertiary);
37
37
  --kbq-form-field-states-error-text: var(--kbq-foreground-error);
38
38
  --kbq-form-field-states-error-focused-focus-outline: var(--kbq-states-line-focus-error);
39
- --kbq-form-field-states-autofill-border-color: var(--kbq-states-line-focus-theme);
39
+ /* Autofill only tints the background: it is a hint that the browser filled the field, not a
40
+ state of its own, so the border, the focus ring and the text colour stay with the state that
41
+ owns them. Background is the only one of these four the component reads; the other three are
42
+ declared and no longer read, and overriding them has no effect (#DS-4096). They are kept
43
+ rather than deleted because `@koobiq/design-tokens` publishes all four names globally
44
+ anyway — removing them here would not take the names out of the CSS a consumer loads — and
45
+ upstream already marks the set `deprecated`, so it retires them on its own schedule.
46
+ This file is nominally generated by tools/tokens/build-each-component.js, but has been
47
+ hand-maintained for a long time and no npm script runs the generator. Re-running it would
48
+ revert the background below to `theme-fade` (see DS-2873) and drop the size tokens above. */
40
49
  --kbq-form-field-states-autofill-background: var(--kbq-background-theme-less);
50
+ /* No longer read: it aliased the focus colour, so a merely filled field read as focused. */
51
+ --kbq-form-field-states-autofill-border-color: var(--kbq-states-line-focus-theme);
52
+ /* No longer read, and never observable: an autofilled field has a value, so no placeholder. */
41
53
  --kbq-form-field-states-autofill-placeholder: var(--kbq-foreground-contrast-tertiary);
54
+ /* No longer read: it forced one colour on every state, which is what lost the error and
55
+ disabled text colours. The state owns the text now. */
42
56
  --kbq-form-field-states-autofill-text: var(--kbq-foreground-contrast);
43
57
  --kbq-form-field-states-disabled-border-color: var(--kbq-states-line-disabled);
44
58
  --kbq-form-field-states-disabled-background: var(--kbq-states-background-disabled);
@@ -91,6 +91,14 @@
91
91
  max-width: 100%;
92
92
  }
93
93
 
94
+ // The rule above drops the indent because the tags carry one of their own. A custom trigger
95
+ // replaces the tag list entirely, so nothing is left to provide it and the projected content
96
+ // would sit tighter to the border than a single select's value — put the indent back.
97
+ // Same specificity as the rule above, so it has to stay after it.
98
+ &:has(.kbq-select_multiple, .kbq-select_multiline):has(kbq-select-trigger, [kbq-select-trigger]) {
99
+ padding-left: var(--kbq-form-field-size-infix-left-padding);
100
+ }
101
+
94
102
  & .kbq-input,
95
103
  & .kbq-tag-input {
96
104
  padding-right: var(--kbq-form-field-size-infix-right-padding);
@@ -109,27 +117,15 @@
109
117
  &.cdk-focused,
110
118
  &.kbq-focused {
111
119
  z-index: 3;
112
-
113
- .kbq-input {
114
- &:-webkit-autofill,
115
- &:-webkit-autofill:hover,
116
- &:-webkit-autofill:focus {
117
- min-height: calc(
118
- var(--kbq-form-field-size-height) - var(--kbq-form-field-size-border-width) *
119
- 2 - var(--kbq-form-field-size-focus-outline-width) * 2
120
- );
121
-
122
- --kbq-input-size-padding-vertical: calc(
123
- var(--kbq-size-xs) - var(--kbq-form-field-size-border-width) - var(
124
- --kbq-form-field-size-focus-outline-width
125
- )
126
- );
127
-
128
- margin: var(--kbq-form-field-size-border-width) 0;
129
- }
130
- }
131
120
  }
132
121
 
122
+ // No autofill geometry here on purpose. DS-4950 shrank the autofilled control by twice the
123
+ // focus-outline width and handed the pixels back as margin, because the control's own autofill
124
+ // background was painting over the 1px ring the container draws as an inset shadow. It has
125
+ // nothing left to paint over: the control is transparent — the browser's background is
126
+ // suppressed, not replaced — and the tint lives on the container, under a shadow that is drawn
127
+ // above it. Reinstating any of it would only move the text on focus.
128
+
133
129
  &.kbq-form-field_without-borders .kbq-form-field__container,
134
130
  &.kbq-form-field_no-borders .kbq-form-field__container {
135
131
  border-color: transparent !important;