diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5cd502f6..5c2c35ec6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,3 +71,35 @@ jobs: env: REACT_APP_API_DOMAIN: http://localhost:8080 run: yarn test + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Remove .yarnrc file to avoid conflicts + run: rm -rf .yarnrc + + - name: Enable Corepack + run: corepack enable + + - name: Prepare and activate Yarn version 1.22.22 + run: corepack prepare yarn@1.22.22 --activate + + - name: Verify Yarn version + run: yarn --version + + - uses: actions/cache@v4 + with: + path: | + ~/node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }} + + - name: Install dependencies with frozen lockfile + run: yarn install --frozen-lockfile + + - name: Build web app + run: yarn build 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 }; +};