selective-ui 1.2.1 → 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 +435 -405
  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 +436 -406
  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 +40 -40
  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 +25 -22
  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 +50 -50
  30. package/src/ts/core/model-manager.ts +53 -53
  31. package/src/ts/core/search-controller.ts +69 -69
  32. package/src/ts/models/group-model.ts +21 -21
  33. package/src/ts/models/option-model.ts +30 -30
  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 +25 -25
  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
@@ -1,4 +1,4 @@
1
- /*! Selective UI v1.2.1 | MIT License */
1
+ /*! Selective UI v1.2.2 | MIT License */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
4
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -11,7 +11,7 @@
11
11
  class iStorage {
12
12
  constructor() {
13
13
  this.defaultConfig = {
14
- showPanel: true,
14
+ accessoryVisible: true,
15
15
  virtualScroll: true,
16
16
  accessoryStyle: "top",
17
17
  multiple: false,
@@ -417,10 +417,20 @@
417
417
  for (const optionKey in myOptions) {
418
418
  const propValue = element[optionKey];
419
419
  if (propValue) {
420
- myOptions[optionKey] = propValue;
420
+ if (typeof myOptions[optionKey] === "boolean") {
421
+ myOptions[optionKey] = this.string2Boolean(propValue);
422
+ }
423
+ else {
424
+ myOptions[optionKey] = propValue;
425
+ }
421
426
  }
422
427
  else if (typeof element?.dataset?.[optionKey] !== "undefined") {
423
- myOptions[optionKey] = element.dataset[optionKey];
428
+ if (typeof myOptions[optionKey] === "boolean") {
429
+ myOptions[optionKey] = this.string2Boolean(element.dataset[optionKey]);
430
+ }
431
+ else {
432
+ myOptions[optionKey] = element.dataset[optionKey];
433
+ }
424
434
  }
425
435
  }
426
436
  return myOptions;
@@ -821,7 +831,7 @@
821
831
  */
822
832
  constructor(options) {
823
833
  this.node = null;
824
- this._options = null;
834
+ this.options = null;
825
835
  if (options)
826
836
  this.init(options);
827
837
  }
@@ -836,7 +846,7 @@
836
846
  classList: "selective-ui-placeholder",
837
847
  innerHTML: options.placeholder,
838
848
  });
839
- this._options = options;
849
+ this.options = options;
840
850
  }
841
851
  /**
842
852
  * Retrieves the current placeholder text from the configuration.
@@ -844,7 +854,7 @@
844
854
  * @returns {string} - The current placeholder text.
845
855
  */
846
856
  get() {
847
- return this._options?.placeholder ?? "";
857
+ return this.options?.placeholder ?? "";
848
858
  }
849
859
  /**
850
860
  * Updates the placeholder text and optionally saves it to the configuration.
@@ -854,12 +864,12 @@
854
864
  * @param {boolean} [isSave=true] - Whether to persist the new value in the configuration.
855
865
  */
856
866
  set(value, isSave = true) {
857
- if (!this.node || !this._options)
867
+ if (!this.node || !this.options)
858
868
  return;
859
869
  if (isSave)
860
- this._options.placeholder = value;
870
+ this.options.placeholder = value;
861
871
  const translated = Libs.tagTranslate(value);
862
- this.node.innerHTML = this._options.allowHtml ? translated : Libs.stripHtml(translated);
872
+ this.node.innerHTML = this.options.allowHtml ? translated : Libs.stripHtml(translated);
863
873
  }
864
874
  }
865
875
 
@@ -868,13 +878,13 @@
868
878
  */
869
879
  class Directive {
870
880
  constructor() {
871
- this.node = this._init();
881
+ this.node = this.init();
872
882
  }
873
883
  /**
874
884
  * Represents a directive button element used to toggle dropdown state.
875
885
  * Initializes a clickable node with appropriate ARIA attributes for accessibility.
876
886
  */
877
- _init() {
887
+ init() {
878
888
  // Libs.nodeCreator returns Element, but this node is always an HTMLElement in practice.
879
889
  return Libs.nodeCreator({
880
890
  node: "div",
@@ -906,8 +916,8 @@
906
916
  this.nodeMounted = null;
907
917
  this.node = null;
908
918
  this.options = null;
909
- this._ActionOnSelectAll = [];
910
- this._ActionOnDeSelectAll = [];
919
+ this.actionOnSelectAll = [];
920
+ this.actionOnDeSelectAll = [];
911
921
  if (options)
912
922
  this.init(options);
913
923
  }
@@ -928,7 +938,7 @@
928
938
  classList: "selective-ui-option-handle-item",
929
939
  textContent: options.textSelectAll,
930
940
  onclick: () => {
931
- iEvents.callFunctions(this._ActionOnSelectAll);
941
+ iEvents.callFunctions(this.actionOnSelectAll);
932
942
  },
933
943
  },
934
944
  },
@@ -938,7 +948,7 @@
938
948
  classList: "selective-ui-option-handle-item",
939
949
  textContent: options.textDeselectAll,
940
950
  onclick: () => {
941
- iEvents.callFunctions(this._ActionOnDeSelectAll);
951
+ iEvents.callFunctions(this.actionOnDeSelectAll);
942
952
  },
943
953
  },
944
954
  },
@@ -993,7 +1003,7 @@
993
1003
  */
994
1004
  OnSelectAll(action = null) {
995
1005
  if (typeof action === "function")
996
- this._ActionOnSelectAll.push(action);
1006
+ this.actionOnSelectAll.push(action);
997
1007
  }
998
1008
  /**
999
1009
  * Registers a callback to be executed when "Deselect All" is clicked.
@@ -1002,7 +1012,7 @@
1002
1012
  */
1003
1013
  OnDeSelectAll(action = null) {
1004
1014
  if (typeof action === "function")
1005
- this._ActionOnDeSelectAll.push(action);
1015
+ this.actionOnDeSelectAll.push(action);
1006
1016
  }
1007
1017
  }
1008
1018
 
@@ -1135,10 +1145,10 @@
1135
1145
  constructor() {
1136
1146
  this.isInit = false;
1137
1147
  this.element = null;
1138
- this._resizeObserver = null;
1139
- this._mutationObserver = null;
1148
+ this.resizeObserver = null;
1149
+ this.mutationObserver = null;
1140
1150
  this.isInit = true;
1141
- this._boundUpdateChanged = this._updateChanged.bind(this);
1151
+ this.boundUpdateChanged = this.updateChanged.bind(this);
1142
1152
  }
1143
1153
  /**
1144
1154
  * Callback invoked when the observed element's metrics change.
@@ -1152,7 +1162,7 @@
1152
1162
  * Computes the current metrics of the bound element (bounding rect + computed styles)
1153
1163
  * and forwards them to `onChanged(metrics)`.
1154
1164
  */
1155
- _updateChanged() {
1165
+ updateChanged() {
1156
1166
  const el = this.element;
1157
1167
  if (!el || typeof el.getBoundingClientRect !== "function") {
1158
1168
  const defaultMetrics = {
@@ -1201,7 +1211,7 @@
1201
1211
  * Manually triggers a metrics computation and notification via `onChanged`.
1202
1212
  */
1203
1213
  trigger() {
1204
- this._updateChanged();
1214
+ this.updateChanged();
1205
1215
  }
1206
1216
  /**
1207
1217
  * Starts observing the provided element for resize and style/class mutations,
@@ -1215,18 +1225,18 @@
1215
1225
  throw new Error("Invalid element");
1216
1226
  }
1217
1227
  this.element = element;
1218
- this._resizeObserver = new ResizeObserver(this._boundUpdateChanged);
1219
- this._resizeObserver.observe(element);
1220
- this._mutationObserver = new MutationObserver(this._boundUpdateChanged);
1221
- this._mutationObserver.observe(element, {
1228
+ this.resizeObserver = new ResizeObserver(this.boundUpdateChanged);
1229
+ this.resizeObserver.observe(element);
1230
+ this.mutationObserver = new MutationObserver(this.boundUpdateChanged);
1231
+ this.mutationObserver.observe(element, {
1222
1232
  attributes: true,
1223
1233
  attributeFilter: ["style", "class"],
1224
1234
  });
1225
- window.addEventListener("scroll", this._boundUpdateChanged, true);
1226
- window.addEventListener("resize", this._boundUpdateChanged);
1235
+ window.addEventListener("scroll", this.boundUpdateChanged, true);
1236
+ window.addEventListener("resize", this.boundUpdateChanged);
1227
1237
  if (window.visualViewport) {
1228
- window.visualViewport.addEventListener("resize", this._boundUpdateChanged);
1229
- window.visualViewport.addEventListener("scroll", this._boundUpdateChanged);
1238
+ window.visualViewport.addEventListener("resize", this.boundUpdateChanged);
1239
+ window.visualViewport.addEventListener("scroll", this.boundUpdateChanged);
1230
1240
  }
1231
1241
  }
1232
1242
  /**
@@ -1234,17 +1244,17 @@
1234
1244
  * and releases internal observer resources.
1235
1245
  */
1236
1246
  disconnect() {
1237
- this._resizeObserver?.disconnect();
1238
- this._mutationObserver?.disconnect();
1247
+ this.resizeObserver?.disconnect();
1248
+ this.mutationObserver?.disconnect();
1239
1249
  this.onChanged = (_metrics) => { };
1240
- window.removeEventListener("scroll", this._boundUpdateChanged, true);
1241
- window.removeEventListener("resize", this._boundUpdateChanged);
1250
+ window.removeEventListener("scroll", this.boundUpdateChanged, true);
1251
+ window.removeEventListener("resize", this.boundUpdateChanged);
1242
1252
  if (window.visualViewport) {
1243
- window.visualViewport.removeEventListener("resize", this._boundUpdateChanged);
1244
- window.visualViewport.removeEventListener("scroll", this._boundUpdateChanged);
1253
+ window.visualViewport.removeEventListener("resize", this.boundUpdateChanged);
1254
+ window.visualViewport.removeEventListener("scroll", this.boundUpdateChanged);
1245
1255
  }
1246
- this._resizeObserver = null;
1247
- this._mutationObserver = null;
1256
+ this.resizeObserver = null;
1257
+ this.mutationObserver = null;
1248
1258
  this.element = null;
1249
1259
  }
1250
1260
  }
@@ -1266,22 +1276,22 @@
1266
1276
  this.isCreated = false;
1267
1277
  this.optionAdapter = null;
1268
1278
  this.node = null;
1269
- this._effSvc = null;
1270
- this._resizeObser = null;
1271
- this._parent = null;
1279
+ this.effSvc = null;
1280
+ this.resizeObser = null;
1281
+ this.parent = null;
1272
1282
  this.optionHandle = null;
1273
1283
  this.emptyState = null;
1274
1284
  this.loadingState = null;
1275
1285
  this.recyclerView = null;
1276
- this._optionsContainer = null;
1277
- this._scrollListener = null;
1278
- this._hideLoadHandle = null;
1286
+ this.optionsContainer = null;
1287
+ this.scrollListener = null;
1288
+ this.hideLoadHandle = null;
1279
1289
  this.virtualScrollConfig = {
1280
1290
  estimateItemHeight: 36,
1281
1291
  overscan: 8,
1282
1292
  dynamicHeights: true
1283
1293
  };
1284
- this._modelManager = modelManager;
1294
+ this.modelManager = modelManager;
1285
1295
  if (select && options) {
1286
1296
  this.init(select, options);
1287
1297
  }
@@ -1294,7 +1304,7 @@
1294
1304
  * @param {object} options - Configuration for panel, IDs, multiple mode, and texts.
1295
1305
  */
1296
1306
  init(select, options) {
1297
- if (!this._modelManager)
1307
+ if (!this.modelManager)
1298
1308
  throw new Error("Popup requires a ModelManager instance.");
1299
1309
  this.optionHandle = new OptionHandle(options);
1300
1310
  this.emptyState = new EmptyState(options);
@@ -1322,8 +1332,8 @@
1322
1332
  },
1323
1333
  }, null);
1324
1334
  this.node = nodeMounted.view;
1325
- this._optionsContainer = nodeMounted.tags.OptionsContainer;
1326
- this._parent = Libs.getBinderMap(select);
1335
+ this.optionsContainer = nodeMounted.tags.OptionsContainer;
1336
+ this.parent = Libs.getBinderMap(select);
1327
1337
  this.options = options;
1328
1338
  const recyclerViewOpt = options.virtualScroll
1329
1339
  ? {
@@ -1334,8 +1344,8 @@
1334
1344
  }
1335
1345
  : {};
1336
1346
  // Load ModelManager resources into container
1337
- this._modelManager.load(this._optionsContainer, { isMultiple: options.multiple }, recyclerViewOpt);
1338
- const MMResources = this._modelManager.getResources();
1347
+ this.modelManager.load(this.optionsContainer, { isMultiple: options.multiple }, recyclerViewOpt);
1348
+ const MMResources = this.modelManager.getResources();
1339
1349
  this.optionAdapter = MMResources.adapter;
1340
1350
  this.recyclerView = MMResources.recyclerView;
1341
1351
  this.optionHandle.OnSelectAll(() => {
@@ -1344,21 +1354,21 @@
1344
1354
  this.optionHandle.OnDeSelectAll(() => {
1345
1355
  MMResources.adapter.checkAll(false);
1346
1356
  });
1347
- this._setupEmptyStateLogic();
1357
+ this.setupEmptyStateLogic();
1348
1358
  }
1349
1359
  /**
1350
1360
  * Shows the loading state and temporarily skips model events.
1351
1361
  * Adjusts size based on current visibility stats and triggers a resize.
1352
1362
  */
1353
1363
  async showLoading() {
1354
- if (!this.options || !this.loadingState || !this.optionHandle || !this.optionAdapter || !this._modelManager)
1364
+ if (!this.options || !this.loadingState || !this.optionHandle || !this.optionAdapter || !this.modelManager)
1355
1365
  return;
1356
- if (this._hideLoadHandle)
1357
- clearTimeout(this._hideLoadHandle);
1358
- this._modelManager.skipEvent(true);
1366
+ if (this.hideLoadHandle)
1367
+ clearTimeout(this.hideLoadHandle);
1368
+ this.modelManager.skipEvent(true);
1359
1369
  if (Libs.string2Boolean(this.options.loadingfield) === false)
1360
1370
  return;
1361
- // this._updateEmptyState({isEmpty: false, hasVisible: true});
1371
+ // this.updateEmptyState({isEmpty: false, hasVisible: true});
1362
1372
  this.emptyState.hide();
1363
1373
  this.loadingState.show(this.optionAdapter.getVisibilityStats().hasVisible);
1364
1374
  // this.optionHandle.hide();
@@ -1369,15 +1379,15 @@
1369
1379
  * updates empty state based on adapter visibility stats, and triggers a resize.
1370
1380
  */
1371
1381
  async hideLoading() {
1372
- if (!this.options || !this.loadingState || !this.optionAdapter || !this._modelManager)
1382
+ if (!this.options || !this.loadingState || !this.optionAdapter || !this.modelManager)
1373
1383
  return;
1374
- if (this._hideLoadHandle)
1375
- clearTimeout(this._hideLoadHandle);
1376
- this._hideLoadHandle = setTimeout(() => {
1377
- this._modelManager?.skipEvent(false);
1384
+ if (this.hideLoadHandle)
1385
+ clearTimeout(this.hideLoadHandle);
1386
+ this.hideLoadHandle = setTimeout(() => {
1387
+ this.modelManager?.skipEvent(false);
1378
1388
  this.loadingState?.hide();
1379
1389
  const stats = this.optionAdapter?.getVisibilityStats();
1380
- this._updateEmptyState(stats ?? undefined);
1390
+ this.updateEmptyState(stats ?? undefined);
1381
1391
  this.triggerResize();
1382
1392
  }, 200);
1383
1393
  }
@@ -1385,15 +1395,15 @@
1385
1395
  * Subscribes to adapter visibility and item changes to keep the empty state in sync.
1386
1396
  * Triggers resize when items change to reflect layout updates.
1387
1397
  */
1388
- _setupEmptyStateLogic() {
1398
+ setupEmptyStateLogic() {
1389
1399
  if (!this.optionAdapter)
1390
1400
  return;
1391
1401
  this.optionAdapter.onVisibilityChanged((stats) => {
1392
- this._updateEmptyState(stats);
1402
+ this.updateEmptyState(stats);
1393
1403
  });
1394
1404
  this.optionAdapter.onPropChanged("items", () => {
1395
1405
  const stats = this.optionAdapter.getVisibilityStats();
1396
- this._updateEmptyState(stats);
1406
+ this.updateEmptyState(stats);
1397
1407
  this.triggerResize();
1398
1408
  });
1399
1409
  }
@@ -1403,23 +1413,23 @@
1403
1413
  *
1404
1414
  * @param {VisibilityStats|undefined} stats - Visibility stats; computed if omitted.
1405
1415
  */
1406
- _updateEmptyState(stats) {
1407
- if (!this.optionAdapter || !this.emptyState || !this.optionHandle || !this._optionsContainer)
1416
+ updateEmptyState(stats) {
1417
+ if (!this.optionAdapter || !this.emptyState || !this.optionHandle || !this.optionsContainer)
1408
1418
  return;
1409
1419
  const s = stats ?? this.optionAdapter.getVisibilityStats();
1410
1420
  if (s.isEmpty) {
1411
1421
  this.emptyState.show("nodata");
1412
- this._optionsContainer.classList.add("hide");
1422
+ this.optionsContainer.classList.add("hide");
1413
1423
  this.optionHandle.hide();
1414
1424
  }
1415
1425
  else if (!s.hasVisible) {
1416
1426
  this.emptyState.show("notfound");
1417
- this._optionsContainer.classList.add("hide");
1427
+ this.optionsContainer.classList.add("hide");
1418
1428
  this.optionHandle.hide();
1419
1429
  }
1420
1430
  else {
1421
1431
  this.emptyState.hide();
1422
- this._optionsContainer.classList.remove("hide");
1432
+ this.optionsContainer.classList.remove("hide");
1423
1433
  this.optionHandle.refresh();
1424
1434
  }
1425
1435
  }
@@ -1439,20 +1449,20 @@
1439
1449
  * Injects an effector service used to perform side effects (e.g., animations or external actions).
1440
1450
  */
1441
1451
  setupEffector(effectorSvc) {
1442
- this._effSvc = effectorSvc;
1452
+ this.effSvc = effectorSvc;
1443
1453
  }
1444
1454
  /**
1445
1455
  * Opens the popup: creates and attaches DOM if needed, initializes observers and effector,
1446
1456
  * computes position and dimensions, and runs expand animation. Invokes callback on completion.
1447
1457
  */
1448
1458
  open(callback = null, isShowEmptyState) {
1449
- if (!this.node || !this.options || !this.optionHandle || !this._parent || !this._effSvc)
1459
+ if (!this.node || !this.options || !this.optionHandle || !this.parent || !this.effSvc)
1450
1460
  return;
1451
1461
  if (!this.isCreated) {
1452
1462
  document.body.appendChild(this.node);
1453
1463
  this.isCreated = true;
1454
- this._resizeObser = new ResizeObserverService();
1455
- this._effSvc.setElement(this.node);
1464
+ this.resizeObser = new ResizeObserverService();
1465
+ this.effSvc.setElement(this.node);
1456
1466
  this.node.addEventListener("mousedown", (e) => {
1457
1467
  e.stopPropagation();
1458
1468
  e.preventDefault();
@@ -1460,11 +1470,11 @@
1460
1470
  }
1461
1471
  this.optionHandle.refresh();
1462
1472
  if (isShowEmptyState) {
1463
- this._updateEmptyState();
1473
+ this.updateEmptyState();
1464
1474
  }
1465
- const location = this._getParentLocation();
1466
- const { position, top, maxHeight, realHeight } = this._calculatePosition(location);
1467
- this._effSvc.expand({
1475
+ const location = this.getParentLocation();
1476
+ const { position, top, maxHeight, realHeight } = this.calculatePosition(location);
1477
+ this.effSvc.expand({
1468
1478
  duration: this.options.animationtime,
1469
1479
  display: "flex",
1470
1480
  width: location.width,
@@ -1474,14 +1484,14 @@
1474
1484
  realHeight,
1475
1485
  position,
1476
1486
  onComplete: () => {
1477
- if (!this._resizeObser || !this._parent)
1487
+ if (!this.resizeObser || !this.parent)
1478
1488
  return;
1479
- this._resizeObser.onChanged = (_metrics) => {
1489
+ this.resizeObser.onChanged = (_metrics) => {
1480
1490
  // Recompute from parent each time to keep behavior identical.
1481
- const loc = this._getParentLocation();
1482
- this._handleResize(loc);
1491
+ const loc = this.getParentLocation();
1492
+ this.handleResize(loc);
1483
1493
  };
1484
- this._resizeObser.connect(this._parent.container.tags.ViewPanel);
1494
+ this.resizeObser.connect(this.parent.container.tags.ViewPanel);
1485
1495
  callback?.();
1486
1496
  const rv = this.recyclerView;
1487
1497
  rv?.resume?.();
@@ -1493,12 +1503,12 @@
1493
1503
  * Safely no-ops if the popup has not been created.
1494
1504
  */
1495
1505
  close(callback = null) {
1496
- if (!this.isCreated || !this.options || !this._resizeObser || !this._effSvc)
1506
+ if (!this.isCreated || !this.options || !this.resizeObser || !this.effSvc)
1497
1507
  return;
1498
1508
  const rv = this.recyclerView;
1499
1509
  rv?.suspend?.();
1500
- this._resizeObser.disconnect();
1501
- this._effSvc.collapse({
1510
+ this.resizeObser.disconnect();
1511
+ this.effSvc.collapse({
1502
1512
  duration: this.options.animationtime,
1503
1513
  onComplete: callback ?? undefined,
1504
1514
  });
@@ -1509,7 +1519,7 @@
1509
1519
  */
1510
1520
  triggerResize() {
1511
1521
  if (this.isCreated)
1512
- this._resizeObser?.trigger();
1522
+ this.resizeObser?.trigger();
1513
1523
  }
1514
1524
  /**
1515
1525
  * Enables infinite scroll by listening to container scroll events and loading more data
@@ -1521,7 +1531,7 @@
1521
1531
  setupInfiniteScroll(searchController, _options) {
1522
1532
  if (!this.node)
1523
1533
  return;
1524
- this._scrollListener = async () => {
1534
+ this.scrollListener = async () => {
1525
1535
  const state = searchController.getPaginationState();
1526
1536
  if (!state.isPaginationEnabled)
1527
1537
  return;
@@ -1539,7 +1549,7 @@
1539
1549
  }
1540
1550
  }
1541
1551
  };
1542
- this.node.addEventListener("scroll", this._scrollListener);
1552
+ this.node.addEventListener("scroll", this.scrollListener);
1543
1553
  }
1544
1554
  /**
1545
1555
  * Completely tear down the popup instance and release all resources.
@@ -1554,24 +1564,24 @@
1554
1564
  * Safe to call multiple times; all operations are guarded via optional chaining.
1555
1565
  */
1556
1566
  detroy() {
1557
- if (this._hideLoadHandle) {
1558
- clearTimeout(this._hideLoadHandle);
1559
- this._hideLoadHandle = null;
1567
+ if (this.hideLoadHandle) {
1568
+ clearTimeout(this.hideLoadHandle);
1569
+ this.hideLoadHandle = null;
1560
1570
  }
1561
- if (this.node && this._scrollListener) {
1562
- this.node.removeEventListener("scroll", this._scrollListener);
1563
- this._scrollListener = null;
1571
+ if (this.node && this.scrollListener) {
1572
+ this.node.removeEventListener("scroll", this.scrollListener);
1573
+ this.scrollListener = null;
1564
1574
  }
1565
1575
  try {
1566
- this._resizeObser?.disconnect();
1576
+ this.resizeObser?.disconnect();
1567
1577
  }
1568
1578
  catch (_) { }
1569
- this._resizeObser = null;
1579
+ this.resizeObser = null;
1570
1580
  try {
1571
- this._effSvc?.setElement?.(null);
1581
+ this.effSvc?.setElement?.(null);
1572
1582
  }
1573
1583
  catch (_) { }
1574
- this._effSvc = null;
1584
+ this.effSvc = null;
1575
1585
  if (this.node) {
1576
1586
  try {
1577
1587
  const clone = this.node.cloneNode(true);
@@ -1583,20 +1593,20 @@
1583
1593
  }
1584
1594
  }
1585
1595
  this.node = null;
1586
- this._optionsContainer = null;
1596
+ this.optionsContainer = null;
1587
1597
  try {
1588
- this._modelManager?.skipEvent?.(false);
1598
+ this.modelManager?.skipEvent?.(false);
1589
1599
  this.recyclerView?.clear?.();
1590
1600
  this.recyclerView = null;
1591
1601
  this.optionAdapter = null;
1592
1602
  this.node.remove();
1593
1603
  }
1594
1604
  catch (_) { }
1595
- this._modelManager = null;
1605
+ this.modelManager = null;
1596
1606
  this.optionHandle = null;
1597
1607
  this.emptyState = null;
1598
1608
  this.loadingState = null;
1599
- this._parent = null;
1609
+ this.parent = null;
1600
1610
  this.options = null;
1601
1611
  this.isCreated = false;
1602
1612
  }
@@ -1604,8 +1614,8 @@
1604
1614
  * Computes the parent panel's location and box metrics, including size, position,
1605
1615
  * padding, and border, accounting for iOS visual viewport offsets.
1606
1616
  */
1607
- _getParentLocation() {
1608
- const viewPanel = this._parent.container.tags.ViewPanel;
1617
+ getParentLocation() {
1618
+ const viewPanel = this.parent.container.tags.ViewPanel;
1609
1619
  const rect = viewPanel.getBoundingClientRect();
1610
1620
  const style = window.getComputedStyle(viewPanel);
1611
1621
  return {
@@ -1631,13 +1641,13 @@
1631
1641
  * Determines popup placement (top/bottom) and height constraints based on available viewport space,
1632
1642
  * content size, and configured min/max heights; returns final position, top, and heights.
1633
1643
  */
1634
- _calculatePosition(location) {
1644
+ calculatePosition(location) {
1635
1645
  const vv = window.visualViewport;
1636
1646
  const is_ios = Libs.IsIOS();
1637
1647
  const viewportHeight = vv?.height ?? window.innerHeight;
1638
1648
  const gap = 3;
1639
1649
  const safeMargin = 15;
1640
- const dimensions = this._effSvc.getHiddenDimensions("flex");
1650
+ const dimensions = this.effSvc.getHiddenDimensions("flex");
1641
1651
  const contentHeight = dimensions.scrollHeight;
1642
1652
  const configMaxHeight = parseFloat(this.options?.panelHeight ?? "220") || 220;
1643
1653
  const configMinHeight = parseFloat(this.options?.panelMinHeight ?? "100") || 100;
@@ -1676,11 +1686,11 @@
1676
1686
  * Handles parent resize events by recalculating placement and dimensions,
1677
1687
  * then animates the popup to the new size and position.
1678
1688
  */
1679
- _handleResize(location) {
1680
- if (!this.options || !this._effSvc)
1689
+ handleResize(location) {
1690
+ if (!this.options || !this.effSvc)
1681
1691
  return;
1682
- const { position, top, maxHeight, realHeight } = this._calculatePosition(location);
1683
- this._effSvc.resize({
1692
+ const { position, top, maxHeight, realHeight } = this.calculatePosition(location);
1693
+ this.effSvc.resize({
1684
1694
  duration: this.options.animationtime,
1685
1695
  width: location.width,
1686
1696
  left: location.left,
@@ -1854,8 +1864,8 @@
1854
1864
  * @param {string|HTMLElement|null} [query] - A CSS selector or the target element to control.
1855
1865
  */
1856
1866
  constructor(query = null) {
1857
- this._timeOut = null;
1858
- this._resizeTimeout = null;
1867
+ this.timeOut = null;
1868
+ this.resizeTimeout = null;
1859
1869
  this._isAnimating = false;
1860
1870
  if (query)
1861
1871
  this.setElement(query);
@@ -1882,13 +1892,13 @@
1882
1892
  * @returns {this} - The effector instance for chaining.
1883
1893
  */
1884
1894
  cancel() {
1885
- if (this._timeOut) {
1886
- clearTimeout(this._timeOut);
1887
- this._timeOut = null;
1895
+ if (this.timeOut) {
1896
+ clearTimeout(this.timeOut);
1897
+ this.timeOut = null;
1888
1898
  }
1889
- if (this._resizeTimeout) {
1890
- clearTimeout(this._resizeTimeout);
1891
- this._resizeTimeout = null;
1899
+ if (this.resizeTimeout) {
1900
+ clearTimeout(this.resizeTimeout);
1901
+ this.resizeTimeout = null;
1892
1902
  }
1893
1903
  this._isAnimating = false;
1894
1904
  return this;
@@ -1963,7 +1973,7 @@
1963
1973
  opacity: "1",
1964
1974
  overflow: isScrollable ? "auto" : "hidden",
1965
1975
  });
1966
- this._timeOut = setTimeout(() => {
1976
+ this.timeOut = setTimeout(() => {
1967
1977
  this.element.style.transition = "none";
1968
1978
  this._isAnimating = false;
1969
1979
  onComplete?.();
@@ -1995,7 +2005,7 @@
1995
2005
  opacity: "0",
1996
2006
  overflow: isScrollable ? "auto" : "hidden",
1997
2007
  });
1998
- this._timeOut = setTimeout(() => {
2008
+ this.timeOut = setTimeout(() => {
1999
2009
  Object.assign(this.element.style, {
2000
2010
  display: "none",
2001
2011
  transition: "none",
@@ -2031,7 +2041,7 @@
2031
2041
  overflow: "hidden",
2032
2042
  });
2033
2043
  });
2034
- this._timeOut = setTimeout(() => {
2044
+ this.timeOut = setTimeout(() => {
2035
2045
  Object.assign(this.element.style, {
2036
2046
  width: "",
2037
2047
  overflow: "",
@@ -2065,7 +2075,7 @@
2065
2075
  overflow: "hidden",
2066
2076
  });
2067
2077
  });
2068
- this._timeOut = setTimeout(() => {
2078
+ this.timeOut = setTimeout(() => {
2069
2079
  Object.assign(this.element.style, {
2070
2080
  width: "",
2071
2081
  overflow: "",
@@ -2109,7 +2119,7 @@
2109
2119
  styles.transition = `height ${duration}ms, top ${duration}ms`;
2110
2120
  }
2111
2121
  else {
2112
- this._resizeTimeout = setTimeout(() => {
2122
+ this.resizeTimeout = setTimeout(() => {
2113
2123
  if (this.element?.style) {
2114
2124
  this.element.style.transition = null;
2115
2125
  }
@@ -2117,7 +2127,7 @@
2117
2127
  }
2118
2128
  Object.assign(this.element.style, styles);
2119
2129
  if (animate && (isPositionChanged || heightDiff > 1)) {
2120
- this._resizeTimeout = setTimeout(() => {
2130
+ this.resizeTimeout = setTimeout(() => {
2121
2131
  this.element.style.transition = null;
2122
2132
  if (isPositionChanged)
2123
2133
  delete this.element.style.transition;
@@ -2212,7 +2222,7 @@
2212
2222
  * Initializes a group model with options and an optional <optgroup> target.
2213
2223
  * Reads the label and collapsed state from the target element's attributes/dataset.
2214
2224
  *
2215
- * @param {DefaultConfig} options - Configuration for the model.
2225
+ * @param {SelectiveOptions} options - Configuration for the model.
2216
2226
  * @param {HTMLOptGroupElement} [targetElement] - The source <optgroup> element.
2217
2227
  */
2218
2228
  constructor(options, targetElement) {
@@ -2220,7 +2230,7 @@
2220
2230
  this.label = "";
2221
2231
  this.items = [];
2222
2232
  this.collapsed = false;
2223
- this._privOnCollapsedChanged = [];
2233
+ this.privOnCollapsedChanged = [];
2224
2234
  if (targetElement) {
2225
2235
  this.label = targetElement.label;
2226
2236
  this.collapsed = Libs.string2Boolean(targetElement.dataset?.collapsed);
@@ -2283,7 +2293,7 @@
2283
2293
  * @param {(evtToken: IEventCallback, model: GroupModel, collapsed: boolean) => void} callback - Listener for collapse changes.
2284
2294
  */
2285
2295
  onCollapsedChanged(callback) {
2286
- this._privOnCollapsedChanged.push(callback);
2296
+ this.privOnCollapsedChanged.push(callback);
2287
2297
  }
2288
2298
  /**
2289
2299
  * Toggles the group's collapsed state, updates the view, and notifies registered listeners.
@@ -2291,7 +2301,7 @@
2291
2301
  toggleCollapse() {
2292
2302
  this.collapsed = !this.collapsed;
2293
2303
  this.view?.setCollapsed(this.collapsed);
2294
- iEvents.callEvent([this, this.collapsed], ...this._privOnCollapsedChanged);
2304
+ iEvents.callEvent([this, this.collapsed], ...this.privOnCollapsedChanged);
2295
2305
  }
2296
2306
  /**
2297
2307
  * Adds an option item to this group and sets its back-reference to the group.
@@ -2337,9 +2347,9 @@
2337
2347
  */
2338
2348
  constructor(options, targetElement = null, view = null) {
2339
2349
  super(options, targetElement, view);
2340
- this._privOnSelected = [];
2341
- this._privOnInternalSelected = [];
2342
- this._privOnVisibilityChanged = [];
2350
+ this.privOnSelected = [];
2351
+ this.privOnInternalSelected = [];
2352
+ this.privOnVisibilityChanged = [];
2343
2353
  this._visible = true;
2344
2354
  this._highlighted = false;
2345
2355
  this.group = null;
@@ -2387,7 +2397,7 @@
2387
2397
  */
2388
2398
  set selected(value) {
2389
2399
  this.selectedNonTrigger = value;
2390
- iEvents.callEvent([this, value], ...this._privOnSelected);
2400
+ iEvents.callEvent([this, value], ...this.privOnSelected);
2391
2401
  }
2392
2402
  /**
2393
2403
  * Gets whether the option is currently visible in the UI.
@@ -2409,7 +2419,7 @@
2409
2419
  const viewEl = this.view?.getView?.();
2410
2420
  if (viewEl)
2411
2421
  viewEl.classList.toggle("hide", !value);
2412
- iEvents.callEvent([this, value], ...this._privOnVisibilityChanged);
2422
+ iEvents.callEvent([this, value], ...this.privOnVisibilityChanged);
2413
2423
  }
2414
2424
  /**
2415
2425
  * Gets the selected state without triggering external listeners (alias of selected).
@@ -2437,7 +2447,7 @@
2437
2447
  }
2438
2448
  if (this.targetElement)
2439
2449
  this.targetElement.selected = value;
2440
- iEvents.callEvent([this, value], ...this._privOnInternalSelected);
2450
+ iEvents.callEvent([this, value], ...this.privOnInternalSelected);
2441
2451
  }
2442
2452
  /**
2443
2453
  * Returns the display text for the option, applying tag translation and optional HTML allowance.
@@ -2495,7 +2505,7 @@
2495
2505
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Selection listener.
2496
2506
  */
2497
2507
  onSelected(callback) {
2498
- this._privOnSelected.push(callback);
2508
+ this.privOnSelected.push(callback);
2499
2509
  }
2500
2510
  /**
2501
2511
  * Registers a listener invoked when internal selection changes (via setter `selectedNonTrigger`).
@@ -2503,7 +2513,7 @@
2503
2513
  * @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Internal selection listener.
2504
2514
  */
2505
2515
  onInternalSelected(callback) {
2506
- this._privOnInternalSelected.push(callback);
2516
+ this.privOnInternalSelected.push(callback);
2507
2517
  }
2508
2518
  /**
2509
2519
  * Registers a listener invoked when visibility changes (via setter `visible`).
@@ -2511,7 +2521,7 @@
2511
2521
  * @param {(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void} callback - Visibility listener.
2512
2522
  */
2513
2523
  onVisibilityChanged(callback) {
2514
- this._privOnVisibilityChanged.push(callback);
2524
+ this.privOnVisibilityChanged.push(callback);
2515
2525
  }
2516
2526
  /**
2517
2527
  * Hook called when the target <option> element changes.
@@ -2552,10 +2562,10 @@
2552
2562
  * @param {object} options - Configuration object passed to GroupModel/OptionModel and view infrastructure.
2553
2563
  */
2554
2564
  constructor(options) {
2555
- this._privModelList = [];
2556
- this._privAdapterHandle = null;
2557
- this._privRecyclerViewHandle = null;
2558
- this._lastFingerprint = null;
2565
+ this.privModelList = [];
2566
+ this.privAdapterHandle = null;
2567
+ this.privRecyclerViewHandle = null;
2568
+ this.lastFingerprint = null;
2559
2569
  this.options = null;
2560
2570
  this.options = options;
2561
2571
  }
@@ -2565,7 +2575,7 @@
2565
2575
  * @param {new TAdapter} adapter - The adapter constructor (class) to instantiate.
2566
2576
  */
2567
2577
  setupAdapter(adapter) {
2568
- this._privAdapter = adapter;
2578
+ this.privAdapter = adapter;
2569
2579
  }
2570
2580
  /**
2571
2581
  * Registers the RecyclerView class responsible for hosting and updating item views.
@@ -2573,7 +2583,7 @@
2573
2583
  * @param {new RecyclerViewContract<TAdapter>} recyclerView - The recycler view constructor.
2574
2584
  */
2575
2585
  setupRecyclerView(recyclerView) {
2576
- this._privRecyclerView = recyclerView;
2586
+ this.privRecyclerView = recyclerView;
2577
2587
  }
2578
2588
  /**
2579
2589
  * Checks whether the provided model data differs from the last recorded fingerprint.
@@ -2584,10 +2594,10 @@
2584
2594
  * @returns {boolean} True if there are real changes; false otherwise.
2585
2595
  */
2586
2596
  hasRealChanges(modelData) {
2587
- const newFingerprint = this._createFingerprint(modelData);
2588
- const hasChanges = newFingerprint !== this._lastFingerprint;
2597
+ const newFingerprint = this.createFingerprint(modelData);
2598
+ const hasChanges = newFingerprint !== this.lastFingerprint;
2589
2599
  if (hasChanges)
2590
- this._lastFingerprint = newFingerprint;
2600
+ this.lastFingerprint = newFingerprint;
2591
2601
  return hasChanges;
2592
2602
  }
2593
2603
  /**
@@ -2599,7 +2609,7 @@
2599
2609
  * @param {Array<HTMLOptionElement|HTMLOptGroupElement>} modelData - The current model data to fingerprint.
2600
2610
  * @returns {string} A deterministic fingerprint representing the structure and selection state.
2601
2611
  */
2602
- _createFingerprint(modelData) {
2612
+ createFingerprint(modelData) {
2603
2613
  return modelData
2604
2614
  .map((item) => {
2605
2615
  if (item.tagName === "OPTGROUP") {
@@ -2627,12 +2637,12 @@
2627
2637
  * @returns {Array<GroupModel|OptionModel>} - The ordered list of group and option models.
2628
2638
  */
2629
2639
  createModelResources(modelData) {
2630
- this._privModelList = [];
2640
+ this.privModelList = [];
2631
2641
  let currentGroup = null;
2632
2642
  modelData.forEach((data) => {
2633
2643
  if (data.tagName === "OPTGROUP") {
2634
2644
  currentGroup = new GroupModel(this.options, data);
2635
- this._privModelList.push(currentGroup);
2645
+ this.privModelList.push(currentGroup);
2636
2646
  }
2637
2647
  else if (data.tagName === "OPTION") {
2638
2648
  const optionEl = data;
@@ -2643,12 +2653,12 @@
2643
2653
  optionModel.group = currentGroup;
2644
2654
  }
2645
2655
  else {
2646
- this._privModelList.push(optionModel);
2656
+ this.privModelList.push(optionModel);
2647
2657
  currentGroup = null;
2648
2658
  }
2649
2659
  }
2650
2660
  });
2651
- return this._privModelList;
2661
+ return this.privModelList;
2652
2662
  }
2653
2663
  /**
2654
2664
  * Replaces the current model list with new data and syncs it into the adapter,
@@ -2657,11 +2667,11 @@
2657
2667
  * @param {Array<HTMLOptGroupElement|HTMLOptionElement>} modelData - New source elements to rebuild models from.
2658
2668
  */
2659
2669
  replace(modelData) {
2660
- this._lastFingerprint = null;
2670
+ this.lastFingerprint = null;
2661
2671
  this.createModelResources(modelData);
2662
- if (this._privAdapterHandle) {
2672
+ if (this.privAdapterHandle) {
2663
2673
  // Adapter expects TModel[], but this manager's list is GroupModel|OptionModel.
2664
- this._privAdapterHandle.syncFromSource(this._privModelList);
2674
+ this.privAdapterHandle.syncFromSource(this.privModelList);
2665
2675
  }
2666
2676
  this.refresh(false);
2667
2677
  }
@@ -2670,7 +2680,7 @@
2670
2680
  * typically used after external updates to model data.
2671
2681
  */
2672
2682
  notify() {
2673
- if (!this._privAdapterHandle)
2683
+ if (!this.privAdapterHandle)
2674
2684
  return;
2675
2685
  this.refresh(false);
2676
2686
  }
@@ -2679,11 +2689,11 @@
2679
2689
  * and applies optional configuration overrides for adapter and recyclerView.
2680
2690
  */
2681
2691
  load(viewElement, adapterOpt = {}, recyclerViewOpt = {}) {
2682
- this._privAdapterHandle = new this._privAdapter(this._privModelList);
2683
- Object.assign(this._privAdapterHandle, adapterOpt);
2684
- this._privRecyclerViewHandle = new this._privRecyclerView(viewElement);
2685
- Object.assign(this._privRecyclerViewHandle, recyclerViewOpt);
2686
- this._privRecyclerViewHandle.setAdapter(this._privAdapterHandle);
2692
+ this.privAdapterHandle = new this.privAdapter(this.privModelList);
2693
+ Object.assign(this.privAdapterHandle, adapterOpt);
2694
+ this.privRecyclerViewHandle = new this.privRecyclerView(viewElement);
2695
+ Object.assign(this.privRecyclerViewHandle, recyclerViewOpt);
2696
+ this.privRecyclerViewHandle.setAdapter(this.privAdapterHandle);
2687
2697
  }
2688
2698
  /**
2689
2699
  * Diffs existing models against new <optgroup>/<option> data to update in place:
@@ -2693,7 +2703,7 @@
2693
2703
  update(modelData) {
2694
2704
  if (!this.hasRealChanges(modelData))
2695
2705
  return;
2696
- const oldModels = this._privModelList;
2706
+ const oldModels = this.privModelList;
2697
2707
  const newModels = [];
2698
2708
  const oldGroupMap = new Map();
2699
2709
  const oldOptionMap = new Map();
@@ -2773,9 +2783,9 @@
2773
2783
  isUpdate = false;
2774
2784
  removedOption.remove();
2775
2785
  });
2776
- this._privModelList = newModels;
2777
- if (this._privAdapterHandle) {
2778
- this._privAdapterHandle.updateData(this._privModelList);
2786
+ this.privModelList = newModels;
2787
+ if (this.privAdapterHandle) {
2788
+ this.privAdapterHandle.updateData(this.privModelList);
2779
2789
  }
2780
2790
  this.onUpdated();
2781
2791
  this.refresh(isUpdate);
@@ -2791,8 +2801,8 @@
2791
2801
  * @param {boolean} value - True to skip events; false to restore normal behavior.
2792
2802
  */
2793
2803
  skipEvent(value) {
2794
- if (this._privAdapterHandle)
2795
- this._privAdapterHandle.isSkipEvent = value;
2804
+ if (this.privAdapterHandle)
2805
+ this.privAdapterHandle.isSkipEvent = value;
2796
2806
  }
2797
2807
  /**
2798
2808
  * Re-renders the recycler view if present and invokes the post-refresh hook.
@@ -2801,9 +2811,9 @@
2801
2811
  * @param isUpdate - Indicates if this refresh is due to an update operation.
2802
2812
  */
2803
2813
  refresh(isUpdate) {
2804
- if (!this._privRecyclerViewHandle)
2814
+ if (!this.privRecyclerViewHandle)
2805
2815
  return;
2806
- this._privRecyclerViewHandle.refresh(isUpdate);
2816
+ this.privRecyclerViewHandle.refresh(isUpdate);
2807
2817
  this.onUpdated();
2808
2818
  }
2809
2819
  /**
@@ -2812,9 +2822,9 @@
2812
2822
  */
2813
2823
  getResources() {
2814
2824
  return {
2815
- modelList: this._privModelList,
2816
- adapter: this._privAdapterHandle,
2817
- recyclerView: this._privRecyclerViewHandle,
2825
+ modelList: this.privModelList,
2826
+ adapter: this.privAdapterHandle,
2827
+ recyclerView: this.privRecyclerViewHandle,
2818
2828
  };
2819
2829
  }
2820
2830
  /**
@@ -2822,14 +2832,14 @@
2822
2832
  * enabling observers to react before a change is applied.
2823
2833
  */
2824
2834
  triggerChanging(event_name) {
2825
- this._privAdapterHandle?.changingProp(event_name);
2835
+ this.privAdapterHandle?.changingProp(event_name);
2826
2836
  }
2827
2837
  /**
2828
2838
  * Triggers the adapter's post-change pipeline for a named event,
2829
2839
  * notifying observers after a change has been applied.
2830
2840
  */
2831
2841
  triggerChanged(event_name) {
2832
- this._privAdapterHandle?.changeProp(event_name);
2842
+ this.privAdapterHandle?.changeProp(event_name);
2833
2843
  }
2834
2844
  }
2835
2845
 
@@ -2920,6 +2930,7 @@
2920
2930
  this.selectUIMask = null;
2921
2931
  this.parentMask = null;
2922
2932
  this.modelManager = null;
2933
+ this.modelDatas = [];
2923
2934
  if (options)
2924
2935
  this.init(options);
2925
2936
  }
@@ -2959,7 +2970,10 @@
2959
2970
  * Keeps the accessory box aligned relative to the parent mask.
2960
2971
  */
2961
2972
  refreshLocation() {
2962
- if (!this.parentMask || !this.node || !this.selectUIMask || !this.options)
2973
+ if (!this.parentMask ||
2974
+ !this.node ||
2975
+ !this.selectUIMask ||
2976
+ !this.options)
2963
2977
  return;
2964
2978
  const ref = this.options.accessoryStyle === "top"
2965
2979
  ? this.selectUIMask
@@ -2985,7 +2999,6 @@
2985
2999
  return;
2986
3000
  this.node.replaceChildren();
2987
3001
  if (modelDatas.length > 0 && this.options.multiple) {
2988
- this.node.classList.remove("hide");
2989
3002
  modelDatas.forEach((modelData) => {
2990
3003
  Libs.mountNode({
2991
3004
  AccessoryItem: {
@@ -3020,10 +3033,26 @@
3020
3033
  });
3021
3034
  }
3022
3035
  else {
3023
- this.node.classList.add("hide");
3036
+ modelDatas = [];
3024
3037
  }
3038
+ this.modelDatas = modelDatas;
3039
+ this.refreshDisplay();
3025
3040
  iEvents.trigger(window, "resize");
3026
3041
  }
3042
+ refreshDisplay() {
3043
+ if (this.options?.accessoryVisible && this.modelDatas.length > 0 && this.options.multiple) {
3044
+ this.show();
3045
+ }
3046
+ else {
3047
+ this.hide();
3048
+ }
3049
+ }
3050
+ show() {
3051
+ this.node.classList.remove("hide");
3052
+ }
3053
+ hide() {
3054
+ this.node.classList.add("hide");
3055
+ }
3027
3056
  }
3028
3057
 
3029
3058
  class SearchController {
@@ -3036,11 +3065,11 @@
3036
3065
  * @param {SelectBox} selectBox - SelectBox handle.
3037
3066
  */
3038
3067
  constructor(selectElement, modelManager, selectBox) {
3039
- this._ajaxConfig = null;
3040
- this._abortController = null;
3041
- this._popup = null;
3042
- this._selectBox = null;
3043
- this._paginationState = {
3068
+ this.ajaxConfig = null;
3069
+ this.abortController = null;
3070
+ this.popup = null;
3071
+ this.selectBox = null;
3072
+ this.paginationState = {
3044
3073
  currentPage: 0,
3045
3074
  totalPages: 1,
3046
3075
  hasMore: false,
@@ -3048,9 +3077,9 @@
3048
3077
  currentKeyword: "",
3049
3078
  isPaginationEnabled: false,
3050
3079
  };
3051
- this._select = selectElement;
3052
- this._modelManager = modelManager;
3053
- this._selectBox = selectBox;
3080
+ this.select = selectElement;
3081
+ this.modelManager = modelManager;
3082
+ this.selectBox = selectBox;
3054
3083
  }
3055
3084
  /**
3056
3085
  * Indicates whether AJAX-based search is configured.
@@ -3058,7 +3087,7 @@
3058
3087
  * @returns {boolean} - True if AJAX config is present; false otherwise.
3059
3088
  */
3060
3089
  isAjax() {
3061
- return !!this._ajaxConfig;
3090
+ return !!this.ajaxConfig;
3062
3091
  }
3063
3092
  /**
3064
3093
  * Load specific options by their values from server
@@ -3066,14 +3095,14 @@
3066
3095
  * @returns {Promise<{success: boolean, items: Array, message?: string}>}
3067
3096
  */
3068
3097
  async loadByValues(values) {
3069
- if (!this._ajaxConfig) {
3098
+ if (!this.ajaxConfig) {
3070
3099
  return { success: false, items: [], message: "Ajax not configured" };
3071
3100
  }
3072
3101
  const valuesArray = Array.isArray(values) ? values : [values];
3073
3102
  if (valuesArray.length === 0)
3074
3103
  return { success: true, items: [] };
3075
3104
  try {
3076
- const cfg = this._ajaxConfig;
3105
+ const cfg = this.ajaxConfig;
3077
3106
  let payload;
3078
3107
  if (typeof cfg.dataByValues === "function") {
3079
3108
  payload = cfg.dataByValues(valuesArray);
@@ -3082,7 +3111,7 @@
3082
3111
  payload = {
3083
3112
  values: valuesArray.join(","),
3084
3113
  load_by_values: "1",
3085
- ...(typeof cfg.data === "function" ? cfg.data.bind(this._selectBox.Selective.find(this._selectBox.container.targetElement))("", 0) : cfg.data ?? {}),
3114
+ ...(typeof cfg.data === "function" ? cfg.data.bind(this.selectBox.Selective.find(this.selectBox.container.targetElement))("", 0) : cfg.data ?? {}),
3086
3115
  };
3087
3116
  }
3088
3117
  let response;
@@ -3102,7 +3131,7 @@
3102
3131
  if (!response.ok)
3103
3132
  throw new Error(`HTTP error! status: ${response.status}`);
3104
3133
  const data = await response.json();
3105
- const result = this._parseResponse(data);
3134
+ const result = this.parseResponse(data);
3106
3135
  return { success: true, items: result.items };
3107
3136
  }
3108
3137
  catch (error) {
@@ -3116,7 +3145,7 @@
3116
3145
  * @returns {{existing: string[], missing: string[]}}
3117
3146
  */
3118
3147
  checkMissingValues(values) {
3119
- const allOptions = Array.from(this._select.options);
3148
+ const allOptions = Array.from(this.select.options);
3120
3149
  const existingValues = allOptions.map((opt) => opt.value);
3121
3150
  const existing = values.filter((v) => existingValues.includes(v));
3122
3151
  const missing = values.filter((v) => !existingValues.includes(v));
@@ -3128,7 +3157,7 @@
3128
3157
  * @param {object} config - AJAX configuration object (e.g., endpoint, headers, query params).
3129
3158
  */
3130
3159
  setAjax(config) {
3131
- this._ajaxConfig = config;
3160
+ this.ajaxConfig = config;
3132
3161
  }
3133
3162
  /**
3134
3163
  * Attaches a Popup instance to allow UI updates during search (e.g., loading, resize).
@@ -3136,34 +3165,34 @@
3136
3165
  * @param {Popup} popupInstance - The popup used to display search results and loading state.
3137
3166
  */
3138
3167
  setPopup(popupInstance) {
3139
- this._popup = popupInstance;
3168
+ this.popup = popupInstance;
3140
3169
  }
3141
3170
  /**
3142
3171
  * Returns a shallow copy of the current pagination state used for search/infinite scroll.
3143
3172
  */
3144
3173
  getPaginationState() {
3145
- return { ...this._paginationState };
3174
+ return { ...this.paginationState };
3146
3175
  }
3147
3176
  /**
3148
3177
  * Resets pagination counters while preserving whether pagination is enabled.
3149
3178
  * Clears page, totals, loading flags, and current keyword.
3150
3179
  */
3151
3180
  resetPagination() {
3152
- this._paginationState = {
3181
+ this.paginationState = {
3153
3182
  currentPage: 0,
3154
3183
  totalPages: 1,
3155
3184
  hasMore: false,
3156
3185
  isLoading: false,
3157
3186
  currentKeyword: "",
3158
- isPaginationEnabled: this._paginationState.isPaginationEnabled,
3187
+ isPaginationEnabled: this.paginationState.isPaginationEnabled,
3159
3188
  };
3160
3189
  }
3161
3190
  /**
3162
3191
  * Clears the current keyword and makes all options visible (local reset).
3163
3192
  */
3164
3193
  clear() {
3165
- this._paginationState.currentKeyword = "";
3166
- const { modelList } = this._modelManager.getResources();
3194
+ this.paginationState.currentKeyword = "";
3195
+ const { modelList } = this.modelManager.getResources();
3167
3196
  const flatOptions = [];
3168
3197
  for (const m of modelList) {
3169
3198
  if (m instanceof OptionModel)
@@ -3179,7 +3208,7 @@
3179
3208
  * Performs a search with either AJAX or local filtering depending on configuration.
3180
3209
  */
3181
3210
  async search(keyword, append = false) {
3182
- if (this._ajaxConfig)
3211
+ if (this.ajaxConfig)
3183
3212
  return this._ajaxSearch(keyword, append);
3184
3213
  return this._localSearch(keyword);
3185
3214
  }
@@ -3187,16 +3216,16 @@
3187
3216
  * Loads the next page for AJAX pagination if enabled and not already loading.
3188
3217
  */
3189
3218
  async loadMore() {
3190
- if (!this._ajaxConfig)
3219
+ if (!this.ajaxConfig)
3191
3220
  return { success: false, message: "Ajax not enabled" };
3192
- if (this._paginationState.isLoading)
3221
+ if (this.paginationState.isLoading)
3193
3222
  return { success: false, message: "Already loading" };
3194
- if (!this._paginationState.isPaginationEnabled)
3223
+ if (!this.paginationState.isPaginationEnabled)
3195
3224
  return { success: false, message: "Pagination not enabled" };
3196
- if (!this._paginationState.hasMore)
3225
+ if (!this.paginationState.hasMore)
3197
3226
  return { success: false, message: "No more data" };
3198
- this._paginationState.currentPage++;
3199
- return this._ajaxSearch(this._paginationState.currentKeyword, true);
3227
+ this.paginationState.currentPage++;
3228
+ return this._ajaxSearch(this.paginationState.currentKeyword, true);
3200
3229
  }
3201
3230
  /**
3202
3231
  * Executes a local (in-memory) search by normalizing the keyword (lowercase, non-accent)
@@ -3204,10 +3233,10 @@
3204
3233
  */
3205
3234
  async _localSearch(keyword) {
3206
3235
  if (this.compareSearchTrigger(keyword))
3207
- this._paginationState.currentKeyword = keyword;
3236
+ this.paginationState.currentKeyword = keyword;
3208
3237
  const lower = String(keyword ?? "").toLowerCase();
3209
3238
  const lowerNA = Libs.string2normalize(lower);
3210
- const { modelList } = this._modelManager.getResources();
3239
+ const { modelList } = this.modelManager.getResources();
3211
3240
  const flatOptions = [];
3212
3241
  for (const m of modelList) {
3213
3242
  if (m instanceof OptionModel)
@@ -3233,29 +3262,29 @@
3233
3262
  * to determine if a new search should be triggered.
3234
3263
  */
3235
3264
  compareSearchTrigger(keyword) {
3236
- return keyword !== this._paginationState.currentKeyword;
3265
+ return keyword !== this.paginationState.currentKeyword;
3237
3266
  }
3238
3267
  /**
3239
3268
  * Executes an AJAX-based search with optional appending.
3240
3269
  */
3241
3270
  async _ajaxSearch(keyword, append = false) {
3242
- const cfg = this._ajaxConfig;
3271
+ const cfg = this.ajaxConfig;
3243
3272
  if (this.compareSearchTrigger(keyword)) {
3244
3273
  this.resetPagination();
3245
- this._paginationState.currentKeyword = keyword;
3274
+ this.paginationState.currentKeyword = keyword;
3246
3275
  append = false;
3247
3276
  }
3248
- this._paginationState.isLoading = true;
3249
- this._popup?.showLoading();
3250
- this._abortController?.abort();
3251
- this._abortController = new AbortController();
3252
- const page = this._paginationState.currentPage;
3253
- const selectedValues = Array.from(this._select.selectedOptions)
3277
+ this.paginationState.isLoading = true;
3278
+ this.popup?.showLoading();
3279
+ this.abortController?.abort();
3280
+ this.abortController = new AbortController();
3281
+ const page = this.paginationState.currentPage;
3282
+ const selectedValues = Array.from(this.select.selectedOptions)
3254
3283
  .map((opt) => opt.value)
3255
3284
  .join(",");
3256
3285
  let payload;
3257
3286
  if (typeof cfg.data === "function") {
3258
- payload = cfg.data.bind(this._selectBox.Selective.find(this._selectBox.container.targetElement))(keyword, page);
3287
+ payload = cfg.data.bind(this.selectBox.Selective.find(this.selectBox.container.targetElement))(keyword, page);
3259
3288
  if (payload && typeof payload.selectedValue === "undefined")
3260
3289
  payload.selectedValue = selectedValues;
3261
3290
  }
@@ -3271,27 +3300,27 @@
3271
3300
  method: "POST",
3272
3301
  body: formData,
3273
3302
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
3274
- signal: this._abortController.signal,
3303
+ signal: this.abortController.signal,
3275
3304
  });
3276
3305
  }
3277
3306
  else {
3278
3307
  const params = new URLSearchParams(payload).toString();
3279
- response = await fetch(`${cfg.url}?${params}`, { signal: this._abortController.signal });
3308
+ response = await fetch(`${cfg.url}?${params}`, { signal: this.abortController.signal });
3280
3309
  }
3281
3310
  const data = await response.json();
3282
- const result = this._parseResponse(data);
3311
+ const result = this.parseResponse(data);
3283
3312
  if (result.hasPagination) {
3284
- this._paginationState.isPaginationEnabled = true;
3285
- this._paginationState.currentPage = result.page;
3286
- this._paginationState.totalPages = result.totalPages;
3287
- this._paginationState.hasMore = result.hasMore;
3313
+ this.paginationState.isPaginationEnabled = true;
3314
+ this.paginationState.currentPage = result.page;
3315
+ this.paginationState.totalPages = result.totalPages;
3316
+ this.paginationState.hasMore = result.hasMore;
3288
3317
  }
3289
3318
  else {
3290
- this._paginationState.isPaginationEnabled = false;
3319
+ this.paginationState.isPaginationEnabled = false;
3291
3320
  }
3292
3321
  this.applyAjaxResult(result.items, !!cfg.keepSelected, append);
3293
- this._paginationState.isLoading = false;
3294
- this._popup?.hideLoading();
3322
+ this.paginationState.isLoading = false;
3323
+ this.popup?.hideLoading();
3295
3324
  return {
3296
3325
  success: true,
3297
3326
  hasResults: result.items.length > 0,
@@ -3303,8 +3332,8 @@
3303
3332
  };
3304
3333
  }
3305
3334
  catch (error) {
3306
- this._paginationState.isLoading = false;
3307
- this._popup?.hideLoading();
3335
+ this.paginationState.isLoading = false;
3336
+ this.popup?.hideLoading();
3308
3337
  if (error?.name === "AbortError")
3309
3338
  return { success: false, message: "Request aborted" };
3310
3339
  console.error("Ajax search error:", error);
@@ -3314,7 +3343,7 @@
3314
3343
  /**
3315
3344
  * Parses various server response shapes into a normalized structure for options and groups.
3316
3345
  */
3317
- _parseResponse(data) {
3346
+ parseResponse(data) {
3318
3347
  let items = [];
3319
3348
  let hasPagination = false;
3320
3349
  let page = 0;
@@ -3381,7 +3410,7 @@
3381
3410
  * Applies normalized AJAX results to the underlying <select> element.
3382
3411
  */
3383
3412
  applyAjaxResult(items, keepSelected, append = false) {
3384
- const select = this._select;
3413
+ const select = this.select;
3385
3414
  let oldSelected = [];
3386
3415
  if (keepSelected)
3387
3416
  oldSelected = Array.from(select.selectedOptions).map((o) => o.value);
@@ -3452,23 +3481,23 @@
3452
3481
  * @param {HTMLSelectElement} select - The <select> element to observe.
3453
3482
  */
3454
3483
  constructor(select) {
3455
- this._debounceTimer = null;
3456
- this._lastSnapshot = null;
3484
+ this.debounceTimer = null;
3485
+ this.lastSnapshot = null;
3457
3486
  this._DEBOUNCE_DELAY = 50;
3458
- this._select = select;
3459
- this._lastSnapshot = this._createSnapshot();
3460
- this._observer = new MutationObserver(() => {
3461
- if (this._debounceTimer)
3462
- clearTimeout(this._debounceTimer);
3463
- this._debounceTimer = setTimeout(() => {
3464
- this._handleChange();
3487
+ this.select = select;
3488
+ this.lastSnapshot = this.createSnapshot();
3489
+ this.observer = new MutationObserver(() => {
3490
+ if (this.debounceTimer)
3491
+ clearTimeout(this.debounceTimer);
3492
+ this.debounceTimer = setTimeout(() => {
3493
+ this.handleChange();
3465
3494
  }, this._DEBOUNCE_DELAY);
3466
3495
  });
3467
3496
  select.addEventListener("options:changed", () => {
3468
- if (this._debounceTimer)
3469
- clearTimeout(this._debounceTimer);
3470
- this._debounceTimer = setTimeout(() => {
3471
- this._handleChange();
3497
+ if (this.debounceTimer)
3498
+ clearTimeout(this.debounceTimer);
3499
+ this.debounceTimer = setTimeout(() => {
3500
+ this.handleChange();
3472
3501
  }, this._DEBOUNCE_DELAY);
3473
3502
  });
3474
3503
  }
@@ -3478,8 +3507,8 @@
3478
3507
  *
3479
3508
  * @returns {SelectSnapshot} A snapshot of the options state.
3480
3509
  */
3481
- _createSnapshot() {
3482
- const options = Array.from(this._select.options);
3510
+ createSnapshot() {
3511
+ const options = Array.from(this.select.options);
3483
3512
  return {
3484
3513
  length: options.length,
3485
3514
  values: options.map((opt) => opt.value).join(","),
@@ -3493,28 +3522,28 @@
3493
3522
  *
3494
3523
  * @returns {boolean} True if a real change occurred, otherwise false.
3495
3524
  */
3496
- _hasRealChange() {
3497
- const newSnapshot = this._createSnapshot();
3498
- const changed = JSON.stringify(newSnapshot) !== JSON.stringify(this._lastSnapshot);
3525
+ hasRealChange() {
3526
+ const newSnapshot = this.createSnapshot();
3527
+ const changed = JSON.stringify(newSnapshot) !== JSON.stringify(this.lastSnapshot);
3499
3528
  if (changed)
3500
- this._lastSnapshot = newSnapshot;
3529
+ this.lastSnapshot = newSnapshot;
3501
3530
  return changed;
3502
3531
  }
3503
3532
  /**
3504
3533
  * Handles detected changes after debouncing.
3505
3534
  * If a real change is found, invokes the onChanged() hook with the current <select> element.
3506
3535
  */
3507
- _handleChange() {
3508
- if (!this._hasRealChange())
3536
+ handleChange() {
3537
+ if (!this.hasRealChange())
3509
3538
  return;
3510
- this.onChanged(this._select);
3539
+ this.onChanged(this.select);
3511
3540
  }
3512
3541
  /**
3513
3542
  * Starts observing the <select> element for child list mutations and attribute changes.
3514
3543
  * Uses MutationObserver with a debounce mechanism to batch rapid updates.
3515
3544
  */
3516
3545
  connect() {
3517
- this._observer.observe(this._select, {
3546
+ this.observer.observe(this.select, {
3518
3547
  childList: true,
3519
3548
  subtree: false,
3520
3549
  attributes: true,
@@ -3536,10 +3565,10 @@
3536
3565
  * Ensures no further change handling occurs after disconnecting.
3537
3566
  */
3538
3567
  disconnect() {
3539
- if (this._debounceTimer)
3540
- clearTimeout(this._debounceTimer);
3541
- this._debounceTimer = null;
3542
- this._observer.disconnect();
3568
+ if (this.debounceTimer)
3569
+ clearTimeout(this.debounceTimer);
3570
+ this.debounceTimer = null;
3571
+ this.observer.disconnect();
3543
3572
  }
3544
3573
  }
3545
3574
 
@@ -3554,9 +3583,9 @@
3554
3583
  * @param {HTMLElement} element - The element whose dataset (data-* attributes) will be observed.
3555
3584
  */
3556
3585
  constructor(element) {
3557
- this._debounceTimer = null;
3558
- this._element = element;
3559
- this._observer = new MutationObserver((mutations) => {
3586
+ this.debounceTimer = null;
3587
+ this.element = element;
3588
+ this.observer = new MutationObserver((mutations) => {
3560
3589
  let datasetChanged = false;
3561
3590
  for (const mutation of mutations) {
3562
3591
  if (mutation.type === "attributes" && mutation.attributeName?.startsWith("data-")) {
@@ -3566,14 +3595,14 @@
3566
3595
  }
3567
3596
  if (!datasetChanged)
3568
3597
  return;
3569
- if (this._debounceTimer)
3570
- clearTimeout(this._debounceTimer);
3571
- this._debounceTimer = setTimeout(() => {
3572
- this.onChanged({ ...this._element.dataset });
3598
+ if (this.debounceTimer)
3599
+ clearTimeout(this.debounceTimer);
3600
+ this.debounceTimer = setTimeout(() => {
3601
+ this.onChanged({ ...this.element.dataset });
3573
3602
  }, 50);
3574
3603
  });
3575
3604
  element.addEventListener("dataset:changed", () => {
3576
- this.onChanged({ ...this._element.dataset });
3605
+ this.onChanged({ ...this.element.dataset });
3577
3606
  });
3578
3607
  }
3579
3608
  /**
@@ -3581,7 +3610,7 @@
3581
3610
  * Uses MutationObserver to track updates to data-* attributes.
3582
3611
  */
3583
3612
  connect() {
3584
- this._observer.observe(this._element, {
3613
+ this.observer.observe(this.element, {
3585
3614
  attributes: true,
3586
3615
  attributeOldValue: true,
3587
3616
  });
@@ -3600,10 +3629,10 @@
3600
3629
  * Stops observing the element and clears any pending debounce timers.
3601
3630
  */
3602
3631
  disconnect() {
3603
- if (this._debounceTimer)
3604
- clearTimeout(this._debounceTimer);
3605
- this._debounceTimer = null;
3606
- this._observer.disconnect();
3632
+ if (this.debounceTimer)
3633
+ clearTimeout(this.debounceTimer);
3634
+ this.debounceTimer = null;
3635
+ this.observer.disconnect();
3607
3636
  }
3608
3637
  }
3609
3638
 
@@ -3903,10 +3932,10 @@
3903
3932
  constructor(parent) {
3904
3933
  super(parent);
3905
3934
  this.view = null;
3906
- this._config = null;
3907
- this._configProxy = null;
3908
- this._isRendered = false;
3909
- this._setupConfigProxy();
3935
+ this.config = null;
3936
+ this.configProxy = null;
3937
+ this.isRendered = false;
3938
+ this.setupConfigProxy();
3910
3939
  }
3911
3940
  /**
3912
3941
  * Creates the internal configuration object and wraps it with a Proxy.
@@ -3914,9 +3943,9 @@
3914
3943
  * applies only the necessary DOM changes for the updated property.
3915
3944
  * No DOM mutations occur before the first render.
3916
3945
  */
3917
- _setupConfigProxy() {
3946
+ setupConfigProxy() {
3918
3947
  const self = this;
3919
- this._config = {
3948
+ this.config = {
3920
3949
  isMultiple: false,
3921
3950
  hasImage: false,
3922
3951
  imagePosition: "right",
@@ -3926,7 +3955,7 @@
3926
3955
  labelValign: "center",
3927
3956
  labelHalign: "left",
3928
3957
  };
3929
- this._configProxy = new Proxy(this._config, {
3958
+ this.configProxy = new Proxy(this.config, {
3930
3959
  set(target, prop, value) {
3931
3960
  if (typeof prop !== "string")
3932
3961
  return true;
@@ -3934,8 +3963,8 @@
3934
3963
  const oldValue = target[key];
3935
3964
  if (oldValue !== value) {
3936
3965
  target[key] = value;
3937
- if (self._isRendered) {
3938
- self._applyPartialChange(key, value, oldValue);
3966
+ if (self.isRendered) {
3967
+ self.applyPartialChange(key, value, oldValue);
3939
3968
  }
3940
3969
  }
3941
3970
  return true;
@@ -3948,7 +3977,7 @@
3948
3977
  * @returns {boolean} True if multiple selection is enabled; otherwise false.
3949
3978
  */
3950
3979
  get isMultiple() {
3951
- return this._config.isMultiple;
3980
+ return this.config.isMultiple;
3952
3981
  }
3953
3982
  /**
3954
3983
  * Enables or disables multiple selection mode.
@@ -3957,7 +3986,7 @@
3957
3986
  * @param {boolean} value - True to enable multiple selection; false for single selection.
3958
3987
  */
3959
3988
  set isMultiple(value) {
3960
- this._configProxy.isMultiple = !!value;
3989
+ this.configProxy.isMultiple = !!value;
3961
3990
  }
3962
3991
  /**
3963
3992
  * Indicates whether the option includes an image block alongside the label.
@@ -3965,7 +3994,7 @@
3965
3994
  * @returns {boolean} True if an image is displayed; otherwise false.
3966
3995
  */
3967
3996
  get hasImage() {
3968
- return this._config.hasImage;
3997
+ return this.config.hasImage;
3969
3998
  }
3970
3999
  /**
3971
4000
  * Shows or hides the image block for the option.
@@ -3974,7 +4003,7 @@
3974
4003
  * @param {boolean} value - True to show the image; false to hide it.
3975
4004
  */
3976
4005
  set hasImage(value) {
3977
- this._configProxy.hasImage = !!value;
4006
+ this.configProxy.hasImage = !!value;
3978
4007
  }
3979
4008
  /**
3980
4009
  * Provides reactive access to the entire option configuration via a Proxy.
@@ -3983,7 +4012,7 @@
3983
4012
  * @returns {object} The proxied configuration object.
3984
4013
  */
3985
4014
  get optionConfig() {
3986
- return this._configProxy;
4015
+ return this.configProxy;
3987
4016
  }
3988
4017
  /**
3989
4018
  * Applies a set of configuration changes in batch.
@@ -3991,23 +4020,23 @@
3991
4020
  * When rendered, each changed property triggers a targeted DOM update via the proxy.
3992
4021
  */
3993
4022
  set optionConfig(config) {
3994
- if (!config || !this._configProxy || !this._config)
4023
+ if (!config || !this.configProxy || !this.config)
3995
4024
  return;
3996
4025
  const changes = {};
3997
- if (config.imageWidth !== undefined && config.imageWidth !== this._config.imageWidth)
4026
+ if (config.imageWidth !== undefined && config.imageWidth !== this.config.imageWidth)
3998
4027
  changes.imageWidth = config.imageWidth;
3999
- if (config.imageHeight !== undefined && config.imageHeight !== this._config.imageHeight)
4028
+ if (config.imageHeight !== undefined && config.imageHeight !== this.config.imageHeight)
4000
4029
  changes.imageHeight = config.imageHeight;
4001
- if (config.imageBorderRadius !== undefined && config.imageBorderRadius !== this._config.imageBorderRadius)
4030
+ if (config.imageBorderRadius !== undefined && config.imageBorderRadius !== this.config.imageBorderRadius)
4002
4031
  changes.imageBorderRadius = config.imageBorderRadius;
4003
- if (config.imagePosition !== undefined && config.imagePosition !== this._config.imagePosition)
4032
+ if (config.imagePosition !== undefined && config.imagePosition !== this.config.imagePosition)
4004
4033
  changes.imagePosition = config.imagePosition;
4005
- if (config.labelValign !== undefined && config.labelValign !== this._config.labelValign)
4034
+ if (config.labelValign !== undefined && config.labelValign !== this.config.labelValign)
4006
4035
  changes.labelValign = config.labelValign;
4007
- if (config.labelHalign !== undefined && config.labelHalign !== this._config.labelHalign)
4036
+ if (config.labelHalign !== undefined && config.labelHalign !== this.config.labelHalign)
4008
4037
  changes.labelHalign = config.labelHalign;
4009
4038
  if (Object.keys(changes).length > 0)
4010
- Object.assign(this._configProxy, changes);
4039
+ Object.assign(this.configProxy, changes);
4011
4040
  }
4012
4041
  /**
4013
4042
  * Renders the option view into the parent element.
@@ -4019,30 +4048,30 @@
4019
4048
  const viewClass = ["selective-ui-option-view"];
4020
4049
  const opt_id = Libs.randomString(7);
4021
4050
  const inputID = `option_${opt_id}`;
4022
- if (this._config.isMultiple)
4051
+ if (this.config.isMultiple)
4023
4052
  viewClass.push("multiple");
4024
- if (this._config.hasImage) {
4053
+ if (this.config.hasImage) {
4025
4054
  viewClass.push("has-image");
4026
- viewClass.push(`image-${this._config.imagePosition}`);
4055
+ viewClass.push(`image-${this.config.imagePosition}`);
4027
4056
  }
4028
4057
  const childStructure = {
4029
4058
  OptionInput: {
4030
4059
  tag: {
4031
4060
  node: "input",
4032
- type: this._config.isMultiple ? "checkbox" : "radio",
4061
+ type: this.config.isMultiple ? "checkbox" : "radio",
4033
4062
  classList: "allow-choice",
4034
4063
  id: inputID,
4035
4064
  },
4036
4065
  },
4037
- ...(this._config.hasImage && {
4066
+ ...(this.config.hasImage && {
4038
4067
  OptionImage: {
4039
4068
  tag: {
4040
4069
  node: "img",
4041
4070
  classList: "option-image",
4042
4071
  style: {
4043
- width: this._config.imageWidth,
4044
- height: this._config.imageHeight,
4045
- borderRadius: this._config.imageBorderRadius,
4072
+ width: this.config.imageWidth,
4073
+ height: this.config.imageHeight,
4074
+ borderRadius: this.config.imageBorderRadius,
4046
4075
  },
4047
4076
  },
4048
4077
  },
@@ -4052,8 +4081,8 @@
4052
4081
  node: "label",
4053
4082
  htmlFor: inputID,
4054
4083
  classList: [
4055
- `align-vertical-${this._config.labelValign}`,
4056
- `align-horizontal-${this._config.labelHalign}`,
4084
+ `align-vertical-${this.config.labelValign}`,
4085
+ `align-horizontal-${this.config.labelHalign}`,
4057
4086
  ],
4058
4087
  },
4059
4088
  child: {
@@ -4075,13 +4104,13 @@
4075
4104
  },
4076
4105
  });
4077
4106
  this.parent.appendChild(this.view.view);
4078
- this._isRendered = true;
4107
+ this.isRendered = true;
4079
4108
  }
4080
4109
  /**
4081
4110
  * Applies a targeted DOM update for a single configuration property change.
4082
4111
  * Safely updates classes, attributes, styles, and child elements without re-rendering the whole view.
4083
4112
  */
4084
- _applyPartialChange(prop, newValue, oldValue) {
4113
+ applyPartialChange(prop, newValue, oldValue) {
4085
4114
  const v = this.view;
4086
4115
  if (!v || !v.view)
4087
4116
  return;
@@ -4101,8 +4130,8 @@
4101
4130
  const val = !!newValue;
4102
4131
  root.classList.toggle("has-image", val);
4103
4132
  if (val) {
4104
- root.classList.add(`image-${this._config.imagePosition}`);
4105
- this._createImage();
4133
+ root.classList.add(`image-${this.config.imagePosition}`);
4134
+ this.createImage();
4106
4135
  }
4107
4136
  else {
4108
4137
  root.className = root.className.replace(/image-(top|right|bottom|left)/g, "").trim();
@@ -4115,7 +4144,7 @@
4115
4144
  break;
4116
4145
  }
4117
4146
  case "imagePosition": {
4118
- if (this._config.hasImage) {
4147
+ if (this.config.hasImage) {
4119
4148
  root.className = root.className.replace(/image-(top|right|bottom|left)/g, "").trim();
4120
4149
  root.classList.add(`image-${String(newValue)}`);
4121
4150
  }
@@ -4138,7 +4167,7 @@
4138
4167
  case "labelValign":
4139
4168
  case "labelHalign": {
4140
4169
  if (label) {
4141
- const newClass = `align-vertical-${this._config.labelValign} align-horizontal-${this._config.labelHalign}`;
4170
+ const newClass = `align-vertical-${this.config.labelValign} align-horizontal-${this.config.labelHalign}`;
4142
4171
  if (label.className !== newClass)
4143
4172
  label.className = newClass;
4144
4173
  }
@@ -4152,7 +4181,7 @@
4152
4181
  * The image receives configured styles (width, height, borderRadius) and is placed
4153
4182
  * before the label if present; otherwise appended to the root. Updates `v.tags.OptionImage`.
4154
4183
  */
4155
- _createImage() {
4184
+ createImage() {
4156
4185
  const v = this.view;
4157
4186
  if (!v || !v.view)
4158
4187
  return;
@@ -4163,9 +4192,9 @@
4163
4192
  const label = v.tags?.OptionLabel;
4164
4193
  const image = document.createElement("img");
4165
4194
  image.className = "option-image";
4166
- image.style.width = this._config.imageWidth;
4167
- image.style.height = this._config.imageHeight;
4168
- image.style.borderRadius = this._config.imageBorderRadius;
4195
+ image.style.width = this.config.imageWidth;
4196
+ image.style.height = this.config.imageHeight;
4197
+ image.style.borderRadius = this.config.imageBorderRadius;
4169
4198
  if (label && label.parentElement)
4170
4199
  root.insertBefore(image, label);
4171
4200
  else
@@ -4181,16 +4210,16 @@
4181
4210
  constructor(items = []) {
4182
4211
  super(items);
4183
4212
  this.isMultiple = false;
4184
- this._visibilityChangedCallbacks = [];
4185
- this._currentHighlightIndex = -1;
4186
- this._selectedItemSingle = null;
4213
+ this.visibilityChangedCallbacks = [];
4214
+ this.currentHighlightIndex = -1;
4215
+ this.selectedItemSingle = null;
4187
4216
  this.groups = [];
4188
4217
  this.flatOptions = [];
4189
- this._buildFlatStructure();
4218
+ this.buildFlatStructure();
4190
4219
  Libs.callbackScheduler.on(`sche_vis_${this.adapterKey}`, () => {
4191
4220
  const visibleCount = this.flatOptions.filter((item) => item.visible).length;
4192
4221
  const totalCount = this.flatOptions.length;
4193
- this._visibilityChangedCallbacks.forEach((callback) => {
4222
+ this.visibilityChangedCallbacks.forEach((callback) => {
4194
4223
  callback({
4195
4224
  visibleCount,
4196
4225
  totalCount,
@@ -4204,7 +4233,7 @@
4204
4233
  /**
4205
4234
  * Build flat list of all options for navigation
4206
4235
  */
4207
- _buildFlatStructure() {
4236
+ buildFlatStructure() {
4208
4237
  this.flatOptions = [];
4209
4238
  this.groups = [];
4210
4239
  this.items.forEach((item) => {
@@ -4240,10 +4269,10 @@
4240
4269
  onViewHolder(item, viewer, position) {
4241
4270
  item.position = position;
4242
4271
  if (item instanceof GroupModel) {
4243
- this._handleGroupView(item, viewer, position);
4272
+ this.handleGroupView(item, viewer, position);
4244
4273
  }
4245
4274
  else if (item instanceof OptionModel) {
4246
- this._handleOptionView(item, viewer, position);
4275
+ this.handleOptionView(item, viewer, position);
4247
4276
  }
4248
4277
  item.isInit = true;
4249
4278
  }
@@ -4255,7 +4284,7 @@
4255
4284
  * @param {GroupView} groupView - The view instance that renders the group in the UI.
4256
4285
  * @param {number} position - The position (index) of the group within a list.
4257
4286
  */
4258
- _handleGroupView(groupModel, groupView, position) {
4287
+ handleGroupView(groupModel, groupView, position) {
4259
4288
  super.onViewHolder(groupModel, groupView, position);
4260
4289
  groupModel.view = groupView;
4261
4290
  const header = groupView.view.tags.GroupHeader;
@@ -4280,7 +4309,7 @@
4280
4309
  if (!optionModel.isInit || !optionViewer) {
4281
4310
  optionViewer = new OptionView(itemsContainer);
4282
4311
  }
4283
- this._handleOptionView(optionModel, optionViewer, idx);
4312
+ this.handleOptionView(optionModel, optionViewer, idx);
4284
4313
  optionModel.isInit = true;
4285
4314
  });
4286
4315
  groupView.setCollapsed(groupModel.collapsed);
@@ -4294,7 +4323,7 @@
4294
4323
  * @param {OptionView} optionViewer - The view instance that renders the option in the UI.
4295
4324
  * @param {number} position - The index of this option within its group's item list.
4296
4325
  */
4297
- _handleOptionView(optionModel, optionViewer, position) {
4326
+ handleOptionView(optionModel, optionViewer, position) {
4298
4327
  optionViewer.isMultiple = this.isMultiple;
4299
4328
  optionViewer.hasImage = optionModel.hasImage;
4300
4329
  optionViewer.optionConfig = {
@@ -4334,8 +4363,8 @@
4334
4363
  else if (optionModel.selected !== true) {
4335
4364
  this.changingProp("select");
4336
4365
  setTimeout(() => {
4337
- if (this._selectedItemSingle)
4338
- this._selectedItemSingle.selected = false;
4366
+ if (this.selectedItemSingle)
4367
+ this.selectedItemSingle.selected = false;
4339
4368
  optionModel.selected = true;
4340
4369
  }, 5);
4341
4370
  }
@@ -4351,16 +4380,16 @@
4351
4380
  });
4352
4381
  optionModel.onInternalSelected((_evtToken, _el, selected) => {
4353
4382
  if (selected)
4354
- this._selectedItemSingle = optionModel;
4383
+ this.selectedItemSingle = optionModel;
4355
4384
  this.changeProp("selected_internal");
4356
4385
  });
4357
4386
  optionModel.onVisibilityChanged((_evtToken, model, _visible) => {
4358
4387
  model.group?.updateVisibility();
4359
- this._notifyVisibilityChanged();
4388
+ this.notifyVisibilityChanged();
4360
4389
  });
4361
4390
  }
4362
4391
  if (optionModel.selected) {
4363
- this._selectedItemSingle = optionModel;
4392
+ this.selectedItemSingle = optionModel;
4364
4393
  optionModel.selectedNonTrigger = true;
4365
4394
  }
4366
4395
  }
@@ -4372,7 +4401,7 @@
4372
4401
  setItems(items) {
4373
4402
  this.changingProp("items", items);
4374
4403
  this.items = items;
4375
- this._buildFlatStructure();
4404
+ this.buildFlatStructure();
4376
4405
  this.changeProp("items", items);
4377
4406
  }
4378
4407
  /**
@@ -4391,7 +4420,7 @@
4391
4420
  */
4392
4421
  updateData(items) {
4393
4422
  this.items = items;
4394
- this._buildFlatStructure();
4423
+ this.buildFlatStructure();
4395
4424
  }
4396
4425
  /**
4397
4426
  * Returns all option items that are currently selected.
@@ -4428,13 +4457,13 @@
4428
4457
  * - Function to invoke when visibility stats change.
4429
4458
  */
4430
4459
  onVisibilityChanged(callback) {
4431
- this._visibilityChangedCallbacks.push(callback);
4460
+ this.visibilityChangedCallbacks.push(callback);
4432
4461
  }
4433
4462
  /**
4434
4463
  * Notifies all registered visibility-change callbacks with up-to-date statistics.
4435
4464
  * Computes visible and total counts, then emits aggregated state.
4436
4465
  */
4437
- _notifyVisibilityChanged() {
4466
+ notifyVisibilityChanged() {
4438
4467
  Libs.callbackScheduler.run(`sche_vis_${this.adapterKey}`);
4439
4468
  }
4440
4469
  /**
@@ -4466,7 +4495,7 @@
4466
4495
  const visibleOptions = this.flatOptions.filter((opt) => opt.visible);
4467
4496
  if (visibleOptions.length === 0)
4468
4497
  return;
4469
- let currentVisibleIndex = visibleOptions.findIndex((opt) => opt === this.flatOptions[this._currentHighlightIndex]);
4498
+ let currentVisibleIndex = visibleOptions.findIndex((opt) => opt === this.flatOptions[this.currentHighlightIndex]);
4470
4499
  if (currentVisibleIndex === -1)
4471
4500
  currentVisibleIndex = -1;
4472
4501
  let nextVisibleIndex = currentVisibleIndex + direction;
@@ -4483,8 +4512,8 @@
4483
4512
  * No-op if nothing is highlighted or the highlighted item is not visible.
4484
4513
  */
4485
4514
  selectHighlighted() {
4486
- if (this._currentHighlightIndex > -1 && this.flatOptions[this._currentHighlightIndex]) {
4487
- const item = this.flatOptions[this._currentHighlightIndex];
4515
+ if (this.currentHighlightIndex > -1 && this.flatOptions[this.currentHighlightIndex]) {
4516
+ const item = this.flatOptions[this.currentHighlightIndex];
4488
4517
  if (item.visible) {
4489
4518
  const viewEl = item.view?.getView?.();
4490
4519
  if (viewEl)
@@ -4511,15 +4540,15 @@
4511
4540
  else {
4512
4541
  index = 0;
4513
4542
  }
4514
- if (this._currentHighlightIndex > -1 && this.flatOptions[this._currentHighlightIndex]) {
4515
- this.flatOptions[this._currentHighlightIndex].highlighted = false;
4543
+ if (this.currentHighlightIndex > -1 && this.flatOptions[this.currentHighlightIndex]) {
4544
+ this.flatOptions[this.currentHighlightIndex].highlighted = false;
4516
4545
  }
4517
4546
  for (let i = index; i < this.flatOptions.length; i++) {
4518
4547
  const item = this.flatOptions[i];
4519
4548
  if (!item?.visible)
4520
4549
  continue;
4521
4550
  item.highlighted = true;
4522
- this._currentHighlightIndex = i;
4551
+ this.currentHighlightIndex = i;
4523
4552
  if (isScrollToView) {
4524
4553
  const el = item.view?.getView?.();
4525
4554
  if (el) {
@@ -4628,15 +4657,15 @@
4628
4657
  this.firstMeasured = false;
4629
4658
  this.start = 0;
4630
4659
  this.end = -1;
4631
- this._rafId = null;
4632
- this._measureRaf = null;
4633
- this._updating = false;
4634
- this._suppressResize = false;
4635
- this._lastRenderCount = 0;
4636
- this._suspended = false;
4637
- this._resumeResizeAfter = false;
4638
- this._stickyCacheTick = 0;
4639
- this._stickyCacheVal = 0;
4660
+ this.rafId = null;
4661
+ this.measureRaf = null;
4662
+ this.updating = false;
4663
+ this.suppressResize = false;
4664
+ this.lastRenderCount = 0;
4665
+ this.suspended = false;
4666
+ this.resumeResizeAfter = false;
4667
+ this.stickyCacheTick = 0;
4668
+ this.stickyCacheVal = 0;
4640
4669
  this.measuredSum = 0;
4641
4670
  this.measuredCount = 0;
4642
4671
  }
@@ -4669,8 +4698,8 @@
4669
4698
  ?? this.viewElement.parentElement;
4670
4699
  if (!this.scrollEl)
4671
4700
  throw new Error("VirtualRecyclerView: scrollEl not found");
4672
- this._boundOnScroll = this.onScroll.bind(this);
4673
- this.scrollEl.addEventListener("scroll", this._boundOnScroll, { passive: true });
4701
+ this.boundOnScroll = this.onScroll.bind(this);
4702
+ this.scrollEl.addEventListener("scroll", this.boundOnScroll, { passive: true });
4674
4703
  this.refresh(false);
4675
4704
  this.attachResizeObserverOnce();
4676
4705
  adapter?.onVisibilityChanged?.(() => this.refreshItem());
@@ -4680,14 +4709,14 @@
4680
4709
  * Cancels pending frames and disconnects observers.
4681
4710
  */
4682
4711
  suspend() {
4683
- this._suspended = true;
4712
+ this.suspended = true;
4684
4713
  this.cancelFrames();
4685
- if (this.scrollEl && this._boundOnScroll) {
4686
- this.scrollEl.removeEventListener("scroll", this._boundOnScroll);
4714
+ if (this.scrollEl && this.boundOnScroll) {
4715
+ this.scrollEl.removeEventListener("scroll", this.boundOnScroll);
4687
4716
  }
4688
4717
  if (this.resizeObs) {
4689
4718
  this.resizeObs.disconnect();
4690
- this._resumeResizeAfter = true;
4719
+ this.resumeResizeAfter = true;
4691
4720
  }
4692
4721
  }
4693
4722
  /**
@@ -4695,13 +4724,13 @@
4695
4724
  * Re-attaches listeners and schedules window update.
4696
4725
  */
4697
4726
  resume() {
4698
- this._suspended = false;
4699
- if (this.scrollEl && this._boundOnScroll) {
4700
- this.scrollEl.addEventListener("scroll", this._boundOnScroll, { passive: true });
4727
+ this.suspended = false;
4728
+ if (this.scrollEl && this.boundOnScroll) {
4729
+ this.scrollEl.addEventListener("scroll", this.boundOnScroll, { passive: true });
4701
4730
  }
4702
- if (this._resumeResizeAfter) {
4731
+ if (this.resumeResizeAfter) {
4703
4732
  this.attachResizeObserverOnce();
4704
- this._resumeResizeAfter = false;
4733
+ this.resumeResizeAfter = false;
4705
4734
  }
4706
4735
  this.scheduleUpdateWindow();
4707
4736
  }
@@ -4717,7 +4746,7 @@
4717
4746
  if (!isUpdate)
4718
4747
  this.refreshItem();
4719
4748
  const count = this.adapter.itemCount();
4720
- this._lastRenderCount = count;
4749
+ this.lastRenderCount = count;
4721
4750
  if (count === 0) {
4722
4751
  this.resetState();
4723
4752
  return;
@@ -4759,8 +4788,8 @@
4759
4788
  */
4760
4789
  dispose() {
4761
4790
  this.cancelFrames();
4762
- if (this.scrollEl && this._boundOnScroll) {
4763
- this.scrollEl.removeEventListener("scroll", this._boundOnScroll);
4791
+ if (this.scrollEl && this.boundOnScroll) {
4792
+ this.scrollEl.removeEventListener("scroll", this.boundOnScroll);
4764
4793
  }
4765
4794
  this.resizeObs?.disconnect();
4766
4795
  this.created.forEach(el => el.remove());
@@ -4788,13 +4817,13 @@
4788
4817
  }
4789
4818
  /** Cancels all pending animation frames. */
4790
4819
  cancelFrames() {
4791
- if (this._rafId != null) {
4792
- cancelAnimationFrame(this._rafId);
4793
- this._rafId = null;
4820
+ if (this.rafId != null) {
4821
+ cancelAnimationFrame(this.rafId);
4822
+ this.rafId = null;
4794
4823
  }
4795
- if (this._measureRaf != null) {
4796
- cancelAnimationFrame(this._measureRaf);
4797
- this._measureRaf = null;
4824
+ if (this.measureRaf != null) {
4825
+ cancelAnimationFrame(this.measureRaf);
4826
+ this.measureRaf = null;
4798
4827
  }
4799
4828
  }
4800
4829
  /** Resets all internal state: DOM, caches, measurements. */
@@ -4880,19 +4909,19 @@
4880
4909
  */
4881
4910
  stickyTopHeight() {
4882
4911
  const now = performance.now();
4883
- if (now - this._stickyCacheTick < 16)
4884
- return this._stickyCacheVal;
4912
+ if (now - this.stickyCacheTick < 16)
4913
+ return this.stickyCacheVal;
4885
4914
  const sticky = this.scrollEl.querySelector(".selective-ui-option-handle:not(.hide)");
4886
- this._stickyCacheVal = sticky?.offsetHeight ?? 0;
4887
- this._stickyCacheTick = now;
4888
- return this._stickyCacheVal;
4915
+ this.stickyCacheVal = sticky?.offsetHeight ?? 0;
4916
+ this.stickyCacheTick = now;
4917
+ return this.stickyCacheVal;
4889
4918
  }
4890
4919
  /** Schedules window update on next frame if not already scheduled. */
4891
4920
  scheduleUpdateWindow() {
4892
- if (this._rafId != null || this._suspended)
4921
+ if (this.rafId != null || this.suspended)
4893
4922
  return;
4894
- this._rafId = requestAnimationFrame(() => {
4895
- this._rafId = null;
4923
+ this.rafId = requestAnimationFrame(() => {
4924
+ this.rafId = null;
4896
4925
  this.updateWindowInternal();
4897
4926
  });
4898
4927
  }
@@ -5014,10 +5043,10 @@
5014
5043
  if (this.resizeObs)
5015
5044
  return;
5016
5045
  this.resizeObs = new ResizeObserver(() => {
5017
- if (this._suppressResize || this._suspended || !this.adapter || this._measureRaf != null)
5046
+ if (this.suppressResize || this.suspended || !this.adapter || this.measureRaf != null)
5018
5047
  return;
5019
- this._measureRaf = requestAnimationFrame(() => {
5020
- this._measureRaf = null;
5048
+ this.measureRaf = requestAnimationFrame(() => {
5049
+ this.measureRaf = null;
5021
5050
  this.measureVisibleAndUpdate();
5022
5051
  });
5023
5052
  });
@@ -5067,17 +5096,17 @@
5067
5096
  * 7. Adjusts scroll position to maintain anchor item position
5068
5097
  */
5069
5098
  updateWindowInternal() {
5070
- if (this._updating || this._suspended)
5099
+ if (this.updating || this.suspended)
5071
5100
  return;
5072
- this._updating = true;
5101
+ this.updating = true;
5073
5102
  try {
5074
5103
  if (!this.adapter)
5075
5104
  return;
5076
5105
  const count = this.adapter.itemCount();
5077
5106
  if (count <= 0)
5078
5107
  return;
5079
- if (this._lastRenderCount !== count) {
5080
- this._lastRenderCount = count;
5108
+ if (this.lastRenderCount !== count) {
5109
+ this.lastRenderCount = count;
5081
5110
  this.heightCache.length = count;
5082
5111
  this.rebuildFenwick(count);
5083
5112
  }
@@ -5101,7 +5130,7 @@
5101
5130
  return;
5102
5131
  this.start = startIndex;
5103
5132
  this.end = endIndex;
5104
- this._suppressResize = true;
5133
+ this.suppressResize = true;
5105
5134
  try {
5106
5135
  this.mountRange(this.start, this.end);
5107
5136
  this.unmountOutside(this.start, this.end);
@@ -5115,7 +5144,7 @@
5115
5144
  this.PadBottom.style.height = `${bottomPx}px`;
5116
5145
  }
5117
5146
  finally {
5118
- this._suppressResize = false;
5147
+ this.suppressResize = false;
5119
5148
  }
5120
5149
  const anchorTopNew = this.offsetTopOf(anchorIndex);
5121
5150
  const targetScroll = this.containerTopInScroll() + anchorTopNew - anchorDelta;
@@ -5126,7 +5155,7 @@
5126
5155
  }
5127
5156
  }
5128
5157
  finally {
5129
- this._updating = false;
5158
+ this.updating = false;
5130
5159
  }
5131
5160
  }
5132
5161
  /** Mounts all items in inclusive range [start..end]. */
@@ -5418,6 +5447,7 @@
5418
5447
  .search(keyword)
5419
5448
  .then((result) => {
5420
5449
  clearTimeout(hightlightTimer);
5450
+ Libs.callbackScheduler.clear(`sche_vis_proxy_${optionAdapter.adapterKey}`);
5421
5451
  Libs.callbackScheduler.on(`sche_vis_proxy_${optionAdapter.adapterKey}`, () => {
5422
5452
  container.popup?.triggerResize?.();
5423
5453
  if (result?.hasResults) {
@@ -5875,9 +5905,9 @@
5875
5905
  */
5876
5906
  class ElementAdditionObserver {
5877
5907
  constructor() {
5878
- this._isActive = false;
5879
- this._observer = null;
5880
- this._actions = [];
5908
+ this.isActive = false;
5909
+ this.observer = null;
5910
+ this.actions = [];
5881
5911
  }
5882
5912
  /**
5883
5913
  * Registers a callback to be invoked whenever a matching element is detected being added to the DOM.
@@ -5885,13 +5915,13 @@
5885
5915
  * @param {(el: T) => void} action - Function executed with the newly added element.
5886
5916
  */
5887
5917
  onDetect(action) {
5888
- this._actions.push(action);
5918
+ this.actions.push(action);
5889
5919
  }
5890
5920
  /**
5891
5921
  * Clears all previously registered detection callbacks.
5892
5922
  */
5893
5923
  clearDetect() {
5894
- this._actions = [];
5924
+ this.actions = [];
5895
5925
  }
5896
5926
  /**
5897
5927
  * Starts observing the document for additions of elements matching the given tag.
@@ -5900,26 +5930,26 @@
5900
5930
  * @param {string} tag - The tag name to watch for (e.g., "select", "div").
5901
5931
  */
5902
5932
  start(tag) {
5903
- if (this._isActive)
5933
+ if (this.isActive)
5904
5934
  return;
5905
- this._isActive = true;
5935
+ this.isActive = true;
5906
5936
  const upperTag = tag.toUpperCase();
5907
5937
  const lowerTag = tag.toLowerCase();
5908
- this._observer = new MutationObserver((mutations) => {
5938
+ this.observer = new MutationObserver((mutations) => {
5909
5939
  for (const mutation of mutations) {
5910
5940
  mutation.addedNodes.forEach((node) => {
5911
5941
  if (node.nodeType !== 1)
5912
5942
  return;
5913
5943
  const subnode = node;
5914
5944
  if (subnode.tagName === upperTag) {
5915
- this._handle(subnode);
5945
+ this.handle(subnode);
5916
5946
  }
5917
5947
  const matches = subnode.querySelectorAll(lowerTag);
5918
- matches.forEach((el) => this._handle(el));
5948
+ matches.forEach((el) => this.handle(el));
5919
5949
  });
5920
5950
  }
5921
5951
  });
5922
- this._observer.observe(document.body, {
5952
+ this.observer.observe(document.body, {
5923
5953
  childList: true,
5924
5954
  subtree: true,
5925
5955
  });
@@ -5929,19 +5959,19 @@
5929
5959
  * No-ops if the observer is not active.
5930
5960
  */
5931
5961
  stop() {
5932
- if (!this._isActive)
5962
+ if (!this.isActive)
5933
5963
  return;
5934
- this._isActive = false;
5935
- this._observer?.disconnect();
5936
- this._observer = null;
5964
+ this.isActive = false;
5965
+ this.observer?.disconnect();
5966
+ this.observer = null;
5937
5967
  }
5938
5968
  /**
5939
5969
  * Internal handler that invokes all registered detection callbacks for the provided element.
5940
5970
  *
5941
5971
  * @param {T} element - The element that was detected as added to the DOM.
5942
5972
  */
5943
- _handle(element) {
5944
- this._actions.forEach((action) => action(element));
5973
+ handle(element) {
5974
+ this.actions.forEach((action) => action(element));
5945
5975
  }
5946
5976
  }
5947
5977
 
@@ -6256,7 +6286,7 @@
6256
6286
  if (typeof globalThis.GLOBAL_SEUI == "undefined") {
6257
6287
  const SECLASS = new Selective();
6258
6288
  globalThis.GLOBAL_SEUI = {
6259
- version: "1.2.1",
6289
+ version: "1.2.2",
6260
6290
  name: "SelectiveUI",
6261
6291
  bind: SECLASS.bind.bind(SECLASS),
6262
6292
  find: SECLASS.find.bind(SECLASS),
@@ -6287,7 +6317,7 @@
6287
6317
  init();
6288
6318
  }
6289
6319
  }
6290
- console.log(`[${"SelectiveUI"}] v${"1.2.1"} loaded successfully`);
6320
+ console.log(`[${"SelectiveUI"}] v${"1.2.2"} loaded successfully`);
6291
6321
  }
6292
6322
  else {
6293
6323
  console.warn(`[${globalThis.GLOBAL_SEUI.name}] Already loaded (v${globalThis.GLOBAL_SEUI.version}). ` +