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

139 lines
3.4 KiB
JavaScript
Raw Normal View History

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
2019-12-04 23:54:44 +00:00
* focus, la contrainte suivante est imposée :
2019-12-04 23:16:27 +00:00
*
* 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);
2019-12-04 23:16:27 +00:00
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),
]);
},
};
};