react-native#ImageStyle TypeScript Examples

The following examples show how to use react-native#ImageStyle. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx    From react-native-floating-label-input with MIT License 6 votes vote down vote up
setGlobalStyles: SetGlobalStyles = {
  /**Set global styles to all floating-label-inputs container */
  containerStyles: undefined as ViewStyle | undefined,
  /**Set global custom styles to all floating-label-inputs labels */
  customLabelStyles: undefined as CustomLabelProps | undefined,
  /**Set global styles to all floating-label-inputs input */
  inputStyles: undefined as TextStyle | undefined,
  /**Set global styles to all floating-label-inputs label */
  labelStyles: undefined as TextStyle | undefined,
  /**Set global styles to all floating-label-inputs show password container */
  showPasswordContainerStyles: undefined as ViewStyle | undefined,
  /**Set global styles to all floating-label-inputs show password image */
  showPasswordImageStyles: undefined as ImageStyle | undefined,
  /**Set global style to the countdown text */
  showCountdownStyles: undefined as TextStyle | undefined,
}
Example #2
Source File: index.tsx    From frontatish with MIT License 4 votes vote down vote up
Searchbar = (props: SearchbarProps) => {
  const Colors = useColors();
  const styles = getStyles(Colors);

  // destructure custom props and TextInput props separately
  const customProps = getCustomProps(props);
  const textInputProps = getTextInputProps(customProps, props);

  const {
    backIcon,
    backIconStyle,
    clearIcon,
    clearIconStyle,
    containerStyle,
    inputStyle,
    leftIcon,
    leftIconStyle,
    leftLogo,
    leftLogoStyle,
    onBackIconPress,
    onClearIconPress,
    onLeftIconPress,
    onLeftLogoPress,
    onRightIconPress,
    onRightLogoPress,
    onPress,
    rightIcon,
    rightIconStyle,
    rightLogo,
    rightLogoStyle,
    showClearIcon,
    showBackIcon,
  } = customProps;

  const { onChangeText, editable, value } = textInputProps;

  const renderClearIcon = () => {
    if (!showClearIcon) {
      return null;
    }

    // we have to show transparent clear icon when value in textinput is empty
    // otherwise the text will move left once the clear icon is rendered
    const opacity = value ? 1 : 0;

    const onPressUtil = () => {
      if (opacity) {
        if (onClearIconPress) {
          onClearIconPress();
        } else if (onChangeText) {
          onChangeText('');
        }
      }
    };

    return renderIcon(clearIcon, clearIconStyle, onPressUtil, opacity);
  };

  const renderBackIcon = () => {
    if (!showBackIcon) {
      return null;
    }
    const opacity = 1;
    return renderIcon(backIcon, backIconStyle, onBackIconPress, opacity);
  };

  const renderLogo = (
    name: ImageSourcePropType,
    logoStyle: StyleProp<ImageStyle> | undefined,
    onLogoPress: (() => void) | undefined,
  ) => {
    const source = name;

    const onPressUtil = onLogoPress || onPress;

    return (
      <TouchableWithoutFeedback onPress={onPressUtil}>
        <Image
          source={source}
          style={{
            alignSelf: 'center',
            height: customScaleDimension(30, 'width', 0.2),
            width: customScaleDimension(30, 'width', 0.2),
            ...(logoStyle as object),
          }}
        />
      </TouchableWithoutFeedback>
    );
  };

  const renderIcon = (
    name: string | undefined,
    iconStyle: StyleProp<TextStyle> | undefined,
    onIconPress: (() => void) | undefined,
    opacity: number,
  ) => {
    const onPressUtil = onIconPress || onPress;

    return (
      <Icon
        name={name}
        size={customScaleDimension(30, 'width', 0.2)}
        onPress={onPressUtil}
        color={Colors.font_1}
        style={{ opacity, alignSelf: 'center', ...(iconStyle as object) }}
      />
    );
  };

  const renderLogoOrIcon = (
    logo: ImageSourcePropType | undefined,
    logoStyle: StyleProp<ImageStyle> | undefined,
    onLogoPress: (() => void) | undefined,
    icon: string | undefined,
    iconStyle: StyleProp<TextStyle> | undefined,
    onIconPress: (() => void) | undefined,
  ) => {
    if (logo) {
      return renderLogo(logo, logoStyle, onLogoPress);
    }
    if (icon) {
      const opacity = 1;
      return renderIcon(icon, iconStyle, onIconPress, opacity);
    }

    return null;
  };

  const renderLeft = () => {
    if (!editable) {
      return renderLogoOrIcon(
        leftLogo,
        leftLogoStyle,
        onLeftLogoPress,
        leftIcon,
        leftIconStyle,
        onLeftIconPress,
      );
    }
    return renderBackIcon();
  };

  const renderRight = () => {
    if (!editable) {
      return renderLogoOrIcon(
        rightLogo,
        rightLogoStyle,
        onRightLogoPress,
        rightIcon,
        rightIconStyle,
        onRightIconPress,
      );
    }
    return renderClearIcon();
  };

  // define some default values
  const searchbarContainerStyle = containerStyle
    ? { ...styles.searchbarContainer, ...(containerStyle as object) }
    : styles.searchbarContainer;

  const searchbarTextInputStyle = inputStyle
    ? { ...styles.textInput, ...(inputStyle as object) }
    : styles.textInput;

  textInputProps.onTouchStart = editable
    ? textInputProps.onTouchStart
    : onPress;

  textInputProps.selectionColor = textInputProps.selectionColor
    ? textInputProps.selectionColor
    : Colors.primary;

  textInputProps.placeholderTextColor = textInputProps.placeholderTextColor
    ? textInputProps.placeholderTextColor
    : Colors.font_3;

  return (
    <TouchableWithoutFeedback onPress={onPress}>
      <View style={searchbarContainerStyle}>
        {renderLeft()}
        <TextInput {...textInputProps} style={searchbarTextInputStyle} />
        {renderRight()}
      </View>
    </TouchableWithoutFeedback>
  );
}
Example #3
Source File: tracing.tsx    From protect-scotland with Apache License 2.0 4 votes vote down vote up
Tracing: FC = () => {
  const [showSpinner, setShowSpinner] = useState(false);
  const {checked, paused, deleteReminder} = useReminder();
  const {t} = useTranslation();
  const navigation = useNavigation();
  const {enabled, status, contacts, start} = useExposure();
  const tracingActive = enabled && status.state === StatusState.active;
  const pauseDate = new Date(Number(paused));
  const {isolationDuration} = useSettings();
  const hasContact = hasCurrentExposure(isolationDuration, contacts);

  if (!checked) {
    return null;
  }

  const renderActive = () => (
    <>
      <Text variant="h3" style={styles.active}>
        {t('tracing:status:heading')}
      </Text>
      <Spacing s={20} />
      <View style={styles.row}>
        <Image
          style={styles.moduleImage as ImageStyle}
          source={IconTracingActive}
          accessibilityIgnoresInvertColors={false}
        />
        <Text variant="h1" style={styles.active}>
          {t('tracing:status:active')}
        </Text>
      </View>
      <Spacing s={20} />
      <Markdown>{t('tracing:message')}</Markdown>
    </>
  );

  const renderInactive = () => (
    <>
      <Text variant="h3" style={styles.notActive}>
        {t('tracing:status:heading')}
      </Text>
      <Spacing s={20} />
      <View style={styles.row}>
        <Image
          style={styles.moduleImage as ImageStyle}
          source={IconTracingInactive}
          accessibilityIgnoresInvertColors={false}
        />
        <Text variant="h1" style={styles.notActive} maxFontSizeMultiplier={3}>
          {t('tracing:status:inactive')}
        </Text>
      </View>
      <Spacing s={20} />
      <Markdown>{t('tracing:inactiveMessage')}</Markdown>
      <Spacing s={20} />
      <Text bold maxFontSizeMultiplier={3}>
        {t('tracing:turnOn1')}
      </Text>
      <Spacing s={20} />
      <Text bold maxFontSizeMultiplier={3}>
        {t('tracing:turnOn2')}
      </Text>
      <Spacing s={30} />
      <GoToSettings />
      <Spacing s={40} />
      <Markdown>{t('tracing:inactiveMessage1')}</Markdown>
    </>
  );

  const renderPaused = () => (
    <>
      <Text variant="h3" style={styles.notActive}>
        {t('tracing:status:heading')}
      </Text>
      <Spacing s={20} />
      <View style={styles.row}>
        <View>
          <Image
            style={styles.moduleImage as ImageStyle}
            source={IconPaused}
            accessibilityIgnoresInvertColors={false}
          />
        </View>
        <View>
          <Text variant="h1" style={styles.notActive}>
            {t('tracing:paused:title')}
          </Text>
        </View>
      </View>
      <Spacing s={20} />
      <Text bold color="errorRed">
        {t('tracing:paused:reminder')} {format(pauseDate, 'HH:mm')}{' '}
        {isToday(pauseDate)
          ? t('common:today')
          : isTomorrow(pauseDate)
          ? t('common:tomorrow')
          : ''}
      </Text>
      {showSpinner ? (
        <View>
          <Spacing s={36} />
          <ActivityIndicator color={colors.darkGrey} size="large" />
          <Spacing s={36} />
        </View>
      ) : (
        <Markdown markdownStyles={inactiveMarkdownStyles}>
          {t('tracing:paused:text')}
        </Markdown>
      )}
      <Spacing s={20} />
      <Button
        type="primary"
        variant="dark"
        rounded
        onPress={async () => {
          setShowSpinner(true);
          await start();
          deleteReminder();
          setShowSpinner(false);
        }}>
        {t('tracing:paused:buttonLabel')}
      </Button>
    </>
  );

  return (
    <ScrollView style={styles.container}>
      <ModalHeader
        icon={TracingIcon}
        closeIcon={CloseIcon}
        heading="tracing:heading"
        color="validationGreen"
      />
      <Spacing s={34} />
      <Container center="horizontal">
        {hasContact && (
          <>
            <TouchableWithoutFeedback
              onPress={() => navigation.navigate(ScreenNames.closeContact)}>
              <Container center="horizontal">
                <RoundedBox style={styles.notification}>
                  <Text variant="h3" color="errorRed">
                    {t('tracing:notificationTitle')}
                  </Text>
                  <Spacing s={10} />
                  <Markdown markdownStyles={notificationMarkdownStyles}>
                    {t('tracing:notificationBody')}
                  </Markdown>
                </RoundedBox>
              </Container>
            </TouchableWithoutFeedback>
            <Spacing s={55} />
          </>
        )}
        <Image
          source={TracingIllustration}
          accessibilityIgnoresInvertColors={false}
        />
        <Spacing s={43} />
        <Text variant="leader" color="darkGrey" align="center">
          {t('tracing:body')}
        </Text>
        <Spacing s={30} />
        <Markdown accessibleLink={t('links:o')}>
          {t('tracing:additional', {link: t('links:o')})}
        </Markdown>
        <Spacing s={34} />
        <RoundedBox
          style={tracingActive && !paused ? styles.active : undefined}>
          {paused
            ? renderPaused()
            : tracingActive
            ? renderActive()
            : renderInactive()}
        </RoundedBox>
        <Spacing s={20} />
        {!paused && tracingActive && (
          <Button
            type="secondary"
            rounded
            textColor="validationGreen"
            onPress={() => navigation.navigate(ScreenNames.pause)}
            style={styles.button}
            buttonStyle={styles.buttonStyle}>
            I want to pause Tracing
          </Button>
        )}
      </Container>
      <Spacing s={120} />
    </ScrollView>
  );
}
Example #4
Source File: DatePicker.tsx    From react-native-jigsaw with MIT License 4 votes vote down vote up
DatePicker: React.FC<Props> = ({
  Icon,
  style,
  theme: { colors, typography, roundness, disabledOpacity },
  date,
  onDateChange = () => {},
  defaultValue,
  disabled = false,
  mode = "date",
  format,
  type = "underline",
  leftIconName,
  rightIconName,
  leftIconMode = "inset",
  label,
  placeholder,
  ...props
}) => {
  const [value, setValue] = React.useState<any>(date || defaultValue);

  React.useEffect(() => {
    if (defaultValue != null) {
      setValue(defaultValue);
    }
  }, [defaultValue]);

  const [pickerVisible, setPickerVisible] = React.useState(false);
  const [labeled] = React.useState<Animated.Value>(
    new Animated.Value(date ? 0 : 1)
  );
  const [placeholder1, setPlaceholder1] = React.useState("");
  const [focused, setFocused] = React.useState<boolean>(false);
  const [labelLayout, setLabelLayout] = React.useState<{
    measured: Boolean;
    width: number;
  }>({ measured: false, width: 0 });

  const getValidDate = (): Date => {
    if (!value) {
      return new Date();
    }
    return typeof value?.getMonth === "function" ? value : new Date();
  };

  const formatDate = (): string => {
    if (!value) return "";
    let newDate = getValidDate();

    if (format) return dateFormat(newDate, format);

    if (mode === "time") {
      return `${newDate.toLocaleTimeString()}`;
    }

    if (mode === "datetime") {
      return `${newDate.toLocaleString()}`;
    }

    return `${
      MONTHS[newDate.getMonth()]
    } ${newDate.getDate()}, ${newDate.getFullYear()}`;
  };

  const toggleVisibility = async () => {
    setPickerVisible(!pickerVisible);
    focused ? _handleBlur() : _handleFocus();
  };
  const insets = useSafeAreaInsets();

  // const _restoreLabel = () =>
  //   Animated.timing(labeled, {
  //     toValue: 1,
  //     duration: FOCUS_ANIMATION_DURATION,
  //     useNativeDriver: true,
  //   }).start();

  // const _minmizeLabel = () =>
  //   Animated.timing(labeled, {
  //     toValue: 0,
  //     duration: BLUR_ANIMATION_DURATION,
  //     useNativeDriver: true,
  //   }).start();

  // const _showPlaceholder = () =>
  //   setTimeout(() => setPlaceholder1(placeholder || ""), 50);

  const _hidePlaceholder = () => {
    setPlaceholder1("");
  };

  React.useEffect(() => {
    setValue(date);
  }, [date]);

  React.useEffect(() => {
    if (value || focused || placeholder1) {
      // _minmizeLabel();
      Animated.timing(labeled, {
        toValue: 0,
        duration: BLUR_ANIMATION_DURATION,
        useNativeDriver: true,
      }).start();
    } else {
      // _restoreLabel();
      Animated.timing(labeled, {
        toValue: 1,
        duration: FOCUS_ANIMATION_DURATION,
        useNativeDriver: true,
      }).start();
    }
  }, [value, focused, placeholder1, labeled]);

  React.useEffect(() => {
    const _showPlaceholder = () =>
      setTimeout(() => setPlaceholder1(placeholder || ""), 50);
    if (focused || !label) {
      _showPlaceholder();
    } else {
      _hidePlaceholder();
    }
    return () => {
      clearTimeout(_showPlaceholder());
    };
  }, [focused, label, placeholder]);

  const _handleFocus = () => {
    if (disabled) {
      return;
    }

    setFocused(true);
  };

  const _handleBlur = () => {
    if (disabled) {
      return;
    }
    setFocused(false);
  };

  const MINIMIZED_LABEL_Y_OFFSET = -(typography.caption.lineHeight + 4);
  const OUTLINE_MINIMIZED_LABEL_Y_OFFSET = -(16 * 0.5 + 4);
  const MAXIMIZED_LABEL_FONT_SIZE = typography.subtitle1.fontSize;
  const MINIMIZED_LABEL_FONT_SIZE = typography.caption.fontSize;

  const hasActiveOutline = focused;

  let inputTextColor,
    activeColor,
    underlineColor,
    borderColor,
    placeholderColor,
    containerStyle: StyleProp<ViewStyle>,
    backgroundColor,
    inputStyle: StyleProp<TextStyle>;

  inputTextColor = colors.strong;
  if (disabled) {
    activeColor = colors.light;
    placeholderColor = colors.light;
    borderColor = "transparent";
    underlineColor = "transparent";
    backgroundColor = colors.divider;
  } else {
    activeColor = colors.primary;
    placeholderColor = borderColor = colors.light;
    underlineColor = colors.light;
    backgroundColor = colors.background;
  }

  const { lineHeight, ...subtitle1 } = typography.subtitle1;

  inputStyle = {
    paddingVertical: 0,
    color: inputTextColor,
    paddingLeft:
      leftIconName && leftIconMode === "inset"
        ? ICON_SIZE + (type === "solid" ? 16 : 12)
        : 0,
    paddingRight: rightIconName ? ICON_SIZE + 16 + 4 : 12,
    ...subtitle1,
    height: lineHeight,
  };

  if (type === "underline") {
    containerStyle = {
      borderTopLeftRadius: roundness,
      borderTopRightRadius: roundness,
      paddingBottom: 12,
      marginTop: 16,
    };
  } else {
    containerStyle = {
      borderRadius: roundness,
      borderColor: hasActiveOutline ? activeColor : borderColor,
      borderWidth: 1,
      paddingTop: labeled ? 16 * 1.5 : 16,
      paddingBottom: labeled ? 16 * 0.5 : 16,
      opacity: disabled ? disabledOpacity : 1,
      backgroundColor,
    };

    inputStyle.paddingHorizontal = 12;
  }

  if (leftIconName && leftIconMode === "outset") {
    containerStyle.marginLeft = ICON_SIZE + 8;
  }

  let leftIconColor;
  if (focused) {
    leftIconColor = colors.primary;
  } else {
    leftIconColor = colors.light;
  }

  const leftIconProps = {
    size: 24,
    color: leftIconColor,
    name: leftIconName || "",
  };

  const leftIconStyle: ImageStyle = {
    position: "absolute",
    marginTop:
      type === "solid"
        ? leftIconMode === "inset"
          ? MINIMIZED_LABEL_FONT_SIZE + 4
          : 16
        : leftIconMode === "outset"
        ? 16
        : 0,
  };

  const labelStyle = {
    ...typography.subtitle1,
    top: type === "solid" ? 16 : 0,
    left:
      leftIconName && leftIconMode === "inset"
        ? ICON_SIZE + (type === "solid" ? 16 : 12)
        : 0,
    transform: [
      {
        // Move label to top
        translateY: labeled.interpolate({
          inputRange: [0, 1],
          outputRange: [
            type === "solid"
              ? OUTLINE_MINIMIZED_LABEL_Y_OFFSET
              : MINIMIZED_LABEL_Y_OFFSET,
            0,
          ],
        }),
      },
      {
        // Make label smaller
        scale: labeled.interpolate({
          inputRange: [0, 1],
          outputRange: [
            MINIMIZED_LABEL_FONT_SIZE / MAXIMIZED_LABEL_FONT_SIZE,
            1,
          ],
        }),
      },
      {
        // Offset label scale since RN doesn't support transform origin
        translateX: labeled.interpolate({
          inputRange: [0, 1],
          outputRange: [
            -(1 - MINIMIZED_LABEL_FONT_SIZE / MAXIMIZED_LABEL_FONT_SIZE) *
              (labelLayout.width / 2),
            0,
          ],
        }),
      },
    ],
  };

  const inputStyles = [
    styles.input,
    inputStyle,
    type === "solid" ? { marginHorizontal: 12 } : {},
  ];

  // const render = (props) => <NativeTextInput {...props} />;

  return (
    <View style={[styles.container, style]}>
      <Touchable disabled={disabled} onPress={toggleVisibility}>
        <View pointerEvents="none">
          <View style={[styles.container, style]}>
            {leftIconName && leftIconMode === "outset" ? (
              <Icon {...leftIconProps} style={leftIconStyle} />
            ) : null}
            <View
              style={[containerStyle, style ? { height: style.height } : {}]}
            >
              {type === "underline" ? (
                // When type === 'flat', render an underline
                <Animated.View
                  style={[
                    styles.underline,
                    {
                      backgroundColor: focused ? activeColor : underlineColor,
                      // Underlines is thinner when input is not focused
                      transform: [{ scaleY: focused ? 1 : 0.5 }],
                    },
                  ]}
                />
              ) : null}

              {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
                <View
                  pointerEvents="none"
                  style={[
                    StyleSheet.absoluteFill,
                    {
                      opacity:
                        // Hide the label in minimized state until we measure its width
                        date || focused ? (labelLayout.measured ? 1 : 0) : 1,
                    },
                  ]}
                >
                  <AnimatedText
                    onLayout={(e: LayoutChangeEvent) =>
                      setLabelLayout({
                        width: e.nativeEvent.layout.width,
                        measured: true,
                      })
                    }
                    style={[
                      styles.placeholder,
                      type === "solid" ? { paddingHorizontal: 12 } : {},
                      labelStyle,
                      {
                        color: colors.light,
                        opacity: labeled.interpolate({
                          inputRange: [0, 1],
                          outputRange: [hasActiveOutline ? 1 : 0, 0],
                        }),
                      },
                    ]}
                    numberOfLines={1}
                  >
                    {label}
                  </AnimatedText>
                  <AnimatedText
                    style={[
                      styles.placeholder,
                      type === "solid" ? { paddingHorizontal: 12 } : {},
                      labelStyle,
                      {
                        color: placeholderColor,
                        opacity: hasActiveOutline ? labeled : 1,
                      },
                    ]}
                    numberOfLines={1}
                  >
                    {label}
                  </AnimatedText>
                </View>
              ) : null}

              {leftIconName && leftIconMode === "inset" ? (
                <Icon
                  {...leftIconProps}
                  style={{
                    ...leftIconStyle,
                    marginLeft: type === "solid" ? 16 : 0,
                  }}
                />
              ) : null}

              <NativeTextInput
                value={formatDate()}
                placeholder={label ? placeholder1 : placeholder}
                editable={!disabled}
                placeholderTextColor={placeholderColor}
                selectionColor={activeColor}
                onFocus={_handleFocus}
                onBlur={_handleBlur}
                underlineColorAndroid={"transparent"}
                style={inputStyles}
                {...props}
              />
            </View>
            {rightIconName ? (
              <Icon
                name={rightIconName}
                size={ICON_SIZE}
                color={colors.light}
                style={{
                  position: "absolute",
                  right: 16,
                  marginTop:
                    type === "solid" ? MINIMIZED_LABEL_FONT_SIZE + 4 : 16,
                }}
              />
            ) : null}
          </View>
        </View>
      </Touchable>
      {pickerVisible && (
        <Portal>
          <View
            style={[
              styles.picker,
              {
                backgroundColor: colors.divider,
              },
            ]}
          >
            <View
              style={[
                styles.pickerContainer,
                {
                  paddingTop: insets.top,
                  paddingBottom: insets.bottom,
                  paddingLeft: insets.left,
                  paddingRight: insets.right,
                },
              ]}
            >
              <DateTimePicker
                value={getValidDate()}
                mode={mode}
                isVisible={pickerVisible}
                toggleVisibility={toggleVisibility}
                onChange={(_event: any, data: any) => {
                  toggleVisibility();
                  setValue(data);
                  onDateChange(data);
                }}
              />
            </View>
          </View>
        </Portal>
      )}
    </View>
  );
}
Example #5
Source File: TextField.tsx    From react-native-jigsaw with MIT License 4 votes vote down vote up
render() {
    const {
      Icon,
      type = "underline",
      disabled = false,
      label,
      error = false,
      leftIconName,
      leftIconMode,
      rightIconName,
      assistiveText,
      underlineColor: underlineColorProp,
      multiline = false,
      numberOfLines = 4,
      style,
      theme: { colors, typography, roundness, disabledOpacity },
      render = (props) => <NativeTextInput {...props} />,
      ...rest
    } = this.props;

    const MINIMIZED_LABEL_Y_OFFSET = -(typography.caption.lineHeight + 4);
    const OUTLINE_MINIMIZED_LABEL_Y_OFFSET = -(16 * 0.5 + 4);
    const MAXIMIZED_LABEL_FONT_SIZE = typography.subtitle1.fontSize;
    const MINIMIZED_LABEL_FONT_SIZE = typography.caption.fontSize;

    const hasActiveOutline = this.state.focused || error;

    let inputTextColor,
      activeColor,
      underlineColor,
      borderColor,
      placeholderColor,
      containerStyle: StyleProp<ViewStyle>,
      backgroundColor,
      inputStyle: StyleProp<TextStyle>;

    inputTextColor = colors.strong;
    if (disabled) {
      activeColor = colors.light;
      placeholderColor = colors.light;
      borderColor = "transparent";
      underlineColor = "transparent";
      backgroundColor = colors.divider;
    } else {
      activeColor = error ? colors.error : colors.primary;
      placeholderColor = borderColor = colors.light;
      underlineColor = underlineColorProp;
      backgroundColor = colors.background;
    }

    if (rest.placeholderTextColor) {
      placeholderColor = rest.placeholderTextColor;
    }

    const { lineHeight, ...subtitle1 } = typography.subtitle1;

    inputStyle = {
      paddingVertical: 0,
      color: inputTextColor,
      paddingLeft:
        leftIconName && leftIconMode === "inset"
          ? ICON_SIZE + 12 + (type === "solid" ? 16 : 0)
          : 0,
      paddingRight: rightIconName ? ICON_SIZE + 16 + 4 : 12,
      ...subtitle1,
    };

    if (!multiline) {
      inputStyle.height = lineHeight;
    }

    let assistiveTextLeftMargin;
    if (type === "underline") {
      containerStyle = {
        borderTopLeftRadius: roundness,
        borderTopRightRadius: roundness,
        paddingBottom: 12,
        marginTop: 16,
      };

      if (leftIconName && leftIconMode === "outset") {
        assistiveTextLeftMargin = ICON_SIZE + 8;
      } else {
        assistiveTextLeftMargin = 0;
      }
    } else {
      containerStyle = {
        borderRadius: roundness,
        borderColor: hasActiveOutline ? activeColor : borderColor,
        borderWidth: 1,
        paddingTop: label ? 16 * 1.5 : 16,
        paddingBottom: label ? 16 * 0.5 : 16,
        opacity: disabled ? disabledOpacity : 1,
        backgroundColor,
      };

      if (leftIconName && leftIconMode === "inset") {
        assistiveTextLeftMargin = 16 + 4;
      } else if (leftIconName && leftIconMode === "outset") {
        assistiveTextLeftMargin = ICON_SIZE + 8 + 12;
      } else {
        assistiveTextLeftMargin = 12;
      }

      inputStyle.paddingHorizontal = 12;
    }

    if (leftIconName && leftIconMode === "outset") {
      containerStyle.marginLeft = ICON_SIZE + 8;
    }

    let leftIconColor;
    if (error) {
      leftIconColor = colors.error;
    } else if (this.state.focused) {
      leftIconColor = colors.primary;
    } else {
      leftIconColor = colors.light;
    }

    const leftIconProps = {
      size: 24,
      color: leftIconColor,
      name: leftIconName || "",
    };

    const leftIconStyle: ImageStyle = {
      position: "absolute",
      marginTop:
        type === "solid"
          ? MINIMIZED_LABEL_FONT_SIZE + 4
          : leftIconMode === "outset"
          ? 16
          : 0,
      marginLeft: leftIconMode === "inset" && type === "solid" ? 16 : 0,
    };

    const labelStyle = {
      ...typography.subtitle1,
      top: type === "solid" ? 16 : 0,
      left:
        leftIconName && leftIconMode === "inset"
          ? ICON_SIZE + (type === "solid" ? 16 : 12)
          : 0,
      transform: [
        {
          // Move label to top
          translateY: this.state.labeled.interpolate({
            inputRange: [0, 1],
            outputRange: [
              type === "solid"
                ? OUTLINE_MINIMIZED_LABEL_Y_OFFSET
                : MINIMIZED_LABEL_Y_OFFSET,
              0,
            ],
          }),
        },
        {
          // Make label smaller
          scale: this.state.labeled.interpolate({
            inputRange: [0, 1],
            outputRange: [
              MINIMIZED_LABEL_FONT_SIZE / MAXIMIZED_LABEL_FONT_SIZE,
              1,
            ],
          }),
        },
        {
          // Offset label scale since RN doesn't support transform origin
          translateX: this.state.labeled.interpolate({
            inputRange: [0, 1],
            outputRange: [
              -(1 - MINIMIZED_LABEL_FONT_SIZE / MAXIMIZED_LABEL_FONT_SIZE) *
                (this.state.labelLayout.width / 2),
              0,
            ],
          }),
        },
      ],
    };

    const { textStyles } = extractStyles(style);
    const inputStyles = applyStyles(
      [
        styles.input,
        inputStyle,
        type === "solid" ? { marginHorizontal: 12 } : {},
      ],
      textStyles
    );

    const {
      backgroundColor: bgColor,
      padding,
      paddingTop,
      paddingBottom,
      paddingLeft,
      paddingRight,
      borderRadius,
      borderWidth,
      borderTopWidth,
      borderRightWidth,
      borderBottomWidth,
      borderLeftWidth,
      borderColor: borderCol,
      ...styleProp
    } = StyleSheet.flatten(style || {}) as ViewStyle & { height?: number };

    return (
      <View style={[styles.container, styleProp]}>
        {leftIconName && leftIconMode === "outset" ? (
          <Icon {...leftIconProps} style={leftIconStyle} />
        ) : null}
        <View
          style={applyStyles([containerStyle], {
            height: style?.height,
            backgroundColor: bgColor,
            padding,
            paddingTop,
            paddingBottom,
            paddingLeft,
            paddingRight,
            borderRadius,
            borderWidth,
            borderTopWidth,
            borderRightWidth,
            borderBottomWidth,
            borderLeftWidth,
            borderColor: borderCol,
          })}
        >
          {type === "underline" ? (
            // When type === 'flat', render an underline
            <Animated.View
              style={[
                styles.underline,
                {
                  backgroundColor:
                    bgColor ||
                    (error
                      ? colors.error
                      : this.state.focused
                      ? activeColor
                      : underlineColor),
                  // Underlines is thinner when input is not focused
                  transform: [{ scaleY: this.state.focused ? 1 : 0.5 }],
                },
              ]}
            />
          ) : null}

          {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
            <View
              pointerEvents="none"
              style={[
                StyleSheet.absoluteFill,
                {
                  opacity:
                    // Hide the label in minimized state until we measure its width
                    this.state.value || this.state.focused
                      ? this.state.labelLayout.measured
                        ? 1
                        : 0
                      : 1,
                },
              ]}
            >
              <AnimatedText
                onLayout={(e: LayoutChangeEvent) =>
                  this.setState({
                    labelLayout: {
                      width: e.nativeEvent.layout.width,
                      measured: true,
                    },
                  })
                }
                style={[
                  styles.placeholder,
                  type === "solid" ? { paddingHorizontal: 12 } : {},
                  labelStyle,
                  {
                    color: placeholderColor,
                    opacity: this.state.labeled.interpolate({
                      inputRange: [0, 1],
                      outputRange: [hasActiveOutline ? 1 : 0, 0],
                    }),
                  },
                ]}
                numberOfLines={1}
              >
                {label}
              </AnimatedText>
              <AnimatedText
                style={[
                  styles.placeholder,
                  type === "solid" ? { paddingHorizontal: 12 } : {},
                  labelStyle,
                  {
                    color: placeholderColor,
                    opacity: hasActiveOutline ? this.state.labeled : 1,
                  },
                ]}
                numberOfLines={1}
              >
                {label}
              </AnimatedText>
            </View>
          ) : null}

          {leftIconName && leftIconMode === "inset" ? (
            <View
              style={{
                justifyContent: type === "solid" ? "center" : undefined,
              }}
            >
              <Icon {...leftIconProps} style={leftIconStyle} />
            </View>
          ) : null}

          {render({
            ref: (c: NativeTextInput) => {
              this._root = c;
            },
            onChange: this._handleChangeText,
            placeholder: label
              ? this.state.placeholder
              : this.props.placeholder,
            placeholderTextColor: placeholderColor,
            editable: !disabled,
            selectionColor: activeColor,
            multiline,
            numberOfLines,
            onFocus: this._handleFocus,
            onBlur: this._handleBlur,
            underlineColorAndroid: "transparent",
            style: inputStyles,
            ...rest,
            value: this.state.value,
          })}
        </View>
        {rightIconName ? (
          <Icon
            name={rightIconName}
            size={ICON_SIZE}
            color={colors.light}
            style={{
              position: "absolute",
              right: 16,
              marginTop: type === "solid" ? MINIMIZED_LABEL_FONT_SIZE + 4 : 16,
            }}
          />
        ) : null}

        {assistiveText ? (
          <Text
            style={[
              {
                color: error ? colors.error : colors.light,
                marginTop: 8,
                marginLeft: assistiveTextLeftMargin,
              },
            ]}
          >
            {assistiveText}
          </Text>
        ) : null}
      </View>
    );
  }