GeekyAnts / NativeBase

Mobile-first, accessible components for React Native & Web to build consistent UI across Android, iOS and Web.
https://nativebase.io/
MIT License
20.17k stars 2.39k forks source link

react-native-text-input-mask and react-native-masked-text doesn't works with floating label #2670

Closed franciscojfs closed 4 years ago

franciscojfs commented 5 years ago

I have gone through these following points

Issue Description

node, npm, react-native, react and native-base version, expo version if used, xcode version

node: v8.11.3 npm: 6.8.0 react: 16.8.3 react-native: 0.59.4 native-base: ^2.12.1

Expected behaviour

The mask defined should be applied correctly to an item with floating labels

Actual behaviour

The mask defined is not applied to an item with floating labels. I have tried with react-native-text-input-mask and react-native-masked-text

Steps to reproduce

Copy the code referenced as an example to the issue https://github.com/GeekyAnts/NativeBase/issues/2392

import React, { Component } from 'react';
import { Container, Header, Content, Form, Item, Input, Label } from 'native-base';
import { TextInputMask } from 'react-native-masked-text';

export default class TestScreen extends Component {
  constructor(props) {
    super(props)

    this.state = {
      lastName: ''
    }
  }

  onChangeField(field, value) {
    let newState = {}
    newState[field] = value

    this.setState(newState)
  }

  _onLastNameSubmitted() {
    const el = this.refs.dateOfBirthInput.getElement()
    // el.focus()
    el._root.focus()
  }

  render() {
    return (
      <Container>
        <Header />
        <Content>
          <Form>
            <Item>
              <Label>Sobrenome</Label>
              <Input
                value={this.state.lastName}
                ref='lastNameInput'
                autoCapitalize='words'
                returnKeyType='next'
                onSubmitEditing={() => { this._onLastNameSubmitted() }}
                onChangeText={text => this.onChangeField('lastName', text)}
              />
            </Item>
            <Item>
              <Label>Data de Nascimento</Label>
              <TextInputMask
                ref='dateOfBirthInput'
                type='datetime'
                returnKeyType='next'
                options={{
                  format: 'DD/MM/YYYY'
                }}
                customTextInput={Input}
              />
            </Item>                     
          </Form>
        </Content>
      </Container>
    );
  }
}

Change the item containing the label "Data de nacimento" to a floating label


import React, { Component } from 'react';
import { Container, Header, Content, Form, Item, Input, Label } from 'native-base';
import { TextInputMask } from 'react-native-masked-text';

export default class TestScreen extends Component {
  constructor(props) {
    super(props)

    this.state = {
      lastName: ''
    }
  }

  onChangeField(field, value) {
    let newState = {}
    newState[field] = value

    this.setState(newState)
  }

  _onLastNameSubmitted() {
    const el = this.refs.dateOfBirthInput.getElement()
    // el.focus()
    el._root.focus()
  }

  render() {
    return (
      <Container>
        <Header />
        <Content>
          <Form>
            <Item>
              <Label>Sobrenome</Label>
              <Input
                value={this.state.lastName}
                ref='lastNameInput'
                autoCapitalize='words'
                returnKeyType='next'
                onSubmitEditing={() => { this._onLastNameSubmitted() }}
                onChangeText={text => this.onChangeField('lastName', text)}
              />
            </Item>
            <Item floatingLabel>
              <Label>Data de Nascimento</Label>
              <TextInputMask
                ref='dateOfBirthInput'
                type='datetime'
                returnKeyType='next'
                options={{
                  format: 'DD/MM/YYYY'
                }}
                customTextInput={Input}
              />
            </Item>                     
          </Form>
        </Content>
      </Container>
    );
  }
}

Is the bug present in both iOS and Android or in any one of them?

I don't own a Mac to test this

Any other additional info which would help us debug the issue quicker.

N/A

SupriyaKalghatgi commented 5 years ago

Is the bug present in both iOS and Android or in any one of them? I don't own a Mac to test this

If neither iOS nor Android, then on which platform did you find this failing?

franciscojfs commented 5 years ago

Hello!

It was tested only on Android, as I don't own a Mac.

juanlarra1 commented 5 years ago

Can confirm this is happening on Android and iOS

hoangnguyen1247 commented 5 years ago

Any update for this issue? Thanks

pipoblak commented 5 years ago

Waiting a update too :/

pipoblak commented 5 years ago

Apparently the Item with floatingLabel property is using his own Input Component, ignoring any Input Component who you insert.

thalesgs-cit commented 4 years ago

We have same problem, any updates?

juliocr-ciandt commented 4 years ago

Hi guys! any news about that?

williamwa-ciandt commented 4 years ago

Any update for this issue?? Thanks

uladzislau-stuk commented 4 years ago

Waiting updates

robinstraub commented 4 years ago

I am also experiencing the issue.

The https://docs.nativebase.io/Components.html#floating-label-headref states that when using floatingLabelproperty, it "creates an Input component". It overrides the input I pass in as described by @pipoblak.

As a workaround, I use the exposed MaskService service to handle the masking logic, which enables me to use the masking features of this library. However, it would make sense to let us use custom inputs when using floating labels.

If anyone is interesting, here's a quick example using react hooks (same can be done with class components)

import React, {useState} from 'react';
import {Input, Item, Label, Text, View} from 'native-base';
import {MaskService, TextInputMaskOptionProp} from 'react-native-masked-text';

// generates an object containing the input required properties (value and onChange) and handles state
const useInputState = (initialValue?: string) => {
  const [value, onChange] = useState(initialValue);
  return {value, onChange};
};

// converts the value using the mask parameters
const mask = ({value = '', onChange}, type: string, options?: TextInputMaskOptionProp) => ({
  // the value is converted to a mask so it is displayed properly with the <Input /> component
  value: MaskService.toMask(type, value, options),
  // when the value is modified, it is converted back to its raw value
  onChangeText: newValue => onChange(MaskService.toRawValue(type, newValue, options).join('')),
});

const component = () => {
  const input = useInputState();
  const masked = mask(input, 'credit-card');

  return (
    <View>
      <Item floatingLabel>
        <Label>card number</Label>
        <Input maxLength={19} {...masked} keyboardType='number-pad' />
      </Item>
      <Text>Actual value: {input.value}</Text>
    </View>
  );
};

export default component;
berkelmas commented 4 years ago

I am also experiencing the issue.

The https://docs.nativebase.io/Components.html#floating-label-headref states that when using floatingLabelproperty, it "creates an Input component". It overrides the input I pass in as described by @pipoblak.

As a workaround, I use the exposed MaskService service to handle the masking logic, which enables me to use the masking features of this library. However, it would make sense to let us use custom inputs when using floating labels.

If anyone is interesting, here's a quick example using react hooks (same can be done with class components)

import React, {useState} from 'react';
import {Input, Item, Label, Text, View} from 'native-base';
import {MaskService, TextInputMaskOptionProp} from 'react-native-masked-text';

// generates an object containing the input required properties (value and onChange) and handles state
const useInputState = (initialValue?: string) => {
  const [value, onChange] = useState(initialValue);
  return {value, onChange};
};

// converts the value using the mask parameters
const mask = ({value = '', onChange}, type: string, options?: TextInputMaskOptionProp) => ({
  // the value is converted to a mask so it is displayed properly with the <Input /> component
  value: MaskService.toMask(type, value, options),
  // when the value is modified, it is converted back to its raw value
  onChangeText: newValue => onChange(MaskService.toRawValue(type, newValue, options).join('')),
});

const component = () => {
  const input = useInputState();
  const masked = mask(input, 'credit-card');

  return (
    <View>
      <Item floatingLabel>
        <Label>card number</Label>
        <Input maxLength={19} {...masked} keyboardType='number-pad' />
      </Item>
      <Text>Actual value: {input.value}</Text>
    </View>
  );
};

export default component;

It works really well. Thanks for sharing.

Temirtator commented 4 years ago

Im also met this issue, this is really problem

hanykumar commented 4 years ago

Hi @francescopersico , Feature FloatingLabel for item is limited. You can use solution provided by @robinstraub. Closing this for now. Thanks.

import React, {useState} from 'react';
import {Input, Item, Label, Text, View} from 'native-base';
import {MaskService, TextInputMaskOptionProp} from 'react-native-masked-text';

// generates an object containing the input required properties (value and onChange) and handles state
const useInputState = (initialValue?: string) => {
  const [value, onChange] = useState(initialValue);
  return {value, onChange};
};

// converts the value using the mask parameters
const mask = ({value = '', onChange}, type: string, options?: TextInputMaskOptionProp) => ({
  // the value is converted to a mask so it is displayed properly with the <Input /> component
  value: MaskService.toMask(type, value, options),
  // when the value is modified, it is converted back to its raw value
  onChangeText: newValue => onChange(MaskService.toRawValue(type, newValue, options).join('')),
});

const component = () => {
  const input = useInputState();
  const masked = mask(input, 'credit-card');

  return (
    <View>
      <Item floatingLabel>
        <Label>card number</Label>
        <Input maxLength={19} {...masked} keyboardType='number-pad' />
      </Item>
      <Text>Actual value: {input.value}</Text>
    </View>
  );
};

export default component;