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
@@ -62,9 +62,12 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
62
62
  * @see {@link ModelContract}
63
63
  */
64
64
  export class Adapter<
65
- TItem extends ModelContract<any, any> & { view: TViewer | null; isInit: boolean },
66
- TViewer extends ViewContract<any>
67
- > extends Lifecycle implements AdapterContract<TItem> {
65
+ TItem extends ModelContract<any, any> & { view?: TViewer; isInit: boolean },
66
+ TViewer extends ViewContract<any>,
67
+ >
68
+ extends Lifecycle
69
+ implements AdapterContract<TItem>
70
+ {
68
71
  /**
69
72
  * Current list of items managed by the adapter.
70
73
  *
@@ -92,6 +95,17 @@ export class Adapter<
92
95
  */
93
96
  recyclerView: any;
94
97
 
98
+ /**
99
+ * Tracks all scheduler keys registered by this adapter instance via
100
+ * {@link onPropChanging} and {@link onPropChanged}.
101
+ *
102
+ * Used during {@link destroy} to clean up all associated pipelines
103
+ * from the global {@link Libs.callbackScheduler}.
104
+ *
105
+ * Keys are deduplicated automatically by Set semantics.
106
+ */
107
+ callbackSchedulerList: Set<string> = new Set();
108
+
95
109
  /**
96
110
  * Creates an adapter with an optional initial item list and initializes its lifecycle.
97
111
  *
@@ -118,7 +132,11 @@ export class Adapter<
118
132
  * @param {number} position - Index of the item within the adapter item list.
119
133
  * @returns {void}
120
134
  */
121
- public onViewHolder(item: TItem, viewer: TViewer | null, position: number): void {
135
+ public onViewHolder(
136
+ item: TItem,
137
+ viewer?: TViewer,
138
+ position?: number,
139
+ ): void {
122
140
  void position;
123
141
 
124
142
  const v = viewer;
@@ -142,8 +160,17 @@ export class Adapter<
142
160
  * @returns {void}
143
161
  * @see {@link changingProp}
144
162
  */
145
- public onPropChanging(propName: string, callback: (...args: unknown[]) => void): void {
146
- Libs.callbackScheduler.on(`${propName}ing_${this.adapterKey}`, callback, { debounce: 0 });
163
+ public onPropChanging(
164
+ propName: string,
165
+ callback: (...args: unknown[]) => void,
166
+ ): void {
167
+ const key = `${propName}ing_${this.adapterKey}`;
168
+ Libs.callbackScheduler.on(
169
+ key,
170
+ callback,
171
+ { debounce: 0 },
172
+ );
173
+ this.callbackSchedulerList.add(key);
147
174
  }
148
175
 
149
176
  /**
@@ -159,8 +186,15 @@ export class Adapter<
159
186
  * @returns {void}
160
187
  * @see {@link changeProp}
161
188
  */
162
- public onPropChanged(propName: string, callback: (...args: unknown[]) => void): void {
163
- Libs.callbackScheduler.on(`${propName}_${this.adapterKey}`, callback, { debounce: 0 });
189
+ public onPropChanged(
190
+ propName: string,
191
+ callback: (...args: unknown[]) => void,
192
+ ): void {
193
+ const key = `${propName}_${this.adapterKey}`;
194
+ Libs.callbackScheduler.on(key, callback, {
195
+ debounce: 0,
196
+ });
197
+ this.callbackSchedulerList.add(key);
164
198
  }
165
199
 
166
200
  /**
@@ -174,7 +208,10 @@ export class Adapter<
174
208
  * @returns {Promise<void>} Resolves when scheduled callbacks complete.
175
209
  */
176
210
  public changeProp(propName: string, ...params: unknown[]): Promise<void> {
177
- return Libs.callbackScheduler.run(`${propName}_${this.adapterKey}`, ...params);
211
+ return Libs.callbackScheduler.run(
212
+ `${propName}_${this.adapterKey}`,
213
+ ...params,
214
+ );
178
215
  }
179
216
 
180
217
  /**
@@ -188,7 +225,10 @@ export class Adapter<
188
225
  * @returns {Promise<void>} Resolves when scheduled callbacks complete.
189
226
  */
190
227
  public changingProp(propName: string, ...params: unknown[]): Promise<void> {
191
- return Libs.callbackScheduler.run(`${propName}ing_${this.adapterKey}`, ...params);
228
+ return Libs.callbackScheduler.run(
229
+ `${propName}ing_${this.adapterKey}`,
230
+ ...params,
231
+ );
192
232
  }
193
233
 
194
234
  /**
@@ -198,9 +238,9 @@ export class Adapter<
198
238
  *
199
239
  * @param {HTMLElement} parent - Container element that will host the viewer.
200
240
  * @param {TItem} item - The model for which the viewer is created.
201
- * @returns {TViewer | null} The created viewer instance; `null` by default.
241
+ * @returns {TViewer} The created viewer instance; `null` by default.
202
242
  */
203
- public viewHolder(parent: HTMLElement, item: TItem): TViewer | null {
243
+ public viewHolder?(parent: HTMLElement, item: TItem): TViewer {
204
244
  void parent;
205
245
  void item;
206
246
  return null;
@@ -316,10 +356,17 @@ export class Adapter<
316
356
  return;
317
357
  }
318
358
 
359
+ this.callbackSchedulerList.forEach((key) => {
360
+ Libs.callbackScheduler.off(key);
361
+ });
362
+
363
+ this.callbackSchedulerList.clear();
319
364
  this.recyclerView = null;
320
- this.items.forEach(item => {
365
+ this.items.forEach((item) => {
321
366
  item?.destroy?.();
322
367
  });
323
368
  this.items = [];
369
+
370
+ super.destroy();
324
371
  }
325
- }
372
+ }
@@ -131,7 +131,8 @@ export class Fenwick extends Lifecycle {
131
131
  * Returns 0 if the first element already exceeds `target`.
132
132
  */
133
133
  public lowerBoundPrefix(target: number): number {
134
- let idx = 0, bitMask = 1;
134
+ let idx = 0,
135
+ bitMask = 1;
135
136
  while (bitMask << 1 <= this.stackNum) bitMask <<= 1;
136
137
 
137
138
  let cur = 0;
@@ -144,4 +145,4 @@ export class Fenwick extends Lifecycle {
144
145
  }
145
146
  return idx;
146
147
  }
147
- }
148
+ }
@@ -1,4 +1,8 @@
1
- import { LifecycleHookContext, LifecycleHooks, LifecycleState } from "src/ts/types/core/base/lifecycle.type";
1
+ import {
2
+ LifecycleHookContext,
3
+ LifecycleHooks,
4
+ LifecycleState,
5
+ } from "src/ts/types/core/base/lifecycle.type";
2
6
 
3
7
  type LifecycleHookName = keyof LifecycleHooks;
4
8
 
@@ -59,7 +63,10 @@ export class Lifecycle {
59
63
  * This map is initialized with keys for all supported hooks in the constructor.
60
64
  * Callbacks are cleared on {@link destroy}.
61
65
  */
62
- private hooks: Map<LifecycleHookName, Set<(ctx: LifecycleHookContext) => void>> = new Map();
66
+ private hooks: Map<
67
+ LifecycleHookName,
68
+ Set<(ctx: LifecycleHookContext) => void>
69
+ > = new Map();
63
70
 
64
71
  /**
65
72
  * Constructs the lifecycle manager and pre-registers hook containers.
@@ -98,7 +105,10 @@ export class Lifecycle {
98
105
  * @param {(ctx: LifecycleHookContext) => void} fn - Callback to remove.
99
106
  * @returns {this} The current instance (chainable).
100
107
  */
101
- off(hook: LifecycleHookName, fn: (ctx: LifecycleHookContext) => void): this {
108
+ off(
109
+ hook: LifecycleHookName,
110
+ fn: (ctx: LifecycleHookContext) => void,
111
+ ): this {
102
112
  this.hooks.get(hook)!.delete(fn);
103
113
  return this;
104
114
  }
@@ -255,4 +265,4 @@ export class Lifecycle {
255
265
  set.clear();
256
266
  }
257
267
  }
258
- }
268
+ }
@@ -43,16 +43,18 @@ export class Model<
43
43
  TTarget extends HTMLElement,
44
44
  TTags extends Record<string, HTMLElement>,
45
45
  TView extends ViewContract<TTags>,
46
- TOptions = unknown
47
- > extends Lifecycle implements ModelContract<TTarget, TView> {
48
-
46
+ TOptions = unknown,
47
+ >
48
+ extends Lifecycle
49
+ implements ModelContract<TTarget, TView>
50
+ {
49
51
  /**
50
52
  * The currently bound target DOM element.
51
53
  *
52
54
  * This element typically represents the source-of-truth node in the host DOM (e.g., a native `<option>`).
53
55
  * May be replaced via {@link updateTarget} during reconciliation.
54
56
  */
55
- public targetElement: TTarget | null = null;
57
+ public targetElement?: TTarget;
56
58
 
57
59
  /**
58
60
  * Configuration options supplied at construction time.
@@ -66,25 +68,25 @@ export class Model<
66
68
  * Ownership: this model will destroy the view on {@link destroy}.
67
69
  * The view may be attached/assigned by external orchestrators (Adapter/RecyclerView) after construction.
68
70
  */
69
- public view: TView | null = null;
71
+ public view?: TView;
70
72
 
71
73
  /**
72
74
  * Position index used by list infrastructure for ordering/tracking.
73
75
  * Semantics are library-specific (e.g., top-level index or adapter position).
74
76
  */
75
- public position = -1;
77
+ public position: number = -1;
76
78
 
77
79
  /**
78
80
  * Indicates whether this model has completed its initial binding step.
79
81
  * Typically set by the adapter/view binding layer to prevent duplicate listener wiring.
80
82
  */
81
- public isInit = false;
83
+ public isInit: boolean = false;
82
84
 
83
85
  /**
84
86
  * Indicates whether this model has been removed/destroyed from the active dataset.
85
87
  * Set to `true` during {@link destroy}.
86
88
  */
87
- public isRemoved = false;
89
+ public isRemoved: boolean = false;
88
90
 
89
91
  /**
90
92
  * Returns the current "value" associated with the bound target element.
@@ -107,13 +109,13 @@ export class Model<
107
109
  * - Calls {@link Lifecycle.init} immediately (`NEW → INITIALIZED`).
108
110
  *
109
111
  * @param {TOptions} options - Configuration options for the model.
110
- * @param {TTarget | null} [targetElement=null] - Optional DOM element to bind.
111
- * @param {TView | null} [view=null] - Optional view responsible for rendering this model.
112
+ * @param {TTarget} [targetElement=null] - Optional DOM element to bind.
113
+ * @param {TView} [view=null] - Optional view responsible for rendering this model.
112
114
  */
113
115
  public constructor(
114
116
  options: TOptions,
115
- targetElement: TTarget | null = null,
116
- view: TView | null = null
117
+ targetElement?: TTarget,
118
+ view?: TView,
117
119
  ) {
118
120
  super();
119
121
  this.options = options;
@@ -134,10 +136,10 @@ export class Model<
134
136
  * - Assigns {@link targetElement}.
135
137
  * - Calls {@link Lifecycle.update} (guarded by lifecycle state).
136
138
  *
137
- * @param {TTarget | null} targetElement - The new DOM element to associate with this model.
139
+ * @param {TTarget} targetElement - The new DOM element to associate with this model.
138
140
  * @returns {void}
139
141
  */
140
- public updateTarget(targetElement: TTarget | null): void {
142
+ public updateTarget(targetElement?: TTarget): void {
141
143
  this.targetElement = targetElement;
142
144
  this.update();
143
145
  }
@@ -167,4 +169,4 @@ export class Model<
167
169
 
168
170
  super.destroy();
169
171
  }
170
- }
172
+ }
@@ -22,9 +22,11 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
22
22
  */
23
23
  export class RecyclerView<
24
24
  TItem extends ModelContract<any, any>,
25
- TAdapter extends AdapterContract<TItem>
26
- > extends Lifecycle implements RecyclerViewContract<TAdapter> {
27
-
25
+ TAdapter extends AdapterContract<TItem>,
26
+ >
27
+ extends Lifecycle
28
+ implements RecyclerViewContract<TAdapter>
29
+ {
28
30
  /** Root container that hosts rendered item views. */
29
31
  public viewElement: HTMLDivElement | null = null;
30
32
 
@@ -113,10 +115,10 @@ export class RecyclerView<
113
115
  if (this.is(LifecycleState.DESTROYED)) {
114
116
  return;
115
117
  }
116
-
118
+
117
119
  this.viewElement = null;
118
120
  this.adapter = null;
119
121
 
120
122
  super.destroy();
121
123
  }
122
- }
124
+ }
@@ -39,13 +39,16 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
39
39
  * @see {@link ViewContract}
40
40
  * @see {@link LifecycleState}
41
41
  */
42
- export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle implements ViewContract<TTags> {
42
+ export class View<TTags extends Record<string, HTMLElement>>
43
+ extends Lifecycle
44
+ implements ViewContract<TTags>
45
+ {
43
46
  /**
44
47
  * Host container element into which this view's root element is rendered/attached.
45
48
  *
46
49
  * This reference is captured at construction time and cleared on {@link destroy}.
47
50
  */
48
- public parent: HTMLElement | null = null;
51
+ public parent?: HTMLElement;
49
52
 
50
53
  /**
51
54
  * Mounted view result containing:
@@ -54,7 +57,7 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
54
57
  *
55
58
  * This is expected to be assigned by subclasses (or a mount helper) before {@link getView} is called.
56
59
  */
57
- public view: MountViewResult<TTags> | null = null;
60
+ public view?: MountViewResult<TTags>;
58
61
 
59
62
  /**
60
63
  * Creates a View bound to the specified parent container and initializes lifecycle state.
@@ -79,7 +82,9 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
79
82
  */
80
83
  public getView(): HTMLElement {
81
84
  if (!this.view?.view) {
82
- throw new Error("View is not mounted. Did you forget to set this.view?");
85
+ throw new Error(
86
+ "View is not mounted. Did you forget to set this.view?",
87
+ );
83
88
  }
84
89
  return this.view.view;
85
90
  }
@@ -108,4 +113,4 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
108
113
 
109
114
  super.destroy();
110
115
  }
111
- }
116
+ }