Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Paste, Copy, Cut events in TextInput #18926

Closed
3 tasks done
pronebird opened this issue Apr 18, 2018 · 34 comments
Closed
3 tasks done

Add support for Paste, Copy, Cut events in TextInput #18926

pronebird opened this issue Apr 18, 2018 · 34 comments
Labels
Bug Component: TextInput Related to the TextInput component. Stale There has been a lack of activity on this issue and it may be closed soon. Type: Enhancement A new feature or enhancement of an existing feature.

Comments

@pronebird
Copy link

pronebird commented Apr 18, 2018

TextInput does not support Paste, Copy, Cut events, but it should.

Environment

Environment:
OS: macOS High Sierra 10.13.4
Node: 8.10.0
Yarn: 1.5.1
npm: 5.6.0
Watchman: Not Found
Xcode: Xcode 9.3 Build version 9E145
Android Studio: Not Found

Packages: (wanted => installed)
react: ^16.0.0 => 16.2.0
react-native: ^0.53.3 => 0.53.3

Steps to Reproduce

Not applicable.

Expected Behavior

Not applicable.

Actual Behavior

Not applicable.

@react-native-bot

This comment has been minimized.

@react-native-bot

This comment has been minimized.

1 similar comment
@react-native-bot

This comment has been minimized.

@react-native-bot

This comment has been minimized.

@pronebird

This comment has been minimized.

@n0213004
Copy link

I'm having the same problem. My users are complaining about not being able to use their password managers to paste passwords into TextInput. I haven't been able to find an elegant way around this.

I have found that the pasting limitation seems to be a Rich Text vs. Plain Text scenario. These steps will result in a failed paste:

  1. Open the Notes app on your iPhone
  2. Type and then copy some text
  3. Paste this into your TextInput

While I've found that these steps will result in a successful paste

  1. Open Safari
  2. Navigate to any website
  3. Select and copy the website URL
  4. Paste this into your TextInput

Hopefully this can be address in an upcoming release.

Environment:
OS: macOS High Sierra 10.13.5
Node: 8.2.1
Yarn: 1.7.0
npm: 6.1.0
Watchman: 4.7.0
Xcode: Xcode 9.4.1 Build version 9F2000
Android Studio: 3.1 AI-173.4819257

Packages: (wanted => installed)
react: 16.0.0 => 16.0.0
react-native: 0.50.4 => 0.50.4

@markmckimlit
Copy link

Hi, I'm also impacted by this. Getting a lot of negative App Store reviews by customers unable to use LastPass and OnePassword with our app.

@harryhiggins
Copy link

I'm hitting this issue as well. This is a pretty popular method of entering passwords, would love RN support.

@trinhdan5555
Copy link

I am having the same problem as well. It it very frustrated

@chrismowbraylit
Copy link

Also having this issue

@conor-lit
Copy link

Customers reporting the same issue.

@christophermark
Copy link

Copy/Paste/Select in TextInputs works, but seems to be broken when the TextInput is in a particular UI: #9958

@njho
Copy link

njho commented Aug 11, 2018

Seems like Paste functionality works on android, and iPhone 8. In particular, doesnt seem to be working on iPhone X for myself.

Haven't tested extensively across multiple devices.

@memken
Copy link

memken commented Aug 14, 2018

Handoff issue? Finding that having Handoff activated on iPhone/iPad disallows paste within react-native TextInput. We've shown that disabling Handoff on iOS devices then allows paste to work.

(On iOS > Settings > General > Handoff.)

@harryhiggins
Copy link

I tested this again disabling Handoff on iPhone X (iOS 12 beta) and the problem still exists.

@memken
Copy link

memken commented Aug 15, 2018

@harryhiggins . Thanks for testing that out! I forgot to mention that sometimes it requires a restart of the iPhone/iPad for it to work as well. It's very flaky, sometimes it works, sometimes not. We've also found that turning off App Refresh and restarting phone will allow it to work as well. Here are a couple of articles which speak to both these issues:

https://www.osxiosexpert.com/universal-clipboard-not-working-here-is-how-to-fix-it/
https://discussions.apple.com/thread/8091217

Hard to know what may be going on here. Is it a react-native issue or iOS (both)?

@nmhoan76
Copy link

have any some update?

@larstadema
Copy link

Encountered this issue as well.

We use expo, so react-native version is slightly out of date:

Environment:
  OS: macOS High Sierra 10.13.4
  Node: 8.12.0
  Yarn: 1.12.3
  npm: 6.4.1
  Watchman: 4.9.0
  Xcode: Xcode 9.4 Build version 9F1027a
  Android Studio: 3.1 AI-173.4720617

Packages: (wanted => installed)
  react: 16.3.1 => 16.3.1
  react-native: https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz => 0.55.4

Seems to happen when a <TextInput /> is inside a <KeyboardAvoidingView />, like #9958 described.

For us what fixed it (removed noise, only the relevant changes):

import React, { Component } from 'react';
import { TextInput as NativeTextInput } from 'react-native';

class TextInput extends Component {
  state = {
     inputWidth: '99%'
  }

  componentDidMount() {
    setTimeout(() => this.setState({ inputWidth: 'auto' }), 100);
  }

  render() {
    const { inputWidth } = this.state;

    return <NativeTextInput style={{ width: inputWidth }} />
 }
}

@devpascoe
Copy link

hmmm appreciate the idea @larstadema however when i create my own TextInput component using your code and use it instead of the RN one i get this error "Warning: Can't call setState (or forceUpdate) on an unmounted component."
Likely to do with the setTimeout.

Back to the drawing board.

@devpascoe
Copy link

I'm back from the drawing board :)
setting an isMounted var worked well. I did also have to change TextInput as NativeTextInput back to TextInput and rename the component something like SafeTextInput to avoid naming conflict. So far so good.

componentDidMount() {
this._isMounted = true
setTimeout(() => {
if (this._isMounted) {
this.setState({ inputWidth: 'auto' })
}
}, 100)
}

componentWillUnmount() {
this._isMounted = false
}

@devpascoe
Copy link

and for fun i'll share my render. I'm using lodash for its cloneDeep method. Its probably an expensive render method but it gets the job done passing in all props from the component above it.

render() {
const { inputWidth } = this.state
const combinedStyle = _.cloneDeep(StyleSheet.flatten(this.props.style ? this.props.style : {}))
combinedStyle['width'] = inputWidth
const remainingProps = _.cloneDeep(this.props)
remainingProps['style'] = combinedStyle
return <TextInput {...remainingProps} />
}

@devpascoe
Copy link

devpascoe commented Dec 13, 2018

better yet make the width change on demand, i intercept and pass along the onFocus event which is less taxing than a setTimeout (especially since i load a bunch of them in a list eg, list of posts with comment boxes) ...

import React, { Component } from 'react'
import { TextInput, StyleSheet } from 'react-native'
import _ from 'lodash'

class SafeTextInput extends Component {
  state = {
    inputWidth: '99%'
  }

  render() {
    const { inputWidth } = this.state
    const combinedStyle = _.cloneDeep(StyleSheet.flatten(this.props.style ? this.props.style : {}))
    combinedStyle['width'] = inputWidth
    const remainingProps = _.cloneDeep(this.props)
    remainingProps['style'] = combinedStyle
    return <TextInput {...remainingProps} onFocus={this.onTextFocus} />
  }

  onTextFocus = () => {
    this.setState({ inputWidth: 'auto' })
    if (this.props.onFocus) {
      this.props.onFocus()
    }
  }
}

export default SafeTextInput

@hramos
Copy link
Contributor

hramos commented Jan 30, 2019

What's the latest minimal reproduction for this? From a quick read, it looks like TextInput does support copy/paste. There's two problems reported so far in this thread: Handoff may be affecting paste functionality, and using TextInput inside a KeyboardAvoidingView might also interfere.

If we can change this issue from a "feature request" (i.e. add support for copy/paste functionality) to a "bug report" (i.e. the functionality already exists, but it fails in X or Y scenario), it might improve its chances of getting fixed.

@hramos hramos removed the Bug Report label Feb 6, 2019
@hramos hramos added Type: Enhancement A new feature or enhancement of an existing feature. and removed Type: Feature Request labels Mar 14, 2019
@nosphera
Copy link

nosphera commented May 8, 2019

I solved this by adding the property "removeClippedSubviews={false}" to my ScrollView and encapsulating the content inside a KeyboardAvoidingView.

 <ScrollView
    contentContainerStyle={Styles.contentContainerStyle}
    keyboardShouldPersistTaps="handled"
    removeClippedSubviews={false}
 >

     <KeyboardAvoidingView>

          <Text style={Styles.labelPageTitle}>
            {'bla bla bla'}
          </Text>
          <Text>
              {'bla bla bla'}
          </Text>
          <TextInput
            onChangeText={text => this.setState({ title: text })}
            style={Styles.textInput}
            value={title}
          />

    </KeyboardAvoidingView>

</ScrollView>

@owinter86
Copy link

@hramos I have been able to reproduce this into a simple example, as per below. Copy paste will break on android if a parent view has removeClippedSubviews enabled, and the textInput is wrapped in a view with certain styles. See below.

function Input() {
  return (
    <View
      // This breaks copy/paste on android with certain styles
      removeClippedSubviews={true}
      style={{
        flex: 1,
        justifyContent: "center",
        padding: 40,
        backgroundColor: "gray"
      }}
    >
      <View style={{ elevation: 1 }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View style={{ borderWidth: 1 }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View style={{ backgroundColor: "white" }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View>
        <TextInput placeholder="Can Copy/Paste" style={{ backgroundColor: "white" }} />
      </View>

      <TextInput placeholder="Can Copy/Paste" style={{ backgroundColor: "white" }} />
    </View>
  );
}

I think more people will have this issue as I believe createBottomTabNavigator from react-navigation uses removeClippedSubviews for performance improvements. I can replicate the same issue by removing the removeClippedSubviews prop from the parent view, but then wrapping it in the createBottomTabNavigator, as per below.

function Input() {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        padding: 40,
        backgroundColor: "gray"
      }}
    >
      <View style={{ elevation: 1 }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View style={{ borderWidth: 1 }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View style={{ backgroundColor: "white" }}>
        <TextInput placeholder="broken copy/paste" style={{ backgroundColor: "white" }} />
      </View>

      <View>
        <TextInput placeholder="Can Copy/Paste" style={{ backgroundColor: "white" }} />
      </View>

      <TextInput placeholder="Can Copy/Paste" style={{ backgroundColor: "white" }} />
    </View>
  );
}

const Navigator = createBottomTabNavigator({
  Input
});

const Navigation = createAppContainer(Navigator);

export default Navigation;

@vgm8
Copy link

vgm8 commented Jun 17, 2019

Something weird is happening to me. When I click for the first time in an empty input, it doesn't show the paste option. Once I write something in the input and delete it the paste option shows correctly. I don't know why I can not paste in an empty input. I've tried not using scroll, use removeClippedSubviews prop... but nothing is working. Any help? Thanks.

@AzizStark
Copy link

AzizStark commented Jun 20, 2019

I was using createMaterialBottomNavigator from react-navigator which caused this issue for me.

I spent to whole night trying to fix this. The problem is the removeClippedSubviews is set as true. After setting it to false the clipboard appeared.
react-navigation uses react-native-paper which is also has this setting that prevents the clipboard options from appearing.

I solved this by setting it to false in five files.

Path to files:

  1. \..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js

  2. \..\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js

  3. \..\node_modules\react-navigation-drawer\dist\view\ResourceSavingScene.js

  4. \..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\dist\views\ResourceSavingScene.js

  5. \..\node_modules\react-native-paper\src\components\BottomNavigation.js

--

removeClippedSubviews={
                 // On iOS, set removeClippedSubviews to true only when not focused
                 // This is an workaround for a bug where the clipped view never re-appears
                 Platform.OS === 'ios' ? navigationState.index !== index : true  //<--  set this to false
               }

@helenzhou6
Copy link

helenzhou6 commented Jun 24, 2019

I've encountered a similar problem, where adding removeClippedSubviews seems to break copying/pasting into an input on Android:

Link to Snack here

Code:

import * as React from 'react';
import { Text, View, StyleSheet, TextInput, KeyboardAvoidingView } from 'react-native';
import Constants from 'expo-constants';

function Input() {
  return (
    <KeyboardAvoidingView>
      <Text selectable>To replicate - copy this text</Text>
      <View
        // removeClippedSubviews breaks copy/paste on android
        removeClippedSubviews={true}
        style={{
          backgroundColor: "lightgray"
        }}
      >
        <Text>Broken Inputs </Text>

        <View style={{ elevation: 1 }} removeClippedSubviews={false}>
          <TextInput
            placeholder="broken copy/paste"
            style={{ backgroundColor: "white" }}
          />
        </View>

        <View style={{ borderWidth: 1 }}>
          <TextInput
            placeholder="broken copy/paste"
            style={{ backgroundColor: "white" }}
          />
        </View>

        <View style={{ backgroundColor: "white" }}>
          <TextInput
            placeholder="broken copy/paste"
            style={{ backgroundColor: "white" }}
          />
        </View>

        <TextInput
          placeholder="broken copy/paste"
          style={{ backgroundColor: "lightblue" }}
        />
      </View>

      <View>
        <Text>Working Inputs </Text>

        <View>
          <TextInput
            placeholder="Can Copy/Paste"
            style={{ backgroundColor: "white" }}
          />
        </View>

        <View style={{ backgroundColor: "lightblue" }}>
          <TextInput placeholder="Can Copy/Paste" />
        </View>

        <TextInput
          placeholder="Can Copy/Paste"
          style={{ backgroundColor: "white" }}
        />
      </View>
    </KeyboardAvoidingView>
  );
}

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Input />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    paddingTop: Constants.statusBarHeight,
    backgroundColor: 'lightgrey',
    padding: 8,
  },
});

@blastering66
Copy link

This Simple Hack Saves me.

#9958 (comment)

Basicly just put width dynamicly, do some delay and update state for its width to 100%

@vorasudh
Copy link

vorasudh commented Sep 4, 2019

I have a different scenario. Paste option works just fine for iOS, but has weird issue on Android:

My TextInput is enclosed in a View. If I try to directly paste something there, it does not show paste option. But if I type atleast one letter and remove it and then try to paste something, it works.

@annieneedscoffee
Copy link

annieneedscoffee commented Oct 11, 2019

I was using createMaterialBottomNavigator from react-navigator which caused this issue for me.

I spent to whole night trying to fix this. The problem is the removeClippedSubviews is set as true. After setting it to false the clipboard appeared.
react-navigation uses react-native-paper which is also has this setting that prevents the clipboard options from appearing.

I solved this by setting it to false in five files.

Path to files:

  1. ..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js
  2. ..\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js
  3. ..\node_modules\react-navigation-drawer\dist\view\ResourceSavingScene.js
  4. ..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\dist\views\ResourceSavingScene.js
  5. ..\node_modules\react-native-paper\src\components\BottomNavigation.js

--

removeClippedSubviews={
                 // On iOS, set removeClippedSubviews to true only when not focused
                 // This is an workaround for a bug where the clipped view never re-appears
                 Platform.OS === 'ios' ? navigationState.index !== index : true  //<--  set this to false
               }

Thank you @AzizStark your answer is what worked for me. Nothing else I tried worked because react-navigation kept on overriding everything else I tried. I'm using Platform.OS === 'ios' ? !isVisible : undefined instead of Platform.OS === 'ios' ? !isVisible : false because both true and false override certain behaviors I want on certain screens. Writing in undefined just prevents there error I get if I leave that space blank.

@AzizStark
Copy link

I was using createMaterialBottomNavigator from react-navigator which caused this issue for me.
I spent to whole night trying to fix this. The problem is the removeClippedSubviews is set as true. After setting it to false the clipboard appeared.
react-navigation uses react-native-paper which is also has this setting that prevents the clipboard options from appearing.
I solved this by setting it to false in five files.
Path to files:

  1. ..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js
  2. ..\node_modules\react-navigation-tabs\src\views\ResourceSavingScene.js
  3. ..\node_modules\react-navigation-drawer\dist\view\ResourceSavingScene.js
  4. ..\node_modules\react-navigation-material-bottom-tabs\node_modules\react-navigation-tabs\dist\views\ResourceSavingScene.js
  5. ..\node_modules\react-native-paper\src\components\BottomNavigation.js

--

removeClippedSubviews={
                 // On iOS, set removeClippedSubviews to true only when not focused
                 // This is an workaround for a bug where the clipped view never re-appears
                 Platform.OS === 'ios' ? navigationState.index !== index : true  //<--  set this to false
               }

Thank you @AzizStark your answer is what worked for me. Nothing else I tried worked because react-navigation kept on overriding everything else I tried. I'm using Platform.OS === 'ios' ? !isVisible : undefined instead of Platform.OS === 'ios' ? !isVisible : false because both true and false override certain behaviors I want on certain screens. Writing in undefined just prevents there error I get if I leave that space blank.

I am glad, It helped!

@stale
Copy link

stale bot commented Jan 13, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 13, 2020
@stale
Copy link

stale bot commented Jan 20, 2020

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

@stale stale bot closed this as completed Jan 20, 2020
@facebook facebook locked as resolved and limited conversation to collaborators Jan 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Component: TextInput Related to the TextInput component. Stale There has been a lack of activity on this issue and it may be closed soon. Type: Enhancement A new feature or enhancement of an existing feature.
Projects
None yet
Development

No branches or pull requests