kr-elements 0.0.1-alpha.1
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 -0
- package/dist/cjs/Boolean.attribute.value.normalizer.js +11 -0
- package/dist/cjs/Combobox.markup.js +315 -0
- package/dist/cjs/HTML.combobox.element.js +317 -0
- package/dist/cjs/HTML.combobox.option.element.js +95 -0
- package/dist/cjs/HTML.combobox.tag.element.js +22 -0
- package/dist/cjs/index.js +17 -0
- package/dist/esm/Boolean.attribute.value.normalizer.js +7 -0
- package/dist/esm/Combobox.markup.js +311 -0
- package/dist/esm/HTML.combobox.element.js +313 -0
- package/dist/esm/HTML.combobox.option.element.js +91 -0
- package/dist/esm/HTML.combobox.tag.element.js +18 -0
- package/dist/esm/index.js +1 -0
- package/dist/types/Boolean.attribute.value.normalizer.d.ts +2 -0
- package/dist/types/Boolean.attribute.value.normalizer.d.ts.map +1 -0
- package/dist/types/Combobox.markup.d.ts +26 -0
- package/dist/types/Combobox.markup.d.ts.map +1 -0
- package/dist/types/HTML.combobox.element.d.ts +50 -0
- package/dist/types/HTML.combobox.element.d.ts.map +1 -0
- package/dist/types/HTML.combobox.option.element.d.ts +15 -0
- package/dist/types/HTML.combobox.option.element.d.ts.map +1 -0
- package/dist/types/HTML.combobox.tag.element.d.ts +4 -0
- package/dist/types/HTML.combobox.tag.element.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Roman Konstantin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toBoolean = void 0;
|
|
4
|
+
function toBoolean(value) {
|
|
5
|
+
if (value == null || value === 'false' || value === false)
|
|
6
|
+
value = false;
|
|
7
|
+
if (value === true || value === 'true' || value === '')
|
|
8
|
+
value = true;
|
|
9
|
+
return Boolean(value);
|
|
10
|
+
}
|
|
11
|
+
exports.toBoolean = toBoolean;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComboboxMarkup = void 0;
|
|
4
|
+
const HTML_combobox_tag_element_js_1 = require("./HTML.combobox.tag.element.js");
|
|
5
|
+
class ComboboxMarkup {
|
|
6
|
+
#shadowRoot;
|
|
7
|
+
#internals;
|
|
8
|
+
tagsContainer = null;
|
|
9
|
+
optionsContainer = null;
|
|
10
|
+
clearAllButton = null;
|
|
11
|
+
dropdown = null;
|
|
12
|
+
placeholder = null;
|
|
13
|
+
searchInput = null;
|
|
14
|
+
constructor(shadowRoot, internals) {
|
|
15
|
+
this.#shadowRoot = shadowRoot;
|
|
16
|
+
this.#internals = internals;
|
|
17
|
+
this.#shadowRoot.host.addEventListener('focus', this.showDropdown);
|
|
18
|
+
this.#shadowRoot.host.addEventListener('blur', this.hideDropdown);
|
|
19
|
+
this.#shadowRoot.host.addEventListener('click', this.showDropdown);
|
|
20
|
+
document.addEventListener('click', this.hideDropdown);
|
|
21
|
+
document.addEventListener('scroll', this.onPageScroll);
|
|
22
|
+
}
|
|
23
|
+
connect() {
|
|
24
|
+
this.tagsContainer = this.#shadowRoot.querySelector('#tags');
|
|
25
|
+
this.optionsContainer = this.#shadowRoot.querySelector('[part="options"]');
|
|
26
|
+
this.clearAllButton = this.#shadowRoot.querySelector('[part="clear-all-button"]');
|
|
27
|
+
this.dropdown = this.#shadowRoot.querySelector('#dropdown');
|
|
28
|
+
this.placeholder = this.#shadowRoot.querySelector('#placeholder');
|
|
29
|
+
this.searchInput = this.#shadowRoot.querySelector('[part="search-input"]');
|
|
30
|
+
}
|
|
31
|
+
sort(query) {
|
|
32
|
+
const regex = new RegExp(query, 'i');
|
|
33
|
+
this.optionsContainer.querySelectorAll('box-option')
|
|
34
|
+
.forEach(option => {
|
|
35
|
+
if (query === '') {
|
|
36
|
+
option.style.display = "initial";
|
|
37
|
+
}
|
|
38
|
+
else if (!regex.test(option.label)) {
|
|
39
|
+
option.style.display = "none";
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
option.style.order = "initial";
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
disconnect() {
|
|
47
|
+
this.#shadowRoot.host.removeEventListener('focus', this.showDropdown);
|
|
48
|
+
this.#shadowRoot.host.removeEventListener('blur', this.hideDropdown);
|
|
49
|
+
this.#shadowRoot.host.removeEventListener('click', this.showDropdown);
|
|
50
|
+
document.removeEventListener('click', this.hideDropdown);
|
|
51
|
+
document.removeEventListener('scroll', this.onPageScroll);
|
|
52
|
+
}
|
|
53
|
+
onPageScroll = () => {
|
|
54
|
+
if (this.dropdown.matches(':popover-open')) {
|
|
55
|
+
this.setDropdownPosition(this.#shadowRoot.host.getBoundingClientRect());
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
setDropdownPosition(rect) {
|
|
59
|
+
const dropdown = this.dropdown;
|
|
60
|
+
const vh = window.innerHeight;
|
|
61
|
+
const sh = rect.height;
|
|
62
|
+
const sy = rect.top;
|
|
63
|
+
if (sy < (vh - vh / 3)) {
|
|
64
|
+
dropdown.style.top = sh + sy + 'px';
|
|
65
|
+
dropdown.style.bottom = 'unset';
|
|
66
|
+
dropdown.style.transform = `unset`;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
dropdown.style.top = sh + sy + 'px';
|
|
70
|
+
dropdown.style.bottom = 'unset';
|
|
71
|
+
dropdown.style.transform = `translateY(calc(-1 * calc(100% + ${sh}px)))`;
|
|
72
|
+
}
|
|
73
|
+
dropdown.style.left = rect.left + 'px';
|
|
74
|
+
dropdown.style.width = rect.width + 'px';
|
|
75
|
+
dropdown.style.maxHeight = '50vh';
|
|
76
|
+
}
|
|
77
|
+
showDropdown = () => {
|
|
78
|
+
try {
|
|
79
|
+
this.setDropdownPosition(this.#shadowRoot.host.getBoundingClientRect());
|
|
80
|
+
this.dropdown.style.display = 'flex';
|
|
81
|
+
this.dropdown.showPopover();
|
|
82
|
+
this.#internals.ariaExpanded = "true";
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
this.#internals.ariaExpanded = "false";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
hideDropdown = (event) => {
|
|
89
|
+
if (event.composedPath().includes(this.#shadowRoot.host))
|
|
90
|
+
return;
|
|
91
|
+
try {
|
|
92
|
+
this.dropdown.hidePopover();
|
|
93
|
+
this.dropdown.style.display = 'none';
|
|
94
|
+
this.#internals.ariaExpanded = "false";
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
this.#internals.ariaExpanded = "true";
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
createAndAppendTag(option) {
|
|
101
|
+
const template = this.tagTemplate;
|
|
102
|
+
const tag = template.cloneNode(true);
|
|
103
|
+
const label = tag.querySelector('[part="tag-label"]');
|
|
104
|
+
label.textContent = option.label;
|
|
105
|
+
const clearButton = tag.querySelector('[part="tag-clear-button"]');
|
|
106
|
+
clearButton.setAttribute('value', option.value);
|
|
107
|
+
tag.setAttribute('value', option.value);
|
|
108
|
+
option.querySelectorAll('[part]')
|
|
109
|
+
.forEach(node => {
|
|
110
|
+
const relatedPart = tag.querySelector(`[part=${node.getAttribute('part')}]`);
|
|
111
|
+
if (relatedPart) {
|
|
112
|
+
tag.replaceChild(node.cloneNode(true), relatedPart);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
this.tagsContainer.appendChild(tag);
|
|
116
|
+
return clearButton;
|
|
117
|
+
}
|
|
118
|
+
getTagByValue(value) {
|
|
119
|
+
return this.tagsContainer.querySelector(`box-tag[value="${value}"]`);
|
|
120
|
+
}
|
|
121
|
+
getOptionByValue(value) {
|
|
122
|
+
return this.optionsContainer.querySelector(`box-option[value="${value}"]`);
|
|
123
|
+
}
|
|
124
|
+
get tagTemplate() {
|
|
125
|
+
let template = this.#shadowRoot.host.firstElementChild;
|
|
126
|
+
if (!template || !(template instanceof HTML_combobox_tag_element_js_1.HTMLComboboxTagElement)) {
|
|
127
|
+
const innerTemplate = this.#shadowRoot.querySelector('#tag-template');
|
|
128
|
+
const doc = document.importNode(innerTemplate.content, true);
|
|
129
|
+
template = doc.querySelector('box-tag');
|
|
130
|
+
}
|
|
131
|
+
return template;
|
|
132
|
+
}
|
|
133
|
+
get selectedOptions() {
|
|
134
|
+
return this.optionsContainer
|
|
135
|
+
.querySelectorAll('box-option[selected]');
|
|
136
|
+
}
|
|
137
|
+
static get template() {
|
|
138
|
+
return `
|
|
139
|
+
<style>
|
|
140
|
+
:host {
|
|
141
|
+
font-size: inherit;
|
|
142
|
+
font-family: inherit;
|
|
143
|
+
display: grid;
|
|
144
|
+
grid-template-columns: minmax(0, max-content) 1fr;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 1px;
|
|
147
|
+
position: relative;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
:host([multiple]) {
|
|
151
|
+
grid-template-columns: minmax(0, max-content) 1fr auto;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#dropdown {
|
|
155
|
+
inset: unset;
|
|
156
|
+
margin: 0;
|
|
157
|
+
box-sizing: border-box;
|
|
158
|
+
overflow-y: scroll;
|
|
159
|
+
flex-direction: column;
|
|
160
|
+
border-radius: inherit;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
[part="options"] {
|
|
164
|
+
display: flex;
|
|
165
|
+
flex-direction: column;
|
|
166
|
+
gap: 2px;
|
|
167
|
+
padding-block: .5rem;
|
|
168
|
+
border-radius: inherit;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
[part="options"] box-option {
|
|
172
|
+
border-radius: inherit;
|
|
173
|
+
content-visibility: auto;
|
|
174
|
+
border: 1px solid cornflowerblue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[part="options"] box-option[selected] {
|
|
178
|
+
background-color: Highlight;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
[part="search-input"] {
|
|
182
|
+
display: none;
|
|
183
|
+
position: sticky;
|
|
184
|
+
top: 0;
|
|
185
|
+
z-index: 2;
|
|
186
|
+
border-radius: inherit;
|
|
187
|
+
border-style: inherit;
|
|
188
|
+
border-width: inherit;
|
|
189
|
+
padding: inherit;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
:host([searchable]) [part="search-input"],
|
|
193
|
+
:host([filterable]) [part="search-input"] {
|
|
194
|
+
display: flex;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#placeholder {
|
|
198
|
+
overflow: hidden;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#tags:not(:empty) + #placeholder {
|
|
202
|
+
display: none;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#tags:not(:empty) {
|
|
206
|
+
grid-column: 1 / span 2;
|
|
207
|
+
width: 100%;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#tags {
|
|
211
|
+
display: flex;
|
|
212
|
+
flex-wrap: wrap;
|
|
213
|
+
overflow: hidden;
|
|
214
|
+
gap: 2px;
|
|
215
|
+
border-radius: inherit;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
[part="tag"] {
|
|
219
|
+
width: 100%;
|
|
220
|
+
justify-self: start;
|
|
221
|
+
font-size: inherit;
|
|
222
|
+
box-sizing: border-box;
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
border-radius: inherit;
|
|
226
|
+
padding-inline-start: 0.2lh;
|
|
227
|
+
padding-inline-end: .2rem;
|
|
228
|
+
background-color: transparent;
|
|
229
|
+
gap: 5px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
:host([multiple]) [part="tag"] {
|
|
233
|
+
background-color: Highlight;
|
|
234
|
+
width: fit-content;
|
|
235
|
+
max-width: 100%;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
[part="tag-label"] {
|
|
239
|
+
white-space: nowrap;
|
|
240
|
+
text-overflow: ellipsis;
|
|
241
|
+
overflow: hidden;
|
|
242
|
+
user-select: none;
|
|
243
|
+
font-size: 95%;
|
|
244
|
+
flex-grow: 1;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
:host([multiple]) [part="tag-label"] {
|
|
248
|
+
flex-grow: unset;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
[part="tag-clear-button"], [part="clear-all-button"] {
|
|
252
|
+
border-radius: 100%;
|
|
253
|
+
border: none;
|
|
254
|
+
aspect-ratio: 1;
|
|
255
|
+
line-height: 0;
|
|
256
|
+
padding: 0!important;
|
|
257
|
+
user-select: none;
|
|
258
|
+
background-color: transparent;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
[part="tag-clear-button"] {
|
|
262
|
+
inline-size: 1em;
|
|
263
|
+
block-size: 1em;
|
|
264
|
+
font-size: 80%;
|
|
265
|
+
display: none;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
:host([multiple]) [part="tag-clear-button"],
|
|
269
|
+
:host([clearable]) [part="tag-clear-button"] {
|
|
270
|
+
display: block;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
[part="clear-all-button"] {
|
|
274
|
+
font-size: inherit;
|
|
275
|
+
inline-size: 1.2em;
|
|
276
|
+
block-size: 1.2em;
|
|
277
|
+
display: none;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
:host([multiple]) [part="clear-all-button"] {
|
|
281
|
+
display: block;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
[part="clear-all-button"]:hover,
|
|
285
|
+
[part="tag-clear-button"]:hover {
|
|
286
|
+
color: ActiveText;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
[part="clear-all-button"]:hover {
|
|
290
|
+
background-color: ButtonFace;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
:host:has(#tags:empty) [part="clear-all-button"] {
|
|
294
|
+
/*display: none;*/
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
</style>
|
|
298
|
+
|
|
299
|
+
<div id="tags"></div>
|
|
300
|
+
<div id="placeholder" ></div>
|
|
301
|
+
<button part="clear-all-button">✕</button>
|
|
302
|
+
<div id="dropdown" popover="manual">
|
|
303
|
+
<input name="search-input" part="search-input" />
|
|
304
|
+
<div part="options"></div>
|
|
305
|
+
</div>
|
|
306
|
+
<template id='tag-template'>
|
|
307
|
+
<box-tag>
|
|
308
|
+
<span part="tag-label"></span>
|
|
309
|
+
<button part="tag-clear-button">✕</button>
|
|
310
|
+
</box-tag>
|
|
311
|
+
</template>
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
exports.ComboboxMarkup = ComboboxMarkup;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HTMLComboboxElement = void 0;
|
|
4
|
+
const Combobox_markup_js_1 = require("./Combobox.markup.js");
|
|
5
|
+
const HTML_combobox_option_element_js_1 = require("./HTML.combobox.option.element.js");
|
|
6
|
+
const Boolean_attribute_value_normalizer_js_1 = require("./Boolean.attribute.value.normalizer.js");
|
|
7
|
+
class HTMLComboboxElement extends HTMLElement {
|
|
8
|
+
static stringAttributes = new Set(['value', 'placeholder', 'query']);
|
|
9
|
+
static booleanAttributes = new Set(['required', 'disabled', 'clearable', 'multiple', 'filterable', 'searchable']);
|
|
10
|
+
static observerOptions = { childList: true, attributes: false, subtree: false };
|
|
11
|
+
static styleSheet = [new CSSStyleSheet];
|
|
12
|
+
static formAssociated = true;
|
|
13
|
+
internals;
|
|
14
|
+
shadowRoot;
|
|
15
|
+
#observer;
|
|
16
|
+
#markup;
|
|
17
|
+
#values = new Set;
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.internals = this.attachInternals();
|
|
21
|
+
this.internals.role = "combobox";
|
|
22
|
+
this.shadowRoot = this.attachShadow({ mode: 'closed', delegatesFocus: true });
|
|
23
|
+
this.#markup = new Combobox_markup_js_1.ComboboxMarkup(this.shadowRoot, this.internals);
|
|
24
|
+
this.shadowRoot.innerHTML = Combobox_markup_js_1.ComboboxMarkup.template;
|
|
25
|
+
this.shadowRoot.adoptedStyleSheets = HTMLComboboxElement.styleSheet;
|
|
26
|
+
this.#observer = new MutationObserver(this.#onOptionsChanges);
|
|
27
|
+
}
|
|
28
|
+
connectedCallback() {
|
|
29
|
+
this.#markup.connect();
|
|
30
|
+
this.#initialAttributesSynchronization();
|
|
31
|
+
this.#onOptionsChanges([{ addedNodes: Array.from(this.children) }]);
|
|
32
|
+
this.#observer.observe(this, HTMLComboboxElement.observerOptions);
|
|
33
|
+
this.#markup.clearAllButton.addEventListener('click', this.#onClickClearAllButton);
|
|
34
|
+
this.#markup.searchInput.addEventListener('input', this.#onInput);
|
|
35
|
+
}
|
|
36
|
+
disconnectedCallback() {
|
|
37
|
+
this.#observer.disconnect();
|
|
38
|
+
this.#markup.disconnect();
|
|
39
|
+
}
|
|
40
|
+
formResetCallback() {
|
|
41
|
+
this.#values = new Set;
|
|
42
|
+
this.selectedOptions.forEach(option => option.removeAttribute('selected'));
|
|
43
|
+
this.#markup.tagsContainer.replaceChildren();
|
|
44
|
+
this.#setValidityAndFormValue();
|
|
45
|
+
this.dispatchEvent(new Event('change'));
|
|
46
|
+
}
|
|
47
|
+
formDisabledCallback(isDisabled) {
|
|
48
|
+
this.disabled = isDisabled;
|
|
49
|
+
}
|
|
50
|
+
get valueAsArray() {
|
|
51
|
+
return Array.from(this.#values);
|
|
52
|
+
}
|
|
53
|
+
get selectedOptions() {
|
|
54
|
+
return this.#markup.selectedOptions;
|
|
55
|
+
}
|
|
56
|
+
get validity() {
|
|
57
|
+
return this.internals.validity;
|
|
58
|
+
}
|
|
59
|
+
get willValidate() {
|
|
60
|
+
return this.internals.willValidate;
|
|
61
|
+
}
|
|
62
|
+
get value() {
|
|
63
|
+
return this.valueAsArray.join(',');
|
|
64
|
+
}
|
|
65
|
+
set value(value) {
|
|
66
|
+
if (this.value === value || typeof value !== 'string')
|
|
67
|
+
return;
|
|
68
|
+
const prevValue = new Set(this.#values);
|
|
69
|
+
this.#values = new Set;
|
|
70
|
+
const values = value.split(',').filter(Boolean);
|
|
71
|
+
Promise.resolve(values)
|
|
72
|
+
.then(values => {
|
|
73
|
+
if (values.length) {
|
|
74
|
+
if (!this.multiple) {
|
|
75
|
+
if (this.#values.size === 0) {
|
|
76
|
+
values.length = 1;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
values.length = 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const key of values) {
|
|
83
|
+
const option = this.#markup.getOptionByValue(key);
|
|
84
|
+
if (option)
|
|
85
|
+
this.#selectOption(option);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const key of prevValue) {
|
|
89
|
+
if (this.#values.has(key))
|
|
90
|
+
continue;
|
|
91
|
+
const option = this.#markup.getOptionByValue(key);
|
|
92
|
+
const tag = this.#markup.getTagByValue(key);
|
|
93
|
+
tag?.remove();
|
|
94
|
+
option?.toggleAttribute('selected', false);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
get query() {
|
|
99
|
+
return this.#markup.searchInput.value;
|
|
100
|
+
}
|
|
101
|
+
set query(value) {
|
|
102
|
+
if (value === this.query)
|
|
103
|
+
return;
|
|
104
|
+
this.#markup.searchInput.value = value;
|
|
105
|
+
super.setAttribute('query', value);
|
|
106
|
+
}
|
|
107
|
+
get clearable() {
|
|
108
|
+
return this.hasAttribute('clearable');
|
|
109
|
+
}
|
|
110
|
+
set clearable(value) {
|
|
111
|
+
super.toggleAttribute('clearable', value);
|
|
112
|
+
}
|
|
113
|
+
get multiple() {
|
|
114
|
+
return this.hasAttribute('multiple');
|
|
115
|
+
}
|
|
116
|
+
set multiple(value) {
|
|
117
|
+
super.toggleAttribute('multiple', value);
|
|
118
|
+
}
|
|
119
|
+
get filterable() {
|
|
120
|
+
return this.hasAttribute('filterable');
|
|
121
|
+
}
|
|
122
|
+
set filterable(value) {
|
|
123
|
+
super.toggleAttribute('filterable', value);
|
|
124
|
+
}
|
|
125
|
+
get searchable() {
|
|
126
|
+
return this.hasAttribute('searchable');
|
|
127
|
+
}
|
|
128
|
+
set searchable(value) {
|
|
129
|
+
super.toggleAttribute('searchable', value);
|
|
130
|
+
}
|
|
131
|
+
get disabled() {
|
|
132
|
+
return this.hasAttribute('disabled');
|
|
133
|
+
}
|
|
134
|
+
set disabled(value) {
|
|
135
|
+
this.internals.ariaDisabled = String(value);
|
|
136
|
+
super.toggleAttribute('disabled', value);
|
|
137
|
+
}
|
|
138
|
+
get required() {
|
|
139
|
+
return this.hasAttribute('required');
|
|
140
|
+
}
|
|
141
|
+
set required(value) {
|
|
142
|
+
this.internals.ariaRequired = String(value);
|
|
143
|
+
super.toggleAttribute('required', value);
|
|
144
|
+
}
|
|
145
|
+
get placeholder() {
|
|
146
|
+
return this.#markup.searchInput.placeholder;
|
|
147
|
+
}
|
|
148
|
+
set placeholder(value) {
|
|
149
|
+
this.#markup.placeholder.innerText = value;
|
|
150
|
+
this.#markup.searchInput.placeholder = value;
|
|
151
|
+
super.setAttribute('placeholder', value);
|
|
152
|
+
}
|
|
153
|
+
setAttribute(name, value) {
|
|
154
|
+
if (HTMLComboboxElement.booleanAttributes.has(name)) {
|
|
155
|
+
Reflect.set(this, name, (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (HTMLComboboxElement.stringAttributes.has(name)) {
|
|
159
|
+
Reflect.set(this, name, value);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
super.setAttribute(name, value);
|
|
163
|
+
}
|
|
164
|
+
removeAttribute(name) {
|
|
165
|
+
if (HTMLComboboxElement.booleanAttributes.has(name)) {
|
|
166
|
+
Reflect.set(this, name, false);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (HTMLComboboxElement.stringAttributes.has(name)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
super.removeAttribute(name);
|
|
173
|
+
}
|
|
174
|
+
reportValidity() {
|
|
175
|
+
this.internals.reportValidity();
|
|
176
|
+
}
|
|
177
|
+
checkValidity() {
|
|
178
|
+
this.internals.checkValidity();
|
|
179
|
+
}
|
|
180
|
+
setCustomValidity(message) {
|
|
181
|
+
if (message === '') {
|
|
182
|
+
this.internals.setValidity({});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
this.internals.setValidity({ customError: true }, message);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
#onInput = (event) => {
|
|
189
|
+
if (this.filterable) {
|
|
190
|
+
if (event.target && event.target instanceof HTMLInputElement) {
|
|
191
|
+
this.#markup.sort(event.target.value);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
#onOptionsChanges = (records) => {
|
|
196
|
+
records.forEach(record => {
|
|
197
|
+
record.addedNodes.forEach(node => {
|
|
198
|
+
if (node instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
|
|
199
|
+
node.addEventListener('click', this.#onSelectOption);
|
|
200
|
+
if (node.selected) {
|
|
201
|
+
if (this.multiple) {
|
|
202
|
+
this.#selectOption(node);
|
|
203
|
+
}
|
|
204
|
+
else if (this.#values.size === 0) {
|
|
205
|
+
this.#selectOption(node);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (node instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement || node instanceof HTMLOptGroupElement) {
|
|
210
|
+
this.#markup.optionsContainer.append(node);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
this.#setValidityAndFormValue();
|
|
215
|
+
};
|
|
216
|
+
#selectOption(option) {
|
|
217
|
+
if (this.#values.has(option.value))
|
|
218
|
+
return;
|
|
219
|
+
const value = option.value;
|
|
220
|
+
this.#values.add(value);
|
|
221
|
+
option.toggleAttribute('selected', true);
|
|
222
|
+
const control = this.#markup.createAndAppendTag(option);
|
|
223
|
+
control.addEventListener('click', this.#onClickTagClearButton);
|
|
224
|
+
}
|
|
225
|
+
#onSelectOption = (event) => {
|
|
226
|
+
let option;
|
|
227
|
+
if (event.target instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
|
|
228
|
+
option = event.target;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
option = event.composedPath()
|
|
232
|
+
.find(el => el instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement);
|
|
233
|
+
}
|
|
234
|
+
if (option) {
|
|
235
|
+
if (this.#values.has(option.value))
|
|
236
|
+
return;
|
|
237
|
+
if (!this.multiple) {
|
|
238
|
+
this.#values.forEach(value => {
|
|
239
|
+
this.#markup.getTagByValue(value)?.remove();
|
|
240
|
+
this.#markup.getOptionByValue(value)?.toggleAttribute('selected', false);
|
|
241
|
+
});
|
|
242
|
+
this.#values.clear();
|
|
243
|
+
this.#markup.tagsContainer.replaceChildren();
|
|
244
|
+
}
|
|
245
|
+
this.#selectOption(option);
|
|
246
|
+
this.#setValidityAndFormValue();
|
|
247
|
+
this.dispatchEvent(new Event('change'));
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
#onClickTagClearButton = (event) => {
|
|
251
|
+
if (event.target && event.target instanceof HTMLButtonElement) {
|
|
252
|
+
const value = event.target.value;
|
|
253
|
+
const option = this.#markup.getOptionByValue(value);
|
|
254
|
+
const tag = this.#markup.getTagByValue(value);
|
|
255
|
+
option.removeAttribute('selected');
|
|
256
|
+
this.#values.delete(event.target.value);
|
|
257
|
+
tag.remove();
|
|
258
|
+
this.#setValidityAndFormValue();
|
|
259
|
+
this.dispatchEvent(new Event('change'));
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
#onClickClearAllButton = () => {
|
|
263
|
+
this.formResetCallback();
|
|
264
|
+
};
|
|
265
|
+
#setValidityAndFormValue() {
|
|
266
|
+
this.internals.setFormValue(this.value);
|
|
267
|
+
if (this.required && this.value === '') {
|
|
268
|
+
this.internals.setValidity({ valueMissing: true });
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
this.internals.setValidity({});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
#initialAttributesSynchronization() {
|
|
275
|
+
for (const key of HTMLComboboxElement.booleanAttributes) {
|
|
276
|
+
const value = (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(this.getAttribute(key));
|
|
277
|
+
Reflect.set(this, key, value);
|
|
278
|
+
}
|
|
279
|
+
for (const key of HTMLComboboxElement.stringAttributes) {
|
|
280
|
+
if (this.hasAttribute(key)) {
|
|
281
|
+
Reflect.set(this, key, this.getAttribute(key));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
static staticLoadCssByUrls(urls) {
|
|
286
|
+
}
|
|
287
|
+
static loadCssFromDocumentStyleSheets() {
|
|
288
|
+
if (document.readyState === 'complete') {
|
|
289
|
+
HTMLComboboxElement.#loadDocumentStyleSheets();
|
|
290
|
+
}
|
|
291
|
+
if (document.readyState === 'loading') {
|
|
292
|
+
document.addEventListener('DOMContentLoaded', HTMLComboboxElement.#loadDocumentStyleSheets);
|
|
293
|
+
}
|
|
294
|
+
if (document.readyState === 'interactive') {
|
|
295
|
+
queueMicrotask(HTMLComboboxElement.#loadDocumentStyleSheets);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
static #loadDocumentStyleSheets() {
|
|
299
|
+
const [innerSheet] = HTMLComboboxElement.styleSheet;
|
|
300
|
+
for (const outerSheet of document.styleSheets) {
|
|
301
|
+
for (const rule of outerSheet.cssRules) {
|
|
302
|
+
innerSheet.insertRule(rule.cssText, innerSheet.cssRules.length);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
exports.HTMLComboboxElement = HTMLComboboxElement;
|
|
308
|
+
document.addEventListener('keypress', (event) => {
|
|
309
|
+
if (document.activeElement instanceof HTMLComboboxElement) {
|
|
310
|
+
if (document.activeElement.shadowRoot.activeElement instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
|
|
311
|
+
document.activeElement.shadowRoot.activeElement.click();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
if (!window.customElements.get('combo-box')) {
|
|
316
|
+
window.customElements.define('combo-box', HTMLComboboxElement);
|
|
317
|
+
}
|