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.
- package/LICENSE +21 -21
- package/README.md +7 -2
- package/dist/selective-ui.css +567 -567
- package/dist/selective-ui.css.map +1 -1
- package/dist/selective-ui.esm.js +6046 -6046
- package/dist/selective-ui.esm.js.map +1 -1
- package/dist/selective-ui.esm.min.js +1 -1
- package/dist/selective-ui.esm.min.js.br +0 -0
- package/dist/selective-ui.min.js +1 -1
- package/dist/selective-ui.min.js.br +0 -0
- package/dist/selective-ui.umd.js +6046 -6046
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +68 -68
- package/src/css/components/accessorybox.css +63 -63
- package/src/css/components/directive.css +19 -19
- package/src/css/components/empty-state.css +25 -25
- package/src/css/components/loading-state.css +25 -25
- package/src/css/components/optgroup.css +61 -61
- package/src/css/components/option-handle.css +33 -33
- package/src/css/components/option.css +129 -129
- package/src/css/components/placeholder.css +14 -14
- package/src/css/components/popup.css +38 -38
- package/src/css/components/searchbox.css +28 -28
- package/src/css/components/selectbox.css +53 -53
- package/src/css/index.css +74 -74
- package/src/js/adapter/mixed-adapter.js +434 -434
- package/src/js/components/accessorybox.js +124 -124
- package/src/js/components/directive.js +37 -37
- package/src/js/components/empty-state.js +67 -67
- package/src/js/components/loading-state.js +59 -59
- package/src/js/components/option-handle.js +113 -113
- package/src/js/components/placeholder.js +56 -56
- package/src/js/components/popup.js +470 -470
- package/src/js/components/searchbox.js +167 -167
- package/src/js/components/selectbox.js +692 -692
- package/src/js/core/base/adapter.js +162 -162
- package/src/js/core/base/model.js +59 -59
- package/src/js/core/base/recyclerview.js +82 -82
- package/src/js/core/base/view.js +62 -62
- package/src/js/core/model-manager.js +286 -286
- package/src/js/core/search-controller.js +521 -521
- package/src/js/index.js +136 -136
- package/src/js/models/group-model.js +142 -142
- package/src/js/models/option-model.js +236 -236
- package/src/js/services/dataset-observer.js +73 -73
- package/src/js/services/ea-observer.js +87 -87
- package/src/js/services/effector.js +403 -403
- package/src/js/services/refresher.js +39 -39
- package/src/js/services/resize-observer.js +151 -151
- package/src/js/services/select-observer.js +60 -60
- package/src/js/types/adapter.type.js +32 -32
- package/src/js/types/effector.type.js +23 -23
- package/src/js/types/ievents.type.js +10 -10
- package/src/js/types/libs.type.js +27 -27
- package/src/js/types/model.type.js +11 -11
- package/src/js/types/recyclerview.type.js +11 -11
- package/src/js/types/resize-observer.type.js +18 -18
- package/src/js/types/view.group.type.js +12 -12
- package/src/js/types/view.option.type.js +14 -14
- package/src/js/types/view.type.js +10 -10
- package/src/js/utils/guard.js +46 -46
- package/src/js/utils/ievents.js +83 -83
- package/src/js/utils/istorage.js +60 -60
- package/src/js/utils/libs.js +618 -618
- package/src/js/utils/selective.js +385 -385
- package/src/js/views/group-view.js +102 -102
- package/src/js/views/option-view.js +152 -152
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
import {Libs} from "../utils/libs.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @class
|
|
5
|
-
*/
|
|
6
|
-
export class SearchBox {
|
|
7
|
-
/**
|
|
8
|
-
* Creates a searchable input box component with optional configuration
|
|
9
|
-
* and initializes it if options are provided.
|
|
10
|
-
*
|
|
11
|
-
* @param {object|null} [options=null] - Configuration (e.g., placeholder, accessibility IDs).
|
|
12
|
-
*/
|
|
13
|
-
constructor(options = null) {
|
|
14
|
-
this.options = options;
|
|
15
|
-
options && this.init(options);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @type {MountViewResult<any>}
|
|
20
|
-
*/
|
|
21
|
-
nodeMounted = null;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @type {HTMLDivElement}
|
|
25
|
-
*/
|
|
26
|
-
node = null;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @type {HTMLInputElement}
|
|
30
|
-
*/
|
|
31
|
-
SearchInput = null;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @type {Function|null}
|
|
35
|
-
*/
|
|
36
|
-
onSearch = null;
|
|
37
|
-
|
|
38
|
-
options = null;
|
|
39
|
-
|
|
40
|
-
onNavigate = null;
|
|
41
|
-
onEnter = null;
|
|
42
|
-
onEsc = null;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Initializes the search box DOM, sets ARIA attributes, and wires keyboard/mouse/input events.
|
|
46
|
-
* Supports navigation (ArrowUp/ArrowDown/Tab), Enter, and Escape through callbacks.
|
|
47
|
-
*
|
|
48
|
-
* @param {object} options - Configuration including placeholder and SEID_LIST for aria-controls.
|
|
49
|
-
*/
|
|
50
|
-
init(options) {
|
|
51
|
-
this.nodeMounted = Libs.mountNode({
|
|
52
|
-
SearchBox: {
|
|
53
|
-
tag: {node: "div", classList: ["selective-ui-searchbox", "hide"]},
|
|
54
|
-
child: {
|
|
55
|
-
SearchInput: {
|
|
56
|
-
tag: {
|
|
57
|
-
id: Libs.randomString(),
|
|
58
|
-
node: "input",
|
|
59
|
-
type: "search",
|
|
60
|
-
classList: ["selective-ui-searchbox-input"],
|
|
61
|
-
placeholder: options.placeholder,
|
|
62
|
-
role: "searchbox",
|
|
63
|
-
ariaControls: options.SEID_LIST,
|
|
64
|
-
ariaAutocomplete: "list"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
this.node = /** @type {HTMLDivElement} */ (this.nodeMounted.view);
|
|
71
|
-
this.SearchInput = this.nodeMounted.tags.SearchInput;
|
|
72
|
-
|
|
73
|
-
let isControlKey = false;
|
|
74
|
-
|
|
75
|
-
/** @type {HTMLInputElement} */
|
|
76
|
-
const SearchInput = this.nodeMounted.tags.SearchInput;
|
|
77
|
-
|
|
78
|
-
SearchInput.addEventListener("mousedown", (e) => {
|
|
79
|
-
e.stopPropagation();
|
|
80
|
-
});
|
|
81
|
-
SearchInput.addEventListener("mouseup", (e) => {
|
|
82
|
-
e.stopPropagation();
|
|
83
|
-
});
|
|
84
|
-
SearchInput.addEventListener("keydown", (e) => {
|
|
85
|
-
isControlKey = false;
|
|
86
|
-
if (e.key === "ArrowDown" || e.key === "Tab") {
|
|
87
|
-
e.preventDefault();
|
|
88
|
-
e.stopPropagation();
|
|
89
|
-
isControlKey = true;
|
|
90
|
-
this.onNavigate?.(1);
|
|
91
|
-
}
|
|
92
|
-
else if (e.key === "ArrowUp") {
|
|
93
|
-
e.preventDefault();
|
|
94
|
-
e.stopPropagation();
|
|
95
|
-
isControlKey = true;
|
|
96
|
-
this.onNavigate?.(-1);
|
|
97
|
-
}
|
|
98
|
-
else if (e.key === "Enter") {
|
|
99
|
-
e.preventDefault();
|
|
100
|
-
e.stopPropagation();
|
|
101
|
-
isControlKey = true;
|
|
102
|
-
this.onEnter?.();
|
|
103
|
-
}
|
|
104
|
-
else if (e.key === "Escape") {
|
|
105
|
-
e.preventDefault();
|
|
106
|
-
e.stopPropagation();
|
|
107
|
-
isControlKey = true;
|
|
108
|
-
this.onEsc?.();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
SearchInput.addEventListener("input", (e) => {
|
|
112
|
-
if (isControlKey) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this.onSearch && this.onSearch(this.nodeMounted.tags.SearchInput.value, true);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Shows the search box, toggles read-only based on `options.searchable`,
|
|
122
|
-
* and focuses the input when searchable.
|
|
123
|
-
*/
|
|
124
|
-
show() {
|
|
125
|
-
this.node.classList.remove("hide");
|
|
126
|
-
this.SearchInput.readOnly = !this.options.searchable;
|
|
127
|
-
if (this.options.searchable) {
|
|
128
|
-
requestAnimationFrame(() => {
|
|
129
|
-
this.SearchInput.focus();
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Hides the search box by adding the "hide" class.
|
|
136
|
-
*/
|
|
137
|
-
hide() {
|
|
138
|
-
this.node.classList.add("hide");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Clears the current search value and optionally triggers the onSearch callback.
|
|
143
|
-
*
|
|
144
|
-
* @param {boolean} [isTrigger=true] - Whether to invoke onSearch with an empty string.
|
|
145
|
-
*/
|
|
146
|
-
clear(isTrigger = true) {
|
|
147
|
-
this.nodeMounted.tags.SearchInput.value = "";
|
|
148
|
-
this.onSearch && this.onSearch("", isTrigger);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Updates the input's placeholder text, stripping any HTML for safety.
|
|
153
|
-
*
|
|
154
|
-
* @param {string} value - The new placeholder text.
|
|
155
|
-
*/
|
|
156
|
-
setPlaceHolder(value) {
|
|
157
|
-
this.SearchInput.placeholder = Libs.stripHtml(value);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Sets the active descendant for ARIA to indicate which option is currently highlighted.
|
|
162
|
-
*
|
|
163
|
-
* @param {string} id - The DOM id of the active option element.
|
|
164
|
-
*/
|
|
165
|
-
setActiveDescendant(id) {
|
|
166
|
-
this.SearchInput.setAttribute("aria-activedescendant", id);
|
|
167
|
-
}
|
|
1
|
+
import {Libs} from "../utils/libs.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @class
|
|
5
|
+
*/
|
|
6
|
+
export class SearchBox {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a searchable input box component with optional configuration
|
|
9
|
+
* and initializes it if options are provided.
|
|
10
|
+
*
|
|
11
|
+
* @param {object|null} [options=null] - Configuration (e.g., placeholder, accessibility IDs).
|
|
12
|
+
*/
|
|
13
|
+
constructor(options = null) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
options && this.init(options);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @type {MountViewResult<any>}
|
|
20
|
+
*/
|
|
21
|
+
nodeMounted = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @type {HTMLDivElement}
|
|
25
|
+
*/
|
|
26
|
+
node = null;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @type {HTMLInputElement}
|
|
30
|
+
*/
|
|
31
|
+
SearchInput = null;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {Function|null}
|
|
35
|
+
*/
|
|
36
|
+
onSearch = null;
|
|
37
|
+
|
|
38
|
+
options = null;
|
|
39
|
+
|
|
40
|
+
onNavigate = null;
|
|
41
|
+
onEnter = null;
|
|
42
|
+
onEsc = null;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Initializes the search box DOM, sets ARIA attributes, and wires keyboard/mouse/input events.
|
|
46
|
+
* Supports navigation (ArrowUp/ArrowDown/Tab), Enter, and Escape through callbacks.
|
|
47
|
+
*
|
|
48
|
+
* @param {object} options - Configuration including placeholder and SEID_LIST for aria-controls.
|
|
49
|
+
*/
|
|
50
|
+
init(options) {
|
|
51
|
+
this.nodeMounted = Libs.mountNode({
|
|
52
|
+
SearchBox: {
|
|
53
|
+
tag: {node: "div", classList: ["selective-ui-searchbox", "hide"]},
|
|
54
|
+
child: {
|
|
55
|
+
SearchInput: {
|
|
56
|
+
tag: {
|
|
57
|
+
id: Libs.randomString(),
|
|
58
|
+
node: "input",
|
|
59
|
+
type: "search",
|
|
60
|
+
classList: ["selective-ui-searchbox-input"],
|
|
61
|
+
placeholder: options.placeholder,
|
|
62
|
+
role: "searchbox",
|
|
63
|
+
ariaControls: options.SEID_LIST,
|
|
64
|
+
ariaAutocomplete: "list"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
this.node = /** @type {HTMLDivElement} */ (this.nodeMounted.view);
|
|
71
|
+
this.SearchInput = this.nodeMounted.tags.SearchInput;
|
|
72
|
+
|
|
73
|
+
let isControlKey = false;
|
|
74
|
+
|
|
75
|
+
/** @type {HTMLInputElement} */
|
|
76
|
+
const SearchInput = this.nodeMounted.tags.SearchInput;
|
|
77
|
+
|
|
78
|
+
SearchInput.addEventListener("mousedown", (e) => {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
});
|
|
81
|
+
SearchInput.addEventListener("mouseup", (e) => {
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
});
|
|
84
|
+
SearchInput.addEventListener("keydown", (e) => {
|
|
85
|
+
isControlKey = false;
|
|
86
|
+
if (e.key === "ArrowDown" || e.key === "Tab") {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
e.stopPropagation();
|
|
89
|
+
isControlKey = true;
|
|
90
|
+
this.onNavigate?.(1);
|
|
91
|
+
}
|
|
92
|
+
else if (e.key === "ArrowUp") {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
e.stopPropagation();
|
|
95
|
+
isControlKey = true;
|
|
96
|
+
this.onNavigate?.(-1);
|
|
97
|
+
}
|
|
98
|
+
else if (e.key === "Enter") {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
e.stopPropagation();
|
|
101
|
+
isControlKey = true;
|
|
102
|
+
this.onEnter?.();
|
|
103
|
+
}
|
|
104
|
+
else if (e.key === "Escape") {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
e.stopPropagation();
|
|
107
|
+
isControlKey = true;
|
|
108
|
+
this.onEsc?.();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
SearchInput.addEventListener("input", (e) => {
|
|
112
|
+
if (isControlKey) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.onSearch && this.onSearch(this.nodeMounted.tags.SearchInput.value, true);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Shows the search box, toggles read-only based on `options.searchable`,
|
|
122
|
+
* and focuses the input when searchable.
|
|
123
|
+
*/
|
|
124
|
+
show() {
|
|
125
|
+
this.node.classList.remove("hide");
|
|
126
|
+
this.SearchInput.readOnly = !this.options.searchable;
|
|
127
|
+
if (this.options.searchable) {
|
|
128
|
+
requestAnimationFrame(() => {
|
|
129
|
+
this.SearchInput.focus();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Hides the search box by adding the "hide" class.
|
|
136
|
+
*/
|
|
137
|
+
hide() {
|
|
138
|
+
this.node.classList.add("hide");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Clears the current search value and optionally triggers the onSearch callback.
|
|
143
|
+
*
|
|
144
|
+
* @param {boolean} [isTrigger=true] - Whether to invoke onSearch with an empty string.
|
|
145
|
+
*/
|
|
146
|
+
clear(isTrigger = true) {
|
|
147
|
+
this.nodeMounted.tags.SearchInput.value = "";
|
|
148
|
+
this.onSearch && this.onSearch("", isTrigger);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Updates the input's placeholder text, stripping any HTML for safety.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} value - The new placeholder text.
|
|
155
|
+
*/
|
|
156
|
+
setPlaceHolder(value) {
|
|
157
|
+
this.SearchInput.placeholder = Libs.stripHtml(value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Sets the active descendant for ARIA to indicate which option is currently highlighted.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} id - The DOM id of the active option element.
|
|
164
|
+
*/
|
|
165
|
+
setActiveDescendant(id) {
|
|
166
|
+
this.SearchInput.setAttribute("aria-activedescendant", id);
|
|
167
|
+
}
|
|
168
168
|
}
|