Skip to content

Commit d3d71ac

Browse files
Gudahttph-fritsche
andauthored
fix(clipboard): prevent default behavior on paste (#862)
Co-authored-by: Philipp Fritsche <[email protected]>
1 parent 7171c9d commit d3d71ac

File tree

4 files changed

+36
-10
lines changed

4 files changed

+36
-10
lines changed

src/clipboard/paste.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import {Config, Instance} from '../setup'
2-
import {
3-
createDataTransfer,
4-
isEditable,
5-
readDataTransferFromClipboard,
6-
input,
7-
} from '../utils'
2+
import {createDataTransfer, readDataTransferFromClipboard} from '../utils'
83

94
export async function paste(
105
this: Instance,
@@ -26,10 +21,6 @@ export async function paste(
2621
this.dispatchUIEvent(target, 'paste', {
2722
clipboardData: dataTransfer,
2823
})
29-
30-
if (isEditable(target)) {
31-
input(this[Config], target, dataTransfer.getData('text'), 'insertFromPaste')
32-
}
3324
}
3425

3526
function getClipboardDataFromString(text: string) {

src/event/behavior/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import './click'
22
import './keydown'
33
import './keypress'
44
import './keyup'
5+
import './paste'
56

67
export {behavior} from './registry'
78
export type {BehaviorPlugin} from './registry'

src/event/behavior/paste.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {input, isEditable} from '../../utils'
2+
import {behavior} from './registry'
3+
4+
behavior.paste = (event, target, config) => {
5+
if (isEditable(target)) {
6+
return () => {
7+
const insertData = event.clipboardData?.getData('text')
8+
if (insertData) {
9+
input(config, target, insertData, 'insertFromPaste')
10+
}
11+
}
12+
}
13+
}

tests/clipboard/paste.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import userEvent from '#src'
22
import {render, setup} from '#testHelpers'
3+
import {createDataTransfer} from '#src/utils'
34

45
test('paste with empty clipboard', async () => {
56
const {element, getEvents, user} = setup(`<input/>`)
@@ -11,6 +12,17 @@ test('paste with empty clipboard', async () => {
1112
expect(getEvents('input')).toHaveLength(0)
1213
})
1314

15+
test('do not trigger input for paste with file data', async () => {
16+
const {getEvents, user} = setup(`<input/>`)
17+
18+
const f0 = new File(['bar'], 'bar0.txt', {type: 'text/plain'})
19+
const dt = createDataTransfer([f0])
20+
await user.paste(dt)
21+
22+
expect(getEvents('paste')).toHaveLength(1)
23+
expect(getEvents('input')).toHaveLength(0)
24+
})
25+
1426
test.each([
1527
[
1628
`<input/>`,
@@ -65,6 +77,15 @@ test('does not paste when disabled', async () => {
6577
)
6678
})
6779

80+
test('prevent input per paste event handler', async () => {
81+
const {element, eventWasFired, user} = setup(`<input />`)
82+
element.addEventListener('paste', e => e.preventDefault())
83+
84+
await user.paste('hi')
85+
expect(eventWasFired('paste')).toBe(true)
86+
expect(eventWasFired('input')).toBe(false)
87+
})
88+
6889
test.each(['input', 'textarea'])(
6990
'should paste text in <%s> up to maxLength if provided',
7091
async type => {

0 commit comments

Comments
 (0)