diff --git a/packages/yoga/src/Avatar/native/Avatar.jsx b/packages/yoga/src/Avatar/native/Avatar.jsx
index e2a186a76e..f0d0653fd9 100644
--- a/packages/yoga/src/Avatar/native/Avatar.jsx
+++ b/packages/yoga/src/Avatar/native/Avatar.jsx
@@ -50,6 +50,7 @@ const Avatar = forwardRef(
borderRadius,
width,
height,
+ onLayout,
...props
},
ref,
@@ -63,6 +64,7 @@ const Avatar = forwardRef(
justifyContent="center"
width={width}
height={height}
+ onLayout={onLayout}
overflow="hidden"
borderRadius={borderRadius}
{...props}
diff --git a/packages/yoga/src/Result/native/Result/TextWithBadge/__snapshots__/index.test.tsx.snap b/packages/yoga/src/Result/native/Result/TextWithBadge/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000000..266b506ce2
--- /dev/null
+++ b/packages/yoga/src/Result/native/Result/TextWithBadge/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,370 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`TextWithBadge should match snapshot 1`] = `
+
+
+ Text with badge
+
+
+
+
+
+
+
+`;
+
+exports[`TextWithBadge should match snapshot with long title 1`] = `
+
+
+ This is an example of a very long title that should be truncated
+
+
+
+
+
+
+
+`;
+
+exports[`TextWithBadge should match snapshot without badgeIcon 1`] = `
+
+
+ Title without Badge
+
+
+
+
+
+`;
diff --git a/packages/yoga/src/Result/native/Result/TextWithBadge/index.test.tsx b/packages/yoga/src/Result/native/Result/TextWithBadge/index.test.tsx
new file mode 100644
index 0000000000..d968d35222
--- /dev/null
+++ b/packages/yoga/src/Result/native/Result/TextWithBadge/index.test.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import { render } from '@testing-library/react-native';
+import { WellhubIcon } from '@gympass/yoga-icons';
+
+import { ThemeProvider } from '../../../../index';
+import TextWithBadge from '.';
+
+describe('TextWithBadge', () => {
+ it('should match snapshot', () => {
+ const { toJSON } = render(
+
+
+ ,
+ );
+
+ expect(toJSON()).toMatchSnapshot();
+ });
+
+ it('should match snapshot with long title', () => {
+ const { toJSON } = render(
+
+
+ ,
+ );
+
+ expect(toJSON()).toMatchSnapshot();
+ });
+
+ it('should match snapshot without badgeIcon', () => {
+ const { toJSON } = render(
+
+
+ ,
+ );
+
+ expect(toJSON()).toMatchSnapshot();
+ });
+});
diff --git a/packages/yoga/src/Result/native/Result/TextWithBadge/index.tsx b/packages/yoga/src/Result/native/Result/TextWithBadge/index.tsx
new file mode 100644
index 0000000000..285320efec
--- /dev/null
+++ b/packages/yoga/src/Result/native/Result/TextWithBadge/index.tsx
@@ -0,0 +1,70 @@
+import React, { ReactNode, useCallback, useState } from 'react';
+import { useWindowDimensions } from 'react-native';
+
+import Badge from '../../Badge';
+
+import { StyledBoxContainer, StyledText } from './styles';
+
+interface TextWithBadgeProps {
+ avatarWidth: number;
+ badgeIcon: ReactNode;
+ title: string;
+}
+
+const SCREEN_PADDINGS = 20;
+const CONTENT_MARGINS = 20;
+const AVATAR_CONTENT_MARGINS = 16;
+const BADGE_LIMIT = 20;
+
+const TextWithBadge = ({
+ avatarWidth,
+ badgeIcon,
+ title,
+}: TextWithBadgeProps) => {
+ const [textSize, setTextSize] = useState(0);
+ const { width: windowWidth } = useWindowDimensions();
+
+ const textMaxSize =
+ windowWidth -
+ (SCREEN_PADDINGS + CONTENT_MARGINS + AVATAR_CONTENT_MARGINS + avatarWidth);
+ const shouldTruncate = textSize >= textMaxSize - BADGE_LIMIT;
+ const containerWidth = shouldTruncate ? null : textSize;
+ const textWidth = shouldTruncate ? '100%' : null;
+
+ const onTextLayout = useCallback(
+ ({
+ nativeEvent: {
+ layout: { width },
+ },
+ }) => {
+ setTextSize(width);
+ },
+ [],
+ );
+
+ return (
+
+
+ {title}
+
+
+
+ );
+};
+
+export default TextWithBadge;
diff --git a/packages/yoga/src/Result/native/Result/TextWithBadge/styles.ts b/packages/yoga/src/Result/native/Result/TextWithBadge/styles.ts
new file mode 100644
index 0000000000..34b852e693
--- /dev/null
+++ b/packages/yoga/src/Result/native/Result/TextWithBadge/styles.ts
@@ -0,0 +1,42 @@
+import React, { ReactNode } from 'react';
+import styled, { css } from 'styled-components';
+import Text from '../../../../Text';
+import Box from '../../../../Box';
+
+export const StyledBoxContainer = styled(Box)<{
+ containerWidth?: number | null;
+ children: ReactNode;
+}>`
+ ${({ containerWidth }) =>
+ css`
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-end;
+ position: relative;
+ width: ${containerWidth}px;
+ `}
+`;
+
+export const StyledText = styled(Text.Body1)<{
+ onLayout: ({ nativeEvent: { layout } }) => void;
+ textWidth?: string | null;
+ numberOfLines: number;
+ bold: boolean;
+ children: React.ReactNode;
+}>`
+ ${({
+ textWidth,
+ theme: {
+ yoga: {
+ spacing: { medium },
+ },
+ },
+ }) =>
+ css`
+ position: absolute;
+ left: 0;
+ padding-right: ${medium};
+ flex: 1;
+ width: ${textWidth};
+ `}
+`;
diff --git a/packages/yoga/src/Result/native/Result/__snapshots__/index.test.jsx.snap b/packages/yoga/src/Result/native/Result/__snapshots__/index.test.jsx.snap
index 7802f9cb15..ce7ef18058 100644
--- a/packages/yoga/src/Result/native/Result/__snapshots__/index.test.jsx.snap
+++ b/packages/yoga/src/Result/native/Result/__snapshots__/index.test.jsx.snap
@@ -24,6 +24,7 @@ exports[` should match snapshot 1`] = `
display="flex"
height={48}
justifyContent="center"
+ onLayout={[Function]}
overflow="hidden"
style={
[
@@ -533,16 +534,9 @@ exports[` should match snapshot 1`] = `
@@ -1056,6 +1050,7 @@ exports[` should match snapshot without attendence 1`] = `
display="flex"
height={48}
justifyContent="center"
+ onLayout={[Function]}
overflow="hidden"
style={
[
@@ -1184,16 +1179,9 @@ exports[` should match snapshot without attendence 1`] = `
}
>
@@ -1573,6 +1561,7 @@ exports[` should match snapshot without limitLabel prop 1`] = `
display="flex"
height={48}
justifyContent="center"
+ onLayout={[Function]}
overflow="hidden"
style={
[
@@ -2082,16 +2071,9 @@ exports[` should match snapshot without limitLabel prop 1`] = `
diff --git a/packages/yoga/src/Result/native/Result/index.jsx b/packages/yoga/src/Result/native/Result/index.jsx
index 4cadaec5a9..2d06358ae1 100644
--- a/packages/yoga/src/Result/native/Result/index.jsx
+++ b/packages/yoga/src/Result/native/Result/index.jsx
@@ -1,13 +1,12 @@
-import React, { isValidElement } from 'react';
-
+import React, { isValidElement, useCallback, useState } from 'react';
import { arrayOf, string, shape, func, bool, node } from 'prop-types';
import Text from '../../../Text';
import Box from '../../../Box';
import Attendances from '../Attendances';
-import Badge from '../Badge';
import { Content, StyledBox } from './styles';
+import TextWithBadge from './TextWithBadge';
/**
* The Result component is used when you have a list to show. It is applied to
@@ -23,48 +22,62 @@ const Result = ({
children,
attendancesColor,
badgeIcon,
-}) => (
-
- {Avatar && <>{isValidElement(Avatar) ? Avatar : }>}
-
- {!!attendances?.length && (
-
+}) => {
+ const [avatarWidth, setAvatarWidth] = useState(0);
+
+ const onAvatarLayout = useCallback(
+ ({
+ nativeEvent: {
+ layout: { width },
+ },
+ }) => {
+ setAvatarWidth(width);
+ },
+ [],
+ );
+
+ return (
+
+ {Avatar && (
+ <>
+ {isValidElement(Avatar) ? (
+ React.cloneElement(Avatar, { onLayout: onAvatarLayout })
+ ) : (
+
+ )}
+ >
)}
-
-
- {title}
-
- {badgeIcon && (
-
+ {!!attendances?.length && (
+
)}
-
- {subTitle && subTitle !== '' && (
-
- {subTitle}
-
- )}
- {children}
-
-
-);
+ {badgeIcon ? (
+
+ ) : (
+
+
+ {title}
+
+
+ )}
+ {subTitle && subTitle !== '' && (
+
+ {subTitle}
+
+ )}
+ {children}
+
+
+ );
+};
Result.propTypes = {
/** The component Avatar */