@koobiq/components 20.3.1 → 20.3.3

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 (106) hide show
  1. package/accordion/accordion.scss +4 -1
  2. package/accordion/index.d.ts +36 -12
  3. package/alert/index.d.ts +8 -0
  4. package/breadcrumbs/index.d.ts +2 -0
  5. package/button-toggle/button-toggle-tokens.scss +14 -0
  6. package/button-toggle/button-toggle.scss +75 -3
  7. package/core/index.d.ts +33 -1
  8. package/core/styles/common/_select.scss +102 -4
  9. package/core/styles/typography/_typography.scss +8 -0
  10. package/ellipsis-center/index.d.ts +35 -2
  11. package/fesm2022/koobiq-components-accordion.mjs +143 -44
  12. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  13. package/fesm2022/koobiq-components-alert.mjs +17 -1
  14. package/fesm2022/koobiq-components-alert.mjs.map +1 -1
  15. package/fesm2022/koobiq-components-app-switcher.mjs +3 -2
  16. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  17. package/fesm2022/koobiq-components-autocomplete.mjs +2 -2
  18. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  19. package/fesm2022/koobiq-components-breadcrumbs.mjs +8 -3
  20. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  21. package/fesm2022/koobiq-components-button-toggle.mjs +2 -2
  22. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  23. package/fesm2022/koobiq-components-code-block.mjs +10 -5
  24. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  25. package/fesm2022/koobiq-components-core.mjs +47 -5
  26. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  27. package/fesm2022/koobiq-components-dropdown.mjs +2 -2
  28. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  29. package/fesm2022/koobiq-components-ellipsis-center.mjs +77 -22
  30. package/fesm2022/koobiq-components-ellipsis-center.mjs.map +1 -1
  31. package/fesm2022/koobiq-components-file-upload.mjs +7 -7
  32. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  33. package/fesm2022/koobiq-components-filter-bar.mjs +76 -41
  34. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  35. package/fesm2022/koobiq-components-list.mjs +3 -3
  36. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  37. package/fesm2022/koobiq-components-markdown.mjs +6 -2
  38. package/fesm2022/koobiq-components-markdown.mjs.map +1 -1
  39. package/fesm2022/koobiq-components-modal.mjs +48 -7
  40. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  41. package/fesm2022/koobiq-components-navbar.mjs +38 -12
  42. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  43. package/fesm2022/koobiq-components-notification-center.mjs +5 -4
  44. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  45. package/fesm2022/koobiq-components-popover.mjs +4 -1
  46. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-select.mjs +117 -16
  48. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-sidebar.mjs +5 -1
  50. package/fesm2022/koobiq-components-sidebar.mjs.map +1 -1
  51. package/fesm2022/koobiq-components-sidepanel.mjs +25 -6
  52. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  53. package/fesm2022/koobiq-components-tabs.mjs +7 -1
  54. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  55. package/fesm2022/koobiq-components-time-range.mjs +388 -74
  56. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-timezone.mjs +2 -2
  58. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  59. package/fesm2022/koobiq-components-title.mjs +15 -3
  60. package/fesm2022/koobiq-components-title.mjs.map +1 -1
  61. package/fesm2022/koobiq-components-tooltip.mjs +29 -4
  62. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  63. package/fesm2022/koobiq-components-tree-select.mjs +2 -2
  64. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  65. package/fesm2022/koobiq-components-tree.mjs +14 -4
  66. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  67. package/file-upload/file-upload.scss +11 -0
  68. package/file-upload/index.d.ts +1 -1
  69. package/file-upload/multiple-file-upload.component.scss +15 -3
  70. package/file-upload/single-file-upload.component.scss +10 -2
  71. package/filter-bar/filter-bar-tokens.scss +2 -1
  72. package/filter-bar/index.d.ts +25 -4
  73. package/filter-bar/pipes/base-pipe.scss +13 -6
  74. package/filter-bar/pipes/pipe-input.scss +3 -1
  75. package/link/_link-theme.scss +50 -15
  76. package/markdown/index.d.ts +2 -0
  77. package/modal/index.d.ts +16 -7
  78. package/navbar/_navbar-item_horizontal.scss +5 -0
  79. package/navbar/index.d.ts +15 -1
  80. package/navbar/navbar-brand.scss +12 -5
  81. package/notification-center/notification-item.scss +4 -1
  82. package/package.json +3 -3
  83. package/prebuilt-themes/dark-theme.css +1 -1
  84. package/prebuilt-themes/light-theme.css +1 -1
  85. package/prebuilt-themes/theme.css +1 -1
  86. package/schematics/migrations/alert-signals/index.js +4 -1
  87. package/schematics/migrations/autocomplete-panel-width-auto/index.js +3 -34
  88. package/schematics/migrations/empty-state-size-attr/index.js +3 -34
  89. package/schematics/migrations/filter-bar-signals/index.js +4 -1
  90. package/schematics/migrations/loader-overlay-size-attr/index.js +3 -34
  91. package/schematics/migrations/v20-upgrade/index.js +4 -1
  92. package/schematics/ng-add/index.js +1 -1
  93. package/schematics/utils/angular-parsing.js +11 -12
  94. package/schematics/utils/package-config.js +5 -4
  95. package/schematics/utils/typescript.js +24 -0
  96. package/select/_select-theme.scss +9 -1
  97. package/select/index.d.ts +19 -2
  98. package/select/select.scss +13 -0
  99. package/sidebar/index.d.ts +1 -0
  100. package/sidepanel/index.d.ts +9 -0
  101. package/tabs/index.d.ts +1 -0
  102. package/time-range/index.d.ts +140 -5
  103. package/time-range/time-range.scss +16 -1
  104. package/title/index.d.ts +10 -2
  105. package/tooltip/index.d.ts +13 -1
  106. package/tree/index.d.ts +1 -0
@@ -22,7 +22,16 @@
22
22
  position: relative;
23
23
  display: flex;
24
24
 
25
+ // The split point is measured against the host's own `clientWidth`, so the host must not grow to fit
26
+ // the text it is about to shorten — a shrink-to-fit host measures the full width, concludes
27
+ // everything fits, and leaves the text unsplit and overflowing. `min-width: 0` opts out of the `auto`
28
+ // minimum a flex item would otherwise inherit from the non-shrinkable end span.
29
+ max-width: 100%;
30
+ min-width: 0;
31
+ overflow: hidden;
32
+
25
33
  .kbq-ellipsis-center_data-text-start {
34
+ // The only half that shrinks, and the only one carrying `text-overflow` — unsplit text lands here.
26
35
  flex: 0 1 auto;
27
36
  overflow: hidden;
28
37
  text-overflow: ellipsis;
@@ -30,6 +39,8 @@
30
39
  }
31
40
 
32
41
  .kbq-ellipsis-center_data-text-end {
42
+ // Holds the tail the split exists to keep visible (the file extension, the trailing digits), so
43
+ // it must not shrink; the directive sizes it from the width the text actually rendered at.
33
44
  flex: 1 0 auto;
34
45
  overflow: hidden;
35
46
  white-space: pre;
@@ -129,7 +129,7 @@ declare class KbqFileList<T> {
129
129
  addArray(items: T[]): void;
130
130
  /** Replaces the current list with the specified items and emits event. */
131
131
  replace(items: T[]): void;
132
- /** Removes the first occurrence of the specified item. Returns removed items and emits event. */
132
+ /** Removes every occurrence of the specified item. Returns the removed items. */
133
133
  remove(item: T): T[];
134
134
  /** Removes item at specified index. Returns removed items and emits event. */
135
135
  removeAt(index: number): T[];
@@ -225,6 +225,13 @@
225
225
  align-items: center;
226
226
  flex: 1;
227
227
 
228
+ // The file name is rendered into `white-space: pre` spans by `kbqEllipsisCenter`, and the tail span
229
+ // is `flex-shrink: 0`. Under the default `min-width: auto` that intrinsic width propagates up
230
+ // through every flex item here, so a long name widens the row past the list instead of being
231
+ // truncated — and `kbqEllipsisCenter` measures the overflowed `clientWidth`, so it truncates to a
232
+ // width that is off-screen.
233
+ min-width: 0;
234
+
228
235
  .kbq-file-upload__grid-cell {
229
236
  padding: 0 var(--kbq-file-upload-size-multiple-big-grid-cell-padding-horizontal);
230
237
  }
@@ -235,9 +242,13 @@
235
242
  flex-grow: 1;
236
243
  gap: var(--kbq-file-upload-size-multiple-big-grid-cell-content-gap-horizontal);
237
244
  padding-left: var(--kbq-size-m);
245
+ min-width: 0;
238
246
 
239
247
  .kbq-file-item__text {
240
- width: 90%;
248
+ // Takes whatever is left between the icon and the size column. The `min-width: 0` and
249
+ // `overflow: hidden` that let it shrink below the name's intrinsic width come from
250
+ // `.kbq-ellipsis-center`, which this element also is.
251
+ flex: 1 1 auto;
241
252
  }
242
253
  }
243
254
 
@@ -253,8 +264,9 @@
253
264
  width: var(--kbq-file-upload-size-multiple-big-grid-cell-file-size-width);
254
265
  min-width: var(--kbq-file-upload-size-multiple-big-grid-cell-file-size-width);
255
266
  max-width: var(--kbq-file-upload-size-multiple-big-grid-cell-file-size-width);
256
- flex-grow: 1;
257
- flex-shrink: 1;
267
+ // The three widths above already pin the column, so growing and shrinking were both inert.
268
+ // Stated outright now that the file-name cell beside it actually shrinks.
269
+ flex: none;
258
270
  text-align: left;
259
271
  }
260
272
 
@@ -113,17 +113,25 @@
113
113
 
114
114
  .kbq-file-item {
115
115
  width: 100%;
116
+ // The row sits beside the delete button in a flex container, and the wrapper below beside the
117
+ // size column. `min-width: auto` would let the file name's intrinsic width propagate up through
118
+ // both and push the row past the component instead of being shortened — and `kbqEllipsisCenter`
119
+ // measures the overflowed `clientWidth`, so it would shorten to a width that is off-screen.
120
+ min-width: 0;
116
121
 
117
122
  .kbq-file-item__text-wrapper {
118
123
  display: flex;
119
124
  align-items: center;
120
125
  width: 100%;
126
+ min-width: 0;
121
127
 
122
128
  gap: var(--kbq-file-upload-size-single-container-content-gap-horizontal);
123
129
 
124
130
  .kbq-file-item__text {
125
- width: 120px;
126
- flex-grow: 1;
131
+ // Takes whatever is left beside the icon and the size column. The `min-width: 0` and
132
+ // `overflow: hidden` that let it shrink below the name's intrinsic width come from
133
+ // `.kbq-ellipsis-center`, which this element also is.
134
+ flex: 1 1 auto;
127
135
  }
128
136
  }
129
137
 
@@ -1,5 +1,6 @@
1
1
  .kbq-filter-bar {
2
- /* Maximum width of a pipe / filters trigger before its label truncates. */
2
+ /* Maximum width of a whole pipe, clear and remove buttons included, and of the filters trigger.
3
+ The input pipe keeps its own width. */
3
4
  --kbq-filter-bar-pipe-max-width: 320px;
4
5
  /* Fixed width of the input pipe's field. Unlike the other pipes it never shrink-wraps its
5
6
  content, so this is a width rather than a max-width. */
@@ -125,6 +125,13 @@ declare abstract class KbqBasePipe<V> implements AfterViewInit {
125
125
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqBasePipe<any>, never>;
126
126
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KbqBasePipe<any>, never, never, {}, {}, never, never, true, never>;
127
127
  }
128
+ /**
129
+ * Keeps a pipe part at its natural width while its text is shorter than `maxSymbolsForFitContent`.
130
+ *
131
+ * @deprecated A pipe lays its name and value out as two shrinkable grid tracks, which already keeps a
132
+ * short part intact; on a grid item this `min-width` only pushes the part past its track, where it is
133
+ * clipped without an ellipsis. Will be removed in the next major.
134
+ */
128
135
  declare class KbqPipeMinWidth {
129
136
  /** KbqFilterBar instance */
130
137
  protected readonly filterBar: KbqFilterBarHost | null;
@@ -293,7 +300,11 @@ interface KbqFilterBarHost {
293
300
  readonly internalFilterChanges: BehaviorSubject<KbqFilter | null>;
294
301
  /** Internal pipe-template changes. */
295
302
  readonly internalTemplatesChanges: BehaviorSubject<KbqPipeTemplate[] | null>;
296
- /** Requests opening a pipe after it is added. */
303
+ /**
304
+ * Requests that an already-added pipe open its pop-up. A one-shot command handled synchronously by the
305
+ * pipes that exist when it is dispatched, not retained state — clear it back to `null` after `next`. A
306
+ * pipe that has not been rendered yet is opened with `openOnAdd` on the pipe itself, not through this.
307
+ */
297
308
  readonly openPipe: BehaviorSubject<string | number | null>;
298
309
  /** Emits when the filter is reset. */
299
310
  readonly onResetFilter: BehaviorSubject<boolean>;
@@ -307,7 +318,11 @@ interface KbqFilterBarHost {
307
318
  * `useExisting`, so pipes `inject(KBQ_FILTER_BAR_HOST)` instead of depending on the concrete bar.
308
319
  */
309
320
  declare const KBQ_FILTER_BAR_HOST: InjectionToken<KbqFilterBarHost>;
310
- /** Injection Token for providing pipes in filter-bar */
321
+ /**
322
+ * Injection Token for providing pipes in filter-bar. Defaults to {@link defaultFilterBarPipes} so the
323
+ * standalone `KbqFilterBar` works without `KbqFilterBarModule`; override it with
324
+ * {@link kbqFilterBarPipesProvider} or a provider of your own.
325
+ */
311
326
  declare const KBQ_FILTER_BAR_PIPES: InjectionToken<Map<KbqPipeType, Type<KbqBasePipe<unknown>>>>;
312
327
  /** Utility provider for `KBQ_FILTER_BAR_PIPES`. */
313
328
  declare const kbqFilterBarPipesProvider: () => Provider;
@@ -814,7 +829,7 @@ declare class KbqFilterBar implements KbqFilterBarHost {
814
829
  readonly internalFilterChanges: BehaviorSubject<KbqFilter | null>;
815
830
  /** internal changes in templates */
816
831
  readonly internalTemplatesChanges: BehaviorSubject<KbqPipeTemplate[] | null>;
817
- /** this subject need for opens pipe after adding
832
+ /** Requests that an already-added pipe open its pop-up. See {@link KbqFilterBarHost.openPipe}.
818
833
  * @docs-private */
819
834
  readonly openPipe: BehaviorSubject<string | number | null>;
820
835
  constructor();
@@ -987,7 +1002,13 @@ declare class KbqPipeState<T> {
987
1002
  /** KbqFilterBar instance
988
1003
  * @docs-private */
989
1004
  private readonly filterBar;
990
- /** Pipe state used to calculate/update the button style. */
1005
+ /**
1006
+ * Pipe state the styled button belongs to.
1007
+ *
1008
+ * Carries the binding this directive's selector matches. Every binding passes the pipe's own `data`,
1009
+ * which is mutated in place, so this value is a constant for the life of the pipe and the style is
1010
+ * derived from `pipe.isEmpty` instead.
1011
+ */
991
1012
  readonly state: _angular_core.InputSignal<T | null>;
992
1013
  constructor();
993
1014
  private updateState;
@@ -5,27 +5,34 @@
5
5
  display: flex;
6
6
  flex-direction: row;
7
7
 
8
+ // Caps the whole pipe, clear and remove buttons included. The label's grid tracks have no
9
+ // min-content, so the trigger gives way down to its own paddings without `min-width: 0`.
10
+ max-width: var(--kbq-filter-bar-pipe-max-width, 320px);
8
11
  max-height: 32px;
9
12
 
10
13
  & .kbq-select .kbq-select__trigger {
11
14
  height: unset;
12
15
  }
13
16
 
14
- .kbq-button-wrapper {
15
- max-width: var(--kbq-filter-bar-pipe-max-width, 320px);
17
+ // The button's default slot is a flex row; a pipe puts its own two independently truncated parts
18
+ // (name + value) in there as two shrinkable grid tracks instead: as flex items they would give up
19
+ // the same percentage, which wipes out a short name long before a long value becomes unreadable.
20
+ // Qualified with `.kbq-button` on purpose: the base rule is `.kbq-button .kbq-button-text`, so a
21
+ // two-class selector would only win on source order, which differs between app bundles.
22
+ .kbq-button .kbq-button-text {
23
+ display: grid;
24
+ grid-auto-flow: column;
25
+ grid-auto-columns: minmax(0, max-content);
26
+ align-items: center;
16
27
  }
17
28
 
18
29
  .kbq-pipe__name {
19
30
  @include common.kbq-truncate-line();
20
-
21
- flex: 1 1 auto;
22
31
  }
23
32
 
24
33
  .kbq-pipe__value {
25
34
  @include common.kbq-truncate-line();
26
35
 
27
- flex: 1 1 auto;
28
-
29
36
  &:not(.kbq-pipe__value_empty) {
30
37
  margin-inline-start: 4px;
31
38
  }
@@ -1,7 +1,9 @@
1
1
  .kbq-pipe.kbq-pipe__input {
2
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.
3
+ // .kbq-filter-bar, which a pipe rendered outside a bar never sees. The width is explicit, so the cap
4
+ // every other pipe takes from that token does not apply here.
4
5
  width: var(--kbq-filter-bar-pipe-input-width, 240px);
6
+ max-width: none;
5
7
  flex: none;
6
8
 
7
9
  .kbq-form-field {
@@ -1,7 +1,33 @@
1
+ @use 'sass:string';
2
+
1
3
  @use '../core/styles/common/tokens' as *;
2
4
 
3
5
  @use './link-tokens';
4
6
 
7
+ // Unquoted, so that the joiner reaches the CSS as an escape rather than as an invisible character
8
+ $_kbq-link-word-joiner: string.unquote('"\\2060"');
9
+
10
+ // The width of a 16px icon less half a pixel: Chromium lays out a line that ends in negative letter-spacing a
11
+ // fraction wider than the max-content size it reports, so the full width would push the last word to the next
12
+ // line in a shrink-to-fit container.
13
+ $_kbq-link-trailing-icon-reserve: 15.5px;
14
+
15
+ // The gap after the text. Before an icon it is part of the reserve instead of a margin: Firefox does not always
16
+ // keep a margin together with the last word, and the icon could wrap alone again.
17
+ @mixin _kbq-link-text-end-gap($gap) {
18
+ &:not(:last-child) {
19
+ margin-right: $gap;
20
+ }
21
+
22
+ &:has(+ .kbq-icon) {
23
+ margin-right: 0;
24
+
25
+ &::after {
26
+ padding-inline-end: calc($gap + $_kbq-link-trailing-icon-reserve);
27
+ }
28
+ }
29
+ }
30
+
5
31
  @mixin kbq-link-geometry() {
6
32
  display: inline;
7
33
 
@@ -38,6 +64,21 @@
38
64
  line-height: 0;
39
65
  }
40
66
  }
67
+
68
+ // A line may break right before an icon, as before any inline-block, and neither a no-break character
69
+ // nor white-space stops that in every engine. So the text reserves room for the icon after its last
70
+ // word, glued to it by a word joiner kept out of the accessible name, and the icon moves back into that
71
+ // room: the last word and the icon fit on the line together or wrap together.
72
+ .kbq-link__text:has(+ .kbq-icon) {
73
+ &::after {
74
+ content: $_kbq-link-word-joiner;
75
+ content: $_kbq-link-word-joiner / '';
76
+ }
77
+
78
+ + .kbq-icon {
79
+ margin-inline-start: -$_kbq-link-trailing-icon-reserve;
80
+ }
81
+ }
41
82
  }
42
83
 
43
84
  &.kbq-text-with-icon .kbq-link__text {
@@ -45,9 +86,7 @@
45
86
  margin-left: var(--kbq-link-size-normal-content-padding);
46
87
  }
47
88
 
48
- &:not(:last-child) {
49
- margin-right: var(--kbq-link-size-normal-content-padding);
50
- }
89
+ @include _kbq-link-text-end-gap(var(--kbq-link-size-normal-content-padding));
51
90
  }
52
91
 
53
92
  &.kbq-link_compact {
@@ -65,9 +104,7 @@
65
104
  margin-left: var(--kbq-link-size-compact-content-padding);
66
105
  }
67
106
 
68
- &:not(:last-child) {
69
- margin-right: var(--kbq-link-size-compact-content-padding);
70
- }
107
+ @include _kbq-link-text-end-gap(var(--kbq-link-size-compact-content-padding));
71
108
  }
72
109
  }
73
110
  }
@@ -78,20 +115,18 @@
78
115
  margin-left: var(--kbq-link-size-big-content-padding);
79
116
  }
80
117
 
81
- &:not(:last-child) {
82
- margin-right: var(--kbq-link-size-big-content-padding);
83
- }
118
+ @include _kbq-link-text-end-gap(var(--kbq-link-size-big-content-padding));
84
119
  }
85
120
  }
86
121
 
87
122
  &.kbq-text-with-icon.kbq-link_external {
88
- .kbq-link__text:not(:last-child) {
89
- margin-right: 1px;
123
+ .kbq-link__text {
124
+ @include _kbq-link-text-end-gap(1px);
90
125
  }
91
126
 
92
127
  &.kbq-link_compact {
93
- .kbq-link__text:not(:last-child) {
94
- margin-right: 0;
128
+ .kbq-link__text {
129
+ @include _kbq-link-text-end-gap(0px);
95
130
  }
96
131
 
97
132
  .kbq-icon {
@@ -100,8 +135,8 @@
100
135
  }
101
136
 
102
137
  &.kbq-link_big {
103
- .kbq-link__text:not(:last-child) {
104
- margin-right: 2px;
138
+ .kbq-link__text {
139
+ @include _kbq-link-text-end-gap(2px);
105
140
  }
106
141
  }
107
142
  }
@@ -38,6 +38,8 @@ declare class KbqMarkdownModule {
38
38
 
39
39
  /**
40
40
  * Service for converting Markdown into HTML.
41
+ *
42
+ * @docs-private
41
43
  */
42
44
  declare class KbqMarkdownService {
43
45
  /**
package/modal/index.d.ts CHANGED
@@ -3,12 +3,12 @@ import * as i0 from '@angular/core';
3
3
  import { TemplateRef, Type, EventEmitter, Injector, OnInit, OnChanges, AfterViewInit, OnDestroy, ElementRef, ViewContainerRef, SimpleChanges, ComponentRef, PipeTransform, InjectionToken } from '@angular/core';
4
4
  import * as i1$1 from '@angular/cdk/overlay';
5
5
  import { OverlayRef, Overlay } from '@angular/cdk/overlay';
6
- import * as i1 from '@koobiq/components/core';
6
+ import * as i2 from '@koobiq/components/core';
7
7
  import { KbqComponentColors, KbqOverflowShadowState } from '@koobiq/components/core';
8
- import * as i2 from '@angular/cdk/a11y';
8
+ import * as i1 from '@koobiq/components/title';
9
+ import * as i2$1 from '@angular/cdk/a11y';
9
10
  import * as i3 from '@koobiq/components/button';
10
11
  import * as i4 from '@koobiq/components/icon';
11
- import * as i5 from '@koobiq/components/title';
12
12
  import * as i6 from '@angular/common';
13
13
 
14
14
  type OnClickCallback<T> = (instance: T) => (false | void | {}) | Promise<false | void | {}>;
@@ -256,7 +256,16 @@ declare abstract class KbqModalRef<C = any, R = unknown> {
256
256
  declare class KbqModalTitle {
257
257
  protected modal: KbqModalComponent<any, any>;
258
258
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalTitle, never>;
259
- static ɵcmp: i0.ɵɵComponentDeclaration<KbqModalTitle, "[kbq-modal-title], kbq-modal-title, [kbqModalTitle]", never, {}, {}, never, ["*"], true, never>;
259
+ static ɵcmp: i0.ɵɵComponentDeclaration<KbqModalTitle, "[kbq-modal-title], kbq-modal-title, [kbqModalTitle]", never, {}, {}, never, ["*", "kbq-modal-caption, [kbq-modal-caption], [kbqModalCaption]"], true, never>;
260
+ }
261
+ /**
262
+ * Caption of a manually composed modal (`kbqComponent`). Projected into the header rendered by
263
+ * `KbqModalTitle`, below the title, and clamped to two lines. The resulting markup matches the
264
+ * header of a modal created via `KbqModalService.create`.
265
+ */
266
+ declare class KbqModalCaption {
267
+ static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalCaption, never>;
268
+ static ɵcmp: i0.ɵɵComponentDeclaration<KbqModalCaption, "[kbq-modal-caption], kbq-modal-caption, [kbqModalCaption]", never, {}, {}, never, ["*"], true, [{ directive: typeof i1.KbqTitleDirective; inputs: {}; outputs: {}; }]>;
260
269
  }
261
270
  /**
262
271
  * Scrollable body of a manually composed modal (`kbqComponent`). Publishes its scroll-shadow
@@ -268,7 +277,7 @@ declare class KbqModalBody {
268
277
  private readonly overflowContainer;
269
278
  constructor();
270
279
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalBody, never>;
271
- static ɵdir: i0.ɵɵDirectiveDeclaration<KbqModalBody, "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", never, {}, {}, never, never, true, [{ directive: typeof i1.KbqOverflowShadowContainer; inputs: {}; outputs: {}; }]>;
280
+ static ɵdir: i0.ɵɵDirectiveDeclaration<KbqModalBody, "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", never, {}, {}, never, never, true, [{ directive: typeof i2.KbqOverflowShadowContainer; inputs: {}; outputs: {}; }]>;
272
281
  }
273
282
  declare class KbqModalFooter {
274
283
  protected modal: KbqModalComponent<any, any>;
@@ -288,7 +297,7 @@ declare class CssUnitPipe implements PipeTransform {
288
297
 
289
298
  declare class KbqModalModule {
290
299
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalModule, never>;
291
- static ɵmod: i0.ɵɵNgModuleDeclaration<KbqModalModule, never, [typeof i1$1.OverlayModule, typeof i2.A11yModule, typeof i3.KbqButtonModule, typeof i4.KbqIconModule, typeof i5.KbqTitleModule, typeof i6.NgTemplateOutlet, typeof KbqModalComponent, typeof KbqModalTitle, typeof KbqModalBody, typeof KbqModalFooter, typeof CssUnitPipe, typeof KbqModalMainAction], [typeof KbqModalComponent, typeof KbqModalTitle, typeof KbqModalBody, typeof KbqModalFooter, typeof KbqModalMainAction]>;
300
+ static ɵmod: i0.ɵɵNgModuleDeclaration<KbqModalModule, never, [typeof i1$1.OverlayModule, typeof i2$1.A11yModule, typeof i3.KbqButtonModule, typeof i4.KbqIconModule, typeof i1.KbqTitleModule, typeof i6.NgTemplateOutlet, typeof KbqModalComponent, typeof KbqModalTitle, typeof KbqModalCaption, typeof KbqModalBody, typeof KbqModalFooter, typeof CssUnitPipe, typeof KbqModalMainAction], [typeof KbqModalComponent, typeof KbqModalTitle, typeof KbqModalCaption, typeof KbqModalBody, typeof KbqModalFooter, typeof KbqModalMainAction]>;
292
301
  static ɵinj: i0.ɵɵInjectorDeclaration<KbqModalModule>;
293
302
  }
294
303
 
@@ -326,5 +335,5 @@ declare class KbqModalService {
326
335
  static ɵprov: i0.ɵɵInjectableDeclaration<KbqModalService>;
327
336
  }
328
337
 
329
- export { KBQ_MODAL_DATA, KbqModalBody, KbqModalComponent, KbqModalFooter, KbqModalMainAction, KbqModalModule, KbqModalRef, KbqModalService, KbqModalTitle, MODAL_ANIMATE_DURATION, ModalBuilderForService, ModalSize };
338
+ export { KBQ_MODAL_DATA, KbqModalBody, KbqModalCaption, KbqModalComponent, KbqModalFooter, KbqModalMainAction, KbqModalModule, KbqModalRef, KbqModalService, KbqModalTitle, MODAL_ANIMATE_DURATION, ModalBuilderForService, ModalSize };
330
339
  export type { ConfirmType, IModalButtonOptions, IModalOptionsForService, ModalOptions, ModalType, OnClickCallback };
@@ -19,6 +19,11 @@
19
19
 
20
20
  justify-content: center;
21
21
 
22
+ // Hit area over the margin this item is spaced with, so the highlight does not drop out between
23
+ // items (DS-2558) — the transparent pseudo-element is hit-tested as part of the item, so hover and
24
+ // click both reach it. `:after` below paints the highlight, at the item's own box. The same
25
+ // technique is written twice more: `select.item-active-area()` for a plain vertical list, and
26
+ // `--kbq-button-toggle-size-item-hit-area-*` for a group whose `gap` two neighbours have to tile.
22
27
  &:before {
23
28
  top: calc(-1 * #{var(--kbq-size-s)});
24
29
  left: calc(-1 * #{var(--kbq-size-s)});
package/navbar/index.d.ts CHANGED
@@ -74,10 +74,23 @@ declare class KbqNavbarFocusableItem implements AfterContentInit, AfterViewInit,
74
74
  get hasFocus(): boolean;
75
75
  set hasFocus(value: boolean);
76
76
  private _hasFocus;
77
- /** Whether the item is disabled. */
77
+ /** Whether the item is disabled. Also reads `true` for a decorative element, which is skipped just the same. */
78
78
  get disabled(): boolean;
79
79
  set disabled(value: boolean);
80
80
  private _disabled;
81
+ /**
82
+ * Keeps an element with nothing to interact with out of the roving focus order, without announcing or
83
+ * styling it as disabled.
84
+ *
85
+ * @internal
86
+ */
87
+ decorative: boolean;
88
+ /**
89
+ * Whether the item was disabled through `disabled`, as opposed to being decorative.
90
+ *
91
+ * @internal
92
+ */
93
+ get explicitlyDisabled(): boolean;
81
94
  get tabIndex(): number;
82
95
  ngAfterViewInit(): void;
83
96
  ngAfterContentInit(): void;
@@ -206,6 +219,7 @@ declare class KbqNavbarBrand extends KbqTooltipTrigger implements AfterContentIn
206
219
  private _collapsed;
207
220
  constructor();
208
221
  ngAfterContentInit(): void;
222
+ private preventDisabledActivation;
209
223
  private updateTooltip;
210
224
  private observeLongTitle;
211
225
  private updateAutoLongTitle;
@@ -22,7 +22,7 @@
22
22
  border-radius: var(--kbq-navbar-item-size-content-border-radius);
23
23
  }
24
24
 
25
- & .kbq-navbar-title {
25
+ &:not(.kbq-disabled) .kbq-navbar-title {
26
26
  cursor: pointer;
27
27
  }
28
28
  }
@@ -112,14 +112,21 @@ a.kbq-navbar-brand {
112
112
  .kbq-navbar-brand {
113
113
  @include navbar-theme.kbq-navbar-item(default);
114
114
 
115
+ // Explicit, or the text of an `<a>` without `href` falls back to the I-beam.
116
+ &.kbq-disabled {
117
+ cursor: default;
118
+ }
119
+
115
120
  &.kbq-navbar-brand_link {
116
- cursor: pointer;
121
+ &:not(.kbq-disabled) {
122
+ cursor: pointer;
123
+ }
117
124
 
118
125
  &:hover:not(.kbq-disabled) {
119
126
  @include navbar-theme.kbq-navbar-item(states-hover);
120
127
  }
121
128
 
122
- &.cdk-focused.cdk-keyboard-focused {
129
+ &.cdk-focused.cdk-keyboard-focused:not(.kbq-disabled) {
123
130
  outline: none;
124
131
 
125
132
  &:after {
@@ -133,13 +140,13 @@ a.kbq-navbar-brand {
133
140
  @include navbar-theme.kbq-navbar-item(states-selected);
134
141
  }
135
142
 
136
- &.kbq-vertical:hover {
143
+ &.kbq-vertical:hover:not(.kbq-disabled) {
137
144
  .kbq-navbar-logo {
138
145
  transform: scale(1.06);
139
146
  }
140
147
  }
141
148
 
142
- &.kbq-horizontal:hover {
149
+ &.kbq-horizontal:hover:not(.kbq-disabled) {
143
150
  .kbq-navbar-logo {
144
151
  z-index: 1;
145
152
  }
@@ -93,8 +93,11 @@
93
93
  margin-right: var(--kbq-size-3xs);
94
94
  }
95
95
 
96
+ // The dot keeps its width once read, or the title gains that width and rewraps under the pointer.
97
+ // Placed before the time, so the time keeps the position it had before the dot was hidden.
96
98
  &.kbq-notification-item-time_read .kbq-notification-item-time__state {
97
- display: none;
99
+ visibility: hidden;
100
+ order: -1;
98
101
  }
99
102
  }
100
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koobiq/components",
3
- "version": "20.3.1",
3
+ "version": "20.3.3",
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.3.1",
29
- "@koobiq/angular-luxon-adapter": "20.3.1",
28
+ "@koobiq/angular-moment-adapter": "20.3.3",
29
+ "@koobiq/angular-luxon-adapter": "20.3.3",
30
30
  "@koobiq/date-formatter": "^3.2.3",
31
31
  "@koobiq/icons": "^11.1.3",
32
32
  "@koobiq/design-tokens": "^3.14.0"