@koobiq/components 20.1.0 → 20.2.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 (120) hide show
  1. package/accordion/_accordion-theme.scss +1 -1
  2. package/accordion/accordion-tokens.scss +1 -0
  3. package/accordion/{accordion-trigger.component.scss → accordion-trigger.scss} +4 -0
  4. package/accordion/{accordion.component.scss → accordion.scss} +3 -3
  5. package/accordion/index.d.ts +215 -119
  6. package/alert/_alert-theme.scss +14 -0
  7. package/alert/alert.component.scss +24 -13
  8. package/alert/index.d.ts +63 -29
  9. package/autocomplete/autocomplete.scss +2 -1
  10. package/autocomplete/index.d.ts +35 -29
  11. package/badge/index.d.ts +2 -3
  12. package/clamped-text/index.d.ts +3 -2
  13. package/core/index.d.ts +116 -11
  14. package/core/styles/_core.scss +2 -0
  15. package/core/styles/common/_animation.scss +31 -24
  16. package/core/styles/common/_connected-overlay.scss +36 -0
  17. package/core/styles/common/_select.scss +7 -2
  18. package/dropdown/dropdown-item.scss +16 -0
  19. package/dropdown/dropdown-tokens.scss +2 -1
  20. package/dropdown/dropdown.scss +9 -0
  21. package/dropdown/index.d.ts +73 -6
  22. package/fesm2022/koobiq-components-accordion.mjs +406 -303
  23. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  24. package/fesm2022/koobiq-components-actions-panel.mjs +1 -1
  25. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  26. package/fesm2022/koobiq-components-alert.mjs +88 -48
  27. package/fesm2022/koobiq-components-alert.mjs.map +1 -1
  28. package/fesm2022/koobiq-components-app-switcher.mjs +1 -1
  29. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  30. package/fesm2022/koobiq-components-autocomplete.mjs +37 -23
  31. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  32. package/fesm2022/koobiq-components-badge.mjs +5 -4
  33. package/fesm2022/koobiq-components-badge.mjs.map +1 -1
  34. package/fesm2022/koobiq-components-breadcrumbs.mjs +1 -1
  35. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  36. package/fesm2022/koobiq-components-clamped-text.mjs +5 -0
  37. package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
  38. package/fesm2022/koobiq-components-code-block.mjs +1 -1
  39. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  40. package/fesm2022/koobiq-components-core.mjs +98 -4
  41. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  42. package/fesm2022/koobiq-components-datepicker.mjs +10 -7
  43. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  44. package/fesm2022/koobiq-components-dropdown.mjs +99 -20
  45. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  46. package/fesm2022/koobiq-components-file-upload.mjs +2 -2
  47. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  48. package/fesm2022/koobiq-components-filter-bar.mjs +203 -32
  49. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  50. package/fesm2022/koobiq-components-form-field.mjs +4 -4
  51. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  52. package/fesm2022/koobiq-components-icon.mjs +14 -5
  53. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  54. package/fesm2022/koobiq-components-inline-edit.mjs +4 -2
  55. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  56. package/fesm2022/koobiq-components-navbar.mjs +117 -22
  57. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  58. package/fesm2022/koobiq-components-notification-center.mjs +19 -4
  59. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  60. package/fesm2022/koobiq-components-popover.mjs +5 -0
  61. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  62. package/fesm2022/koobiq-components-search-expandable.mjs +43 -8
  63. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  64. package/fesm2022/koobiq-components-select.mjs +36 -45
  65. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  66. package/fesm2022/koobiq-components-split-button.mjs +3 -10
  67. package/fesm2022/koobiq-components-split-button.mjs.map +1 -1
  68. package/fesm2022/koobiq-components-tabs.mjs +29 -17
  69. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  70. package/fesm2022/koobiq-components-tags.mjs +1 -1
  71. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  72. package/fesm2022/koobiq-components-timepicker.mjs +3 -4
  73. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  74. package/fesm2022/koobiq-components-timezone.mjs +3 -5
  75. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  76. package/fesm2022/koobiq-components-toast.mjs +1 -1
  77. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  78. package/fesm2022/koobiq-components-tooltip.mjs +118 -6
  79. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  80. package/fesm2022/koobiq-components-tree-select.mjs +39 -31
  81. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  82. package/filter-bar/_filter-bar-theme.scss +0 -4
  83. package/filter-bar/filter-bar-tokens.scss +3 -0
  84. package/filter-bar/filters.scss +3 -2
  85. package/filter-bar/index.d.ts +62 -3
  86. package/filter-bar/pipes/base-pipe.scss +0 -11
  87. package/filter-bar/pipes/pipe-input.scss +10 -0
  88. package/icon/icon-button.scss +3 -1
  89. package/icon/index.d.ts +15 -2
  90. package/navbar/_navbar-item_vertical.scss +7 -5
  91. package/navbar/index.d.ts +38 -4
  92. package/navbar/navbar-brand.scss +17 -7
  93. package/notification-center/index.d.ts +2 -1
  94. package/package.json +3 -3
  95. package/prebuilt-themes/dark-theme.css +1 -1
  96. package/prebuilt-themes/light-theme.css +1 -1
  97. package/prebuilt-themes/theme.css +1 -1
  98. package/schematics/collection.json +10 -0
  99. package/schematics/migrations/alert-signals/README.md +64 -0
  100. package/schematics/migrations/alert-signals/data.js +70 -0
  101. package/schematics/migrations/alert-signals/index.js +350 -0
  102. package/schematics/migrations/alert-signals/schema.json +20 -0
  103. package/schematics/migrations/autocomplete-panel-width-auto/README.md +68 -0
  104. package/schematics/migrations/autocomplete-panel-width-auto/index.js +70 -0
  105. package/schematics/migrations/autocomplete-panel-width-auto/schema.json +15 -0
  106. package/schematics/migrations/filter-bar-signals/README.md +1 -1
  107. package/schematics/migrations.json +11 -1
  108. package/schematics/ng-add/index.js +1 -1
  109. package/schematics/utils/angular-parsing.js +11 -2
  110. package/search-expandable/index.d.ts +3 -0
  111. package/select/index.d.ts +51 -24
  112. package/tabs/_tabs-common.scss +60 -31
  113. package/tabs/_tabs-theme.scss +12 -0
  114. package/tabs/index.d.ts +2 -2
  115. package/tabs/tab-header.scss +14 -0
  116. package/tabs/tab-nav-bar.scss +4 -0
  117. package/tabs/tabs-tokens.scss +1 -0
  118. package/timezone/index.d.ts +1 -3
  119. package/tooltip/index.d.ts +73 -4
  120. package/tree-select/index.d.ts +46 -22
@@ -10,6 +10,7 @@ import { KbqDropdownTrigger } from '@koobiq/components/dropdown';
10
10
  import { KbqPopoverTrigger } from '@koobiq/components/popover';
11
11
  import { KbqSelect } from '@koobiq/components/select';
12
12
  import { KbqListSelection } from '@koobiq/components/list';
13
+ import { KbqInput } from '@koobiq/components/input';
13
14
  import { FlatTreeControl, KbqTreeFlattener, KbqTreeFlatDataSource, KbqTreeSelection, KbqTreeOption } from '@koobiq/components/tree';
14
15
  import { KbqTreeSelect } from '@koobiq/components/tree-select';
15
16
 
@@ -47,6 +48,12 @@ declare abstract class KbqBasePipe<V> implements AfterViewInit {
47
48
  protected values: any;
48
49
  /** TemplateRef for selecting an option */
49
50
  protected valueTemplate?: TemplateRef<any> | string;
51
+ /**
52
+ * Optional equality comparator forwarded from the pipe template to the underlying `kbq-select`.
53
+ * Only consumed by the select / multi-select pipe components; when unset they fall back to their
54
+ * own id-based `compareByValue`.
55
+ */
56
+ protected optionCompareWith?: (o1: KbqSelectValue | null | undefined, o2: KbqSelectValue | null | undefined) => boolean;
50
57
  /**
51
58
  * Whether the current platform is a Mac.
52
59
  *
@@ -272,6 +279,8 @@ declare const kbqFilterBarPipesProvider: () => Provider;
272
279
  declare enum KbqPipeTypes {
273
280
  ReadOnly = "readonly",
274
281
  Text = "text",
282
+ /** Renders a bare input: no popover, never opens. Commits while typing (debounced), on Enter and on blur. */
283
+ Input = "input",
275
284
  Select = "select",
276
285
  TreeSelect = "tree-select",
277
286
  MultiSelect = "multiselect",
@@ -327,6 +336,12 @@ interface KbqPipeData<V> extends KbqPipe {
327
336
  interface KbqPipeTemplate extends Omit<KbqPipe, 'value'> {
328
337
  values?: unknown[];
329
338
  valueTemplate?: TemplateRef<any> | string;
339
+ /**
340
+ * Custom equality comparator forwarded to the underlying `kbq-select` of the `select` /
341
+ * `multiselect` pipes. When omitted, the pipe's default id-based comparator (`compareByValue`)
342
+ * is used. Ignored by other pipe types.
343
+ */
344
+ compareWith?: (o1: KbqSelectValue | null | undefined, o2: KbqSelectValue | null | undefined) => boolean;
330
345
  }
331
346
  interface KbqSaveFilterError {
332
347
  text?: string;
@@ -409,7 +424,8 @@ declare class KbqFilterSavePopover implements AfterViewInit {
409
424
  /** true if saving a new filter, false if saving changes in filter */
410
425
  saveNewFilter: boolean;
411
426
  showFilterSavingError: boolean;
412
- filterSavingErrorText: string;
427
+ /** Custom error text passed to `showError()`; `null` when the locale-derived default should be used. */
428
+ private customErrorText;
413
429
  isSaving: boolean;
414
430
  /** localized data
415
431
  * @docs-private */
@@ -431,6 +447,9 @@ declare class KbqFilterSavePopover implements AfterViewInit {
431
447
  cancelButton: string;
432
448
  actionsTooltip: string;
433
449
  };
450
+ /** Filter saving error text (custom or locale-derived).
451
+ * @docs-private */
452
+ get filterSavingErrorText(): string;
434
453
  /** header of popover. Depends on the mode */
435
454
  get popoverHeader(): string;
436
455
  ngAfterViewInit(): void;
@@ -651,7 +670,9 @@ declare class KbqFilterBar implements KbqFilterBarHost {
651
670
  };
652
671
  } | null;
653
672
  /** Localized strings and configuration for the filter-bar and its pipes. */
654
- configuration: KbqFilterBarConfiguration;
673
+ get configuration(): KbqFilterBarConfiguration;
674
+ set configuration(value: KbqFilterBarConfiguration);
675
+ private readonly _configuration;
655
676
  /** @docs-private */
656
677
  readonly filters: _angular_core.Signal<KbqFilters | undefined>;
657
678
  /** @docs-private */
@@ -970,6 +991,44 @@ declare class KbqPipeDatetimeComponent<D> extends KbqPipeDateBaseComponent<D> {
970
991
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqPipeDatetimeComponent<any>, "kbq-pipe-datetime", never, {}, {}, never, never, true, never>;
971
992
  }
972
993
 
994
+ declare class KbqPipeInputComponent extends KbqBasePipe<string | null> implements OnInit {
995
+ /** @docs-private */
996
+ protected readonly input: _angular_core.Signal<KbqInput>;
997
+ /**
998
+ * Input control.
999
+ *
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.
1003
+ */
1004
+ readonly control: FormControl<string | null>;
1005
+ /**
1006
+ * Debounce in milliseconds between the last keystroke and the typed value being applied to the filter.
1007
+ * Matches `defaultEmitValueTimeout` of `kbq-search-expandable`, so both search fields of a bar feel the
1008
+ * same. `Enter` and blur apply immediately and cancel a pending apply.
1009
+ */
1010
+ debounceTime: number;
1011
+ /**
1012
+ * Minimum number of characters before typing applies the value to the filter. Anything shorter —
1013
+ * including an emptied field — is applied as `null`, so the filter never keeps text the user has
1014
+ * already erased. `Enter` and blur ignore the threshold. Set to `0` to apply every keystroke.
1015
+ */
1016
+ minLength: number;
1017
+ /** Cancels a pending debounced apply once the value has been applied (or cleared) through another path. */
1018
+ private readonly cancelPendingApply;
1019
+ /** Whether the current pipe is empty. Used for apply style modifier */
1020
+ get isEmpty(): boolean;
1021
+ ngOnInit(): void;
1022
+ /** clears the pipe and triggers changes */
1023
+ onClear(): void;
1024
+ /** focuses the input */
1025
+ open(): void;
1026
+ /** Commits a value to `data` and notifies the filter-bar. */
1027
+ private commit;
1028
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqPipeInputComponent, never>;
1029
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqPipeInputComponent, "kbq-pipe-input", never, {}, {}, never, never, true, never>;
1030
+ }
1031
+
973
1032
  declare class KbqPipeMultiSelectComponent extends KbqBasePipe<KbqSelectValue[]> implements AfterViewInit, OnInit {
974
1033
  /** control for search options */
975
1034
  readonly searchControl: FormControl<string | null>;
@@ -1161,5 +1220,5 @@ declare class KbqPipeTreeSelectComponent extends KbqTreeSelectPipeBase<KbqSelect
1161
1220
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqPipeTreeSelectComponent, "kbq-pipe-tree-select", never, {}, {}, never, never, true, never>;
1162
1221
  }
1163
1222
 
1164
- export { KBQ_FILTER_BAR_CONFIGURATION, KBQ_FILTER_BAR_DEFAULT_CONFIGURATION, KBQ_FILTER_BAR_HOST, KBQ_FILTER_BAR_PIPES, KBQ_PIPE_DATA, KbqBasePipe, KbqFilterBar, KbqFilterBarButton, KbqFilterBarModule, KbqFilterRefresher as KbqFilterBarRefresher, KbqFilterRefresher, KbqFilterReset, KbqFilterSavePopover, KbqFilters, KbqPipeAdd, KbqPipeButton, KbqPipeDateBaseComponent, KbqPipeDateComponent, KbqPipeDatetimeComponent, KbqPipeDirective, KbqPipeMinWidth, KbqPipeMultiSelectComponent, KbqPipeMultiTreeSelectComponent, KbqPipeReadonlyComponent, KbqPipeSelectComponent, KbqPipeState, KbqPipeTextComponent, KbqPipeTreeSelectComponent, KbqPipeTypes, KbqSaveFilterStatuses, KbqTreeSelectFlatNode, KbqTreeSelectPipeBase, defaultFilterBarPipes, getId, kbqBuildTree, kbqFilterBarPipesProvider };
1223
+ export { KBQ_FILTER_BAR_CONFIGURATION, KBQ_FILTER_BAR_DEFAULT_CONFIGURATION, KBQ_FILTER_BAR_HOST, KBQ_FILTER_BAR_PIPES, KBQ_PIPE_DATA, KbqBasePipe, KbqFilterBar, KbqFilterBarButton, KbqFilterBarModule, KbqFilterRefresher as KbqFilterBarRefresher, KbqFilterRefresher, KbqFilterReset, KbqFilterSavePopover, KbqFilters, KbqPipeAdd, KbqPipeButton, KbqPipeDateBaseComponent, KbqPipeDateComponent, KbqPipeDatetimeComponent, KbqPipeDirective, KbqPipeInputComponent, KbqPipeMinWidth, KbqPipeMultiSelectComponent, KbqPipeMultiTreeSelectComponent, KbqPipeReadonlyComponent, KbqPipeSelectComponent, KbqPipeState, KbqPipeTextComponent, KbqPipeTreeSelectComponent, KbqPipeTypes, KbqSaveFilterStatuses, KbqTreeSelectFlatNode, KbqTreeSelectPipeBase, defaultFilterBarPipes, getId, kbqBuildTree, kbqFilterBarPipesProvider };
1165
1224
  export type { KbqDateTimeValue, KbqFilter, KbqFilterBarConfiguration, KbqFilterBarHost, KbqPipe, KbqPipeData, KbqPipeTemplate, KbqPipeType, KbqSaveFilterError, KbqSaveFilterEvent, KbqSelectValue, KbqTreeSelectNode };
@@ -31,17 +31,6 @@
31
31
  }
32
32
  }
33
33
 
34
- .kbq-pipe__separator {
35
- z-index: 1;
36
-
37
- margin-inline-start: -1px;
38
- margin-inline-end: 0;
39
-
40
- height: var(--kbq-size-l);
41
-
42
- align-self: center;
43
- }
44
-
45
34
  .kbq-select:not(:hover, .kbq-active),
46
35
  .kbq-tree-select:not(:hover, .kbq-active),
47
36
  .kbq-button:not(:hover, .kbq-active, [disabled]) {
@@ -0,0 +1,10 @@
1
+ .kbq-pipe.kbq-pipe__input {
2
+ // Fall back like base-pipe.scss does for --kbq-filter-bar-pipe-max-width: the token is declared on
3
+ // .kbq-filter-bar, which a pipe rendered outside a bar never sees.
4
+ width: var(--kbq-filter-bar-pipe-input-width, 240px);
5
+ flex: none;
6
+
7
+ .kbq-form-field {
8
+ width: 100%;
9
+ }
10
+ }
@@ -9,7 +9,9 @@
9
9
 
10
10
  padding: var(--kbq-icon-button-size-normal-vertical-padding) var(--kbq-icon-button-size-normal-horizontal-padding);
11
11
 
12
- &.kbq-icon-button_small {
12
+ // @deprcated Will be removed in the next major release (#DS-5338)
13
+ &.kbq-icon-button_small,
14
+ &.kbq-icon-button_compact {
13
15
  padding: var(--kbq-icon-button-size-small-vertical-padding) var(--kbq-icon-button-size-small-horizontal-padding);
14
16
  }
15
17
 
package/icon/index.d.ts CHANGED
@@ -83,9 +83,22 @@ declare class KbqIcon extends KbqColorDirective implements AfterContentInit, OnC
83
83
  static ɵcmp: i0.ɵɵComponentDeclaration<KbqIcon, "[kbq-icon]", never, { "small": { "alias": "small"; "required": false; "isSignal": true; }; "autoColor": { "alias": "autoColor"; "required": false; }; "iconName": { "alias": "kbq-icon"; "required": false; }; }, {}, never, ["*"], true, never>;
84
84
  }
85
85
 
86
+ /**
87
+ * Size options for `KbqIconButton`.
88
+ * - `compact`: 16px icon with padding, 24×24px container.
89
+ * - `normal`: 24px icon, no padding.
90
+ */
91
+ type KbqIconButtonSize = 'compact' | 'normal';
86
92
  declare class KbqIconButton extends KbqIcon implements AfterViewInit, OnDestroy {
87
93
  protected readonly focusMonitor: FocusMonitor;
94
+ /** Size of the icon button. */
95
+ readonly size: i0.InputSignal<KbqIconButtonSize>;
96
+ /**
97
+ * @deprecated Use `size` input instead. Will be removed in the next major release (#DS-5338).
98
+ */
88
99
  readonly small: i0.InputSignal<boolean>;
100
+ /** @docs-private */
101
+ protected readonly isCompact: i0.Signal<boolean>;
89
102
  /** Name of an icon within a @koobiq/icons. */
90
103
  iconName: string;
91
104
  get tabindex(): any;
@@ -104,7 +117,7 @@ declare class KbqIconButton extends KbqIcon implements AfterViewInit, OnDestroy
104
117
  private runFocusMonitor;
105
118
  private stopFocusMonitor;
106
119
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqIconButton, never>;
107
- static ɵcmp: i0.ɵɵComponentDeclaration<KbqIconButton, "[kbq-icon-button]", never, { "small": { "alias": "small"; "required": false; "isSignal": true; }; "iconName": { "alias": "kbq-icon-button"; "required": false; }; "tabindex": { "alias": "tabindex"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, {}, never, ["*"], true, never>;
120
+ static ɵcmp: i0.ɵɵComponentDeclaration<KbqIconButton, "[kbq-icon-button]", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "small": { "alias": "small"; "required": false; "isSignal": true; }; "iconName": { "alias": "kbq-icon-button"; "required": false; }; "tabindex": { "alias": "tabindex"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, {}, never, ["*"], true, never>;
108
121
  static ngAcceptInputType_disabled: unknown;
109
122
  }
110
123
 
@@ -159,4 +172,4 @@ declare class KbqIconModule {
159
172
  }
160
173
 
161
174
  export { KBQ_ICONS_CONFIG, KBQ_ICON_RESOLVER, KbqIcon, KbqIconButton, KbqIconItem, KbqIconModule, KbqIconRegistry, kbqIconsDictProvider, kbqIconsProvider, kbqIconsResolverProvider };
162
- export type { KbqIconOptions, KbqIconResolver, KbqIconsConfig };
175
+ export type { KbqIconButtonSize, KbqIconOptions, KbqIconResolver, KbqIconsConfig };
@@ -55,17 +55,19 @@
55
55
  &.kbq-navbar-bento .kbq-navbar-item__title {
56
56
  margin-left: -8px;
57
57
  opacity: 0;
58
+
59
+ transition:
60
+ opacity 150ms ease-out,
61
+ margin-left 150ms ease-out;
58
62
  }
59
63
 
60
64
  &.kbq-navbar-bento:hover,
61
- &.kbq-navbar-bento.cdk-keyboard-focused {
65
+ &.kbq-navbar-bento.cdk-keyboard-focused,
66
+ &.kbq-navbar-bento.kbq-active,
67
+ &.kbq-navbar-bento.kbq-pressed {
62
68
  & .kbq-navbar-item__title {
63
69
  margin-left: 0;
64
70
  opacity: 1;
65
-
66
- transition:
67
- opacity 150ms ease-out,
68
- margin-left 150ms ease-out;
69
71
  }
70
72
  }
71
73
  }
package/navbar/index.d.ts CHANGED
@@ -31,11 +31,19 @@ declare class KbqNavbarTitle implements AfterViewInit {
31
31
  private readonly window;
32
32
  readonly hovered: Subject<boolean>;
33
33
  outerElementWidth: number;
34
- isTextOverflown: boolean;
35
34
  get text(): string;
35
+ /** Whether the text is clipped horizontally (e.g. by `text-overflow: ellipsis`). */
36
36
  get isOverflown(): boolean;
37
+ /**
38
+ * Whether the text is clipped vertically (e.g. by `-webkit-line-clamp`).
39
+ *
40
+ * Kept separate from `isOverflown` on purpose: wrapped text never exceeds its width, so only this
41
+ * check catches a clamped title. `isOverflown` is also read by `KbqNavbarItem`, whose titles are
42
+ * always `nowrap` — folding the two together would let sub-pixel line-height rounding enable
43
+ * tooltips on every navbar item.
44
+ */
45
+ get isClamped(): boolean;
37
46
  getOuterElementWidth(): number;
38
- checkTextOverflown(): void;
39
47
  ngAfterViewInit(): void;
40
48
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqNavbarTitle, never>;
41
49
  static ɵdir: i0.ɵɵDirectiveDeclaration<KbqNavbarTitle, "kbq-navbar-title, [kbq-navbar-title]", never, {}, {}, never, never, true, never>;
@@ -143,10 +151,26 @@ declare class KbqNavbarBrand extends KbqTooltipTrigger implements AfterContentIn
143
151
  protected readonly rectangleElement: KbqNavbarRectangleElement;
144
152
  /** @docs-private */
145
153
  protected readonly navbarFocusableItem: KbqNavbarFocusableItem;
154
+ private readonly isBrowser;
155
+ private readonly resizeObserver;
156
+ private readonly contentObserver;
157
+ private readonly document;
158
+ private readonly injector;
159
+ private readonly debounceInterval;
146
160
  /** @docs-private */
147
161
  readonly title: i0.Signal<KbqNavbarTitle | undefined>;
148
- /** alternative display of the brand name in two lines */
149
- readonly longTitle: i0.InputSignal<boolean>;
162
+ /** Whether the title has been measured as not fitting into a single line. */
163
+ private readonly autoLongTitle;
164
+ /**
165
+ * Alternative display of the brand name in two lines.
166
+ *
167
+ * @deprecated The mode is now detected automatically when the title does not fit into a single line.
168
+ * Leave unset for auto-detection; `true` and `false` force the mode on and off respectively.
169
+ * Will be removed in the next major release.
170
+ */
171
+ readonly longTitle: i0.InputSignal<boolean | undefined>;
172
+ /** @docs-private */
173
+ protected readonly longTitleEnabled: i0.Signal<boolean>;
150
174
  /** text that will be displayed in the tooltip. By default, the text is taken from kbq-navbar-title. */
151
175
  get collapsedText(): string;
152
176
  set collapsedText(value: string);
@@ -168,6 +192,16 @@ declare class KbqNavbarBrand extends KbqTooltipTrigger implements AfterContentIn
168
192
  constructor();
169
193
  ngAfterContentInit(): void;
170
194
  private updateTooltip;
195
+ private observeLongTitle;
196
+ private updateAutoLongTitle;
197
+ /**
198
+ * Measures whether the title fits into a single line in the *default* presentation.
199
+ *
200
+ * Removing and restoring the class within a single task is safe: the browser does not paint mid-task, and
201
+ * Angular's host binding only writes to the DOM when its value changes, which it does not here. Both rely
202
+ * on there being no CSS transition on the title - add one and this starts to flicker.
203
+ */
204
+ private measureNeedsLongTitle;
171
205
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqNavbarBrand, never>;
172
206
  static ɵcmp: i0.ɵɵComponentDeclaration<KbqNavbarBrand, "kbq-navbar-brand, [kbq-navbar-brand]", ["kbqNavbarBrand"], { "longTitle": { "alias": "longTitle"; "required": false; "isSignal": true; }; "collapsedText": { "alias": "collapsedText"; "required": false; }; }, {}, ["title"], ["*"], true, never>;
173
207
  }
@@ -46,6 +46,8 @@ a.kbq-navbar-brand {
46
46
  }
47
47
 
48
48
  & .kbq-navbar-title {
49
+ max-width: 154px;
50
+
49
51
  padding-right: var(--kbq-size-m);
50
52
  }
51
53
  }
@@ -85,14 +87,19 @@ a.kbq-navbar-brand {
85
87
  display: none !important;
86
88
  }
87
89
  }
90
+ }
88
91
 
89
- &.kbq-navbar-brand_long-title .kbq-navbar-title {
90
- display: -webkit-box;
91
-
92
- -webkit-box-orient: vertical;
93
- -webkit-line-clamp: 2;
94
- white-space: normal;
95
- }
92
+ // Must stay below the per-orientation rules: `.kbq-vertical` sets `display: block` on the title at the very
93
+ // same specificity, so moving this up lets that win and silently kills the clamp - `-webkit-line-clamp` does
94
+ // nothing without `-webkit-box`, and the title then wraps to an unbounded number of lines with no ellipsis.
95
+ // `.kbq-collapsed` still wins over it via `!important`.
96
+ .kbq-navbar-brand.kbq-navbar-brand_long-title .kbq-navbar-title {
97
+ display: -webkit-box;
98
+
99
+ -webkit-box-orient: vertical;
100
+ -webkit-line-clamp: 2;
101
+ line-clamp: 2;
102
+ white-space: normal;
96
103
  }
97
104
 
98
105
  @mixin kbq-navbar-brand-theme() {
@@ -145,8 +152,11 @@ a.kbq-navbar-brand {
145
152
  @include kbq-typography-level-to-styles-css-variables(typography, navbar-title);
146
153
  }
147
154
 
155
+ // Both orientations: two lines of the 18px/28px default would grow the navbar (48px -> 72px
156
+ // horizontally), which is what the compact type exists to prevent.
148
157
  &.kbq-navbar-brand_long-title .kbq-navbar-title {
149
158
  @include kbq-typography-level-to-styles-css-variables(typography, text-normal-strong);
159
+ line-height: 16px;
150
160
  }
151
161
  }
152
162
  }
@@ -195,7 +195,8 @@ declare class KbqNotificationCenterComponent extends KbqPopUp implements AfterVi
195
195
  * stall. Suppressed while a load is in flight, errored, or when there is nothing more to load.
196
196
  */
197
197
  private subscribeToScrolledToBottom;
198
- /** Whether the list is scrolled to within `scrolledToBottomOffset` pixels of the bottom. */
198
+ /** Whether the list is scrolled to within `scrolledToBottomOffset` pixels of the bottom.
199
+ * Sub-pixel measurement error is absorbed by `SCROLLED_TO_BOTTOM_TOLERANCE`. */
199
200
  private isScrolledToBottom;
200
201
  /** Emits `onNextPage` unless a load is already in flight, errored, or there is nothing more to load. */
201
202
  private requestNextPage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koobiq/components",
3
- "version": "20.1.0",
3
+ "version": "20.2.0",
4
4
  "description": "koobiq",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,8 +25,8 @@
25
25
  "@angular/cdk": ">=20.0.0",
26
26
  "@angular/core": ">=20.0.0",
27
27
  "@angular/forms": ">=20.0.0",
28
- "@koobiq/angular-moment-adapter": "20.1.0",
29
- "@koobiq/angular-luxon-adapter": "20.1.0",
28
+ "@koobiq/angular-moment-adapter": "20.2.0",
29
+ "@koobiq/angular-luxon-adapter": "20.2.0",
30
30
  "@koobiq/date-formatter": "^3.2.3",
31
31
  "@koobiq/icons": "^11.1.3",
32
32
  "@koobiq/design-tokens": "^3.14.0"