@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
137 lines (136 loc) • 4.4 kB
JavaScript
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"];