selective-ui 1.2.2 → 1.2.3
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.
- package/dist/selective-ui.esm.js +74 -73
- package/dist/selective-ui.esm.js.map +1 -1
- package/dist/selective-ui.esm.min.js +2 -2
- package/dist/selective-ui.esm.min.js.br +0 -0
- package/dist/selective-ui.min.js +2 -2
- package/dist/selective-ui.min.js.br +0 -0
- package/dist/selective-ui.umd.js +75 -74
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/ts/adapter/mixed-adapter.ts +11 -15
- package/src/ts/components/accessorybox.ts +3 -5
- package/src/ts/components/popup.ts +1 -1
- package/src/ts/components/selectbox.ts +0 -7
- package/src/ts/core/base/adapter.ts +11 -11
- package/src/ts/core/base/virtual-recyclerview.ts +5 -2
- package/src/ts/core/model-manager.ts +14 -7
- package/src/ts/core/search-controller.ts +0 -2
- package/src/ts/services/effector.ts +2 -2
- package/src/ts/services/select-observer.ts +1 -8
- package/src/ts/utils/callback-scheduler.ts +38 -18
package/dist/selective-ui.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Selective UI v1.2.
|
|
1
|
+
/*! Selective UI v1.2.3 | MIT License */
|
|
2
2
|
/**
|
|
3
3
|
* @class
|
|
4
4
|
*/
|
|
@@ -143,11 +143,14 @@ class CallbackScheduler {
|
|
|
143
143
|
*/
|
|
144
144
|
run(key, ...params) {
|
|
145
145
|
const executes = this.executeStored.get(key);
|
|
146
|
-
if (!executes)
|
|
147
|
-
return;
|
|
148
|
-
|
|
146
|
+
if (!executes || executes.length === 0) {
|
|
147
|
+
return Promise.resolve();
|
|
148
|
+
}
|
|
149
|
+
if (!this.timerRunner.has(key)) {
|
|
149
150
|
this.timerRunner.set(key, new Map());
|
|
151
|
+
}
|
|
150
152
|
const runner = this.timerRunner.get(key);
|
|
153
|
+
const tasks = [];
|
|
151
154
|
for (let i = 0; i < executes.length; i++) {
|
|
152
155
|
const entry = executes[i];
|
|
153
156
|
if (!entry)
|
|
@@ -155,20 +158,31 @@ class CallbackScheduler {
|
|
|
155
158
|
const prev = runner.get(i);
|
|
156
159
|
if (prev)
|
|
157
160
|
clearTimeout(prev);
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
161
|
+
const task = new Promise((resolve) => {
|
|
162
|
+
const timer = setTimeout(async () => {
|
|
163
|
+
try {
|
|
164
|
+
const resp = entry.callback(params.length > 0 ? params : null);
|
|
165
|
+
if (resp instanceof Promise) {
|
|
166
|
+
await resp;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch { }
|
|
170
|
+
finally {
|
|
171
|
+
if (entry.once) {
|
|
172
|
+
executes[i] = undefined;
|
|
173
|
+
const current = runner.get(i);
|
|
174
|
+
if (current)
|
|
175
|
+
clearTimeout(current);
|
|
176
|
+
runner.delete(i);
|
|
177
|
+
}
|
|
178
|
+
resolve();
|
|
179
|
+
}
|
|
180
|
+
}, entry.timeout);
|
|
181
|
+
runner.set(i, timer);
|
|
182
|
+
});
|
|
183
|
+
tasks.push(task);
|
|
171
184
|
}
|
|
185
|
+
return Promise.all(tasks).then(() => void 0);
|
|
172
186
|
}
|
|
173
187
|
/**
|
|
174
188
|
* Clears callbacks and timers.
|
|
@@ -1383,7 +1397,7 @@ class Popup {
|
|
|
1383
1397
|
const stats = this.optionAdapter?.getVisibilityStats();
|
|
1384
1398
|
this.updateEmptyState(stats ?? undefined);
|
|
1385
1399
|
this.triggerResize();
|
|
1386
|
-
},
|
|
1400
|
+
}, this.options.animationtime);
|
|
1387
1401
|
}
|
|
1388
1402
|
/**
|
|
1389
1403
|
* Subscribes to adapter visibility and item changes to keep the empty state in sync.
|
|
@@ -2099,7 +2113,7 @@ class EffectorImpl {
|
|
|
2099
2113
|
if (isPositionChanged) {
|
|
2100
2114
|
this.element.style.transition = `top ${duration}ms ease-out, height ${duration}ms ease-out, max-height ${duration}ms ease-out;`;
|
|
2101
2115
|
}
|
|
2102
|
-
|
|
2116
|
+
requestAnimationFrame(() => {
|
|
2103
2117
|
const styles = {
|
|
2104
2118
|
width: `${width}px`,
|
|
2105
2119
|
left: `${left}px`,
|
|
@@ -2133,7 +2147,7 @@ class EffectorImpl {
|
|
|
2133
2147
|
delete this.element.style.transition;
|
|
2134
2148
|
onComplete?.();
|
|
2135
2149
|
}
|
|
2136
|
-
}
|
|
2150
|
+
});
|
|
2137
2151
|
return this;
|
|
2138
2152
|
}
|
|
2139
2153
|
/**
|
|
@@ -2561,6 +2575,7 @@ class ModelManager {
|
|
|
2561
2575
|
this.privRecyclerViewHandle = null;
|
|
2562
2576
|
this.lastFingerprint = null;
|
|
2563
2577
|
this.options = null;
|
|
2578
|
+
this.oldPosition = 0;
|
|
2564
2579
|
this.options = options;
|
|
2565
2580
|
}
|
|
2566
2581
|
/**
|
|
@@ -2660,12 +2675,12 @@ class ModelManager {
|
|
|
2660
2675
|
*
|
|
2661
2676
|
* @param {Array<HTMLOptGroupElement|HTMLOptionElement>} modelData - New source elements to rebuild models from.
|
|
2662
2677
|
*/
|
|
2663
|
-
replace(modelData) {
|
|
2678
|
+
async replace(modelData) {
|
|
2664
2679
|
this.lastFingerprint = null;
|
|
2665
2680
|
this.createModelResources(modelData);
|
|
2666
2681
|
if (this.privAdapterHandle) {
|
|
2667
2682
|
// Adapter expects TModel[], but this manager's list is GroupModel|OptionModel.
|
|
2668
|
-
this.privAdapterHandle.syncFromSource(this.privModelList);
|
|
2683
|
+
await this.privAdapterHandle.syncFromSource(this.privModelList);
|
|
2669
2684
|
}
|
|
2670
2685
|
this.refresh(false);
|
|
2671
2686
|
}
|
|
@@ -2769,6 +2784,10 @@ class ModelManager {
|
|
|
2769
2784
|
}
|
|
2770
2785
|
});
|
|
2771
2786
|
let isUpdate = true;
|
|
2787
|
+
if (this.oldPosition == 0) {
|
|
2788
|
+
isUpdate = false;
|
|
2789
|
+
}
|
|
2790
|
+
this.oldPosition = position;
|
|
2772
2791
|
oldGroupMap.forEach((removedGroup) => {
|
|
2773
2792
|
isUpdate = false;
|
|
2774
2793
|
removedGroup.remove();
|
|
@@ -2781,7 +2800,7 @@ class ModelManager {
|
|
|
2781
2800
|
if (this.privAdapterHandle) {
|
|
2782
2801
|
this.privAdapterHandle.updateData(this.privModelList);
|
|
2783
2802
|
}
|
|
2784
|
-
this.onUpdated();
|
|
2803
|
+
// this.onUpdated();
|
|
2785
2804
|
this.refresh(isUpdate);
|
|
2786
2805
|
}
|
|
2787
2806
|
/**
|
|
@@ -2826,14 +2845,14 @@ class ModelManager {
|
|
|
2826
2845
|
* enabling observers to react before a change is applied.
|
|
2827
2846
|
*/
|
|
2828
2847
|
triggerChanging(event_name) {
|
|
2829
|
-
this.privAdapterHandle?.changingProp(event_name);
|
|
2848
|
+
return this.privAdapterHandle?.changingProp(event_name);
|
|
2830
2849
|
}
|
|
2831
2850
|
/**
|
|
2832
2851
|
* Triggers the adapter's post-change pipeline for a named event,
|
|
2833
2852
|
* notifying observers after a change has been applied.
|
|
2834
2853
|
*/
|
|
2835
2854
|
triggerChanged(event_name) {
|
|
2836
|
-
this.privAdapterHandle?.changeProp(event_name);
|
|
2855
|
+
return this.privAdapterHandle?.changeProp(event_name);
|
|
2837
2856
|
}
|
|
2838
2857
|
}
|
|
2839
2858
|
|
|
@@ -3005,12 +3024,10 @@ class AccessoryBox {
|
|
|
3005
3024
|
role: "button",
|
|
3006
3025
|
ariaLabel: `${this.options.textAccessoryDeselect}${modelData.textContent}`,
|
|
3007
3026
|
title: `${this.options.textAccessoryDeselect}${modelData.textContent}`,
|
|
3008
|
-
onclick: (evt) => {
|
|
3027
|
+
onclick: async (evt) => {
|
|
3009
3028
|
evt.preventDefault();
|
|
3010
|
-
this.modelManager?.triggerChanging?.("select");
|
|
3011
|
-
|
|
3012
|
-
modelData.selected = false;
|
|
3013
|
-
}, 10);
|
|
3029
|
+
await this.modelManager?.triggerChanging?.("select");
|
|
3030
|
+
modelData.selected = false;
|
|
3014
3031
|
},
|
|
3015
3032
|
},
|
|
3016
3033
|
},
|
|
@@ -3459,7 +3476,6 @@ class SearchController {
|
|
|
3459
3476
|
select.appendChild(option);
|
|
3460
3477
|
}
|
|
3461
3478
|
});
|
|
3462
|
-
select.dispatchEvent(new CustomEvent("options:changed"));
|
|
3463
3479
|
}
|
|
3464
3480
|
}
|
|
3465
3481
|
|
|
@@ -3469,7 +3485,7 @@ class SearchController {
|
|
|
3469
3485
|
class SelectObserver {
|
|
3470
3486
|
/**
|
|
3471
3487
|
* Initializes the SelectObserver for a given <select> element.
|
|
3472
|
-
* Captures the initial snapshot, sets up a MutationObserver
|
|
3488
|
+
* Captures the initial snapshot, sets up a MutationObserver.
|
|
3473
3489
|
* Changes are debounced to prevent excessive calls.
|
|
3474
3490
|
*
|
|
3475
3491
|
* @param {HTMLSelectElement} select - The <select> element to observe.
|
|
@@ -3487,13 +3503,6 @@ class SelectObserver {
|
|
|
3487
3503
|
this.handleChange();
|
|
3488
3504
|
}, this._DEBOUNCE_DELAY);
|
|
3489
3505
|
});
|
|
3490
|
-
select.addEventListener("options:changed", () => {
|
|
3491
|
-
if (this.debounceTimer)
|
|
3492
|
-
clearTimeout(this.debounceTimer);
|
|
3493
|
-
this.debounceTimer = setTimeout(() => {
|
|
3494
|
-
this.handleChange();
|
|
3495
|
-
}, this._DEBOUNCE_DELAY);
|
|
3496
|
-
});
|
|
3497
3506
|
}
|
|
3498
3507
|
/**
|
|
3499
3508
|
* Creates a snapshot of the current state of the <select> element's options.
|
|
@@ -3679,7 +3688,7 @@ class Adapter {
|
|
|
3679
3688
|
* @param {Function} callback - Function to execute before the property changes.
|
|
3680
3689
|
*/
|
|
3681
3690
|
onPropChanging(propName, callback) {
|
|
3682
|
-
Libs.callbackScheduler.on(`${propName}ing_${this.adapterKey}`, callback, { debounce:
|
|
3691
|
+
Libs.callbackScheduler.on(`${propName}ing_${this.adapterKey}`, callback, { debounce: 0 });
|
|
3683
3692
|
}
|
|
3684
3693
|
/**
|
|
3685
3694
|
* Registers a post-change callback for a property change pipeline.
|
|
@@ -3689,7 +3698,7 @@ class Adapter {
|
|
|
3689
3698
|
* @param {Function} callback - Function to execute after the property changes.
|
|
3690
3699
|
*/
|
|
3691
3700
|
onPropChanged(propName, callback) {
|
|
3692
|
-
Libs.callbackScheduler.on(`${propName}_${this.adapterKey}`, callback);
|
|
3701
|
+
Libs.callbackScheduler.on(`${propName}_${this.adapterKey}`, callback, { debounce: 0 });
|
|
3693
3702
|
}
|
|
3694
3703
|
/**
|
|
3695
3704
|
* Triggers the post-change pipeline for a given property, passing optional parameters
|
|
@@ -3699,7 +3708,7 @@ class Adapter {
|
|
|
3699
3708
|
* @param {...any} params - Parameters forwarded to the callbacks.
|
|
3700
3709
|
*/
|
|
3701
3710
|
changeProp(propName, ...params) {
|
|
3702
|
-
Libs.callbackScheduler.run(`${propName}_${this.adapterKey}`, ...params);
|
|
3711
|
+
return Libs.callbackScheduler.run(`${propName}_${this.adapterKey}`, ...params);
|
|
3703
3712
|
}
|
|
3704
3713
|
/**
|
|
3705
3714
|
* Triggers the pre-change pipeline for a given property, passing optional parameters
|
|
@@ -3709,7 +3718,7 @@ class Adapter {
|
|
|
3709
3718
|
* @param {...any} params - Parameters forwarded to the callbacks.
|
|
3710
3719
|
*/
|
|
3711
3720
|
changingProp(propName, ...params) {
|
|
3712
|
-
Libs.callbackScheduler.run(`${propName}ing_${this.adapterKey}`, ...params);
|
|
3721
|
+
return Libs.callbackScheduler.run(`${propName}ing_${this.adapterKey}`, ...params);
|
|
3713
3722
|
}
|
|
3714
3723
|
/**
|
|
3715
3724
|
* Creates and returns a viewer instance for the given item within the specified parent container.
|
|
@@ -3736,10 +3745,10 @@ class Adapter {
|
|
|
3736
3745
|
*
|
|
3737
3746
|
* @param {TItem[]} items - The new list of items to set.
|
|
3738
3747
|
*/
|
|
3739
|
-
setItems(items) {
|
|
3740
|
-
this.changingProp("items", items);
|
|
3748
|
+
async setItems(items) {
|
|
3749
|
+
await this.changingProp("items", items);
|
|
3741
3750
|
this.items = items;
|
|
3742
|
-
this.changeProp("items", items);
|
|
3751
|
+
await this.changeProp("items", items);
|
|
3743
3752
|
}
|
|
3744
3753
|
/**
|
|
3745
3754
|
* Synchronizes adapter items from an external source by delegating to setItems().
|
|
@@ -3747,8 +3756,8 @@ class Adapter {
|
|
|
3747
3756
|
*
|
|
3748
3757
|
* @param {TItem[]} items - The source list of items to synchronize.
|
|
3749
3758
|
*/
|
|
3750
|
-
syncFromSource(items) {
|
|
3751
|
-
this.setItems(items);
|
|
3759
|
+
async syncFromSource(items) {
|
|
3760
|
+
await this.setItems(items);
|
|
3752
3761
|
}
|
|
3753
3762
|
/**
|
|
3754
3763
|
* Iterates through all items and ensures each has a viewer. For new items, calls viewHolder()
|
|
@@ -4343,24 +4352,20 @@ class MixedAdapter extends Adapter {
|
|
|
4343
4352
|
}
|
|
4344
4353
|
optionViewer.view.tags.LabelContent.innerHTML = optionModel.text;
|
|
4345
4354
|
if (!optionModel.isInit) {
|
|
4346
|
-
optionViewer.view.tags.OptionView.addEventListener("click", (ev) => {
|
|
4355
|
+
optionViewer.view.tags.OptionView.addEventListener("click", async (ev) => {
|
|
4347
4356
|
ev.stopPropagation();
|
|
4348
4357
|
ev.preventDefault();
|
|
4349
4358
|
if (this.isSkipEvent)
|
|
4350
4359
|
return;
|
|
4351
4360
|
if (this.isMultiple) {
|
|
4352
|
-
this.changingProp("select");
|
|
4353
|
-
|
|
4354
|
-
optionModel.selected = !optionModel.selected;
|
|
4355
|
-
}, 5);
|
|
4361
|
+
await this.changingProp("select");
|
|
4362
|
+
optionModel.selected = !optionModel.selected;
|
|
4356
4363
|
}
|
|
4357
4364
|
else if (optionModel.selected !== true) {
|
|
4358
|
-
this.changingProp("select");
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
optionModel.selected = true;
|
|
4363
|
-
}, 5);
|
|
4365
|
+
await this.changingProp("select");
|
|
4366
|
+
if (this.selectedItemSingle)
|
|
4367
|
+
this.selectedItemSingle.selected = false;
|
|
4368
|
+
optionModel.selected = true;
|
|
4364
4369
|
}
|
|
4365
4370
|
});
|
|
4366
4371
|
optionViewer.view.tags.OptionView.title = optionModel.textContent;
|
|
@@ -4392,19 +4397,19 @@ class MixedAdapter extends Adapter {
|
|
|
4392
4397
|
*
|
|
4393
4398
|
* @param {Array<GroupModel|OptionModel>} items - The new collection of items to be displayed.
|
|
4394
4399
|
*/
|
|
4395
|
-
setItems(items) {
|
|
4396
|
-
this.changingProp("items", items);
|
|
4400
|
+
async setItems(items) {
|
|
4401
|
+
await this.changingProp("items", items);
|
|
4397
4402
|
this.items = items;
|
|
4398
4403
|
this.buildFlatStructure();
|
|
4399
|
-
this.changeProp("items", items);
|
|
4404
|
+
await this.changeProp("items", items);
|
|
4400
4405
|
}
|
|
4401
4406
|
/**
|
|
4402
4407
|
* Synchronizes the component's items from an external source by delegating to setItems().
|
|
4403
4408
|
*
|
|
4404
4409
|
* @param {Array<GroupModel|OptionModel>} items - The new collection of items to sync.
|
|
4405
4410
|
*/
|
|
4406
|
-
syncFromSource(items) {
|
|
4407
|
-
this.setItems(items);
|
|
4411
|
+
async syncFromSource(items) {
|
|
4412
|
+
await this.setItems(items);
|
|
4408
4413
|
}
|
|
4409
4414
|
/**
|
|
4410
4415
|
* Updates the component's data items and rebuilds the internal flat structure
|
|
@@ -4895,7 +4900,7 @@ class VirtualRecyclerView extends RecyclerView {
|
|
|
4895
4900
|
containerTopInScroll() {
|
|
4896
4901
|
const a = this.viewElement.getBoundingClientRect();
|
|
4897
4902
|
const b = this.scrollEl.getBoundingClientRect();
|
|
4898
|
-
return a.top - b.top + this.scrollEl.scrollTop;
|
|
4903
|
+
return Math.max(0, a.top - b.top + this.scrollEl.scrollTop);
|
|
4899
4904
|
}
|
|
4900
4905
|
/**
|
|
4901
4906
|
* Returns sticky header height with 16ms cache to avoid DOM thrashing.
|
|
@@ -5144,7 +5149,9 @@ class VirtualRecyclerView extends RecyclerView {
|
|
|
5144
5149
|
const targetScroll = this.containerTopInScroll() + anchorTopNew - anchorDelta;
|
|
5145
5150
|
const maxScroll = Math.max(0, this.scrollEl.scrollHeight - this.scrollEl.clientHeight);
|
|
5146
5151
|
const clamped = Math.min(Math.max(0, targetScroll), maxScroll);
|
|
5147
|
-
|
|
5152
|
+
const heightChanged = Math.abs(anchorTopNew - anchorTop) > 1;
|
|
5153
|
+
const scrollDiff = Math.abs(this.scrollEl.scrollTop - clamped);
|
|
5154
|
+
if (heightChanged && scrollDiff > 0.5 && scrollDiff < 100) {
|
|
5148
5155
|
this.scrollEl.scrollTop = clamped;
|
|
5149
5156
|
}
|
|
5150
5157
|
}
|
|
@@ -5418,12 +5425,6 @@ class SelectBox {
|
|
|
5418
5425
|
this.isVisible = Libs.string2Boolean(dataset.visible ?? "1");
|
|
5419
5426
|
}
|
|
5420
5427
|
};
|
|
5421
|
-
// Custom event (manual refresh)
|
|
5422
|
-
select.addEventListener("options:changed", () => {
|
|
5423
|
-
optionModelManager.update(Libs.parseSelectToArray(select));
|
|
5424
|
-
this.getAction()?.refreshMask();
|
|
5425
|
-
container.popup?.triggerResize?.();
|
|
5426
|
-
});
|
|
5427
5428
|
// AJAX setup (if provided)
|
|
5428
5429
|
if (options.ajax) {
|
|
5429
5430
|
searchController.setAjax(options.ajax);
|
|
@@ -6283,7 +6284,7 @@ const SECLASS = new Selective();
|
|
|
6283
6284
|
*
|
|
6284
6285
|
* Declared as `const` literal type to enable strict typing and easy tree-shaking.
|
|
6285
6286
|
*/
|
|
6286
|
-
const version = "1.2.
|
|
6287
|
+
const version = "1.2.3";
|
|
6287
6288
|
/**
|
|
6288
6289
|
* Library name identifier.
|
|
6289
6290
|
*
|