Compare commits
3 commits
d689d970e0
...
ab7a89b413
Author | SHA1 | Date | |
---|---|---|---|
ab7a89b413 | |||
03d321fbe8 | |||
cada3646d3 |
4 changed files with 76 additions and 14 deletions
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -83,4 +87,13 @@ better-select {
|
||||||
&:state(open)::part(display)::after {
|
&:state(open)::part(display)::after {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:not([required]):state(value)::part(display)::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::part(clear) {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
9
src/better-select.d.ts
vendored
9
src/better-select.d.ts
vendored
|
@ -45,7 +45,8 @@ export class BetterSelect extends HTMLElement {
|
||||||
* @param {string} state
|
* @param {string} state
|
||||||
*/
|
*/
|
||||||
setValue(value: string, state?: string): void;
|
setValue(value: string, state?: string): void;
|
||||||
set value(arg: any);
|
updateClearButton(): void;
|
||||||
|
set value(value: any);
|
||||||
get value(): any;
|
get value(): any;
|
||||||
get valueText(): any;
|
get valueText(): any;
|
||||||
setOptions(): void;
|
setOptions(): void;
|
||||||
|
@ -60,7 +61,7 @@ export class BetterSelect extends HTMLElement {
|
||||||
/**
|
/**
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
set name(arg: string);
|
set name(name: string);
|
||||||
/**
|
/**
|
||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
|
@ -70,7 +71,7 @@ export class BetterSelect extends HTMLElement {
|
||||||
/**
|
/**
|
||||||
* @param {Boolean} disabled
|
* @param {Boolean} disabled
|
||||||
*/
|
*/
|
||||||
set disabled(arg: boolean);
|
set disabled(disabled: boolean);
|
||||||
get disabled(): boolean;
|
get disabled(): boolean;
|
||||||
/**
|
/**
|
||||||
* @param {ValidityConstraint} _constraint
|
* @param {ValidityConstraint} _constraint
|
||||||
|
@ -84,7 +85,7 @@ export class BetterSelect extends HTMLElement {
|
||||||
/**
|
/**
|
||||||
* @param {Boolean} required
|
* @param {Boolean} required
|
||||||
*/
|
*/
|
||||||
set required(arg: boolean);
|
set required(required: boolean);
|
||||||
get required(): boolean;
|
get required(): boolean;
|
||||||
reportValidity(): boolean;
|
reportValidity(): boolean;
|
||||||
requiredChanged(): void;
|
requiredChanged(): void;
|
||||||
|
|
|
@ -154,7 +154,10 @@ export class BetterSelect extends HTMLElement {
|
||||||
[part="display-text"]:empty {
|
[part="display-text"]:empty {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
:not(:empty + *)[name="placeholder"] {
|
:not(#text:empty + *)[name="placeholder"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#text:empty ~ *[name="clear"] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
[part="drop-down"], [part="item"] {
|
[part="drop-down"], [part="item"] {
|
||||||
|
@ -185,10 +188,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;
|
||||||
|
@ -203,6 +208,13 @@ export class BetterSelect extends HTMLElement {
|
||||||
[part="list"] { display: none; }
|
[part="list"] { display: none; }
|
||||||
slot[name="loading"] { display: block; }
|
slot[name="loading"] { display: block; }
|
||||||
}
|
}
|
||||||
|
slot[name="clear"] > button {
|
||||||
|
all: unset;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
&::after {
|
||||||
|
content: "+";
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
/** @type {HTMLElement} */
|
/** @type {HTMLElement} */
|
||||||
|
@ -230,6 +242,11 @@ export class BetterSelect extends HTMLElement {
|
||||||
<slot name="placeholder" aria-hidden="true">
|
<slot name="placeholder" aria-hidden="true">
|
||||||
<span part="placeholder" id="placeholder" aria-hidden="true"></span>
|
<span part="placeholder" id="placeholder" aria-hidden="true"></span>
|
||||||
</slot>
|
</slot>
|
||||||
|
<template id="clear-template">
|
||||||
|
<slot name="clear" part="clear">
|
||||||
|
<button></button>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<dialog id="dialog" part="drop-down">
|
<dialog id="dialog" part="drop-down">
|
||||||
<slot name="top"></slot>
|
<slot name="top"></slot>
|
||||||
|
@ -258,9 +275,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) {
|
||||||
this.setOption(item)
|
if (!item.part.contains("disabled")) {
|
||||||
this.dispatchEvent(new InputEvent("input", {bubbles: true}))
|
this.setOption(item)
|
||||||
this.close()
|
this.dispatchEvent(new InputEvent("input", {bubbles: true}))
|
||||||
|
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)) {
|
||||||
|
@ -452,9 +471,27 @@ export class BetterSelect extends HTMLElement {
|
||||||
this.#internals.setFormValue(value, state)
|
this.#internals.setFormValue(value, state)
|
||||||
this.text.innerText = state
|
this.text.innerText = state
|
||||||
|
|
||||||
|
this.#states.toggle("value", value)
|
||||||
|
|
||||||
|
this.updateClearButton()
|
||||||
this.setValidity()
|
this.setValidity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateClearButton() {
|
||||||
|
const template = /** @type {HTMLTemplateElement} */(this.shadowRoot.getElementById("clear-template"))
|
||||||
|
const clearButton = template.nextElementSibling
|
||||||
|
if (this.required || this.#value.value === undefined) {
|
||||||
|
clearButton?.remove()
|
||||||
|
} else if (!clearButton && !this.required) {
|
||||||
|
const button = template.content.cloneNode(true)
|
||||||
|
template.after(button)
|
||||||
|
template.nextElementSibling.addEventListener("click", event => {
|
||||||
|
event.stopPropagation()
|
||||||
|
this.clear()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get value() { return this.#value.value }
|
get value() { return this.#value.value }
|
||||||
set value(value) {
|
set value(value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
|
@ -475,7 +512,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
|
||||||
}
|
}
|
||||||
|
@ -557,7 +602,10 @@ export class BetterSelect extends HTMLElement {
|
||||||
|
|
||||||
reportValidity() { return this.#internals.reportValidity() }
|
reportValidity() { return this.#internals.reportValidity() }
|
||||||
|
|
||||||
requiredChanged() { this.setValidity() }
|
requiredChanged() {
|
||||||
|
this.updateClearButton()
|
||||||
|
this.setValidity()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
|
|
Loading…
Reference in a new issue