@koobiq/components 20.3.0 → 20.3.2

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 (95) 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 +98 -3
  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-autocomplete.mjs +2 -2
  16. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  17. package/fesm2022/koobiq-components-breadcrumbs.mjs +8 -3
  18. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  19. package/fesm2022/koobiq-components-button-toggle.mjs +2 -2
  20. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  21. package/fesm2022/koobiq-components-code-block.mjs +10 -5
  22. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  23. package/fesm2022/koobiq-components-core.mjs +52 -11
  24. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  25. package/fesm2022/koobiq-components-dropdown.mjs +2 -2
  26. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  27. package/fesm2022/koobiq-components-ellipsis-center.mjs +77 -22
  28. package/fesm2022/koobiq-components-ellipsis-center.mjs.map +1 -1
  29. package/fesm2022/koobiq-components-file-upload.mjs +7 -7
  30. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  31. package/fesm2022/koobiq-components-filter-bar.mjs +76 -41
  32. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  33. package/fesm2022/koobiq-components-form-field.mjs +13 -7
  34. package/fesm2022/koobiq-components-form-field.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 +60 -11
  40. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  41. package/fesm2022/koobiq-components-select.mjs +99 -12
  42. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  43. package/fesm2022/koobiq-components-sidebar.mjs +5 -1
  44. package/fesm2022/koobiq-components-sidebar.mjs.map +1 -1
  45. package/fesm2022/koobiq-components-sidepanel.mjs +25 -6
  46. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-tabs.mjs +10 -6
  48. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-time-range.mjs +388 -74
  50. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  51. package/fesm2022/koobiq-components-timezone.mjs +2 -2
  52. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  53. package/fesm2022/koobiq-components-title.mjs +15 -3
  54. package/fesm2022/koobiq-components-title.mjs.map +1 -1
  55. package/fesm2022/koobiq-components-tree-select.mjs +3 -3
  56. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-tree.mjs +14 -4
  58. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  59. package/file-upload/file-upload.scss +11 -0
  60. package/file-upload/index.d.ts +1 -1
  61. package/file-upload/multiple-file-upload.component.scss +15 -3
  62. package/file-upload/single-file-upload.component.scss +10 -2
  63. package/filter-bar/filter-bar-tokens.scss +2 -1
  64. package/filter-bar/index.d.ts +25 -4
  65. package/filter-bar/pipes/base-pipe.scss +13 -6
  66. package/filter-bar/pipes/pipe-input.scss +3 -1
  67. package/form-field/index.d.ts +1 -3
  68. package/link/_link-theme.scss +50 -15
  69. package/markdown/index.d.ts +2 -0
  70. package/modal/index.d.ts +17 -8
  71. package/navbar/_navbar-item_horizontal.scss +5 -0
  72. package/package.json +3 -3
  73. package/prebuilt-themes/dark-theme.css +1 -1
  74. package/prebuilt-themes/light-theme.css +1 -1
  75. package/prebuilt-themes/theme.css +1 -1
  76. package/schematics/migrations/alert-signals/index.js +4 -1
  77. package/schematics/migrations/autocomplete-panel-width-auto/index.js +3 -34
  78. package/schematics/migrations/empty-state-size-attr/index.js +3 -34
  79. package/schematics/migrations/filter-bar-signals/index.js +4 -1
  80. package/schematics/migrations/loader-overlay-size-attr/index.js +3 -34
  81. package/schematics/migrations/v20-upgrade/index.js +4 -1
  82. package/schematics/ng-add/index.js +1 -1
  83. package/schematics/utils/angular-parsing.js +11 -12
  84. package/schematics/utils/package-config.js +5 -4
  85. package/schematics/utils/typescript.js +24 -0
  86. package/select/_select-theme.scss +9 -1
  87. package/select/index.d.ts +12 -2
  88. package/select/select.scss +13 -0
  89. package/sidebar/index.d.ts +1 -0
  90. package/sidepanel/index.d.ts +9 -0
  91. package/tabs/index.d.ts +1 -1
  92. package/time-range/index.d.ts +140 -5
  93. package/time-range/time-range.scss +16 -1
  94. package/title/index.d.ts +10 -2
  95. package/tree/index.d.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken, OnInit, TemplateRef, WritableSignal, Provider, Injector } from '@angular/core';
3
- import { ValidatorFn, ControlValueAccessor, NgControl, FormControl, Validator, FormGroup, AbstractControl, FormGroupDirective, NgForm, ValidationErrors } from '@angular/forms';
2
+ import { Signal, InjectionToken, OnInit, TemplateRef, WritableSignal, Provider, Injector } from '@angular/core';
3
+ import { ValidatorFn, ControlValueAccessor, NgControl, FormControl, Validator, FormGroup, AbstractControl, ValidationErrors } from '@angular/forms';
4
4
  import { DateAdapter, DateFormatter, KbqTimeRangeLocaleConfig, PopUpSizes, PopUpPlacements, ErrorStateMatcher } from '@koobiq/components/core';
5
5
  import { KbqPopoverTrigger } from '@koobiq/components/popover';
6
6
  import { DurationObjectUnits, DurationUnit } from '@koobiq/date-adapter';
@@ -82,18 +82,47 @@ declare class KbqTimeRangeService<T> {
82
82
  readonly providedDefaultTimeRangeTypes: KbqTimeRangeType[];
83
83
  readonly customTimeRangeTypes: KbqCustomTimeRangeType[] | null;
84
84
  readonly DEFAULT_RANGE_TYPE: KbqTimeRangeType;
85
+ private readonly boundsSource;
86
+ /**
87
+ * Bounds of the owning component, so that every default and every check reads one pair. Both are
88
+ * exact instants rather than whole days: a `maxDate` that should admit its own day has to carry the
89
+ * end of that day.
90
+ */
91
+ readonly minDate: Signal<NonNullable<T> | null>;
92
+ /** @see minDate */
93
+ readonly maxDate: Signal<NonNullable<T> | null>;
85
94
  readonly timeRangeConfig: Record<KbqTimeRangeType, Omit<KbqCustomTimeRangeType, 'type'>>;
86
95
  constructor();
87
96
  static range: (dateTimeISOString: string) => KbqRange;
88
97
  add({ type, ...customTimeRangeConfig }: KbqCustomTimeRangeType): void;
98
+ /**
99
+ * Hands the owning component's own bound inputs over, rather than a copy of their values: a signal
100
+ * input reads as its initial value until the first change detection, so a mirror would leave every
101
+ * default computed in a constructor clamped against no bounds at all.
102
+ */
103
+ bindBounds(min: Signal<T | null | undefined>, max: Signal<T | null | undefined>): void;
89
104
  getTimeRangeTypeUnits(type: KbqTimeRangeType): KbqTimeRangeUnits;
90
105
  getTimeRangeUnitByType(type: KbqTimeRangeType): KbqTimeRangeTranslationType;
106
+ /**
107
+ * "Yesterday to today", pulled inside {@link minDate}/{@link maxDate} when they are set - otherwise
108
+ * the editor opens on a range it would itself report as out of bounds.
109
+ *
110
+ * Milliseconds are dropped from "today" *before* clamping, so a clamped end lands exactly on its
111
+ * bound rather than a fraction of a second below it.
112
+ */
91
113
  getDefaultRangeValue(): Required<KbqRangeValue<T>>;
92
114
  getTimeRangeDefaultValue(rangeValue: KbqRangeValue<T>, availableTimeRangeTypes?: KbqTimeRangeType[]): KbqTimeRangeRange;
93
115
  calculateTimeRange(type?: KbqTimeRangeType, rangeValue?: KbqRangeValue<T>): KbqRange;
94
116
  combineDateAndTime(date: T, time: T): T;
95
117
  lastUnitsRange: (unitsInfo: KbqTimeRangeUnits) => KbqRange;
96
118
  checkAndCorrectTimeRangeValue(value: KbqTimeRangeRange | null | undefined, availableTimeRangeTypes: KbqTimeRangeType[], rangeValue: KbqRangeValue<T>): KbqTimeRangeRange;
119
+ /** Which bound, if any, an instant falls outside of. */
120
+ private checkBounds;
121
+ /**
122
+ * `DateAdapter.clampDate` compares whole days only, while a border is rejected by its time as well -
123
+ * a value clamped to the day would still land outside the bounds.
124
+ */
125
+ private clampToBounds;
97
126
  omitMilliseconds(date: T): T;
98
127
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqTimeRangeService<any>, never>;
99
128
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<KbqTimeRangeService<any>>;
@@ -122,6 +151,8 @@ declare const kbqTimeRangeLocaleConfigurationProvider: (configuration: KbqTimeRa
122
151
  declare class KbqTimeRange<T> implements ControlValueAccessor, OnInit {
123
152
  private readonly timeRangeService;
124
153
  private readonly localeService;
154
+ private readonly editorBridge;
155
+ private readonly document;
125
156
  /** @docs-private */
126
157
  readonly ngControl: NgControl | null;
127
158
  /** The minimum selectable date. */
@@ -170,7 +201,17 @@ declare class KbqTimeRange<T> implements ControlValueAccessor, OnInit {
170
201
  ngOnInit(): void;
171
202
  /** Implemented as part of ControlValueAccessor */
172
203
  writeValue(value: KbqTimeRangeRange | null): void;
173
- /** @docs-private */
204
+ /**
205
+ * Lets the editor tell an "apply" gesture from a plain focus loss before the click even lands - the
206
+ * `focusout` it reacts to is dispatched between this `mousedown` and the `click` below.
207
+ * @docs-private
208
+ */
209
+ protected onFooterPointerDown(): void;
210
+ /**
211
+ * Applying is always offered; an invalid editor keeps the popover open and sends the user to the
212
+ * first field at fault instead.
213
+ * @docs-private
214
+ */
174
215
  onApply(popover: KbqPopoverTrigger): void;
175
216
  /** @docs-private */
176
217
  onCancel(popover: KbqPopoverTrigger): void;
@@ -183,6 +224,8 @@ declare class KbqTimeRange<T> implements ControlValueAccessor, OnInit {
183
224
  registerOnChange(fn: (_value: KbqTimeRangeRange) => void): void;
184
225
  /** Implemented as part of ControlValueAccessor */
185
226
  registerOnTouched(fn: () => void): void;
227
+ /** What the editor opens on: the first offered type, or a plain range when none are offered. */
228
+ private defaultEditorValue;
186
229
  private handleAvailableTypesChange;
187
230
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KbqTimeRange<any>, never>;
188
231
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KbqTimeRange<any>, "kbq-time-range", never, { "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "defaultRangeValue": { "alias": "defaultRangeValue"; "required": false; "isSignal": true; }; "availableTimeRangeTypes": { "alias": "availableTimeRangeTypes"; "required": false; "isSignal": true; }; "titleTemplate": { "alias": "titleTemplate"; "required": false; "isSignal": true; }; "optionTemplate": { "alias": "optionTemplate"; "required": false; "isSignal": true; }; "arrow": { "alias": "arrow"; "required": false; "isSignal": true; }; "showRangeAsDefault": { "alias": "showRangeAsDefault"; "required": false; "isSignal": true; }; "nonNullable": { "alias": "nonNullable"; "required": false; "isSignal": true; }; }, { "valueCorrected": "valueCorrected"; }, never, never, true, never>;
@@ -210,12 +253,22 @@ interface FormValue<T> {
210
253
  toTime: FormControl<T>;
211
254
  toDate: FormControl<T>;
212
255
  }
256
+ /** One end of the range. Its date and its time are checked together, and revealed together. */
257
+ type RangeBorder = 'from' | 'to';
258
+ /**
259
+ * Errors are reported only once the user has left the border they belong to, and go quiet again as soon
260
+ * as typing resumes. The validators themselves always run, so that `validate()` stays honest about
261
+ * whether the range could be saved - only the painting waits.
262
+ */
213
263
  declare class RangeErrorStateMatcher implements ErrorStateMatcher {
214
- isErrorState(control: AbstractControl | null, form: FormGroupDirective | NgForm | null): boolean;
264
+ isErrorState(control: AbstractControl | null): boolean;
215
265
  }
216
266
  /** @docs-private */
217
267
  declare class KbqTimeRangeEditor<T> implements ControlValueAccessor, Validator, OnInit {
218
268
  private readonly timeRangeService;
269
+ private readonly editorBridge;
270
+ private readonly elementRef;
271
+ private readonly document;
219
272
  /** The maximum selectable date. */
220
273
  readonly maxDate: _angular_core.InputSignal<T | null>;
221
274
  /** The minimum selectable date. */
@@ -232,15 +285,32 @@ declare class KbqTimeRangeEditor<T> implements ControlValueAccessor, Validator,
232
285
  protected readonly isRangeVisible: _angular_core.Signal<boolean>;
233
286
  /** @docs-private */
234
287
  protected readonly timeRangeTypesWithoutRange: _angular_core.Signal<KbqTimeRangeOptionContext[]>;
288
+ /**
289
+ * Caption under the "range" option, spelling out the bounds the border has to stay within. Read from
290
+ * the service rather than from this component's own inputs, so that it can never disagree with what
291
+ * the border validators go on to enforce.
292
+ * @docs-private
293
+ */
294
+ protected readonly boundsHint: _angular_core.Signal<string>;
235
295
  /** @docs-private */
236
296
  protected readonly timepickerList: _angular_core.Signal<readonly KbqTimepicker<T>[]>;
237
297
  /** @docs-private */
238
298
  protected readonly form: FormGroup<FormValue<T>>;
299
+ /**
300
+ * The same four controls as `form`, indexed as two ends each with a date and a time. The form itself
301
+ * has to stay flat, because its value is the `KbqRangeValue` the service and the bound control speak
302
+ * in - this is the single place the two shapes are tied together, and `Record` over both dimensions is
303
+ * what keeps it exhaustive.
304
+ */
305
+ private readonly borderControls;
306
+ /** The same four, flat, for the checks that treat the range as one thing. */
307
+ private readonly rangeControls;
239
308
  /** @docs-private */
240
309
  protected readonly timepickerFormat = TimeFormats.HHmmss;
241
310
  /** @docs-private */
242
311
  protected readonly rangeStateMatcher: RangeErrorStateMatcher;
243
- private lastValidationErrorOnEmit;
312
+ /** Raised by the first "apply", after which a border left wholly empty counts as an error too. */
313
+ private applyAttempted;
244
314
  constructor();
245
315
  ngOnInit(): void;
246
316
  /** @docs-private */
@@ -255,6 +325,71 @@ declare class KbqTimeRangeEditor<T> implements ControlValueAccessor, Validator,
255
325
  registerOnChange(fn: (value: KbqTimeRangeRange) => void): void;
256
326
  /** Implemented as part of ControlValueAccessor */
257
327
  registerOnTouched(fn: () => void): void;
328
+ /**
329
+ * Leaving one border reports what is wrong with it. Angular marks a control touched on its own blur,
330
+ * which is a finer grain than the spec asks for - so moving between a border's own date and time
331
+ * takes the touch back off, and the pair is judged only once focus is out of both.
332
+ * @docs-private
333
+ */
334
+ protected onBorderFocusOut(border: RangeBorder, { currentTarget, relatedTarget }: FocusEvent): void;
335
+ /**
336
+ * Typing puts a border back to its neutral state, the way `validation-on-blur` does for a single
337
+ * field. What is wrong with it is said again when focus leaves it.
338
+ * @docs-private
339
+ */
340
+ protected onBorderInput(border: RangeBorder): void;
341
+ /**
342
+ * What is said when the range as a whole has left the bounds. Said once, below the last of the two
343
+ * ends, and only when both of them are at fault: a single end out of bounds is already pointed at by
344
+ * the fields painted around it. Silent until the ends have been left, keeping step with that
345
+ * painting.
346
+ * @docs-private
347
+ */
348
+ protected outOfBoundsMessage(): string;
349
+ /**
350
+ * Once focus leaves the manual range fields, a reversed range is silently swapped back into order -
351
+ * except on the way to "apply", where the swap is left to the emitted value so that the popover does
352
+ * not visibly reorder itself in the same gesture that closes it.
353
+ * @docs-private
354
+ */
355
+ protected onRangeFocusOut({ currentTarget, relatedTarget }: FocusEvent): void;
356
+ /**
357
+ * Reveals both borders and sends the user to the first field at fault, reporting whether there is
358
+ * anything to fix at all.
359
+ */
360
+ private revealErrors;
361
+ /** Whether a bound is a moment within its day rather than the day itself. */
362
+ private carriesTime;
363
+ /** Whether focus is still inside `group`, counting the datepicker calendar as part of it. */
364
+ private staysWithin;
365
+ /** Both halves of a border are painted, or neither: the pair is what the user is judged on. */
366
+ private setBorderTouched;
367
+ /** Both halves of one end, in the order they are painted. */
368
+ private borderHalves;
369
+ /** Each half is checked against its sibling, so a change to one has to re-run the other. */
370
+ private revalidateRange;
371
+ private swapIfReversed;
372
+ /**
373
+ * Whether anything about the borders would stop the range being saved. Deliberately blind to which
374
+ * borders have been revealed: a swap rewrites the user's values, so it has to answer "is this range
375
+ * actually sound", not "has the user been shown the problem yet".
376
+ */
377
+ private hasBorderProblem;
378
+ /**
379
+ * What is wrong with each half of a border, whether or not the user has been shown it. A missing half
380
+ * is flagged on its own; a bound is judged in two steps, so that the field actually at fault is the
381
+ * one painted.
382
+ */
383
+ private borderErrors;
384
+ /** Which bound a border falls outside of, and whether its day or only its time is to blame. */
385
+ private checkBorderBounds;
386
+ private isReversed;
387
+ /**
388
+ * A border reports only what the pickers do not: an empty half next to a filled one, a border left
389
+ * wholly empty once "apply" was pressed, and a border outside the bounds. Format is the pickers' own
390
+ * business, and so is the calendar restriction.
391
+ */
392
+ private borderValidator;
258
393
  private mapTimeRange;
259
394
  private getFormattedOption;
260
395
  private concatControlValidationErrors;
@@ -40,9 +40,24 @@
40
40
  gap: var(--kbq-size-s);
41
41
 
42
42
  .kbq-time-range-editor__date-time-prefix {
43
- align-self: center;
43
+ // The label names the fields, not the caption or the error message below them, so it is
44
+ // centred on the row of fields alone. Centring it on the whole block would drop it as
45
+ // soon as the fieldset grows downwards.
46
+ display: flex;
47
+ align-items: center;
48
+ align-self: flex-start;
49
+ min-height: var(--kbq-size-3xl);
50
+ flex: none;
44
51
  width: 57px;
45
52
  }
53
+
54
+ // Sized by the row rather than by what it holds: the caption and the error message are wider
55
+ // than the fields, and an intrinsically sized fieldset would leave the two rows a few pixels
56
+ // apart from each other.
57
+ .kbq-fieldset {
58
+ flex: 1;
59
+ min-width: 0;
60
+ }
46
61
  }
47
62
  }
48
63
  }
package/title/index.d.ts CHANGED
@@ -12,7 +12,8 @@ import { Subject } from 'rxjs';
12
12
  * By default, the tooltip content is the trimmed `textContent` of the host. Provide explicit content
13
13
  * with `[kbq-title]="stringOrTemplateRef"`. For nested markup, mark the measured container with the
14
14
  * `#kbqTitleContainer` template reference and the text element(s) with `#kbqTitleText`; several
15
- * `#kbqTitleText` elements are supported and the tooltip is shown when any of them overflows.
15
+ * `#kbqTitleText` elements are supported and the tooltip is shown when any of them overflows the container
16
+ * or is clipped by its siblings.
16
17
  *
17
18
  * Host components that provide `KBQ_TITLE_TEXT_REF` (e.g. `KbqOption`) supply the text and parent
18
19
  * elements automatically, so the directive works without explicit template references.
@@ -42,7 +43,8 @@ declare class KbqTitleDirective extends KbqTooltipTrigger implements AfterViewIn
42
43
  /**
43
44
  * Whether the host content is clipped and therefore needs a tooltip. Returns `true` if any measured
44
45
  * text element overflows the parent — covering multiple `#kbqTitleText` elements, the sub-pixel
45
- * special case, and both horizontal and vertical overflow.
46
+ * special case, and both horizontal and vertical overflow — or, with several text elements, if one of
47
+ * them clips its own content.
46
48
  */
47
49
  get isOverflown(): boolean;
48
50
  /** Whether the text is clipped horizontally: the parent `offsetWidth` is smaller than the child `scrollWidth`. */
@@ -118,6 +120,12 @@ declare class KbqTitleDirective extends KbqTooltipTrigger implements AfterViewIn
118
120
  /** Always disables (hides) the tooltip. Bound to `mouseleave` and non-keyboard focus changes.
119
121
  * @docs-private */
120
122
  hideTooltip(): void;
123
+ /**
124
+ * Whether a text element is narrower than its own text. Text elements that share the parent can take width
125
+ * from each other, so one is clipped while its full text would still fit the parent — which the parent
126
+ * comparison above cannot see. An inline element reports a zero `clientWidth` and never clips.
127
+ * @docs-private */
128
+ private isClippedInOwnBox;
121
129
  static ɵfac: i0.ɵɵFactoryDeclaration<KbqTitleDirective, never>;
122
130
  static ɵdir: i0.ɵɵDirectiveDeclaration<KbqTitleDirective, "[kbq-title]", ["kbqTitle"], { "titleContent": { "alias": "kbq-title"; "required": false; "isSignal": true; }; }, {}, ["parentContainer", "childContainer"], never, true, never>;
123
131
  }
package/tree/index.d.ts CHANGED
@@ -499,6 +499,7 @@ declare class KbqTreeOptionChange {
499
499
  declare class KbqTreeOption extends KbqTreeNode<KbqTreeOption> implements AfterContentInit, KbqTitleTextRef {
500
500
  private changeDetectorRef;
501
501
  private ngZone;
502
+ private readonly destroyRef;
502
503
  tree: any;
503
504
  readonly onFocus: Subject<KbqTreeOptionEvent>;
504
505
  readonly onBlur: Subject<KbqTreeOptionEvent>;