gov-gui
Version:
Gov UI Component Library Demo ready Build
282 lines (278 loc) • 14.6 kB
JavaScript
import { r as registerInstance, c as createEvent, h, g as getElement } from './index-6e6d5b7d.js';
import { g as getGlobalPropsClasses } from './global-styles-helper-eea949ad.js';
import { g as getAnimationClasses } from './animation-helpers-c4acb0ac.js';
import { a as accessibleLifecycle } from './accessible-bd4bc261.js';
const govStepperCss = ".stepper-container{position:relative;padding:20px;border-radius:12px;border:1px solid var(--border-color);box-shadow:0 2px 5px rgba(0, 0, 0, 0.1)}.stepper{display:flex;gap:1rem;margin-bottom:1.5rem}.stepper.horizontal{justify-content:space-between}.stepper.horizontal::before{content:'';position:absolute;top:35px;left:40px;right:40px;height:2px;background-color:#0098DB;z-index:-1}.stepper.vertical{flex-direction:column;align-items:flex-start}.stepper.vertical::before{content:'';position:absolute;top:30px;left:35px;height:calc(100% - 100px);width:2px;background-color:#0098DB;z-index:-1}.step{display:flex;align-items:center;gap:0.5rem}.step-number{width:30px;height:30px;border-radius:50%;background:var(--border-color);display:flex;align-items:center;justify-content:center;font-weight:bold}.step.active .step-number{background:var(--primary-color);color:var(--white-color)}.step.completed .step-number{background:var(--primary-color);color:var(--white-color)}.step-content{margin-top:1rem}.stepper-buttons{display:flex;gap:0.5rem;margin-top:1.5rem}.step-error{margin-top:10px;padding:0.75rem;border-radius:4px;background-color:var(--danger-color);color:var(--white-color);text-align:center}.submit-status{margin-top:1rem;padding:0.75rem;border-radius:4px;display:none;text-align:center}.submit-status.visible{display:block}.status-success{background:var(--success-color);color:var(--white-color)}.status-error{background:var(--error-color);color:var(--white-color)}.loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(129, 19, 19, 0.8);display:flex;align-items:center;justify-content:center}";
const GovStepperStyle0 = govStepperCss;
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const GovStepper = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.stepChanged = createEvent(this, "stepChanged", 7);
this.stepSubmitted = createEvent(this, "stepSubmitted", 7);
this.stepError = createEvent(this, "stepError", 7);
this.currentStep = 0;
this.steps = [];
this.isSubmitting = false;
this.submitStatus = 'idle';
this.stepErrorMessage = ''; // Holds error messages for the current step
this.variant = 'horizontal';
this.nextText = 'Next';
this.prevText = 'Previous';
this.submitText = 'Submit';
this.resetOnSubmit = true; // Reset on submit by default
this.maxStepsVisible = 5; // For horizontal variant
this._styles = {};
this._buttonStyles = {};
this.animationDelay = '2s';
this.allClasses = '';
}
handleStepChange(newValue) {
this.stepChanged.emit(newValue);
}
//watching for any change in animations to trigger them
watchAnimations() {
this.provideClass();
}
watchAnimationsDelay() {
this.provideClass();
}
watchAnimationsSpeed() {
this.provideClass();
}
watchStyles(newValue) {
if (typeof newValue === 'string') {
try {
this._styles = JSON.parse(newValue);
}
catch (e) {
console.error('Failed to parse styles:', e);
this._styles = {};
}
}
else {
this._styles = newValue || {};
}
}
watchButtonStyles(newValue) {
if (typeof newValue === 'string') {
try {
this._buttonStyles = JSON.parse(newValue);
}
catch (e) {
console.error('Failed to parse styles:', e);
this._buttonStyles = {};
}
}
else {
this._buttonStyles = newValue || {};
}
}
updateGlobalClasses() {
this.provideClass();
}
connectedCallback() {
// Any component-specific setup here
}
componentWillLoad() {
// Collect all step slots (assuming slots are named step-0, step-1, etc.)
const slotElements = this.el.querySelectorAll('[slot^="step-"]');
this.steps = Array.from(slotElements).map((_, index) => `Step ${index + 1}`);
this.watchButtonStyles(this.buttonStyles);
this.watchStyles(this.styles);
this.provideClass();
}
//Called on change of any animation related property to trigger change
provideClass() {
const animationClasses = getAnimationClasses({
animation: this.animation,
animationDelay: this.animationDelay,
animationSpeed: this.animationSpeed
});
this.allClasses = getGlobalPropsClasses({
classes: (this.classes ? this.classes + ' ' : '') + animationClasses,
variant: this.variant,
size: this.size
});
}
async handleStepTransition(direction) {
try {
if (direction === 'next' && this.currentStep < this.steps.length - 1) {
// Validate current step's inputs before moving to next step.
if (!this.areInputsValid(this.currentStep))
return;
if (this.validateStep && !(await this.validateStep(this.currentStep)))
return;
// Clear any previous error messages once validation passes
this.stepErrorMessage = '';
this.currentStep += 1;
}
else if (direction === 'prev' && this.currentStep > 0) {
this.currentStep -= 1;
}
}
catch (error) {
this.submitStatus = 'error';
this.stepError.emit(error);
}
}
async handleSubmit() {
try {
this.isSubmitting = true;
// Collect input values from all custom input components.
const formData = this.collectInputData();
console.log('Collected Data:', formData); // Debugging
// Emit the collected data.
this.stepSubmitted.emit(formData);
// Call onSubmit handler if provided.
if (this.onSubmit) {
await this.onSubmit();
}
// Reset inputs if resetOnSubmit is true.
if (this.resetOnSubmit) {
this.resetInputs();
this.currentStep = 0;
this.submitStatus = 'success';
setTimeout(() => {
this.submitStatus = 'idle'; // Reset status after showing success message.
}, 2000);
}
}
catch (error) {
this.submitStatus = 'error';
this.stepError.emit(error);
}
finally {
this.isSubmitting = false;
}
}
/**
* Helper: Returns the current value from a custom component.
* For gov-input and gov-radiobutton, it attempts to use the public 'value' property;
* for gov-checkbox, it returns the public 'checked' property.
*/
getValueFromComponent(component) {
const comp = component;
const tag = component.tagName.toLowerCase();
if (tag === 'gov-input') {
return comp.value !== undefined ? comp.value : component.getAttribute('value') || '';
}
else if (tag === 'gov-radiobutton') {
return comp.value !== undefined ? comp.value : '';
}
else if (tag === 'gov-checkbox') {
return comp.checked;
}
return null;
}
/**
* Collects input data from all custom components (gov-input, gov-radiobutton, gov-checkbox)
* present in the stepper.
*/
collectInputData() {
const components = this.el.querySelectorAll('gov-input, gov-radiobutton, gov-checkbox');
const formData = {};
components.forEach(component => {
const name = component.getAttribute('name');
if (!name)
return;
const value = this.getValueFromComponent(component);
if (value !== null && value !== undefined) {
// For checkboxes, include only if checked.
if (component.tagName.toLowerCase() === 'gov-checkbox') {
if (value) {
formData[name] = component.getAttribute('value') || 'true';
}
}
else {
formData[name] = String(value);
}
}
});
return formData;
}
/**
* Validates all required fields within the current step.
* This queries for custom elements marked with [required] and uses the helper function
* to determine if they have a non-empty value (or are checked, for checkboxes).
* If there are validation errors, an error message is stored in `stepErrorMessage`.
*/
areInputsValid(stepIndex) {
const stepSlot = this.el.querySelector(`[slot="step-${stepIndex}"]`);
if (!stepSlot)
return false;
// Query custom elements that are marked as required.
const requiredComponents = stepSlot.querySelectorAll('gov-input[required], gov-radiobutton[required], gov-checkbox[required]');
let allValid = true;
const messages = [];
requiredComponents.forEach(component => {
const tag = component.tagName.toLowerCase();
// Use the 'name' attribute for a friendly label.
const name = component.getAttribute('name') || 'This field';
const value = this.getValueFromComponent(component);
if (tag === 'gov-input' || tag === 'gov-radiobutton') {
if (!value || (typeof value === 'string' && value.trim() === '')) {
allValid = false;
messages.push(`${name} is required.`);
}
}
else if (tag === 'gov-checkbox') {
if (!value) {
allValid = false;
messages.push(`You must agree to ${name}.`);
}
}
});
// Update the state error message for display in the step.
this.stepErrorMessage = allValid ? '' : messages.join(' ');
return allValid;
}
/**
* Resets all custom input components by calling their reset() method, if available.
*/
resetInputs() {
const components = this.el.querySelectorAll('gov-input, gov-radiobutton, gov-checkbox');
components.forEach(component => {
if (typeof component.reset === 'function') {
component.reset();
}
});
}
render() {
const isLastStep = this.currentStep === this.steps.length - 1;
const statusClass = this.submitStatus !== 'idle' ? 'visible' : '';
return (h("div", { key: '4337544e696eb41b173bb6185db8b7fa4722e5d9', class: `stepper-container ${this.allClasses}`, style: Object.assign({}, this._styles) }, this.isSubmitting && (h("div", { key: '763a75648aa0a1a8bbaa56089737668bcadfed56', class: "loading-overlay" }, h("gov-spinner", { key: '387423a8f5672862995322cfe74e79d1a6aaff21', size: "lg" }))), h("div", { key: 'edd6d1def46e014411419d7e8ef68660cd255d3c', class: { stepper: true, [this.variant]: true } }, this.steps.map((_, index) => (h("div", { class: {
step: true,
active: index === this.currentStep,
completed: index < this.currentStep,
[this.variant]: true,
} }, h("div", { class: "step-number" }, index + 1), this.variant === 'vertical' && index === this.currentStep && (h("div", { class: "step-content" }, h("slot", { name: `step-${this.currentStep}` }))))))), this.variant === 'horizontal' && (h("div", { key: 'b1982b940d166dea3b1c12d2e23c01880b5c2c7b', class: "step-content" }, h("slot", { key: '3f6b0b0f556b93bc12a3011cba70b3b9a7757c89', name: `step-${this.currentStep}` }), this.stepErrorMessage && (h("div", { key: '30e62ecd2a2f8c9bfd8e08dbee4c7b577dc2d199', class: "step-error" }, this.stepErrorMessage)))), h("div", { key: '8d08d8bf9d8b4feb4cba90940ce5249a1f01002e', class: "stepper-buttons" }, h("gov-button", { key: 'a467d86a4ae44d1cf0d447d9d4b07d46902ce6d6', variant: "white", disabled: this.currentStep === 0 || this.isSubmitting, onClick: () => this.handleStepTransition('prev'), label: this.prevText, styles: Object.assign({}, this._buttonStyles) }), h("gov-button", { key: 'b5a2066e788f6961dd0189d27eeef583fc1a323e', variant: "primary", disabled: this.isSubmitting, onClick: isLastStep
? () => this.handleSubmit()
: () => this.handleStepTransition('next'), label: isLastStep ? this.submitText : this.nextText, styles: Object.assign({}, this._buttonStyles) })), h("div", { key: 'be0b4f5d2dd066e31d44efbb0b22ad571df5bdfe', class: `submit-status ${statusClass} status-${this.submitStatus}` }, h("slot", { key: '10f0d05e763580619c534e25c07ad2e4796e0abb', name: this.submitStatus === 'success' ? 'success-message' : 'error-message' }, this.submitStatus === 'success' && 'Form submitted successfully!', this.submitStatus === 'error' && 'Submission failed. Please try again.'))));
}
get el() { return getElement(this); }
static get watchers() { return {
"currentStep": ["handleStepChange"],
"animation": ["watchAnimations"],
"animationDelay": ["watchAnimationsDelay"],
"animationSpeed": ["watchAnimationsSpeed"],
"styles": ["watchStyles"],
"buttonStyles": ["watchButtonStyles"],
"classes": ["updateGlobalClasses"]
}; }
};
__decorate([
accessibleLifecycle('gov-stepper')
], GovStepper.prototype, "connectedCallback", null);
GovStepper.style = GovStepperStyle0;
export { GovStepper as gov_stepper };
//# sourceMappingURL=gov-stepper.entry.js.map