UNPKG

@postnord/web-components

Version:
597 lines (596 loc) 23.7 kB
/*! * Built with Stencil * By PostNord. */ import { uuidv4, awaitTopbar, en } from "../../../globals/helpers"; import { h, Host } from "@stencil/core"; import { close_small, search } from "pn-design-assets/pn-assets/icons.js"; import { translations } from "./translations"; /** * The search field has multiple button variants that changes the visual appearance. * * @nativeInput Use the `input` event to listen to content being modified by the user. It is emitted everytime a user writes or removes content in the input. * @nativeChange The `change` event is emitted when the input loses focus, the user clicks `Enter` or makes a selection (such as auto complete or suggestions). */ export class PnSearchField { id = `pn-search-field-${uuidv4()}`; hostElement; /** Provide an aria-label for the search field. */ label; /** Override the pntopbar language. */ language = undefined; /** Set the value of the search field. @category Native attributes */ value = ''; /** Set HTML name of the search input. @category Native attributes */ name; /** Set a search field placeholder. @category Native attributes */ placeholder; /** Allow the browser to autocomplete the search field. @category Native attributes */ autocomplete; /** Point to a datalist element with this id. @category Native attributes */ list; /** Set the search field as required. @category Native attributes */ required = false; /** Disable the search field. @category Native attributes */ disabled = false; /** Display loading animation. @category Features */ loading = false; /** * Button variant changes the visual of the search field: * - `''` Standard with a blue button. * - `simple` | ~~`icon`~~ with simple white icon only button. * - `auto` | ~~`icon-inline`~~ | ~~`none`~~ with a white inline search button. * - `jumbo` with a larger blue icon only button. * * @since v7.18.0: Use `''`, `simple`, `auto` or `jumbo`. * * @category Features */ button = ''; /** Label for the button element. @category Features */ buttonLabel; /** Add a tooltip to the search button. @category Features */ buttonTooltip; /** * Light instead of dark search button. * * @deprecated The color is now set automatically based on the button prop. * @category Features */ buttonLight = false; /** Set a custom ID for the search input. @since v7.25.0 @category HTML attributes */ pnId; /** * Provide the label from another element via its ID. * We strongly recommend you use the `label` prop instead. * @since v7.25.0 * @category HTML attributes */ pnAriaLabelledby; /** Set a unique ID for the search input. @deprecated Use `pn-id` instead. @category HTML attributes */ searchid; /** This is emitted on search submission both with keyboard and mouse. */ search; /** Custom event that handles both clearing and input to have the option of just binding listeners to one event instead of two. */ update; inputHandler() { this.update.emit(this.value); } async componentWillLoad() { if (this.language === undefined) await awaitTopbar(this.hostElement); } getId() { return this.pnId || this.searchid || this.id; } translate(prop) { return translations?.[prop]?.[this.language || en]; } emitSearch({ click, button }) { if (click?.type === 'click' || (button?.type === 'keydown' && button?.key === 'Enter')) { // We prevent the native search event since it's not supported in IE and FF, then we emit our own instead const event = click || button; event.preventDefault(); this.search.emit(this.value); } } setVal(e) { this.value = e.target.value; } clearInput() { this.value = ''; this.update.emit(this.value); this.hostElement.querySelector('input').focus(); } displayLabel() { return !!this.label; } getAriaLabelledby() { return !this.displayLabel() ? this.pnAriaLabelledby : null; } getButtonLabel() { return this.buttonLabel || this.translate('SEARCH'); } /** icon === simple-search */ searchSimple() { return this.button === 'icon' || this.button === 'simple'; } /** none | icon-inline === auto-search */ searchAuto() { return this.button === 'icon-inline' || this.button === 'none' || this.button === 'auto'; } searchJumbo() { return this.button === 'jumbo'; } searchButtonAppearance() { return this.searchSimple() ? 'light' : null; } searchButtonVariant() { return this.searchSimple() ? 'outlined' : null; } render() { return (h(Host, { key: '5ffa0c58cd54c1a6588147e5ec9a72e0045e16aa' }, h("div", { key: 'd18a2bdaef46229ff87fe1612d39489443fd70cc', class: "pn-search-field", "data-inline": this.searchAuto(), "data-loading": this.loading, "data-searching": !!this.value, "data-jumbo": this.searchJumbo() }, h("div", { key: '1a7c9e872e0c7696f0d1d84a3420eade2b1cd2ed', class: "pn-search-field-container" }, h("input", { key: '3ff3e9809123283f66ea933f7bc9fb5a92489e51', class: "pn-search-field-input", id: this.getId(), type: "search", value: this.value, name: this.name, placeholder: this.placeholder, autocomplete: this.autocomplete, list: this.list, required: this.required, disabled: this.disabled, "aria-label": this.label, "aria-labelledby": this.getAriaLabelledby(), onKeyDown: e => this.emitSearch({ button: e }), onInput: e => this.setVal(e) }), h("div", { key: 'eeb6d382c93f98da5561b30219ef829c668eab54', class: "pn-search-field-inline" }, this.searchAuto() && (h("pn-button", { key: '65d7049753656a7f4bce29e7e8c99305e99f15e2', class: "pn-search-field-button", type: "button", appearance: "light", small: true, icon: search, iconOnly: true, arialabel: this.getButtonLabel(), noTab: this.loading, onPnClick: e => this.emitSearch({ click: e.detail }) })), !this.disabled && (h("pn-button", { key: '58bae5e2fc05c66cee21081e71904530ca75a0b9', small: true, class: "pn-search-field-clear", type: "button", appearance: "light", icon: close_small, iconOnly: true, arialabel: this.translate('CLEAR'), noTab: !this.value || this.loading, onPnClick: () => this.clearInput() })), this.searchAuto() && h("pn-spinner", { key: 'd3955278766f786897eb0024c7523179a2ad78c4', class: "pn-search-field-spinner" }))), !this.searchAuto() && (h("pn-button", { key: 'fd46d299cfd9600e671e827daa4a00675a6bd25b', class: "pn-search-field-submit", label: this.getButtonLabel(), tooltip: this.buttonTooltip, appearance: this.searchButtonAppearance(), variant: this.searchButtonVariant(), icon: search, iconOnly: this.searchSimple() || this.searchJumbo(), arialabel: this.searchSimple() || this.searchJumbo() ? this.getButtonLabel() : null, loading: this.loading, onPnClick: e => this.emitSearch({ click: e.detail }) }))))); } static get is() { return "pn-search-field"; } static get originalStyleUrls() { return { "$": ["pn-search-field.scss"] }; } static get styleUrls() { return { "$": ["pn-search-field.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Provide an aria-label for the search field." }, "getter": false, "setter": false, "reflect": false, "attribute": "label" }, "language": { "type": "string", "mutable": false, "complexType": { "original": "PnLanguages", "resolved": "\"\" | \"da\" | \"en\" | \"fi\" | \"no\" | \"sv\"", "references": { "PnLanguages": { "location": "import", "path": "@/globals/types", "id": "src/globals/types.ts::PnLanguages", "referenceLocation": "PnLanguages" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Override the pntopbar language." }, "getter": false, "setter": false, "reflect": false, "attribute": "language", "defaultValue": "undefined" }, "value": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Set the value of the search field." }, "getter": false, "setter": false, "reflect": false, "attribute": "value", "defaultValue": "''" }, "name": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Set HTML name of the search input." }, "getter": false, "setter": false, "reflect": false, "attribute": "name" }, "placeholder": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Set a search field placeholder." }, "getter": false, "setter": false, "reflect": false, "attribute": "placeholder" }, "autocomplete": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Allow the browser to autocomplete the search field." }, "getter": false, "setter": false, "reflect": false, "attribute": "autocomplete" }, "list": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Point to a datalist element with this id." }, "getter": false, "setter": false, "reflect": false, "attribute": "list" }, "required": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Set the search field as required." }, "getter": false, "setter": false, "reflect": false, "attribute": "required", "defaultValue": "false" }, "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Disable the search field." }, "getter": false, "setter": false, "reflect": false, "attribute": "disabled", "defaultValue": "false" }, "loading": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Display loading animation." }, "getter": false, "setter": false, "reflect": false, "attribute": "loading", "defaultValue": "false" }, "button": { "type": "string", "mutable": false, "complexType": { "original": "PnSearchFieldButton", "resolved": "\"\" | \"auto\" | \"icon\" | \"icon-inline\" | \"jumbo\" | \"none\" | \"simple\"", "references": { "PnSearchFieldButton": { "location": "import", "path": "@/globals/types", "id": "src/globals/types.ts::PnSearchFieldButton", "referenceLocation": "PnSearchFieldButton" } } }, "required": false, "optional": false, "docs": { "tags": [{ "name": "since", "text": "v7.18.0: Use `''`, `simple`, `auto` or `jumbo`." }, { "name": "category", "text": "Features" }], "text": "Button variant changes the visual of the search field:\n- `''` Standard with a blue button.\n- `simple` | ~~`icon`~~ with simple white icon only button.\n- `auto` |\u00A0~~`icon-inline`~~ | ~~`none`~~ with a white inline search button.\n- `jumbo` with a larger blue icon only button." }, "getter": false, "setter": false, "reflect": false, "attribute": "button", "defaultValue": "''" }, "buttonLabel": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Label for the button element." }, "getter": false, "setter": false, "reflect": false, "attribute": "button-label" }, "buttonTooltip": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Add a tooltip to the search button." }, "getter": false, "setter": false, "reflect": false, "attribute": "button-tooltip" }, "buttonLight": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "deprecated", "text": "The color is now set automatically based on the button prop." }, { "name": "category", "text": "Features" }], "text": "Light instead of dark search button." }, "getter": false, "setter": false, "reflect": false, "attribute": "button-light", "defaultValue": "false" }, "pnId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.25.0" }, { "name": "category", "text": "HTML attributes" }], "text": "Set a custom ID for the search input." }, "getter": false, "setter": false, "reflect": false, "attribute": "pn-id" }, "pnAriaLabelledby": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.25.0" }, { "name": "category", "text": "HTML attributes" }], "text": "Provide the label from another element via its ID.\nWe strongly recommend you use the `label` prop instead." }, "getter": false, "setter": false, "reflect": false, "attribute": "pn-aria-labelledby" }, "searchid": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "deprecated", "text": "Use `pn-id` instead." }, { "name": "category", "text": "HTML attributes" }], "text": "Set a unique ID for the search input." }, "getter": false, "setter": false, "reflect": false, "attribute": "searchid" } }; } static get events() { return [{ "method": "search", "name": "search", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "This is emitted on search submission both with keyboard and mouse." }, "complexType": { "original": "string", "resolved": "string", "references": {} } }, { "method": "update", "name": "update", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Custom event that handles both clearing and input to have the option of just binding listeners to one event instead of two." }, "complexType": { "original": "string", "resolved": "string", "references": {} } }]; } static get elementRef() { return "hostElement"; } static get listeners() { return [{ "name": "input", "method": "inputHandler", "target": undefined, "capture": false, "passive": false }]; } }