Skip to content

Commit

Permalink
feat: adjust TextInput (#3108)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewalczak authored May 30, 2022
1 parent 529f21b commit 22ce25d
Show file tree
Hide file tree
Showing 13 changed files with 1,600 additions and 522 deletions.
801 changes: 421 additions & 380 deletions example/src/Examples/TextInputExample.tsx

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion src/components/TextInput/Adornment/TextInputAdornment.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import TextInputIcon, { IconAdornment } from './TextInputIcon';
import TextInputAffix, { AffixAdornment } from './TextInputAffix';
import { ADORNMENT_OFFSET, OUTLINED_INPUT_OFFSET } from '../constants';
import type {
LayoutChangeEvent,
TextStyle,
Expand All @@ -13,6 +12,7 @@ import type {
AdornmentStyleAdjustmentForNativeInput,
} from './types';
import { AdornmentSide, AdornmentType, InputMode } from './enums';
import { getConstants } from '../helpers';

export function getAdornmentConfig({
left,
Expand Down Expand Up @@ -52,14 +52,18 @@ export function getAdornmentStyleAdjustmentForNativeInput({
paddingHorizontal,
inputOffset = 0,
mode,
isV3,
}: {
inputOffset?: number;
adornmentConfig: AdornmentConfig[];
leftAffixWidth: number;
rightAffixWidth: number;
mode?: 'outlined' | 'flat';
paddingHorizontal?: number | string;
isV3?: boolean;
}): AdornmentStyleAdjustmentForNativeInput | {} {
const { OUTLINED_INPUT_OFFSET, ADORNMENT_OFFSET } = getConstants(isV3);

if (adornmentConfig.length) {
const adornmentStyleAdjustmentForNativeInput = adornmentConfig.map(
({ type, side }: AdornmentConfig) => {
Expand Down
5 changes: 3 additions & 2 deletions src/components/TextInput/Adornment/TextInputAffix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {
import { withTheme } from '../../../core/theming';
import { AdornmentSide } from './enums';
import type { Theme } from '../../../types';

const AFFIX_OFFSET = 12;
import { getConstants } from '../helpers';

export type Props = {
/**
Expand Down Expand Up @@ -109,6 +108,8 @@ const AffixAdornment: React.FunctionComponent<
*/

const TextInputAffix = ({ text, textStyle: labelStyle, theme }: Props) => {
const { AFFIX_OFFSET } = getConstants(theme.isV3);

const { textStyle, onLayout, topPosition, side, visible, paddingHorizontal } =
React.useContext(AffixContext);
const textColor = color(
Expand Down
26 changes: 22 additions & 4 deletions src/components/TextInput/Adornment/TextInputIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import IconButton from '../../IconButton';
import type { $Omit, Theme } from '../../../types';
import type { IconSource } from '../../Icon';
import { useTheme } from '../../../core/theming';
import { getConstants } from '../helpers';
import { ICON_SIZE } from '../constants';

export type Props = $Omit<
React.ComponentProps<typeof IconButton>,
Expand Down Expand Up @@ -32,9 +35,6 @@ export type Props = $Omit<
theme?: Theme;
};

export const ICON_SIZE = 24;
const ICON_OFFSET = 12;

type StyleContextType = {
style: StyleProp<ViewStyle>;
isTextInputFocused: boolean;
Expand All @@ -55,6 +55,9 @@ const IconAdornment: React.FunctionComponent<
side: 'left' | 'right';
} & Omit<StyleContextType, 'style'>
> = ({ icon, topPosition, side, isTextInputFocused, forceFocus }) => {
const { isV3 } = useTheme();
const { ICON_OFFSET } = getConstants(isV3);

const style = {
top: topPosition,
[side]: ICON_OFFSET,
Expand Down Expand Up @@ -113,14 +116,29 @@ const TextInputIcon = ({
onPress?.();
}, [forceTextInputFocus, forceFocus, isTextInputFocused, onPress]);

const theme = useTheme();

let iconColor = color;

if (theme.isV3) {
if (rest.disabled) {
iconColor = theme.colors.onSurface;
}
iconColor = theme.colors.onSurfaceVariant;
} else {
iconColor = theme.colors.text;
}

return (
<View style={[styles.container, style]}>
<IconButton
icon={name}
style={styles.iconButton}
size={ICON_SIZE}
onPress={onPressWithFocusControl}
color={typeof color === 'function' ? color(isTextInputFocused) : color}
color={
typeof color === 'function' ? color(isTextInputFocused) : iconColor
}
{...rest}
/>
</View>
Expand Down
23 changes: 20 additions & 3 deletions src/components/TextInput/Label/InputLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import { Animated, StyleSheet } from 'react-native';
import AnimatedText from '../../Typography/AnimatedText';
import { useTheme } from '../../../core/theming';

import type { InputLabelProps } from '../types';

const InputLabel = (props: InputLabelProps) => {
const { parentState, labelBackground } = props;

const { isV3 } = useTheme();
const { parentState, labelBackground, mode } = props;
const {
label,
error,
Expand Down Expand Up @@ -70,6 +71,15 @@ const InputLabel = (props: InputLabelProps) => {
],
};

let textColor = placeholderColor;

if (error && errorColor) {
textColor = errorColor;
}
if (isV3 && parentState.value && mode !== 'outlined') {
textColor = activeColor;
}

return label ? (
// Position colored placeholder and gray placeholder on top of each other and crossfade them
// This gives the effect of animating the color, but allows us to use native driver
Expand All @@ -96,6 +106,7 @@ const InputLabel = (props: InputLabelProps) => {
labelProps: props.labelProps,
})}
<AnimatedText
variant="bodySmall"
onLayout={onLayoutAnimatedText}
style={[
placeholderStyle,
Expand All @@ -111,12 +122,14 @@ const InputLabel = (props: InputLabelProps) => {
outputRange: [hasActiveOutline ? 1 : 0, 0],
}),
},
isV3 && styles.md3TextLine,
]}
numberOfLines={1}
>
{label}
</AnimatedText>
<AnimatedText
variant={parentState.focused ? 'bodyLarge' : 'bodySmall'}
style={[
placeholderStyle,
{
Expand All @@ -125,9 +138,10 @@ const InputLabel = (props: InputLabelProps) => {
labelStyle,
paddingOffset,
{
color: error && errorColor ? errorColor : placeholderColor,
color: textColor,
opacity: placeholderOpacity,
},
isV3 && styles.md3TextLine,
]}
numberOfLines={1}
>
Expand All @@ -141,6 +155,9 @@ const styles = StyleSheet.create({
labelContainer: {
zIndex: 3,
},
md3TextLine: {
lineHeight: undefined,
},
});

export default InputLabel;
61 changes: 38 additions & 23 deletions src/components/TextInput/Label/LabelBackground.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { Animated, StyleSheet } from 'react-native';
import { useTheme } from '../../../core/theming';

import AnimatedText from '../../Typography/AnimatedText';

Expand All @@ -24,17 +25,37 @@ const LabelBackground = ({
outputRange: [hasFocus ? 1 : 0, 0],
});

const { isV3, colors } = useTheme();

const labelTranslationX = {
transform: [
{
translateX: parentState.labeled.interpolate({
inputRange: [0, 1],
outputRange: [-baseLabelTranslateX, 0],
}),
},
],
translateX: parentState.labeled.interpolate({
inputRange: [0, 1],
outputRange: [-baseLabelTranslateX, 0],
}),
};

const labelTextScaleY = {
scaleY: parentState.labeled.interpolate({
inputRange: [0, 1],
outputRange: [0.2, 1],
}),
};

const labelTextTransform = isV3
? [...labelStyle.transform]
: [...labelStyle.transform, labelTextScaleY];

const labelTextWidth = isV3
? {
width:
parentState.labelLayout.width - placeholderStyle.paddingHorizontal,
}
: {
maxWidth:
parentState.labelLayout.width -
2 * placeholderStyle.paddingHorizontal,
};

return label
? [
<Animated.View
Expand All @@ -48,8 +69,8 @@ const LabelBackground = ({
maxHeight: Math.max(roundness / 3, 2),
opacity,
bottom: Math.max(roundness, 2),
transform: [labelTranslationX],
},
labelTranslationX,
]}
/>,
<AnimatedText
Expand All @@ -58,23 +79,14 @@ const LabelBackground = ({
placeholderStyle,
labelStyle,
styles.outlinedLabel,
isV3 && styles.md3OutlinedLabel,
{
top: topPosition + 1,
backgroundColor,
top: topPosition + (isV3 ? 0 : 1),
backgroundColor: isV3 ? colors.surface : backgroundColor,
opacity,
transform: [
...labelStyle.transform,
{
scaleY: parentState.labeled.interpolate({
inputRange: [0, 1],
outputRange: [0.2, 1],
}),
},
],
maxWidth:
parentState.labelLayout.width -
2 * placeholderStyle.paddingHorizontal,
transform: labelTextTransform,
},
labelTextWidth,
]}
numberOfLines={1}
>
Expand All @@ -99,4 +111,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 0,
color: 'transparent',
},
md3OutlinedLabel: {
left: 8,
},
});
Loading

0 comments on commit 22ce25d

Please sign in to comment.