import {useState, useEffect} from 'react'; /** * Hook permettant d’obtenir des résultats asynchrones. * * @param initial Valeur initiale lorsque la promesse n’a pas répondu. * @param func Fonction renvoyant une promesse. * @param ...args Arguments à passer à `func` qui sont susceptibles de changer. * @return Résultats de la promesse. */ export const useAsync = (initial, func, ...args) => { const [results, setResults] = useState(initial); useEffect(() => { const fetcher = async () => { setResults(await func(...args)); }; fetcher(); }, args); return results; }; /** * Crée un état composé d’une liste et d’un élément ayant le focus dans cette * liste. À la modification de la liste ou de l’indice de l’élément ayant le * focus, la contrainte suivante est imposée : * * — si la liste n’est pas vide, focus ∈ [0, taille de la liste]. * — sinon, focus = 0. */ export const useFocusableList = () => { const [list, setList] = useState([]); const [focus, setFocus] = useState(0); return { /** * Contenu courant de la liste. */ list, /** * Indice de l’élément ayant présentement le focus. */ focus, /** * Modifie la liste et s’assure que l’élément ayant le focus est * toujours dans sa plage de valeurs possibles. * * @param nextList Nouvelle liste. */ setList(nextList) { setList(nextList); setFocus( nextList.length === 0 ? 0 : Math.min(nextList.length - 1, focus) ); }, /** * Modifie l’élément ayant le focus en imposant les contraintes * d’intégrité. * * @param nextFocus Indice du nouvel élément ayant le focus. */ setFocus(nextFocus) { const itemCount = list.length; if (itemCount === 0) { // Sur la liste vide, on ne peut pas changer le focus return; } // Ramène une valeur négative dans les positifs while (nextFocus < 0) { nextFocus += itemCount; } // Ramène une valeur trop grande à l’intérieur de la liste nextFocus = nextFocus % itemCount; setFocus(nextFocus); }, }; }; /** * Crée une liste de termes de recherche. */ export const useQuery = () => { const [query, setQuery] = useState([]); return { /** * Liste des termes de la requête. */ query, /** * Ajoute un terme à la requête. * * @param term Terme à ajouter. */ addTerm(term) { if (query.some(({id}) => id === term.id)) { // N’ajoute pas les termes déjà sélectionnés return; } setQuery(query.concat([term])); }, /** * Supprime un terme de la requête. * * @param index Indice du terme à supprimer dans la liste. */ removeTerm(index) { setQuery([ ...query.slice(0, index), ...query.slice(index + 1), ]); }, }; };