-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ajout d'un textarea avec auto resize
- Loading branch information
Showing
6 changed files
with
106 additions
and
17 deletions.
There are no files selected for viewing
29 changes: 29 additions & 0 deletions
29
packages/ui/src/design-system/Textarea/AutoResizedTextarea.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import {Ref, RefObject, forwardRef, useEffect, useState} from 'react'; | ||
import {useAutoResize} from './useAutoResize'; | ||
import {Textarea, TextareaProps} from './Textarea'; | ||
|
||
export const AutoResizedTextarea = forwardRef( | ||
(props: TextareaProps, ref?: Ref<HTMLTextAreaElement>) => { | ||
// Valeur locale, nécessaire pour le refresh des valeurs textareaRef et shadowRef | ||
const [value, setValue] = useState<string | undefined>(props.value); | ||
|
||
useEffect(() => setValue(value), [props.value]); | ||
|
||
const {textareaRef, shadowRef} = useAutoResize( | ||
value?.toString(), | ||
ref as RefObject<HTMLTextAreaElement> | ||
); | ||
|
||
const handleChange = evt => { | ||
props.onChange?.(evt.target.value); | ||
setValue(evt.target.value); | ||
}; | ||
|
||
return ( | ||
<div className="flex items-start w-full"> | ||
<div ref={shadowRef} className="w-px -mr-px" /> | ||
<Textarea ref={textareaRef} onChange={handleChange} resize="none" /> | ||
</div> | ||
); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './Textarea'; | ||
export * from './AutoResizedTextarea'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {RefObject, useLayoutEffect, useRef} from 'react'; | ||
|
||
/** | ||
* Rend un champ de texte avec redimensionnement automatique en fonction de son contenu | ||
* Copié / adapté depuis: | ||
* https://www.kindacode.com/article/react-typescript-create-an-autosize-textarea-from-scratch/ | ||
* https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/#comment-1794830 | ||
*/ | ||
|
||
export const useAutoResize = ( | ||
value?: string, | ||
forwardRef?: RefObject<HTMLTextAreaElement> | null | ||
) => { | ||
// Référence locale associée à la balise <textarea/> | ||
const ref = useRef<HTMLTextAreaElement | null>(null); | ||
|
||
// Référence associée à la balise invisible <div/> | ||
// Cette div permet de conserver la hauteur pour éviter | ||
// les sauts dans la page à la mise à jour du texte | ||
const shadowRef = useRef<HTMLDivElement | null>(null); | ||
|
||
// Référence associée à la balise <textarea> | ||
// (locale ou issue des props) | ||
const textareaRef = forwardRef ? forwardRef : ref; | ||
|
||
// Permet de set la taille du textarea au changement de valeur | ||
useLayoutEffect(() => { | ||
if (textareaRef && textareaRef.current && shadowRef && shadowRef.current) { | ||
// Initialise la hauteur du textarea à 0px | ||
textareaRef.current.style.height = '0px'; | ||
|
||
// Met à jour la hauteur en fonction du contenu | ||
textareaRef.current.style.height = | ||
textareaRef.current.scrollHeight + 'px'; | ||
|
||
// Une div invisible qui permet de conserver la hauteur pour éviter | ||
// les sauts dans la page à la mise à jour du texte | ||
shadowRef.current.style.height = textareaRef.current.scrollHeight + 'px'; | ||
} | ||
}, [value]); | ||
|
||
return {textareaRef, shadowRef}; | ||
}; |