UNPKG

@postnord/web-components

Version:
290 lines (289 loc) 11.4 kB
/*! * Built with Stencil * By PostNord. */ import { h, Host } from "@stencil/core"; import { translations } from "./translations"; import { en, awaitTopbar, uuidv4 } from "../../../globals/helpers"; /** * The `pn-progress-stepper` is used to visualize the users progress through a flow (checkout/survey, etc...). **/ export class PnProgressStepper { id = `pn-progress-stepper-${uuidv4()}`; minStep = 1; maxStep = 7; hostElement; builtInLabel; /** Percentage calculated with currentStep / totalSteps. */ progressValue = 0; /** Set custom label for the stepper, default label is "Step". */ label = ''; /** Set a custom HTML id on the progress stepper element to associate progress bar with label. */ progressStepperId = ''; /** * Set the language manually, only use this prop if the pnTopbar is not loaded. * Will not overwrite the custom `label` prop if used. **/ language = null; /** Set total amount of steps, maximum allowed is `7`. @category Steps */ totalSteps = this.maxStep; /** The current step of the progress stepper. @category Steps */ currentStep = this.minStep; /** You can add a custom optional string to the label if you need a name for the current step. @category Steps */ stepName; /** * Use the dots visual, instead of the bar. * * This will hide the label from view, but is still accessible to screenreaders. * * @since v7.16.0 * @category Visual */ dots = false; stepWatchers(a, b, c) { if (c === 'currentStep') this.validate(a, 'currentStep'); if (c === 'totalSteps') this.validate(b, 'totalSteps'); this.calculateProgress(); } watchLanguage() { this.builtInLabel = translations.STEP[this.language || en]; } async componentWillLoad() { this.watchLanguage(); this.validate(this.currentStep, 'currentStep'); this.validate(this.totalSteps, 'totalSteps'); this.calculateProgress(); if (this.language === null) await awaitTopbar(this.hostElement); } validate(step, prop) { const componentName = this.hostElement.localName; if (step < this.minStep) { console.warn(`${componentName}: The ${prop} ${step} is below the minimum allowed steps of ${this.minStep}. ${prop} will default to ${this.minStep}.`); this[prop] = this.minStep; } if (prop === 'currentStep' && step > this.totalSteps) { console.warn(`${componentName}: The ${prop} ${step} is above totalSteps ${this.totalSteps}, ${prop} will default to ${this.totalSteps}.`); this[prop] = this.totalSteps; } if (step > this.maxStep) { console.warn(`${componentName}: The ${prop} ${step} is above the maximum allowed steps of ${this.maxStep}. ${prop} will default to ${this.maxStep}.`); this[prop] = this.maxStep; } } calculateProgress() { try { this.progressValue = Math.floor((this.currentStep / this.totalSteps) * 100); this.hostElement.style.setProperty('--pn-progress-value', `${this.progressValue}%`); } catch (error) { console.error(`${this.hostElement.localName}:`, error.message); } } getLabel() { return this.label || this.builtInLabel; } getId() { return this.progressStepperId || this.id; } render() { return (h(Host, { key: 'eae49d6f5d3085e714bff2e668694523185c6fb6' }, h("label", { key: 'd5ec64934b8e8eab33b771d20aa34cdfb595f600', htmlFor: this.getId(), class: 'pn-progress-label' + (this.dots ? ' pn-progress-sr-only' : '') }, h("span", { key: 'a30465882d45cdc3ee6513c79a9b9a0cacb68a88' }, this.getLabel(), " ", this.currentStep, "/", this.totalSteps), this.stepName && h("span", { key: 'fb4f2eb25ccd60c648c7a2d077dfce35b6888f52' }, " - ", this.stepName)), h("progress", { key: '6822b750b6d86644f5a77115d449c050b7be418d', id: this.getId(), class: "pn-progress-sr-only", max: "100", value: this.progressValue }), this.dots ? (h("div", { class: "pn-progress-dots", "aria-hidden": "true" }, [...Array(this.totalSteps)].map((_, i) => (h("div", { class: "pn-progress-dot", "data-active": i + 1 <= this.currentStep, key: i }))))) : (h("div", { "aria-hidden": "true", class: "pn-progress" }, h("div", { class: "pn-progress-value", "data-full": this.currentStep === this.totalSteps }))))); } static get is() { return "pn-progress-stepper"; } static get originalStyleUrls() { return { "$": ["pn-progress-stepper.scss"] }; } static get styleUrls() { return { "$": ["pn-progress-stepper.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Set custom label for the stepper, default label is \"Step\"." }, "getter": false, "setter": false, "reflect": false, "attribute": "label", "defaultValue": "''" }, "progressStepperId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Set a custom HTML id on the progress stepper element to associate progress bar with label." }, "getter": false, "setter": false, "reflect": false, "attribute": "progress-stepper-id", "defaultValue": "''" }, "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": "Set the language manually, only use this prop if the pnTopbar is not loaded.\nWill not overwrite the custom `label` prop if used." }, "getter": false, "setter": false, "reflect": false, "attribute": "language", "defaultValue": "null" }, "totalSteps": { "type": "number", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Steps" }], "text": "Set total amount of steps, maximum allowed is `7`." }, "getter": false, "setter": false, "reflect": false, "attribute": "total-steps", "defaultValue": "this.maxStep" }, "currentStep": { "type": "number", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Steps" }], "text": "The current step of the progress stepper." }, "getter": false, "setter": false, "reflect": false, "attribute": "current-step", "defaultValue": "this.minStep" }, "stepName": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Steps" }], "text": "You can add a custom optional string to the label if you need a name for the current step." }, "getter": false, "setter": false, "reflect": false, "attribute": "step-name" }, "dots": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "since", "text": "v7.16.0" }, { "name": "category", "text": "Visual" }], "text": "Use the dots visual, instead of the bar.\n\nThis will hide the label from view, but is still accessible to screenreaders." }, "getter": false, "setter": false, "reflect": false, "attribute": "dots", "defaultValue": "false" } }; } static get states() { return { "builtInLabel": {}, "progressValue": {} }; } static get elementRef() { return "hostElement"; } static get watchers() { return [{ "propName": "currentStep", "methodName": "stepWatchers" }, { "propName": "totalSteps", "methodName": "stepWatchers" }, { "propName": "language", "methodName": "watchLanguage" }]; } }