From 8c6f921a3e614d39d429564fb6fdace2d726ed54 Mon Sep 17 00:00:00 2001 From: Ramir Mesquita Date: Wed, 15 Jan 2025 13:32:23 -0300 Subject: [PATCH] fix: creates a hook to wrap words larger than 15 characters --- .../ui/items/RadioItem/RegularGrid.tsx | 75 +++++++----------- .../ui/Items/SelectBase/SelectBaseText.tsx | 18 ++++- src/shared/utils/hooks/useCustomWordWrap.ts | 76 +++++++++++++++++++ 3 files changed, 118 insertions(+), 51 deletions(-) create mode 100644 src/shared/utils/hooks/useCustomWordWrap.ts diff --git a/src/entities/activity/ui/items/RadioItem/RegularGrid.tsx b/src/entities/activity/ui/items/RadioItem/RegularGrid.tsx index ee54bd837..c6af2ddb6 100644 --- a/src/entities/activity/ui/items/RadioItem/RegularGrid.tsx +++ b/src/entities/activity/ui/items/RadioItem/RegularGrid.tsx @@ -1,12 +1,10 @@ -import { useMemo } from 'react'; - import RadioGroup from '@mui/material/RadioGroup'; import { RegularRadioOption } from './RegularRadioOption'; import { RadioItem } from '../../../lib'; import { Box } from '~/shared/ui'; -import { splitList, useCustomMediaQuery } from '~/shared/utils'; +import { useCustomMediaQuery } from '~/shared/utils'; type Props = { options: RadioItem['responseValues']['options']; @@ -28,54 +26,33 @@ export const RegularGrid = ({ }: Props) => { const { lessThanSM } = useCustomMediaQuery(); - const [evenColumn, oddColumn] = useMemo(() => { - return splitList(options); - }, [options]); - return ( - - - {evenColumn.map((option) => { - return ( - onValueChange(String(option.value))} - description={option.tooltip} - image={option.image} - disabled={isDisabled} - defaultChecked={String(option.value) === value} - color={option.color} - replaceText={replaceText} - /> - ); - })} - - - - {oddColumn.map((option) => { - return ( - onValueChange(String(option.value))} - description={option.tooltip} - image={option.image} - disabled={isDisabled} - defaultChecked={String(option.value) === value} - color={option.color} - replaceText={replaceText} - /> - ); - })} - + + {options.map((option) => { + return ( + onValueChange(String(option.value))} + description={option.tooltip} + image={option.image} + disabled={isDisabled} + defaultChecked={String(option.value) === value} + color={option.color} + replaceText={replaceText} + /> + ); + })} ); diff --git a/src/shared/ui/Items/SelectBase/SelectBaseText.tsx b/src/shared/ui/Items/SelectBase/SelectBaseText.tsx index 6c5042441..d8a12c99d 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 ( { sx={{ wordBreak: 'none', cursor: 'pointer', - hyphens: 'none', + lineBreak: 'normal', display: '-webkit-box', // Using kebab-case (i.e. `-webkit-some-things`) would cause warnings @@ -27,7 +30,18 @@ export const SelectBaseText = (props: Props) => { webkitBoxOrient: 'vertical', }} > - {props.text} + {processedWords.map(({ word, needsWrap, ref }, index) => { + if (needsWrap) + return ( + + {word.split('').map((letter: string, index) => ( + {letter} + ))} + + ); + + return `${word} `; + })} ); }; diff --git a/src/shared/utils/hooks/useCustomWordWrap.ts b/src/shared/utils/hooks/useCustomWordWrap.ts new file mode 100644 index 000000000..c8f189f92 --- /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, index) => { + if (word.length > 15) + return { + word, + needsWrap: true, + ref: mustBreakWord, + }; + + return { + word, + needsWrap: false, + ref: null, + }; + }); + + return { processedWords }; +};