selective-ui 1.4.0 → 1.4.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 (71) hide show
  1. package/dist/selective-ui.css +2 -2
  2. package/dist/selective-ui.css.map +1 -1
  3. package/dist/selective-ui.esm.js +407 -573
  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 +409 -575
  12. package/dist/selective-ui.umd.js.map +1 -1
  13. package/package.json +12 -12
  14. package/src/css/views/option-view.css +2 -2
  15. package/src/ts/adapter/mixed-adapter.ts +149 -71
  16. package/src/ts/components/accessorybox.ts +14 -11
  17. package/src/ts/components/directive.ts +1 -1
  18. package/src/ts/components/option-handle.ts +12 -9
  19. package/src/ts/components/placeholder.ts +5 -5
  20. package/src/ts/components/popup/empty-state.ts +5 -5
  21. package/src/ts/components/popup/loading-state.ts +5 -5
  22. package/src/ts/components/popup/popup.ts +138 -76
  23. package/src/ts/components/searchbox.ts +17 -13
  24. package/src/ts/components/selectbox.ts +260 -84
  25. package/src/ts/core/base/adapter.ts +61 -14
  26. package/src/ts/core/base/fenwick.ts +3 -2
  27. package/src/ts/core/base/lifecycle.ts +14 -4
  28. package/src/ts/core/base/model.ts +17 -15
  29. package/src/ts/core/base/recyclerview.ts +7 -5
  30. package/src/ts/core/base/view.ts +10 -5
  31. package/src/ts/core/base/virtual-recyclerview.ts +178 -45
  32. package/src/ts/core/model-manager.ts +48 -21
  33. package/src/ts/core/search-controller.ts +174 -56
  34. package/src/ts/global.ts +5 -8
  35. package/src/ts/index.ts +2 -2
  36. package/src/ts/models/group-model.ts +33 -8
  37. package/src/ts/models/option-model.ts +88 -20
  38. package/src/ts/services/dataset-observer.ts +6 -3
  39. package/src/ts/services/ea-observer.ts +1 -1
  40. package/src/ts/services/effector.ts +22 -12
  41. package/src/ts/services/refresher.ts +14 -4
  42. package/src/ts/services/resize-observer.ts +24 -11
  43. package/src/ts/services/select-observer.ts +2 -2
  44. package/src/ts/types/components/popup.type.ts +18 -1
  45. package/src/ts/types/components/searchbox.type.ts +43 -30
  46. package/src/ts/types/components/state.box.type.ts +1 -1
  47. package/src/ts/types/core/base/adapter.type.ts +13 -5
  48. package/src/ts/types/core/base/lifecycle.type.ts +1 -2
  49. package/src/ts/types/core/base/model.type.ts +3 -3
  50. package/src/ts/types/core/base/recyclerview.type.ts +7 -5
  51. package/src/ts/types/core/base/view.type.ts +6 -6
  52. package/src/ts/types/core/base/virtual-recyclerview.type.ts +45 -46
  53. package/src/ts/types/core/search-controller.type.ts +18 -2
  54. package/src/ts/types/css.d.ts +1 -0
  55. package/src/ts/types/plugins/plugin.type.ts +2 -2
  56. package/src/ts/types/services/effector.type.ts +25 -25
  57. package/src/ts/types/services/resize-observer.type.ts +23 -12
  58. package/src/ts/types/utils/callback-scheduler.type.ts +2 -2
  59. package/src/ts/types/utils/ievents.type.ts +1 -1
  60. package/src/ts/types/utils/istorage.type.ts +62 -60
  61. package/src/ts/types/utils/libs.type.ts +19 -17
  62. package/src/ts/types/utils/selective.type.ts +6 -3
  63. package/src/ts/types/views/view.group.type.ts +9 -5
  64. package/src/ts/types/views/view.option.type.ts +39 -17
  65. package/src/ts/utils/callback-scheduler.ts +12 -7
  66. package/src/ts/utils/ievents.ts +12 -5
  67. package/src/ts/utils/istorage.ts +5 -3
  68. package/src/ts/utils/libs.ts +122 -43
  69. package/src/ts/utils/selective.ts +15 -8
  70. package/src/ts/views/group-view.ts +11 -9
  71. package/src/ts/views/option-view.ts +37 -18
@@ -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,37 @@ 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
+ );
267
+ }
268
+
269
+ /**
270
+ * Resolved display mask for this option.
271
+ *
272
+ * The mask is the primary render label used by the UI layer and supports
273
+ * optional inline tag translation / rich HTML rendering.
274
+ *
275
+ * Source priority:
276
+ * 1. `data-mask` (`dataset.mask`)
277
+ * 2. Native `<option>` text content (`targetElement.text`)
278
+ *
279
+ * Processing pipeline:
280
+ * - Raw content is first passed through {@link Libs.tagTranslate}.
281
+ * - When `options.allowHtml === true`, translated HTML is preserved.
282
+ * - Otherwise, all markup is stripped via {@link Libs.stripHtml}.
283
+ *
284
+ * Unlike {@link text}, this getter prioritizes the custom dataset mask,
285
+ * making it suitable for display overrides without mutating the native
286
+ * `<option>` label.
287
+ *
288
+ * @returns {string} Render-ready option label.
289
+ */
290
+ public get mask(): string {
291
+ const raw = this.dataset?.mask ?? this.targetElement?.text ?? "";
292
+ const translated = Libs.tagTranslate(raw);
293
+ return this.options.allowHtml ? translated : Libs.stripHtml(translated);
247
294
  }
248
295
 
249
296
  /**
@@ -259,7 +306,7 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
259
306
  * @returns {string}
260
307
  */
261
308
  public get text(): string {
262
- const raw = this.dataset?.mask ?? this.targetElement?.text ?? "";
309
+ const raw = this.targetElement?.text ?? this.dataset?.mask ?? "";
263
310
  const translated = Libs.tagTranslate(raw);
264
311
  return this.options.allowHtml ? translated : Libs.stripHtml(translated);
265
312
  }
@@ -273,7 +320,9 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
273
320
  * @returns {string}
274
321
  */
275
322
  public get textContent(): string {
276
- return this.options.allowHtml ? Libs.stripHtml(this.text).trim() : this.text.trim();
323
+ return this.options.allowHtml
324
+ ? Libs.stripHtml(this.text).trim()
325
+ : this.text.trim();
277
326
  }
278
327
 
279
328
  /**
@@ -323,7 +372,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
323
372
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
324
373
  * @returns {void}
325
374
  */
326
- public onSelected(callback: (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void): void {
375
+ public onSelected(
376
+ callback: (
377
+ evtToken: IEventCallback,
378
+ el: OptionModel,
379
+ selected: boolean,
380
+ ) => void,
381
+ ): void {
327
382
  this.privOnSelected.push(callback);
328
383
  }
329
384
 
@@ -333,7 +388,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
333
388
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
334
389
  * @returns {void}
335
390
  */
336
- public onInternalSelected(callback: (evtToken: IEventCallback, el: OptionModel, selected: boolean) => void): void {
391
+ public onInternalSelected(
392
+ callback: (
393
+ evtToken: IEventCallback,
394
+ el: OptionModel,
395
+ selected: boolean,
396
+ ) => void,
397
+ ): void {
337
398
  this.privOnInternalSelected.push(callback);
338
399
  }
339
400
 
@@ -343,7 +404,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
343
404
  * @param {(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void} callback - Listener callback.
344
405
  * @returns {void}
345
406
  */
346
- public onVisibilityChanged(callback: (evtToken: IEventCallback, model: OptionModel, visible: boolean) => void): void {
407
+ public onVisibilityChanged(
408
+ callback: (
409
+ evtToken: IEventCallback,
410
+ model: OptionModel,
411
+ visible: boolean,
412
+ ) => void,
413
+ ): void {
347
414
  this.privOnVisibilityChanged.push(callback);
348
415
  }
349
416
 
@@ -389,7 +456,8 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
389
456
  }
390
457
  }
391
458
 
392
- if (this.targetElement) this.selectedNonTrigger = this.targetElement.selected;
459
+ if (this.targetElement)
460
+ this.selectedNonTrigger = this.targetElement.selected;
393
461
 
394
462
  super.update();
395
463
  }
@@ -416,7 +484,7 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
416
484
  this.privOnVisibilityChanged = [];
417
485
  this.group = null;
418
486
  this.textToFind = null;
419
-
487
+
420
488
  super.destroy();
421
489
  }
422
- }
490
+ }
@@ -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
+ }
@@ -36,8 +36,13 @@ export class Refresher {
36
36
  *
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
+ * @param isWidthOnly - If true, only the width will be updated; height will be left unchanged.
39
40
  */
40
- public static resizeBox(select: HTMLSelectElement, view: HTMLElement): void {
41
+ public static resizeBox(
42
+ select: HTMLSelectElement,
43
+ view: HTMLElement,
44
+ isWidthOnly = false,
45
+ ): void {
41
46
  const bindedMap = Libs.getBinderMap<BinderMap>(select);
42
47
  if (!bindedMap?.options) return;
43
48
 
@@ -55,11 +60,16 @@ export class Refresher {
55
60
  const cstyle = getComputedStyle(select);
56
61
 
57
62
  if (width === "0px" && cstyle.width !== "auto") width = cstyle.width;
58
- if (height === "0px" && cstyle.height !== "auto") height = cstyle.height;
63
+ if (height === "0px" && cstyle.height !== "auto")
64
+ height = cstyle.height;
59
65
 
60
66
  if (cfgWidth > 0) width = options.width;
61
67
  if (cfgHeight > 0) height = options.height;
62
68
 
63
- Object.assign(view.style, { width, height, minWidth, minHeight });
69
+ if (isWidthOnly) {
70
+ Object.assign(view.style, { width, maxWidth: width, minWidth });
71
+ } else {
72
+ Object.assign(view.style, { width, height, maxWidth: width, minWidth, minHeight });
73
+ }
64
74
  }
65
- }
75
+ }
@@ -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
+ }
@@ -14,8 +14,8 @@ import { OptionModel } from "src/ts/models/option-model";
14
14
  * Represents the DOM elements used in the SearchBox component.
15
15
  */
16
16
  export type SearchBoxTags = {
17
- SearchBox: HTMLDivElement; // Container for the search box
18
- SearchInput: HTMLInputElement; // Input field for search queries
17
+ SearchBox: HTMLDivElement; // Container for the search box
18
+ SearchInput: HTMLInputElement; // Input field for search queries
19
19
  };
20
20
 
21
21
  /**
@@ -35,7 +35,7 @@ export type NavigateHandler = (direction: 1 | -1) => void;
35
35
  * Represents the DOM elements used in the SelectBox component.
36
36
  */
37
37
  export type SelectBoxTags = {
38
- ViewPanel: HTMLDivElement; // Panel that displays selectable options
38
+ ViewPanel: HTMLDivElement; // Panel that displays selectable options
39
39
  };
40
40
 
41
41
  /**
@@ -43,46 +43,46 @@ export type SelectBoxTags = {
43
43
  * Combines mounted view result with additional services and components.
44
44
  */
45
45
  export type ContainerRuntime = MountViewResult<SelectBoxTags> & {
46
- placeholder: PlaceHolder; // Placeholder manager
47
- directive: Directive; // Directive handler for dynamic behavior
48
- searchbox: SearchBox; // Search box component
49
- popup: Popup; // Popup component for dropdown
50
- effector: EffectorInterface; // Effector for state management
51
- targetElement: HTMLSelectElement; // Original select element
52
- accessorybox: AccessoryBox; // Accessory box for extra UI elements
46
+ placeholder: PlaceHolder; // Placeholder manager
47
+ directive: Directive; // Directive handler for dynamic behavior
48
+ searchbox: SearchBox; // Search box component
49
+ popup: Popup; // Popup component for dropdown
50
+ effector: EffectorInterface; // Effector for state management
51
+ targetElement: HTMLSelectElement; // Original select element
52
+ accessorybox: AccessoryBox; // Accessory box for extra UI elements
53
53
  searchController: SearchController; // Controller for search logic
54
- selectObserver: SelectObserver; // Observer for selection changes
55
- datasetObserver: DatasetObserver; // Observer for dataset updates
54
+ selectObserver: SelectObserver; // Observer for selection changes
55
+ datasetObserver: DatasetObserver; // Observer for dataset updates
56
56
  };
57
57
 
58
58
  /**
59
59
  * Interface defining actions and properties for the SelectBox component.
60
60
  */
61
61
  export interface SelectBoxAction {
62
- targetElement: HTMLSelectElement; // Target Select element
62
+ targetElement: HTMLSelectElement; // Target Select element
63
63
 
64
- placeholder: string; // Placeholder text
65
- oldValue: unknown; // Previous value before change
64
+ placeholder: string; // Placeholder text
65
+ oldValue: unknown; // Previous value before change
66
66
 
67
- value: string | string[]; // Current selected value(s)
68
- valueArray: string[]; // Selected values as an array
69
- valueString: string; // Selected values as a single string
67
+ value: string | string[]; // Current selected value(s)
68
+ valueArray: string[]; // Selected values as an array
69
+ valueString: string; // Selected values as a single string
70
70
 
71
- valueOptions: OptionModel[]; // Selected option models
72
- mask: string[]; // Masked values for filtering
73
- valueText: string | string[]; // Display text for selected values
71
+ valueOptions: OptionModel[]; // Selected option models
72
+ mask: string[]; // Masked values for filtering
73
+ valueText: string | string[]; // Display text for selected values
74
74
 
75
- isOpen: boolean; // Indicates if the dropdown is open
75
+ isOpen: boolean; // Indicates if the dropdown is open
76
76
 
77
- disabled: boolean; // Indicates if the component is disabled
78
- readonly: boolean; // Indicates if the component is read-only
79
- visible: boolean; // Indicates if the component is visible
77
+ disabled: boolean; // Indicates if the component is disabled
78
+ readonly: boolean; // Indicates if the component is read-only
79
+ visible: boolean; // Indicates if the component is visible
80
80
 
81
81
  /**
82
82
  * Get parent of self
83
83
  * @param evtToken - Optional event token for tracking.
84
84
  */
85
- getParent(evtToken?: unknown): HTMLElement
85
+ getParent(evtToken?: unknown): HTMLElement;
86
86
 
87
87
  /**
88
88
  * Get dataset from selected options
@@ -90,7 +90,11 @@ export interface SelectBoxAction {
90
90
  * @param strDataset - Property to find
91
91
  * @param isArray - Keep array or return once
92
92
  */
93
- valueDataset(evtToken?: unknown, strDataset?: string, isArray?: boolean): any[] | string
93
+ valueDataset(
94
+ evtToken?: unknown,
95
+ strDataset?: string,
96
+ isArray?: boolean,
97
+ ): any[] | string;
94
98
 
95
99
  /**
96
100
  * Select all available options.
@@ -113,7 +117,12 @@ export interface SelectBoxAction {
113
117
  * @param trigger - Whether to trigger change events.
114
118
  * @param force - Whether to force the update.
115
119
  */
116
- setValue(evtToken: unknown | null, value: unknown, trigger?: boolean, force?: boolean): void;
120
+ setValue(
121
+ evtToken?: unknown,
122
+ value?: unknown,
123
+ trigger?: boolean,
124
+ force?: boolean,
125
+ ): void;
117
126
 
118
127
  /**
119
128
  * Load options for the SelectBox, typically from an AJAX source.
@@ -156,7 +165,11 @@ export interface SelectBoxAction {
156
165
  * @param evtName - Name of the event.
157
166
  * @param handle - Callback function for the event.
158
167
  */
159
- on(evtToken: unknown, evtName: string, handle: (...args: any[]) => any): void;
168
+ on(
169
+ evtToken: unknown,
170
+ evtName: string,
171
+ handle: (...args: any[]) => any,
172
+ ): void;
160
173
 
161
174
  /**
162
175
  * Perform an AJAX request.
@@ -170,4 +183,4 @@ export interface SelectBoxAction {
170
183
  * @param evtToken - Event token for tracking.
171
184
  */
172
185
  loadAjax(evtToken: unknown, obj: unknown): void;
173
- }
186
+ }
@@ -3,4 +3,4 @@
3
3
  * - "notfound": No matching results found.
4
4
  * - "nodata": No data available to display.
5
5
  */
6
- export type EmptyStateType = "notfound" | "nodata";
6
+ export type EmptyStateType = "notfound" | "nodata";