The idea is to create an element in react, which can be clicked or longClicked (long touch). onClick should open the link directly, longClick should copy the link to clipboard (after 2 seconds pressing the button).
Both functions work very well for there own. But if I combine them to one, the browser said the execCommand was ignored, because it was not part of a direct user interaction. Well, that means 2 seconds are to long to trigger this command.
I tested it and in Firefox 59 the treshhold is ca. 0.5 seconds and in Chrome 65 it is 1 second.
If you trigger a function after this time it is no direct user interaction anymore.
So if I set time={0.4}
seconds, like in the following code, it works:
import { ListItem, ListItemText } from 'material-ui/List'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { withStyles } from 'material-ui/styles'
import { withRouter } from 'react-router-dom'
import ClickNHold from 'react-click-n-hold';
const styles = {
card: {
borderBottom: '1px solid rgba(0, 0, 0, 0.12)',
'&:last-of-type': { borderBottom: 'none' }
},
title: {
marginBottom: 16,
fontSize: 14
},
itemText: { fontSize: '0.8em' }
}
class GroupCard extends Component {
openGroup = () => {
this.props.history.push(`/groups/${this.props.link}`)
}
copyToClipboard = () => {
const uri = 'https://example.com/api/',
textField = document.createElement('textarea')
textField.innerText = `${uri}groups/${this.props.link}`
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
touchEnd = (e, enough) => {
enough ? null : this.openGroup()
}
render() {
const { classes, name, link } = this.props,
uri = 'https://example.com/api/'
return (
<ClickNHold time={0.4}
onClickNHold={this.copyToClipboard}
onEnd={this.touchEnd}>
<ListItem button className={classes.card} >
<ListItemText
primary={name ? name : 'unknown'}
secondary={<span className={classes.itemText}>{`${uri}groups/${link}`}</span>}
/>
</ListItem>
</ClickNHold>
)
}
}
GroupCard.propTypes = { classes: PropTypes.object.isRequired }
export default withRouter(withStyles(styles)(GroupCard))
But the code doesn't work with time={2}
seconds. So the only Problem here is the time element. Is there an other solution to copy text to clipboard or to avoid the broser default times for direct user interaction?
Or is that simpy not possible in webbased APPs and i have to use something like react-native?
Following the idea of Seth, the link is copied instantly but the info for that is coming after 2 seconds. Seems to be a nice workaround..
class GroupCard extends Component {
openGroup = () => {
this.props.history.push(`/groups/${this.props.link}`)
}
touchStart = () => {
const uri = 'https://example.com/',
textField = document.createElement('textarea')
textField.innerText = `${uri}groups/${this.props.link}`
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
touchEnd = (e, enough) => {
!enough && this.openGroup()
}
render() {
const { classes, name, link } = this.props,
uri = 'https://example.com/'
return (
<ClickNHold time={2}
onStart={this.touchStart}
onClickNHold={console.log('copied')}
onEnd={this.touchEnd}>
<ListItem button className={classes.card} >
<ListItemText
primary={name ? name : 'unknown'}
secondary={<span className={classes.itemText}>{`${uri}groups/${link}`}</span>}
/>
</ListItem>
</ClickNHold>
)
}
}