import '../templating.js';
import { injectable } from '@joist/di';
import { attr, css, element, html, listen, query } from '@joist/element';
import { bind } from '@joist/templating';
import { effect } from '@joist/observable';
import { SELECT_CONTEXT, type SelectContainer } from './context.js';
declare global {
interface HTMLElementTagNameMap {
'usa-select': USASelectElement;
}
}
@injectable({
name: 'usa-select-ctx',
provideSelfAs: [SELECT_CONTEXT],
})
@element({
tagName: 'usa-select',
shadowDom: [
css`
:host {
display: block;
line-height: 1.3;
position: relative;
width: 100%;
max-width: 30rem;
margin-bottom: 1.5rem;
}
select {
font-size: 1.06rem;
appearance: none;
border-width: 1px;
border-color: #5c5c5c;
border-style: solid;
border-radius: 0;
color: #1b1b1b;
background-color: #fff;
display: block;
height: 2.5rem;
margin-top: 0.5rem;
padding: 0.5rem;
width: 100%;
}
select:not(:disabled):focus {
outline: 0.25rem solid #2491ff;
outline-offset: 0;
}
select:disabled {
background-color: #fff;
border-color: #757575;
color: #757575;
}
usa-icon {
position: absolute;
right: 0.5rem;
bottom: 12%;
height: 1.5rem;
width: 1.5rem;
}
`,
html`
`,
],
})
export class USASelectElement extends HTMLElement implements SelectContainer {
static formAssociated = true;
@attr()
@bind()
accessor value = '';
@attr()
@bind()
accessor name = '';
@attr()
@bind()
accessor required = false;
@attr()
@bind()
accessor disabled = false;
#select = query('select');
#internals = this.attachInternals();
connectedCallback() {
this.#syncFormState();
}
@effect()
onChange() {
this.#syncFormState();
}
@listen('input')
onSelectChange(e: Event) {
e.stopImmediatePropagation();
const select = this.#select();
this.value = select.value;
this.dispatchEvent(new Event('input', { bubbles: true }));
}
addSelectOption(option: HTMLOptionElement) {
const select = this.#select();
if (!this.value && !select.children.length) {
this.value = option.value;
}
select.append(option);
}
async #syncFormState() {
const select = this.#select();
this.#internals.setFormValue(this.value);
this.#internals.setValidity({});
await new Promise((resolve) => setTimeout(resolve));
if (select.validationMessage) {
this.#internals.setValidity({ customError: true }, select.validationMessage, select);
}
}
}