selective-ui 1.2.5 → 1.2.6
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/README.md +7 -0
- package/dist/selective-ui.css +64 -58
- package/dist/selective-ui.css.map +1 -1
- package/dist/selective-ui.esm.js +240 -125
- 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.css +1 -1
- package/dist/selective-ui.min.css.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 +245 -126
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/css/components/accessorybox.css +1 -1
- package/src/css/components/directive.css +2 -2
- package/src/css/components/option-handle.css +4 -4
- package/src/css/components/placeholder.css +1 -1
- package/src/css/components/popup/empty-state.css +3 -3
- package/src/css/components/popup/loading-state.css +3 -3
- package/src/css/components/popup/popup.css +5 -5
- package/src/css/components/searchbox.css +2 -2
- package/src/css/components/selectbox.css +7 -7
- package/src/css/views/group-view.css +8 -8
- package/src/css/views/option-view.css +22 -22
- package/src/ts/adapter/mixed-adapter.ts +1 -1
- package/src/ts/components/accessorybox.ts +9 -9
- package/src/ts/components/directive.ts +2 -2
- package/src/ts/components/option-handle.ts +9 -9
- package/src/ts/components/placeholder.ts +5 -5
- package/src/ts/components/popup/empty-state.ts +4 -4
- package/src/ts/components/popup/loading-state.ts +4 -4
- package/src/ts/components/popup/popup.ts +19 -38
- package/src/ts/components/searchbox.ts +6 -6
- package/src/ts/components/selectbox.ts +93 -11
- package/src/ts/core/base/adapter.ts +2 -2
- package/src/ts/core/base/virtual-recyclerview.ts +6 -6
- package/src/ts/core/model-manager.ts +10 -11
- package/src/ts/core/search-controller.ts +2 -2
- package/src/ts/global.ts +26 -5
- package/src/ts/index.ts +22 -3
- package/src/ts/models/option-model.ts +13 -5
- package/src/ts/services/refresher.ts +2 -1
- package/src/ts/services/resize-observer.ts +4 -4
- package/src/ts/types/core/base/view.type.ts +3 -3
- package/src/ts/types/core/base/virtual-recyclerview.type.ts +1 -1
- package/src/ts/types/plugins/plugin.type.ts +46 -0
- package/src/ts/types/utils/istorage.type.ts +8 -4
- package/src/ts/types/utils/libs.type.ts +2 -2
- package/src/ts/types/utils/selective.type.ts +14 -1
- package/src/ts/utils/callback-scheduler.ts +4 -4
- package/src/ts/utils/libs.ts +41 -65
- package/src/ts/utils/selective.ts +85 -21
- package/src/ts/views/group-view.ts +6 -6
- package/src/ts/views/option-view.ts +11 -11
package/dist/selective-ui.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Selective UI v1.2.
|
|
1
|
+
/*! Selective UI v1.2.6 | MIT License */
|
|
2
2
|
/**
|
|
3
3
|
* @class
|
|
4
4
|
*/
|
|
@@ -207,7 +207,7 @@ class CallbackScheduler {
|
|
|
207
207
|
* @public
|
|
208
208
|
* @param {TimerKey} key - Key whose callbacks will be scheduled.
|
|
209
209
|
* @param {...any[]} params - Parameters passed as a shared payload to all callbacks.
|
|
210
|
-
* @returns {Promise<void>
|
|
210
|
+
* @returns {Promise<void>} Promise resolving when all callbacks finish execution.
|
|
211
211
|
*/
|
|
212
212
|
run(key, ...params) {
|
|
213
213
|
const executes = this.executeStored.get(key);
|
|
@@ -326,11 +326,11 @@ class Libs {
|
|
|
326
326
|
return result;
|
|
327
327
|
}
|
|
328
328
|
/**
|
|
329
|
-
* Resolves a selector, NodeList, or single
|
|
329
|
+
* Resolves a selector, NodeList, or single HTMLElement into an array of elements.
|
|
330
330
|
* Returns an empty array if nothing is found.
|
|
331
331
|
*
|
|
332
|
-
* @param {string|NodeListOf<
|
|
333
|
-
* @returns {
|
|
332
|
+
* @param {string|NodeListOf<HTMLElement>|HTMLElement|HTMLElement|ArrayLike<HTMLElement>|null} queryCommon - CSS selector, NodeList, or HTMLElement.
|
|
333
|
+
* @returns {HTMLElement[]} - Array of matched elements (empty if none).
|
|
334
334
|
*/
|
|
335
335
|
static getElements(queryCommon) {
|
|
336
336
|
if (!queryCommon)
|
|
@@ -339,7 +339,7 @@ class Libs {
|
|
|
339
339
|
const nodeList = document.querySelectorAll(queryCommon);
|
|
340
340
|
return Array.from(nodeList);
|
|
341
341
|
}
|
|
342
|
-
if (queryCommon instanceof
|
|
342
|
+
if (queryCommon instanceof HTMLElement) {
|
|
343
343
|
return [queryCommon];
|
|
344
344
|
}
|
|
345
345
|
// NodeList or array-like
|
|
@@ -349,27 +349,27 @@ class Libs {
|
|
|
349
349
|
return [];
|
|
350
350
|
}
|
|
351
351
|
/**
|
|
352
|
-
* Creates a new
|
|
352
|
+
* Creates a new HTMLElement based on a NodeSpec and applies attributes, classes, styles, dataset, and events.
|
|
353
353
|
*
|
|
354
354
|
* @param {NodeSpec} data - Specification describing the element to create.
|
|
355
|
-
* @returns {
|
|
355
|
+
* @returns {HTMLElement} - The created element.
|
|
356
356
|
*/
|
|
357
357
|
static nodeCreator(data = {}) {
|
|
358
358
|
const nodeName = (data.node ?? "div");
|
|
359
359
|
return this.nodeCloner(document.createElement(nodeName), data, true);
|
|
360
360
|
}
|
|
361
361
|
/**
|
|
362
|
-
* Clones an element (or converts a Node to
|
|
362
|
+
* Clones an element (or converts a Node to HTMLElement) and applies NodeSpec options.
|
|
363
363
|
* When systemNodeCreate=true, uses the provided node as-is.
|
|
364
364
|
*
|
|
365
|
-
* @param {
|
|
365
|
+
* @param {HTMLElement} node - The element to clone or use.
|
|
366
366
|
* @param {NodeSpec|null} _nodeOption - Options (classList, style, dataset, event, other props).
|
|
367
367
|
* @param {boolean} systemNodeCreate - If true, do not clone; use original node.
|
|
368
|
-
* @returns {
|
|
368
|
+
* @returns {HTMLElement} - The processed element.
|
|
369
369
|
*/
|
|
370
370
|
static nodeCloner(node = document.documentElement, _nodeOption = null, systemNodeCreate = false) {
|
|
371
371
|
const nodeOption = { ...(_nodeOption ?? {}) };
|
|
372
|
-
const element_creation = systemNodeCreate ? node :
|
|
372
|
+
const element_creation = systemNodeCreate ? node : node.cloneNode(true);
|
|
373
373
|
const classList = nodeOption.classList;
|
|
374
374
|
if (typeof classList === "string") {
|
|
375
375
|
element_creation.classList.add(classList);
|
|
@@ -429,40 +429,17 @@ class Libs {
|
|
|
429
429
|
});
|
|
430
430
|
return element_creation;
|
|
431
431
|
}
|
|
432
|
-
/**
|
|
433
|
-
* Ensures the given Node is an Element; throws if not.
|
|
434
|
-
*
|
|
435
|
-
* @param {Node} node - The node to validate.
|
|
436
|
-
* @returns {Element} - The element cast.
|
|
437
|
-
* @throws {TypeError} - If node is not an Element.
|
|
438
|
-
*/
|
|
439
|
-
static nodeToElement(node) {
|
|
440
|
-
if (node instanceof Element)
|
|
441
|
-
return node;
|
|
442
|
-
throw new TypeError("Node is not an Element");
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Mounts a view from a plain object specification and returns a typed result
|
|
446
|
-
* containing the root element and a tag map.
|
|
447
|
-
*
|
|
448
|
-
* @template TTags
|
|
449
|
-
* @param {object} rawObj - The specification describing elements and tags.
|
|
450
|
-
* @returns {MountViewResult<TTags>} - The mounted view and its tag references.
|
|
451
|
-
*/
|
|
452
|
-
static mountView(rawObj) {
|
|
453
|
-
return this.mountNode(rawObj);
|
|
454
|
-
}
|
|
455
432
|
/**
|
|
456
433
|
* Recursively builds DOM nodes from a specification object, appends/prepends them
|
|
457
434
|
* to an optional parent, and returns either a tag map or a full MountViewResult.
|
|
458
435
|
*
|
|
459
436
|
* @template TTags
|
|
460
437
|
* @param {Object<string, any>} rawObj - Node spec (keys -> { tag, child }).
|
|
461
|
-
* @param {
|
|
438
|
+
* @param {HTMLElement|null} [parentE=null] - Parent to attach into; if null, returns root.
|
|
462
439
|
* @param {boolean} [isPrepend=false] - If true, prepend; otherwise append.
|
|
463
440
|
* @param {boolean} [isRecusive=false] - Internal flag for recursion control.
|
|
464
441
|
* @param {TTags|Object} [recursiveTemp={}] - Accumulator for tag references.
|
|
465
|
-
* @returns {
|
|
442
|
+
* @returns {TTags} - Tag map or the final mount result.
|
|
466
443
|
*/
|
|
467
444
|
static mountNode(rawObj, parentE = null, isPrepend = false, isRecusive = false, recursiveTemp = {}) {
|
|
468
445
|
let view = null;
|
|
@@ -581,7 +558,7 @@ class Libs {
|
|
|
581
558
|
/**
|
|
582
559
|
* Removes a binder map entry for the given element from the global storage.
|
|
583
560
|
*
|
|
584
|
-
* @param {HTMLElement} element -
|
|
561
|
+
* @param {HTMLElement} element - HTMLElement key to remove from the binder map.
|
|
585
562
|
* @returns {boolean} - True if an entry existed and was removed.
|
|
586
563
|
*/
|
|
587
564
|
static removeBinderMap(element) {
|
|
@@ -590,8 +567,8 @@ class Libs {
|
|
|
590
567
|
/**
|
|
591
568
|
* Retrieves the binder map entry associated with the given element.
|
|
592
569
|
*
|
|
593
|
-
* @param {HTMLElement} item -
|
|
594
|
-
* @returns {BinderMap |
|
|
570
|
+
* @param {HTMLElement} item - HTMLElement key whose binder map is requested.
|
|
571
|
+
* @returns {BinderMap | any} - The stored binder map value or undefined if absent.
|
|
595
572
|
*/
|
|
596
573
|
static getBinderMap(item) {
|
|
597
574
|
return this.iStorage.bindedMap.get(item);
|
|
@@ -599,7 +576,7 @@ class Libs {
|
|
|
599
576
|
/**
|
|
600
577
|
* Sets or updates the binder map entry for a given element.
|
|
601
578
|
*
|
|
602
|
-
* @param {HTMLElement} item -
|
|
579
|
+
* @param {HTMLElement} item - HTMLElement key to associate with the binder map.
|
|
603
580
|
* @param {BinderMap} bindMap - Value to store in the binder map.
|
|
604
581
|
*/
|
|
605
582
|
static setBinderMap(item, bindMap) {
|
|
@@ -608,7 +585,7 @@ class Libs {
|
|
|
608
585
|
/**
|
|
609
586
|
* Removes an unbinder map entry for the given element from the global storage.
|
|
610
587
|
*
|
|
611
|
-
* @param {HTMLElement} element -
|
|
588
|
+
* @param {HTMLElement} element - HTMLElement key to remove from the unbinder map.
|
|
612
589
|
* @returns {boolean} - True if an entry existed and was removed.
|
|
613
590
|
*/
|
|
614
591
|
static removeUnbinderMap(element) {
|
|
@@ -617,7 +594,7 @@ class Libs {
|
|
|
617
594
|
/**
|
|
618
595
|
* Retrieves the unbinder map entry associated with the given element.
|
|
619
596
|
*
|
|
620
|
-
* @param {HTMLElement} item -
|
|
597
|
+
* @param {HTMLElement} item - HTMLElement key whose unbinder map is requested.
|
|
621
598
|
* @returns {unknown} - The stored unbinder map value or undefined if absent.
|
|
622
599
|
*/
|
|
623
600
|
static getUnbinderMap(item) {
|
|
@@ -626,7 +603,7 @@ class Libs {
|
|
|
626
603
|
/**
|
|
627
604
|
* Sets or updates the unbinder map entry for a given element.
|
|
628
605
|
*
|
|
629
|
-
* @param {HTMLElement} item -
|
|
606
|
+
* @param {HTMLElement} item - HTMLElement key to associate with the unbinder map.
|
|
630
607
|
* @param {BinderMap} bindMap - Value to store in the unbinder map.
|
|
631
608
|
*/
|
|
632
609
|
static setUnbinderMap(item, bindMap) {
|
|
@@ -1274,7 +1251,7 @@ class Lifecycle {
|
|
|
1274
1251
|
* getter/setter APIs for the placeholder content.
|
|
1275
1252
|
*
|
|
1276
1253
|
* ### Responsibility
|
|
1277
|
-
* - Create and own the placeholder DOM element (`.
|
|
1254
|
+
* - Create and own the placeholder DOM element (`.seui-placeholder`).
|
|
1278
1255
|
* - Render placeholder content from {@link SelectiveOptions.placeholder}.
|
|
1279
1256
|
* - Support runtime updates via {@link set}, optionally persisting into options.
|
|
1280
1257
|
* - Participate in the shared {@link Lifecycle} FSM.
|
|
@@ -1332,7 +1309,7 @@ class PlaceHolder extends Lifecycle {
|
|
|
1332
1309
|
* Builds the placeholder DOM node and starts the lifecycle.
|
|
1333
1310
|
*
|
|
1334
1311
|
* Side effects:
|
|
1335
|
-
* - Creates a `div.
|
|
1312
|
+
* - Creates a `div.seui-placeholder` node via {@link Libs.nodeCreator}.
|
|
1336
1313
|
* - Writes initial placeholder content into `innerHTML`.
|
|
1337
1314
|
* - Transitions the lifecycle by calling `init()`.
|
|
1338
1315
|
*
|
|
@@ -1342,7 +1319,7 @@ class PlaceHolder extends Lifecycle {
|
|
|
1342
1319
|
initialize(options) {
|
|
1343
1320
|
this.node = Libs.nodeCreator({
|
|
1344
1321
|
node: "div",
|
|
1345
|
-
classList: "
|
|
1322
|
+
classList: "seui-placeholder",
|
|
1346
1323
|
innerHTML: options.placeholder,
|
|
1347
1324
|
});
|
|
1348
1325
|
this.options = options;
|
|
@@ -1463,7 +1440,7 @@ class Directive extends Lifecycle {
|
|
|
1463
1440
|
// is guaranteed to be an HTMLElement in this context.
|
|
1464
1441
|
this.node = Libs.nodeCreator({
|
|
1465
1442
|
node: "div",
|
|
1466
|
-
classList: "
|
|
1443
|
+
classList: "seui-directive",
|
|
1467
1444
|
role: "button",
|
|
1468
1445
|
ariaLabel: "Toggle dropdown",
|
|
1469
1446
|
});
|
|
@@ -1602,9 +1579,9 @@ class OptionHandle extends Lifecycle {
|
|
|
1602
1579
|
* Initializes DOM and binds event handlers.
|
|
1603
1580
|
*
|
|
1604
1581
|
* DOM structure (conceptually):
|
|
1605
|
-
* - Root: `div.
|
|
1606
|
-
* - Child: `a.
|
|
1607
|
-
* - Child: `a.
|
|
1582
|
+
* - Root: `div.seui-option-handle.hide`
|
|
1583
|
+
* - Child: `a.seui-option-handle-item` ("Select all")
|
|
1584
|
+
* - Child: `a.seui-option-handle-item` ("Deselect all")
|
|
1608
1585
|
*
|
|
1609
1586
|
* Click handlers:
|
|
1610
1587
|
* - "Select all" → dispatches {@link actionOnSelectAll} via {@link iEvents.callFunctions}
|
|
@@ -1620,12 +1597,12 @@ class OptionHandle extends Lifecycle {
|
|
|
1620
1597
|
initialize(options) {
|
|
1621
1598
|
this.nodeMounted = Libs.mountNode({
|
|
1622
1599
|
OptionHandle: {
|
|
1623
|
-
tag: { node: "div", classList: ["
|
|
1600
|
+
tag: { node: "div", classList: ["seui-option-handle", "hide"] },
|
|
1624
1601
|
child: {
|
|
1625
1602
|
SelectAll: {
|
|
1626
1603
|
tag: {
|
|
1627
1604
|
node: "a",
|
|
1628
|
-
classList: "
|
|
1605
|
+
classList: "seui-option-handle-item",
|
|
1629
1606
|
textContent: options.textSelectAll,
|
|
1630
1607
|
onclick: () => {
|
|
1631
1608
|
iEvents.callFunctions(this.actionOnSelectAll);
|
|
@@ -1635,7 +1612,7 @@ class OptionHandle extends Lifecycle {
|
|
|
1635
1612
|
DeSelectAll: {
|
|
1636
1613
|
tag: {
|
|
1637
1614
|
node: "a",
|
|
1638
|
-
classList: "
|
|
1615
|
+
classList: "seui-option-handle-item",
|
|
1639
1616
|
textContent: options.textDeselectAll,
|
|
1640
1617
|
onclick: () => {
|
|
1641
1618
|
iEvents.callFunctions(this.actionOnDeSelectAll);
|
|
@@ -1833,7 +1810,7 @@ class EmptyState extends Lifecycle {
|
|
|
1833
1810
|
*
|
|
1834
1811
|
* Side effects:
|
|
1835
1812
|
* - Creates the root `div` node with `role="status"` and `aria-live="polite"`.
|
|
1836
|
-
* - Applies base CSS classes: `"
|
|
1813
|
+
* - Applies base CSS classes: `"seui-empty-state"` and `"hide"`.
|
|
1837
1814
|
* - Stores the options reference and calls {@link Lifecycle.init}.
|
|
1838
1815
|
*
|
|
1839
1816
|
* @param {SelectiveOptions} options - Configuration object containing empty state messages.
|
|
@@ -1843,7 +1820,7 @@ class EmptyState extends Lifecycle {
|
|
|
1843
1820
|
this.options = options;
|
|
1844
1821
|
this.node = Libs.nodeCreator({
|
|
1845
1822
|
node: "div",
|
|
1846
|
-
classList: ["
|
|
1823
|
+
classList: ["seui-empty-state", "hide"],
|
|
1847
1824
|
role: "status",
|
|
1848
1825
|
ariaLive: "polite",
|
|
1849
1826
|
});
|
|
@@ -1976,7 +1953,7 @@ class LoadingState extends Lifecycle {
|
|
|
1976
1953
|
* Initializes internal resources for this component.
|
|
1977
1954
|
*
|
|
1978
1955
|
* Side effects:
|
|
1979
|
-
* - Creates the root `div` node with base CSS classes: `"
|
|
1956
|
+
* - Creates the root `div` node with base CSS classes: `"seui-loading-state"` and `"hide"`.
|
|
1980
1957
|
* - Sets initial text to `options.textLoading`.
|
|
1981
1958
|
* - Applies `role="status"` and `aria-live="polite"`.
|
|
1982
1959
|
* - Stores the options reference and calls {@link Lifecycle.init}.
|
|
@@ -1988,7 +1965,7 @@ class LoadingState extends Lifecycle {
|
|
|
1988
1965
|
this.options = options;
|
|
1989
1966
|
this.node = Libs.nodeCreator({
|
|
1990
1967
|
node: "div",
|
|
1991
|
-
classList: ["
|
|
1968
|
+
classList: ["seui-loading-state", "hide"],
|
|
1992
1969
|
textContent: options.textLoading,
|
|
1993
1970
|
role: "status",
|
|
1994
1971
|
ariaLive: "polite",
|
|
@@ -2249,7 +2226,7 @@ class ResizeObserverService {
|
|
|
2249
2226
|
* Not idempotent. Call {@link disconnect} before calling `connect()` again to avoid duplicates.
|
|
2250
2227
|
*/
|
|
2251
2228
|
connect(element) {
|
|
2252
|
-
if (!(element instanceof
|
|
2229
|
+
if (!(element instanceof HTMLElement)) {
|
|
2253
2230
|
throw new Error("Invalid element");
|
|
2254
2231
|
}
|
|
2255
2232
|
this.element = element;
|
|
@@ -2389,7 +2366,7 @@ class Popup extends Lifecycle {
|
|
|
2389
2366
|
PopupContainer: {
|
|
2390
2367
|
tag: {
|
|
2391
2368
|
node: "div",
|
|
2392
|
-
classList: "
|
|
2369
|
+
classList: "seui-popup",
|
|
2393
2370
|
style: { maxHeight: options.panelHeight },
|
|
2394
2371
|
},
|
|
2395
2372
|
child: {
|
|
@@ -2398,7 +2375,7 @@ class Popup extends Lifecycle {
|
|
|
2398
2375
|
tag: {
|
|
2399
2376
|
id: options.SEID_LIST,
|
|
2400
2377
|
node: "div",
|
|
2401
|
-
classList: "
|
|
2378
|
+
classList: "seui-options-container",
|
|
2402
2379
|
role: "listbox",
|
|
2403
2380
|
},
|
|
2404
2381
|
},
|
|
@@ -2682,10 +2659,8 @@ class Popup extends Lifecycle {
|
|
|
2682
2659
|
if (this.is(LifecycleState.DESTROYED)) {
|
|
2683
2660
|
return;
|
|
2684
2661
|
}
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
this.hideLoadHandle = null;
|
|
2688
|
-
}
|
|
2662
|
+
clearTimeout(this.hideLoadHandle);
|
|
2663
|
+
this.hideLoadHandle = null;
|
|
2689
2664
|
if (this.node && this.scrollListener) {
|
|
2690
2665
|
this.node.removeEventListener("scroll", this.scrollListener);
|
|
2691
2666
|
this.scrollListener = null;
|
|
@@ -2693,19 +2668,14 @@ class Popup extends Lifecycle {
|
|
|
2693
2668
|
this.emptyState.destroy();
|
|
2694
2669
|
this.loadingState.destroy();
|
|
2695
2670
|
this.optionHandle.destroy();
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
this.
|
|
2701
|
-
try {
|
|
2702
|
-
this.effSvc?.setElement?.(null);
|
|
2703
|
-
}
|
|
2704
|
-
catch (_) { }
|
|
2705
|
-
this.effSvc = null;
|
|
2671
|
+
this.resizeObser?.disconnect?.();
|
|
2672
|
+
this.effSvc?.setElement?.(null);
|
|
2673
|
+
this.modelManager?.skipEvent?.(false);
|
|
2674
|
+
this.recyclerView?.clear?.();
|
|
2675
|
+
this.node?.remove?.();
|
|
2706
2676
|
if (this.node) {
|
|
2707
2677
|
try {
|
|
2708
|
-
const clone = this.node
|
|
2678
|
+
const clone = Libs.nodeCloner(this.node);
|
|
2709
2679
|
this.node.replaceWith(clone);
|
|
2710
2680
|
clone.remove();
|
|
2711
2681
|
}
|
|
@@ -2715,15 +2685,6 @@ class Popup extends Lifecycle {
|
|
|
2715
2685
|
}
|
|
2716
2686
|
this.node = null;
|
|
2717
2687
|
this.optionsContainer = null;
|
|
2718
|
-
try {
|
|
2719
|
-
this.modelManager?.skipEvent?.(false);
|
|
2720
|
-
this.recyclerView?.clear?.();
|
|
2721
|
-
this.recyclerView = null;
|
|
2722
|
-
this.optionAdapter = null;
|
|
2723
|
-
// Original behavior kept intentionally.
|
|
2724
|
-
this.node.remove();
|
|
2725
|
-
}
|
|
2726
|
-
catch (_) { }
|
|
2727
2688
|
this.modelManager = null;
|
|
2728
2689
|
this.optionHandle = null;
|
|
2729
2690
|
this.emptyState = null;
|
|
@@ -2731,6 +2692,10 @@ class Popup extends Lifecycle {
|
|
|
2731
2692
|
this.parent = null;
|
|
2732
2693
|
this.options = null;
|
|
2733
2694
|
this.isCreated = false;
|
|
2695
|
+
this.effSvc = null;
|
|
2696
|
+
this.resizeObser = null;
|
|
2697
|
+
this.recyclerView = null;
|
|
2698
|
+
this.optionAdapter = null;
|
|
2734
2699
|
super.destroy();
|
|
2735
2700
|
}
|
|
2736
2701
|
/**
|
|
@@ -2964,8 +2929,8 @@ class SearchBox extends Lifecycle {
|
|
|
2964
2929
|
* Initializes DOM, ARIA attributes, and interaction listeners.
|
|
2965
2930
|
*
|
|
2966
2931
|
* DOM structure (conceptually):
|
|
2967
|
-
* - Root: `div.
|
|
2968
|
-
* - Child: `input[type="search"].
|
|
2932
|
+
* - Root: `div.seui-searchbox.hide`
|
|
2933
|
+
* - Child: `input[type="search"].seui-searchbox-input`
|
|
2969
2934
|
*
|
|
2970
2935
|
* Accessibility attributes set on the input:
|
|
2971
2936
|
* - `role="searchbox"`: announces search field semantics
|
|
@@ -2995,14 +2960,14 @@ class SearchBox extends Lifecycle {
|
|
|
2995
2960
|
initialize(options) {
|
|
2996
2961
|
this.nodeMounted = Libs.mountNode({
|
|
2997
2962
|
SearchBox: {
|
|
2998
|
-
tag: { node: "div", classList: ["
|
|
2963
|
+
tag: { node: "div", classList: ["seui-searchbox", "hide"] },
|
|
2999
2964
|
child: {
|
|
3000
2965
|
SearchInput: {
|
|
3001
2966
|
tag: {
|
|
3002
2967
|
id: Libs.randomString(),
|
|
3003
2968
|
node: "input",
|
|
3004
2969
|
type: "search",
|
|
3005
|
-
classList: ["
|
|
2970
|
+
classList: ["seui-searchbox-input"],
|
|
3006
2971
|
placeholder: options.placeholder,
|
|
3007
2972
|
role: "searchbox",
|
|
3008
2973
|
ariaControls: options.SEID_LIST,
|
|
@@ -4190,15 +4155,17 @@ class OptionModel extends Model {
|
|
|
4190
4155
|
set selectedNonTrigger(value) {
|
|
4191
4156
|
const input = this.view?.view?.tags?.OptionInput;
|
|
4192
4157
|
const viewEl = this.view?.getView?.();
|
|
4193
|
-
if (input)
|
|
4158
|
+
if (input) {
|
|
4194
4159
|
input.checked = value;
|
|
4160
|
+
}
|
|
4195
4161
|
if (viewEl && this.targetElement) {
|
|
4196
4162
|
viewEl.classList.toggle("checked", !!value);
|
|
4197
4163
|
viewEl.setAttribute("aria-selected", value ? "true" : "false");
|
|
4198
4164
|
this.targetElement.toggleAttribute("selected", !!value);
|
|
4199
4165
|
}
|
|
4200
|
-
if (this.targetElement)
|
|
4166
|
+
if (this.targetElement) {
|
|
4201
4167
|
this.targetElement.selected = value;
|
|
4168
|
+
}
|
|
4202
4169
|
iEvents.callEvent([this, value], ...this.privOnInternalSelected);
|
|
4203
4170
|
}
|
|
4204
4171
|
/**
|
|
@@ -4322,8 +4289,12 @@ class OptionModel extends Model {
|
|
|
4322
4289
|
}
|
|
4323
4290
|
const imageTag = this.view.view.tags.OptionImage;
|
|
4324
4291
|
if (imageTag && this.hasImage) {
|
|
4325
|
-
imageTag.src
|
|
4326
|
-
|
|
4292
|
+
if (imageTag.src != this.imageSrc) {
|
|
4293
|
+
imageTag.src = this.imageSrc;
|
|
4294
|
+
}
|
|
4295
|
+
if (imageTag.alt != this.text) {
|
|
4296
|
+
imageTag.alt = this.text;
|
|
4297
|
+
}
|
|
4327
4298
|
}
|
|
4328
4299
|
if (this.targetElement)
|
|
4329
4300
|
this.selectedNonTrigger = this.targetElement.selected;
|
|
@@ -4455,9 +4426,8 @@ class ModelManager extends Lifecycle {
|
|
|
4455
4426
|
this.privModelList.push(currentGroup);
|
|
4456
4427
|
}
|
|
4457
4428
|
else if (data.tagName === "OPTION") {
|
|
4458
|
-
const
|
|
4459
|
-
const
|
|
4460
|
-
const parentGroup = optionEl["__parentGroup"];
|
|
4429
|
+
const optionModel = new OptionModel(this.options, data);
|
|
4430
|
+
const parentGroup = data["__parentGroup"];
|
|
4461
4431
|
if (parentGroup && currentGroup && parentGroup === currentGroup.targetElement) {
|
|
4462
4432
|
currentGroup.addItem(optionModel);
|
|
4463
4433
|
optionModel.group = currentGroup;
|
|
@@ -4868,7 +4838,7 @@ class RecyclerView extends Lifecycle {
|
|
|
4868
4838
|
* popup/layout logic to recompute geometry.
|
|
4869
4839
|
*
|
|
4870
4840
|
* ### DOM & a11y side effects
|
|
4871
|
-
* - Creates a root `<div>` with classes `
|
|
4841
|
+
* - Creates a root `<div>` with classes `seui-accessorybox hide`.
|
|
4872
4842
|
* - Stops `mouseup` propagation on the root to avoid "outside click" behaviors.
|
|
4873
4843
|
* - Each chip has:
|
|
4874
4844
|
* - a `<span role="button">` with `aria-label`/`title` for screen readers and tooltips,
|
|
@@ -4948,7 +4918,7 @@ class AccessoryBox extends Lifecycle {
|
|
|
4948
4918
|
* Guarded: runs only when state is `NEW`.
|
|
4949
4919
|
*
|
|
4950
4920
|
* Side effects:
|
|
4951
|
-
* - Creates the root node with base classes (`
|
|
4921
|
+
* - Creates the root node with base classes (`seui-accessorybox`, `hide`).
|
|
4952
4922
|
* - Stops `mouseup` propagation to avoid outside-click handlers reacting to chip interactions.
|
|
4953
4923
|
*
|
|
4954
4924
|
* @returns {void}
|
|
@@ -4961,7 +4931,7 @@ class AccessoryBox extends Lifecycle {
|
|
|
4961
4931
|
AccessoryBox: {
|
|
4962
4932
|
tag: {
|
|
4963
4933
|
node: "div",
|
|
4964
|
-
classList: ["
|
|
4934
|
+
classList: ["seui-accessorybox", "hide"],
|
|
4965
4935
|
onmouseup: (evt) => {
|
|
4966
4936
|
// Prevent outside listeners from reacting to chip clicks
|
|
4967
4937
|
evt.stopPropagation();
|
|
@@ -5028,7 +4998,7 @@ class AccessoryBox extends Lifecycle {
|
|
|
5028
4998
|
/**
|
|
5029
4999
|
* Assigns the {@link ModelManager} used to run selection pipelines and mutate selection state.
|
|
5030
5000
|
*
|
|
5031
|
-
* @param {ModelManager<MixedItem, MixedAdapter>
|
|
5001
|
+
* @param {ModelManager<MixedItem, MixedAdapter>} modelManager - Model manager controlling option state.
|
|
5032
5002
|
* @returns {void}
|
|
5033
5003
|
*/
|
|
5034
5004
|
setModelManager(modelManager) {
|
|
@@ -6515,7 +6485,7 @@ class GroupView extends View {
|
|
|
6515
6485
|
*
|
|
6516
6486
|
* Creation flow:
|
|
6517
6487
|
* 1. Generates unique group ID (7-character random string).
|
|
6518
|
-
* 2. Creates DOM structure via {@link Libs.
|
|
6488
|
+
* 2. Creates DOM structure via {@link Libs.mountNode}:
|
|
6519
6489
|
* - Root: `<div role="group" aria-labelledby="seui-{id}-header">`
|
|
6520
6490
|
* - Header: `<div role="presentation" id="seui-{id}-header">`
|
|
6521
6491
|
* - Items: `<div role="group">` (nested group for child items)
|
|
@@ -6537,11 +6507,11 @@ class GroupView extends View {
|
|
|
6537
6507
|
*/
|
|
6538
6508
|
mount() {
|
|
6539
6509
|
const group_id = Libs.randomString(7);
|
|
6540
|
-
this.view = Libs.
|
|
6510
|
+
this.view = Libs.mountNode({
|
|
6541
6511
|
GroupView: {
|
|
6542
6512
|
tag: {
|
|
6543
6513
|
node: "div",
|
|
6544
|
-
classList: ["
|
|
6514
|
+
classList: ["seui-group"],
|
|
6545
6515
|
role: "group",
|
|
6546
6516
|
ariaLabelledby: `seui-${group_id}-header`,
|
|
6547
6517
|
id: `seui-${group_id}-group`,
|
|
@@ -6550,7 +6520,7 @@ class GroupView extends View {
|
|
|
6550
6520
|
GroupHeader: {
|
|
6551
6521
|
tag: {
|
|
6552
6522
|
node: "div",
|
|
6553
|
-
classList: ["
|
|
6523
|
+
classList: ["seui-group-header"],
|
|
6554
6524
|
role: "presentation",
|
|
6555
6525
|
id: `seui-${group_id}-header`,
|
|
6556
6526
|
},
|
|
@@ -6558,7 +6528,7 @@ class GroupView extends View {
|
|
|
6558
6528
|
GroupItems: {
|
|
6559
6529
|
tag: {
|
|
6560
6530
|
node: "div",
|
|
6561
|
-
classList: ["
|
|
6531
|
+
classList: ["seui-group-items"],
|
|
6562
6532
|
role: "group",
|
|
6563
6533
|
},
|
|
6564
6534
|
},
|
|
@@ -7003,7 +6973,7 @@ class OptionView extends View {
|
|
|
7003
6973
|
* - **OptionImage** (conditional): `<img>` with inline styles (width/height/borderRadius).
|
|
7004
6974
|
* - **OptionLabel**: `<label htmlFor="{inputID}">` with alignment classes.
|
|
7005
6975
|
* - **LabelContent**: `<div>` (content placeholder).
|
|
7006
|
-
* 4. Creates DOM via {@link Libs.
|
|
6976
|
+
* 4. Creates DOM via {@link Libs.mountNode}.
|
|
7007
6977
|
* 5. Appends root to {@link parent}.
|
|
7008
6978
|
* 6. Sets {@link isRendered} to `true` (enables reactive updates).
|
|
7009
6979
|
* 7. Transitions `INITIALIZED → MOUNTED` via `super.mount()`.
|
|
@@ -7021,7 +6991,7 @@ class OptionView extends View {
|
|
|
7021
6991
|
* @override
|
|
7022
6992
|
*/
|
|
7023
6993
|
mount() {
|
|
7024
|
-
const viewClass = ["
|
|
6994
|
+
const viewClass = ["seui-option-view"];
|
|
7025
6995
|
const opt_id = Libs.randomString(7);
|
|
7026
6996
|
const inputID = `option_${opt_id}`;
|
|
7027
6997
|
if (this.config.isMultiple)
|
|
@@ -7065,7 +7035,7 @@ class OptionView extends View {
|
|
|
7065
7035
|
},
|
|
7066
7036
|
},
|
|
7067
7037
|
};
|
|
7068
|
-
this.view = Libs.
|
|
7038
|
+
this.view = Libs.mountNode({
|
|
7069
7039
|
OptionView: {
|
|
7070
7040
|
tag: {
|
|
7071
7041
|
node: "div",
|
|
@@ -8113,15 +8083,15 @@ class VirtualRecyclerView extends RecyclerView {
|
|
|
8113
8083
|
return;
|
|
8114
8084
|
this.viewElement.replaceChildren();
|
|
8115
8085
|
const nodeMounted = Libs.mountNode({
|
|
8116
|
-
PadTop: { tag: { node: "div", classList: "
|
|
8117
|
-
ItemsHost: { tag: { node: "div", classList: "
|
|
8118
|
-
PadBottom: { tag: { node: "div", classList: "
|
|
8086
|
+
PadTop: { tag: { node: "div", classList: "seui-virtual-pad-top" } },
|
|
8087
|
+
ItemsHost: { tag: { node: "div", classList: "seui-virtual-items" } },
|
|
8088
|
+
PadBottom: { tag: { node: "div", classList: "seui-virtual-pad-bottom" } },
|
|
8119
8089
|
}, this.viewElement);
|
|
8120
8090
|
this.PadTop = nodeMounted.PadTop;
|
|
8121
8091
|
this.ItemsHost = nodeMounted.ItemsHost;
|
|
8122
8092
|
this.PadBottom = nodeMounted.PadBottom;
|
|
8123
8093
|
this.scrollEl = this.opts.scrollEl
|
|
8124
|
-
?? this.viewElement.closest(".
|
|
8094
|
+
?? this.viewElement.closest(".seui-popup")
|
|
8125
8095
|
?? this.viewElement.parentElement;
|
|
8126
8096
|
if (!this.scrollEl)
|
|
8127
8097
|
throw new Error("VirtualRecyclerView: scrollEl not found");
|
|
@@ -8450,7 +8420,7 @@ class VirtualRecyclerView extends RecyclerView {
|
|
|
8450
8420
|
const now = performance.now();
|
|
8451
8421
|
if (now - this.stickyCacheTick < 16)
|
|
8452
8422
|
return this.stickyCacheVal;
|
|
8453
|
-
const sticky = this.scrollEl.querySelector(".
|
|
8423
|
+
const sticky = this.scrollEl.querySelector(".seui-option-handle:not(.hide)");
|
|
8454
8424
|
this.stickyCacheVal = sticky?.offsetHeight ?? 0;
|
|
8455
8425
|
this.stickyCacheTick = now;
|
|
8456
8426
|
return this.stickyCacheVal;
|
|
@@ -9013,12 +8983,29 @@ class SelectBox extends Lifecycle {
|
|
|
9013
8983
|
* @internal
|
|
9014
8984
|
*/
|
|
9015
8985
|
this.isBeforeSearch = false;
|
|
8986
|
+
/**
|
|
8987
|
+
* Tracks whether {@link deInit} has already run.
|
|
8988
|
+
*
|
|
8989
|
+
* This guards teardown work (including plugin lifecycle hooks) from running more than once
|
|
8990
|
+
* when {@link deInit} is called separately before {@link destroy}.
|
|
8991
|
+
*
|
|
8992
|
+
* @internal
|
|
8993
|
+
*/
|
|
8994
|
+
this.hasDeInitialized = false;
|
|
9016
8995
|
/**
|
|
9017
8996
|
* Selective context (global helper / registry).
|
|
9018
8997
|
*
|
|
9019
8998
|
* Used to locate the instance wrapper via `Selective.find(...)` and to close other open instances.
|
|
9020
8999
|
*/
|
|
9021
9000
|
this.Selective = null;
|
|
9001
|
+
/**
|
|
9002
|
+
* Registered plugins for this SelectBox instance.
|
|
9003
|
+
*/
|
|
9004
|
+
this.plugins = [];
|
|
9005
|
+
/**
|
|
9006
|
+
* Cached plugin context for this SelectBox instance.
|
|
9007
|
+
*/
|
|
9008
|
+
this.pluginContext = null;
|
|
9022
9009
|
if (select && Selective)
|
|
9023
9010
|
this.initialize(select, Selective);
|
|
9024
9011
|
}
|
|
@@ -9135,12 +9122,12 @@ class SelectBox extends Lifecycle {
|
|
|
9135
9122
|
placeholder.node.id = String(options.SEID_HOLDER ?? "");
|
|
9136
9123
|
const container = Libs.mountNode({
|
|
9137
9124
|
Container: {
|
|
9138
|
-
tag: { node: "div", classList: "
|
|
9125
|
+
tag: { node: "div", classList: "seui-MAIN" },
|
|
9139
9126
|
child: {
|
|
9140
9127
|
ViewPanel: {
|
|
9141
9128
|
tag: {
|
|
9142
9129
|
node: "div",
|
|
9143
|
-
classList: "
|
|
9130
|
+
classList: "seui-view",
|
|
9144
9131
|
tabIndex: 0,
|
|
9145
9132
|
onkeydown: (e) => {
|
|
9146
9133
|
if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
|
|
@@ -9200,6 +9187,20 @@ class SelectBox extends Lifecycle {
|
|
|
9200
9187
|
accessoryBox.setModelManager(optionModelManager);
|
|
9201
9188
|
this.setupEventHandlers(select, container, options, searchController, searchbox);
|
|
9202
9189
|
this.setupObservers(selectObserver, datasetObserver, select, optionModelManager);
|
|
9190
|
+
this.plugins = this.Selective?.getPlugins?.() ?? [];
|
|
9191
|
+
if (this.plugins.length) {
|
|
9192
|
+
const resources = optionModelManager.getResources();
|
|
9193
|
+
const pluginContext = {
|
|
9194
|
+
selectBox: this,
|
|
9195
|
+
options,
|
|
9196
|
+
adapter: resources.adapter,
|
|
9197
|
+
recycler: resources.recyclerView,
|
|
9198
|
+
viewTags: container.tags,
|
|
9199
|
+
actions: this.getAction(),
|
|
9200
|
+
};
|
|
9201
|
+
this.pluginContext = pluginContext;
|
|
9202
|
+
this.runPluginHook("init", (plugin) => plugin.init?.(pluginContext));
|
|
9203
|
+
}
|
|
9203
9204
|
// Initial states
|
|
9204
9205
|
this.isDisabled = Libs.string2Boolean(options.disabled);
|
|
9205
9206
|
this.isReadOnly = Libs.string2Boolean(options.readonly);
|
|
@@ -9397,12 +9398,21 @@ class SelectBox extends Lifecycle {
|
|
|
9397
9398
|
* preventing memory leaks and unintended background updates.
|
|
9398
9399
|
*/
|
|
9399
9400
|
deInit() {
|
|
9401
|
+
if (this.hasDeInitialized) {
|
|
9402
|
+
return;
|
|
9403
|
+
}
|
|
9400
9404
|
const c = this.container ?? {};
|
|
9401
9405
|
const { selectObserver, datasetObserver } = c;
|
|
9406
|
+
if (this.plugins.length) {
|
|
9407
|
+
this.runPluginHook("destroy", (plugin) => plugin.destroy?.());
|
|
9408
|
+
}
|
|
9409
|
+
this.plugins = [];
|
|
9410
|
+
this.pluginContext = null;
|
|
9402
9411
|
if (selectObserver?.disconnect)
|
|
9403
9412
|
selectObserver.disconnect();
|
|
9404
9413
|
if (datasetObserver?.disconnect)
|
|
9405
9414
|
datasetObserver.disconnect();
|
|
9415
|
+
this.hasDeInitialized = true;
|
|
9406
9416
|
}
|
|
9407
9417
|
/**
|
|
9408
9418
|
* Lifecycle: `destroy` (teardown stage).
|
|
@@ -9716,6 +9726,9 @@ class SelectBox extends Lifecycle {
|
|
|
9716
9726
|
if (bindedOptions.multiple)
|
|
9717
9727
|
ViewPanel.setAttribute("aria-multiselectable", "true");
|
|
9718
9728
|
iEvents.callEvent([getInstance()], ...bindedOptions.on.show);
|
|
9729
|
+
if (superThis.pluginContext) {
|
|
9730
|
+
superThis.runPluginHook("onOpen", (plugin) => plugin.onOpen?.(superThis.pluginContext));
|
|
9731
|
+
}
|
|
9719
9732
|
return;
|
|
9720
9733
|
},
|
|
9721
9734
|
close() {
|
|
@@ -9732,6 +9745,9 @@ class SelectBox extends Lifecycle {
|
|
|
9732
9745
|
container.searchbox.hide();
|
|
9733
9746
|
container.tags.ViewPanel.setAttribute("aria-expanded", "false");
|
|
9734
9747
|
iEvents.callEvent([getInstance()], ...bindedOptions.on.close);
|
|
9748
|
+
if (superThis.pluginContext) {
|
|
9749
|
+
superThis.runPluginHook("onClose", (plugin) => plugin.onClose?.(superThis.pluginContext));
|
|
9750
|
+
}
|
|
9735
9751
|
return;
|
|
9736
9752
|
},
|
|
9737
9753
|
toggle() {
|
|
@@ -9770,6 +9786,10 @@ class SelectBox extends Lifecycle {
|
|
|
9770
9786
|
if (superThis.is(LifecycleState.MOUNTED)) {
|
|
9771
9787
|
superThis.update();
|
|
9772
9788
|
}
|
|
9789
|
+
if (superThis.pluginContext && superThis.optionModelManager) {
|
|
9790
|
+
const resources = superThis.optionModelManager.getResources();
|
|
9791
|
+
superThis.runPluginHook("onChange", (plugin) => plugin.onChange?.(this.value, resources.modelList, resources.adapter, superThis.pluginContext));
|
|
9792
|
+
}
|
|
9773
9793
|
},
|
|
9774
9794
|
refreshMask() {
|
|
9775
9795
|
let mask = bindedOptions.placeholder;
|
|
@@ -9902,6 +9922,27 @@ class SelectBox extends Lifecycle {
|
|
|
9902
9922
|
}
|
|
9903
9923
|
return flatOptions;
|
|
9904
9924
|
}
|
|
9925
|
+
/**
|
|
9926
|
+
* Safely runs a hook across all registered plugins.
|
|
9927
|
+
*
|
|
9928
|
+
* Any plugin failure is isolated to prevent breaking the current flow.
|
|
9929
|
+
*
|
|
9930
|
+
* @param hook - Hook name for logging context.
|
|
9931
|
+
* @param runner - Hook invocation handler.
|
|
9932
|
+
* @internal
|
|
9933
|
+
*/
|
|
9934
|
+
runPluginHook(hook, runner) {
|
|
9935
|
+
if (!this.plugins.length)
|
|
9936
|
+
return;
|
|
9937
|
+
this.plugins.forEach((plugin) => {
|
|
9938
|
+
try {
|
|
9939
|
+
runner(plugin);
|
|
9940
|
+
}
|
|
9941
|
+
catch (error) {
|
|
9942
|
+
console.error(`Plugin "${plugin.id}" ${hook} error:`, error);
|
|
9943
|
+
}
|
|
9944
|
+
});
|
|
9945
|
+
}
|
|
9905
9946
|
}
|
|
9906
9947
|
|
|
9907
9948
|
/**
|
|
@@ -10128,6 +10169,15 @@ class Selective extends Lifecycle {
|
|
|
10128
10169
|
* @private
|
|
10129
10170
|
*/
|
|
10130
10171
|
this.bindedQueries = new Map();
|
|
10172
|
+
/**
|
|
10173
|
+
* Registry of Selective plugins keyed by plugin ID.
|
|
10174
|
+
*
|
|
10175
|
+
* - Managed via {@link registerPlugin}, {@link unregisterPlugin}, and {@link getPlugin}.
|
|
10176
|
+
* - Cleared during {@link destroyAll} after invoking plugin teardown hooks.
|
|
10177
|
+
*
|
|
10178
|
+
* @private
|
|
10179
|
+
*/
|
|
10180
|
+
this.plugins = new Map();
|
|
10131
10181
|
this.init();
|
|
10132
10182
|
}
|
|
10133
10183
|
/**
|
|
@@ -10136,6 +10186,7 @@ class Selective extends Lifecycle {
|
|
|
10136
10186
|
* Behavior:
|
|
10137
10187
|
* - No-op if not in {@link LifecycleState.NEW} (idempotent guard).
|
|
10138
10188
|
* - Initializes {@link bindedQueries} as empty `Map`.
|
|
10189
|
+
* - Initializes {@link plugins} as empty `Map`.
|
|
10139
10190
|
* - Transitions `NEW → INITIALIZED` via `super.init()`.
|
|
10140
10191
|
*
|
|
10141
10192
|
* Notes:
|
|
@@ -10151,6 +10202,7 @@ class Selective extends Lifecycle {
|
|
|
10151
10202
|
return;
|
|
10152
10203
|
// Initialize core properties
|
|
10153
10204
|
this.bindedQueries = new Map();
|
|
10205
|
+
this.plugins = new Map();
|
|
10154
10206
|
super.init();
|
|
10155
10207
|
}
|
|
10156
10208
|
/**
|
|
@@ -10318,6 +10370,14 @@ class Selective extends Lifecycle {
|
|
|
10318
10370
|
}
|
|
10319
10371
|
return response;
|
|
10320
10372
|
}
|
|
10373
|
+
/**
|
|
10374
|
+
* Returns all registered Selective plugins.
|
|
10375
|
+
*
|
|
10376
|
+
* @returns The list of plugins in registration order.
|
|
10377
|
+
*/
|
|
10378
|
+
getPlugins() {
|
|
10379
|
+
return Array.from(this.plugins.values());
|
|
10380
|
+
}
|
|
10321
10381
|
/**
|
|
10322
10382
|
* Activates auto-binding for newly added `<select>` elements.
|
|
10323
10383
|
*
|
|
@@ -10389,14 +10449,51 @@ class Selective extends Lifecycle {
|
|
|
10389
10449
|
this.update();
|
|
10390
10450
|
}
|
|
10391
10451
|
}
|
|
10452
|
+
/**
|
|
10453
|
+
* Registers a plugin for Selective lifecycle integration.
|
|
10454
|
+
*
|
|
10455
|
+
* @public
|
|
10456
|
+
* @param {SelectivePlugin} plugin - Plugin instance to register.
|
|
10457
|
+
* @returns {void}
|
|
10458
|
+
*/
|
|
10459
|
+
registerPlugin(plugin) {
|
|
10460
|
+
if (!plugin?.id)
|
|
10461
|
+
return;
|
|
10462
|
+
this.plugins.set(plugin.id, plugin);
|
|
10463
|
+
}
|
|
10464
|
+
/**
|
|
10465
|
+
* Unregisters a plugin by ID.
|
|
10466
|
+
*
|
|
10467
|
+
* @public
|
|
10468
|
+
* @param {string} id - Plugin ID to remove.
|
|
10469
|
+
* @returns {void}
|
|
10470
|
+
*/
|
|
10471
|
+
unregisterPlugin(id) {
|
|
10472
|
+
if (!id)
|
|
10473
|
+
return;
|
|
10474
|
+
this.plugins.delete(id);
|
|
10475
|
+
}
|
|
10476
|
+
/**
|
|
10477
|
+
* Retrieves a plugin by ID.
|
|
10478
|
+
*
|
|
10479
|
+
* @public
|
|
10480
|
+
* @param {string} id - Plugin ID to retrieve.
|
|
10481
|
+
* @returns {SelectivePlugin | undefined} Plugin instance if found.
|
|
10482
|
+
*/
|
|
10483
|
+
getPlugin(id) {
|
|
10484
|
+
if (!id)
|
|
10485
|
+
return undefined;
|
|
10486
|
+
return this.plugins.get(id);
|
|
10487
|
+
}
|
|
10392
10488
|
/**
|
|
10393
10489
|
* Destroys all bound Selective instances and releases global resources.
|
|
10394
10490
|
*
|
|
10395
10491
|
* Teardown flow:
|
|
10396
10492
|
* 1. Iterates all registered queries and calls {@link destroyByQuery}.
|
|
10397
10493
|
* 2. Clears {@link bindedQueries} and {@link Libs.getBindedCommand}.
|
|
10398
|
-
* 3.
|
|
10399
|
-
* 4.
|
|
10494
|
+
* 3. Invokes plugin teardown hooks and clears {@link plugins}.
|
|
10495
|
+
* 4. Disconnects {@link EAObserver} (stops auto-binding).
|
|
10496
|
+
* 5. Transitions to {@link LifecycleState.DESTROYED} via `super.destroy()`.
|
|
10400
10497
|
*
|
|
10401
10498
|
* Idempotency:
|
|
10402
10499
|
* - No-op if already {@link LifecycleState.DESTROYED}.
|
|
@@ -10411,7 +10508,13 @@ class Selective extends Lifecycle {
|
|
|
10411
10508
|
bindedCommands.forEach((query) => this.destroyByQuery(query));
|
|
10412
10509
|
this.bindedQueries.clear();
|
|
10413
10510
|
Libs.getBindedCommand().length = 0;
|
|
10511
|
+
this.plugins.forEach((plugin) => {
|
|
10512
|
+
plugin.destroy?.();
|
|
10513
|
+
plugin.onDestroy?.();
|
|
10514
|
+
});
|
|
10515
|
+
this.plugins.clear();
|
|
10414
10516
|
this.EAObserver?.disconnect();
|
|
10517
|
+
this.plugins.clear();
|
|
10415
10518
|
// Call parent lifecycle destroy
|
|
10416
10519
|
super.destroy();
|
|
10417
10520
|
}
|
|
@@ -10478,12 +10581,8 @@ class Selective extends Lifecycle {
|
|
|
10478
10581
|
const wasObserving = !!this.EAObserver;
|
|
10479
10582
|
if (wasObserving)
|
|
10480
10583
|
this.EAObserver?.disconnect();
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
}
|
|
10484
|
-
catch (_) { }
|
|
10485
|
-
const wrapper = bindMap.container?.element ??
|
|
10486
|
-
selectElement.parentElement;
|
|
10584
|
+
bindMap.self?.deInit?.();
|
|
10585
|
+
const wrapper = (bindMap.container?.element) ?? selectElement.parentElement;
|
|
10487
10586
|
selectElement.style.display = "";
|
|
10488
10587
|
selectElement.style.visibility = "";
|
|
10489
10588
|
selectElement.disabled = false;
|
|
@@ -10703,7 +10802,7 @@ const SECLASS = new Selective();
|
|
|
10703
10802
|
*
|
|
10704
10803
|
* Declared as `const` literal type to enable strict typing and easy tree-shaking.
|
|
10705
10804
|
*/
|
|
10706
|
-
const version = "1.2.
|
|
10805
|
+
const version = "1.2.6";
|
|
10707
10806
|
/**
|
|
10708
10807
|
* Library name identifier.
|
|
10709
10808
|
*
|
|
@@ -10782,6 +10881,22 @@ function rebind(query, options = {}) {
|
|
|
10782
10881
|
function effector(element) {
|
|
10783
10882
|
return Effector(element);
|
|
10784
10883
|
}
|
|
10884
|
+
/**
|
|
10885
|
+
* Register a Selective plugin globally.
|
|
10886
|
+
*
|
|
10887
|
+
* @param plugin - Plugin to register.
|
|
10888
|
+
*/
|
|
10889
|
+
function registerPlugin(plugin) {
|
|
10890
|
+
SECLASS.registerPlugin(plugin);
|
|
10891
|
+
}
|
|
10892
|
+
/**
|
|
10893
|
+
* Unregister a Selective plugin by id.
|
|
10894
|
+
*
|
|
10895
|
+
* @param id - Plugin id.
|
|
10896
|
+
*/
|
|
10897
|
+
function unregisterPlugin(id) {
|
|
10898
|
+
SECLASS.unregisterPlugin(id);
|
|
10899
|
+
}
|
|
10785
10900
|
let domInitialized = false;
|
|
10786
10901
|
function init() {
|
|
10787
10902
|
if (domInitialized)
|
|
@@ -10806,5 +10921,5 @@ if (typeof document !== "undefined") {
|
|
|
10806
10921
|
}
|
|
10807
10922
|
}
|
|
10808
10923
|
|
|
10809
|
-
export { bind, destroy, effector, find, name, rebind, version };
|
|
10924
|
+
export { bind, destroy, effector, find, name, rebind, registerPlugin, unregisterPlugin, version };
|
|
10810
10925
|
//# sourceMappingURL=selective-ui.esm.js.map
|