selective-ui 1.2.0 → 1.2.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 (48) hide show
  1. package/dist/selective-ui.css +3 -1
  2. package/dist/selective-ui.css.map +1 -1
  3. package/dist/selective-ui.esm.js +487 -436
  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 +488 -437
  12. package/dist/selective-ui.umd.js.map +1 -1
  13. package/package.json +1 -1
  14. package/src/css/components/popup.css +3 -1
  15. package/src/ts/adapter/mixed-adapter.ts +56 -50
  16. package/src/ts/components/accessorybox.ts +49 -21
  17. package/src/ts/components/directive.ts +3 -3
  18. package/src/ts/components/empty-state.ts +7 -7
  19. package/src/ts/components/loading-state.ts +7 -7
  20. package/src/ts/components/option-handle.ts +17 -17
  21. package/src/ts/components/placeholder.ts +12 -12
  22. package/src/ts/components/popup.ts +93 -108
  23. package/src/ts/components/searchbox.ts +14 -14
  24. package/src/ts/components/selectbox.ts +41 -31
  25. package/src/ts/core/base/adapter.ts +12 -12
  26. package/src/ts/core/base/model.ts +12 -13
  27. package/src/ts/core/base/recyclerview.ts +7 -7
  28. package/src/ts/core/base/view.ts +6 -6
  29. package/src/ts/core/base/virtual-recyclerview.ts +51 -50
  30. package/src/ts/core/model-manager.ts +53 -53
  31. package/src/ts/core/search-controller.ts +70 -73
  32. package/src/ts/models/group-model.ts +21 -21
  33. package/src/ts/models/option-model.ts +50 -31
  34. package/src/ts/services/dataset-observer.ts +17 -17
  35. package/src/ts/services/ea-observer.ts +21 -21
  36. package/src/ts/services/effector.ts +30 -30
  37. package/src/ts/services/refresher.ts +1 -1
  38. package/src/ts/services/resize-observer.ts +29 -29
  39. package/src/ts/services/select-observer.ts +29 -29
  40. package/src/ts/types/components/popup.type.ts +15 -0
  41. package/src/ts/types/utils/istorage.type.ts +1 -1
  42. package/src/ts/utils/callback-scheduler.ts +4 -4
  43. package/src/ts/utils/ievents.ts +4 -4
  44. package/src/ts/utils/istorage.ts +5 -5
  45. package/src/ts/utils/libs.ts +38 -29
  46. package/src/ts/utils/selective.ts +11 -11
  47. package/src/ts/views/group-view.ts +7 -7
  48. package/src/ts/views/option-view.ts +51 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selective-ui",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "An overlay for the HTML select element.",
5
5
  "author": "Huỳnh Công Xuân Mai",
6
6
  "license": "MIT",
@@ -10,7 +10,7 @@
10
10
  display: none;
11
11
  position: fixed;
12
12
  z-index: 9999;
13
- overflow: none;
13
+ overflow: hidden;
14
14
  flex-direction: column;
15
15
 
16
16
  height: 0px;
@@ -22,6 +22,8 @@
22
22
  border-style: var(--seui-popup-border-style);
23
23
  border-width: var(--seui-popup-border-width);
24
24
  border-radius: var(--seui-popup-border-radius);
25
+
26
+ transition: none;
25
27
  }
26
28
 
27
29
  .selective-ui-options-container {
@@ -6,31 +6,47 @@ import { OptionView } from "../views/option-view";
6
6
  import { MixedItem, VisibilityStats } from "../types/core/base/mixed-adapter.type";
7
7
  import { IEventCallback } from "../types/utils/ievents.type";
8
8
  import { ImagePosition, LabelHalign, LabelValign } from "../types/views/view.option.type";
9
+ import { Libs } from "../utils/libs";
9
10
 
10
11
  /**
11
12
  * @extends {Adapter<GroupModel|OptionModel>}
12
13
  */
13
14
  export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
14
- isMultiple = false;
15
+ public isMultiple = false;
15
16
 
16
- private _visibilityChangedCallbacks: Array<(stats: VisibilityStats) => void> = [];
17
- private _currentHighlightIndex = -1;
17
+ private visibilityChangedCallbacks: Array<(stats: VisibilityStats) => void> = [];
18
+ private currentHighlightIndex = -1;
18
19
 
19
- private _selectedItemSingle: OptionModel | null = null;
20
+ private selectedItemSingle: OptionModel | null = null;
20
21
 
21
- groups: GroupModel[] = [];
22
+ public groups: GroupModel[] = [];
22
23
 
23
- flatOptions: OptionModel[] = [];
24
+ public flatOptions: OptionModel[] = [];
24
25
 
25
- constructor(items: MixedItem[] = []) {
26
+ public constructor(items: MixedItem[] = []) {
26
27
  super(items);
27
- this._buildFlatStructure();
28
+ this.buildFlatStructure();
29
+
30
+ Libs.callbackScheduler.on(`sche_vis_${this.adapterKey}`, () => {
31
+ const visibleCount = this.flatOptions.filter((item) => item.visible).length;
32
+ const totalCount = this.flatOptions.length;
33
+
34
+ this.visibilityChangedCallbacks.forEach((callback) => {
35
+ callback({
36
+ visibleCount,
37
+ totalCount,
38
+ hasVisible: visibleCount > 0,
39
+ isEmpty: totalCount === 0,
40
+ });
41
+ });
42
+ Libs.callbackScheduler.run(`sche_vis_proxy_${this.adapterKey}`);
43
+ }, {debounce: 10});
28
44
  }
29
45
 
30
46
  /**
31
47
  * Build flat list of all options for navigation
32
48
  */
33
- private _buildFlatStructure(): void {
49
+ private buildFlatStructure(): void {
34
50
  this.flatOptions = [];
35
51
  this.groups = [];
36
52
 
@@ -68,9 +84,9 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
68
84
  item.position = position;
69
85
 
70
86
  if (item instanceof GroupModel) {
71
- this._handleGroupView(item, viewer as GroupView, position);
87
+ this.handleGroupView(item, viewer as GroupView, position);
72
88
  } else if (item instanceof OptionModel) {
73
- this._handleOptionView(item, viewer as OptionView, position);
89
+ this.handleOptionView(item, viewer as OptionView, position);
74
90
  }
75
91
 
76
92
  item.isInit = true;
@@ -84,7 +100,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
84
100
  * @param {GroupView} groupView - The view instance that renders the group in the UI.
85
101
  * @param {number} position - The position (index) of the group within a list.
86
102
  */
87
- private _handleGroupView(groupModel: GroupModel, groupView: GroupView, position: number): void {
103
+ private handleGroupView(groupModel: GroupModel, groupView: GroupView, position: number): void {
88
104
  super.onViewHolder(groupModel, groupView, position);
89
105
  groupModel.view = groupView;
90
106
 
@@ -118,7 +134,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
118
134
  optionViewer = new OptionView(itemsContainer);
119
135
  }
120
136
 
121
- this._handleOptionView(optionModel, optionViewer, idx);
137
+ this.handleOptionView(optionModel, optionViewer, idx);
122
138
  optionModel.isInit = true;
123
139
  });
124
140
 
@@ -134,7 +150,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
134
150
  * @param {OptionView} optionViewer - The view instance that renders the option in the UI.
135
151
  * @param {number} position - The index of this option within its group's item list.
136
152
  */
137
- private _handleOptionView(optionModel: OptionModel, optionViewer: OptionView, position: number): void {
153
+ private handleOptionView(optionModel: OptionModel, optionViewer: OptionView, position: number): void {
138
154
  optionViewer.isMultiple = this.isMultiple;
139
155
  optionViewer.hasImage = optionModel.hasImage;
140
156
 
@@ -178,7 +194,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
178
194
  } else if (optionModel.selected !== true) {
179
195
  this.changingProp("select");
180
196
  setTimeout(() => {
181
- if (this._selectedItemSingle) this._selectedItemSingle.selected = false;
197
+ if (this.selectedItemSingle) this.selectedItemSingle.selected = false;
182
198
  optionModel.selected = true;
183
199
  }, 5);
184
200
  }
@@ -196,18 +212,18 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
196
212
  });
197
213
 
198
214
  optionModel.onInternalSelected((_evtToken: IEventCallback, _el: OptionModel, selected: boolean) => {
199
- if (selected) this._selectedItemSingle = optionModel;
215
+ if (selected) this.selectedItemSingle = optionModel;
200
216
  this.changeProp("selected_internal");
201
217
  });
202
218
 
203
219
  optionModel.onVisibilityChanged((_evtToken: IEventCallback, model: OptionModel, _visible: boolean) => {
204
220
  model.group?.updateVisibility();
205
- this._notifyVisibilityChanged();
221
+ this.notifyVisibilityChanged();
206
222
  });
207
223
  }
208
224
 
209
225
  if (optionModel.selected) {
210
- this._selectedItemSingle = optionModel;
226
+ this.selectedItemSingle = optionModel;
211
227
  optionModel.selectedNonTrigger = true;
212
228
  }
213
229
  }
@@ -220,7 +236,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
220
236
  override setItems(items: MixedItem[]): void {
221
237
  this.changingProp("items", items);
222
238
  this.items = items;
223
- this._buildFlatStructure();
239
+ this.buildFlatStructure();
224
240
  this.changeProp("items", items);
225
241
  }
226
242
 
@@ -241,7 +257,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
241
257
  */
242
258
  override updateData(items: MixedItem[]): void {
243
259
  this.items = items;
244
- this._buildFlatStructure();
260
+ this.buildFlatStructure();
245
261
  }
246
262
 
247
263
  /**
@@ -249,7 +265,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
249
265
  *
250
266
  * @returns {OptionModel[]} - An array of selected option items from the flat list.
251
267
  */
252
- getSelectedItems(): OptionModel[] {
268
+ public getSelectedItems(): OptionModel[] {
253
269
  return this.flatOptions.filter((item) => item.selected);
254
270
  }
255
271
 
@@ -258,7 +274,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
258
274
  *
259
275
  * @returns {OptionModel|undefined} - The first selected option or undefined if none are selected.
260
276
  */
261
- getSelectedItem(): OptionModel | undefined {
277
+ public getSelectedItem(): OptionModel | undefined {
262
278
  return this.flatOptions.find((item) => item.selected);
263
279
  }
264
280
 
@@ -267,7 +283,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
267
283
  *
268
284
  * @param {boolean} isChecked - If true, select all; if false, deselect all.
269
285
  */
270
- checkAll(isChecked: boolean): void {
286
+ public checkAll(isChecked: boolean): void {
271
287
  if (!this.isMultiple) return;
272
288
  this.flatOptions.forEach((item) => {
273
289
  item.selected = isChecked;
@@ -280,32 +296,22 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
280
296
  * @param {(stats: {visibleCount:number,totalCount:number,hasVisible:boolean,isEmpty:boolean}) => void} callback
281
297
  * - Function to invoke when visibility stats change.
282
298
  */
283
- onVisibilityChanged(callback: (stats: VisibilityStats) => void): void {
284
- this._visibilityChangedCallbacks.push(callback);
299
+ public onVisibilityChanged(callback: (stats: VisibilityStats) => void): void {
300
+ this.visibilityChangedCallbacks.push(callback);
285
301
  }
286
302
 
287
303
  /**
288
304
  * Notifies all registered visibility-change callbacks with up-to-date statistics.
289
305
  * Computes visible and total counts, then emits aggregated state.
290
306
  */
291
- private _notifyVisibilityChanged(): void {
292
- const visibleCount = this.flatOptions.filter((item) => item.visible).length;
293
- const totalCount = this.flatOptions.length;
294
-
295
- this._visibilityChangedCallbacks.forEach((callback) => {
296
- callback({
297
- visibleCount,
298
- totalCount,
299
- hasVisible: visibleCount > 0,
300
- isEmpty: totalCount === 0,
301
- });
302
- });
307
+ private notifyVisibilityChanged(): void {
308
+ Libs.callbackScheduler.run(`sche_vis_${this.adapterKey}`);
303
309
  }
304
310
 
305
311
  /**
306
312
  * Computes and returns current visibility statistics for options.
307
313
  */
308
- getVisibilityStats(): VisibilityStats {
314
+ public getVisibilityStats(): VisibilityStats {
309
315
  const visibleCount = this.flatOptions.filter((item) => item.visible).length;
310
316
  const totalCount = this.flatOptions.length;
311
317
 
@@ -320,7 +326,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
320
326
  /**
321
327
  * Resets the highlight to the first visible option (index 0).
322
328
  */
323
- resetHighlight(): void {
329
+ public resetHighlight(): void {
324
330
  this.setHighlight(0);
325
331
  }
326
332
 
@@ -330,12 +336,12 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
330
336
  * @param {number} direction - Increment (+1) or decrement (-1) of the current visible index.
331
337
  * @param {boolean} [isScrollToView=true] - Whether to scroll the highlighted item into view.
332
338
  */
333
- navigate(direction: number, isScrollToView: boolean = true): void {
339
+ public navigate(direction: number, isScrollToView: boolean = true): void {
334
340
  const visibleOptions = this.flatOptions.filter((opt) => opt.visible);
335
341
  if (visibleOptions.length === 0) return;
336
342
 
337
343
  let currentVisibleIndex = visibleOptions.findIndex(
338
- (opt) => opt === this.flatOptions[this._currentHighlightIndex]
344
+ (opt) => opt === this.flatOptions[this.currentHighlightIndex]
339
345
  );
340
346
  if (currentVisibleIndex === -1) currentVisibleIndex = -1;
341
347
 
@@ -353,9 +359,9 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
353
359
  * Triggers a click on the currently highlighted and visible option to select it.
354
360
  * No-op if nothing is highlighted or the highlighted item is not visible.
355
361
  */
356
- selectHighlighted(): void {
357
- if (this._currentHighlightIndex > -1 && this.flatOptions[this._currentHighlightIndex]) {
358
- const item = this.flatOptions[this._currentHighlightIndex];
362
+ public selectHighlighted(): void {
363
+ if (this.currentHighlightIndex > -1 && this.flatOptions[this.currentHighlightIndex]) {
364
+ const item = this.flatOptions[this.currentHighlightIndex];
359
365
  if (item.visible) {
360
366
  const viewEl = item.view?.getView?.();
361
367
  if (viewEl) viewEl.click();
@@ -370,7 +376,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
370
376
  * @param {number|OptionModel} target - Flat index or the specific OptionModel to highlight.
371
377
  * @param {boolean} [isScrollToView=true] - Whether to scroll the highlighted item into view.
372
378
  */
373
- setHighlight(target: number | OptionModel, isScrollToView: boolean = true): void {
379
+ public setHighlight(target: number | OptionModel, isScrollToView: boolean = true): void {
374
380
  let index = 0;
375
381
 
376
382
  if (typeof target === "number") {
@@ -382,8 +388,8 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
382
388
  index = 0;
383
389
  }
384
390
 
385
- if (this._currentHighlightIndex > -1 && this.flatOptions[this._currentHighlightIndex]) {
386
- this.flatOptions[this._currentHighlightIndex].highlighted = false;
391
+ if (this.currentHighlightIndex > -1 && this.flatOptions[this.currentHighlightIndex]) {
392
+ this.flatOptions[this.currentHighlightIndex].highlighted = false;
387
393
  }
388
394
 
389
395
  for (let i = index; i < this.flatOptions.length; i++) {
@@ -391,7 +397,7 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
391
397
  if (!item?.visible) continue;
392
398
 
393
399
  item.highlighted = true;
394
- this._currentHighlightIndex = i;
400
+ this.currentHighlightIndex = i;
395
401
 
396
402
  if (isScrollToView) {
397
403
  const el = item.view?.getView?.();
@@ -411,11 +417,11 @@ export class MixedAdapter extends Adapter<MixedItem, GroupView | OptionView> {
411
417
  * Hook invoked whenever the highlight changes.
412
418
  * Override to handle UI side effects (e.g., ARIA announcement, focus sync).
413
419
  */
414
- onHighlightChange(index: number, id?: string): void { }
420
+ public onHighlightChange(index: number, id?: string): void { }
415
421
 
416
422
  /**
417
423
  * Hook invoked when a group's collapsed state changes.
418
424
  * Override to handle side effects like analytics or layout adjustments.
419
425
  */
420
- onCollapsedChange(model: GroupModel, collapsed: boolean): void { }
426
+ public onCollapsedChange(model: GroupModel, collapsed: boolean): void { }
421
427
  }
@@ -11,24 +11,26 @@ import { Libs } from "../utils/libs";
11
11
  * @class
12
12
  */
13
13
  export class AccessoryBox {
14
- nodeMounted: MountViewResult<any> | null = null;
14
+ private nodeMounted: MountViewResult<any> | null = null;
15
15
 
16
- node: HTMLDivElement | null = null;
16
+ private node: HTMLDivElement | null = null;
17
17
 
18
- options: SelectiveOptions | null = null;
18
+ private options: SelectiveOptions | null = null;
19
19
 
20
- selectUIMask: HTMLDivElement | null = null;
20
+ private selectUIMask: HTMLDivElement | null = null;
21
21
 
22
- parentMask: HTMLDivElement | null = null;
22
+ private parentMask: HTMLDivElement | null = null;
23
23
 
24
- modelManager: ModelManager<MixedItem, MixedAdapter> | null = null;
24
+ private modelManager: ModelManager<MixedItem, MixedAdapter> | null = null;
25
+
26
+ private modelDatas: OptionModel[] = [];
25
27
 
26
28
  /**
27
29
  * Initializes the accessory box with optional configuration and immediately calls init() if provided.
28
30
  *
29
31
  * @param {object|null} options - Configuration options for the accessory box (e.g., layout and behavior).
30
32
  */
31
- constructor(options: SelectiveOptions | null = null) {
33
+ public constructor(options: SelectiveOptions | null = null) {
32
34
  if (options) this.init(options);
33
35
  }
34
36
 
@@ -38,7 +40,7 @@ export class AccessoryBox {
38
40
  *
39
41
  * @param {SelectiveOptions} options - Configuration object for the accessory box.
40
42
  */
41
- init(options: SelectiveOptions): void {
43
+ private init(options: SelectiveOptions): void {
42
44
  this.nodeMounted = Libs.mountNode({
43
45
  AccessoryBox: {
44
46
  tag: {
@@ -60,7 +62,7 @@ export class AccessoryBox {
60
62
  *
61
63
  * @param {HTMLDivElement} selectUIMask - The overlay/mask element of the main Select UI.
62
64
  */
63
- setRoot(selectUIMask: HTMLDivElement): void {
65
+ public setRoot(selectUIMask: HTMLDivElement): void {
64
66
  this.selectUIMask = selectUIMask;
65
67
  this.parentMask = selectUIMask.parentElement as HTMLDivElement | null;
66
68
 
@@ -71,8 +73,14 @@ export class AccessoryBox {
71
73
  * Inserts the accessory box before or after the Select UI mask depending on the configured accessoryStyle.
72
74
  * Keeps the accessory box aligned relative to the parent mask.
73
75
  */
74
- refreshLocation(): void {
75
- if (!this.parentMask || !this.node || !this.selectUIMask || !this.options) return;
76
+ public refreshLocation(): void {
77
+ if (
78
+ !this.parentMask ||
79
+ !this.node ||
80
+ !this.selectUIMask ||
81
+ !this.options
82
+ )
83
+ return;
76
84
 
77
85
  const ref =
78
86
  this.options.accessoryStyle === "top"
@@ -87,7 +95,9 @@ export class AccessoryBox {
87
95
  *
88
96
  * @param {ModelManager} modelManager - The model manager controlling option state.
89
97
  */
90
- setModelManager(modelManager: ModelManager<MixedItem, MixedAdapter> | null): void {
98
+ public setModelManager(
99
+ modelManager: ModelManager<MixedItem, MixedAdapter> | null,
100
+ ): void {
91
101
  this.modelManager = modelManager;
92
102
  }
93
103
 
@@ -97,14 +107,11 @@ export class AccessoryBox {
97
107
  *
98
108
  * @param {OptionModel[]} modelDatas - List of option models to render as accessory items.
99
109
  */
100
- setModelData(modelDatas: OptionModel[]): void {
110
+ public setModelData(modelDatas: OptionModel[]): void {
101
111
  if (!this.node || !this.options) return;
102
-
103
112
  this.node.replaceChildren();
104
113
 
105
114
  if (modelDatas.length > 0 && this.options.multiple) {
106
- this.node.classList.remove("hide");
107
-
108
115
  modelDatas.forEach((modelData) => {
109
116
  Libs.mountNode(
110
117
  {
@@ -120,7 +127,9 @@ export class AccessoryBox {
120
127
  title: `${this.options!.textAccessoryDeselect}${modelData.textContent}`,
121
128
  onclick: (evt: MouseEvent) => {
122
129
  evt.preventDefault();
123
- this.modelManager?.triggerChanging?.("select");
130
+ this.modelManager?.triggerChanging?.(
131
+ "select",
132
+ );
124
133
  setTimeout(() => {
125
134
  modelData.selected = false;
126
135
  }, 10);
@@ -137,13 +146,32 @@ export class AccessoryBox {
137
146
  },
138
147
  },
139
148
  },
140
- this.node
149
+ this.node,
141
150
  );
142
151
  });
143
- } else {
144
- this.node.classList.add("hide");
152
+ }
153
+ else {
154
+ modelDatas = [];
145
155
  }
146
156
 
157
+ this.modelDatas = modelDatas;
158
+ this.refreshDisplay();
147
159
  iEvents.trigger(window, "resize");
148
160
  }
149
- }
161
+
162
+ private refreshDisplay(): void {
163
+ if (this.options?.accessoryVisible && this.modelDatas.length > 0 && this.options.multiple) {
164
+ this.show();
165
+ } else {
166
+ this.hide();
167
+ }
168
+ }
169
+
170
+ private show(): void {
171
+ this.node.classList.remove("hide");
172
+ }
173
+
174
+ private hide(): void {
175
+ this.node.classList.add("hide");
176
+ }
177
+ }
@@ -8,14 +8,14 @@ export class Directive {
8
8
  node: HTMLElement;
9
9
 
10
10
  constructor() {
11
- this.node = this._init();
11
+ this.node = this.init();
12
12
  }
13
13
 
14
14
  /**
15
15
  * Represents a directive button element used to toggle dropdown state.
16
16
  * Initializes a clickable node with appropriate ARIA attributes for accessibility.
17
17
  */
18
- private _init(): HTMLElement {
18
+ private init(): HTMLElement {
19
19
  // Libs.nodeCreator returns Element, but this node is always an HTMLElement in practice.
20
20
  return Libs.nodeCreator({
21
21
  node: "div",
@@ -30,7 +30,7 @@ export class Directive {
30
30
  *
31
31
  * @param {boolean} value - If true, adds the "drop-down" class; otherwise removes it.
32
32
  */
33
- setDropdown(value: boolean): void {
33
+ public setDropdown(value: boolean): void {
34
34
  this.node.classList.toggle("drop-down", !!value);
35
35
  }
36
36
  }
@@ -6,15 +6,15 @@ import { Libs } from "../utils/libs";
6
6
  * @class
7
7
  */
8
8
  export class EmptyState {
9
- node: HTMLDivElement | null = null;
9
+ public node: HTMLDivElement | null = null;
10
10
 
11
- options: SelectiveOptions | null = null;
11
+ public options: SelectiveOptions | null = null;
12
12
 
13
13
  /**
14
14
  * Represents an empty state component that displays a message when no data or search results are available.
15
15
  * Provides methods to show/hide the state and check its visibility.
16
16
  */
17
- constructor(options: SelectiveOptions | null = null) {
17
+ public constructor(options: SelectiveOptions | null = null) {
18
18
  if (options) this.init(options);
19
19
  }
20
20
 
@@ -23,7 +23,7 @@ export class EmptyState {
23
23
  *
24
24
  * @param {object} options - Configuration object containing text for "no data" and "not found" states.
25
25
  */
26
- init(options: SelectiveOptions): void {
26
+ private init(options: SelectiveOptions): void {
27
27
  this.options = options;
28
28
 
29
29
  this.node = Libs.nodeCreator({
@@ -40,7 +40,7 @@ export class EmptyState {
40
40
  * @param {"notfound" | "nodata"} [type="nodata"] - Determines which message to show:
41
41
  * "notfound" for search results not found, "nodata" for no available data.
42
42
  */
43
- show(type: EmptyStateType = "nodata"): void {
43
+ public show(type: EmptyStateType = "nodata"): void {
44
44
  if (!this.node || !this.options) return;
45
45
 
46
46
  const text = type === "notfound" ? this.options.textNotFound : this.options.textNoData;
@@ -52,7 +52,7 @@ export class EmptyState {
52
52
  /**
53
53
  * Hides the empty state element by adding the "hide" class.
54
54
  */
55
- hide(): void {
55
+ public hide(): void {
56
56
  if (!this.node) return;
57
57
  this.node.classList.add("hide");
58
58
  }
@@ -62,7 +62,7 @@ export class EmptyState {
62
62
  *
63
63
  * @returns {boolean} - True if visible, false otherwise.
64
64
  */
65
- get isVisible(): boolean {
65
+ public get isVisible(): boolean {
66
66
  return !!this.node && !this.node.classList.contains("hide");
67
67
  }
68
68
  }
@@ -5,15 +5,15 @@ import { Libs } from "../utils/libs";
5
5
  * @class
6
6
  */
7
7
  export class LoadingState {
8
- node: HTMLDivElement | null = null;
8
+ public node: HTMLDivElement | null = null;
9
9
 
10
- options: SelectiveOptions | null = null;
10
+ public options: SelectiveOptions | null = null;
11
11
 
12
12
  /**
13
13
  * Represents a loading state component that displays a loading message during data fetch or processing.
14
14
  * Provides methods to show/hide the state and check its visibility.
15
15
  */
16
- constructor(options: SelectiveOptions | null = null) {
16
+ public constructor(options: SelectiveOptions | null = null) {
17
17
  if (options) this.init(options);
18
18
  }
19
19
 
@@ -22,7 +22,7 @@ export class LoadingState {
22
22
  *
23
23
  * @param {object} options - Configuration object containing text for the loading message.
24
24
  */
25
- init(options: SelectiveOptions): void {
25
+ private init(options: SelectiveOptions): void {
26
26
  this.options = options;
27
27
 
28
28
  this.node = Libs.nodeCreator({
@@ -39,7 +39,7 @@ export class LoadingState {
39
39
  *
40
40
  * @param {boolean} hasItems - If true, applies a "small" style for compact display.
41
41
  */
42
- show(hasItems: boolean): void {
42
+ public show(hasItems: boolean): void {
43
43
  if (!this.node || !this.options) return;
44
44
 
45
45
  this.node.textContent = this.options.textLoading;
@@ -50,7 +50,7 @@ export class LoadingState {
50
50
  /**
51
51
  * Hides the loading state element by adding the "hide" class.
52
52
  */
53
- hide(): void {
53
+ public hide(): void {
54
54
  if (!this.node) return;
55
55
  this.node.classList.add("hide");
56
56
  }
@@ -60,7 +60,7 @@ export class LoadingState {
60
60
  *
61
61
  * @returns {boolean} - True if visible, false otherwise.
62
62
  */
63
- get isVisible(): boolean {
63
+ public get isVisible(): boolean {
64
64
  return !!this.node && !this.node.classList.contains("hide");
65
65
  }
66
66
  }