@koobiq/components 20.2.0 → 20.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/accordion/_accordion-theme.scss +5 -1
  2. package/accordion/accordion-tokens.scss +2 -0
  3. package/accordion/accordion-trigger.scss +6 -0
  4. package/accordion/accordion.scss +21 -0
  5. package/accordion/index.d.ts +55 -8
  6. package/actions-panel/index.d.ts +25 -13
  7. package/app-switcher/app-switcher-dropdown-app.scss +7 -5
  8. package/app-switcher/app-switcher-dropdown-site.scss +6 -4
  9. package/app-switcher/index.d.ts +41 -4
  10. package/app-switcher/kbq-app-switcher-list-item.scss +6 -8
  11. package/autocomplete/index.d.ts +24 -9
  12. package/breadcrumbs/index.d.ts +1 -1
  13. package/button/index.d.ts +2 -2
  14. package/button-toggle/button-toggle-tokens.scss +2 -0
  15. package/button-toggle/button-toggle.scss +9 -0
  16. package/button-toggle/index.d.ts +5 -0
  17. package/checkbox/index.d.ts +33 -29
  18. package/clamped-text/index.d.ts +1 -1
  19. package/code-block/index.d.ts +24 -19
  20. package/content-panel/index.d.ts +1 -1
  21. package/core/index.d.ts +1125 -199
  22. package/core/option/_action-container-mixins.scss +28 -0
  23. package/core/option/_option-theme.scss +24 -0
  24. package/core/option/action.scss +7 -0
  25. package/core/styles/_koobiq-theme.scss +2 -0
  26. package/core/styles/_tokens.scss +1 -0
  27. package/core/styles/common/_connected-overlay.scss +6 -3
  28. package/core/styles/common/_select.scss +12 -0
  29. package/core/styles/common/_tokens.scss +0 -9
  30. package/core/styles/theming/_index.scss +0 -1
  31. package/core/styles/theming/_theming.scss +34 -5
  32. package/datepicker/index.d.ts +46 -15
  33. package/dl/dl.scss +26 -0
  34. package/dl/index.d.ts +8 -1
  35. package/dropdown/_dropdown-theme.scss +28 -2
  36. package/dropdown/dropdown-item.scss +13 -0
  37. package/dropdown/dropdown.scss +7 -1
  38. package/dropdown/index.d.ts +264 -17
  39. package/dynamic-translation/index.d.ts +1 -1
  40. package/fesm2022/koobiq-components-accordion.mjs +106 -46
  41. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  42. package/fesm2022/koobiq-components-actions-panel.mjs +57 -46
  43. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  44. package/fesm2022/koobiq-components-alert.mjs +16 -16
  45. package/fesm2022/koobiq-components-app-switcher.mjs +233 -38
  46. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-autocomplete.mjs +54 -31
  48. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-badge.mjs +13 -13
  50. package/fesm2022/koobiq-components-breadcrumbs.mjs +25 -25
  51. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  52. package/fesm2022/koobiq-components-button-toggle.mjs +17 -12
  53. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  54. package/fesm2022/koobiq-components-button.mjs +25 -25
  55. package/fesm2022/koobiq-components-checkbox.mjs +69 -92
  56. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-clamped-text.mjs +13 -13
  58. package/fesm2022/koobiq-components-code-block.mjs +56 -69
  59. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  60. package/fesm2022/koobiq-components-content-panel.mjs +29 -29
  61. package/fesm2022/koobiq-components-core.mjs +2445 -789
  62. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  63. package/fesm2022/koobiq-components-datepicker.mjs +160 -121
  64. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  65. package/fesm2022/koobiq-components-divider.mjs +7 -7
  66. package/fesm2022/koobiq-components-dl.mjs +23 -15
  67. package/fesm2022/koobiq-components-dl.mjs.map +1 -1
  68. package/fesm2022/koobiq-components-dropdown.mjs +754 -155
  69. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  70. package/fesm2022/koobiq-components-dynamic-translation.mjs +13 -13
  71. package/fesm2022/koobiq-components-ellipsis-center.mjs +7 -7
  72. package/fesm2022/koobiq-components-empty-state.mjs +19 -19
  73. package/fesm2022/koobiq-components-file-upload.mjs +74 -42
  74. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  75. package/fesm2022/koobiq-components-filter-bar.mjs +605 -192
  76. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  77. package/fesm2022/koobiq-components-flag.mjs +7 -7
  78. package/fesm2022/koobiq-components-form-field.mjs +346 -158
  79. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  80. package/fesm2022/koobiq-components-icon.mjs +39 -21
  81. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  82. package/fesm2022/koobiq-components-inline-edit.mjs +172 -27
  83. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  84. package/fesm2022/koobiq-components-input.mjs +41 -24
  85. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  86. package/fesm2022/koobiq-components-link.mjs +8 -8
  87. package/fesm2022/koobiq-components-list.mjs +657 -143
  88. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  89. package/fesm2022/koobiq-components-loader-overlay.mjs +16 -16
  90. package/fesm2022/koobiq-components-markdown.mjs +14 -11
  91. package/fesm2022/koobiq-components-markdown.mjs.map +1 -1
  92. package/fesm2022/koobiq-components-modal.mjs +59 -35
  93. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  94. package/fesm2022/koobiq-components-navbar.mjs +69 -54
  95. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  96. package/fesm2022/koobiq-components-notification-center.mjs +23 -22
  97. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  98. package/fesm2022/koobiq-components-overflow-items.mjs +16 -17
  99. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  100. package/fesm2022/koobiq-components-popover.mjs +26 -21
  101. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  102. package/fesm2022/koobiq-components-progress-bar.mjs +13 -13
  103. package/fesm2022/koobiq-components-progress-spinner.mjs +13 -13
  104. package/fesm2022/koobiq-components-radio.mjs +10 -10
  105. package/fesm2022/koobiq-components-resizer.mjs +33 -14
  106. package/fesm2022/koobiq-components-resizer.mjs.map +1 -1
  107. package/fesm2022/koobiq-components-scrollbar.mjs +10 -10
  108. package/fesm2022/koobiq-components-search-expandable.mjs +7 -7
  109. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  110. package/fesm2022/koobiq-components-select.mjs +419 -106
  111. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  112. package/fesm2022/koobiq-components-sidebar.mjs +14 -14
  113. package/fesm2022/koobiq-components-sidepanel.mjs +26 -26
  114. package/fesm2022/koobiq-components-skeleton.mjs +10 -10
  115. package/fesm2022/koobiq-components-split-button.mjs +7 -7
  116. package/fesm2022/koobiq-components-splitter.mjs +17 -17
  117. package/fesm2022/koobiq-components-table.mjs +15 -13
  118. package/fesm2022/koobiq-components-table.mjs.map +1 -1
  119. package/fesm2022/koobiq-components-tabs.mjs +54 -54
  120. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  121. package/fesm2022/koobiq-components-tags.mjs +283 -122
  122. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  123. package/fesm2022/koobiq-components-textarea.mjs +13 -8
  124. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  125. package/fesm2022/koobiq-components-time-range.mjs +29 -24
  126. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  127. package/fesm2022/koobiq-components-timepicker.mjs +58 -26
  128. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  129. package/fesm2022/koobiq-components-timezone.mjs +76 -39
  130. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  131. package/fesm2022/koobiq-components-title.mjs +7 -7
  132. package/fesm2022/koobiq-components-toast.mjs +51 -26
  133. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  134. package/fesm2022/koobiq-components-toggle.mjs +72 -64
  135. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  136. package/fesm2022/koobiq-components-tooltip.mjs +115 -36
  137. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  138. package/fesm2022/koobiq-components-top-bar.mjs +13 -13
  139. package/fesm2022/koobiq-components-tree-select.mjs +189 -55
  140. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  141. package/fesm2022/koobiq-components-tree.mjs +302 -81
  142. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  143. package/fesm2022/koobiq-components-username.mjs +27 -27
  144. package/file-upload/index.d.ts +25 -6
  145. package/file-upload/multiple-file-upload.component.scss +14 -0
  146. package/filter-bar/_filter-bar-theme.scss +0 -6
  147. package/filter-bar/index.d.ts +222 -9
  148. package/filter-bar/pipes/pipe-multi-tree-select.scss +0 -6
  149. package/filter-bar/pipes/pipe-multiselect.scss +0 -6
  150. package/filter-bar/pipes/pipe-tree-select.scss +0 -6
  151. package/form-field/_form-field-theme.scss +76 -20
  152. package/form-field/fieldset.scss +10 -0
  153. package/form-field/form-field-tokens.scss +15 -1
  154. package/form-field/form-field.scss +15 -19
  155. package/form-field/index.d.ts +147 -65
  156. package/icon/index.d.ts +31 -6
  157. package/inline-edit/index.d.ts +57 -4
  158. package/inline-edit/inline-edit.scss +10 -0
  159. package/input/index.d.ts +17 -2
  160. package/list/_list-theme.scss +42 -10
  161. package/list/index.d.ts +326 -79
  162. package/list/list-tokens.scss +43 -8
  163. package/list/list.scss +186 -12
  164. package/markdown/index.d.ts +1 -1
  165. package/modal/index.d.ts +21 -4
  166. package/modal/modal-tokens.scss +1 -1
  167. package/navbar/index.d.ts +16 -1
  168. package/navbar/navbar-brand.scss +6 -0
  169. package/navbar/vertical-navbar.scss +6 -0
  170. package/notification-center/notification-item.scss +6 -0
  171. package/package.json +3 -6
  172. package/popover/index.d.ts +2 -2
  173. package/prebuilt-themes/dark-theme.css +1 -1
  174. package/prebuilt-themes/light-theme.css +1 -1
  175. package/prebuilt-themes/theme.css +1 -1
  176. package/resizer/index.d.ts +12 -0
  177. package/schematics/migrations/deprecated-icons/README.md +29 -4
  178. package/schematics/migrations/deprecated-icons/data.js +7 -0
  179. package/schematics/migrations/deprecated-icons/index.js +62 -35
  180. package/schematics/migrations/new-icons-pack/README.md +37 -2
  181. package/schematics/migrations/new-icons-pack/data.js +8 -0
  182. package/schematics/migrations/new-icons-pack/index.js +144 -53
  183. package/schematics/ng-add/index.js +3 -3
  184. package/schematics/utils/angular-parsing.js +30 -12
  185. package/schematics/utils/ast.js +31 -0
  186. package/schematics/utils/icon-migration.js +530 -0
  187. package/schematics/utils/typescript.js +44 -0
  188. package/scrollbar/index.d.ts +1 -1
  189. package/select/index.d.ts +163 -18
  190. package/select/select-tokens.scss +0 -1
  191. package/select/select.scss +0 -2
  192. package/splitter/index.d.ts +1 -1
  193. package/table/_table-theme.scss +4 -0
  194. package/table/index.d.ts +2 -1
  195. package/table/table.scss +8 -0
  196. package/tags/index.d.ts +128 -29
  197. package/textarea/index.d.ts +5 -0
  198. package/time-range/index.d.ts +1 -1
  199. package/timepicker/index.d.ts +4 -0
  200. package/timezone/index.d.ts +9 -5
  201. package/toast/index.d.ts +26 -3
  202. package/toggle/index.d.ts +34 -14
  203. package/tooltip/index.d.ts +54 -11
  204. package/tree/_tree-theme.scss +25 -5
  205. package/tree/index.d.ts +71 -3
  206. package/tree/tree-option.scss +2 -8
  207. package/tree-select/_tree-select-theme.scss +22 -0
  208. package/tree-select/index.d.ts +83 -16
  209. package/core/styles/_tokens.kbq.import.scss +0 -4
  210. package/core/styles/theming/_components-theming.scss +0 -1927
  211. package/filter-bar/pipes/pipe-select.scss +0 -5
  212. package/overflow-items/overflow-items.scss +0 -20
@@ -1,8 +1,12 @@
1
1
  @use '../core/styles/common/tokens' as *;
2
2
 
3
3
  @mixin kbq-accordion-theme() {
4
+ // Only the trigger owns the item's focus ring. `:focus-within` would also fire for header
5
+ // actions and for controls inside the expanded content, ringing a section the user is merely
6
+ // typing in. Both shapes are matched because `<kbq-accordion-header>` is optional.
4
7
  .kbq-accordion.cdk-keyboard-focused {
5
- & .kbq-accordion-item:focus-within {
8
+ & .kbq-accordion-item:has(> .kbq-accordion-trigger:focus),
9
+ & .kbq-accordion-item:has(> .kbq-accordion-header .kbq-accordion-trigger:focus) {
6
10
  border-color: var(--kbq-accordion-item-states-focus-border-color);
7
11
  }
8
12
  }
@@ -5,6 +5,8 @@
5
5
  --kbq-accordion-size-item-header-variant-hug-padding: var(--kbq-size-xs) var(--kbq-size-s) var(--kbq-size-xs)
6
6
  var(--kbq-size-m);
7
7
  --kbq-accordion-size-item-content-padding: 0px var(--kbq-size-m) var(--kbq-size-s) var(--kbq-size-m);
8
+ --kbq-accordion-size-item-header-actions-gap: var(--kbq-size-3xs);
9
+ --kbq-accordion-size-item-header-actions-padding-right: var(--kbq-size-s);
8
10
  /* THEME TOKENS */
9
11
  --kbq-accordion-item-default-background: transparent;
10
12
  --kbq-accordion-item-default-text-color: var(--kbq-foreground-contrast);
@@ -23,6 +23,8 @@
23
23
  margin-right: var(--kbq-size-s);
24
24
  }
25
25
 
26
+ // @deprecated Actions nested inside the trigger are focusable elements inside a `role="button"`.
27
+ // Put them in a `.kbq-accordion-header__actions` sibling of the trigger instead.
26
28
  & .kbq-accordion-trigger__action {
27
29
  padding: var(--kbq-size-xxs) var(--kbq-size-xxs) var(--kbq-size-3xs);
28
30
  margin-bottom: calc(-1 * #{var(--kbq-size-3xs)});
@@ -61,4 +63,8 @@
61
63
 
62
64
  button.kbq-accordion-trigger {
63
65
  flex: 1;
66
+
67
+ // A flex item floors at its min-content width by default, which would push the header actions
68
+ // past the item's right edge instead of letting a long label give way.
69
+ min-width: 0;
64
70
  }
@@ -17,6 +17,27 @@
17
17
  display: flex;
18
18
 
19
19
  height: var(--kbq-accordion-size-item-header-height);
20
+ // The height above is fixed, so a trigger label long enough to wrap would paint outside the
21
+ // header and over the item's border. Clipping keeps it inside; the trigger is a flex container,
22
+ // so `text-overflow` cannot ellipsize its text — wrap the label in an element of your own if you
23
+ // need that.
24
+ overflow: hidden;
25
+
26
+ // Interactive controls live NEXT TO the trigger, never inside it: the trigger is `role="button"`
27
+ // and nesting focusable elements in it is an accessibility violation. The trigger's `flex: 1`
28
+ // keeps the rest of the header clickable, so the actions sit flush right; their padding matches
29
+ // the trigger's own right padding, which is `--kbq-size-s` in every variant.
30
+ & > .kbq-accordion-header__actions {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: var(--kbq-accordion-size-item-header-actions-gap);
34
+
35
+ // Icon buttons have a fixed size and nothing to reflow, so the trigger — not the actions —
36
+ // is what gives way when the header runs out of room.
37
+ flex-shrink: 0;
38
+
39
+ padding-right: var(--kbq-accordion-size-item-header-actions-padding-right);
40
+ }
20
41
  }
21
42
 
22
43
  .kbq-accordion-content {
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken, AfterViewInit, OnDestroy, ChangeDetectorRef, AfterContentInit, ElementRef } from '@angular/core';
2
+ import { InjectionToken, AfterViewInit, OnDestroy, ChangeDetectorRef, AfterContentInit, ElementRef, Signal } from '@angular/core';
3
3
  import { FocusMonitor, FocusKeyManager } from '@angular/cdk/a11y';
4
4
  import { Directionality } from '@angular/cdk/bidi';
5
5
  import { UniqueSelectionDispatcher } from '@angular/cdk/collections';
@@ -70,6 +70,15 @@ declare class KbqAccordionTriggerDirective {
70
70
  * @docs-private
71
71
  */
72
72
  onFocus(): void;
73
+ /**
74
+ * Routes keyboard interaction to the accordion, but only while the trigger itself is focused.
75
+ *
76
+ * A `keydown` targets the focused element, so header actions placed next to the trigger and
77
+ * controls inside the expanded content keep their own keys — the accordion no longer toggles the
78
+ * section on Enter/Space nor moves focus to another header on the arrow keys. The `target` check
79
+ * additionally covers focusable content mistakenly nested inside the trigger.
80
+ */
81
+ onKeydown(event: KeyboardEvent): void;
73
82
  /** @docs-private */
74
83
  focus(): void;
75
84
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqAccordionTriggerDirective, never>;
@@ -100,8 +109,11 @@ declare class KbqAccordionTrigger implements AfterViewInit, OnDestroy {
100
109
 
101
110
  type KbqAccordionItemState = 'open' | 'closed';
102
111
  declare class KbqAccordionItem implements OnDestroy {
103
- /** @docs-private */
104
- protected readonly accordion: KbqAccordion;
112
+ /**
113
+ * The accordion this item belongs to — always the nearest one, because it is injected.
114
+ * The accordion reads it back to tell its own items apart from a nested accordion's.
115
+ */
116
+ readonly accordion: KbqAccordion;
105
117
  /** @docs-private */
106
118
  protected readonly changeDetectorRef: ChangeDetectorRef;
107
119
  /** @docs-private */
@@ -195,8 +207,24 @@ declare class KbqAccordion implements OnDestroy, AfterViewInit, AfterContentInit
195
207
  protected keyManager: FocusKeyManager<KbqAccordionItem>;
196
208
  /** Emits every time `openAll()` or `closeAll()` is called. @docs-private */
197
209
  readonly openCloseAllActions: Subject<boolean>;
198
- /** The accordion items projected into this accordion. @docs-private */
199
- readonly items: _angular_core.Signal<readonly any[]>;
210
+ /**
211
+ * Every item the content query matches, including those of a nested accordion.
212
+ * Use `items` instead — this one is the raw, unfiltered query.
213
+ * @docs-private
214
+ */
215
+ protected readonly allItems: Signal<readonly KbqAccordionItem[]>;
216
+ /**
217
+ * The accordion items that belong to this accordion.
218
+ *
219
+ * A descendant content query resolves against the template the tag is authored in and does not
220
+ * stop at a nested component of the same type, so `allItems` of an outer accordion also matches
221
+ * the items of an accordion rendered inside an item's content. Each item's own `accordion` is
222
+ * injected and therefore always its nearest one, which makes ownership the reliable filter.
223
+ * Without it the key manager would move focus into the nested accordion's headers, `valueChange`
224
+ * would report a nested item's value and state saving would persist it under the outer key.
225
+ * @docs-private
226
+ */
227
+ readonly items: Signal<readonly KbqAccordionItem[]>;
200
228
  /** Whether the accordion persists the expanded state of its items across reloads. Defaults to `false`. */
201
229
  readonly useStateSaving: _angular_core.InputSignalWithTransform<boolean, unknown>;
202
230
  /**
@@ -238,7 +266,7 @@ declare class KbqAccordion implements OnDestroy, AfterViewInit, AfterContentInit
238
266
  * Always an array in `multiple` mode and always a string in `single` mode — an empty string
239
267
  * when nothing is expanded, matching what `valueChange` emits.
240
268
  */
241
- readonly value: _angular_core.Signal<string | string[]>;
269
+ readonly value: Signal<string | string[]>;
242
270
  /** Emits the current value whenever the expanded state of the accordion changes. */
243
271
  readonly valueChange: _angular_core.OutputEmitterRef<string | string[]>;
244
272
  /** The unique id of this accordion. */
@@ -255,7 +283,15 @@ declare class KbqAccordion implements OnDestroy, AfterViewInit, AfterContentInit
255
283
  ngAfterContentInit(): void;
256
284
  ngAfterViewInit(): void;
257
285
  ngOnDestroy(): void;
258
- /** @docs-private */
286
+ /**
287
+ * Handles a key pressed on an item's trigger.
288
+ *
289
+ * Invoked by `KbqAccordionTriggerDirective`, not bound on the accordion host: a root listener
290
+ * also receives keys bubbling from the section content and from controls placed next to the
291
+ * trigger, and would swallow their Enter/Space and hijack their arrow keys. It would also
292
+ * activate the first item — stealing focus — the first time any key was pressed anywhere inside.
293
+ * @docs-private
294
+ */
259
295
  keydownHandler(event: KeyboardEvent): void;
260
296
  /** Opens all enabled accordion items in an accordion where `type` is `multiple`. */
261
297
  openAll(): void;
@@ -273,7 +309,7 @@ declare class KbqAccordion implements OnDestroy, AfterViewInit, AfterContentInit
273
309
  /** The key used to persist/restore state. */
274
310
  private get stateStorageKey();
275
311
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqAccordion, never>;
276
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqAccordion, "kbq-accordion, [kbq-accordion]", never, { "useStateSaving": { "alias": "useStateSaving"; "required": false; "isSignal": true; }; "stateSavingKey": { "alias": "stateSavingKey"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "level": { "alias": "level"; "required": false; "isSignal": true; }; "defaultValue": { "alias": "defaultValue"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "collapsible": { "alias": "collapsible"; "required": false; "isSignal": true; }; "valueInput": { "alias": "value"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, ["items"], ["*"], true, never>;
312
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqAccordion, "kbq-accordion, [kbq-accordion]", never, { "useStateSaving": { "alias": "useStateSaving"; "required": false; "isSignal": true; }; "stateSavingKey": { "alias": "stateSavingKey"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "level": { "alias": "level"; "required": false; "isSignal": true; }; "defaultValue": { "alias": "defaultValue"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "collapsible": { "alias": "collapsible"; "required": false; "isSignal": true; }; "valueInput": { "alias": "value"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, ["allItems"], ["*"], true, never>;
277
313
  }
278
314
 
279
315
  declare class KbqAccordionContentDirective implements AfterViewInit {
@@ -320,6 +356,17 @@ declare class KbqAccordionHeader {
320
356
  protected readonly item: KbqAccordionItem;
321
357
  /** @docs-private */
322
358
  protected readonly accordion: KbqAccordion;
359
+ /**
360
+ * Names the heading after the trigger alone.
361
+ *
362
+ * A `role="heading"` takes its name from its content, so the header actions sitting beside the
363
+ * trigger would otherwise append their own labels to it — a section titled "Profile" would be
364
+ * announced as "Profile Run More" when navigating by heading. Pointing at the trigger yields the
365
+ * announcement the WAI-ARIA APG gets by keeping the button the only element in the heading,
366
+ * which this component cannot do because the header is also the row that lays the actions out.
367
+ * @docs-private
368
+ */
369
+ protected get labelledBy(): string | null;
323
370
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqAccordionHeader, never>;
324
371
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KbqAccordionHeader, "kbq-accordion-header, [kbq-accordion-header]", never, {}, {}, never, never, true, never>;
325
372
  }
@@ -1,6 +1,6 @@
1
1
  import { Overlay, ScrollStrategy, OverlayRef, ComponentType } from '@angular/cdk/overlay';
2
2
  import * as i0 from '@angular/core';
3
- import { Injector, ElementRef, InjectionToken, Provider, OnDestroy, EventEmitter, TemplateRef } from '@angular/core';
3
+ import { InjectionToken, Injector, ElementRef, Provider, OnDestroy, EventEmitter, TemplateRef } from '@angular/core';
4
4
  import { Direction } from '@angular/cdk/bidi';
5
5
  import { CdkDialogContainer, DialogRef } from '@angular/cdk/dialog';
6
6
  import { Observable } from 'rxjs';
@@ -183,30 +183,42 @@ declare class KbqActionsPanelRef<I = unknown, R = unknown> {
183
183
  * @docs-private
184
184
  */
185
185
  containerInstance: KbqActionsPanelContainer;
186
- /** Gets an observable that is notified when the actions panel is finished closing. */
187
- get afterClosed(): Observable<R | undefined>;
188
- /** Gets an observable that emits when keydown events are targeted on the overlay. */
189
- get keydownEvents(): Observable<KeyboardEvent>;
190
- /** Gets an observable that is notified when the actions panel has opened and appeared. */
191
- get afterOpened(): Observable<void>;
186
+ private readonly afterOpenedSubject;
187
+ private readonly beforeOpenedSubject;
188
+ private readonly beforeClosedSubject;
189
+ /** Emits when keydown events are targeted on the overlay. */
190
+ readonly keydownEvents: Observable<KeyboardEvent>;
191
+ /** Emits when the actions panel starts opening, before its entrance animation plays. */
192
+ readonly beforeOpened: Observable<void>;
193
+ /** Emits when the actions panel has opened and appeared. */
194
+ readonly afterOpened: Observable<void>;
195
+ /** Emits when the actions panel starts closing, before its exit animation plays. */
196
+ readonly beforeClosed: Observable<R | undefined>;
197
+ /** Emits when the actions panel is finished closing. */
198
+ readonly afterClosed: Observable<R | undefined>;
192
199
  /**
193
- * Gets the overlay reference for the actions panel.
200
+ * Overlay reference for the actions panel.
194
201
  *
195
202
  * @docs-private
196
203
  */
197
- get overlayRef(): OverlayRef;
204
+ readonly overlayRef: OverlayRef;
198
205
  /**
199
- * Gets the ID of the actions panel.
206
+ * ID of the actions panel.
200
207
  *
201
208
  * @docs-private
202
209
  */
203
- get id(): string;
204
- private readonly _afterOpened;
210
+ readonly id: string;
205
211
  /** Result to be passed down to the `afterClosed` stream. */
206
212
  private result;
207
213
  /** Handle to the timeout that's running as a fallback in case the close animation doesn't fire. */
208
- private closeAnimationFallbackTimeout;
214
+ private closeAnimationFallbackTimeout?;
209
215
  constructor(dialogRef: DialogRef<R, I>, containerInstance: KbqActionsPanelContainer);
216
+ /**
217
+ * Opens the actions panel, playing its entrance animation.
218
+ *
219
+ * @docs-private
220
+ */
221
+ open(): void;
210
222
  /** Closes the actions panel. */
211
223
  close(result?: R): void;
212
224
  private handleAnimation;
@@ -9,7 +9,7 @@
9
9
  min-height: 50px;
10
10
 
11
11
  border-radius: var(--kbq-size-xs);
12
- // base transparent border so the .cdk-keyboard-focused border-color renders a focus ring (matches list-item-base)
12
+ // transparent border to keep the box model aligned with the other list rows (matches kbq-list-item-base)
13
13
  border: var(--kbq-size-3xs) solid transparent;
14
14
 
15
15
  @include common.user-select(none);
@@ -59,12 +59,14 @@
59
59
  color: var(--kbq-list-default-text-color);
60
60
 
61
61
  &.kbq-dropdown-item_highlighted,
62
- &:hover {
63
- background: var(--kbq-states-background-transparent-active);
62
+ &:hover,
63
+ &.cdk-keyboard-focused {
64
+ background: var(--kbq-states-background-transparent-hover);
64
65
  }
65
66
 
66
- &.cdk-keyboard-focused {
67
- border-color: var(--kbq-list-states-focused-focus-outline-color);
67
+ &:active,
68
+ &.kbq-active {
69
+ background: var(--kbq-states-background-transparent-active);
68
70
  }
69
71
 
70
72
  .kbq-app-switcher-dropdown-app__caption {
@@ -33,12 +33,14 @@
33
33
  color: var(--kbq-list-default-text-color);
34
34
 
35
35
  &.kbq-dropdown-item_highlighted,
36
- &:hover {
37
- background: var(--kbq-states-background-transparent-active);
36
+ &:hover,
37
+ &.cdk-keyboard-focused {
38
+ background: var(--kbq-states-background-transparent-hover);
38
39
  }
39
40
 
40
- &.cdk-keyboard-focused {
41
- border-color: var(--kbq-list-states-focused-focus-outline-color);
41
+ &:active,
42
+ &.kbq-active {
43
+ background: var(--kbq-states-background-transparent-active);
42
44
  }
43
45
  }
44
46
  }
@@ -1,9 +1,9 @@
1
1
  import * as rxjs from 'rxjs';
2
2
  import { Subscription } from 'rxjs';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, AfterViewInit, AfterContentInit, OnInit, TemplateRef, EventEmitter, Type } from '@angular/core';
4
+ import { InjectionToken, AfterViewInit, OnDestroy, AfterContentInit, OnInit, TemplateRef, EventEmitter, Type, QueryList } from '@angular/core';
5
5
  import * as _koobiq_components_core from '@koobiq/components/core';
6
- import { KbqPopUp, KbqPopUpTrigger, KbqPopUpPlacementValues, KbqPopUpSizeValues } from '@koobiq/components/core';
6
+ import { KbqPopUp, KbqPopUpTrigger, KbqPopUpPlacementValues, FocusKeyManager, KbqPopUpSizeValues } from '@koobiq/components/core';
7
7
  import { ScrollStrategy, Overlay, OverlayConfig, CdkScrollable } from '@angular/cdk/overlay';
8
8
  import { FormControl } from '@angular/forms';
9
9
  import { KbqDropdownTrigger, KbqDropdownItem } from '@koobiq/components/dropdown';
@@ -58,7 +58,7 @@ declare const KBQ_APP_SWITCHER_DEFAULT_CONFIGURATION: {
58
58
  /** @docs-private */
59
59
  declare const KBQ_APP_SWITCHER_CONFIGURATION: InjectionToken<unknown>;
60
60
  /** @docs-private */
61
- declare class KbqAppSwitcherComponent extends KbqPopUp implements AfterViewInit {
61
+ declare class KbqAppSwitcherComponent extends KbqPopUp implements AfterViewInit, OnDestroy {
62
62
  /** @docs-private */
63
63
  protected readonly localeService: _koobiq_components_core.KbqLocaleService | null;
64
64
  readonly externalConfiguration: unknown;
@@ -84,14 +84,49 @@ declare class KbqAppSwitcherComponent extends KbqPopUp implements AfterViewInit
84
84
  readonly input: i0.Signal<KbqInput | undefined>;
85
85
  /** @docs-private */
86
86
  readonly otherSites: i0.Signal<KbqDropdownTrigger>;
87
+ /** @docs-private */
88
+ protected allItems: QueryList<KbqDropdownItem>;
89
+ /** Roving-focus manager over the inline menu items (flat app rows and other-site rows). */
90
+ protected keyManager: FocusKeyManager<KbqDropdownItem>;
91
+ /** @docs-private */
92
+ private readonly menuItems;
93
+ /** @docs-private */
94
+ private readonly dir;
95
+ /**
96
+ * CSS class marking a nested alias row, bound in the template (see app-switcher.html). Kept as a
97
+ * single named constant, rather than a literal repeated in both places, so handleGroupHorizontal's
98
+ * classList check can't silently drift from the template's class binding if the class is renamed.
99
+ */
100
+ protected readonly nestedAliasClass = "kbq-app-switcher-site_nested";
87
101
  constructor();
88
102
  ngAfterViewInit(): void;
103
+ /** Releases the internal roving-focus menu QueryList. */
104
+ ngOnDestroy(): void;
89
105
  /** @docs-private */
90
106
  updateClassMap(placement: string, customClass: string, size: KbqPopUpSizeValues): void;
91
107
  /** @docs-private */
92
108
  updateTrapFocus(isTrapFocus: boolean): void;
93
109
  /** @docs-private */
94
110
  escapeHandler(): void;
111
+ /** Handles keyboard navigation across the app-switcher menu items.
112
+ * @docs-private */
113
+ protected keydownHandler(event: KeyboardEvent): void;
114
+ /**
115
+ * Expands/collapses an app group (or steps from an alias back to its header) on Left/Right,
116
+ * honouring the current text direction. Returns whether the key was consumed.
117
+ */
118
+ private handleGroupHorizontal;
119
+ /** Whether the keyboard event originated from the search input. */
120
+ private eventFromInput;
121
+ /** Syncs the key manager's active item with focus that arrives via Tab, click or a closing flyout.
122
+ * Clears the active item (index -1) when focus lands on a focusable element that isn't one of
123
+ * `menuItems` (e.g. the search field's clear button) - otherwise a stale `activeItem` from before
124
+ * the focus move would keep receiving Enter/Space/arrow-key actions meant for the new target.
125
+ * @docs-private */
126
+ protected focusinHandler(event: FocusEvent): void;
127
+ /** Closes the popup once focus leaves the menu and its site flyouts, mirroring the dropdown.
128
+ * @docs-private */
129
+ protected focusoutHandler(event: FocusEvent): void;
95
130
  /** @docs-private */
96
131
  selectAppInSite(site: KbqAppSwitcherSite, app: KbqAppSwitcherApp): void;
97
132
  private filterSites;
@@ -221,11 +256,13 @@ declare class KbqAppSwitcherListItem extends KbqDropdownItem {
221
256
  private sanitizer;
222
257
  app: KbqAppSwitcherApp;
223
258
  readonly toggle: i0.InputSignalWithTransform<boolean, unknown>;
259
+ /** Search query to highlight within the app name. */
260
+ readonly highlightText: i0.InputSignal<string>;
224
261
  collapsed: boolean;
225
262
  clickHandler(event: MouseEvent): void;
226
263
  getIcon(icon: string | null): _angular_platform_browser.SafeHtml;
227
264
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqAppSwitcherListItem, never>;
228
- static ɵcmp: i0.ɵɵComponentDeclaration<KbqAppSwitcherListItem, "[kbq-app-switcher-list-item]", ["kbqAppSwitcherApp"], { "app": { "alias": "app"; "required": false; }; "toggle": { "alias": "toggle"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; }; }, {}, never, never, true, never>;
265
+ static ɵcmp: i0.ɵɵComponentDeclaration<KbqAppSwitcherListItem, "[kbq-app-switcher-list-item]", ["kbqAppSwitcherApp"], { "app": { "alias": "app"; "required": false; }; "toggle": { "alias": "toggle"; "required": false; "isSignal": true; }; "highlightText": { "alias": "highlightText"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; }; }, {}, never, never, true, never>;
229
266
  static ngAcceptInputType_collapsed: unknown;
230
267
  }
231
268
 
@@ -118,7 +118,8 @@
118
118
  .kbq-app-switcher-list-item {
119
119
  &:hover,
120
120
  &.kbq-hover,
121
- &.kbq-focused {
121
+ &.kbq-focused,
122
+ &.cdk-keyboard-focused {
122
123
  &:has(.kbq-app-switcher-list-item__toggle) .kbq-app-switcher-list-item__icon {
123
124
  visibility: hidden;
124
125
  }
@@ -129,7 +130,8 @@
129
130
  }
130
131
 
131
132
  &:hover,
132
- &.kbq-hover {
133
+ &.kbq-hover,
134
+ &.cdk-keyboard-focused {
133
135
  background: var(--kbq-states-background-transparent-hover);
134
136
 
135
137
  & .kbq-app-switcher-list-item__toggle {
@@ -146,7 +148,8 @@
146
148
  background: var(--kbq-background-theme-less);
147
149
 
148
150
  &:hover,
149
- &.kbq-hover {
151
+ &.kbq-hover,
152
+ &.cdk-keyboard-focused {
150
153
  background: var(--kbq-states-background-theme-less-hover);
151
154
  }
152
155
 
@@ -158,11 +161,6 @@
158
161
 
159
162
  background: var(--kbq-list-default-container-background);
160
163
  color: var(--kbq-list-default-text-color);
161
-
162
- &.cdk-keyboard-focused {
163
- outline: none;
164
- border-color: var(--kbq-list-states-focused-focus-outline-color);
165
- }
166
164
  }
167
165
  }
168
166
 
@@ -1,10 +1,10 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { ElementRef, AfterContentInit, TemplateRef, QueryList, InjectionToken, Provider, AfterViewInit, OnDestroy } from '@angular/core';
2
+ import { ElementRef, InjectionToken, AfterContentInit, TemplateRef, QueryList, Provider, AfterViewInit, OnDestroy } from '@angular/core';
3
3
  import * as i2 from '@angular/cdk/overlay';
4
4
  import { ScrollStrategy, Overlay } from '@angular/cdk/overlay';
5
5
  import { ControlValueAccessor } from '@angular/forms';
6
6
  import * as i1 from '@koobiq/components/core';
7
- import { ActiveDescendantKeyManager, KbqOption, KbqOptgroup, KbqPanelWidth, KbqPanelMaxWidth, KeyboardNavigationHandler, KbqOptionSelectionChange } from '@koobiq/components/core';
7
+ import { ActiveDescendantKeyManager, KbqOption, KbqOptgroup, KbqPanelWidth, KbqPanelMaxWidth, KeyboardNavigationHandler, KbqSiblingPopup, KbqOptionSelectionChange } from '@koobiq/components/core';
8
8
  import { Observable } from 'rxjs';
9
9
 
10
10
  /**
@@ -109,13 +109,18 @@ declare class KbqAutocomplete implements AfterContentInit {
109
109
  }
110
110
 
111
111
  /**
112
- * The following style constants are necessary to save here in order
113
- * to properly calculate the scrollTop of the panel. Because we are not
114
- * actually focusing the active item, scroll must be handled manually.
112
+ * The total height of the autocomplete panel.
113
+ *
114
+ * @deprecated Unused the panel is capped by `--kbq-autocomplete-size-panel-max-height` and reveals its
115
+ * active option through `KbqOption.focus`, so nothing computes a scroll offset from this. Will be removed
116
+ * in the next major release.
115
117
  */
116
- /** The total height of the autocomplete panel. */
117
118
  declare const AUTOCOMPLETE_PANEL_HEIGHT = 256;
118
- /** Injection token that determines the scroll handling while the autocomplete panel is open. */
119
+ /**
120
+ * Injection token that determines the scroll handling while the autocomplete panel is open. The root default
121
+ * keeps the trigger usable outside `KbqAutocompleteModule`'s injector; providing the token anywhere still wins
122
+ * over it.
123
+ */
119
124
  declare const KBQ_AUTOCOMPLETE_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>;
120
125
  declare function KBQ_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy;
121
126
  declare const KBQ_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER: {
@@ -133,14 +138,14 @@ declare const KBQ_AUTOCOMPLETE_VALUE_ACCESSOR: Provider;
133
138
  * @docs-private
134
139
  */
135
140
  declare function getKbqAutocompleteMissingPanelError(): Error;
136
- declare class KbqAutocompleteTrigger implements AfterViewInit, ControlValueAccessor, OnDestroy, KeyboardNavigationHandler {
141
+ declare class KbqAutocompleteTrigger implements AfterViewInit, ControlValueAccessor, OnDestroy, KeyboardNavigationHandler, KbqSiblingPopup {
137
142
  private elementRef;
138
143
  private viewContainerRef;
139
144
  private changeDetectorRef;
140
145
  private overlay;
141
146
  private zone;
142
147
  private dir;
143
- private formField;
148
+ private readonly formField;
144
149
  private viewportRuler;
145
150
  protected readonly document: Document;
146
151
  readonly optionSelections: Observable<KbqOptionSelectionChange>;
@@ -149,6 +154,16 @@ declare class KbqAutocompleteTrigger implements AfterViewInit, ControlValueAcces
149
154
  get panelOpen(): boolean;
150
155
  /** The autocomplete panel to be attached to this trigger. */
151
156
  readonly autocomplete: _angular_core.InputSignal<KbqAutocomplete>;
157
+ /** Whether the autocomplete panel is currently on screen. Part of the `KbqSiblingPopup` contract. */
158
+ get isAttached(): boolean;
159
+ /**
160
+ * Emits `true` when the panel opens and `false` when it closes. Part of the `KbqSiblingPopup`
161
+ * contract.
162
+ *
163
+ * Built on top of the `autocomplete` signal rather than read once: the panel is bound after the consumers
164
+ * of this stream are created (a tooltip on the same element subscribes in its constructor).
165
+ */
166
+ readonly openedChange: Observable<boolean>;
152
167
  /**
153
168
  * Reference relative to which to position the autocomplete panel.
154
169
  * Defaults to the autocomplete trigger element.
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnInit, OnDestroy, InjectionToken, Provider, TemplateRef } from '@angular/core';
2
+ import { OnInit, OnDestroy, InjectionToken, TemplateRef, Provider } from '@angular/core';
3
3
  import { RouterLink } from '@angular/router';
4
4
  import { KbqButtonStyles } from '@koobiq/components/button';
5
5
  import { KbqDefaultSizes, KbqComponentColors, PopUpPlacements } from '@koobiq/components/core';
package/button/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { AfterContentInit, OnDestroy, AfterViewInit, ElementRef } from '@angular/core';
3
- import { KbqColorDirective, KbqTitleTextRef, KbqComponentColors, ThemePalette, KbqOrientation } from '@koobiq/components/core';
2
+ import { OnDestroy, AfterViewInit, AfterContentInit, ElementRef } from '@angular/core';
3
+ import { KbqColorDirective, KbqTitleTextRef, KbqOrientation, KbqComponentColors, ThemePalette } from '@koobiq/components/core';
4
4
  import { KbqDropdownTrigger } from '@koobiq/components/dropdown';
5
5
  import * as i1 from '@angular/cdk/a11y';
6
6
  import * as i2 from '@angular/cdk/platform';
@@ -3,6 +3,8 @@
3
3
  --kbq-button-toggle-size-container-padding-horizontal: var(--kbq-size-xxs);
4
4
  --kbq-button-toggle-size-container-padding-vertical: var(--kbq-size-xxs);
5
5
  --kbq-button-toggle-size-container-content-gap-horizontal: var(--kbq-size-xxs);
6
+ // 22px, not the design's 24px: the item's 1px border is outside this height. See the
7
+ // `box-sizing: content-box` in button-toggle.scss, which is what keeps that arithmetic true.
6
8
  --kbq-button-toggle-size-item-height: 22px;
7
9
  --kbq-button-toggle-size-item-border-radius: var(--kbq-size-xxs);
8
10
  --kbq-button-toggle-size-item-padding-horizontal: var(--kbq-size-s);
@@ -21,6 +21,15 @@
21
21
  justify-content: flex-start;
22
22
  align-items: center;
23
23
 
24
+ // Content-box on purpose, and load-bearing. `--kbq-button-toggle-size-item-height` is 22px,
25
+ // not the 24px of the design's `--kbq-size-xxl`: DS-3136 subtracted the border it added here
26
+ // from the token rather than from the rendered box, so the item only reaches its designed
27
+ // 24px while the border sits outside the declared height. A global `border-box` reset in a
28
+ // consuming application would pull the border back inside and leave the item 2px short —
29
+ // and the inner button, which is sized from the same token, would overflow the shrunken
30
+ // content box and be clipped by `overflow: hidden` above.
31
+ box-sizing: content-box;
32
+
24
33
  height: var(--kbq-button-toggle-size-item-height);
25
34
  min-height: var(--kbq-button-toggle-size-item-height);
26
35
 
@@ -147,6 +147,11 @@ declare class KbqButtonToggle implements OnInit, AfterContentInit, AfterViewInit
147
147
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqButtonToggle, "kbq-button-toggle", ["kbqButtonToggle"], { "checked": { "alias": "checked"; "required": false; }; "value": { "alias": "value"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "change": "change"; }, ["icons"], ["*"], true, never>;
148
148
  }
149
149
 
150
+ /**
151
+ * Entry point for `KbqButtonToggleGroup`/`KbqButtonToggle`. Both are standalone, so a bare
152
+ * `imports: [KbqButtonToggle]` works; this module is the convenience bundle that also pulls in
153
+ * `KbqButtonModule`/`KbqTitleModule` and re-exports the slot markers.
154
+ */
150
155
  declare class KbqButtonToggleModule {
151
156
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqButtonToggleModule, never>;
152
157
  static ɵmod: _angular_core.ɵɵNgModuleDeclaration<KbqButtonToggleModule, never, [typeof i1.KbqButtonModule, typeof i2.KbqTitleModule, typeof KbqButtonToggleGroup, typeof KbqButtonToggle], [typeof KbqButtonToggleGroup, typeof KbqButtonToggle]>;