Passed
Push — task/improve-find-skills-modal... ( 114b93...aefbfa )
by Yonathan
06:27
created

resources/assets/js/helpers/forms.ts   A

Complexity

Total Complexity 9
Complexity/F 0

Size

Lines of Code 120
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 9
eloc 68
mnd 9
bc 9
fnc 0
dl 0
loc 120
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import { FormikProps, FormikValues } from "formik";
2
import isEmpty from "lodash/isEmpty";
3
import { RefObject } from "react";
4
import { notEmpty } from "./queries";
5
6
/**
7
 * Takes a selector or an HTMLElement and focuses on the element.
8
 * @param x
9
 */
10
export const focusOnElement = (x: HTMLElement | string): void => {
11
  if (typeof x === "string") {
12
    const element = document.querySelector(x) as HTMLElement;
13
    if (element) {
14
      element.focus();
15
    }
16
  } else {
17
    x.focus();
18
  }
19
};
20
21
/**
22
 * Toggle accordion with given id.
23
 * @param id
24
 */
25
export const toggleAccordion = (elementId: string): void => {
26
  const element = document.getElementById(elementId);
27
  if (element) {
28
    element.classList.toggle("active");
29
    const { firstElementChild } = element;
30
    if (firstElementChild) {
31
      firstElementChild.setAttribute("aria-expanded", "true");
32
    }
33
  }
34
};
35
36
/**
37
 * Focuses on the previous element in the list.
38
 * @param focusList List of focusable HTML elements.
39
 */
40
export const focusPreviousItem = (focusList: HTMLElement[]) => {
41
  const item = document.activeElement as HTMLElement;
42
  const activeElementIndex = focusList.findIndex(
43
    (focusItem) => item === focusItem,
44
  );
45
  // If, the active element is first in order then move focus to last element in the focus list.
46
  // Else, move to the previous element.
47
  if (activeElementIndex === 0) {
48
    focusList[focusList.length - 1].focus();
49
  } else {
50
    focusList[activeElementIndex - 1].focus();
51
  }
52
};
53
54
/**
55
 * Focuses on the next element in the list.
56
 * @param focusList List of focusable HTML elements.
57
 */
58
export const focusNextItem = (focusList: HTMLElement[]) => {
59
  const item = document.activeElement as HTMLElement;
60
  const activeElementIndex = focusList.findIndex(
61
    (focusItem) => item === focusItem,
62
  );
63
  // If, the active element is last in order then move focus to first element in the focus list.
64
  // Else, move to the previous element.
65
  if (activeElementIndex === focusList.length - 1) {
66
    focusList[0].focus();
67
  } else {
68
    focusList[activeElementIndex + 1].focus();
69
  }
70
};
71
72
/**
73
 * Returns a list of tabable elements within the parent element.
74
 * @param parentElement Parent element.
75
 * @returns
76
 */
77
export const getTabList = (parentElement: HTMLElement | null): HTMLElement[] =>
78
  parentElement
79
    ? (Array.from(
80
        parentElement.querySelectorAll(
81
          "button:not([disabled]), [href], input:not([disabled]), select, textarea, [tabindex]:not([tabindex='-1'])",
82
        ),
83
      ) as HTMLElement[])
84
    : [];
85
86
/**
87
 * Runs validation on all forms, then returns true if they are all valid.
88
 * TODO: Figure out how to focus the first (or last) invalid input, if any.
89
 * @param refs
90
 */
91
export const validateAllForms = (
92
  refs: RefObject<FormikProps<FormikValues>>[],
93
): Promise<boolean> => {
94
  return Promise.all(
95
    refs
96
      .filter(notEmpty)
97
      .map(
98
        (ref: RefObject<FormikProps<FormikValues>>): Promise<any> =>
99
          ref.current !== null ? ref.current.validateForm() : Promise.resolve(),
100
      ),
101
  ).then((errors) => errors.every(isEmpty));
102
};
103
104
/**
105
 * Submits all forms.
106
 * @param refs
107
 */
108
export const submitAllForms = (
109
  refs: React.RefObject<FormikProps<FormikValues>>[],
110
): Promise<void[]> => {
111
  return Promise.all(
112
    refs.filter(notEmpty).map((ref: RefObject<FormikProps<FormikValues>>) => {
113
      // TODO: Might need to make one mass submission by combining all values into an array.
114
      return ref.current !== null
115
        ? ref.current.submitForm()
116
        : Promise.resolve();
117
    }),
118
  );
119
};
120