UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

398 lines (397 loc) 14.2 kB
import { c as e, d as t, i as n, l as r, o as i, r as a, s as o, t as s } from "./element-cZ85T_aa.js"; import { t as c } from "./class-map-C8HuhNzZ.js"; import { t as l } from "./if-defined-Cjj8qN-Z.js"; import { t as u } from "./repeat-DV1O43YU.js"; import { n as d } from "./utils-BOOZ0ppt.js"; //#region ../../shared-utils/combobox/option-utils.ts var f = (e, t) => t && (e.find((e) => e.value === t) || e.find((e) => e.label === t)) || null, p = (e, t) => { if (!t) return -1; let n = e.findIndex((e) => e.value === t); return n >= 0 ? n : e.findIndex((e) => e.label === t); }, m = (e, t) => { if (!t) return [...e]; let n = t.toLowerCase(); return e.filter((e) => (e.fulltext || e.value + (e.label || "") + (e.prefix || "")).toLowerCase().includes(n)); }, h = (e) => e.value + (e.label || "") + (e.prefix || ""), g = (e, t) => t !== null && e >= t, _ = (e, t) => { if (!t) return { filtered: [...e], suggestion: null }; let n = t.toLowerCase(), r = e.filter((e) => e.fulltext?.toLowerCase().includes(n)); return { filtered: r, suggestion: r.find((e) => !e.selected && e.label?.toLowerCase().startsWith(n)) || null }; }, v = (e, t, n, r) => { if (!e.trim()) return { addValueText: null, userInfoMessage: "" }; let i = e.trim().toLowerCase(), a = t.find((e) => e.toLowerCase() === i), o = n.filter((e) => e.label?.toLowerCase().includes(i) || e.value.toLowerCase().includes(i)), s = o.find((e) => e.label?.toLowerCase() === i || e.value.toLowerCase() === i); return (o.length === 0 || !s) && r ? { addValueText: e, userInfoMessage: "" } : o.length === 0 && !r ? { addValueText: null, userInfoMessage: "Ingen treff i søket" } : a ? { addValueText: null, userInfoMessage: "Verdien er allerede valgt" } : { addValueText: null, userInfoMessage: "" }; }, y = (e) => /^[\p{L} ]$/u.test(e), b = (e = 500) => { let t = "", n; return { append: (r) => (t += r.toLowerCase(), n !== void 0 && clearTimeout(n), n = setTimeout(() => { t = ""; }, e), t), reset: () => { t = "", n !== void 0 && (clearTimeout(n), n = void 0); }, getBuffer: () => t }; }, x = (e, t) => { let n = t.toLowerCase(); return e.findIndex((e) => e.textContent?.trim().toLowerCase().startsWith(n)); }, S = (e) => { e.scrollIntoView({ block: "nearest" }), window.setTimeout(() => e.focus(), 0); }, C = (e) => Array.from(e.querySelectorAll("[role=\"option\"]:not([data-disabled])") || []), w = (e) => { let t = e.nextElementSibling; t && S(t); }, T = (e, t, n) => { let r = e.previousElementSibling; if (e.dataset.index === "0" && n) { let e = t.querySelector("[role=\"searchbox\"]"); e && S(e); } else r && S(r); }, E = (e) => { let t = C(e); t[0] && S(t[0]); }, D = (e) => { let t = C(e), n = t[t.length - 1]; n && S(n); }, O = (e, t) => { if (t.disabled) return; let n = C(e); if (t.allowUserInput && t.customUserInput) { let t = e.querySelector("[data-type=\"new-option\"]"); if (t) { S(t); return; } } let r = n.find((e) => e.dataset.selected === "true"); if (r) { S(r); return; } if (t.includeSearch && !(document.activeElement instanceof HTMLInputElement)) { let t = e.querySelector("[role=\"searchbox\"]"); if (t) { window.setTimeout(() => t.focus(), 0); return; } } n[0] && S(n[0]); }, k = class extends s { constructor(...e) { super(...e), this.id = d(), this.label = null, this.options = [], this.isOpen = !1, this.disabled = !1, this.includeSearch = !1, this.isMultiSelect = !1, this.allowUserInput = !1, this.maxIsReached = !1, this.customUserInput = null, this.searchPlaceholder = null, this.searchValue = null, this.maxLength = 0, this.userMessage = null, this._selectedOptions = 0, this.typeahead = b(), this._filteredOptions = []; } connectedCallback() { super.connectedCallback(), this.includeSearch && !this.searchValue && (this.searchValue = ""), this.options.length > 0 && this.filterOptions(), this.setAttribute("tabindex", "-1"), this.addEventListener("focus", this.focusFirstOrSelectedOption); } disconnectedCallback() { super.disconnectedCallback(), this.typeahead.reset(); } updated(e) { (e.has("options") || e.has("searchValue")) && this.filterOptions(), super.updated(e); } attributeChangedCallback(e, t, n) { (e === "options" || e === "search-value") && this.filterOptions(), super.attributeChangedCallback(e, t, n); } get _hasOptions() { return this._filteredOptions.length > 0 || this.options.length > 0; } render() { return t` <div class=${c({ "pkt-listbox": !0, "pkt-listbox__open": this.isOpen, "pkt-txt-16-light": !0 })} role=${l(this._hasOptions ? "listbox" : void 0)} aria-multiselectable=${l(this._hasOptions && this.isMultiSelect ? "true" : void 0)} aria-label=${l(this._hasOptions ? this.label ?? void 0 : void 0)} > <div class="pkt-listbox__banners"> ${this.renderSearch()} ${this.renderMaximumReachedBanner()} ${this.renderUserMessage()} ${this.renderEmptyMessage()} ${this.renderNewOptionBanner()} </div> <ul class="pkt-listbox__options" role="presentation"> ${this.renderList()} </ul> </div> <div aria-live="polite" class="pkt-visually-hidden">${this.userMessage}</div> `; } renderCheckboxOrCheckIcon(e, n) { return this.isMultiSelect ? t` <input class="pkt-input-check__input-checkbox" type="checkbox" role="presentation" tabindex="-1" value=${e.value} @change=${(e) => { e.stopPropagation(); }} .checked=${e.selected} aria-labelledby=${this.id + "-option-label-" + n} ?disabled=${this.disabled || e.disabled || this.maxIsReached && !e.selected} /> ` : e.selected ? t`<pkt-icon name="check-big"></pkt-icon>` : r; } renderEmptyMessage() { return this.options.length > 0 || this._filteredOptions.length > 0 || this.userMessage ? r : t`<div class="pkt-listbox__banner pkt-listbox__banner--empty"> <pkt-icon class="pkt-listbox__banner-icon" name="exclamation-mark-circle" size="large" ></pkt-icon> Tom liste </div>`; } renderList() { return t` ${u(this._filteredOptions, (e) => e.value, (e, n) => t` <li @click=${() => { this.toggleOption(e); }} aria-selected=${e.selected ? "true" : "false"} @keydown=${this.handleOptionKeydown} class=${c({ "pkt-listbox__option": !0, "pkt-listbox__option--selected": !!(!this.isMultiSelect && e.selected), "pkt-listbox__option--checkBox": this.isMultiSelect })} tabindex="${this.disabled || e.disabled ? "-1" : "0"}" data-index=${n} data-value=${e.value} data-selected=${e.selected ? "true" : "false"} ?data-disabled=${this.disabled || e.disabled || this.maxIsReached && !e.selected} aria-disabled=${this.disabled || e.disabled || this.maxIsReached && !e.selected ? "true" : "false"} role="option" id=${`${this.id}-${n}`} > ${this.renderCheckboxOrCheckIcon(e, n)} <span class="pkt-listbox__option-label" id=${this.id + "-option-label-" + n}> ${e.prefix ? t`<span class="pkt-listbox__option-prefix">${e.prefix}</span>` : r} ${e.label || e.value} </span> ${e.description ? t`<span class="pkt-listbox__option-description pkt-txt-14-light" >${e.description}</span >` : r} </li> `)} `; } renderNewOptionBanner() { return this.allowUserInput && this.customUserInput ? t` <div class="pkt-listbox__banner pkt-listbox__banner--new-option pkt-listbox__option" data-type="new-option" data-value=${this.customUserInput} data-selected="false" tabindex="0" @click=${() => this.toggleOption({ value: this.customUserInput || "" })} @keydown=${this.handleOptionKeydown} > <pkt-icon class="pkt-listbox__banner-icon" name="plus-sign" size="large"></pkt-icon> Legg til "${this.customUserInput}" </div> ` : r; } renderMaximumReachedBanner() { return this._selectedOptions = this.options.filter((e) => e.selected).length, this.isMultiSelect && this._selectedOptions > 0 && this.maxLength > 0 ? t` <div class="pkt-listbox__banner pkt-listbox__banner--maximum-reached"> ${this._selectedOptions} av maks ${this.maxLength} mulige er valgt. </div> ` : r; } renderUserMessage() { return this.userMessage ? t`<div class="pkt-listbox__banner pkt-listbox__banner--user-message"> <pkt-icon class="pkt-listbox__banner-icon" name="exclamation-mark-circle" size="large" ></pkt-icon> ${this.userMessage} </div>` : r; } renderSearch() { return this.includeSearch ? t` <div class="pkt-listbox__search"> <span class="pkt-listbox__search-icon"> <pkt-icon name="magnifying-glass-small" size="large"></pkt-icon> </span> <input class="pkt-txt-16-light" type="text" aria-label="Søk i listen" form="" placeholder=${this.searchPlaceholder || n.forms.search.placeholder} @input=${this.handleSearchInput} @keydown=${this.handleSearchKeydown} .value=${this.searchValue} data-type="searchbox" ?disabled=${this.disabled} ?readonly=${this.disabled} role="searchbox" /> </div> ` : r; } handleSearchInput(e) { this.searchValue = e.target.value, this.dispatchEvent(new CustomEvent("search", { detail: this.searchValue, bubbles: !1 })); } handleSearchKeydown(e) { switch (e.key) { case "Enter": e.preventDefault(); break; case "ArrowUp": case "Escape": this.closeOptions(), e.preventDefault(); break; case "ArrowDown": this.focusFirstOrSelectedOption(); break; case "Tab": this.tabClose(); break; } } handleOptionKeydown(e) { let t = e.currentTarget, n = t.dataset.value, r = t.dataset.type, i = t.dataset.selected === "true"; if (!(!C(this).length && (!this.customUserInput || !this.allowUserInput && this.customUserInput) && r !== "new-option" && r !== "searchbox")) switch (e.key) { case " ": case "Enter": this.toggleOption(t), e.preventDefault(); break; case "Backspace": n && (i ? this.toggleOption(t) : this.closeOptions()), e.preventDefault(); break; case "Escape": this.closeOptions(), e.preventDefault(); break; case "Tab": this.tabClose(); break; case "ArrowDown": e.altKey ? D(this) : r === "searchbox" || r === "new-option" ? E(this) : w(t), e.preventDefault(); break; case "ArrowUp": if (e.altKey) E(this); else if (t.dataset.index === "0" && this.includeSearch) { let e = this.querySelector("[role=\"searchbox\"]"); e && e.focus(); } else if (t.dataset.index === "0" && this.customUserInput) { let e = this.querySelector("[data-type=\"new-option\"]"); e && e.focus(); } else T(t, this, this.includeSearch); e.preventDefault(); break; case "Home": E(this), e.preventDefault(); break; case "End": D(this), e.preventDefault(); break; default: (e.metaKey || e.ctrlKey) && e.key === "a" && (this.selectAll(), e.preventDefault()), y(e.key) && (this.handleTypeAhead(e.key), e.preventDefault()); break; } } focusFirstOrSelectedOption() { O(this, { disabled: this.disabled, allowUserInput: this.allowUserInput, customUserInput: this.customUserInput, includeSearch: this.includeSearch }); } toggleOption(e) { let t = e instanceof HTMLElement ? e.dataset.disabled : e.disabled; if (this.disabled || t) return; let n = e instanceof HTMLElement ? e.dataset.value : e.value; this.dispatchEvent(new CustomEvent("option-toggle", { detail: n, bubbles: !1 })); } selectAll() { this.dispatchEvent(new CustomEvent("select-all", { bubbles: !1 })); } closeOptions() { this.dispatchEvent(new CustomEvent("close-options", { bubbles: !1 })); } tabClose() { this.dispatchEvent(new CustomEvent("tab-close", { bubbles: !1 })); } filterOptions() { this._filteredOptions = m(this.options, this.searchValue); } handleTypeAhead(e) { let t = this.typeahead.append(e), n = C(this), r = x(n, t); r >= 0 && S(n[r]); } }; a([o({ type: String })], k.prototype, "id", void 0), a([o({ type: String })], k.prototype, "label", void 0), a([o({ type: Array })], k.prototype, "options", void 0), a([o({ type: Boolean, reflect: !0, attribute: "is-open" })], k.prototype, "isOpen", void 0), a([o({ type: Boolean })], k.prototype, "disabled", void 0), a([o({ type: Boolean, attribute: "include-search" })], k.prototype, "includeSearch", void 0), a([o({ type: Boolean, attribute: "is-multi-select" })], k.prototype, "isMultiSelect", void 0), a([o({ type: Boolean, attribute: "allow-user-input" })], k.prototype, "allowUserInput", void 0), a([o({ type: Boolean, attribute: "max-is-reached" })], k.prototype, "maxIsReached", void 0), a([o({ type: String, attribute: "custom-user-input" })], k.prototype, "customUserInput", void 0), a([o({ type: String, attribute: "search-placeholder" })], k.prototype, "searchPlaceholder", void 0), a([o({ type: String, attribute: "search-value" })], k.prototype, "searchValue", void 0), a([o({ type: Number, attribute: "max-length" })], k.prototype, "maxLength", void 0), a([o({ type: String, attribute: "user-message" })], k.prototype, "userMessage", void 0), a([i()], k.prototype, "_filteredOptions", void 0); try { e("pkt-listbox")(k); } catch { console.warn("Forsøker å definere <pkt-listbox>, men den er allerede definert"); } //#endregion //#region src/components/listbox/index.ts var A = k; //#endregion export { p as a, g as c, f as i, k as n, _ as o, h as r, v as s, A as t };