kr-elements 0.0.1-alpha.34 → 0.0.1-alpha.35

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.
@@ -94,7 +94,6 @@ class ComboboxMarkup {
94
94
  try {
95
95
  this.setDropdownPosition(this.#shadowRoot.host.getBoundingClientRect());
96
96
  this.dropdown.style.display = 'flex';
97
- // @ts-ignore
98
97
  this.dropdown.showPopover();
99
98
  this.#internals.ariaExpanded = "true";
100
99
  if (this.tagsContainer?.children.length === 0) {
@@ -108,7 +107,6 @@ class ComboboxMarkup {
108
107
  };
109
108
  closeDropdown() {
110
109
  try {
111
- // @ts-ignore
112
110
  this.dropdown.hidePopover();
113
111
  this.dropdown.style.display = 'none';
114
112
  this.#internals.ariaExpanded = "false";
@@ -137,6 +135,7 @@ class ComboboxMarkup {
137
135
  const clone = relatedNode.cloneNode(true);
138
136
  clone.part.remove(...clone.part.values());
139
137
  clone.part.add(...node.part.values());
138
+ clone.classList.add(...node.classList.values());
140
139
  tag.replaceChild(clone, node);
141
140
  }
142
141
  });
@@ -151,7 +150,7 @@ class ComboboxMarkup {
151
150
  label.textContent = option.label;
152
151
  button = tag.querySelector('[part="clear-tag"]');
153
152
  }
154
- button.setAttribute('value', value);
153
+ button?.setAttribute('value', value);
155
154
  tag.setAttribute('value', value);
156
155
  this.tagsContainer.appendChild(tag);
157
156
  return button;
@@ -264,7 +263,7 @@ class ComboboxMarkup {
264
263
  border-radius: inherit;
265
264
  }
266
265
 
267
- [part*="tag"] {
266
+ box-tag {
268
267
  width: 100%;
269
268
  justify-self: start;
270
269
  box-sizing: border-box;
@@ -279,13 +278,13 @@ class ComboboxMarkup {
279
278
  text-transform: uppercase;
280
279
  }
281
280
 
282
- :host([multiple]) [part*="tag"] {
281
+ :host([multiple]) box-tag {
283
282
  background-color: Highlight;
284
283
  width: fit-content;
285
284
  max-width: 100%;
286
285
  }
287
286
 
288
- [part*="tag-label"] {
287
+ box-tag [part*="tag-label"] {
289
288
  white-space: nowrap;
290
289
  text-overflow: ellipsis;
291
290
  overflow: hidden;
@@ -294,7 +293,7 @@ class ComboboxMarkup {
294
293
  flex-grow: 1;
295
294
  }
296
295
 
297
- :host([multiple]) [part*="tag-label"] {
296
+ :host([multiple]) box-tag [part*="tag-label"] {
298
297
  flex-grow: unset;
299
298
  }
300
299
 
@@ -10,17 +10,18 @@ class HTMLComboboxElement extends HTMLElement {
10
10
  static observerOptions = { childList: true, attributes: false, subtree: false };
11
11
  static styleSheet = [new CSSStyleSheet];
12
12
  static formAssociated = true;
13
- internals;
14
13
  shadowRoot;
14
+ #internals;
15
15
  #observer;
16
16
  #markup;
17
17
  #values = new Set;
18
18
  constructor() {
19
19
  super();
20
- this.internals = this.attachInternals();
21
- this.internals.role = "combobox";
20
+ this.#internals = this.attachInternals();
21
+ this.#internals.role = "combobox";
22
+ this.#internals.ariaHasPopup = "dialog";
22
23
  this.shadowRoot = this.attachShadow({ mode: 'closed', delegatesFocus: true });
23
- this.#markup = new Combobox_markup_js_1.ComboboxMarkup(this.shadowRoot, this.internals);
24
+ this.#markup = new Combobox_markup_js_1.ComboboxMarkup(this.shadowRoot, this.#internals);
24
25
  this.shadowRoot.innerHTML = Combobox_markup_js_1.ComboboxMarkup.template;
25
26
  this.shadowRoot.adoptedStyleSheets = _a.styleSheet;
26
27
  this.#observer = new MutationObserver(this.#onOptionsChanges);
@@ -31,12 +32,14 @@ class HTMLComboboxElement extends HTMLElement {
31
32
  this.#initialAttributesSynchronization();
32
33
  this.#onOptionsChanges([{ addedNodes: Array.from(this.children) }]);
33
34
  this.#observer.observe(this, _a.observerOptions);
34
- this.#markup.clearAllButton.addEventListener('click', this.#onClickClearAllButton);
35
+ this.#markup.clearAllButton.addEventListener('click', this.#onClear);
35
36
  this.#markup.searchInput.addEventListener('input', this.#onInput);
36
37
  }
37
38
  disconnectedCallback() {
38
39
  this.#observer.disconnect();
39
40
  this.#markup.disconnect();
41
+ this.#markup.clearAllButton.removeEventListener('click', this.#onClear);
42
+ this.#markup.searchInput.removeEventListener('input', this.#onInput);
40
43
  }
41
44
  formResetCallback() {
42
45
  this.#values = new Set;
@@ -49,56 +52,10 @@ class HTMLComboboxElement extends HTMLElement {
49
52
  this.disabled = isDisabled;
50
53
  }
51
54
  // Instance properties
52
- // readonly
55
+ // <combo-box> specific properties
53
56
  get valueAsArray() {
54
57
  return Array.from(this.#values);
55
58
  }
56
- get selectedOptions() {
57
- return this.#markup.selectedOptions;
58
- }
59
- get validity() {
60
- return this.internals.validity;
61
- }
62
- get willValidate() {
63
- return this.internals.willValidate;
64
- }
65
- // configurable
66
- get value() {
67
- return this.valueAsArray.join(',');
68
- }
69
- set value(value) {
70
- if (this.value === value || typeof value !== 'string')
71
- return;
72
- const prevValue = new Set(this.#values);
73
- this.#values = new Set;
74
- const values = value.split(',').filter(Boolean);
75
- Promise.resolve(values)
76
- .then(values => {
77
- if (values.length) {
78
- if (!this.multiple) {
79
- if (this.#values.size === 0) {
80
- values.length = 1;
81
- }
82
- else {
83
- values.length = 0;
84
- }
85
- }
86
- for (const key of values) {
87
- const option = this.#markup.getOptionByValue(key);
88
- if (option)
89
- this.#selectOption(option);
90
- }
91
- }
92
- for (const key of prevValue) {
93
- if (this.#values.has(key))
94
- continue;
95
- const option = this.#markup.getOptionByValue(key);
96
- const tag = this.#markup.getTagByValue(key);
97
- tag?.remove();
98
- option?.toggleAttribute('selected', false);
99
- }
100
- });
101
- }
102
59
  get query() {
103
60
  return this.getAttribute('query');
104
61
  }
@@ -132,12 +89,6 @@ class HTMLComboboxElement extends HTMLElement {
132
89
  set clearable(value) {
133
90
  super.toggleAttribute('clearable', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
134
91
  }
135
- get multiple() {
136
- return this.hasAttribute('multiple');
137
- }
138
- set multiple(value) {
139
- super.toggleAttribute('multiple', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
140
- }
141
92
  get filterable() {
142
93
  return this.hasAttribute('filterable');
143
94
  }
@@ -150,21 +101,120 @@ class HTMLComboboxElement extends HTMLElement {
150
101
  set searchable(value) {
151
102
  super.toggleAttribute('searchable', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
152
103
  }
104
+ // <select> specific properties (implements HTMLSelectElement)
153
105
  get disabled() {
154
106
  return this.hasAttribute('disabled');
155
107
  }
156
108
  set disabled(value) {
157
- this.internals.ariaDisabled = String(value);
109
+ this.#internals.ariaDisabled = String(value);
158
110
  super.toggleAttribute('disabled', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
159
111
  }
112
+ get form() {
113
+ return this.#internals.form;
114
+ }
115
+ get labels() {
116
+ return this.#internals.labels;
117
+ }
118
+ get length() {
119
+ return this.#markup.options.length;
120
+ }
121
+ get multiple() {
122
+ return this.hasAttribute('multiple');
123
+ }
124
+ set multiple(value) {
125
+ super.toggleAttribute('multiple', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
126
+ }
127
+ // get options
128
+ // (there is no constructor of HTMLOptionsCollection, need to implement)
160
129
  get required() {
161
130
  return this.hasAttribute('required');
162
131
  }
163
132
  set required(value) {
164
- this.internals.ariaRequired = String(value);
133
+ this.#internals.ariaRequired = String(value);
165
134
  super.toggleAttribute('required', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
166
135
  }
136
+ // selected index is part of HTMLOptionsCollection, see option above
137
+ get selectedOptions() {
138
+ return this.#markup.selectedOptions;
139
+ }
140
+ // get/set size
141
+ // for the original select, this is the same as rowsCount of textarea
142
+ // probably, there are no reasons to this one, but it should be implemented for interface compatibility
143
+ get type() {
144
+ return this.multiple ? "select-multiple" : "select-one";
145
+ }
146
+ get validationMessage() {
147
+ return this.#internals.validationMessage;
148
+ }
149
+ get validity() {
150
+ return this.#internals.validity;
151
+ }
152
+ get willValidate() {
153
+ return this.#internals.willValidate;
154
+ }
155
+ get value() {
156
+ return this.valueAsArray.join(',');
157
+ }
158
+ set value(value) {
159
+ if (this.value === value || typeof value !== 'string')
160
+ return;
161
+ const prevValue = new Set(this.#values);
162
+ this.#values = new Set;
163
+ const values = value.split(',').filter(Boolean);
164
+ Promise.resolve(values)
165
+ .then(values => {
166
+ if (values.length) {
167
+ if (!this.multiple) {
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
+ }
189
+ });
190
+ }
167
191
  // Instance methods
192
+ // <select> specific methods (implements HTMLSelectElement)
193
+ // add()
194
+ checkValidity() {
195
+ this.#internals.checkValidity();
196
+ }
197
+ item(index) {
198
+ return this.#markup.options.item(index);
199
+ }
200
+ // namedItem()
201
+ // !!! Conflicts with node.remove()
202
+ // remove(index: number)
203
+ reportValidity() {
204
+ this.#internals.reportValidity();
205
+ }
206
+ setCustomValidity(message) {
207
+ if (message === '') {
208
+ this.#internals.setValidity({});
209
+ }
210
+ else {
211
+ this.#internals.setValidity({ customError: true }, message);
212
+ }
213
+ }
214
+ showPicker() {
215
+ this.#markup.showDropdown();
216
+ }
217
+ // Overwritten methods
168
218
  setAttribute(name, value) {
169
219
  if (_a.OWN_IDL.has(name)) {
170
220
  Reflect.set(this, name, value);
@@ -181,20 +231,6 @@ class HTMLComboboxElement extends HTMLElement {
181
231
  super.removeAttribute(name);
182
232
  }
183
233
  }
184
- reportValidity() {
185
- this.internals.reportValidity();
186
- }
187
- checkValidity() {
188
- this.internals.checkValidity();
189
- }
190
- setCustomValidity(message) {
191
- if (message === '') {
192
- this.internals.setValidity({});
193
- }
194
- else {
195
- this.internals.setValidity({ customError: true }, message);
196
- }
197
- }
198
234
  // Internal
199
235
  #onInput = (event) => {
200
236
  if (!this.searchable && this.filterable) {
@@ -232,76 +268,63 @@ class HTMLComboboxElement extends HTMLElement {
232
268
  this.#values.add(value);
233
269
  option.toggleAttribute('selected', true);
234
270
  const control = this.#markup.createAndAppendTag(option);
235
- control?.addEventListener('click', this.#onClickTagClearButton);
271
+ control?.addEventListener('click', this.#onClearTag);
236
272
  if (!this.multiple) {
237
273
  this.#markup.closeDropdown();
238
274
  }
239
275
  }
240
276
  #onSelectOption = (event) => {
241
- let option;
242
- if (event.target instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement) {
243
- option = event.target;
244
- }
245
- else {
246
- option = event.composedPath()
247
- .find(el => el instanceof HTML_combobox_option_element_js_1.HTMLComboboxOptionElement);
248
- }
249
- if (option) {
250
- if (this.#values.has(option.value))
251
- return;
252
- if (!this.multiple) {
253
- this.#values.forEach(value => {
254
- this.#markup.getTagByValue(value)?.remove();
255
- this.#markup.getOptionByValue(value)?.toggleAttribute('selected', false);
256
- });
257
- this.#values.clear();
258
- this.#markup.tagsContainer.replaceChildren();
259
- }
260
- if (!this.multiple) {
261
- event.stopPropagation();
277
+ const target = event.target;
278
+ if (target && target instanceof HTMLElement) {
279
+ const option = target.closest('box-option');
280
+ if (option) {
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);
293
+ this.#setValidityAndFormValue();
294
+ this.dispatchEvent(new Event('change'));
262
295
  }
263
- this.#selectOption(option);
264
- this.#setValidityAndFormValue();
265
- this.dispatchEvent(new Event('change'));
266
296
  }
267
297
  };
268
- #onClickTagClearButton = (event) => {
269
- let button;
270
- if (event.target instanceof HTMLButtonElement) {
271
- button = event.target;
272
- }
273
- else {
274
- button = event.composedPath()
275
- .find(el => {
276
- return el instanceof HTMLElement && el.part.contains('clear-tag');
277
- });
278
- }
279
- if (button) {
280
- const value = button.value;
281
- const option = this.#markup.getOptionByValue(value);
282
- const tag = this.#markup.getTagByValue(value);
283
- option.removeAttribute('selected');
284
- this.#values.delete(value);
285
- tag.remove();
286
- this.#setValidityAndFormValue();
287
- this.dispatchEvent(new Event('change'));
298
+ #onClearTag = (event) => {
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');
306
+ this.#values.delete(value);
307
+ tag.remove();
308
+ this.#setValidityAndFormValue();
309
+ this.dispatchEvent(new Event('change'));
310
+ }
288
311
  }
289
312
  };
290
- #onClickClearAllButton = () => {
313
+ #onClear = () => {
291
314
  this.formResetCallback();
292
315
  };
293
316
  #setValidityAndFormValue() {
294
- this.internals.setFormValue(this.value);
317
+ this.#internals.setFormValue(this.value);
295
318
  if (this.required && this.value === '') {
296
- this.internals.setValidity({ valueMissing: true });
319
+ this.#internals.setValidity({ valueMissing: true });
297
320
  }
298
321
  else {
299
- this.internals.setValidity({});
322
+ this.#internals.setValidity({});
300
323
  }
301
324
  }
302
325
  #initialAttributesSynchronization() {
303
326
  for (const key of _a.OWN_IDL) {
304
- Reflect.set(this, key, this.getAttribute(key));
327
+ this[key] = this.getAttribute(key);
305
328
  }
306
329
  }
307
330
  static staticLoadCssByUrls(urls) {
@@ -91,7 +91,6 @@ export class ComboboxMarkup {
91
91
  try {
92
92
  this.setDropdownPosition(this.#shadowRoot.host.getBoundingClientRect());
93
93
  this.dropdown.style.display = 'flex';
94
- // @ts-ignore
95
94
  this.dropdown.showPopover();
96
95
  this.#internals.ariaExpanded = "true";
97
96
  if (this.tagsContainer?.children.length === 0) {
@@ -105,7 +104,6 @@ export class ComboboxMarkup {
105
104
  };
106
105
  closeDropdown() {
107
106
  try {
108
- // @ts-ignore
109
107
  this.dropdown.hidePopover();
110
108
  this.dropdown.style.display = 'none';
111
109
  this.#internals.ariaExpanded = "false";
@@ -134,6 +132,7 @@ export class ComboboxMarkup {
134
132
  const clone = relatedNode.cloneNode(true);
135
133
  clone.part.remove(...clone.part.values());
136
134
  clone.part.add(...node.part.values());
135
+ clone.classList.add(...node.classList.values());
137
136
  tag.replaceChild(clone, node);
138
137
  }
139
138
  });
@@ -148,7 +147,7 @@ export class ComboboxMarkup {
148
147
  label.textContent = option.label;
149
148
  button = tag.querySelector('[part="clear-tag"]');
150
149
  }
151
- button.setAttribute('value', value);
150
+ button?.setAttribute('value', value);
152
151
  tag.setAttribute('value', value);
153
152
  this.tagsContainer.appendChild(tag);
154
153
  return button;
@@ -261,7 +260,7 @@ export class ComboboxMarkup {
261
260
  border-radius: inherit;
262
261
  }
263
262
 
264
- [part*="tag"] {
263
+ box-tag {
265
264
  width: 100%;
266
265
  justify-self: start;
267
266
  box-sizing: border-box;
@@ -276,13 +275,13 @@ export class ComboboxMarkup {
276
275
  text-transform: uppercase;
277
276
  }
278
277
 
279
- :host([multiple]) [part*="tag"] {
278
+ :host([multiple]) box-tag {
280
279
  background-color: Highlight;
281
280
  width: fit-content;
282
281
  max-width: 100%;
283
282
  }
284
283
 
285
- [part*="tag-label"] {
284
+ box-tag [part*="tag-label"] {
286
285
  white-space: nowrap;
287
286
  text-overflow: ellipsis;
288
287
  overflow: hidden;
@@ -291,7 +290,7 @@ export class ComboboxMarkup {
291
290
  flex-grow: 1;
292
291
  }
293
292
 
294
- :host([multiple]) [part*="tag-label"] {
293
+ :host([multiple]) box-tag [part*="tag-label"] {
295
294
  flex-grow: unset;
296
295
  }
297
296
 
@@ -6,17 +6,18 @@ export class HTMLComboboxElement extends HTMLElement {
6
6
  static observerOptions = { childList: true, attributes: false, subtree: false };
7
7
  static styleSheet = [new CSSStyleSheet];
8
8
  static formAssociated = true;
9
- internals;
10
9
  shadowRoot;
10
+ #internals;
11
11
  #observer;
12
12
  #markup;
13
13
  #values = new Set;
14
14
  constructor() {
15
15
  super();
16
- this.internals = this.attachInternals();
17
- this.internals.role = "combobox";
16
+ this.#internals = this.attachInternals();
17
+ this.#internals.role = "combobox";
18
+ this.#internals.ariaHasPopup = "dialog";
18
19
  this.shadowRoot = this.attachShadow({ mode: 'closed', delegatesFocus: true });
19
- this.#markup = new ComboboxMarkup(this.shadowRoot, this.internals);
20
+ this.#markup = new ComboboxMarkup(this.shadowRoot, this.#internals);
20
21
  this.shadowRoot.innerHTML = ComboboxMarkup.template;
21
22
  this.shadowRoot.adoptedStyleSheets = HTMLComboboxElement.styleSheet;
22
23
  this.#observer = new MutationObserver(this.#onOptionsChanges);
@@ -27,12 +28,14 @@ export class HTMLComboboxElement extends HTMLElement {
27
28
  this.#initialAttributesSynchronization();
28
29
  this.#onOptionsChanges([{ addedNodes: Array.from(this.children) }]);
29
30
  this.#observer.observe(this, HTMLComboboxElement.observerOptions);
30
- this.#markup.clearAllButton.addEventListener('click', this.#onClickClearAllButton);
31
+ this.#markup.clearAllButton.addEventListener('click', this.#onClear);
31
32
  this.#markup.searchInput.addEventListener('input', this.#onInput);
32
33
  }
33
34
  disconnectedCallback() {
34
35
  this.#observer.disconnect();
35
36
  this.#markup.disconnect();
37
+ this.#markup.clearAllButton.removeEventListener('click', this.#onClear);
38
+ this.#markup.searchInput.removeEventListener('input', this.#onInput);
36
39
  }
37
40
  formResetCallback() {
38
41
  this.#values = new Set;
@@ -45,56 +48,10 @@ export class HTMLComboboxElement extends HTMLElement {
45
48
  this.disabled = isDisabled;
46
49
  }
47
50
  // Instance properties
48
- // readonly
51
+ // <combo-box> specific properties
49
52
  get valueAsArray() {
50
53
  return Array.from(this.#values);
51
54
  }
52
- get selectedOptions() {
53
- return this.#markup.selectedOptions;
54
- }
55
- get validity() {
56
- return this.internals.validity;
57
- }
58
- get willValidate() {
59
- return this.internals.willValidate;
60
- }
61
- // configurable
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
55
  get query() {
99
56
  return this.getAttribute('query');
100
57
  }
@@ -128,12 +85,6 @@ export class HTMLComboboxElement extends HTMLElement {
128
85
  set clearable(value) {
129
86
  super.toggleAttribute('clearable', toBoolean(value));
130
87
  }
131
- get multiple() {
132
- return this.hasAttribute('multiple');
133
- }
134
- set multiple(value) {
135
- super.toggleAttribute('multiple', toBoolean(value));
136
- }
137
88
  get filterable() {
138
89
  return this.hasAttribute('filterable');
139
90
  }
@@ -146,21 +97,120 @@ export class HTMLComboboxElement extends HTMLElement {
146
97
  set searchable(value) {
147
98
  super.toggleAttribute('searchable', toBoolean(value));
148
99
  }
100
+ // <select> specific properties (implements HTMLSelectElement)
149
101
  get disabled() {
150
102
  return this.hasAttribute('disabled');
151
103
  }
152
104
  set disabled(value) {
153
- this.internals.ariaDisabled = String(value);
105
+ this.#internals.ariaDisabled = String(value);
154
106
  super.toggleAttribute('disabled', toBoolean(value));
155
107
  }
108
+ get form() {
109
+ return this.#internals.form;
110
+ }
111
+ get labels() {
112
+ return this.#internals.labels;
113
+ }
114
+ get length() {
115
+ return this.#markup.options.length;
116
+ }
117
+ get multiple() {
118
+ return this.hasAttribute('multiple');
119
+ }
120
+ set multiple(value) {
121
+ super.toggleAttribute('multiple', toBoolean(value));
122
+ }
123
+ // get options
124
+ // (there is no constructor of HTMLOptionsCollection, need to implement)
156
125
  get required() {
157
126
  return this.hasAttribute('required');
158
127
  }
159
128
  set required(value) {
160
- this.internals.ariaRequired = String(value);
129
+ this.#internals.ariaRequired = String(value);
161
130
  super.toggleAttribute('required', toBoolean(value));
162
131
  }
132
+ // selected index is part of HTMLOptionsCollection, see option above
133
+ get selectedOptions() {
134
+ return this.#markup.selectedOptions;
135
+ }
136
+ // get/set size
137
+ // for the original select, this is the same as rowsCount of textarea
138
+ // probably, there are no reasons to this one, but it should be implemented for interface compatibility
139
+ get type() {
140
+ return this.multiple ? "select-multiple" : "select-one";
141
+ }
142
+ get validationMessage() {
143
+ return this.#internals.validationMessage;
144
+ }
145
+ get validity() {
146
+ return this.#internals.validity;
147
+ }
148
+ get willValidate() {
149
+ return this.#internals.willValidate;
150
+ }
151
+ get value() {
152
+ return this.valueAsArray.join(',');
153
+ }
154
+ set value(value) {
155
+ if (this.value === value || typeof value !== 'string')
156
+ return;
157
+ const prevValue = new Set(this.#values);
158
+ this.#values = new Set;
159
+ const values = value.split(',').filter(Boolean);
160
+ Promise.resolve(values)
161
+ .then(values => {
162
+ if (values.length) {
163
+ if (!this.multiple) {
164
+ if (this.#values.size === 0) {
165
+ values.length = 1;
166
+ }
167
+ else {
168
+ values.length = 0;
169
+ }
170
+ }
171
+ for (const key of values) {
172
+ const option = this.#markup.getOptionByValue(key);
173
+ if (option)
174
+ this.#selectOption(option);
175
+ }
176
+ }
177
+ for (const key of prevValue) {
178
+ if (this.#values.has(key))
179
+ continue;
180
+ const option = this.#markup.getOptionByValue(key);
181
+ const tag = this.#markup.getTagByValue(key);
182
+ tag?.remove();
183
+ option?.toggleAttribute('selected', false);
184
+ }
185
+ });
186
+ }
163
187
  // Instance methods
188
+ // <select> specific methods (implements HTMLSelectElement)
189
+ // add()
190
+ checkValidity() {
191
+ this.#internals.checkValidity();
192
+ }
193
+ item(index) {
194
+ return this.#markup.options.item(index);
195
+ }
196
+ // namedItem()
197
+ // !!! Conflicts with node.remove()
198
+ // remove(index: number)
199
+ reportValidity() {
200
+ this.#internals.reportValidity();
201
+ }
202
+ setCustomValidity(message) {
203
+ if (message === '') {
204
+ this.#internals.setValidity({});
205
+ }
206
+ else {
207
+ this.#internals.setValidity({ customError: true }, message);
208
+ }
209
+ }
210
+ showPicker() {
211
+ this.#markup.showDropdown();
212
+ }
213
+ // Overwritten methods
164
214
  setAttribute(name, value) {
165
215
  if (HTMLComboboxElement.OWN_IDL.has(name)) {
166
216
  Reflect.set(this, name, value);
@@ -177,20 +227,6 @@ export class HTMLComboboxElement extends HTMLElement {
177
227
  super.removeAttribute(name);
178
228
  }
179
229
  }
180
- reportValidity() {
181
- this.internals.reportValidity();
182
- }
183
- checkValidity() {
184
- this.internals.checkValidity();
185
- }
186
- setCustomValidity(message) {
187
- if (message === '') {
188
- this.internals.setValidity({});
189
- }
190
- else {
191
- this.internals.setValidity({ customError: true }, message);
192
- }
193
- }
194
230
  // Internal
195
231
  #onInput = (event) => {
196
232
  if (!this.searchable && this.filterable) {
@@ -228,76 +264,63 @@ export class HTMLComboboxElement extends HTMLElement {
228
264
  this.#values.add(value);
229
265
  option.toggleAttribute('selected', true);
230
266
  const control = this.#markup.createAndAppendTag(option);
231
- control?.addEventListener('click', this.#onClickTagClearButton);
267
+ control?.addEventListener('click', this.#onClearTag);
232
268
  if (!this.multiple) {
233
269
  this.#markup.closeDropdown();
234
270
  }
235
271
  }
236
272
  #onSelectOption = (event) => {
237
- let option;
238
- if (event.target instanceof HTMLComboboxOptionElement) {
239
- option = event.target;
240
- }
241
- else {
242
- option = event.composedPath()
243
- .find(el => el instanceof HTMLComboboxOptionElement);
244
- }
245
- if (option) {
246
- if (this.#values.has(option.value))
247
- return;
248
- if (!this.multiple) {
249
- this.#values.forEach(value => {
250
- this.#markup.getTagByValue(value)?.remove();
251
- this.#markup.getOptionByValue(value)?.toggleAttribute('selected', false);
252
- });
253
- this.#values.clear();
254
- this.#markup.tagsContainer.replaceChildren();
255
- }
256
- if (!this.multiple) {
257
- event.stopPropagation();
273
+ const target = event.target;
274
+ if (target && target instanceof HTMLElement) {
275
+ const option = target.closest('box-option');
276
+ if (option) {
277
+ if (this.#values.has(option.value))
278
+ return;
279
+ if (!this.multiple) {
280
+ event.stopPropagation();
281
+ this.#values.forEach(value => {
282
+ this.#markup.getTagByValue(value)?.remove();
283
+ this.#markup.getOptionByValue(value)?.toggleAttribute('selected', false);
284
+ });
285
+ this.#values.clear();
286
+ this.#markup.tagsContainer.replaceChildren();
287
+ }
288
+ this.#selectOption(option);
289
+ this.#setValidityAndFormValue();
290
+ this.dispatchEvent(new Event('change'));
258
291
  }
259
- this.#selectOption(option);
260
- this.#setValidityAndFormValue();
261
- this.dispatchEvent(new Event('change'));
262
292
  }
263
293
  };
264
- #onClickTagClearButton = (event) => {
265
- let button;
266
- if (event.target instanceof HTMLButtonElement) {
267
- button = event.target;
268
- }
269
- else {
270
- button = event.composedPath()
271
- .find(el => {
272
- return el instanceof HTMLElement && el.part.contains('clear-tag');
273
- });
274
- }
275
- if (button) {
276
- const value = button.value;
277
- const option = this.#markup.getOptionByValue(value);
278
- const tag = this.#markup.getTagByValue(value);
279
- option.removeAttribute('selected');
280
- this.#values.delete(value);
281
- tag.remove();
282
- this.#setValidityAndFormValue();
283
- this.dispatchEvent(new Event('change'));
294
+ #onClearTag = (event) => {
295
+ const target = event.target;
296
+ if (target && target instanceof HTMLElement) {
297
+ const tag = target.closest('box-tag');
298
+ if (tag) {
299
+ const value = tag.getAttribute('value');
300
+ const option = this.#markup.getOptionByValue(value);
301
+ option.removeAttribute('selected');
302
+ this.#values.delete(value);
303
+ tag.remove();
304
+ this.#setValidityAndFormValue();
305
+ this.dispatchEvent(new Event('change'));
306
+ }
284
307
  }
285
308
  };
286
- #onClickClearAllButton = () => {
309
+ #onClear = () => {
287
310
  this.formResetCallback();
288
311
  };
289
312
  #setValidityAndFormValue() {
290
- this.internals.setFormValue(this.value);
313
+ this.#internals.setFormValue(this.value);
291
314
  if (this.required && this.value === '') {
292
- this.internals.setValidity({ valueMissing: true });
315
+ this.#internals.setValidity({ valueMissing: true });
293
316
  }
294
317
  else {
295
- this.internals.setValidity({});
318
+ this.#internals.setValidity({});
296
319
  }
297
320
  }
298
321
  #initialAttributesSynchronization() {
299
322
  for (const key of HTMLComboboxElement.OWN_IDL) {
300
- Reflect.set(this, key, this.getAttribute(key));
323
+ this[key] = this.getAttribute(key);
301
324
  }
302
325
  }
303
326
  static staticLoadCssByUrls(urls) {
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.markup.d.ts","sourceRoot":"","sources":["../../../src/combobox/Combobox.markup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,qBAAa,cAAc;;IAGzB,aAAa,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC5C,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC/C,cAAc,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAChD,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAQ;IACvC,WAAW,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC1C,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAC5C,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IAClD,OAAO,EAAE,UAAU,CAAC,yBAAyB,CAAC,GAAG,IAAI,CAAC;IACtD,SAAS,UAAS;gBAEN,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB;IAU/D,OAAO;IAiBP,sBAAsB;IAMtB,IAAI,CAAC,KAAK,EAAE,MAAM;IAelB,UAAU;IASV,YAAY,aAIX;IAED,mBAAmB,CAAC,IAAI,EAAE,OAAO;IAmBjC,YAAY,aAcX;IAED,aAAa;IAYb,YAAY,GAAI,OAAO,KAAK,UAG3B;IAED,kBAAkB,CAAC,MAAM,EAAE,yBAAyB;IAqCpD,aAAa,CAAC,KAAK,EAAE,MAAM;IAI3B,gBAAgB,CAAC,KAAK,EAAE,MAAM;IAI9B,IAAI,eAAe,0CAGlB;IAED,MAAM,KAAK,QAAQ,WAoMlB;CACF"}
1
+ {"version":3,"file":"Combobox.markup.d.ts","sourceRoot":"","sources":["../../../src/combobox/Combobox.markup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,qBAAa,cAAc;;IAGzB,aAAa,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC5C,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC/C,cAAc,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAChD,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAQ;IACvC,WAAW,EAAE,cAAc,GAAG,IAAI,CAAQ;IAC1C,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAC5C,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IAClD,OAAO,EAAE,UAAU,CAAC,yBAAyB,CAAC,GAAG,IAAI,CAAC;IACtD,SAAS,UAAS;gBAEN,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB;IAU/D,OAAO;IAiBP,sBAAsB;IAMtB,IAAI,CAAC,KAAK,EAAE,MAAM;IAelB,UAAU;IASV,YAAY,aAIX;IAED,mBAAmB,CAAC,IAAI,EAAE,OAAO;IAmBjC,YAAY,aAaX;IAED,aAAa;IAWb,YAAY,GAAI,OAAO,KAAK,UAG3B;IAED,kBAAkB,CAAC,MAAM,EAAE,yBAAyB;IAsCpD,aAAa,CAAC,KAAK,EAAE,MAAM;IAI3B,gBAAgB,CAAC,KAAK,EAAE,MAAM;IAI9B,IAAI,eAAe,0CAGlB;IAED,MAAM,KAAK,QAAQ,WAoMlB;CACF"}
@@ -9,7 +9,6 @@ export declare class HTMLComboboxElement extends HTMLElement {
9
9
  };
10
10
  static styleSheet: CSSStyleSheet[];
11
11
  static formAssociated: boolean;
12
- internals: ElementInternals;
13
12
  shadowRoot: ShadowRoot;
14
13
  constructor();
15
14
  connectedCallback(): void;
@@ -17,32 +16,39 @@ export declare class HTMLComboboxElement extends HTMLElement {
17
16
  formResetCallback(): void;
18
17
  formDisabledCallback(isDisabled: boolean): void;
19
18
  get valueAsArray(): string[];
20
- get selectedOptions(): NodeListOf<HTMLComboboxOptionElement>;
21
- get validity(): ValidityState;
22
- get willValidate(): boolean;
23
- get value(): string;
24
- set value(value: string);
25
19
  get query(): string;
26
20
  set query(value: string);
27
21
  get placeholder(): string;
28
22
  set placeholder(value: string);
29
23
  get clearable(): boolean;
30
24
  set clearable(value: boolean);
31
- get multiple(): boolean;
32
- set multiple(value: boolean);
33
25
  get filterable(): boolean;
34
26
  set filterable(value: boolean);
35
27
  get searchable(): boolean;
36
28
  set searchable(value: boolean);
37
29
  get disabled(): boolean;
38
30
  set disabled(value: boolean);
31
+ get form(): HTMLFormElement;
32
+ get labels(): NodeList;
33
+ get length(): number;
34
+ get multiple(): boolean;
35
+ set multiple(value: boolean);
39
36
  get required(): boolean;
40
37
  set required(value: boolean);
41
- setAttribute(name: string, value: any): void;
42
- removeAttribute(name: string): void;
43
- reportValidity(): void;
38
+ get selectedOptions(): NodeListOf<HTMLComboboxOptionElement>;
39
+ get type(): "select-one" | "select-multiple";
40
+ get validationMessage(): string;
41
+ get validity(): ValidityState;
42
+ get willValidate(): boolean;
43
+ get value(): string;
44
+ set value(value: string);
44
45
  checkValidity(): void;
46
+ item(index: number): HTMLComboboxOptionElement;
47
+ reportValidity(): void;
45
48
  setCustomValidity(message: string): void;
49
+ showPicker(): void;
50
+ setAttribute(name: string, value: any): void;
51
+ removeAttribute(name: string): void;
46
52
  static staticLoadCssByUrls(urls: string[]): void;
47
53
  static loadCssFromDocumentStyleSheets(): void;
48
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HTML.combobox.element.d.ts","sourceRoot":"","sources":["../../../src/combobox/HTML.combobox.element.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAG9E,qBAAa,mBAAoB,SAAQ,WAAW;;IAClD,MAAM,CAAC,OAAO,cAA0H;IACxI,MAAM,CAAC,eAAe;;;;MAA0D;IAChF,MAAM,CAAC,UAAU,kBAAuB;IACxC,MAAM,CAAC,cAAc,UAAQ;IAE7B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;;IAkBvB,iBAAiB;IASjB,oBAAoB;IAKpB,iBAAiB;IAQjB,oBAAoB,CAAC,UAAU,EAAE,OAAO;IAMxC,IAAI,YAAY,aAEf;IACD,IAAI,eAAe,0CAElB;IACD,IAAI,QAAQ,kBAEX;IACD,IAAI,YAAY,YAEf;IAGD,IAAI,KAAK,IAGQ,MAAM,CADtB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAgCtB;IAED,IAAI,KAAK,IAGQ,MAAM,CADtB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAQtB;IAED,IAAI,WAAW,WAEd;IACD,IAAI,WAAW,CAAC,KAAK,QAAA,EAQpB;IAED,IAAI,SAAS,YAEZ;IACD,IAAI,SAAS,CAAC,KAAK,SAAA,EAElB;IAED,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAEjB;IAED,IAAI,UAAU,YAEb;IACD,IAAI,UAAU,CAAC,KAAK,SAAA,EAEnB;IAED,IAAI,UAAU,YAEb;IACD,IAAI,UAAU,CAAC,KAAK,SAAA,EAEnB;IAED,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAGjB;IAED,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAGjB;IAGD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAQrC,eAAe,CAAC,IAAI,EAAE,MAAM;IAQ5B,cAAc;IAId,aAAa;IAIb,iBAAiB,CAAC,OAAO,EAAE,MAAM;IAwHjC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE;IAIzC,MAAM,CAAC,8BAA8B;CAoBtC"}
1
+ {"version":3,"file":"HTML.combobox.element.d.ts","sourceRoot":"","sources":["../../../src/combobox/HTML.combobox.element.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAI9E,qBAAa,mBAAoB,SAAQ,WAAW;;IAClD,MAAM,CAAC,OAAO,cAA0H;IACxI,MAAM,CAAC,eAAe;;;;MAA0D;IAChF,MAAM,CAAC,UAAU,kBAAuB;IACxC,MAAM,CAAC,cAAc,UAAQ;IAE7B,UAAU,EAAE,UAAU,CAAC;;IAoBvB,iBAAiB;IASjB,oBAAoB;IAOpB,iBAAiB;IAQjB,oBAAoB,CAAC,UAAU,EAAE,OAAO;IAOxC,IAAI,YAAY,aAEf;IAED,IAAI,KAAK,IAGQ,MAAM,CADtB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAQtB;IAED,IAAI,WAAW,WAEd;IACD,IAAI,WAAW,CAAC,KAAK,QAAA,EAQpB;IAED,IAAI,SAAS,YAEZ;IACD,IAAI,SAAS,CAAC,KAAK,SAAA,EAElB;IAED,IAAI,UAAU,YAEb;IACD,IAAI,UAAU,CAAC,KAAK,SAAA,EAEnB;IAED,IAAI,UAAU,YAEb;IACD,IAAI,UAAU,CAAC,KAAK,SAAA,EAEnB;IAGD,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAGjB;IAED,IAAI,IAAI,oBAEP;IAED,IAAI,MAAM,aAET;IAED,IAAI,MAAM,WAET;IAED,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAEjB;IAKD,IAAI,QAAQ,YAEX;IACD,IAAI,QAAQ,CAAC,KAAK,SAAA,EAGjB;IAID,IAAI,eAAe,0CAElB;IAMD,IAAI,IAAI,qCAEP;IAED,IAAI,iBAAiB,WAEpB;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,YAAY,YAEf;IAED,IAAI,KAAK,IAGQ,MAAM,CADtB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAgCtB;IAQD,aAAa;IAIb,IAAI,CAAC,KAAK,EAAE,MAAM;IASlB,cAAc;IAId,iBAAiB,CAAC,OAAO,EAAE,MAAM;IAQjC,UAAU;IAKV,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAQrC,eAAe,CAAC,IAAI,EAAE,MAAM;IA4G5B,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE;IAIzC,MAAM,CAAC,8BAA8B;CAoBtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kr-elements",
3
- "version": "0.0.1-alpha.34",
3
+ "version": "0.0.1-alpha.35",
4
4
  "description": "Custom elements",
5
5
  "type": "module",
6
6
  "scripts": {