// HOC to add a paste button to a text input import Clipboard from '@react-native-clipboard/clipboard' import * as React from 'react' import { AppState, NativeEventSubscription, ViewProps } from 'react-native' import { deviceIsIos14OrNewer } from 'src/utils/IosVersionUtils' import Logger from 'src/utils/Logger' const TAG = 'WithPasteAware' interface PasteAwareProps { value: string shouldShowClipboard: (value: string) => boolean onChangeText: (text: string) => void leftIcon?: React.ReactNode } export interface PasteAwareWrappedElementProps { isPasteIconVisible: boolean onPressPaste: () => void onChangeText: (text: string) => void clipboardContent: string | null leftIcon?: React.ReactNode } interface PasteAwareState { isPasteIconVisible: boolean clipboardContent: string | null } export function withPasteAware
( WrappedView: React.ComponentType
) { return class WithPasteAware extends React.Component
{
state: PasteAwareState = {
isPasteIconVisible: false,
clipboardContent: null,
}
_interval?: number
_isMounted = false
_appStateListener: NativeEventSubscription | null = null
async componentDidMount() {
this._isMounted = true
this._appStateListener = AppState.addEventListener('change', this.checkClipboardContents)
// TODO: make it work for iOS 14
// https://9to5mac.com/2020/06/24/ios-14-clipboard-notifications/
this._interval = window.setInterval(async () => {
await this.checkClipboardContents()
}, 1000) // Every 1s
await this.checkClipboardContents()
}
componentWillUnmount() {
this._isMounted = false
this._appStateListener?.remove()
clearInterval(this._interval)
}
checkClipboardContents = async () => {
try {
if (!this._isMounted) {
return
}
if (deviceIsIos14OrNewer()) {
const clipboardHasContent = await Clipboard.hasString()
this.setState({ isPasteIconVisible: clipboardHasContent, clipboardContent: null })
return
}
const clipboardContent = await Clipboard.getString()
const { shouldShowClipboard, value } = this.props
if (
clipboardContent &&
!(value && clipboardContent.toLowerCase().includes(value.toLowerCase())) &&
shouldShowClipboard(clipboardContent)
) {
this.setState({ isPasteIconVisible: true, clipboardContent })
} else {
this.setState({ isPasteIconVisible: false, clipboardContent: null })
}
} catch (error) {
Logger.warn(TAG, 'Error checking clipboard contents', error)
}
}
onPressPaste = async () => {
const { clipboardContent: storedClipboardContent } = this.state
const clipboardContent = storedClipboardContent || (await Clipboard.getString())
if (!clipboardContent) {
Logger.warn(TAG, 'Attempted to paste but clipboard content empty. Should never happen.')
return
}
this.setState({ isPasteIconVisible: false, clipboardContent: null })
this.props.onChangeText(clipboardContent)
}
render() {
const { isPasteIconVisible } = this.state
return (