wikimedica-disease-search/app/src/util.js

139 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {useState, useEffect} from 'react';
/**
* Hook permettant dobtenir des résultats asynchrones.
*
* @param initial Valeur initiale lorsque la promesse na 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é dune liste et dun élément ayant le focus dans cette
* liste. À la modification de la liste ou de lindice de lélément ayant le
* focus, la contrainte suivante est imposée :
*
* — si la liste nest 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 sassure 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
* dinté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 à linté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))
{
// Najoute 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),
]);
},
};
};