Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android / iOS] Code blocks are overflowing the app border #44953

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
92d3147
add handling for wrapped code text for native devices
cdOut Jul 8, 2024
ebeed08
fix lint issues
cdOut Jul 8, 2024
e8441ef
correct imports and prettier
cdOut Jul 8, 2024
6f2325b
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 9, 2024
5764928
split long singular words into mulltiple strings
cdOut Sep 10, 2024
e74c97e
fix prettier and lint errors
cdOut Sep 10, 2024
39a022f
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 10, 2024
44d0d7d
memoize fontSize and infer it from textStyles
cdOut Sep 11, 2024
f0aa075
fix lint errors and refactor code
cdOut Sep 11, 2024
dae171d
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 13, 2024
1a0e31b
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 20, 2024
00740c4
remove manual memoization in favor of react-compiler
cdOut Sep 26, 2024
d4e9810
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 26, 2024
513be86
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Sep 30, 2024
5db19ff
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Oct 1, 2024
c6756b3
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Oct 2, 2024
a7b0e02
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Oct 15, 2024
30a4176
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Oct 28, 2024
89dc570
Merge branch 'main' into @cdOut/code-report-fixed
cdOut Oct 30, 2024
23e436b
add longer explaination comment
cdOut Oct 30, 2024
66d9dc5
add unit test for splitLongWord
cdOut Oct 30, 2024
e9c459b
fix prettier
cdOut Oct 30, 2024
5c66624
fix jsdoc lint errors
cdOut Oct 30, 2024
32ea3fc
fix unit test expected results
cdOut Oct 30, 2024
8b76cc9
remove unexpected output substring from test
cdOut Oct 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions src/components/InlineCodeBlock/WrappedText.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, {Fragment} from 'react';
import React, {Fragment, useMemo} from 'react';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import {View} from 'react-native';
import Text from '@components/Text';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {containsOnlyEmojis} from '@libs/EmojiUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type ChildrenProps from '@src/types/utils/ChildrenProps';

Expand Down Expand Up @@ -40,15 +42,59 @@ function containsEmoji(text: string): boolean {
return CONST.REGEX.EMOJIS.test(text);
}

/**
* Takes a long word and splits it into an array of sub-strings.
*
* The function tests whether the length of the provided word exceeds the provided maximum length.
* If the word's length is less than or equal to `maxLength`, it returns an array with the original word.
* If the word's length exceeds 'maxLength', it utilizes a regular expression to split the word into
* substrings with a specified 'maxLength' and returns them as an array of strings.
*
* @param word The original word to be split.
* @param maxLength The maximum length of each substring.
* @return An array of substrings derived from the original word.
*
* @example
* splitLongWord('longteststring', 4);
* // Output: ['long', 'test', 'stri', 'ng']
*/
function splitLongWord(word: string, maxLength: number): string[] {
if (word.length <= maxLength) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a unit test for this function? With a handful of different sized strings. To make sure it always returns the array we expect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added unit test for this function 👍

return [word];
}

return word.match(new RegExp(`.{1,${maxLength}}`, 'g')) ?? [];
}

function getFontSizeFromStyles(textStyles: StyleProp<TextStyle>): number {
if (Array.isArray(textStyles)) {
for (const style of textStyles) {
if (style && 'fontSize' in style && style.fontSize) {
return style.fontSize;
}
}
} else if (textStyles && 'fontSize' in textStyles && textStyles.fontSize) {
return textStyles.fontSize;
}

// if we cannot infer fontSize from styles, a default value is returned
return variables.fontSizeLabel;
}

function WrappedText({children, wordStyles, textStyles}: WrappedTextProps) {
const styles = useThemeStyles();
const {windowWidth} = useWindowDimensions();

const fontSize = useMemo(() => getFontSizeFromStyles(textStyles), [textStyles]);
const childrenString = typeof children === 'string' ? children : '';
const charsPerLine = useMemo(() => Math.floor(windowWidth / (fontSize * variables.fontSizeToWidthRatio)), [windowWidth, fontSize]);

const textMatrix = getTextMatrix(childrenString).map((row) => row.flatMap((word) => splitLongWord(word, charsPerLine)));

if (typeof children !== 'string') {
return null;
}

const textMatrix = getTextMatrix(children);

return textMatrix.map((rowText, rowIndex) => (
<Fragment
// eslint-disable-next-line react/no-array-index-key
Expand Down Expand Up @@ -87,3 +133,5 @@ function WrappedText({children, wordStyles, textStyles}: WrappedTextProps) {
WrappedText.displayName = 'WrappedText';

export default WrappedText;

export {splitLongWord};
1 change: 1 addition & 0 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export default {
restrictedActionIllustrationHeight: 136,
photoUploadPopoverWidth: 335,
onboardingModalWidth: 500,
fontSizeToWidthRatio: getValueUsingPixelRatio(0.8, 1),

// The height of the empty list is 14px (2px for borders and 12px for vertical padding)
// This is calculated based on the values specified in the 'getGoogleListViewStyle' function of the 'StyleUtils' utility
Expand Down
47 changes: 47 additions & 0 deletions tests/unit/splitLongWordTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {splitLongWord} from '@components/InlineCodeBlock/WrappedText';

describe('splitLongWord', () => {
const testCases = [
{
word: 'thissadasdasdsadsadasdadsadasdasdasdasdasdasdasdasdasdsadsadggggggggggggggggg',
maxLength: 4,
output: ['this', 'sada', 'sdas', 'dsad', 'sada', 'sdad', 'sada', 'sdas', 'dasd', 'asda', 'sdas', 'dasd', 'asda', 'sdsa', 'dsad', 'gggg', 'gggg', 'gggg', 'gggg', 'g'],
},
{
word: 'https://www.google.com/search?q=google&oq=goog&gs_lcrp=EgZjaHJvbWUqEAgAEAAYgwEY4wIYsQMYgAQyEAgAEAAYgwEY4wIYsQMYgAQyEwgBEC4YgwEYxwEYsQMY0QMYgAQyDQgCEAAYgwEYsQMYgAQyBggDEEUYOzIGCAQQRRg8MgYIBRBFGDwyBggGEEUYPDIGCAcQBRhA0gEHNzM1ajBqN6gCALACAA&sourceid=chrome&ie=UTF-8',
maxLength: 20,
output: [
'https://www.google.c',
'om/search?q=google&o',
'q=goog&gs_lcrp=EgZja',
'HJvbWUqEAgAEAAYgwEY4',
'wIYsQMYgAQyEAgAEAAYg',
'wEY4wIYsQMYgAQyEwgBE',
'C4YgwEYxwEYsQMY0QMYg',
'AQyDQgCEAAYgwEYsQMYg',
'AQyBggDEEUYOzIGCAQQR',
'Rg8MgYIBRBFGDwyBggGE',
'EUYPDIGCAcQBRhA0gEHN',
'zM1ajBqN6gCALACAA&so',
'urceid=chrome&ie=UTF',
'-8',
],
},
{
word: 'superkalifragilistischexpialigetisch',
maxLength: 5,
output: ['super', 'kalif', 'ragil', 'istis', 'chexp', 'ialig', 'etisc', 'h'],
},
{
word: 'Este es un ejemplo de texto en español para la prueba',
maxLength: 8,
output: ['Este es ', 'un ejemp', 'lo de te', 'xto en e', 'spañol p', 'ara la p', 'rueba'],
},
];

testCases.forEach(({word, maxLength, output}) => {
test(`should split ${word} into ${output.join()} with maxLength of ${maxLength}`, () => {
expect(splitLongWord(word, maxLength)).toEqual(output);
});
});
});
Loading