selective-ui 1.4.0 → 1.4.1

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 (70) hide show
  1. package/dist/selective-ui.css +0 -6
  2. package/dist/selective-ui.css.map +1 -1
  3. package/dist/selective-ui.esm.js +252 -553
  4. package/dist/selective-ui.esm.js.map +1 -1
  5. package/dist/selective-ui.esm.min.js +2 -2
  6. package/dist/selective-ui.esm.min.js.br +0 -0
  7. package/dist/selective-ui.min.css +1 -1
  8. package/dist/selective-ui.min.css.br +0 -0
  9. package/dist/selective-ui.min.js +2 -2
  10. package/dist/selective-ui.min.js.br +0 -0
  11. package/dist/selective-ui.umd.js +254 -555
  12. package/dist/selective-ui.umd.js.map +1 -1
  13. package/package.json +12 -12
  14. package/src/ts/adapter/mixed-adapter.ts +147 -68
  15. package/src/ts/components/accessorybox.ts +14 -11
  16. package/src/ts/components/directive.ts +1 -1
  17. package/src/ts/components/option-handle.ts +12 -9
  18. package/src/ts/components/placeholder.ts +5 -5
  19. package/src/ts/components/popup/empty-state.ts +5 -5
  20. package/src/ts/components/popup/loading-state.ts +5 -5
  21. package/src/ts/components/popup/popup.ts +138 -76
  22. package/src/ts/components/searchbox.ts +17 -13
  23. package/src/ts/components/selectbox.ts +242 -81
  24. package/src/ts/core/base/adapter.ts +39 -14
  25. package/src/ts/core/base/fenwick.ts +3 -2
  26. package/src/ts/core/base/lifecycle.ts +14 -4
  27. package/src/ts/core/base/model.ts +17 -15
  28. package/src/ts/core/base/recyclerview.ts +7 -5
  29. package/src/ts/core/base/view.ts +10 -5
  30. package/src/ts/core/base/virtual-recyclerview.ts +89 -37
  31. package/src/ts/core/model-manager.ts +48 -21
  32. package/src/ts/core/search-controller.ts +174 -56
  33. package/src/ts/global.ts +5 -8
  34. package/src/ts/index.ts +2 -2
  35. package/src/ts/models/group-model.ts +33 -8
  36. package/src/ts/models/option-model.ts +60 -19
  37. package/src/ts/services/dataset-observer.ts +6 -3
  38. package/src/ts/services/ea-observer.ts +1 -1
  39. package/src/ts/services/effector.ts +22 -12
  40. package/src/ts/services/refresher.ts +7 -3
  41. package/src/ts/services/resize-observer.ts +24 -11
  42. package/src/ts/services/select-observer.ts +2 -2
  43. package/src/ts/types/components/popup.type.ts +18 -1
  44. package/src/ts/types/components/searchbox.type.ts +43 -30
  45. package/src/ts/types/components/state.box.type.ts +1 -1
  46. package/src/ts/types/core/base/adapter.type.ts +13 -5
  47. package/src/ts/types/core/base/lifecycle.type.ts +1 -2
  48. package/src/ts/types/core/base/model.type.ts +3 -3
  49. package/src/ts/types/core/base/recyclerview.type.ts +7 -5
  50. package/src/ts/types/core/base/view.type.ts +6 -6
  51. package/src/ts/types/core/base/virtual-recyclerview.type.ts +45 -46
  52. package/src/ts/types/core/search-controller.type.ts +18 -2
  53. package/src/ts/types/css.d.ts +1 -0
  54. package/src/ts/types/plugins/plugin.type.ts +2 -2
  55. package/src/ts/types/services/effector.type.ts +25 -25
  56. package/src/ts/types/services/resize-observer.type.ts +23 -12
  57. package/src/ts/types/utils/callback-scheduler.type.ts +2 -2
  58. package/src/ts/types/utils/ievents.type.ts +1 -1
  59. package/src/ts/types/utils/istorage.type.ts +62 -60
  60. package/src/ts/types/utils/libs.type.ts +19 -17
  61. package/src/ts/types/utils/selective.type.ts +6 -3
  62. package/src/ts/types/views/view.group.type.ts +9 -5
  63. package/src/ts/types/views/view.option.type.ts +39 -17
  64. package/src/ts/utils/callback-scheduler.ts +12 -7
  65. package/src/ts/utils/ievents.ts +12 -5
  66. package/src/ts/utils/istorage.ts +5 -3
  67. package/src/ts/utils/libs.ts +122 -43
  68. package/src/ts/utils/selective.ts +15 -8
  69. package/src/ts/views/group-view.ts +11 -9
  70. package/src/ts/views/option-view.ts +37 -18
@@ -43,7 +43,12 @@ import { LifecycleState } from "../types/core/base/lifecycle.type";
43
43
  * @see {@link OptionModel}
44
44
  * @see {@link GroupView}
45
45
  */
46
- export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupView, SelectiveOptions> {
46
+ export class GroupModel extends Model<
47
+ HTMLOptGroupElement,
48
+ GroupViewTags,
49
+ GroupView,
50
+ SelectiveOptions
51
+ > {
47
52
  /** Group label (mirrors `HTMLSelectOptGroupElement.label`). */
48
53
  public label = "";
49
54
 
@@ -67,7 +72,13 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
67
72
  * Subscribers invoked when collapsed state changes.
68
73
  * Callbacks are invoked through {@link iEvents.callEvent}.
69
74
  */
70
- private privOnCollapsedChanged: Array<(evtToken: IEventCallback, model: GroupModel, collapsed: boolean) => void> = [];
75
+ private privOnCollapsedChanged: Array<
76
+ (
77
+ evtToken: IEventCallback,
78
+ model: GroupModel,
79
+ collapsed: boolean,
80
+ ) => void
81
+ > = [];
71
82
 
72
83
  /**
73
84
  * Creates a group model from configuration and an optional `<optgroup>` element.
@@ -75,10 +86,15 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
75
86
  * @param {SelectiveOptions} options - Shared configuration for models/views.
76
87
  * @param {HTMLOptGroupElement} [targetElement] - Backing `<optgroup>` element (when available).
77
88
  */
78
- public constructor(options: SelectiveOptions, targetElement?: HTMLOptGroupElement) {
89
+ public constructor(
90
+ options: SelectiveOptions,
91
+ targetElement?: HTMLOptGroupElement,
92
+ ) {
79
93
  super(options, targetElement ?? null, null);
80
94
  this.label = this.targetElement.label;
81
- this.collapsed = Libs.string2Boolean(this.targetElement.dataset?.collapsed);
95
+ this.collapsed = Libs.string2Boolean(
96
+ this.targetElement.dataset?.collapsed,
97
+ );
82
98
  }
83
99
 
84
100
  /**
@@ -189,7 +205,7 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
189
205
  return;
190
206
  }
191
207
 
192
- this.items.forEach(item => {
208
+ this.items.forEach((item) => {
193
209
  item.destroy();
194
210
  });
195
211
 
@@ -206,7 +222,13 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
206
222
  * Listener invoked with `(evtToken, model, collapsed)`.
207
223
  * @returns {void}
208
224
  */
209
- public onCollapsedChanged(callback: (evtToken: IEventCallback, model: GroupModel, collapsed: boolean) => void): void {
225
+ public onCollapsedChanged(
226
+ callback: (
227
+ evtToken: IEventCallback,
228
+ model: GroupModel,
229
+ collapsed: boolean,
230
+ ) => void,
231
+ ): void {
210
232
  this.privOnCollapsedChanged.push(callback);
211
233
  }
212
234
 
@@ -224,7 +246,10 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
224
246
  this.collapsed = !this.collapsed;
225
247
  this.view?.setCollapsed(this.collapsed);
226
248
 
227
- iEvents.callEvent<[GroupModel, boolean]>([this, this.collapsed], ...this.privOnCollapsedChanged);
249
+ iEvents.callEvent<[GroupModel, boolean]>(
250
+ [this, this.collapsed],
251
+ ...this.privOnCollapsedChanged,
252
+ );
228
253
  }
229
254
 
230
255
  /**
@@ -267,4 +292,4 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
267
292
  public updateVisibility(): void {
268
293
  this.view?.updateVisibility();
269
294
  }
270
- }
295
+ }
@@ -55,24 +55,35 @@ import { LifecycleState } from "../types/core/base/lifecycle.type";
55
55
  * @see {@link GroupModel}
56
56
  * @see {@link OptionView}
57
57
  */
58
- export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, OptionView, SelectiveOptions> {
58
+ export class OptionModel extends Model<
59
+ HTMLOptionElement,
60
+ OptionViewTags,
61
+ OptionView,
62
+ SelectiveOptions
63
+ > {
59
64
  /**
60
65
  * External selection subscribers (emitted by the {@link selected} setter).
61
66
  * Use this for user-facing selection flows.
62
67
  */
63
- private privOnSelected: Array<(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void> = [];
68
+ private privOnSelected: Array<
69
+ (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void
70
+ > = [];
64
71
 
65
72
  /**
66
73
  * Internal selection subscribers (emitted by the {@link selectedNonTrigger} setter).
67
74
  * Use this for silent synchronization flows.
68
75
  */
69
- private privOnInternalSelected: Array<(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void> = [];
76
+ private privOnInternalSelected: Array<
77
+ (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void
78
+ > = [];
70
79
 
71
80
  /**
72
81
  * Visibility subscribers (emitted by the {@link visible} setter).
73
82
  * Commonly used to recompute group visibility and update aggregated visibility stats.
74
83
  */
75
- private privOnVisibilityChanged: Array<(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void> = [];
84
+ private privOnVisibilityChanged: Array<
85
+ (evtToken: IEventCallback, model: OptionModel, visible: boolean) => void
86
+ > = [];
76
87
 
77
88
  /**
78
89
  * Visibility flag used for filtering/search.
@@ -87,19 +98,19 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
87
98
  * Parent group model (if this option belongs to a group).
88
99
  * Assigned by grouping logic (e.g., GroupModel/MixedAdapter).
89
100
  */
90
- public group: GroupModel | null = null;
101
+ public group?: GroupModel;
91
102
 
92
103
  /**
93
104
  * Creates an option model.
94
105
  *
95
106
  * @param {SelectiveOptions} options - Shared configuration for models/views.
96
- * @param {HTMLOptionElement | null} [targetElement=null] - Backing `<option>` element.
97
- * @param {OptionView | null} [view=null] - Optional view used to render this model.
107
+ * @param {HTMLOptionElement} [targetElement=null] - Backing `<option>` element.
108
+ * @param {OptionView} [view=null] - Optional view used to render this model.
98
109
  */
99
110
  public constructor(
100
111
  options: SelectiveOptions,
101
- targetElement: HTMLOptionElement | null = null,
102
- view: OptionView | null = null
112
+ targetElement?: HTMLOptionElement,
113
+ view?: OptionView,
103
114
  ) {
104
115
  super(options, targetElement, view);
105
116
  }
@@ -168,7 +179,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
168
179
  */
169
180
  public set selected(value: boolean) {
170
181
  this.selectedNonTrigger = value;
171
- iEvents.callEvent<[OptionModel, boolean]>([this, value], ...this.privOnSelected);
182
+ iEvents.callEvent<[OptionModel, boolean]>(
183
+ [this, value],
184
+ ...this.privOnSelected,
185
+ );
172
186
  }
173
187
 
174
188
  /**
@@ -199,7 +213,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
199
213
  const viewEl = this.view?.getView?.();
200
214
  if (viewEl) viewEl.classList.toggle("hide", !value);
201
215
 
202
- iEvents.callEvent<[OptionModel, boolean]>([this, value], ...this.privOnVisibilityChanged);
216
+ iEvents.callEvent<[OptionModel, boolean]>(
217
+ [this, value],
218
+ ...this.privOnVisibilityChanged,
219
+ );
203
220
  }
204
221
 
205
222
  /**
@@ -243,7 +260,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
243
260
  this.targetElement.selected = value;
244
261
  }
245
262
 
246
- iEvents.callEvent<[OptionModel, boolean]>([this, value], ...this.privOnInternalSelected);
263
+ iEvents.callEvent<[OptionModel, boolean]>(
264
+ [this, value],
265
+ ...this.privOnInternalSelected,
266
+ );
247
267
  }
248
268
 
249
269
  /**
@@ -273,7 +293,9 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
273
293
  * @returns {string}
274
294
  */
275
295
  public get textContent(): string {
276
- return this.options.allowHtml ? Libs.stripHtml(this.text).trim() : this.text.trim();
296
+ return this.options.allowHtml
297
+ ? Libs.stripHtml(this.text).trim()
298
+ : this.text.trim();
277
299
  }
278
300
 
279
301
  /**
@@ -323,7 +345,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
323
345
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
324
346
  * @returns {void}
325
347
  */
326
- public onSelected(callback: (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void): void {
348
+ public onSelected(
349
+ callback: (
350
+ evtToken: IEventCallback,
351
+ el: OptionModel,
352
+ selected: boolean,
353
+ ) => void,
354
+ ): void {
327
355
  this.privOnSelected.push(callback);
328
356
  }
329
357
 
@@ -333,7 +361,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
333
361
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
334
362
  * @returns {void}
335
363
  */
336
- public onInternalSelected(callback: (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void): void {
364
+ public onInternalSelected(
365
+ callback: (
366
+ evtToken: IEventCallback,
367
+ el: OptionModel,
368
+ selected: boolean,
369
+ ) => void,
370
+ ): void {
337
371
  this.privOnInternalSelected.push(callback);
338
372
  }
339
373
 
@@ -343,7 +377,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
343
377
  * @param {(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void} callback - Listener callback.
344
378
  * @returns {void}
345
379
  */
346
- public onVisibilityChanged(callback: (evtToken: IEventCallback, model: OptionModel, visible: boolean) => void): void {
380
+ public onVisibilityChanged(
381
+ callback: (
382
+ evtToken: IEventCallback,
383
+ model: OptionModel,
384
+ visible: boolean,
385
+ ) => void,
386
+ ): void {
347
387
  this.privOnVisibilityChanged.push(callback);
348
388
  }
349
389
 
@@ -389,7 +429,8 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
389
429
  }
390
430
  }
391
431
 
392
- if (this.targetElement) this.selectedNonTrigger = this.targetElement.selected;
432
+ if (this.targetElement)
433
+ this.selectedNonTrigger = this.targetElement.selected;
393
434
 
394
435
  super.update();
395
436
  }
@@ -416,7 +457,7 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
416
457
  this.privOnVisibilityChanged = [];
417
458
  this.group = null;
418
459
  this.textToFind = null;
419
-
460
+
420
461
  super.destroy();
421
462
  }
422
- }
463
+ }
@@ -38,7 +38,7 @@ export class DatasetObserver {
38
38
  * Debounce timer handle for coalescing rapid attribute mutations.
39
39
  * Cleared/replaced whenever a new relevant mutation arrives within the debounce window.
40
40
  */
41
- private debounceTimer: ReturnType<typeof setTimeout> | null = null;
41
+ private debounceTimer?: NodeJS.Timeout;
42
42
 
43
43
  /**
44
44
  * Creates a {@link DatasetObserver} for the given element.
@@ -62,7 +62,10 @@ export class DatasetObserver {
62
62
  let datasetChanged = false;
63
63
 
64
64
  for (const mutation of mutations) {
65
- if (mutation.type === "attributes" && mutation.attributeName?.startsWith("data-")) {
65
+ if (
66
+ mutation.type === "attributes" &&
67
+ mutation.attributeName?.startsWith("data-")
68
+ ) {
66
69
  datasetChanged = true;
67
70
  break;
68
71
  }
@@ -132,4 +135,4 @@ export class DatasetObserver {
132
135
  this.debounceTimer = null;
133
136
  this.observer.disconnect();
134
137
  }
135
- }
138
+ }
@@ -43,7 +43,7 @@ export class ElementAdditionObserver<T extends Element = Element> {
43
43
  *
44
44
  * @internal
45
45
  */
46
- private observer: MutationObserver | null = null;
46
+ private observer?: MutationObserver;
47
47
 
48
48
  /**
49
49
  * Registered detection callbacks.
@@ -27,7 +27,7 @@ import type {
27
27
  * @param query - CSS selector or element to control. When `null`, the effector is unbound.
28
28
  * @returns An effector instance implementing {@link EffectorInterface}.
29
29
  */
30
- export function Effector(query?: string | HTMLElement | null): EffectorInterface {
30
+ export function Effector(query?: string | HTMLElement): EffectorInterface {
31
31
  return new EffectorImpl(query ?? null);
32
32
  }
33
33
 
@@ -57,13 +57,13 @@ class EffectorImpl implements EffectorInterface {
57
57
  * Timeout used to finalize expand/collapse/swipe animations.
58
58
  * Cleared by {@link cancel}.
59
59
  */
60
- private timeOut: ReturnType<typeof setTimeout> | null = null;
60
+ private timeOut?: NodeJS.Timeout;
61
61
 
62
62
  /**
63
63
  * Timeout used to clear transitions after resize in non-animated scenarios.
64
64
  * Cleared by {@link cancel}.
65
65
  */
66
- private resizeTimeout: ReturnType<typeof setTimeout> | null = null;
66
+ private resizeTimeout?: NodeJS.Timeout;
67
67
 
68
68
  /**
69
69
  * Internal animation flag set while a timed animation is in-flight.
@@ -80,7 +80,7 @@ class EffectorImpl implements EffectorInterface {
80
80
  *
81
81
  * @param query - CSS selector or element to control. When `null`, instance starts unbound.
82
82
  */
83
- public constructor(query: string | HTMLElement | null = null) {
83
+ public constructor(query?: string | HTMLElement) {
84
84
  if (query) this.setElement(query);
85
85
  }
86
86
 
@@ -145,7 +145,9 @@ class EffectorImpl implements EffectorInterface {
145
145
  * @param display - The display style to use for measurement (defaults to `"flex"`).
146
146
  * @returns A dimension snapshot including `scrollHeight` adjusted for vertical borders.
147
147
  */
148
- public getHiddenDimensions(display: "flex" | string = "flex"): DimensionObject {
148
+ public getHiddenDimensions(
149
+ display: "flex" | string = "flex",
150
+ ): DimensionObject {
149
151
  // Guard: element may not be set yet.
150
152
  if (!this.element) return { width: 0, height: 0, scrollHeight: 0 };
151
153
 
@@ -169,7 +171,8 @@ class EffectorImpl implements EffectorInterface {
169
171
  const borderTopWidth = parseFloat(cs.borderTopWidth);
170
172
  const borderBottomWidth = parseFloat(cs.borderBottomWidth);
171
173
 
172
- const scrollHeight = this.element.scrollHeight + borderTopWidth + borderBottomWidth;
174
+ const scrollHeight =
175
+ this.element.scrollHeight + borderTopWidth + borderBottomWidth;
173
176
  const rect = this.element.getBoundingClientRect();
174
177
 
175
178
  const dimensions: DimensionObject = {
@@ -286,10 +289,14 @@ class EffectorImpl implements EffectorInterface {
286
289
 
287
290
  const currentHeight = this.element.offsetHeight;
288
291
  const currentTop = this.element.offsetTop;
289
- const position = this.element.classList.contains("position-top") ? "top" : "bottom";
290
- const isScrollable = this.element.scrollHeight - this.element.offsetHeight > 0;
292
+ const position = this.element.classList.contains("position-top")
293
+ ? "top"
294
+ : "bottom";
295
+ const isScrollable =
296
+ this.element.scrollHeight - this.element.offsetHeight > 0;
291
297
 
292
- const finalTop = position === "top" ? currentTop + currentHeight : currentTop;
298
+ const finalTop =
299
+ position === "top" ? currentTop + currentHeight : currentTop;
293
300
 
294
301
  requestAnimationFrame(() => {
295
302
  Object.assign(this.element.style, {
@@ -459,7 +466,9 @@ class EffectorImpl implements EffectorInterface {
459
466
  onComplete,
460
467
  } = config;
461
468
 
462
- const currentPosition = this.element.classList.contains("position-top") ? "top" : "bottom";
469
+ const currentPosition = this.element.classList.contains("position-top")
470
+ ? "top"
471
+ : "bottom";
463
472
  const isPositionChanged = currentPosition !== position;
464
473
  const isScrollable = this.element.scrollHeight > maxHeight;
465
474
 
@@ -471,7 +480,8 @@ class EffectorImpl implements EffectorInterface {
471
480
  }
472
481
 
473
482
  requestAnimationFrame(() => {
474
- const styles: Partial<CSSStyleDeclaration> & Record<string, string> = {
483
+ const styles: Partial<CSSStyleDeclaration> &
484
+ Record<string, string> = {
475
485
  width: `${width}px`,
476
486
  left: `${left}px`,
477
487
  top: `${top}px`,
@@ -521,4 +531,4 @@ class EffectorImpl implements EffectorInterface {
521
531
  public get isAnimating(): boolean {
522
532
  return this._isAnimating;
523
533
  }
524
- }
534
+ }
@@ -37,7 +37,10 @@ export class Refresher {
37
37
  * @param select - Native `<select>` element used as the sizing reference and option source.
38
38
  * @param view - View panel element whose inline styles will be updated.
39
39
  */
40
- public static resizeBox(select: HTMLSelectElement, view: HTMLElement): void {
40
+ public static resizeBox(
41
+ select: HTMLSelectElement,
42
+ view: HTMLElement,
43
+ ): void {
41
44
  const bindedMap = Libs.getBinderMap<BinderMap>(select);
42
45
  if (!bindedMap?.options) return;
43
46
 
@@ -55,11 +58,12 @@ export class Refresher {
55
58
  const cstyle = getComputedStyle(select);
56
59
 
57
60
  if (width === "0px" && cstyle.width !== "auto") width = cstyle.width;
58
- if (height === "0px" && cstyle.height !== "auto") height = cstyle.height;
61
+ if (height === "0px" && cstyle.height !== "auto")
62
+ height = cstyle.height;
59
63
 
60
64
  if (cfgWidth > 0) width = options.width;
61
65
  if (cfgHeight > 0) height = options.height;
62
66
 
63
67
  Object.assign(view.style, { width, height, minWidth, minHeight });
64
68
  }
65
- }
69
+ }
@@ -63,7 +63,7 @@ export class ResizeObserverService {
63
63
  * @remarks
64
64
  * Set by {@link connect} and cleared by {@link disconnect}.
65
65
  */
66
- public element: HTMLElement | null = null;
66
+ public element?: HTMLElement;
67
67
 
68
68
  /**
69
69
  * Underlying `ResizeObserver` instance.
@@ -71,7 +71,7 @@ export class ResizeObserverService {
71
71
  * @remarks
72
72
  * Allocated on {@link connect}. Disconnected and nulled on {@link disconnect}.
73
73
  */
74
- private resizeObserver: ResizeObserver | null = null;
74
+ private resizeObserver?: ResizeObserver;
75
75
 
76
76
  /**
77
77
  * Underlying `MutationObserver` instance watching `style` and `class` attribute changes.
@@ -79,7 +79,7 @@ export class ResizeObserverService {
79
79
  * @remarks
80
80
  * Allocated on {@link connect}. Disconnected and nulled on {@link disconnect}.
81
81
  */
82
- private mutationObserver: MutationObserver | null = null;
82
+ private mutationObserver?: MutationObserver;
83
83
 
84
84
  /**
85
85
  * Stable, `this`-bound handler shared by observers and global event listeners.
@@ -115,7 +115,7 @@ export class ResizeObserverService {
115
115
  * @param metrics - Snapshot of geometry and box edges (padding/border/margin).
116
116
  */
117
117
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
118
- public onChanged(metrics: ElementMetrics): void { }
118
+ public onChanged(metrics: ElementMetrics): void {}
119
119
 
120
120
  /**
121
121
  * Computes metrics for the current {@link element} and forwards them to {@link onChanged}.
@@ -150,7 +150,8 @@ export class ResizeObserverService {
150
150
 
151
151
  const rect = el.getBoundingClientRect();
152
152
  const style =
153
- typeof window !== "undefined" && typeof window.getComputedStyle === "function"
153
+ typeof window !== "undefined" &&
154
+ typeof window.getComputedStyle === "function"
154
155
  ? window.getComputedStyle(el)
155
156
  : null;
156
157
 
@@ -233,8 +234,14 @@ export class ResizeObserverService {
233
234
  window.addEventListener("resize", this.boundUpdateChanged);
234
235
 
235
236
  if (window.visualViewport) {
236
- window.visualViewport.addEventListener("resize", this.boundUpdateChanged);
237
- window.visualViewport.addEventListener("scroll", this.boundUpdateChanged);
237
+ window.visualViewport.addEventListener(
238
+ "resize",
239
+ this.boundUpdateChanged,
240
+ );
241
+ window.visualViewport.addEventListener(
242
+ "scroll",
243
+ this.boundUpdateChanged,
244
+ );
238
245
  }
239
246
  }
240
247
 
@@ -254,18 +261,24 @@ export class ResizeObserverService {
254
261
  this.resizeObserver?.disconnect();
255
262
  this.mutationObserver?.disconnect();
256
263
 
257
- this.onChanged = (_metrics: ElementMetrics) => { };
264
+ this.onChanged = (_metrics: ElementMetrics) => {};
258
265
 
259
266
  window.removeEventListener("scroll", this.boundUpdateChanged, true);
260
267
  window.removeEventListener("resize", this.boundUpdateChanged);
261
268
 
262
269
  if (window.visualViewport) {
263
- window.visualViewport.removeEventListener("resize", this.boundUpdateChanged);
264
- window.visualViewport.removeEventListener("scroll", this.boundUpdateChanged);
270
+ window.visualViewport.removeEventListener(
271
+ "resize",
272
+ this.boundUpdateChanged,
273
+ );
274
+ window.visualViewport.removeEventListener(
275
+ "scroll",
276
+ this.boundUpdateChanged,
277
+ );
265
278
  }
266
279
 
267
280
  this.resizeObserver = null;
268
281
  this.mutationObserver = null;
269
282
  this.element = null;
270
283
  }
271
- }
284
+ }
@@ -62,7 +62,7 @@ export class SelectObserver {
62
62
  *
63
63
  * @private
64
64
  */
65
- private debounceTimer: ReturnType<typeof setTimeout> | null = null;
65
+ private debounceTimer?: NodeJS.Timeout;
66
66
 
67
67
  /**
68
68
  * Debounce delay in milliseconds.
@@ -171,4 +171,4 @@ export class SelectObserver {
171
171
  this.debounceTimer = null;
172
172
  this.observer.disconnect();
173
173
  }
174
- }
174
+ }
@@ -12,4 +12,21 @@ export interface VirtualRecyclerOptions {
12
12
  estimateItemHeight?: number;
13
13
  overscan?: number;
14
14
  dynamicHeights?: boolean;
15
- }
15
+ }
16
+
17
+ export interface PopupPosition {
18
+ position: "top" | "bottom";
19
+ top: number;
20
+ maxHeight: number;
21
+ realHeight: number;
22
+ contentHeight: number;
23
+ }
24
+
25
+ export interface PopupLocaltion {
26
+ width: number;
27
+ height: number;
28
+ top: number;
29
+ left: number;
30
+ padding: { top: number; right: number; bottom: number; left: number };
31
+ border: { top: number; right: number; bottom: number; left: number };
32
+ }