html-combobox-element 0.0.2-beta.1 → 0.0.2-beta.11
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 +1 -0
- package/combobox-skill/SKILL.md +43 -0
- package/combobox-skill/custom-box-tag.md +17 -0
- package/combobox-skill/customization.md +23 -0
- package/combobox-skill/legacy-react-restrictions.md +14 -0
- package/combobox-skill/share-styles.md +17 -0
- package/dist/cjs/combobox/Combobox.markup.js +228 -118
- package/dist/cjs/combobox/HTML.combobox.element.js +192 -112
- package/dist/cjs/combobox/HTML.combobox.option.element.js +86 -5
- package/dist/cjs/combobox/HTML.combobox.tag.element.js +27 -7
- package/dist/cjs/index.js +0 -62
- package/dist/esm/combobox/Combobox.markup.js +228 -118
- package/dist/esm/combobox/HTML.combobox.element.js +192 -112
- package/dist/esm/combobox/HTML.combobox.option.element.js +86 -5
- package/dist/esm/combobox/HTML.combobox.tag.element.js +27 -7
- package/dist/esm/index.js +0 -62
- package/dist/types/combobox/Combobox.markup.d.ts +14 -8
- package/dist/types/combobox/Combobox.markup.d.ts.map +1 -1
- package/dist/types/combobox/HTML.combobox.element.d.ts +5 -3
- package/dist/types/combobox/HTML.combobox.element.d.ts.map +1 -1
- package/dist/types/combobox/HTML.combobox.option.element.d.ts +11 -0
- package/dist/types/combobox/HTML.combobox.option.element.d.ts.map +1 -1
- package/dist/types/combobox/HTML.combobox.tag.element.d.ts +9 -1
- package/dist/types/combobox/HTML.combobox.tag.element.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -7,7 +7,7 @@ const HTML_combobox_option_element_js_1 = require("./HTML.combobox.option.elemen
|
|
|
7
7
|
const Boolean_attribute_value_normalizer_js_1 = require("./Boolean.attribute.value.normalizer.js");
|
|
8
8
|
class HTMLComboboxElement extends HTMLElement {
|
|
9
9
|
static OWN_IDL = new Set(['required', 'disabled', 'clearable', 'multiple', 'filterable', 'searchable', 'value', 'placeholder', 'query']);
|
|
10
|
-
static observerOptions = { childList: true
|
|
10
|
+
static observerOptions = { childList: true };
|
|
11
11
|
static styleSheet = [new CSSStyleSheet];
|
|
12
12
|
static formAssociated = true;
|
|
13
13
|
shadowRoot;
|
|
@@ -15,41 +15,85 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
15
15
|
#observer;
|
|
16
16
|
#markup;
|
|
17
17
|
#values = new Set;
|
|
18
|
+
#prevValue = '';
|
|
19
|
+
#changed = false;
|
|
18
20
|
constructor() {
|
|
19
21
|
super();
|
|
20
22
|
this.#internals = this.attachInternals();
|
|
21
23
|
this.#internals.role = "combobox";
|
|
22
24
|
this.#internals.ariaHasPopup = "dialog";
|
|
23
|
-
this.shadowRoot = this.attachShadow({ mode: '
|
|
25
|
+
this.shadowRoot = this.attachShadow({ mode: 'open', delegatesFocus: true }); //delegatesFocus: true
|
|
24
26
|
this.#markup = new Combobox_markup_js_1.ComboboxMarkup(this.shadowRoot, this.#internals);
|
|
25
|
-
|
|
27
|
+
// console.log(ComboboxMarkup.markup)
|
|
28
|
+
this.shadowRoot.appendChild(Combobox_markup_js_1.ComboboxMarkup.markup.content.cloneNode(true));
|
|
29
|
+
// this.shadowRoot.innerHTML = ComboboxMarkup.template;
|
|
26
30
|
this.shadowRoot.adoptedStyleSheets = _a.styleSheet;
|
|
27
31
|
this.#observer = new MutationObserver(this.#onOptionsChanges);
|
|
32
|
+
this.#markup.connect();
|
|
28
33
|
}
|
|
34
|
+
// static c = false
|
|
29
35
|
// Lifecycle callbacks
|
|
30
36
|
connectedCallback() {
|
|
31
|
-
|
|
37
|
+
// super.setAttribute('tabindex', '0');
|
|
38
|
+
this.#markup.onHostConnected();
|
|
39
|
+
this.shadowRoot.addEventListener('optionselectedstatechange', this.#onOptionSelectedStateChanges);
|
|
40
|
+
this.shadowRoot.addEventListener('tagcleared', this.#onClearTag);
|
|
41
|
+
// this.#onOptionsChanges([{ addedNodes: Array.from(this.children) }] as unknown as MutationRecord[]);
|
|
32
42
|
this.#initialAttributesSynchronization();
|
|
33
|
-
this.#
|
|
34
|
-
this
|
|
35
|
-
this.#markup.clearAllButton.addEventListener('click', this.#
|
|
43
|
+
this.#observer.observe(this.#markup.optionsContainer, _a.observerOptions);
|
|
44
|
+
this.addEventListener('keydown', this.#onKeyDown);
|
|
45
|
+
this.#markup.clearAllButton.addEventListener('click', this.#onClearAll);
|
|
36
46
|
this.#markup.searchInput.addEventListener('input', this.#onInput);
|
|
47
|
+
this.#markup.dropdown.addEventListener('toggle', this.#onPickerToggle);
|
|
48
|
+
this.#setValidityAndFormValue();
|
|
49
|
+
// if (!HTMLComboboxElement.c) {
|
|
50
|
+
// HTMLComboboxElement.c = true;
|
|
51
|
+
// this.showPicker()
|
|
52
|
+
// }
|
|
53
|
+
}
|
|
54
|
+
insertBefore = (node, referenceNode) => {
|
|
55
|
+
// Since we just move options to the #markup.optionsContainer, they are no more part of this children
|
|
56
|
+
// next time, when someone is calling this(combo-box).insertBefore, an error will be thrown:
|
|
57
|
+
// Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
|
|
58
|
+
// Here we overwrite this method, and if new node is HTMLComboboxOptionElement,
|
|
59
|
+
// we just delegate this job to the real option parent: optionsContainer
|
|
60
|
+
if (node instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement || node instanceof HTMLOptGroupElement) {
|
|
61
|
+
this.#markup.optionsContainer?.insertBefore(node, referenceNode);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
super.insertBefore(node, referenceNode);
|
|
65
|
+
}
|
|
66
|
+
return node;
|
|
67
|
+
};
|
|
68
|
+
appendChild(node) {
|
|
69
|
+
return this.insertBefore(node, null);
|
|
70
|
+
}
|
|
71
|
+
removeChild(child) {
|
|
72
|
+
// console.log(child, 'removed')
|
|
73
|
+
return child;
|
|
74
|
+
}
|
|
75
|
+
get changed() {
|
|
76
|
+
return this.#changed;
|
|
37
77
|
}
|
|
38
78
|
disconnectedCallback() {
|
|
39
79
|
this.#observer.disconnect();
|
|
40
80
|
this.#markup.disconnect();
|
|
41
|
-
this
|
|
81
|
+
this.removeEventListener('keydown', this.#onKeyDown);
|
|
82
|
+
this.#markup.clearAllButton.removeEventListener('click', this.#onClearAll);
|
|
42
83
|
this.#markup.searchInput.removeEventListener('input', this.#onInput);
|
|
84
|
+
this.#markup.dropdown.removeEventListener('toggle', this.#onPickerToggle);
|
|
85
|
+
this.shadowRoot.removeEventListener('optionselectedstatechange', this.#onOptionSelectedStateChanges);
|
|
86
|
+
this.shadowRoot.removeEventListener('tagcleared', this.#onClearTag);
|
|
43
87
|
}
|
|
44
88
|
formResetCallback() {
|
|
45
|
-
this.#values = new Set;
|
|
46
89
|
this.selectedOptions.forEach(option => option.selected = false);
|
|
47
|
-
this
|
|
48
|
-
this.#
|
|
49
|
-
this.dispatchEvent(new Event('change'));
|
|
90
|
+
this.dispatchEvent(new Event('reset'));
|
|
91
|
+
requestAnimationFrame(() => this.#markup.searchInput?.focus());
|
|
50
92
|
}
|
|
51
|
-
formDisabledCallback(
|
|
52
|
-
|
|
93
|
+
formDisabledCallback() {
|
|
94
|
+
// toDo
|
|
95
|
+
// when inside fieldset, this callback is only invoked for the first time
|
|
96
|
+
// isDisabled: boolean
|
|
53
97
|
}
|
|
54
98
|
// Instance properties
|
|
55
99
|
// <combo-box> specific properties
|
|
@@ -66,22 +110,17 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
66
110
|
value = '';
|
|
67
111
|
value = String(value);
|
|
68
112
|
super.setAttribute('query', value);
|
|
69
|
-
|
|
70
|
-
this.#markup.searchInput.value = value;
|
|
71
|
-
}
|
|
113
|
+
this.#markup?.setInputValue(value);
|
|
72
114
|
}
|
|
73
115
|
get placeholder() {
|
|
74
116
|
return this.getAttribute('placeholder');
|
|
75
117
|
}
|
|
76
118
|
set placeholder(value) {
|
|
77
119
|
if (value == null)
|
|
78
|
-
value = '';
|
|
120
|
+
value = ' ';
|
|
79
121
|
value = String(value);
|
|
80
122
|
super.setAttribute('placeholder', value);
|
|
81
|
-
|
|
82
|
-
this.#markup.placeholder.innerText = value;
|
|
83
|
-
this.#markup.searchInput.placeholder = value;
|
|
84
|
-
}
|
|
123
|
+
this.#markup?.setPlaceholder(value);
|
|
85
124
|
}
|
|
86
125
|
get clearable() {
|
|
87
126
|
return this.hasAttribute('clearable');
|
|
@@ -107,7 +146,9 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
107
146
|
}
|
|
108
147
|
set disabled(value) {
|
|
109
148
|
this.#internals.ariaDisabled = String(value);
|
|
110
|
-
|
|
149
|
+
value = (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value);
|
|
150
|
+
super.toggleAttribute('disabled', value);
|
|
151
|
+
super.toggleAttribute('inert', value);
|
|
111
152
|
}
|
|
112
153
|
get form() {
|
|
113
154
|
return this.#internals.form;
|
|
@@ -158,34 +199,11 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
158
199
|
set value(value) {
|
|
159
200
|
if (this.value === value || typeof value !== 'string')
|
|
160
201
|
return;
|
|
161
|
-
const prevValue = new Set(this.#values);
|
|
162
|
-
this.#values = new Set;
|
|
163
202
|
const values = value.split(',').filter(Boolean);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (this.#values.size === 0) {
|
|
169
|
-
values.length = 1;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
values.length = 0;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
for (const key of values) {
|
|
176
|
-
const option = this.#markup.getOptionByValue(key);
|
|
177
|
-
if (option)
|
|
178
|
-
this.#selectOption(option);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
for (const key of prevValue) {
|
|
182
|
-
if (this.#values.has(key))
|
|
183
|
-
continue;
|
|
184
|
-
const option = this.#markup.getOptionByValue(key);
|
|
185
|
-
const tag = this.#markup.getTagByValue(key);
|
|
186
|
-
tag?.remove();
|
|
187
|
-
option?.toggleAttribute('selected', false);
|
|
188
|
-
}
|
|
203
|
+
this.#values = new Set(values);
|
|
204
|
+
this.#markup.options.forEach(option => {
|
|
205
|
+
const value = option.value;
|
|
206
|
+
option.selected = this.#values.has(value);
|
|
189
207
|
});
|
|
190
208
|
}
|
|
191
209
|
// Instance methods
|
|
@@ -232,91 +250,152 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
232
250
|
}
|
|
233
251
|
}
|
|
234
252
|
// Internal
|
|
235
|
-
#onInput = (event) => {
|
|
236
|
-
if (!this.searchable && this.filterable) {
|
|
237
|
-
if (event.target && event.target instanceof HTMLInputElement) {
|
|
238
|
-
this.#markup.sort(event.target.value);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
253
|
#onOptionsChanges = (records) => {
|
|
254
|
+
// console.log(records)
|
|
243
255
|
records.forEach(record => {
|
|
244
|
-
record.
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.#selectOption(node);
|
|
253
|
-
}
|
|
256
|
+
record.removedNodes.forEach(option => {
|
|
257
|
+
if (option instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
|
|
258
|
+
// console.log(e)
|
|
259
|
+
const value = option.value;
|
|
260
|
+
if (this.#values.has(value)) {
|
|
261
|
+
this.#values.delete(value);
|
|
262
|
+
const control = this.#markup.getTagByValue(value);
|
|
263
|
+
control?.remove();
|
|
254
264
|
}
|
|
255
265
|
}
|
|
256
|
-
if (node instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement || node instanceof HTMLOptGroupElement) {
|
|
257
|
-
this.#markup.optionsContainer.append(node);
|
|
258
|
-
}
|
|
259
266
|
});
|
|
267
|
+
// record.removedNodes.forEach(node => {
|
|
268
|
+
// console.log(node);
|
|
269
|
+
// })
|
|
260
270
|
});
|
|
261
|
-
this.#markup.invalidateOptionsCache();
|
|
262
|
-
this.#setValidityAndFormValue();
|
|
263
271
|
};
|
|
264
|
-
#
|
|
265
|
-
|
|
266
|
-
return;
|
|
272
|
+
#onOptionSelectedStateChanges = (event) => {
|
|
273
|
+
const option = event.target;
|
|
267
274
|
const value = option.value;
|
|
268
|
-
|
|
269
|
-
option.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (this.#values.has(option.value))
|
|
282
|
-
return;
|
|
283
|
-
if (!this.multiple) {
|
|
284
|
-
event.stopPropagation();
|
|
285
|
-
this.#values.forEach(value => {
|
|
286
|
-
this.#markup.getTagByValue(value)?.remove();
|
|
287
|
-
this.#markup.getOptionByValue(value)?.toggleAttribute('selected', false);
|
|
288
|
-
});
|
|
289
|
-
this.#values.clear();
|
|
290
|
-
this.#markup.tagsContainer.replaceChildren();
|
|
291
|
-
}
|
|
292
|
-
this.#selectOption(option);
|
|
275
|
+
// console.log(event, value, option)
|
|
276
|
+
if (option.selected) {
|
|
277
|
+
if (!this.multiple) {
|
|
278
|
+
this.#values.forEach(value => {
|
|
279
|
+
const prevOption = this.#markup.getOptionByValue(value);
|
|
280
|
+
if (prevOption) {
|
|
281
|
+
prevOption.selected = false;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (!this.#values.has(value)) {
|
|
286
|
+
this.#values.add(value);
|
|
287
|
+
this.#markup.createAndAppendTag(option);
|
|
293
288
|
this.#setValidityAndFormValue();
|
|
294
289
|
this.dispatchEvent(new Event('change'));
|
|
295
290
|
}
|
|
296
291
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const target = event.target;
|
|
300
|
-
if (target && target instanceof HTMLElement) {
|
|
301
|
-
const tag = target.closest('box-tag');
|
|
302
|
-
if (tag) {
|
|
303
|
-
const value = tag.getAttribute('value');
|
|
304
|
-
const option = this.#markup.getOptionByValue(value);
|
|
305
|
-
option.removeAttribute('selected');
|
|
292
|
+
else {
|
|
293
|
+
if (this.#values.has(value)) {
|
|
306
294
|
this.#values.delete(value);
|
|
307
|
-
|
|
295
|
+
const control = this.#markup.getTagByValue(value);
|
|
296
|
+
control?.remove();
|
|
308
297
|
this.#setValidityAndFormValue();
|
|
309
298
|
this.dispatchEvent(new Event('change'));
|
|
310
299
|
}
|
|
311
300
|
}
|
|
312
301
|
};
|
|
313
|
-
#
|
|
302
|
+
#onClearTag = (event) => {
|
|
303
|
+
const target = event.target;
|
|
304
|
+
if (target) {
|
|
305
|
+
const option = this.#markup.getOptionByValue(target.value);
|
|
306
|
+
if (option)
|
|
307
|
+
option.selected = false;
|
|
308
|
+
requestAnimationFrame(() => {
|
|
309
|
+
if (this.#values.size) {
|
|
310
|
+
this.focus();
|
|
311
|
+
}
|
|
312
|
+
else if (this.searchable || this.filterable) {
|
|
313
|
+
this.#markup.searchInput?.focus();
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
this.focus();
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
#onClearAll = () => {
|
|
314
322
|
this.formResetCallback();
|
|
315
323
|
};
|
|
324
|
+
#onPickerToggle = (event) => {
|
|
325
|
+
const state = Reflect.get(event, 'newState');
|
|
326
|
+
const oldState = Reflect.get(event, 'oldState');
|
|
327
|
+
if (state === oldState)
|
|
328
|
+
return;
|
|
329
|
+
// console.log(event)
|
|
330
|
+
if (state === 'open') {
|
|
331
|
+
this.#prevValue = this.value;
|
|
332
|
+
this.#changed = true;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
this.#changed = this.#prevValue !== this.value;
|
|
336
|
+
this.dispatchEvent(new Event('close'));
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
#onKeyDown = (event) => {
|
|
340
|
+
if (this.#internals.ariaExpanded !== 'true')
|
|
341
|
+
return;
|
|
342
|
+
const activeElement = this.shadowRoot.activeElement;
|
|
343
|
+
if (!activeElement) {
|
|
344
|
+
// ??? how we should react ???
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (activeElement === this.#markup.searchInput && event.key === 'Enter') {
|
|
348
|
+
event.stopPropagation();
|
|
349
|
+
if (!this.searchable && this.filterable) {
|
|
350
|
+
console.log('sss');
|
|
351
|
+
this.#markup.sort(this.#markup.searchInput.value);
|
|
352
|
+
}
|
|
353
|
+
if (this.searchable) {
|
|
354
|
+
this.dispatchEvent(new Event('search'));
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (event.key === 'Enter' && activeElement instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
|
|
359
|
+
if (!activeElement.selected) {
|
|
360
|
+
event.stopPropagation();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (event.key === 'Enter' && activeElement.part.contains('clear-tag')) {
|
|
365
|
+
// @ts-ignore
|
|
366
|
+
// this.#onClearTag(event);
|
|
367
|
+
// event.stopPropagation();
|
|
368
|
+
// event.preventDefault()
|
|
369
|
+
// @ts-ignore
|
|
370
|
+
activeElement.click();
|
|
371
|
+
// event.stopPropagation();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (event.key === 'Escape' || event.key === 'Enter') {
|
|
375
|
+
this.#markup.closeDropdown();
|
|
376
|
+
this.blur();
|
|
377
|
+
}
|
|
378
|
+
// console.log(event, this.#internals.ariaExpanded)
|
|
379
|
+
// if (event.key !== 'Enter') return;
|
|
380
|
+
};
|
|
381
|
+
#onInput = () => {
|
|
382
|
+
this.query = this.#markup.searchInput.value;
|
|
383
|
+
if (!this.searchable && this.filterable) {
|
|
384
|
+
this.#markup.sort(this.#markup.searchInput?.value || '');
|
|
385
|
+
}
|
|
386
|
+
};
|
|
316
387
|
#setValidityAndFormValue() {
|
|
388
|
+
this.#markup.clearAllButton?.toggleAttribute('disabled', !Boolean(this.#values.size));
|
|
389
|
+
let empty = false;
|
|
390
|
+
if (this.#values.size === 0)
|
|
391
|
+
empty = true;
|
|
392
|
+
if (this.#values.size > 0 && !this.clearable && !this.multiple && (this.searchable || this.filterable)) {
|
|
393
|
+
empty = true;
|
|
394
|
+
}
|
|
395
|
+
this.#markup.searchInput?.toggleAttribute('autofocus', empty);
|
|
317
396
|
this.#internals.setFormValue(this.value);
|
|
318
397
|
if (this.required && this.value === '') {
|
|
319
|
-
this.#internals.setValidity({ valueMissing: true });
|
|
398
|
+
this.#internals.setValidity({ valueMissing: true }, 'Value missing');
|
|
320
399
|
}
|
|
321
400
|
else {
|
|
322
401
|
this.#internals.setValidity({});
|
|
@@ -324,6 +403,7 @@ class HTMLComboboxElement extends HTMLElement {
|
|
|
324
403
|
}
|
|
325
404
|
#initialAttributesSynchronization() {
|
|
326
405
|
for (const key of _a.OWN_IDL) {
|
|
406
|
+
// @ts-ignore
|
|
327
407
|
this[key] = this.getAttribute(key);
|
|
328
408
|
}
|
|
329
409
|
}
|
|
@@ -4,16 +4,68 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.HTMLComboboxOptionElement = void 0;
|
|
5
5
|
const Boolean_attribute_value_normalizer_js_1 = require("./Boolean.attribute.value.normalizer.js");
|
|
6
6
|
class HTMLComboboxOptionElement extends HTMLElement {
|
|
7
|
-
static OWN_IDL = new Set(['value', 'label', 'selected']);
|
|
7
|
+
static OWN_IDL = new Set(['value', 'label', 'selected', 'disabled']);
|
|
8
|
+
static EventInit = { bubbles: true, cancelable: true, composed: true };
|
|
9
|
+
static captureFocus(event) {
|
|
10
|
+
if (event.relatedTarget && event.relatedTarget instanceof _a) {
|
|
11
|
+
event.stopPropagation();
|
|
12
|
+
event.preventDefault();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
static onNavigate(event) {
|
|
16
|
+
// event.stopPropagation();
|
|
17
|
+
// const target = event.target as HTMLComboboxOptionElement;
|
|
18
|
+
// if (event.key === 'Enter') {
|
|
19
|
+
// event.preventDefault();
|
|
20
|
+
// target.click();
|
|
21
|
+
// return;
|
|
22
|
+
// }
|
|
23
|
+
// if (event.key === 'Tab') return;
|
|
24
|
+
// event.preventDefault();
|
|
25
|
+
// console.log(event.target)
|
|
26
|
+
if (!event.target ||
|
|
27
|
+
!(event.target instanceof _a) ||
|
|
28
|
+
event.key === 'Tab' ||
|
|
29
|
+
event.key === 'Enter')
|
|
30
|
+
return;
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
if (event.key === 'ArrowDown') {
|
|
33
|
+
const next = event.target.nextElementSibling;
|
|
34
|
+
if (next && next instanceof _a) {
|
|
35
|
+
next.focus();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (event.key === 'ArrowUp') {
|
|
39
|
+
const prev = event.target.previousElementSibling;
|
|
40
|
+
if (prev && prev instanceof _a) {
|
|
41
|
+
prev.focus();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
8
45
|
connectedCallback() {
|
|
46
|
+
this.addEventListener('keydown', _a.onNavigate);
|
|
47
|
+
this.addEventListener('focusout', _a.captureFocus);
|
|
48
|
+
this.addEventListener('click', this.#toggleSelection);
|
|
9
49
|
this.#initialAttributesSynchronization();
|
|
10
50
|
this.part.add('option');
|
|
11
51
|
super.setAttribute('tabindex', "0");
|
|
12
52
|
super.setAttribute('role', "option");
|
|
13
|
-
if (!this.value)
|
|
14
|
-
this.value = this.
|
|
15
|
-
|
|
53
|
+
if (!this.value)
|
|
54
|
+
this.value = this.label;
|
|
55
|
+
if (!this.textContent)
|
|
56
|
+
this.textContent = this.value;
|
|
57
|
+
this.dispatchEvent(new Event('optionselectedstatechange', _a.EventInit));
|
|
16
58
|
}
|
|
59
|
+
disconnectedCallback() {
|
|
60
|
+
this.removeEventListener('click', this.#toggleSelection);
|
|
61
|
+
this.removeEventListener('keydown', _a.onNavigate);
|
|
62
|
+
this.removeEventListener('focusout', _a.captureFocus);
|
|
63
|
+
}
|
|
64
|
+
#toggleSelection = (event) => {
|
|
65
|
+
// console.log('#toggleSelection', this.value)
|
|
66
|
+
event.stopPropagation();
|
|
67
|
+
this.selected = !this.selected;
|
|
68
|
+
};
|
|
17
69
|
get value() {
|
|
18
70
|
return this.getAttribute('value');
|
|
19
71
|
}
|
|
@@ -34,15 +86,38 @@ class HTMLComboboxOptionElement extends HTMLElement {
|
|
|
34
86
|
return this.hasAttribute('selected');
|
|
35
87
|
}
|
|
36
88
|
set selected(value) {
|
|
37
|
-
|
|
89
|
+
const prev = this.selected;
|
|
90
|
+
const force = (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value);
|
|
91
|
+
if (prev === force) {
|
|
92
|
+
// console.log(prev, value, this.value)
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
super.toggleAttribute('selected', force);
|
|
96
|
+
this.part.toggle('selected', force);
|
|
97
|
+
// this.dispatchEvent(new Event('optionselectedstatechange', HTMLComboboxOptionElement.EventInit));
|
|
98
|
+
if (this.isConnected) {
|
|
99
|
+
// console.log('new optionselectedstatechange', this.value)
|
|
100
|
+
this.dispatchEvent(new Event('optionselectedstatechange', _a.EventInit));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
get disabled() {
|
|
104
|
+
return this.hasAttribute('disabled');
|
|
105
|
+
}
|
|
106
|
+
set disabled(value) {
|
|
107
|
+
const force = (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value);
|
|
108
|
+
super.toggleAttribute('disabled', force);
|
|
109
|
+
this.part.toggle('disabled', force);
|
|
110
|
+
super.toggleAttribute('inert', force);
|
|
38
111
|
}
|
|
39
112
|
#initialAttributesSynchronization() {
|
|
40
113
|
for (const key of _a.OWN_IDL) {
|
|
114
|
+
// @ts-ignore
|
|
41
115
|
this[key] = this.getAttribute(key);
|
|
42
116
|
}
|
|
43
117
|
}
|
|
44
118
|
setAttribute(name, value) {
|
|
45
119
|
if (_a.OWN_IDL.has(name)) {
|
|
120
|
+
// @ts-ignore
|
|
46
121
|
this[name] = value;
|
|
47
122
|
}
|
|
48
123
|
else {
|
|
@@ -51,12 +126,18 @@ class HTMLComboboxOptionElement extends HTMLElement {
|
|
|
51
126
|
}
|
|
52
127
|
removeAttribute(name) {
|
|
53
128
|
if (_a.OWN_IDL.has(name)) {
|
|
129
|
+
// @ts-ignore
|
|
54
130
|
this[name] = null;
|
|
55
131
|
}
|
|
56
132
|
else {
|
|
57
133
|
super.removeAttribute(name);
|
|
58
134
|
}
|
|
59
135
|
}
|
|
136
|
+
toggleAttribute(name, force) {
|
|
137
|
+
if (name === 'selected')
|
|
138
|
+
this.part.toggle(name, force);
|
|
139
|
+
return super.toggleAttribute(name, force);
|
|
140
|
+
}
|
|
60
141
|
}
|
|
61
142
|
exports.HTMLComboboxOptionElement = HTMLComboboxOptionElement;
|
|
62
143
|
_a = HTMLComboboxOptionElement;
|
|
@@ -2,19 +2,39 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HTMLComboboxTagElement = void 0;
|
|
4
4
|
class HTMLComboboxTagElement extends HTMLElement {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
static EventInit = { bubbles: true, cancelable: true, composed: true };
|
|
6
|
+
get value() {
|
|
7
|
+
return this.getAttribute('value') || '';
|
|
7
8
|
}
|
|
8
9
|
connectedCallback() {
|
|
9
10
|
this.part.add('tag');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const control = this.querySelector('[part*="clear-tag"]');
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
if (!this.hasAttribute('visible')) {
|
|
14
|
+
super.setAttribute('tabindex', '0');
|
|
15
|
+
}
|
|
16
|
+
control?.addEventListener('focusout', HTMLComboboxTagElement.captureFocus);
|
|
17
|
+
control?.addEventListener('click', HTMLComboboxTagElement.onClearTag);
|
|
18
|
+
const root = this.getRootNode();
|
|
19
|
+
if (root instanceof ShadowRoot) {
|
|
20
|
+
if (root.host.hasAttribute('multiple') && !control) {
|
|
21
|
+
throw new Error(`A <button> with part="clear-tag" is required for <combo-box> with multiple attribute`);
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
24
|
}
|
|
25
|
+
disconnectedCallback() {
|
|
26
|
+
const control = this.querySelector('[part*="clear-tag"]');
|
|
27
|
+
control?.removeEventListener('focusout', HTMLComboboxTagElement.captureFocus);
|
|
28
|
+
control?.removeEventListener('click', HTMLComboboxTagElement.onClearTag);
|
|
29
|
+
}
|
|
30
|
+
static onClearTag(event) {
|
|
31
|
+
const [target] = event.composedPath().filter(el => el instanceof HTMLComboboxTagElement);
|
|
32
|
+
target?.dispatchEvent(new Event('tagcleared', HTMLComboboxTagElement.EventInit));
|
|
33
|
+
}
|
|
34
|
+
static captureFocus(event) {
|
|
35
|
+
event.stopPropagation();
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
}
|
|
18
38
|
}
|
|
19
39
|
exports.HTMLComboboxTagElement = HTMLComboboxTagElement;
|
|
20
40
|
if (!window.customElements.get('box-tag')) {
|
package/dist/cjs/index.js
CHANGED
|
@@ -19,65 +19,3 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
__exportStar(require("./combobox/index.js"), exports);
|
|
22
|
-
// declare global {
|
|
23
|
-
// namespace React {
|
|
24
|
-
// namespace JSX {
|
|
25
|
-
// interface IntrinsicElements {
|
|
26
|
-
// 'combo-box': React.DetailedHTMLProps<Omit<React.HTMLAttributes<HTMLComboboxElement>, 'defaultValue'>,
|
|
27
|
-
// HTMLComboboxElement
|
|
28
|
-
// > & ComboboxJsxAttributes;
|
|
29
|
-
//
|
|
30
|
-
// 'box-option': React.DetailedHTMLProps<
|
|
31
|
-
// React.HTMLAttributes<HTMLComboboxOptionElement>,
|
|
32
|
-
// HTMLComboboxOptionElement>
|
|
33
|
-
// & ComboboxOptionJsxAttributes;
|
|
34
|
-
//
|
|
35
|
-
// 'box-tag': React.DetailedHTMLProps<React.HTMLAttributes<HTMLComboboxTagElement>, HTMLComboboxTagElement>;
|
|
36
|
-
// }
|
|
37
|
-
// }
|
|
38
|
-
// }
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// namespace preact {
|
|
42
|
-
// namespace JSX {
|
|
43
|
-
// interface IntrinsicElements {
|
|
44
|
-
// 'combo-box': preact.HTMLAttributes<HTMLComboboxElement> & ComboboxJsxAttributes;
|
|
45
|
-
// 'box-option': preact.HTMLAttributes<HTMLComboboxOptionElement> & ComboboxOptionJsxAttributes;
|
|
46
|
-
// 'box-tag': preact.HTMLAttributes<HTMLComboboxTagElement>;
|
|
47
|
-
// }
|
|
48
|
-
// }
|
|
49
|
-
// }
|
|
50
|
-
//
|
|
51
|
-
// }
|
|
52
|
-
//
|
|
53
|
-
// declare module 'preact' {
|
|
54
|
-
// namespace JSX {
|
|
55
|
-
// interface IntrinsicElements {
|
|
56
|
-
// 'combo-box': preact.HTMLAttributes<HTMLComboboxElement> & ComboboxJsxAttributes;
|
|
57
|
-
// 'box-option': preact.HTMLAttributes<HTMLComboboxOptionElement> & ComboboxOptionJsxAttributes;
|
|
58
|
-
// 'box-tag': preact.HTMLAttributes<HTMLComboboxTagElement>;
|
|
59
|
-
// }
|
|
60
|
-
// }
|
|
61
|
-
// }
|
|
62
|
-
//
|
|
63
|
-
// // Solid
|
|
64
|
-
// declare module 'solid-js' {
|
|
65
|
-
// namespace JSX {
|
|
66
|
-
// interface IntrinsicElements {
|
|
67
|
-
// 'combo-box': HTMLAttributes<HTMLComboboxElement> & ComboboxJsxAttributes
|
|
68
|
-
// 'box-option': HTMLAttributes<HTMLComboboxOptionElement> & ComboboxOptionJsxAttributes
|
|
69
|
-
// 'box-tag': HTMLAttributes<HTMLElement>
|
|
70
|
-
// }
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
// declare global {
|
|
76
|
-
// namespace JSX {
|
|
77
|
-
// interface IntrinsicElements {
|
|
78
|
-
// 'combo-box': ComboboxJsxAttributes;
|
|
79
|
-
// 'box-option': ComboboxOptionJsxAttributes;
|
|
80
|
-
// 'box-tag': HTMLElement;
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
// }
|