@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
516 lines (513 loc) • 23.2 kB
JavaScript
import { E as y, x as d, n as r, a as k } from "./element-CgEWt74-.js";
import { o as f } from "./if-defined-CmuO4Vz9.js";
import { r as c } from "./state-Bo2bck5_.js";
import { e as _, n as v } from "./ref-BBYSqgeW.js";
import { e as w } from "./class-map-BpTj9gtz.js";
import { c as R } from "./repeat-C8BeHwYx.js";
import { P as V } from "./input-element-NnrDmp4r.js";
import { P as S } from "./pkt-options-controller-CZO1nxZ8.js";
import { P as C } from "./pkt-slot-controller-BPGj-LC5.js";
import "./input-wrapper-Dr__Sxql.js";
import "./icon-CC1js8eR.js";
import "./tag-BWm6s48d.js";
import "./listbox-CLsSW32I.js";
const A = {
displayValueAs: {
default: "label"
}
}, T = {
props: A
};
var M = Object.defineProperty, F = Object.getOwnPropertyDescriptor, o = (t, e, i, s) => {
for (var l = s > 1 ? void 0 : s ? F(e, i) : e, n = t.length - 1, a; n >= 0; n--)
(a = t[n]) && (l = (s ? a(e, i, l) : a(l)) || l);
return s && l && M(e, i, l), l;
};
let h = class extends V {
constructor() {
super(), this.helptextSlot = _(), this.value = "", this.options = [], this.defaultOptions = [], this.allowUserInput = !1, this.typeahead = !1, this.includeSearch = !1, this.searchPlaceholder = "", this.multiple = !1, this.maxlength = null, this.displayValueAs = T.props.displayValueAs.default, this.tagPlacement = null, this._options = [], this._isOptionsOpen = !1, this._value = [], this._userInfoMessage = "", this._addValueText = null, this._maxIsReached = !1, this._search = "", this._inputFocus = !1, this._editingSingleValue = !1, this.inputRef = _(), this.arrowRef = _(), this.listboxRef = _(), this.focusRef = _(), this.optionTagRef = _(), this.optionsController = new S(this), this.slotController = new C(this, this.helptextSlot), this.slotController.skipOptions = !0;
}
// Lifecycle methods
connectedCallback() {
var t;
if (super.connectedCallback(), document && document.body.addEventListener("click", (e) => {
this._isOptionsOpen && !this.contains(e.target) && this.handleFocusOut(e);
}), this._options = [], this.defaultOptions && this.defaultOptions.length) {
const e = ((t = this.options) == null ? void 0 : t.filter((i) => i.userAdded)) || [];
this.options = [...e, ...JSON.parse(JSON.stringify(this.defaultOptions))], this._options = [...this.options];
}
if (this.optionsController.nodes.length) {
const e = [];
this.optionsController.nodes.forEach((i) => {
if (!i.textContent && !i.getAttribute("value")) return null;
const s = {
value: i.getAttribute("value") || i.textContent || "",
label: i.textContent || i.getAttribute("value") || ""
};
i.getAttribute("data-prefix") && (s.prefix = i.getAttribute("data-prefix") || void 0), i.getAttribute("tagskincolor") && (s.tagSkinColor = i.getAttribute("tagskincolor")), i.getAttribute("description") && (s.description = i.getAttribute("description") || void 0), s.fulltext = s.value + s.label + (s.prefix || ""), e.push(s);
}), e.length && (this.options = [...e], this._options = [...e]);
}
}
updated(t) {
var e;
if (t.has("_value") && this.valueChanged(this._value, t.get("_value")), t.has("value") && (this._value = Array.isArray(this.value) ? this.value : this.value ? this.value.split(",") : [], !this.multiple && this._value.length > 1 && (this._value = [this._value[0]]), this.isMaxItemsReached()), t.has("defaultOptions") && this.defaultOptions.length) {
const i = ((e = this.options) == null ? void 0 : e.filter((s) => s.userAdded)) || [];
this.options = [...i, ...JSON.parse(JSON.stringify(this.defaultOptions))], this._options = [...this.options];
}
if (t.has("options") && this.options.length) {
const s = this._options.filter((l) => l.userAdded).filter(
(l) => !this.options.some((n) => n.value === l.value)
);
this._options = [...s, ...this.options], this._options.forEach((l) => {
if (l.value && !l.label && (l.label = l.value), l.selected && !this._value.includes(l.value)) {
const n = [...this._value];
this._value = [...this._value, l.value], this.valueChanged(this._value, n);
}
l.fulltext = l.value + l.label + (l.prefix || ""), l.selected = l.selected || this._value.includes(l.value);
});
}
t.has("_search") && this.dispatchEvent(
new CustomEvent("search", {
detail: this._search,
bubbles: !1
})
), super.updated(t);
}
attributeChangedCallback(t, e, i) {
t === "value" && (this._value = Array.isArray(this.value) ? this.value : this.value ? this.value.split(",") : [], !this.multiple && this._value.length > 1 && (this._value = [this._value[0]])), t === "options" && (this._options = this.options, this._options.forEach((s) => {
s.value && !s.label && (s.label = s.value), s.selected && !this._value.includes(s.value) && (this._value = [...this._value, s.value]), s.fulltext = s.value + s.label + (s.prefix || "");
}), this._search = ""), super.attributeChangedCallback(t, e, i);
}
// Render methods
render() {
return d`
<pkt-input-wrapper
.label=${this.label}
.helptext=${this.helptext}
.helptextDropdown=${f(this.helptextDropdown)}
.helptextDropdownButton=${f(this.helptextDropdownButton)}
?fullwidth=${this.fullwidth}
?hasError=${this.hasError}
?inline=${this.inline}
?disabled=${this.disabled}
.errorMessage=${this.errorMessage}
?optionalTag=${this.optionalTag}
.optionalText=${this.optionalText}
?requiredTag=${this.requiredTag}
.requiredText=${this.requiredText}
.tagText=${this.tagText}
?useWrapper=${this.useWrapper}
.forId=${this.allowUserInput || this.typeahead ? this.id + "-input" : this.id + "-arrow"}
class="pkt-combobox__wrapper"
=${this.handleInputClick}
>
<div class="pkt-contents" ${v(this.helptextSlot)} name="helptext" slot="helptext"></div>
<div class="pkt-combobox" =${this.handleFocusOut}>
<div
class=${w({
"pkt-combobox__input": !0,
"pkt-combobox__input--fullwidth": this.fullwidth,
"pkt-combobox__input--open": this._isOptionsOpen,
"pkt-combobox__input--error": this.hasError,
"pkt-combobox__input--disabled": this.disabled
})}
tabindex="-1"
=${this.handleInputClick}
>
${this.placeholder && (!this._value.length || this.multiple && this.tagPlacement == "outside") && !this._inputFocus ? d`<span class="pkt-combobox__placeholder">${this.placeholder}</span>` : this.tagPlacement !== "outside" ? this.renderSingleOrMultipleValues() : y}
${this.renderInputField()}
<div
class="pkt-btn pkt-btn--tertiary pkt-combobox__arrow"
=${this.handleArrowClick}
=${this.handleArrowClick}
id="${this.id}-arrow"
${v(this.arrowRef)}
aria-expanded=${this._isOptionsOpen}
aria-controls="${this.id}-listbox"
aria-haspopup="listbox"
aria-label="Åpne liste"
?disabled=${this.disabled}
?data-disabled=${this.disabled}
role="button"
tabindex="${this.disabled ? "-1" : "0"}"
>
<pkt-icon
class=${w({
"pkt-combobox__arrow-icon": !0,
"pkt-combobox__arrow-icon--open": this._isOptionsOpen
})}
name="chevron-thin-down"
></pkt-icon>
</div>
<div ${v(this.focusRef)} tabindex="-1" =${this.handleArrowClick}></div>
</div>
<pkt-listbox
id="${this.id}-listbox"
.options=${this._options}
.isOpen=${this._isOptionsOpen}
.searchPlaceholder=${this.searchPlaceholder}
.label="Liste: ${this.label || ""}"
?includeSearch=${this.includeSearch}
?isMultiSelect=${this.multiple}
?allowUserInput=${this.allowUserInput && !this._maxIsReached}
?maxIsReached=${this._maxIsReached}
.customUserInput=${f(this._addValueText)}
.userMessage=${this._userInfoMessage}
=${this.handleSearch}
-toggle=${this.handleOptionToggled}
-all=${this.addAllOptions}
-options=${() => this._isOptionsOpen = !1}
.searchValue=${this._search || null}
.maxLength=${this.maxlength || 0}
${v(this.listboxRef)}
></pkt-listbox>
</div>
${this.tagPlacement === "outside" && this.multiple ? d`<div class="pkt-combobox__tags-outside">
${this.renderSingleOrMultipleValues()}
</div>` : y}
</pkt-input-wrapper>
`;
}
renderInputField() {
return this.typeahead || this.allowUserInput ? d`
<div class="pkt-combobox__input-div combobox__input">
<input
type="text"
id="${this.id}-input"
name=${(this.name || this.id) + "-input"}
=${this.handleInput}
=${this.handleInputKeydown}
=${this.handleFocus}
=${this.handleBlur}
autocomplete="off"
role="combobox"
aria-label=${f(this.label)}
aria-autocomplete=${this.typeahead ? "both" : "list"}
aria-controls="${this.id}-listbox"
aria-multiselectable=${f(this.multiple ? "true" : void 0)}
aria-activedescendant=${f(
this._value[0] && this.findValueInOptions(this._value[0]) ? `${this.id}-listbox-${this.findIndexInOptions(this._value[0])}` : void 0
)}
${v(this.inputRef)}
/>
</div>
` : d`
<input
type="hidden"
id="${this.id}-input"
name=${(this.name || this.id) + "-input"}
.value=${this._value.join(",")}
${v(this.inputRef)}
/>
`;
}
renderSingleOrMultipleValues() {
const t = !this.multiple, e = this._editingSingleValue ? null : this.renderValueTag(this.findValueInOptions(this._value[0])), i = R(
this._value,
(s) => s,
(s) => {
var a;
const l = this.findValueInOptions(s), n = (a = this.options.find((u) => u.value === s)) == null ? void 0 : a.tagSkinColor;
return d`
<pkt-tag
skin=${n || "blue-dark"}
?closeTag=${!this.disabled}
=${() => this.handleTagRemove(s)}
>
${this.renderValueTag(l)}
</pkt-tag>
`;
}
);
return t ? e : i;
}
renderValueTag(t) {
if (!t) return "";
switch (this.displayValueAs) {
case "prefixAndValue":
return d`<span data-focusfix=${this.id}>${t.prefix || ""} ${t.value}</span>`;
case "value":
return d`<span data-focusfix=${this.id}>${t.value}</span>`;
case "label":
default:
return d`<span data-focusfix=${this.id}>${t.label || t.value}</span>`;
}
}
// Event handlers
handleInput(t) {
if (t.stopPropagation(), t.stopImmediatePropagation(), this.disabled) return;
this.touched = !0;
const e = t.target;
if (this._search = e.value, this.checkForMatches(), this.typeahead)
if (this._search) {
if (this._options = this.options.filter(
(i) => {
var s;
return (s = i.fulltext) == null ? void 0 : s.toLowerCase().includes(this._search.toLowerCase());
}
), t.inputType !== "deleteContentBackward") {
const i = this._options.filter(
(s) => {
var l;
return !s.selected && ((l = s.label) == null ? void 0 : l.toLowerCase().startsWith(this._search.toLowerCase()));
}
);
if (i.length > 0 && this.inputRef.value && this.inputRef.value.type !== "hidden") {
const s = i[0];
s != null && s.label && (e.value = s.label, window.setTimeout(
() => e.setSelectionRange(this._search.length, e.value.length),
0
), e.selectionDirection = "backward");
}
}
} else
this._options = [...this.options];
}
handleFocus() {
if (!this.disabled) {
if (!this.multiple && this._value[0] && this.inputRef.value && this.inputRef.value.type !== "hidden") {
const t = this.findValueInOptions(this._value[0]);
this._editingSingleValue = !0, this.inputRef.value.value = this.displayValueAs === "label" && (t != null && t.label) ? t.label : this._value[0];
}
this._inputFocus = !0, this._search = "", this._options = [...this.options], this._isOptionsOpen = !0, this.onFocus(), this.requestUpdate();
}
}
handleFocusOut(t) {
var e, i, s, l, n;
if (!this.disabled && ((i = (e = t.relatedTarget) == null ? void 0 : e.closest("pkt-combobox")) == null ? void 0 : i.id) !== this.id && ((l = (s = t.relatedTarget) == null ? void 0 : s.closest("pkt-combobox")) == null ? void 0 : l.id) !== this.id && ((n = t.target) == null ? void 0 : n.getAttribute("data-focusfix")) !== this.id && t.relatedTarget !== this.focusRef.value && t.relatedTarget !== this.inputRef.value && t.relatedTarget !== this.arrowRef.value && this._isOptionsOpen) {
if (this._inputFocus = !1, this._addValueText = null, this._userInfoMessage = "", this._search = "", this.inputRef.value && this.inputRef.value.type !== "hidden" && this.inputRef.value.value !== "") {
const a = this.inputRef.value.value, u = this.findValueInOptions(a);
!this._value.includes(a) && !u ? this.allowUserInput ? this.addNewUserValue(a) : this.multiple || this.removeValue(this._value[0]) : u && !this._value.includes(u.value) && this.setSelected(u.value), this.inputRef.value.value = "";
}
this._isOptionsOpen = !1, this.onBlur();
}
}
handleBlur() {
this._inputFocus = !1, this._editingSingleValue = !1, this.onBlur();
}
handleInputClick(t) {
var e, i;
this.disabled || (t.currentTarget && t.currentTarget !== this.arrowRef.value && ((e = this.inputRef.value) == null ? void 0 : e.type) !== "hidden" ? (i = this.inputRef.value) == null || i.focus() : this.handleArrowClick(t));
}
handleArrowClick(t) {
var e, i;
this.disabled || t instanceof KeyboardEvent && t.key && t.key !== "Enter" && t.key !== " " && t.key !== "ArrowDown" || (t.stopImmediatePropagation(), t.preventDefault(), this._isOptionsOpen = !this._isOptionsOpen, this._isOptionsOpen ? (e = this.listboxRef.value) == null || e.focusFirstOrSelectedOption() : (i = this.arrowRef.value) == null || i.focus());
}
handleOptionToggled(t) {
this.toggleValue(t.detail);
}
handleSearch(t) {
t.stopPropagation(), this._search = t.detail.toLowerCase();
}
handleInputKeydown(t) {
var e, i, s;
switch (t.key) {
case ",":
case "Enter":
t.preventDefault(), this.addValue();
break;
case "Backspace":
!this._search && ((e = this.inputRef.value) == null ? void 0 : e.type) === "hidden" && this.removeLastValue(t);
break;
case "Tab":
case "ArrowDown":
t.shiftKey || ((i = this.listboxRef.value) == null || i.focusFirstOrSelectedOption(), t.preventDefault());
break;
case "Escape":
this._isOptionsOpen = !1, (s = this.arrowRef.value) == null || s.focus(), t.preventDefault();
break;
}
}
handleTagRemove(t) {
this.removeSelected(t);
}
blurInput() {
this.inputRef.value && this.inputRef.value.matches(":focus") && this.inputRef.value.blur();
}
checkForMatches() {
var n;
const t = ((n = this.inputRef.value) == null ? void 0 : n.value) || this._search || "", e = t.trim().toLowerCase() || "";
if (!e) {
!this.multiple && this._value[0] && this.removeValue(this._value[0]), this.resetComboboxInput(!1);
return;
}
const i = this._value.find((a) => a.toLowerCase() === e), s = this._options.filter(
(a) => {
var u;
return ((u = a.label) == null ? void 0 : u.toLowerCase().includes(e)) ?? !1;
}
), l = s.find(
(a) => {
var u;
return ((u = a.label) == null ? void 0 : u.toLowerCase()) === e || a.value.toLowerCase() === e;
}
);
switch (!0) {
case ((s.length === 0 || !l) && this.allowUserInput):
this._addValueText = t, this._userInfoMessage = "";
break;
case (s.length === 0 && !this.allowUserInput):
this._addValueText = null, this._userInfoMessage = "Ingen match i søket";
break;
case !!i:
this._addValueText = null, this._userInfoMessage = "Verdien er allerede valgt";
break;
case s.length > 1:
this._addValueText = null, this._userInfoMessage = "";
break;
default:
this._addValueText = null, this._userInfoMessage = "";
}
}
findValueInOptions(t) {
return this.options.find((e) => e.value === t || e.label === t) || null;
}
findIndexInOptions(t) {
return this._options.findIndex((e) => e.value === t || e.label === t);
}
isMaxItemsReached() {
const t = this.maxlength !== null && this._value.length >= this.maxlength;
return t ? this._maxIsReached = !0 : this._maxIsReached = !1, t;
}
toggleValue(t) {
var $, I;
if (this.disabled) return;
this.touched = !0, this._userInfoMessage = "", this._addValueText = null;
const e = (($ = this.findValueInOptions(t)) == null ? void 0 : $.value) || null, i = this._value.includes(t || e || ""), s = !!e, l = ((I = this._options.find((m) => m.value === t)) == null ? void 0 : I.disabled) || !1, n = !(t != null && t.trim()), a = !this.multiple, u = this.multiple, O = this.isMaxItemsReached();
let p = !1, b = !0, g = "", x = "";
l || (!s && this.allowUserInput && !n ? (this.addNewUserValue(t), g = "Ny verdi lagt til", p = !u) : !s && !this.allowUserInput ? (a && this._value[0] && this.removeValue(this._value[0]), b = !1, p = !0, g = "Ingen treff i søket") : i ? (this.removeValue(e), p = !0) : n && a ? (this.removeAllSelected(), p = !0) : a ? (this._value[0] && this.removeSelected(this._value[0]), this.setSelected(e), p = !1, this.inputRef.value && this.inputRef.value.type !== "hidden" && (this.inputRef.value.value = "", this.inputRef.value.blur())) : u && !O ? (this.setSelected(e), p = !0) : u && O ? (this._userInfoMessage = "Maks antall valg nådd", b = !1, x = t) : (a && this.removeAllSelected(), this._userInfoMessage = "Ingen gyldig verdi valgt", b = !1, p = !0, x = t), this._isOptionsOpen = p, p || window.setTimeout(() => {
var m;
(m = this.focusRef.value) == null || m.focus();
}, 0), this._userInfoMessage = g, this._search = x || "", this.resetComboboxInput(b), u && this.isMaxItemsReached());
}
setSelected(t) {
if (!this._value.includes(t)) {
if (this.multiple && this.isMaxItemsReached()) {
this._userInfoMessage = "Maks antall valg nådd";
return;
}
!this.multiple && this.removeAllSelected(), this._value = t ? [...this._value, t] : this._value, this._options = this._options.map((e) => (e.value === t && (e.selected = !0), e)), this.resetComboboxInput(!0);
}
}
removeSelected(t) {
if (!t) return;
this._value = this._value.filter((i) => i !== t);
const e = this.findValueInOptions(t);
e ? (e.selected = !1, e.userAdded ? (this._options = [...this._options.filter((i) => i.value !== t)], this.options = [...this.options.filter((i) => i.value !== t)]) : this._options = [...this._options, e]) : !t && !this.multiple && (this._options = this._options.map((i) => (i.selected = !1, i)));
}
addAllOptions() {
if (this.multiple) {
if (this.maxlength && this._options.length > this.maxlength) {
this._userInfoMessage = "For mange valgt";
return;
}
this._value = this._options.map((t) => t.value), this._options = this._options.map((t) => (t.selected = !0, t)), this.requestUpdate();
}
}
removeAllSelected() {
this._value = [], this._options = this._options.map((t) => (t.selected = !1, t)), this._options = this._options.filter((t) => !t.userAdded), this.requestUpdate();
}
addValue() {
var e;
const t = ((e = this.inputRef.value) == null ? void 0 : e.value.trim()) || "";
this._search = t, this.toggleValue(t);
}
removeValue(t) {
this._value = this.multiple ? this._value.filter((e) => e !== t) : [], this.removeSelected(t);
}
addNewUserValue(t) {
if (!t || t.trim() === "") return;
if (!this.multiple)
this._value[0] && this.removeSelected(this._value[0]), this._value = [t], this._isOptionsOpen = !1, this.blurInput();
else if (!this.findValueInOptions(t)) {
if (this.isMaxItemsReached()) return;
this._value = [...this._value, t];
}
const e = { value: t, label: t, userAdded: !0 };
this.options = [e, ...this.options], this._options = [e, ...this._options], this.setSelected(t), this.requestUpdate();
}
resetComboboxInput(t = !0) {
if (this._addValueText = null, this.inputRef.value && this.inputRef.value.type !== "hidden" && t)
if (this._search = "", this.multiple)
this.inputRef.value.value = "";
else {
const e = this.findValueInOptions(this._value[0]);
window.setTimeout(() => {
!this.inputRef.value || this.inputRef.value.type === "hidden" || (this.inputRef.value.value = this.displayValueAs === "label" && (e != null && e.label) ? e.label : this._value[0] || "");
}, 0), this._userInfoMessage = "";
}
this._options = [...this.options];
}
removeLastValue(t) {
if (this._value.length === 0) return;
t.preventDefault();
const e = this._value[this._value.length - 1];
e && this.removeSelected(e), this.isMaxItemsReached();
}
};
o([
r({ type: String, reflect: !0 })
], h.prototype, "value", 2);
o([
r({ type: Array })
], h.prototype, "options", 2);
o([
r({ type: Array })
], h.prototype, "defaultOptions", 2);
o([
r({ type: Boolean })
], h.prototype, "allowUserInput", 2);
o([
r({ type: Boolean })
], h.prototype, "typeahead", 2);
o([
r({ type: Boolean })
], h.prototype, "includeSearch", 2);
o([
r({ type: String })
], h.prototype, "searchPlaceholder", 2);
o([
r({ type: Boolean })
], h.prototype, "multiple", 2);
o([
r({ type: Number })
], h.prototype, "maxlength", 2);
o([
r({ type: String })
], h.prototype, "displayValueAs", 2);
o([
r({ type: String })
], h.prototype, "tagPlacement", 2);
o([
c()
], h.prototype, "_options", 2);
o([
c()
], h.prototype, "_isOptionsOpen", 2);
o([
c()
], h.prototype, "_value", 2);
o([
c()
], h.prototype, "_userInfoMessage", 2);
o([
c()
], h.prototype, "_addValueText", 2);
o([
c()
], h.prototype, "_maxIsReached", 2);
o([
c()
], h.prototype, "_search", 2);
o([
c()
], h.prototype, "_inputFocus", 2);
o([
c()
], h.prototype, "_editingSingleValue", 2);
h = o([
k("pkt-combobox")
], h);
export {
h as P
};