Skip to content

Commit

Permalink
Add "Text Styles" TextInput Example
Browse files Browse the repository at this point in the history
Summary:
This adds a series of examples for TextInput styles to screenshot test, specifically the ones which are projected to Android as spans. This will be used in refactoring to verify we do not change visual output.

Changelog:
[Internal][Added] - Add "Text Styles" TextInput Example

Reviewed By: cortinico

Differential Revision: D43158004

fbshipit-source-id: adaecf0e37941e66e280db282e2631a95b08b27a
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Feb 21, 2023
1 parent d147bbb commit 817948e
Show file tree
Hide file tree
Showing 2 changed files with 258 additions and 12 deletions.
3 changes: 2 additions & 1 deletion packages/rn-tester/js/components/RNTesterButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes';

type Props = $ReadOnly<{|
testID?: string,
textTestID?: string,
children?: React.Node,
onPress?: ?(event: PressEvent) => mixed,
|}>;
Expand All @@ -30,7 +31,7 @@ class RNTesterButton extends React.Component<Props> {
onPress={this.props.onPress}
style={styles.button}
underlayColor="grey">
<Text>{this.props.children}</Text>
<Text testID={this.props.textTestID}>{this.props.children}</Text>
</TouchableHighlight>
);
}
Expand Down
267 changes: 256 additions & 11 deletions packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@

'use strict';

const React = require('react');

const {
import * as React from 'react';
import {useContext, useState} from 'react';
import {
Button,
Platform,
Text,
TextInput,
View,
StyleSheet,
} = require('react-native');
} from 'react-native';
import type {TextStyle} from 'react-native/Libraries/StyleSheet/StyleSheet';

import RNTesterButton from '../../components/RNTesterButton';
import {RNTesterThemeContext} from '../../components/RNTesterTheme';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';

const styles = StyleSheet.create({
Expand Down Expand Up @@ -49,9 +52,10 @@ const styles = StyleSheet.create({
},
label: {
width: 115,
alignItems: 'flex-end',
textAlign: 'right',
marginRight: 10,
paddingTop: 2,
fontSize: 12,
},
inputContainer: {
flex: 1,
Expand Down Expand Up @@ -80,15 +84,20 @@ const styles = StyleSheet.create({
fontSize: 13,
padding: 4,
},
screenshotArea: {
position: 'absolute',
top: -5,
left: 120,
right: -5,
bottom: -5,
},
});

class WithLabel extends React.Component<$FlowFixMeProps> {
render(): React.Node {
return (
<View style={styles.labelContainer}>
<View style={styles.label}>
<Text>{this.props.label}</Text>
</View>
<Text style={styles.label}>{this.props.label}</Text>
<View style={styles.inputContainer}>{this.props.children}</View>
</View>
);
Expand Down Expand Up @@ -592,6 +601,239 @@ function UncontrolledExample() {
);
}

const TextStylesExample = React.memo(() => {
const theme = useContext(RNTesterThemeContext);

return (
<TextStylesContainer
examples={[
{
name: 'backgroundColor',
textStyles: [
{backgroundColor: theme.SystemBackgroundColor},
{backgroundColor: 'red'},
{backgroundColor: 'orange'},
{backgroundColor: 'yellow'},
{backgroundColor: 'green'},
{backgroundColor: 'blue'},
],
},
{
name: 'color',
textStyles: [
{color: theme.LabelColor},
{color: 'red'},
{color: 'orange'},
{color: 'yellow'},
{color: 'green'},
{color: 'blue'},
],
},
{
name: 'fontFamily',
textStyles: [
{fontFamily: 'sans-serif'},
{fontFamily: 'serif'},
{fontFamily: 'monospace'},
],
},
{
name: 'fontSize',
textStyles: [
{fontSize: 8},
{fontSize: 10},
{fontSize: 12},
{fontSize: 14},
{fontSize: 16},
{fontSize: 18},
],
},
{
name: 'fontStyle',
textStyles: [{fontStyle: 'normal'}, {fontStyle: 'italic'}],
},
{
name: 'fontWeight',
textStyles: [
{fontWeight: 'normal'},
{fontWeight: 'bold'},
{fontWeight: '200'},
{fontWeight: '400'},
{fontWeight: '600'},
{fontWeight: '800'},
],
},
{
name: 'letterSpacing',
textStyles: [
{letterSpacing: 0},
{letterSpacing: 1},
{letterSpacing: 2},
{letterSpacing: 3},
{letterSpacing: 4},
{letterSpacing: 5},
],
},
{
name: 'lineHeight',
multiline: true,
textStyles: [
{lineHeight: 4},
{lineHeight: 8},
{lineHeight: 16},
{lineHeight: 24},
],
},
{
name: 'textDecorationLine',
textStyles: [
{textDecorationLine: 'none'},
{textDecorationLine: 'underline'},
{textDecorationLine: 'line-through'},
{textDecorationLine: 'underline line-through'},
],
},
{
name: 'textShadow',
textStyles: [
{
textShadowColor: 'black',
textShadowOffset: {width: 0, height: 0},
textShadowRadius: 0,
},
{
textShadowColor: 'black',
textShadowOffset: {width: 0, height: 0},
textShadowRadius: 5,
},
{
textShadowColor: 'red',
textShadowOffset: {width: 0, height: 0},
textShadowRadius: 5,
},
{
textShadowColor: 'blue',
textShadowOffset: {width: 0, height: -5},
textShadowRadius: 5,
},
{
textShadowColor: 'green',
textShadowOffset: {width: 0, height: 5},
textShadowRadius: 5,
},
{
textShadowColor: 'orange',
textShadowOffset: {width: 10, height: 0},
textShadowRadius: 5,
},
],
},
]}
/>
);
});

type TextStylesContainerProps = {
examples: $ReadOnlyArray<{
name: string,
textStyles: $ReadOnlyArray<TextStyle>,
multiline?: boolean,
}>,
};

function TextStylesContainer({examples}: TextStylesContainerProps) {
const [offset, setOffset] = useState(0);

const MAX_CYCLES = 6;

return (
<View>
<RNTesterButton
testID="cycle-styles"
textTestID="cycle-styles-label"
onPress={() => setOffset((offset + 1) % MAX_CYCLES)}>
Cycle {offset + 1}/{MAX_CYCLES}
</RNTesterButton>
<View>
<View testID="styles-screenshot-area" style={styles.screenshotArea} />
{examples.map(({name, multiline, textStyles}) => (
<WithLabel label={name} key={name}>
{multiline ? (
<MultilineStyledTextInput
name={name}
textStyles={textStyles}
styleOffset={offset}
/>
) : (
<StyledTextInput
name={name}
textStyles={textStyles}
styleOffset={offset}
/>
)}
</WithLabel>
))}
</View>
</View>
);
}

type StyledTextInputProps = {
name: string,
textStyles: $ReadOnlyArray<TextStyle>,
styleOffset: number,
};

function StyledTextInput({
name,
textStyles,
styleOffset,
}: StyledTextInputProps) {
return (
<TextInput
style={[
styles.default,
textStyles[(0 + styleOffset) % textStyles.length],
]}
testID={`style-${name}`}>
<Text>He</Text>
<Text style={textStyles[(1 + styleOffset) % textStyles.length]}>ll</Text>
<Text style={textStyles[(2 + styleOffset) % textStyles.length]}>
o,
<Text style={textStyles[(0 + styleOffset) % textStyles.length]}> </Text>
</Text>
<Text style={textStyles[(3 + styleOffset) % textStyles.length]}>Wo</Text>
<Text style={textStyles[(4 + styleOffset) % textStyles.length]}>rl</Text>
<Text style={textStyles[(5 + styleOffset) % textStyles.length]}>d!</Text>
</TextInput>
);
}

function MultilineStyledTextInput({
name,
textStyles,
styleOffset,
}: StyledTextInputProps) {
return (
<TextInput
multiline={true}
style={[
styles.default,
textStyles[(0 + styleOffset) % textStyles.length],
]}
testID={`style-${name}`}>
<Text>Hel{'\n'}</Text>
<Text style={textStyles[(1 + styleOffset) % textStyles.length]}>
lo {'\n'}
</Text>
<Text style={textStyles[(2 + styleOffset) % textStyles.length]}>
Wor{'\n'}
</Text>
<Text style={textStyles[(3 + styleOffset) % textStyles.length]}>ld!</Text>
</TextInput>
);
}

module.exports = ([
{
title: 'Auto-focus',
Expand Down Expand Up @@ -867,8 +1109,11 @@ module.exports = ([
{
title: 'Uncontrolled component with layout changes',
name: 'uncontrolledComponent',
render: function (): React.Node {
return <UncontrolledExample />;
},
render: () => <UncontrolledExample />,
},
{
title: 'Text styles',
name: 'textStyles',
render: () => <TextStylesExample />,
},
]: Array<RNTesterModuleExample>);

0 comments on commit 817948e

Please sign in to comment.