UNPKG

gov-gui

Version:

Gov UI Component Library Demo ready Build

282 lines (278 loc) 14.6 kB
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