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