From c0b5f1ed98d9b0ad1acf5e5ad1bbead55093852b Mon Sep 17 00:00:00 2001 From: Artur Yorsh Date: Fri, 28 Feb 2020 15:11:00 +0300 Subject: [PATCH] BREAKING: refactor Toggle to new api --- src/components/ui/toggle/toggle.component.tsx | 100 ++++++-------- src/components/ui/toggle/toggle.spec.tsx | 122 +++++++----------- 2 files changed, 91 insertions(+), 131 deletions(-) diff --git a/src/components/ui/toggle/toggle.component.tsx b/src/components/ui/toggle/toggle.component.tsx index 0bc7ef9c4..b65d23ed2 100644 --- a/src/components/ui/toggle/toggle.component.tsx +++ b/src/components/ui/toggle/toggle.component.tsx @@ -14,39 +14,38 @@ import { PanResponderGestureState, PanResponderInstance, Platform, - StyleProp, StyleSheet, - TextStyle, - TouchableOpacity, TouchableOpacityProps, View, ViewProps, } from 'react-native'; +import { Overwrite } from 'utility-types'; +import { + FalsyText, + RenderProp, + RTLService, + TouchableWithoutFeedback, + WebEventResponder, + WebEventResponderInstance, +} from '../../devsupport'; import { Interaction, styled, StyledComponentProps, StyleType, -} from '@kitten/theme'; -import { - Text, - TextElement, -} from '../text/text.component'; -import { CheckMark } from '../support/components/checkmark.component'; -import { - I18nLayoutService, - WebEventResponder, - WebEventResponderInstance, -} from '../support/services'; +} from '../../theme'; +import { TextProps } from '../text/text.component'; +import { CheckMark } from '../shared/checkmark.component'; -export interface ToggleProps extends StyledComponentProps, TouchableOpacityProps { +type ToggleStyledProps = Overwrite; + +export interface ToggleProps extends TouchableOpacityProps, ToggleStyledProps { checked?: boolean; - disabled?: boolean; - status?: string; - size?: string; - text?: string; - textStyle?: StyleProp; onChange?: (checked: boolean) => void; + text?: RenderProp | React.ReactText; + status?: 'basic' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'control' | string; } export type ToggleElement = React.ReactElement; @@ -59,18 +58,16 @@ export type ToggleElement = React.ReactElement; * @property {boolean} checked - Determines whether component is checked. * Default is `false`. * - * @property {boolean} disabled - Determines whether component is disabled. - * Default is `false. - * * @property {string} status - Determines the status of the component. * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. * Default is `basic`. * - * @property {string} text - Determines text of the component. + * @property {string | (props: TextProps) => ReactElement} text - A string or a function component + * to render near the toggle. + * If it is a function, it will be called with props provided by Eva. + * Otherwise, renders a Text styled by Eva. * - * @property {StyleProp} textStyle - Customizes text style. - * - * @property {(checked: boolean) => void} onChange - Fires when selection state is changed. + * @property {(checked: boolean) => void} onChange - Called on toggle value change. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. * @@ -204,7 +201,7 @@ export class ToggleComponent extends React.Component implements Pan } }; - private getComponentStyle = (source: StyleType): StyleType => { + private getComponentStyle = (source: StyleType) => { const { checked, disabled } = this.props; const { @@ -231,7 +228,6 @@ export class ToggleComponent extends React.Component implements Pan } = source; return { - toggleContainer: {}, ellipseContainer: { borderColor: borderColor, backgroundColor: backgroundColor, @@ -280,7 +276,7 @@ export class ToggleComponent extends React.Component implements Pan this.thumbTranslateAnimationActive = true; Animated.timing(this.thumbTranslateAnimation, { - toValue: I18nLayoutService.select(value, -value), + toValue: RTLService.select(value, -value), duration: 150, easing: Easing.linear, }).start(() => { @@ -326,44 +322,30 @@ export class ToggleComponent extends React.Component implements Pan this.animateThumbWidth(this.props.eva.style.thumbWidth); }; - private renderTextElement = (style: StyleType): TextElement => { - return ( - - {this.props.text} - - ); - }; - - private renderComponentChildren = (style: StyleType): React.ReactNodeArray => { - return [ - this.props.text && this.renderTextElement(style.text), - ]; - }; - public render(): React.ReactElement { - const { eva, style, checked, ...restProps } = this.props; - - const componentStyle: StyleType = this.getComponentStyle(eva.style); - const [textElement] = this.renderComponentChildren(componentStyle); + const { eva, style, checked, text, ...touchableProps } = this.props; + const evaStyle = this.getComponentStyle(eva.style); return ( - - - - - - + style={[webStyles.toggleContainer, styles.toggleContainer]}> + + + + + - - {textElement} + + ); } diff --git a/src/components/ui/toggle/toggle.spec.tsx b/src/components/ui/toggle/toggle.spec.tsx index 43f1083df..50047d46c 100644 --- a/src/components/ui/toggle/toggle.spec.tsx +++ b/src/components/ui/toggle/toggle.spec.tsx @@ -1,110 +1,88 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + import React from 'react'; +import { Text } from 'react-native'; import { fireEvent, render, - RenderAPI, + waitForElement, } from 'react-native-testing-library'; import { ReactTestInstance } from 'react-test-renderer'; import { - ApplicationProvider, - ApplicationProviderProps, -} from '@kitten/theme'; + light, + mapping, +} from '@eva-design/eva'; +import { ApplicationProvider } from '../../theme'; import { Toggle, ToggleComponent, ToggleProps, } from './toggle.component'; -import { - mapping, - theme, -} from '../support/tests'; - -jest.mock('react-native/Libraries/Animated/src/Animated', (): unknown => { - const AnimatedModule = jest.requireActual('react-native/Libraries/Animated/src/Animated'); - return { - ...AnimatedModule, - timing: (value, config) => { - return { - start: (callback) => { - value.setValue(config.toValue); - callback && callback(); - }, - }; - }, - }; -}); -const Mock = (props?: ToggleProps): React.ReactElement => { - return ( +describe('@toggle: component checks', () => { + + const TestToggle = (props?: ToggleProps) => ( + theme={light}> ); -}; -const renderComponent = (props?: ToggleProps): RenderAPI => { - return render( - , - ); -}; + it('should request checking', async () => { + const onCheckedChange = jest.fn(); -describe('@toggle: component checks', () => { + const component = render( + , + ); - it('contains text', () => { - const component: RenderAPI = renderComponent({ - text: 'Sample Text', - }); + const responder = component.getByType(ToggleComponent).children[0]; + fireEvent(responder as ReactTestInstance, 'responderRelease'); - expect(component.getByText('Sample Text')).toBeTruthy(); + await waitForElement(() => expect(onCheckedChange).toBeCalledWith(true)); }); - it('emits onChange', () => { - const onChange = jest.fn(); + it('should request unchecking', async () => { + const onCheckedChange = jest.fn(); - const component: RenderAPI = renderComponent({ onChange }); - const { [0]: containerView } = component.getByType(ToggleComponent).children; + const component = render( + , + ); - fireEvent(containerView as ReactTestInstance, 'responderRelease'); + const responder = component.getByType(ToggleComponent).children[0]; + fireEvent(responder as ReactTestInstance, 'responderRelease'); - expect(onChange).toHaveBeenCalled(); + await waitForElement(() => expect(onCheckedChange).toBeCalledWith(false)); }); - it('checking of value direct', () => { - let checked: boolean = false; - const onChangeValue = (changed: boolean) => { - checked = changed; - }; - - const component: RenderAPI = renderComponent({ - checked: checked, - onChange: onChangeValue, - }); + it('should render text', () => { + const component = render( + , + ); - const { [0]: containerView } = component.getByType(ToggleComponent).children; + const text = component.getByText('I love Babel'); - fireEvent(containerView as ReactTestInstance, 'responderRelease'); - - expect(checked).toBe(true); + expect(text).toBeTruthy(); }); - it('checking of value reverse', () => { - let checked: boolean = true; - const onChangeValue = (changed: boolean) => { - checked = changed; - }; - - const component: RenderAPI = renderComponent({ - checked: checked, - onChange: onChangeValue, - }); - - const { [0]: containerView } = component.getByType(ToggleComponent).children; + it('should render text as component', () => { + const component = render( + I love Babel}/>, + ); - fireEvent(containerView as ReactTestInstance, 'responderRelease'); + const text = component.getByText('I love Babel'); - expect(checked).toBe(false); + expect(text).toBeTruthy(); }); });