Skip to content

Commit

Permalink
crear componente button - falta storybooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Damian Morales committed Apr 16, 2024
1 parent 4d9f083 commit b633673
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 37 deletions.
1 change: 1 addition & 0 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const App = () => (
iconPosition={IconPosition.Left}
disabled={false}
style={{marginLeft: 6}}

Check warning on line 27 in App.tsx

View workflow job for this annotation

GitHub Actions / Build

Inline style: { marginLeft: 6 }
iconStyle={{color: 'red', fontSize: 30}}

Check warning on line 28 in App.tsx

View workflow job for this annotation

GitHub Actions / Build

Inline style: { color: 'red', fontSize: 30 }
/>
</View>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/BaseButton/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import {create} from 'react-test-renderer';
import {View, Text, Pressable} from 'react-native';
import {View, Text} from 'react-native';
import BaseButton from './';

const validData = {
Expand Down
8 changes: 7 additions & 1 deletion src/components/Button/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
const verticalHeights = ['top', 'bottom'];
const validTypes= ['main', 'secondary']
const validVariants = ['contained', 'outlined', 'text'];
const validIconPositions = ['top', 'bottom', 'left', 'right'];
const defaultColor = 'primary';
const defaultType = 'main';
const defaultVariant = 'contained';
const defaultIconPosition = 'left';

export {
verticalHeights,
validTypes,
validVariants,
validIconPositions,
defaultColor,
defaultType,
defaultVariant,
defaultIconPosition
defaultIconPosition,
}
81 changes: 79 additions & 2 deletions src/components/Button/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,80 @@
describe('Button', () => {
/* global expect */
import React from 'react';
import {create} from 'react-test-renderer';
import {Text} from 'react-native';
import Icon from '../Icon';
import BaseButton from '../BaseButton';
import Loading from '../Loading';
import Button, { Color, IconPosition, Type, Variant } from './';

const validData = {
type: Type.Main,
variant: Variant.Contained,
color: Color.Primary,
isLoading: true,
value: 'Button Test',
icon: 'box',
iconPosition: IconPosition.Left,
};

const setIsPressed = jest.fn();
const spyUseState = jest.spyOn(React, 'useState');
jest.spyOn(React, 'useEffect').mockImplementation((f) => f());
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');

describe('Button component', () => {
describe('returns null', () => {
it('when value and icon props are not passed to the Button component', () => {
const {toJSON} = create(<Button />);
expect(toJSON()).toBeNull();
});
});

describe('it renders correctly', () => {
it('when it has valie as minimum prop', () => {
const {root} = create(<Button value={validData.value} />);
const TitleComp = root.findByType(Text);
const {children} = TitleComp.props;

expect(children).toEqual(validData.value);
});


it('when it has icon as minimum prop', () => {
const {root} = create(<Button icon={validData.icon} />);
const IconComp = root.findByType(Icon);
const {name} = IconComp.props;

expect(name).toEqual(validData.icon);
});

it('when it is pressed', () => {
spyUseState.mockReturnValueOnce([false, setIsPressed]);

const {root} = create(
<Button
type={Type.Main}
variant={Variant.Contained}
color={Color.Primary}
value="Button Test"
icon="box"
iconPosition={IconPosition.Left}
/>);

const ButtonComp = root.findByType(BaseButton)
const {onPressIn, onPressOut} = ButtonComp.props;

onPressIn();
onPressOut();

expect(setIsPressed).toBeCalledTimes(2);
});

it('when isLoading is true, show an loading spinner', () => {
const {root} = create(<Button icon={validData.icon} isLoading={validData.isLoading} />);
const LoadingComp = root.findByType(Loading)
const {isLoading} = LoadingComp.props;

expect(isLoading).toEqual(validData.isLoading);
})
});
});
9 changes: 4 additions & 5 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ interface ButtonProps extends BaseButtonProps {
icon?: string;
iconPosition?: IconPosition;
disabled?: boolean;
borderRadius?: number;
style?: ViewStyle;
iconStyle?: ViewStyle;
iconStyle?: TextStyle;
textStyle?: TextStyle;
pressedColor?: string;
onPressIn?: () => void;
onPressOut?: () => void;
}
Expand All @@ -63,11 +61,12 @@ const Button: FC<ButtonProps> = ({
style,
iconStyle,
textStyle,
pressedColor,
onPressIn = () => {},
onPressOut = () => {},
...props
}) => {
if(!icon && !value) return null;

const [isPressed, setIsPressed] = useState<Boolean>(false);
const hasIconAndText = !!icon && !!value;
const borderRadius = variant === 'text' ? 6 : 50;
Expand All @@ -86,7 +85,7 @@ const Button: FC<ButtonProps> = ({
const styles = StyleSheet.create(buttonStyle);

const handleOnPressIn = () => {
setIsPressed(true)
setIsPressed(true);
onPressIn();
}

Expand Down
1 change: 1 addition & 0 deletions src/components/Button/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface Params {
isLoading: Boolean,
isPressed: Boolean,
disabled: Boolean,
hasIconAndText?: Boolean,
}

export interface ReturnStyles {
Expand Down
88 changes: 88 additions & 0 deletions src/components/Button/utils/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { getMixedButtonStyles } from ".";
import { Color, IconPosition, Type, Variant } from "..";

const props = {
type: Type.Secondary,
variant: Variant.Outlined,
color: Color.Secondary,
iconPosition: IconPosition.Top,
isLoading: true,
isPressed: true,
disabled: true,
hasIconAndText: true,
}

const failedProps = {
type: undefined,
variant: undefined,
color: undefined,
iconPosition: undefined,
isLoading: false,
isPressed: false,
disabled: false,
hasIconAndText: false,
}

describe('getMixedButtonStyles util', () => {
it('return styles when params are passed correclty', () => {
const response = getMixedButtonStyles(props);
expect(response).toEqual(
{
container: {
borderWidth: 1,
borderColor: '#C4C6CC',
backgroundColor: '#DDDFE2',
paddingHorizontal: 16.5,
paddingVertical: 21,
shadowColor: '#000',
elevation: 5,
shadowOpacity: 0.25,
shadowRadius: 3.84,
shadowOffset: { width: 0, height: 6.5 }
},
direction: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column'
},
text: {
fontWeight: '500',
textAlign: 'center',
color: '#C4C6CC',
fontSize: 29
},
icon: { fontWeight: '500', textAlign: 'center', color: '#C4C6CC' },
loadingColor: '#2F2F2F'
}
)
});

it('returns default styles when params is not correct or no exist', () => {
// @ts-ignore
const response = getMixedButtonStyles(failedProps);
expect(response).toEqual(
{
container: {
borderWidth: 1,
borderColor: 'transparent',
backgroundColor: '#2979FF',
paddingHorizontal: 16.5,
height: 104
},
direction: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row'
},
text: {
fontWeight: '500',
textAlign: 'center',
color: '#fff',
fontSize: 29
},
icon: { fontWeight: '500', textAlign: 'center', color: '#fff' },
loadingColor: '#2979FF'
}
)
});
});
82 changes: 62 additions & 20 deletions src/components/Button/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import { moderateScale, scaledForDevice } from "../../../scale"
import { colorConfig, stlyeConfig } from "../theme/configs";
import { themeColors } from "../theme";
import { defaultColor, defaultIconPosition, defaultType, defaultVariant, verticalHeights } from '../constants';
import type { ContainerStyle, DirectionStyle, LoadingStyle, Params, ReturnStyles, TextStyle } from "../types";

const containerStyle = ({isPressed, disabled: isDisabled, isLoading, color, variant, type, iconPosition}: ContainerStyle) => {
import {
defaultColor,
validTypes,
validVariants,
validIconPositions,
defaultIconPosition,
defaultType,
defaultVariant,
verticalHeights
} from '../constants';
import type {
ContainerStyle,
DirectionStyle,
LoadingStyle,
Params,
ReturnStyles,
TextStyle
} from "../types";

const containerStyle = ({
disabled: isDisabled,
isPressed,
isLoading,
color,
variant,
type,
iconPosition
}: ContainerStyle) => {
const selectedColor = themeColors[color] || themeColors[defaultColor];
const {main, pressed, disabled} = colorConfig(selectedColor);

const {container} = stlyeConfig;

const mainBgColor = main.background[variant] || main.background[defaultVariant];
const mainBorderColor = main.border[variant] || main.border[defaultVariant];
const validType = !!validTypes.includes(type) ? type : defaultType;
const validVariant = !!validVariants.includes(variant) ? variant : defaultVariant;

const pressedBgColor = pressed.background[variant] || pressed.background[defaultVariant];
const pressedBorderColor = pressed.border[variant] || pressed.border[defaultVariant];
const disabledBgColor = disabled.background[variant] || disabled.background[defaultVariant];
const disabledBorderColor = disabled.border[type][variant] || disabled.border[defaultType][defaultVariant];
const mainBgColor = main.background[validVariant];
const mainBorderColor = main.border[validVariant];

const pressedBgColor = pressed.background[validVariant];
const pressedBorderColor = pressed.border[validVariant];

const containerHeight = container.height[type] || container.height[defaultType];
const disabledBgColor = disabled.background[validVariant];
const disabledBorderColor = disabled.border[validType][validVariant];

const containerHeight = container.height[validType];
const containerShadow = container.shadow;

// main and pressed button colors
Expand All @@ -46,25 +73,38 @@ const containerStyle = ({isPressed, disabled: isDisabled, isLoading, color, vari
const directionWrapperStyle = ({iconPosition}: DirectionStyle ) => {
const {directionWrapper} = stlyeConfig;

const flexDirection =
directionWrapper.flexDirection[iconPosition] || directionWrapper.flexDirection[defaultIconPosition];
const flexCenter = directionWrapper.center || {};
const flexCenter = directionWrapper.center;

const validIconPosition = !!validIconPositions.includes(iconPosition)
? iconPosition
: defaultIconPosition;
const flexDirection = directionWrapper.flexDirection[validIconPosition];

return {
...flexCenter,
flexDirection,
}
};

const baseTextStyle = ({type, variant, color, disabled: isDisabled, isLoading, isPressed}: TextStyle) => {
const baseTextStyle = ({
disabled: isDisabled,
type,
variant,
color,
isLoading,
isPressed
}: TextStyle) => {
const selectedColor = themeColors[color] || themeColors[defaultColor];
const {main, pressed, disabled} = colorConfig(selectedColor);

const {text: textStyle} = stlyeConfig;

const mainTextColor = main.text[type][variant] || main.text[defaultType][defaultVariant];
const pressedTextColor = pressed.text[type][variant] || pressed.text[defaultType][defaultVariant];
const disabledTextColor = disabled.text[type][variant] || disabled.text[defaultType][defaultVariant];
const validType = !!validTypes.includes(type) ? type : defaultType;
const validVariant = !!validVariants.includes(variant) ? variant : defaultVariant;

const mainTextColor = main.text[validType][validVariant];
const pressedTextColor = pressed.text[validType][validVariant];
const disabledTextColor = disabled.text[validType][validVariant];

const mainColor = isPressed ? pressedTextColor : mainTextColor;

Expand All @@ -73,10 +113,12 @@ const baseTextStyle = ({type, variant, color, disabled: isDisabled, isLoading, i
color: isDisabled || isLoading ? disabledTextColor : mainColor,
}
};

const textStyle = (params : TextStyle) => ({
...baseTextStyle(params),
fontSize: scaledForDevice(14, moderateScale),
});

const iconStyle = (params: TextStyle) => {
const {hasIconAndText, iconPosition} = params;
const {icon} = stlyeConfig;
Expand Down
Loading

0 comments on commit b633673

Please sign in to comment.