@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
@@ -9,11 +9,17 @@
9
9
  --kbq-list-states-hover-text-color: var(--kbq-foreground-contrast);
10
10
  --kbq-list-states-hover-icon-color: var(--kbq-icon-contrast);
11
11
  --kbq-list-states-hover-icon-button-color: var(--kbq-icon-contrast-fade);
12
+ --kbq-list-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);
12
13
  --kbq-list-states-selected-container-background: var(--kbq-background-theme-less);
13
14
  --kbq-list-multiple-states-selected-container-background: var(--kbq-background-contrast-less);
14
15
  --kbq-list-states-selected-text-color: var(--kbq-foreground-contrast);
15
16
  --kbq-list-states-selected-icon-color: var(--kbq-icon-contrast);
16
17
  --kbq-list-states-selected-icon-button-color: var(--kbq-icon-contrast-fade);
18
+ --kbq-list-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);
19
+ --kbq-list-multiple-states-selected-text-color: var(--kbq-foreground-contrast);
20
+ --kbq-list-multiple-states-selected-icon-color: var(--kbq-icon-contrast);
21
+ --kbq-list-multiple-states-selected-icon-button-color: var(--kbq-icon-contrast-fade);
22
+ --kbq-list-multiple-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);
17
23
  --kbq-list-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);
18
24
  --kbq-list-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);
19
25
  --kbq-list-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);
@@ -21,28 +27,57 @@
21
27
  --kbq-list-states-selected-hover-text-color: var(--kbq-foreground-contrast);
22
28
  --kbq-list-states-selected-hover-icon-color: var(--kbq-icon-contrast);
23
29
  --kbq-list-states-selected-hover-icon-button-color: var(--kbq-icon-contrast-fade);
30
+ --kbq-list-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);
31
+ --kbq-list-multiple-states-selected-hover-text-color: var(--kbq-foreground-contrast);
32
+ --kbq-list-multiple-states-selected-hover-icon-color: var(--kbq-icon-contrast);
33
+ --kbq-list-multiple-states-selected-hover-icon-button-color: var(--kbq-icon-contrast-fade);
34
+ --kbq-list-multiple-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);
24
35
  --kbq-list-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);
25
36
  --kbq-list-states-disabled-container-background: transparent;
26
37
  --kbq-list-states-disabled-text-color: var(--kbq-states-foreground-disabled);
27
38
  --kbq-list-states-disabled-icon-color: var(--kbq-states-icon-disabled);
28
39
  --kbq-list-states-disabled-icon-button-color: var(--kbq-states-icon-disabled);
29
40
  --kbq-list-states-disabled-caption-color: var(--kbq-states-foreground-disabled);
41
+ // The dragged clone floats over the page, so unlike an option in place it needs an opaque surface.
42
+ --kbq-list-states-dragged-container-background: var(--kbq-background-card);
43
+ --kbq-list-states-dragged-container-shadow: var(--kbq-shadow-popup);
30
44
  }
31
45
 
32
46
  .kbq-list,
33
- .kbq-list-selection {
47
+ .kbq-list-selection,
48
+ // The drag preview is inserted into `<body>`, outside any list, so it has to carry the tokens
49
+ // itself — otherwise every themed color below resolves to nothing. Both shapes of it: the clone of
50
+ // the option, and the plate of its text.
51
+ .kbq-list-option.cdk-drag-preview,
52
+ .kbq-list-drag-preview_text {
53
+ /* SIZE TOKENS — consumed by `.kbq-list-item` / `.kbq-list-option` in list.scss */
34
54
  --kbq-list-size-container-padding-left: var(--kbq-size-m);
35
55
  --kbq-list-size-container-padding-right: var(--kbq-size-m);
36
- --kbq-list-size-container-padding-vertical: var(--kbq-size-xs);
56
+ --kbq-list-size-container-padding-vertical: var(--kbq-size-xxs);
37
57
  --kbq-list-size-container-content-gap-horizontal: var(--kbq-size-s);
38
58
  --kbq-list-size-container-content-gap-vertical: var(--kbq-size-3xs);
39
59
  --kbq-list-size-container-focus-outline-width: var(--kbq-size-3xs);
40
- --kbq-list-size-header-padding-top: var(--kbq-size-s);
41
- --kbq-list-size-header-padding-bottom: var(--kbq-size-xxs);
42
- --kbq-list-size-header-padding-horizontal: var(--kbq-size-m);
43
- --kbq-list-size-subheading-padding-top: var(--kbq-size-m);
44
- --kbq-list-size-subheading-padding-bottom: var(--kbq-size-xxs);
45
- --kbq-list-size-subheading-padding-horizontal: var(--kbq-size-m);
46
60
  /* THEME TOKENS */
47
61
  @include list-theme-tokens;
48
62
  }
63
+
64
+ // Declared here rather than in `list-theme-tokens`, which is also included by the option and dropdown
65
+ // token files: the insertion indicator only ever exists on `kbq-list-selection`. The colour still
66
+ // follows the theme, because the global token it points at does.
67
+ .kbq-list-selection {
68
+ --kbq-list-size-dragged-indicator-thickness: var(--kbq-size-3xs);
69
+ --kbq-list-states-dragged-indicator-color: var(--kbq-line-theme);
70
+ }
71
+
72
+ // Also kept out of `list-theme-tokens`: only the text preview has a width of its own to cap, and only
73
+ // it is meant to let through what it covers — the clone stays on the opaque surface declared above.
74
+ // Mixed rather than taken from `--kbq-background-overlay-inverse`, which reads as a scrim and turns
75
+ // black in the dark theme; the preview is a card that lets a little through, so the card is the base.
76
+ .kbq-list-drag-preview_text {
77
+ --kbq-list-size-drag-preview-max-width: 480px;
78
+ --kbq-list-states-drag-preview-background: color-mix(
79
+ in srgb,
80
+ var(--kbq-background-card) /* color-mix only allows percentage value */ calc(var(--kbq-opacity-overlay) * 100%),
81
+ transparent
82
+ );
83
+ }
package/list/list.scss CHANGED
@@ -1,12 +1,13 @@
1
+ @use '../core/option/action-container-mixins' as action-container;
1
2
  @use '../core/styles/common/list';
2
3
  @use '../core/styles/common/vendor-prefixes';
3
4
  @use './list-theme' as theme;
4
5
 
5
- @mixin _kbq-list-item-border-radius() {
6
+ /// Squares off the corners between adjacent selected rows so a run of them reads as one block.
7
+ /// Only `.kbq-list-option` is ever selectable, hence the option-only scope.
8
+ @mixin _kbq-list-option-selected-border-radius() {
6
9
  $selectors: '.kbq-selected';
7
10
 
8
- border-radius: var(--kbq-size-border-radius);
9
-
10
11
  &:is(#{$selectors}):has(+ :is(#{$selectors})) {
11
12
  border-bottom-left-radius: unset;
12
13
  border-bottom-right-radius: unset;
@@ -24,25 +25,198 @@
24
25
  outline: none;
25
26
  }
26
27
 
28
+ // `horizontal` rebinds Left/Right arrows on the key manager; without a row layout the visual order
29
+ // would disagree with the focus order.
30
+ .kbq-list-selection_horizontal {
31
+ display: flex;
32
+ flex-direction: row;
33
+
34
+ .kbq-list-option {
35
+ flex: 0 0 auto;
36
+ }
37
+ }
38
+
39
+ // Positioning context for the drop indicator, which is the list's own last child.
40
+ .kbq-list-selection {
41
+ position: relative;
42
+ }
43
+
27
44
  .kbq-list-item,
28
45
  .kbq-list-option {
29
46
  @include vendor-prefixes.user-select(none);
30
47
  @include list.kbq-list-item-base();
31
- @include _kbq-list-item-border-radius();
48
+
49
+ // Re-declared on top of the shared base so the `--kbq-list-size-*` tokens become real override
50
+ // points. `.kbq-list-option` is guaranteed to be inside `.kbq-list-selection` (it injects it),
51
+ // but `.kbq-list-item`/`a[kbq-list-item]` has no such enforcement, so every token here falls back
52
+ // to the shared base mixin's own value in case it's ever rendered outside `.kbq-list`.
53
+ // The horizontal padding subtracts the transparent focus border so the total stays on the grid.
54
+ border-width: var(--kbq-list-size-container-focus-outline-width, var(--kbq-size-3xs));
55
+ border-radius: var(--kbq-size-border-radius);
56
+ gap: var(--kbq-list-size-container-content-gap-horizontal, var(--kbq-size-s));
57
+ padding-top: var(--kbq-list-size-container-padding-vertical, var(--kbq-size-xxs));
58
+ padding-right: calc(
59
+ var(--kbq-list-size-container-padding-right, var(--kbq-size-m)) - var(
60
+ --kbq-list-size-container-focus-outline-width,
61
+ var(--kbq-size-3xs)
62
+ )
63
+ );
64
+ padding-bottom: var(--kbq-list-size-container-padding-vertical, var(--kbq-size-xxs));
65
+ padding-left: calc(
66
+ var(--kbq-list-size-container-padding-left, var(--kbq-size-m)) - var(
67
+ --kbq-list-size-container-focus-outline-width,
68
+ var(--kbq-size-3xs)
69
+ )
70
+ );
71
+
72
+ .kbq-list-option-caption {
73
+ padding-top: var(--kbq-list-size-container-content-gap-vertical, var(--kbq-size-3xs));
74
+ }
32
75
 
33
76
  &:not(.kbq-disabled) {
34
77
  cursor: pointer;
78
+ }
79
+ }
80
+
81
+ // `cursor: grabbing` goes on the body rather than on the dragged element, which CDK hides from hit
82
+ // testing anyway: https://github.com/angular/components/blob/18.2.14/src/cdk/drag-drop/resets.scss#L14-L15
83
+ // The body alone is not enough, though: the cursor is resolved from whatever sits under the pointer, and
84
+ // during a drag that is another option, whose own `grab` outranks anything the body sets.
85
+ // Keyed on the preview because it is in the DOM for as long as the drag lasts, and unlike
86
+ // `cdk-drop-list-dragging` it is not an Angular host binding waiting on change detection. The class
87
+ // comes from `CdkDrag.previewClass`, so the hook holds whichever shape `dragPreview` gives the preview.
88
+ body:has(.kbq-list-drag-preview) {
89
+ cursor: grabbing;
90
+
91
+ // Qualified with both classes so it outranks the `kbq-list-option_grab-cursor` rule below: that one
92
+ // adds a `:not(:has())`, which counts as a class, and a row that advertises the grab would otherwise
93
+ // keep advertising it mid-drag.
94
+ .kbq-list-option.kbq-list-option_draggable,
95
+ .kbq-list-option_draggable .cdk-drag-handle {
96
+ cursor: grabbing;
97
+ }
98
+
99
+ // What is being dragged into is the list, not the row under the pointer, so a row that lights up on
100
+ // hover promises a reaction it will not deliver. Taking the options out of hit testing drops `:hover`
101
+ // and `:active` in one go, and keeps a stray click off the action button mid-drag.
102
+ .kbq-list-option {
103
+ pointer-events: none;
104
+ }
105
+
106
+ // A group header is the one thing left inside a list that still resolves a cursor of its own: it is
107
+ // not an option, so nothing takes it out of hit testing, and `.kbq-optgroup-label` sets `default`.
108
+ // The pointer crossing a header is still over the list, so it must not read as leaving it — over a
109
+ // `kbq-divider`, which sets no cursor at all, it already does not. `inherit` rather than `grabbing`
110
+ // so the header also follows the body into `no-drop` below.
111
+ .kbq-optgroup-label {
112
+ cursor: inherit;
113
+ }
35
114
 
36
- &.kbq-hovered,
37
- &:hover,
38
- &.kbq-focused,
39
- &.kbq-action-button-focused {
40
- & .kbq-action-container {
41
- display: flex;
42
- }
43
- }
115
+ // Nothing under the pointer would take the option, so stop promising a drop. Nested rather than
116
+ // written as a sibling: it has to outrank `grabbing` above on specificity, not on source order.
117
+ &:has(.kbq-list-option_drop-forbidden) {
118
+ cursor: no-drop;
44
119
  }
45
120
  }
46
121
 
122
+ // Option-only: `.kbq-selected` never lands on `.kbq-list-item`, and only options host an action container.
123
+ .kbq-list-option {
124
+ @include _kbq-list-option-selected-border-radius();
125
+ @include action-container.kbq-option-action-visibility('.kbq-list-selection.cdk-keyboard-focused');
126
+
127
+ // A projected handle is the one thing that always advertises the grab: it exists to say where the
128
+ // row can be picked up.
129
+ &.kbq-list-option_draggable .cdk-drag-handle {
130
+ cursor: grab;
131
+ }
132
+
133
+ // The row itself only advertises it when the list asks, through `dragCursor="grab"` — being
134
+ // draggable is not on its own a reason to stop looking like the selectable row it also is. Matched
135
+ // on as many classes as the rule this replaces, so the drag-time `grabbing` above keeps outranking
136
+ // it by its one element, and nothing else in the cascade shifts.
137
+ &.kbq-list-option_grab-cursor:not(:has(.cdk-drag-handle)) {
138
+ cursor: grab;
139
+ }
140
+
141
+ // The row the drag started from keeps its slot. `cdk-drag-anchor` is the clone CDK leaves behind
142
+ // once the option has been dragged into a connected list.
143
+ &.cdk-drag-placeholder,
144
+ &.cdk-drag-anchor {
145
+ opacity: var(--kbq-opacity-disabled);
146
+ }
147
+
148
+ // Hidden while the placeholder sits in a list the option was not dragged from, so that list keeps
149
+ // its layout. Toggled from `KbqListSelection` on `cdkDropListEntered`.
150
+ &.kbq-list-option_foreign-placeholder {
151
+ display: none;
152
+ }
153
+
154
+ // No `.cdk-drag-animating` transition on purpose. CDK animates the preview onto the placeholder,
155
+ // which — with sorting disabled — never leaves the slot the drag started from, so the preview
156
+ // would fly back to the origin and read as a rejected drop. With no transition declared the
157
+ // duration is 0 and CDK disposes of the preview without animating it anywhere.
158
+ }
159
+
160
+ // Marks the gap the dragged option would land in. Sorting is disabled, so the list never opens a gap
161
+ // of its own and this line is the only feedback about the target position.
162
+ .kbq-list-selection__drop-indicator {
163
+ position: absolute;
164
+ background: var(--kbq-list-states-dragged-indicator-color);
165
+ pointer-events: none;
166
+ }
167
+
168
+ .kbq-list-selection:not(.kbq-list-selection_horizontal) .kbq-list-selection__drop-indicator {
169
+ left: 0;
170
+ right: 0;
171
+ // The line straddles the gap instead of sitting below it, so it reads as "between these two rows".
172
+ top: calc(var(--kbq-list-drop-indicator-offset, 0px) - var(--kbq-list-size-dragged-indicator-thickness) / 2);
173
+ block-size: var(--kbq-list-size-dragged-indicator-thickness);
174
+ }
175
+
176
+ .kbq-list-selection_horizontal .kbq-list-selection__drop-indicator {
177
+ top: 0;
178
+ bottom: 0;
179
+ left: calc(var(--kbq-list-drop-indicator-offset, 0px) - var(--kbq-list-size-dragged-indicator-thickness) / 2);
180
+ inline-size: var(--kbq-list-size-dragged-indicator-thickness);
181
+ }
182
+
47
183
  @include theme.kbq-list-theme();
48
184
  @include theme.kbq-list-typography();
185
+
186
+ // Declared after the theme so it outranks the default state, whose background is `transparent`
187
+ // because an option normally sits on the surface of its list. The dragged clone has no such surface.
188
+ // Selected states carry a higher specificity and deliberately keep their own background.
189
+ .kbq-list-option.cdk-drag-preview {
190
+ background: var(--kbq-list-states-dragged-container-background);
191
+ box-shadow: var(--kbq-list-states-dragged-container-shadow);
192
+ }
193
+
194
+ // The default preview: a plate of the option's text rather than a clone of the row. It is inserted into
195
+ // `<body>`, so it inherits nothing from the list and carries its own tokens — the same reason the clone
196
+ // is listed in `list-tokens.scss`. No width: CDK pins the preview `position: fixed`, which already
197
+ // shrinks the box to its content, so only the maximum is worth stating. No `transition` either, for the
198
+ // same reason as the clone above — a zero duration lets CDK drop the preview instead of flying it back.
199
+ .kbq-list-drag-preview_text {
200
+ // The cap is on the plate, not on the text inside it, and the page default here is `content-box`.
201
+ box-sizing: border-box;
202
+ max-inline-size: var(--kbq-list-size-drag-preview-max-width);
203
+ border-radius: var(--kbq-size-border-radius);
204
+ padding: var(--kbq-list-size-container-padding-vertical) var(--kbq-list-size-container-padding-right)
205
+ var(--kbq-list-size-container-padding-vertical) var(--kbq-list-size-container-padding-left);
206
+ background: var(--kbq-list-states-drag-preview-background);
207
+ box-shadow: var(--kbq-list-states-dragged-container-shadow);
208
+ color: var(--kbq-list-default-text-color);
209
+
210
+ // Clamped line by line, not on the plate: a long label must not push the caption out of the box.
211
+ .kbq-list-drag-preview__label,
212
+ .kbq-list-drag-preview__caption {
213
+ overflow: hidden;
214
+ text-overflow: ellipsis;
215
+ white-space: nowrap;
216
+ }
217
+
218
+ .kbq-list-drag-preview__caption {
219
+ color: var(--kbq-list-default-caption-color);
220
+ padding-top: var(--kbq-list-size-container-content-gap-vertical);
221
+ }
222
+ }
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Provider, OnDestroy } from '@angular/core';
2
+ import { InjectionToken, OnDestroy, Provider } from '@angular/core';
3
3
  import { SafeHtml } from '@angular/platform-browser';
4
4
  import { MarkedOptions } from 'marked';
5
5
 
package/modal/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { Observable } from 'rxjs';
2
2
  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
- import * as i1 from '@angular/cdk/overlay';
4
+ import * as i1$1 from '@angular/cdk/overlay';
5
5
  import { OverlayRef, Overlay } from '@angular/cdk/overlay';
6
- import { KbqComponentColors } from '@koobiq/components/core';
6
+ import * as i1 from '@koobiq/components/core';
7
+ import { KbqComponentColors, KbqOverflowShadowState } from '@koobiq/components/core';
7
8
  import * as i2 from '@angular/cdk/a11y';
8
9
  import * as i3 from '@koobiq/components/button';
9
10
  import * as i4 from '@koobiq/components/icon';
@@ -141,6 +142,13 @@ declare class KbqModalComponent<T = any, R = any> extends KbqModalRef<T, R> impl
141
142
  maskAnimationClassMap: object | null;
142
143
  modalAnimationClassMap: object | null;
143
144
  transformOrigin: string;
145
+ /**
146
+ * Scroll-shadow state published by `KbqModalBody` when the modal content is composed
147
+ * manually (`kbq-modal-title`/`kbq-modal-body`/`kbq-modal-footer`), so the header/footer
148
+ * can render matching shadows without a direct template reference between them.
149
+ * @docs-private
150
+ */
151
+ readonly bodyOverflow: i0.WritableSignal<KbqOverflowShadowState>;
144
152
  get afterOpen(): Observable<void>;
145
153
  /** Observable alias for `kbqBeforeClose` */
146
154
  get beforeClose(): Observable<R | undefined>;
@@ -250,11 +258,20 @@ declare class KbqModalTitle {
250
258
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalTitle, never>;
251
259
  static ɵcmp: i0.ɵɵComponentDeclaration<KbqModalTitle, "[kbq-modal-title], kbq-modal-title, [kbqModalTitle]", never, {}, {}, never, ["*"], true, never>;
252
260
  }
261
+ /**
262
+ * Scrollable body of a manually composed modal (`kbqComponent`). Publishes its scroll-shadow
263
+ * state onto the modal instance so a sibling `KbqModalTitle`/`KbqModalFooter` can render the
264
+ * matching shadow, since they have no direct template reference to this element.
265
+ */
253
266
  declare class KbqModalBody {
267
+ private readonly modal;
268
+ private readonly overflowContainer;
269
+ constructor();
254
270
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalBody, never>;
255
- static ɵdir: i0.ɵɵDirectiveDeclaration<KbqModalBody, "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", never, {}, {}, never, never, true, never>;
271
+ static ɵdir: i0.ɵɵDirectiveDeclaration<KbqModalBody, "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", never, {}, {}, never, never, true, [{ directive: typeof i1.KbqOverflowShadowContainer; inputs: {}; outputs: {}; }]>;
256
272
  }
257
273
  declare class KbqModalFooter {
274
+ protected modal: KbqModalComponent<any, any>;
258
275
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalFooter, never>;
259
276
  static ɵdir: i0.ɵɵDirectiveDeclaration<KbqModalFooter, "[kbq-modal-footer], kbq-modal-footer, [kbqModalFooter]", never, {}, {}, never, never, true, never>;
260
277
  }
@@ -271,7 +288,7 @@ declare class CssUnitPipe implements PipeTransform {
271
288
 
272
289
  declare class KbqModalModule {
273
290
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqModalModule, never>;
274
- static ɵmod: i0.ɵɵNgModuleDeclaration<KbqModalModule, never, [typeof i1.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]>;
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]>;
275
292
  static ɵinj: i0.ɵɵInjectorDeclaration<KbqModalModule>;
276
293
  }
277
294
 
@@ -2,7 +2,7 @@
2
2
  --kbq-modal-size-small-width: 400px;
3
3
  --kbq-modal-size-medium-width: 640px;
4
4
  --kbq-modal-size-large-width: 960px;
5
- --kbq-modal-size-border-radius: var(--kbq-size-s);
5
+ --kbq-modal-size-border-radius: var(--kbq-size-m);
6
6
  --kbq-modal-size-header-padding-vertical: var(--kbq-size-l);
7
7
  --kbq-modal-size-header-padding-left: var(--kbq-size-xxl);
8
8
  --kbq-modal-size-header-padding-right: var(--kbq-size-6xl);
package/navbar/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as i2 from '@koobiq/components/tooltip';
4
4
  import { KbqTooltipTrigger } from '@koobiq/components/tooltip';
5
5
  import * as i1 from '@angular/cdk/a11y';
6
6
  import { FocusOrigin, FocusMonitor } from '@angular/cdk/a11y';
7
- import { KbqButtonCssStyler, KbqButton } from '@koobiq/components/button';
7
+ import { KbqButton, KbqButtonCssStyler } from '@koobiq/components/button';
8
8
  import * as _koobiq_components_core from '@koobiq/components/core';
9
9
  import { IFocusableOption, FocusKeyManager } from '@koobiq/components/core';
10
10
  import { KbqFormField } from '@koobiq/components/form-field';
@@ -43,6 +43,12 @@ declare class KbqNavbarTitle implements AfterViewInit {
43
43
  * tooltips on every navbar item.
44
44
  */
45
45
  get isClamped(): boolean;
46
+ /**
47
+ * Outer width of the title: its border box plus horizontal margins.
48
+ *
49
+ * Measured with `getBoundingClientRect()` rather than `getComputedStyle().width`, which resolves
50
+ * to the used content-box width whatever `box-sizing` says and would drop the title's padding.
51
+ */
46
52
  getOuterElementWidth(): number;
47
53
  ngAfterViewInit(): void;
48
54
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqNavbarTitle, never>;
@@ -101,6 +107,15 @@ declare class KbqNavbarRectangleElement {
101
107
  set collapsed(value: boolean);
102
108
  private _collapsed;
103
109
  readonly button: i0.Signal<KbqButtonCssStyler | undefined>;
110
+ /**
111
+ * Outer width of the item: its border box plus horizontal margins.
112
+ *
113
+ * Measured with `getBoundingClientRect()` rather than `getComputedStyle().width`, which resolves
114
+ * to the used content-box width whatever `box-sizing` says. `.kbq-navbar-item` is `border-box`
115
+ * with horizontal padding, so the computed value dropped that padding from every item, while
116
+ * `KbqNavbar.width` — the figure this sum is compared against — has always been a border box.
117
+ * The navbar therefore under-counted its own content and collapsed later than it should.
118
+ */
104
119
  getOuterElementWidth(): number;
105
120
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqNavbarRectangleElement, never>;
106
121
  static ɵdir: i0.ɵɵDirectiveDeclaration<KbqNavbarRectangleElement, "kbq-navbar-item, [kbq-navbar-item], kbq-navbar-divider, kbq-navbar-brand, [kbq-navbar-brand]", never, {}, {}, ["button"], never, true, never>;
@@ -46,6 +46,12 @@ a.kbq-navbar-brand {
46
46
  }
47
47
 
48
48
  & .kbq-navbar-title {
49
+ // 154px is a raw number, and it caps the text rather than the box: the padding beside it is
50
+ // spacing towards the collapse control, not part of the budget. Under a global `border-box`
51
+ // reset in a consuming application the cap would absorb the padding and a long brand title
52
+ // would start truncating 12px earlier.
53
+ box-sizing: content-box;
54
+
49
55
  max-width: 154px;
50
56
 
51
57
  padding-right: var(--kbq-size-m);
@@ -26,6 +26,12 @@
26
26
  }
27
27
 
28
28
  & .kbq-vertical-navbar__container {
29
+ // The 1px `border-right` the theme adds belongs inside these widths, not beside them: the
30
+ // collapsed rail is `--kbq-size-6xl`, the same token this component's own `min-width` above
31
+ // is written in, so rendering it a pixel wider overshot that contract. Under `content-box`
32
+ // it measured 57px collapsed and 241px expanded.
33
+ box-sizing: border-box;
34
+
29
35
  position: relative;
30
36
 
31
37
  display: flex;
@@ -28,6 +28,12 @@
28
28
  .kbq-notification-item__icon-container {
29
29
  flex-shrink: 0;
30
30
 
31
+ // The size below is the icon itself and the padding only positions it, so the two must not share
32
+ // a box. Under a global `border-box` reset in a consuming application the padding would be
33
+ // subtracted from the icon instead of added around it, and `max-width`/`max-height` would clamp
34
+ // what is left — a 16px icon squeezed into 4px wide and 2px tall.
35
+ box-sizing: content-box;
36
+
31
37
  width: var(--kbq-size-l);
32
38
  max-width: var(--kbq-size-l);
33
39
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koobiq/components",
3
- "version": "20.2.0",
3
+ "version": "20.3.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.2.0",
29
- "@koobiq/angular-luxon-adapter": "20.2.0",
28
+ "@koobiq/angular-moment-adapter": "20.3.0",
29
+ "@koobiq/angular-luxon-adapter": "20.3.0",
30
30
  "@koobiq/date-formatter": "^3.2.3",
31
31
  "@koobiq/icons": "^11.1.3",
32
32
  "@koobiq/design-tokens": "^3.14.0"
@@ -55,9 +55,6 @@
55
55
  "./prebuilt-themes/theme.css": {
56
56
  "style": "./prebuilt-themes/theme.css"
57
57
  },
58
- "./prebuilt-visual/default-visual.css": {
59
- "style": "./prebuilt-visual/default-visual.css"
60
- },
61
58
  "./package.json": {
62
59
  "default": "./package.json"
63
60
  },
@@ -1,12 +1,12 @@
1
1
  import { AnimationTriggerMetadata } from '@angular/animations';
2
2
  import * as i0 from '@angular/core';
3
- import { AfterViewInit, TemplateRef, AfterContentInit, OnInit, DestroyRef, EventEmitter, Type, ElementRef, InjectionToken } from '@angular/core';
3
+ import { InjectionToken, AfterViewInit, TemplateRef, AfterContentInit, OnInit, DestroyRef, EventEmitter, Type, ElementRef } from '@angular/core';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Subject } from 'rxjs';
6
6
  import * as i3 from '@angular/cdk/a11y';
7
7
  import { CdkTrapFocus } from '@angular/cdk/a11y';
8
8
  import * as i1 from '@angular/cdk/overlay';
9
- import { ScrollStrategy, OverlayConfig, CdkScrollable, Overlay } from '@angular/cdk/overlay';
9
+ import { ScrollStrategy, Overlay, OverlayConfig, CdkScrollable } from '@angular/cdk/overlay';
10
10
  import { KbqPopUp, KbqPopUpTrigger, KbqPopUpPlacementValues, KbqStickToWindowPlacementValues, KbqPopUpSizeValues, KbqOverflowShadowContainer, KbqComponentColors } from '@koobiq/components/core';
11
11
  import * as i2 from '@koobiq/components/button';
12
12
  import * as i4 from '@koobiq/components/icon';