selective-ui 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +7 -2
  3. package/dist/selective-ui.css +567 -567
  4. package/dist/selective-ui.css.map +1 -1
  5. package/dist/selective-ui.esm.js +6046 -6046
  6. package/dist/selective-ui.esm.js.map +1 -1
  7. package/dist/selective-ui.esm.min.js +1 -1
  8. package/dist/selective-ui.esm.min.js.br +0 -0
  9. package/dist/selective-ui.min.js +1 -1
  10. package/dist/selective-ui.min.js.br +0 -0
  11. package/dist/selective-ui.umd.js +6046 -6046
  12. package/dist/selective-ui.umd.js.map +1 -1
  13. package/package.json +68 -68
  14. package/src/css/components/accessorybox.css +63 -63
  15. package/src/css/components/directive.css +19 -19
  16. package/src/css/components/empty-state.css +25 -25
  17. package/src/css/components/loading-state.css +25 -25
  18. package/src/css/components/optgroup.css +61 -61
  19. package/src/css/components/option-handle.css +33 -33
  20. package/src/css/components/option.css +129 -129
  21. package/src/css/components/placeholder.css +14 -14
  22. package/src/css/components/popup.css +38 -38
  23. package/src/css/components/searchbox.css +28 -28
  24. package/src/css/components/selectbox.css +53 -53
  25. package/src/css/index.css +74 -74
  26. package/src/js/adapter/mixed-adapter.js +434 -434
  27. package/src/js/components/accessorybox.js +124 -124
  28. package/src/js/components/directive.js +37 -37
  29. package/src/js/components/empty-state.js +67 -67
  30. package/src/js/components/loading-state.js +59 -59
  31. package/src/js/components/option-handle.js +113 -113
  32. package/src/js/components/placeholder.js +56 -56
  33. package/src/js/components/popup.js +470 -470
  34. package/src/js/components/searchbox.js +167 -167
  35. package/src/js/components/selectbox.js +692 -692
  36. package/src/js/core/base/adapter.js +162 -162
  37. package/src/js/core/base/model.js +59 -59
  38. package/src/js/core/base/recyclerview.js +82 -82
  39. package/src/js/core/base/view.js +62 -62
  40. package/src/js/core/model-manager.js +286 -286
  41. package/src/js/core/search-controller.js +521 -521
  42. package/src/js/index.js +136 -136
  43. package/src/js/models/group-model.js +142 -142
  44. package/src/js/models/option-model.js +236 -236
  45. package/src/js/services/dataset-observer.js +73 -73
  46. package/src/js/services/ea-observer.js +87 -87
  47. package/src/js/services/effector.js +403 -403
  48. package/src/js/services/refresher.js +39 -39
  49. package/src/js/services/resize-observer.js +151 -151
  50. package/src/js/services/select-observer.js +60 -60
  51. package/src/js/types/adapter.type.js +32 -32
  52. package/src/js/types/effector.type.js +23 -23
  53. package/src/js/types/ievents.type.js +10 -10
  54. package/src/js/types/libs.type.js +27 -27
  55. package/src/js/types/model.type.js +11 -11
  56. package/src/js/types/recyclerview.type.js +11 -11
  57. package/src/js/types/resize-observer.type.js +18 -18
  58. package/src/js/types/view.group.type.js +12 -12
  59. package/src/js/types/view.option.type.js +14 -14
  60. package/src/js/types/view.type.js +10 -10
  61. package/src/js/utils/guard.js +46 -46
  62. package/src/js/utils/ievents.js +83 -83
  63. package/src/js/utils/istorage.js +60 -60
  64. package/src/js/utils/libs.js +618 -618
  65. package/src/js/utils/selective.js +385 -385
  66. package/src/js/views/group-view.js +102 -102
  67. package/src/js/views/option-view.js +152 -152
package/src/js/index.js CHANGED
@@ -1,137 +1,137 @@
1
- import "../css/index.css";
2
- import "../css/components/selectbox.css";
3
- import "../css/components/placeholder.css";
4
- import "../css/components/directive.css";
5
- import "../css/components/empty-state.css";
6
- import "../css/components/loading-state.css";
7
- import "../css/components/optgroup.css";
8
- import "../css/components/popup.css";
9
- import "../css/components/searchbox.css";
10
- import "../css/components/option-handle.css";
11
- import "../css/components/option.css";
12
- import "../css/components/accessorybox.css";
13
-
14
- import "./types/adapter.type";
15
- import "./types/effector.type";
16
- import "./types/ievents.type";
17
- import "./types/libs.type";
18
- import "./types/model.type";
19
- import "./types/recyclerview.type";
20
- import "./types/resize-observer.type";
21
- import "./types/view.option.type";
22
- import "./types/view.type";
23
-
24
- import { Selective } from "./utils/selective";
25
- import { checkDuplicate, markLoaded } from "./utils/guard";
26
- import { Libs } from "./utils/libs";
27
- import { Effector } from "./services/effector";
28
-
29
- export const version = "1.0.2";
30
- export const name = "SelectiveUI";
31
-
32
- const alreadyLoaded = checkDuplicate(name);
33
-
34
- /**
35
- * Enhances all <select> elements matching the query with Selective UI.
36
- * If a prior global instance is already loaded, proxies the call to it; otherwise uses local Selective.bind.
37
- *
38
- * @param {string} query - CSS selector for target <select> elements.
39
- * @param {object} [options={}] - Configuration overrides merged with defaults.
40
- */
41
- export function bind(query, options = {}) {
42
- if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
43
- return window[name].bind(query, options);
44
- }
45
-
46
- Selective.bind(query, options);
47
- }
48
-
49
- /**
50
- * Retrieves the dynamic action API for bound instances matching the query.
51
- * Proxies to an already-loaded global instance if present; otherwise uses local Selective.find.
52
- *
53
- * @param {string} query - CSS selector identifying bound instances.
54
- * @returns {{isEmpty:boolean} & Record<string, unknown>} - Action API; {isEmpty:true} if none found.
55
- */
56
- export function find(query) {
57
- if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
58
- return window[name].find(query);
59
- }
60
-
61
- return Selective.find(query);
62
- }
63
-
64
- /**
65
- * Destroys Selective instances associated with the given query.
66
- * Proxies to a global loaded instance if available; otherwise uses local Selective.destroy.
67
- *
68
- * @param {string} query - CSS selector identifying instances to tear down.
69
- * @returns {void}
70
- */
71
- export function destroy(query) {
72
- if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
73
- return window[name].destroy(query);
74
- }
75
-
76
- return Selective.destroy(query);
77
- }
78
-
79
- /**
80
- * Rebinds Selective for the given query by destroying existing instances and binding anew.
81
- * Proxies to a global loaded instance if available; otherwise uses local Selective.rebind.
82
- *
83
- * @param {string} query - CSS selector for target <select> elements.
84
- * @param {object} [options={}] - Configuration overrides for the new binding.
85
- * @returns {void}
86
- */
87
- export function rebind(query, options = {}) {
88
- if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
89
- return window[name].rebind(query, options);
90
- }
91
-
92
- return Selective.rebind(query, options);
93
- }
94
-
95
- /**
96
- * Returns an effector instance for a given element, enabling expand/collapse/resize animations.
97
- * Proxies to a global loaded instance if available; otherwise constructs a local Effector.
98
- *
99
- * @param {string|HTMLElement} element - CSS selector or element to control.
100
- * @returns {EffectorInterface} - The effector utility bound to the element.
101
- */
102
- export function effector(element) {
103
- if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
104
- return window[name].effector(element);
105
- }
106
-
107
- return Effector(element);
108
- }
109
-
110
- if (!alreadyLoaded) {
111
- let initialized = false;
112
-
113
- function init() {
114
- if (initialized) return;
115
- initialized = true;
116
-
117
- document.addEventListener("mousedown", () => {
118
- const sels = Libs.getBindedCommand();
119
- if (sels.length > 0) {
120
- const optanObj = Selective.find(sels.join(", "));
121
- if (!optanObj.isEmpty) {
122
- optanObj.close();
123
- }
124
- }
125
- });
126
-
127
- Selective.Observer();
128
-
129
- markLoaded(name, version, { bind, find, destroy, rebind, effector, version });
130
- }
131
-
132
- if (document.readyState === "loading") {
133
- document.addEventListener("DOMContentLoaded", init);
134
- } else {
135
- init();
136
- }
1
+ import "../css/index.css";
2
+ import "../css/components/selectbox.css";
3
+ import "../css/components/placeholder.css";
4
+ import "../css/components/directive.css";
5
+ import "../css/components/empty-state.css";
6
+ import "../css/components/loading-state.css";
7
+ import "../css/components/optgroup.css";
8
+ import "../css/components/popup.css";
9
+ import "../css/components/searchbox.css";
10
+ import "../css/components/option-handle.css";
11
+ import "../css/components/option.css";
12
+ import "../css/components/accessorybox.css";
13
+
14
+ import "./types/adapter.type";
15
+ import "./types/effector.type";
16
+ import "./types/ievents.type";
17
+ import "./types/libs.type";
18
+ import "./types/model.type";
19
+ import "./types/recyclerview.type";
20
+ import "./types/resize-observer.type";
21
+ import "./types/view.option.type";
22
+ import "./types/view.type";
23
+
24
+ import { Selective } from "./utils/selective";
25
+ import { checkDuplicate, markLoaded } from "./utils/guard";
26
+ import { Libs } from "./utils/libs";
27
+ import { Effector } from "./services/effector";
28
+
29
+ export const version = "1.0.3";
30
+ export const name = "SelectiveUI";
31
+
32
+ const alreadyLoaded = checkDuplicate(name);
33
+
34
+ /**
35
+ * Enhances all <select> elements matching the query with Selective UI.
36
+ * If a prior global instance is already loaded, proxies the call to it; otherwise uses local Selective.bind.
37
+ *
38
+ * @param {string} query - CSS selector for target <select> elements.
39
+ * @param {object} [options={}] - Configuration overrides merged with defaults.
40
+ */
41
+ export function bind(query, options = {}) {
42
+ if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
43
+ return window[name].bind(query, options);
44
+ }
45
+
46
+ Selective.bind(query, options);
47
+ }
48
+
49
+ /**
50
+ * Retrieves the dynamic action API for bound instances matching the query.
51
+ * Proxies to an already-loaded global instance if present; otherwise uses local Selective.find.
52
+ *
53
+ * @param {string} query - CSS selector identifying bound instances.
54
+ * @returns {{isEmpty:boolean} & Record<string, unknown>} - Action API; {isEmpty:true} if none found.
55
+ */
56
+ export function find(query) {
57
+ if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
58
+ return window[name].find(query);
59
+ }
60
+
61
+ return Selective.find(query);
62
+ }
63
+
64
+ /**
65
+ * Destroys Selective instances associated with the given query.
66
+ * Proxies to a global loaded instance if available; otherwise uses local Selective.destroy.
67
+ *
68
+ * @param {string} query - CSS selector identifying instances to tear down.
69
+ * @returns {void}
70
+ */
71
+ export function destroy(query) {
72
+ if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
73
+ return window[name].destroy(query);
74
+ }
75
+
76
+ return Selective.destroy(query);
77
+ }
78
+
79
+ /**
80
+ * Rebinds Selective for the given query by destroying existing instances and binding anew.
81
+ * Proxies to a global loaded instance if available; otherwise uses local Selective.rebind.
82
+ *
83
+ * @param {string} query - CSS selector for target <select> elements.
84
+ * @param {object} [options={}] - Configuration overrides for the new binding.
85
+ * @returns {void}
86
+ */
87
+ export function rebind(query, options = {}) {
88
+ if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
89
+ return window[name].rebind(query, options);
90
+ }
91
+
92
+ return Selective.rebind(query, options);
93
+ }
94
+
95
+ /**
96
+ * Returns an effector instance for a given element, enabling expand/collapse/resize animations.
97
+ * Proxies to a global loaded instance if available; otherwise constructs a local Effector.
98
+ *
99
+ * @param {string|HTMLElement} element - CSS selector or element to control.
100
+ * @returns {EffectorInterface} - The effector utility bound to the element.
101
+ */
102
+ export function effector(element) {
103
+ if (alreadyLoaded && typeof window !== "undefined" && window[name]) {
104
+ return window[name].effector(element);
105
+ }
106
+
107
+ return Effector(element);
108
+ }
109
+
110
+ if (!alreadyLoaded) {
111
+ let initialized = false;
112
+
113
+ function init() {
114
+ if (initialized) return;
115
+ initialized = true;
116
+
117
+ document.addEventListener("mousedown", () => {
118
+ const sels = Libs.getBindedCommand();
119
+ if (sels.length > 0) {
120
+ const optanObj = Selective.find(sels.join(", "));
121
+ if (!optanObj.isEmpty) {
122
+ optanObj.close();
123
+ }
124
+ }
125
+ });
126
+
127
+ Selective.Observer();
128
+
129
+ markLoaded(name, version, { bind, find, destroy, rebind, effector, version });
130
+ }
131
+
132
+ if (document.readyState === "loading") {
133
+ document.addEventListener("DOMContentLoaded", init);
134
+ } else {
135
+ init();
136
+ }
137
137
  }
@@ -1,143 +1,143 @@
1
- import { Model } from "../core/base/model";
2
- import { iEvents } from "../utils/ievents";
3
- import { Libs } from "../utils/libs";
4
- import { GroupView } from "../views/group-view";
5
- import { OptionModel } from "./option-model";
6
-
7
- /**
8
- * @extends {Model<HTMLOptGroupElement, GroupViewTags, GroupView>}
9
- */
10
- export class GroupModel extends Model {
11
- label = "";
12
- /** @type {OptionModel[]} */
13
- items = [];
14
- collapsed = false;
15
- #privOnCollapsedChanged = [];
16
-
17
- /**
18
- * Initializes a group model with options and an optional <optgroup> target.
19
- * Reads the label and collapsed state from the target element's attributes/dataset.
20
- *
21
- * @param {object} options - Configuration for the model.
22
- * @param {HTMLOptGroupElement} [targetElement] - The source <optgroup> element.
23
- */
24
- constructor(options, targetElement) {
25
- super(options, targetElement);
26
- if (targetElement) {
27
- this.label = targetElement.label;
28
- this.collapsed = Libs.string2Boolean(targetElement.dataset?.collapsed);
29
- }
30
- }
31
-
32
- /**
33
- * Returns the array of values from all option items within the group.
34
- *
35
- * @type {String[]}
36
- */
37
- get value() {
38
- return this.items.map(item => item.value);
39
- }
40
-
41
- /**
42
- * Returns the list of option items currently selected within the group.
43
- *
44
- * @type {OptionModel[]}
45
- */
46
- get selectedItems() {
47
- return this.items.filter(item => item.selected);
48
- }
49
-
50
- /**
51
- * Returns the list of option items currently visible within the group.
52
- *
53
- * @type {OptionModel[]}
54
- */
55
- get visibleItems() {
56
- return this.items.filter(item => item.visible);
57
- }
58
-
59
- /**
60
- * Indicates whether the group has at least one visible option item.
61
- *
62
- * @type {boolean}
63
- */
64
- get hasVisibleItems() {
65
- return this.visibleItems.length > 0;
66
- }
67
-
68
- /**
69
- * Updates the group's label from the new target element and propagates the change to the view.
70
- *
71
- * @param {HTMLOptGroupElement} targetElement - The updated <optgroup> element.
72
- */
73
- update(targetElement) {
74
- this.label = targetElement.label;
75
- if (this.view) {
76
- this.view.updateLabel(this.label);
77
- }
78
- }
79
-
80
- /**
81
- * Hook invoked when the target element reference changes.
82
- * Updates the view's label and collapsed state to keep UI in sync.
83
- */
84
- onTargetChanged() {
85
- if (this.view) {
86
- this.view.updateLabel(this.label);
87
- this.view.setCollapsed(this.collapsed);
88
- }
89
- }
90
-
91
- /**
92
- * Registers a callback to be invoked when the group's collapsed state changes.
93
- *
94
- * @param {(evtToken: any, model: GroupModel, collapsed: boolean) => void} callback - Listener for collapse changes.
95
- */
96
- onCollapsedChanged(callback) {
97
- this.#privOnCollapsedChanged.push(callback);
98
- }
99
-
100
- /**
101
- * Toggles the group's collapsed state, updates the view, and notifies registered listeners.
102
- */
103
- toggleCollapse() {
104
- this.collapsed = !this.collapsed;
105
- if (this.view) {
106
- this.view.setCollapsed(this.collapsed);
107
- }
108
- iEvents.callEvent([this, this.collapsed], ...this.#privOnCollapsedChanged);
109
- }
110
-
111
- /**
112
- * Adds an option item to this group and sets its back-reference to the group.
113
- *
114
- * @param {OptionModel} optionModel - The option to add.
115
- */
116
- addItem(optionModel) {
117
- this.items.push(optionModel);
118
- optionModel.group = this;
119
- }
120
-
121
- /**
122
- * Removes an option item from this group and clears its group reference.
123
- *
124
- * @param {OptionModel} optionModel - The option to remove.
125
- */
126
- removeItem(optionModel) {
127
- const index = this.items.indexOf(optionModel);
128
- if (index > -1) {
129
- this.items.splice(index, 1);
130
- optionModel.group = null;
131
- }
132
- }
133
-
134
- /**
135
- * Updates the group's visibility in the view, typically based on children visibility.
136
- * No-ops if the view is not initialized.
137
- */
138
- updateVisibility() {
139
- if (this.view) {
140
- this.view.updateVisibility();
141
- }
142
- }
1
+ import { Model } from "../core/base/model";
2
+ import { iEvents } from "../utils/ievents";
3
+ import { Libs } from "../utils/libs";
4
+ import { GroupView } from "../views/group-view";
5
+ import { OptionModel } from "./option-model";
6
+
7
+ /**
8
+ * @extends {Model<HTMLOptGroupElement, GroupViewTags, GroupView>}
9
+ */
10
+ export class GroupModel extends Model {
11
+ label = "";
12
+ /** @type {OptionModel[]} */
13
+ items = [];
14
+ collapsed = false;
15
+ #privOnCollapsedChanged = [];
16
+
17
+ /**
18
+ * Initializes a group model with options and an optional <optgroup> target.
19
+ * Reads the label and collapsed state from the target element's attributes/dataset.
20
+ *
21
+ * @param {object} options - Configuration for the model.
22
+ * @param {HTMLOptGroupElement} [targetElement] - The source <optgroup> element.
23
+ */
24
+ constructor(options, targetElement) {
25
+ super(options, targetElement);
26
+ if (targetElement) {
27
+ this.label = targetElement.label;
28
+ this.collapsed = Libs.string2Boolean(targetElement.dataset?.collapsed);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Returns the array of values from all option items within the group.
34
+ *
35
+ * @type {String[]}
36
+ */
37
+ get value() {
38
+ return this.items.map(item => item.value);
39
+ }
40
+
41
+ /**
42
+ * Returns the list of option items currently selected within the group.
43
+ *
44
+ * @type {OptionModel[]}
45
+ */
46
+ get selectedItems() {
47
+ return this.items.filter(item => item.selected);
48
+ }
49
+
50
+ /**
51
+ * Returns the list of option items currently visible within the group.
52
+ *
53
+ * @type {OptionModel[]}
54
+ */
55
+ get visibleItems() {
56
+ return this.items.filter(item => item.visible);
57
+ }
58
+
59
+ /**
60
+ * Indicates whether the group has at least one visible option item.
61
+ *
62
+ * @type {boolean}
63
+ */
64
+ get hasVisibleItems() {
65
+ return this.visibleItems.length > 0;
66
+ }
67
+
68
+ /**
69
+ * Updates the group's label from the new target element and propagates the change to the view.
70
+ *
71
+ * @param {HTMLOptGroupElement} targetElement - The updated <optgroup> element.
72
+ */
73
+ update(targetElement) {
74
+ this.label = targetElement.label;
75
+ if (this.view) {
76
+ this.view.updateLabel(this.label);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Hook invoked when the target element reference changes.
82
+ * Updates the view's label and collapsed state to keep UI in sync.
83
+ */
84
+ onTargetChanged() {
85
+ if (this.view) {
86
+ this.view.updateLabel(this.label);
87
+ this.view.setCollapsed(this.collapsed);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Registers a callback to be invoked when the group's collapsed state changes.
93
+ *
94
+ * @param {(evtToken: any, model: GroupModel, collapsed: boolean) => void} callback - Listener for collapse changes.
95
+ */
96
+ onCollapsedChanged(callback) {
97
+ this.#privOnCollapsedChanged.push(callback);
98
+ }
99
+
100
+ /**
101
+ * Toggles the group's collapsed state, updates the view, and notifies registered listeners.
102
+ */
103
+ toggleCollapse() {
104
+ this.collapsed = !this.collapsed;
105
+ if (this.view) {
106
+ this.view.setCollapsed(this.collapsed);
107
+ }
108
+ iEvents.callEvent([this, this.collapsed], ...this.#privOnCollapsedChanged);
109
+ }
110
+
111
+ /**
112
+ * Adds an option item to this group and sets its back-reference to the group.
113
+ *
114
+ * @param {OptionModel} optionModel - The option to add.
115
+ */
116
+ addItem(optionModel) {
117
+ this.items.push(optionModel);
118
+ optionModel.group = this;
119
+ }
120
+
121
+ /**
122
+ * Removes an option item from this group and clears its group reference.
123
+ *
124
+ * @param {OptionModel} optionModel - The option to remove.
125
+ */
126
+ removeItem(optionModel) {
127
+ const index = this.items.indexOf(optionModel);
128
+ if (index > -1) {
129
+ this.items.splice(index, 1);
130
+ optionModel.group = null;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Updates the group's visibility in the view, typically based on children visibility.
136
+ * No-ops if the view is not initialized.
137
+ */
138
+ updateVisibility() {
139
+ if (this.view) {
140
+ this.view.updateVisibility();
141
+ }
142
+ }
143
143
  }