From b7a1f5c12198780661799d6bed91cb4a15f18a84 Mon Sep 17 00:00:00 2001 From: Ramir Mesquita <790844+ramirlm@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:58:11 -0300 Subject: [PATCH] fix: Fixing word break for large description option answers (M2-8267) (#562) * fix: fixing word break for large description option answers * fix: fixing long words issue breaking the layout * fix: fixing long words issue breaking the layout * fix: corrects wrongly generated line breaks detected in qa * fix: update word break and hyphenation styles in SelectBaseText component to prevent word break * fix: creates a hook to wrap words larger than 15 characters * fix: removing unused index on loop * fix: add space after customWrap words * revert RegularGrid changes --------- Co-authored-by: Ramir Mesquita Co-authored-by: Carlos Chacon --- .../ui/Items/SelectBase/SelectBaseText.tsx | 17 ++++- src/shared/utils/hooks/useCustomWordWrap.ts | 76 +++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/shared/utils/hooks/useCustomWordWrap.ts diff --git a/src/shared/ui/Items/SelectBase/SelectBaseText.tsx b/src/shared/ui/Items/SelectBase/SelectBaseText.tsx index 00c983805..513c28984 100644 --- a/src/shared/ui/Items/SelectBase/SelectBaseText.tsx +++ b/src/shared/ui/Items/SelectBase/SelectBaseText.tsx @@ -1,11 +1,14 @@ import { Theme } from '~/shared/constants'; import Text from '~/shared/ui/Text'; +import { useCustomWordWrap } from '~/shared/utils/hooks/useCustomWordWrap'; type Props = { text: string; }; export const SelectBaseText = (props: Props) => { + const { processedWords } = useCustomWordWrap(props.text); + return ( { lineHeight="28px" testid="select-text" sx={{ + wordBreak: 'none', cursor: 'pointer', - lineBreak: 'anywhere', + lineBreak: 'normal', display: '-webkit-box', - overflow: 'hidden', // Using kebab-case (i.e. `-webkit-some-things`) would cause warnings // in the JS console about kebab-case being not supported for CSS @@ -27,7 +30,15 @@ export const SelectBaseText = (props: Props) => { webkitBoxOrient: 'vertical', }} > - {props.text} + {processedWords.map(({ word, needsWrap, ref }, index) => { + return needsWrap ? ( + + {`${word} `} + + ) : ( + `${word} ` + ); + })} ); }; diff --git a/src/shared/utils/hooks/useCustomWordWrap.ts b/src/shared/utils/hooks/useCustomWordWrap.ts new file mode 100644 index 000000000..5244f2a89 --- /dev/null +++ b/src/shared/utils/hooks/useCustomWordWrap.ts @@ -0,0 +1,76 @@ +import { useEffect, useRef, useState } from 'react'; + +export const useCustomWordWrap = (text: string) => { + const textAsArray = text.split(' '); + const mustBreakWord = useRef(null); + const originalWord = useRef(''); + const [resize, setResize] = useState(0); + const debounceTimeout = useRef(); + + useEffect(() => { + const handleResize = () => { + if (debounceTimeout.current) { + clearTimeout(debounceTimeout.current); + } + + debounceTimeout.current = setTimeout(() => { + setResize((prev) => prev + 1); + }, 300); + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + if (debounceTimeout.current) { + clearTimeout(debounceTimeout.current); + } + }; + }, []); + + useEffect(() => { + if (mustBreakWord.current) { + if (!originalWord.current && mustBreakWord.current.textContent) { + originalWord.current = mustBreakWord.current.textContent; + } + + if (originalWord.current) { + const characters = originalWord.current.split(''); + mustBreakWord.current.innerHTML = characters + .map((letter) => `${letter}`) + .join(''); + } + + const mustBreakWordCharacters = Array.from(mustBreakWord.current.children); + for (let i = 0; i < mustBreakWordCharacters.length; i++) { + const currentCharacter = mustBreakWordCharacters[i] as HTMLElement; + const previousCharacter = i > 0 ? (mustBreakWordCharacters[i - 1] as HTMLElement) : null; + + if ( + previousCharacter && + !previousCharacter.innerText.includes('-') && + currentCharacter.offsetTop > previousCharacter?.offsetTop + ) { + (mustBreakWordCharacters[i - 3] as HTMLElement).innerText += '-\n'; + } + } + } + }, [resize]); + + const processedWords = textAsArray.map((word: string) => { + if (word.length > 15) + return { + word, + needsWrap: true, + ref: mustBreakWord, + }; + + return { + word, + needsWrap: false, + ref: null, + }; + }); + + return { processedWords }; +};