UNPKG

@stimulus-library/controllers

Version:

A library of useful controllers for Stimulus

137 lines (136 loc) 4.4 kB
import { BaseController, clamp, scrollToElement } from "@stimulus-library/utilities"; import { installClassMethods } from "@stimulus-library/mixins"; export class NavigateFormErrorsController extends BaseController { constructor() { super(...arguments); this._errors = []; this._firstClick = false; } get defaultCurrentClasses() { return ["currentError"]; } get _errorCount() { return this._errors.length; } get _previousIndex() { const index = this._index - 1; if (index < 0) { return 0; } return index; } get _nextIndex() { const index = this._index + 1; if (index > this._errors.length - 1) { return this._errors.length - 1; } return index; } get _index() { return clamp(this.hasIndexValue ? this.indexValue : 0, 0, this._errors.length); } get _selector() { if (this.hasSelectorValue) { return this.selectorValue; } else { throw new Error("Expected `selectorValue` to be present"); } } get _currentError() { return this._errors[this._index]; } get _otherErrors() { return this._errors.filter((error, index) => index !== this._index); } connect() { installClassMethods(this); requestAnimationFrame(() => { this._firstClick = true; this._toggleButtons(); this._toggleVisibility(); }); } async current(event) { event === null || event === void 0 ? void 0 : event.preventDefault(); if (this._firstClick) { this._firstClick = false; this._toggleButtons(); } await scrollToElement(this._currentError, { behavior: "smooth", block: "center", inline: "center" }); this._updateClasses(); } async next(event) { event === null || event === void 0 ? void 0 : event.preventDefault(); if (this._firstClick) { this._firstClick = false; this._toggleButtons(); } else { this.indexValue = this._nextIndex; } await scrollToElement(this._currentError, { behavior: "smooth", block: "center", inline: "center" }); this._updateClasses(); } async previous(event) { event === null || event === void 0 ? void 0 : event.preventDefault(); if (this._firstClick) { this._firstClick = false; this._toggleButtons(); } else { this.indexValue = this._previousIndex; } await scrollToElement(this._currentError, { behavior: "smooth", block: "center", inline: "center" }); this._updateClasses(); } indexValueChanged() { this._toggleButtons(); } selectorValueChanged() { this._errors = Array.from(document.querySelectorAll(this._selector)); this.indexValue = 0; this._toggleButtons(); this._toggleVisibility(); } _updateClasses() { this.addCurrentClasses(this._currentError); this._otherErrors.forEach((error) => this.removeCurrentClasses(error)); } _toggleVisibility() { if (this._errorCount === 0) { this.el.style.display = "none"; } else { this.el.style.display = ""; } } _toggleButtons() { if (this.hasNextTarget) { if (!this.hasCurrentTarget && this._firstClick && this.indexValue == this._errorCount - 1) { this.nextTarget.removeAttribute("disabled"); return; } else if (this.indexValue >= this._errorCount - 1) { this.nextTarget.setAttribute("disabled", "true"); } else { this.nextTarget.removeAttribute("disabled"); } } if (this.hasPreviousTarget) { if (this.indexValue <= 0) { this.previousTarget.setAttribute("disabled", "true"); } else { this.previousTarget.removeAttribute("disabled"); } } } } NavigateFormErrorsController.values = { selector: String, index: Number, }; NavigateFormErrorsController.classes = ["current"]; NavigateFormErrorsController.targets = ["next", "current", "previous"];