Allow disabling of individual options

This commit is contained in:
Talia 2025-08-07 14:53:42 +02:00
parent d689d970e0
commit cada3646d3
3 changed files with 24 additions and 8 deletions

View file

@ -53,7 +53,7 @@
<better-select name="better-selection" class="search" placeholder="Placeholder..." search-placeholder="Search..."> <better-select name="better-selection" class="search" placeholder="Placeholder..." search-placeholder="Search...">
<span slot="placeholder">Placeholder...</span> <span slot="placeholder">Placeholder...</span>
<option value="first">First value</option> <option value="first">First value</option>
<option value="second">Second value</option> <option value="second" disabled>Second value</option>
<option value="third">Third value</option> <option value="third">Third value</option>
</better-select> </better-select>

View file

@ -62,10 +62,14 @@ better-select {
padding-inline: var(--h-padding); padding-inline: var(--h-padding);
} }
&::part(item):is(:hover, :focus) { &::part(item enabled):is(:hover, :focus) {
background-color: var(--highlight); background-color: var(--highlight);
} }
&::part(item disabled) {
opacity: .6;
}
&:not(:state(open))::part(drop-down) { &:not(:state(open))::part(drop-down) {
transform: scale(100%, 70%) translate(0, -30%); transform: scale(100%, 70%) translate(0, -30%);
opacity: 0; opacity: 0;

View file

@ -185,10 +185,12 @@ export class BetterSelect extends HTMLElement {
[part="list"] { [part="list"] {
display: contents; display: contents;
} }
[part="item"] { [part~="item"] {
display: block; display: block;
cursor: pointer;
white-space: nowrap; white-space: nowrap;
&[part~="enabled"] {
cursor: pointer;
}
} }
[part="item"]:focus { [part="item"]:focus {
font-weight: bold; font-weight: bold;
@ -258,9 +260,11 @@ export class BetterSelect extends HTMLElement {
/** @type {HTMLLIElement} */ /** @type {HTMLLIElement} */
const item = event.target.closest("#list > li") const item = event.target.closest("#list > li")
if (item) { if (item) {
if (!item.part.contains("disabled")) {
this.setOption(item) this.setOption(item)
this.dispatchEvent(new InputEvent("input", {bubbles: true})) this.dispatchEvent(new InputEvent("input", {bubbles: true}))
this.close() this.close()
}
} else if (!this.#states.has("open")) { } else if (!this.#states.has("open")) {
this.open() this.open()
} else if (this.display.contains(event.target) || this.display.contains(event.target.closest("[slot]")?.assignedSlot)) { } else if (this.display.contains(event.target) || this.display.contains(event.target.closest("[slot]")?.assignedSlot)) {
@ -475,7 +479,15 @@ export class BetterSelect extends HTMLElement {
setOptions() { setOptions() {
this.list.replaceChildren() this.list.replaceChildren()
for (const option of this.options) { for (const option of this.options) {
this.list.append(f`<li tabindex="0" part="item" data-value="${option.value}">${option.innerText}</li>`) const fragment = f`<li tabindex="0" part="item" data-value="${option.value}">${option.innerText}</li>`
const li = fragment.querySelector("li")
if (option.disabled) {
li.part.add("disabled")
li.removeAttribute("tabindex")
} else {
li.part.add("enabled")
}
this.list.append(fragment)
if (this.value == undefined && option.selected) { if (this.value == undefined && option.selected) {
this.value = option.value this.value = option.value
} }