139 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| 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)
 | ||
|             ]);
 | ||
|         },
 | ||
|     };
 | ||
| };
 |