Compare commits
3 commits
12850294e9
...
9900d51342
Author | SHA1 | Date | |
---|---|---|---|
9900d51342 | |||
aad018dad0 | |||
82ccdb3a55 |
1 changed files with 45 additions and 10 deletions
|
@ -126,6 +126,9 @@ export class BetterSelect extends HTMLElement {
|
||||||
#abortOpen
|
#abortOpen
|
||||||
#value = {}
|
#value = {}
|
||||||
|
|
||||||
|
/** @type {number} */
|
||||||
|
#index = undefined
|
||||||
|
|
||||||
#internals = this.attachInternals()
|
#internals = this.attachInternals()
|
||||||
#states = new StateAttributeSet(this, this.#internals.states)
|
#states = new StateAttributeSet(this, this.#internals.states)
|
||||||
|
|
||||||
|
@ -160,7 +163,7 @@ export class BetterSelect extends HTMLElement {
|
||||||
#text:empty ~ *[name="clear"] {
|
#text:empty ~ *[name="clear"] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
[part="drop-down"], [part="item"] {
|
[part="drop-down"], [part~="item"] {
|
||||||
/* Resets */
|
/* Resets */
|
||||||
border: unset;
|
border: unset;
|
||||||
outline: unset;
|
outline: unset;
|
||||||
|
@ -195,10 +198,10 @@ export class BetterSelect extends HTMLElement {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[part="item"]:focus {
|
[part~="item"]:focus {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
[part="item"][hidden] {
|
[part~="item"][hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
slot[name="loading"] {
|
slot[name="loading"] {
|
||||||
|
@ -313,6 +316,14 @@ export class BetterSelect extends HTMLElement {
|
||||||
this.keyboardSearchAppend(key)
|
this.keyboardSearchAppend(key)
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
} else if (key == "Delete") {
|
||||||
|
this.clear()
|
||||||
|
} else if (key == "ArrowDown") {
|
||||||
|
event.preventDefault()
|
||||||
|
this.next()
|
||||||
|
} else if (key == "ArrowUp") {
|
||||||
|
event.preventDefault()
|
||||||
|
this.previous()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -421,10 +432,11 @@ export class BetterSelect extends HTMLElement {
|
||||||
/** @param {String} value */
|
/** @param {String} value */
|
||||||
search(value) {
|
search(value) {
|
||||||
for (const item of this.list.children) {
|
for (const item of this.list.children) {
|
||||||
if (item instanceof HTMLElement)
|
if (item instanceof HTMLElement) {
|
||||||
item.toggleAttribute("hidden", !this.match(value, item))
|
item.toggleAttribute("hidden", !this.match(value, item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
selectDefault() {
|
selectDefault() {
|
||||||
const active = this.shadowRoot.activeElement
|
const active = this.shadowRoot.activeElement
|
||||||
|
@ -433,18 +445,21 @@ export class BetterSelect extends HTMLElement {
|
||||||
this.close()
|
this.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const candidates = /** @type {HTMLElement[]} */(Array.from(this.list.children).filter(child => !child.hasAttribute("hidden")))
|
const candidates = /** @type {HTMLElement[]} */(Array.from(this.list.children).filter(child => !child.hasAttribute("hidden") && !child.part.contains("disabled")))
|
||||||
if (candidates.length) {
|
if (candidates.length) {
|
||||||
this.setOption(candidates[0])
|
this.setOption(candidates[0])
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static searchHideDisabled = true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} value
|
* @param {string} value
|
||||||
* @param {HTMLElement} item
|
* @param {HTMLElement} item
|
||||||
*/
|
*/
|
||||||
match(value, item) {
|
match(value, item) {
|
||||||
|
if (/** @type {Object} */(value && this.constructor).searchHideDisabled && item.part.contains("disabled")) return false
|
||||||
return item.innerText.toLowerCase().match(value.toLowerCase())
|
return item.innerText.toLowerCase().match(value.toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,14 +473,17 @@ export class BetterSelect extends HTMLElement {
|
||||||
|
|
||||||
/** @param {HTMLElement} option */
|
/** @param {HTMLElement} option */
|
||||||
setOption(option) {
|
setOption(option) {
|
||||||
return this.setValue(option.dataset.value, option.innerText)
|
return this.setValue(Number(option.dataset.index), option.dataset.value, option.innerText)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {number} index
|
||||||
* @param {string} value
|
* @param {string} value
|
||||||
* @param {string} state
|
* @param {string} state
|
||||||
*/
|
*/
|
||||||
setValue(value, state=value) {
|
setValue(index, value, state=value) {
|
||||||
|
this.#index = Number(index)
|
||||||
|
|
||||||
this.#value = {value, state}
|
this.#value = {value, state}
|
||||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
this.#internals.setFormValue(value, state)
|
this.#internals.setFormValue(value, state)
|
||||||
|
@ -497,9 +515,10 @@ export class BetterSelect extends HTMLElement {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
this.clear()
|
this.clear()
|
||||||
} else {
|
} else {
|
||||||
|
let index = 0
|
||||||
for (const option of this.options) {
|
for (const option of this.options) {
|
||||||
if (option.value === String(value)) {
|
if (option.value === String(value)) {
|
||||||
this.setValue(option.value, option.innerText)
|
this.setValue(index++, option.value, option.innerText)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -511,8 +530,9 @@ export class BetterSelect extends HTMLElement {
|
||||||
|
|
||||||
setOptions() {
|
setOptions() {
|
||||||
this.list.replaceChildren()
|
this.list.replaceChildren()
|
||||||
|
let idx = 0
|
||||||
for (const option of this.options) {
|
for (const option of this.options) {
|
||||||
const fragment = f`<li tabindex="0" part="item" data-value="${option.value}">${option.innerText}</li>`
|
const fragment = f`<li data-index=${idx++} tabindex="0" part="item" data-value="${option.value}">${option.innerText}</li>`
|
||||||
const li = fragment.querySelector("li")
|
const li = fragment.querySelector("li")
|
||||||
if (option.disabled) {
|
if (option.disabled) {
|
||||||
li.part.add("disabled")
|
li.part.add("disabled")
|
||||||
|
@ -554,7 +574,7 @@ export class BetterSelect extends HTMLElement {
|
||||||
get form() { return this.#internals.form }
|
get form() { return this.#internals.form }
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
this.setValue(undefined, "")
|
this.setValue(undefined, undefined, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -570,6 +590,21 @@ export class BetterSelect extends HTMLElement {
|
||||||
return "Please select an option."
|
return "Please select an option."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next() {
|
||||||
|
const index = (this.#index ?? -1) + 1
|
||||||
|
const item = /** @type {HTMLElement} */(this.list.children[index])
|
||||||
|
if (item) {
|
||||||
|
this.setOption(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previous() {
|
||||||
|
const index = (this.#index ?? this.options.length) - 1
|
||||||
|
const item = /** @type {HTMLElement} */(this.list.children[index])
|
||||||
|
if (item) {
|
||||||
|
this.setOption(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setValidity() {
|
setValidity() {
|
||||||
if (this.required) {
|
if (this.required) {
|
||||||
|
|
Loading…
Reference in a new issue