@postnord/web-components
Version:
PostNord Web Components
597 lines (596 loc) • 23.7 kB
JavaScript
/*!
* 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
}];
}
}