@testing-library/user-event
Advanced tools
Comparing version
@@ -37,4 +37,4 @@ 'use strict'; | ||
} | ||
const blured = getActiveTarget(this.ownerDocument); | ||
if (blured === this) { | ||
const blurred = getActiveTarget(this.ownerDocument); | ||
if (blurred === this) { | ||
return; | ||
@@ -44,8 +44,8 @@ } | ||
activeCall = thisCall; | ||
if (blured) { | ||
blur.call(blured); | ||
dispatchEvent.dispatchDOMEvent(blured, 'blur', { | ||
if (blurred) { | ||
blur.call(blurred); | ||
dispatchEvent.dispatchDOMEvent(blurred, 'blur', { | ||
relatedTarget: this | ||
}); | ||
dispatchEvent.dispatchDOMEvent(blured, 'focusout', { | ||
dispatchEvent.dispatchDOMEvent(blurred, 'focusout', { | ||
relatedTarget: activeCall === thisCall ? this : null | ||
@@ -57,3 +57,3 @@ }); | ||
dispatchEvent.dispatchDOMEvent(this, 'focus', { | ||
relatedTarget: blured | ||
relatedTarget: blurred | ||
}); | ||
@@ -63,3 +63,3 @@ } | ||
dispatchEvent.dispatchDOMEvent(this, 'focusin', { | ||
relatedTarget: blured | ||
relatedTarget: blurred | ||
}); | ||
@@ -72,4 +72,4 @@ } | ||
} | ||
const blured = getActiveTarget(this.ownerDocument); | ||
if (blured !== this) { | ||
const blurred = getActiveTarget(this.ownerDocument); | ||
if (blurred !== this) { | ||
return; | ||
@@ -80,6 +80,6 @@ } | ||
blur.call(this); | ||
dispatchEvent.dispatchDOMEvent(blured, 'blur', { | ||
dispatchEvent.dispatchDOMEvent(blurred, 'blur', { | ||
relatedTarget: null | ||
}); | ||
dispatchEvent.dispatchDOMEvent(blured, 'focusout', { | ||
dispatchEvent.dispatchDOMEvent(blurred, 'focusout', { | ||
relatedTarget: null | ||
@@ -86,0 +86,0 @@ }); |
@@ -14,8 +14,8 @@ 'use strict'; | ||
const control = context && isElementType.isElementType(context, 'label') && context.control; | ||
if (control) { | ||
if (control && control !== target) { | ||
return ()=>{ | ||
if (isFocusable.isFocusable(control)) { | ||
focus.focusElement(control); | ||
instance.dispatchEvent(control, cloneEvent.cloneEvent(event)); | ||
} | ||
instance.dispatchEvent(control, cloneEvent.cloneEvent(event)); | ||
}; | ||
@@ -22,0 +22,0 @@ } else if (isElementType.isElementType(target, 'input', { |
@@ -29,3 +29,3 @@ 'use strict'; | ||
})) { | ||
return ()=>radio.walkRadio(instance, target, -1); | ||
return ()=>radio.walkRadio(instance, target, 1); | ||
} | ||
@@ -53,3 +53,3 @@ }, | ||
})) { | ||
return ()=>radio.walkRadio(instance, target, 1); | ||
return ()=>radio.walkRadio(instance, target, -1); | ||
} | ||
@@ -56,0 +56,0 @@ }, |
@@ -22,3 +22,3 @@ 'use strict'; | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initMouseEvent | ||
@@ -28,3 +28,3 @@ ], | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initMouseEvent, | ||
@@ -35,3 +35,3 @@ initPointerEvent | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initKeyboardEvent | ||
@@ -144,3 +144,3 @@ ] | ||
} | ||
function initUIEventModififiers(event, { altKey, ctrlKey, metaKey, shiftKey, modifierAltGraph, modifierCapsLock, modifierFn, modifierFnLock, modifierNumLock, modifierScrollLock, modifierSymbol, modifierSymbolLock }) { | ||
function initUIEventModifiers(event, { altKey, ctrlKey, metaKey, shiftKey, modifierAltGraph, modifierCapsLock, modifierFn, modifierFnLock, modifierNumLock, modifierScrollLock, modifierSymbol, modifierSymbolLock }) { | ||
assignProps(event, { | ||
@@ -199,4 +199,4 @@ altKey: Boolean(altKey), | ||
pointerId: sanitizeNumber(pointerId), | ||
width: sanitizeNumber(width), | ||
height: sanitizeNumber(height), | ||
width: sanitizeNumber(width !== null && width !== undefined ? width : 1), | ||
height: sanitizeNumber(height !== null && height !== undefined ? height : 1), | ||
pressure: sanitizeNumber(pressure), | ||
@@ -203,0 +203,0 @@ tangentialPressure: sanitizeNumber(tangentialPressure), |
@@ -23,2 +23,3 @@ 'use strict'; | ||
instance.dispatchUIEvent(group[i], 'click'); | ||
return; | ||
} | ||
@@ -25,0 +26,0 @@ } |
@@ -8,3 +8,3 @@ 'use strict'; | ||
*/ const defaultKeyMap = [ | ||
// alphanumeric keys | ||
// alphanumeric block - writing system | ||
...'0123456789'.split('').map((c)=>({ | ||
@@ -28,2 +28,20 @@ code: `Digit${c}`, | ||
})), | ||
{ | ||
code: 'BracketLeft', | ||
key: '[' | ||
}, | ||
{ | ||
code: 'BracketLeft', | ||
key: '{', | ||
shiftKey: true | ||
}, | ||
{ | ||
code: 'BracketRight', | ||
key: ']' | ||
}, | ||
{ | ||
code: 'BracketRight', | ||
key: '}', | ||
shiftKey: true | ||
}, | ||
// alphanumeric block - functional | ||
@@ -85,2 +103,6 @@ { | ||
{ | ||
code: 'ContextMenu', | ||
key: 'ContextMenu' | ||
}, | ||
{ | ||
code: 'Tab', | ||
@@ -87,0 +109,0 @@ key: 'Tab' |
@@ -7,3 +7,3 @@ 'use strict'; | ||
/** | ||
* Parse key defintions per `keyboardMap` | ||
* Parse key definitions per `keyboardMap` | ||
* | ||
@@ -10,0 +10,0 @@ * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`. |
@@ -26,4 +26,6 @@ 'use strict'; | ||
async press(instance, keyDef, position) { | ||
this.devices.get(keyDef.pointerType).addPressed(keyDef); | ||
this.buttons.down(keyDef); | ||
const pointerName = this.getPointerName(keyDef); | ||
const pointer = keyDef.pointerType === 'touch' ? this.pointers.new(pointerName, keyDef).init(instance, position) : this.pointers.get(pointerName); | ||
const pointer = keyDef.pointerType === 'touch' ? this.pointers.new(pointerName, keyDef.pointerType, this.buttons) : this.pointers.get(pointerName); | ||
// TODO: deprecate the following implicit setting of position | ||
@@ -34,8 +36,9 @@ pointer.position = position; | ||
} | ||
this.devices.get(keyDef.pointerType).addPressed(keyDef); | ||
this.buttons.down(keyDef); | ||
pointer.down(instance, keyDef); | ||
if (pointer.pointerType !== 'touch' && !pointer.isPrevented) { | ||
this.mouse.down(instance, keyDef, pointer); | ||
if (pointer.pointerType === 'touch') { | ||
pointer.init(instance); | ||
} | ||
pointer.down(instance, keyDef.button); | ||
if (pointer.pointerType !== 'touch') { | ||
this.mouse.down(instance, keyDef, pointer.isPrevented); | ||
} | ||
} | ||
@@ -49,3 +52,3 @@ async move(instance, pointerName, position) { | ||
const pointermove = pointer.move(instance, position); | ||
const mousemove = pointer.pointerType === 'touch' || pointer.isPrevented && pointer.isDown ? undefined : this.mouse.move(instance, position); | ||
const mousemove = pointer.pointerType === 'touch' ? undefined : this.mouse.move(instance, position, pointer.isPrevented); | ||
pointermove === null || pointermove === undefined ? undefined : pointermove.leave(); | ||
@@ -63,2 +66,3 @@ mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
const pointer = this.pointers.get(this.getPointerName(keyDef)); | ||
const isPrevented = pointer.isPrevented; | ||
// TODO: deprecate the following implicit setting of position | ||
@@ -70,3 +74,3 @@ pointer.position = position; | ||
if (device.countPressed === 0) { | ||
pointer.up(instance, keyDef); | ||
pointer.up(instance, keyDef.button); | ||
} | ||
@@ -76,18 +80,16 @@ if (pointer.pointerType === 'touch') { | ||
} | ||
if (!pointer.isPrevented) { | ||
if (pointer.pointerType === 'touch' && !pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, pointer.position); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.down(instance, keyDef, pointer); | ||
} | ||
if (!pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, pointer.position); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.up(instance, keyDef, pointer); | ||
} | ||
if (pointer.pointerType === 'touch' && !pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, position, isPrevented); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.down(instance, keyDef, isPrevented); | ||
} | ||
if (!pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, position, isPrevented); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.up(instance, keyDef, isPrevented); | ||
} | ||
} | ||
@@ -126,7 +128,7 @@ getPointerName(keyDef) { | ||
_define_property(this, "pointers", new class { | ||
new(pointerName, keyDef) { | ||
const isPrimary = keyDef.pointerType !== 'touch' || !Object.values(this.registry).some((p)=>p.pointerType === 'touch' && !p.isCancelled); | ||
new(pointerName, pointerType, buttons) { | ||
const isPrimary = pointerType !== 'touch' || !Object.values(this.registry).some((p)=>p.pointerType === 'touch' && !p.isCancelled); | ||
if (!isPrimary) { | ||
Object.values(this.registry).forEach((p)=>{ | ||
if (p.pointerType === keyDef.pointerType && !p.isCancelled) { | ||
if (p.pointerType === pointerType && !p.isCancelled) { | ||
p.isMultitouch = true; | ||
@@ -138,5 +140,5 @@ } | ||
pointerId: this.nextId++, | ||
pointerType: keyDef.pointerType, | ||
pointerType, | ||
isPrimary | ||
}); | ||
}, buttons); | ||
return this.registry[pointerName]; | ||
@@ -154,10 +156,4 @@ } | ||
constructor(){ | ||
_define_property(this, "registry", { | ||
mouse: new pointer.Pointer({ | ||
pointerId: 1, | ||
pointerType: 'mouse', | ||
isPrimary: true | ||
}) | ||
}); | ||
_define_property(this, "nextId", 2); | ||
_define_property(this, "registry", {}); | ||
_define_property(this, "nextId", 1); | ||
} | ||
@@ -168,2 +164,3 @@ }()); | ||
this.mouse = new mouse.Mouse(); | ||
this.pointers.new('mouse', 'mouse', this.buttons); | ||
} | ||
@@ -170,0 +167,0 @@ } |
@@ -35,3 +35,3 @@ 'use strict'; | ||
*/ class Mouse { | ||
move(instance, position) { | ||
move(instance, position, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const prevPosition = this.position; | ||
@@ -60,2 +60,5 @@ const prevTarget = this.getTarget(instance); | ||
move: ()=>{ | ||
if (isPrevented) { | ||
return; | ||
} | ||
instance.dispatchUIEvent(nextTarget, 'mousemove', init); | ||
@@ -66,3 +69,3 @@ this.modifySelecting(instance); | ||
} | ||
down(instance, keyDef, pointer) { | ||
down(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const button = this.buttons.down(keyDef); | ||
@@ -74,5 +77,5 @@ if (button === undefined) { | ||
this.buttonDownTarget[button] = target; | ||
const init = this.getEventInit('mousedown', keyDef.button); | ||
const disabled = isDisabled.isDisabled(target); | ||
const init = this.getEventInit('mousedown', keyDef.button); | ||
if (disabled || instance.dispatchUIEvent(target, 'mousedown', init)) { | ||
if (!isPrevented && (disabled || instance.dispatchUIEvent(target, 'mousedown', init))) { | ||
this.startSelecting(instance, init.detail); | ||
@@ -82,6 +85,6 @@ focus.focusElement(target); | ||
if (!disabled && buttons.getMouseEventButton(keyDef.button) === 2) { | ||
instance.dispatchUIEvent(target, 'contextmenu', this.getEventInit('contextmenu', keyDef.button, pointer)); | ||
instance.dispatchUIEvent(target, 'contextmenu', this.getEventInit('contextmenu', keyDef.button)); | ||
} | ||
} | ||
up(instance, keyDef, pointer) { | ||
up(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const button = this.buttons.up(keyDef); | ||
@@ -93,7 +96,10 @@ if (button === undefined) { | ||
if (!isDisabled.isDisabled(target)) { | ||
instance.dispatchUIEvent(target, 'mouseup', this.getEventInit('mouseup', keyDef.button)); | ||
this.endSelecting(); | ||
if (!isPrevented) { | ||
const mouseUpInit = this.getEventInit('mouseup', keyDef.button); | ||
instance.dispatchUIEvent(target, 'mouseup', mouseUpInit); | ||
this.endSelecting(); | ||
} | ||
const clickTarget = getTreeDiff.getTreeDiff(this.buttonDownTarget[button], target)[2][0]; | ||
if (clickTarget) { | ||
const init = this.getEventInit('click', keyDef.button, pointer); | ||
const init = this.getEventInit('click', keyDef.button); | ||
if (init.detail) { | ||
@@ -114,11 +120,6 @@ instance.dispatchUIEvent(clickTarget, init.button === 0 ? 'click' : 'auxclick', init); | ||
} | ||
getEventInit(type, button, pointer) { | ||
getEventInit(type, button) { | ||
const init = { | ||
...this.position.coords | ||
}; | ||
if (pointer) { | ||
init.pointerId = pointer.pointerId; | ||
init.pointerType = pointer.pointerType; | ||
init.isPrimary = pointer.isPrimary; | ||
} | ||
init.button = buttons.getMouseEventButton(button); | ||
@@ -125,0 +126,0 @@ init.buttons = this.buttons.getButtons(); |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var shared = require('./shared.js'); | ||
var buttons = require('./buttons.js'); | ||
@@ -23,4 +24,3 @@ function _define_property(obj, key, value) { | ||
class Pointer { | ||
init(instance, position) { | ||
this.position = position; | ||
init(instance) { | ||
const target = this.getTarget(instance); | ||
@@ -42,3 +42,3 @@ const [, enter] = getTreeDiff.getTreeDiff(null, target); | ||
const nextTarget = this.getTarget(instance); | ||
const init = this.getEventInit(); | ||
const init = this.getEventInit(-1); | ||
const [leave, enter] = getTreeDiff.getTreeDiff(prevTarget, nextTarget); | ||
@@ -66,3 +66,3 @@ return { | ||
} | ||
down(instance, _keyDef) { | ||
down(instance, button = 0) { | ||
if (this.isDown) { | ||
@@ -74,5 +74,5 @@ return; | ||
this.isDown = true; | ||
this.isPrevented = !instance.dispatchUIEvent(target, 'pointerdown', this.getEventInit()); | ||
this.isPrevented = !instance.dispatchUIEvent(target, 'pointerdown', this.getEventInit(button)); | ||
} | ||
up(instance, _keyDef) { | ||
up(instance, button = 0) { | ||
if (!this.isDown) { | ||
@@ -83,4 +83,5 @@ return; | ||
cssPointerEvents.assertPointerEvents(instance, target); | ||
this.isPrevented = false; | ||
this.isDown = false; | ||
instance.dispatchUIEvent(target, 'pointerup', this.getEventInit()); | ||
instance.dispatchUIEvent(target, 'pointerup', this.getEventInit(button)); | ||
} | ||
@@ -103,3 +104,8 @@ release(instance) { | ||
} | ||
getEventInit() { | ||
getEventInit(/** | ||
* The `button` that caused the event. | ||
* | ||
* This should be `-1` if the event is not caused by a button or touch/pen contact, | ||
* e.g. a moving pointer. | ||
*/ button) { | ||
return { | ||
@@ -109,9 +115,12 @@ ...this.position.coords, | ||
pointerType: this.pointerType, | ||
isPrimary: this.isPrimary | ||
isPrimary: this.isPrimary, | ||
button: buttons.getMouseEventButton(button), | ||
buttons: this.buttons.getButtons() | ||
}; | ||
} | ||
constructor({ pointerId, pointerType, isPrimary }){ | ||
constructor({ pointerId, pointerType, isPrimary }, buttons){ | ||
_define_property(this, "pointerId", undefined); | ||
_define_property(this, "pointerType", undefined); | ||
_define_property(this, "isPrimary", undefined); | ||
_define_property(this, "buttons", undefined); | ||
_define_property(this, "isMultitouch", false); | ||
@@ -126,2 +135,3 @@ _define_property(this, "isCancelled", false); | ||
this.isMultitouch = !isPrimary; | ||
this.buttons = buttons; | ||
} | ||
@@ -128,0 +138,0 @@ } |
@@ -38,2 +38,6 @@ 'use strict'; | ||
} | ||
// When matching files, browsers ignore case and consider jpeg/jpg interchangeable. | ||
function normalize(nameOrType) { | ||
return nameOrType.toLowerCase().replace(/(\.|\/)jpg\b/g, '$1jpeg'); | ||
} | ||
function isAcceptableFile(file, accept) { | ||
@@ -48,10 +52,10 @@ if (!accept) { | ||
]; | ||
return accept.split(',').some((acceptToken)=>{ | ||
return normalize(accept).trim().split(/\s*,\s*/).some((acceptToken)=>{ | ||
// tokens starting with a dot represent a file extension | ||
if (acceptToken.startsWith('.')) { | ||
// tokens starting with a dot represent a file extension | ||
return file.name.endsWith(acceptToken); | ||
return normalize(file.name).endsWith(acceptToken); | ||
} else if (wildcards.includes(acceptToken)) { | ||
return file.type.startsWith(acceptToken.substr(0, acceptToken.length - 1)); | ||
return normalize(file.type).startsWith(acceptToken.replace('*', '')); | ||
} | ||
return file.type === acceptToken; | ||
return normalize(file.type) === acceptToken; | ||
}); | ||
@@ -58,0 +62,0 @@ } |
@@ -12,3 +12,3 @@ 'use strict'; | ||
// The cursor always moves to zero offset if the focus area (contenteditable or body) ends there. | ||
// When walking foward both ignore zero offset. | ||
// When walking forward both ignore zero offset. | ||
// When walking over input elements the cursor moves before or after that element. | ||
@@ -15,0 +15,0 @@ // When walking over line breaks the cursor moves inside any following text node. |
@@ -35,4 +35,4 @@ import { dispatchDOMEvent } from '../event/dispatchEvent.js'; | ||
} | ||
const blured = getActiveTarget(this.ownerDocument); | ||
if (blured === this) { | ||
const blurred = getActiveTarget(this.ownerDocument); | ||
if (blurred === this) { | ||
return; | ||
@@ -42,8 +42,8 @@ } | ||
activeCall = thisCall; | ||
if (blured) { | ||
blur.call(blured); | ||
dispatchDOMEvent(blured, 'blur', { | ||
if (blurred) { | ||
blur.call(blurred); | ||
dispatchDOMEvent(blurred, 'blur', { | ||
relatedTarget: this | ||
}); | ||
dispatchDOMEvent(blured, 'focusout', { | ||
dispatchDOMEvent(blurred, 'focusout', { | ||
relatedTarget: activeCall === thisCall ? this : null | ||
@@ -55,3 +55,3 @@ }); | ||
dispatchDOMEvent(this, 'focus', { | ||
relatedTarget: blured | ||
relatedTarget: blurred | ||
}); | ||
@@ -61,3 +61,3 @@ } | ||
dispatchDOMEvent(this, 'focusin', { | ||
relatedTarget: blured | ||
relatedTarget: blurred | ||
}); | ||
@@ -70,4 +70,4 @@ } | ||
} | ||
const blured = getActiveTarget(this.ownerDocument); | ||
if (blured !== this) { | ||
const blurred = getActiveTarget(this.ownerDocument); | ||
if (blurred !== this) { | ||
return; | ||
@@ -78,6 +78,6 @@ } | ||
blur.call(this); | ||
dispatchDOMEvent(blured, 'blur', { | ||
dispatchDOMEvent(blurred, 'blur', { | ||
relatedTarget: null | ||
}); | ||
dispatchDOMEvent(blured, 'focusout', { | ||
dispatchDOMEvent(blurred, 'focusout', { | ||
relatedTarget: null | ||
@@ -84,0 +84,0 @@ }); |
@@ -12,8 +12,8 @@ import { isElementType } from '../../utils/misc/isElementType.js'; | ||
const control = context && isElementType(context, 'label') && context.control; | ||
if (control) { | ||
if (control && control !== target) { | ||
return ()=>{ | ||
if (isFocusable(control)) { | ||
focusElement(control); | ||
instance.dispatchEvent(control, cloneEvent(event)); | ||
} | ||
instance.dispatchEvent(control, cloneEvent(event)); | ||
}; | ||
@@ -20,0 +20,0 @@ } else if (isElementType(target, 'input', { |
@@ -27,3 +27,3 @@ import { getUIValue, setUISelection } from '../../document/UI.js'; | ||
})) { | ||
return ()=>walkRadio(instance, target, -1); | ||
return ()=>walkRadio(instance, target, 1); | ||
} | ||
@@ -51,3 +51,3 @@ }, | ||
})) { | ||
return ()=>walkRadio(instance, target, 1); | ||
return ()=>walkRadio(instance, target, -1); | ||
} | ||
@@ -54,0 +54,0 @@ }, |
@@ -20,3 +20,3 @@ import '../utils/dataTransfer/Clipboard.js'; | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initMouseEvent | ||
@@ -26,3 +26,3 @@ ], | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initMouseEvent, | ||
@@ -33,3 +33,3 @@ initPointerEvent | ||
initUIEvent, | ||
initUIEventModififiers, | ||
initUIEventModifiers, | ||
initKeyboardEvent | ||
@@ -142,3 +142,3 @@ ] | ||
} | ||
function initUIEventModififiers(event, { altKey, ctrlKey, metaKey, shiftKey, modifierAltGraph, modifierCapsLock, modifierFn, modifierFnLock, modifierNumLock, modifierScrollLock, modifierSymbol, modifierSymbolLock }) { | ||
function initUIEventModifiers(event, { altKey, ctrlKey, metaKey, shiftKey, modifierAltGraph, modifierCapsLock, modifierFn, modifierFnLock, modifierNumLock, modifierScrollLock, modifierSymbol, modifierSymbolLock }) { | ||
assignProps(event, { | ||
@@ -197,4 +197,4 @@ altKey: Boolean(altKey), | ||
pointerId: sanitizeNumber(pointerId), | ||
width: sanitizeNumber(width), | ||
height: sanitizeNumber(height), | ||
width: sanitizeNumber(width !== null && width !== undefined ? width : 1), | ||
height: sanitizeNumber(height !== null && height !== undefined ? height : 1), | ||
pressure: sanitizeNumber(pressure), | ||
@@ -201,0 +201,0 @@ tangentialPressure: sanitizeNumber(tangentialPressure), |
@@ -21,2 +21,3 @@ import '../utils/dataTransfer/Clipboard.js'; | ||
instance.dispatchUIEvent(group[i], 'click'); | ||
return; | ||
} | ||
@@ -23,0 +24,0 @@ } |
@@ -6,3 +6,3 @@ import { DOM_KEY_LOCATION } from '../system/keyboard.js'; | ||
*/ const defaultKeyMap = [ | ||
// alphanumeric keys | ||
// alphanumeric block - writing system | ||
...'0123456789'.split('').map((c)=>({ | ||
@@ -26,2 +26,20 @@ code: `Digit${c}`, | ||
})), | ||
{ | ||
code: 'BracketLeft', | ||
key: '[' | ||
}, | ||
{ | ||
code: 'BracketLeft', | ||
key: '{', | ||
shiftKey: true | ||
}, | ||
{ | ||
code: 'BracketRight', | ||
key: ']' | ||
}, | ||
{ | ||
code: 'BracketRight', | ||
key: '}', | ||
shiftKey: true | ||
}, | ||
// alphanumeric block - functional | ||
@@ -83,2 +101,6 @@ { | ||
{ | ||
code: 'ContextMenu', | ||
key: 'ContextMenu' | ||
}, | ||
{ | ||
code: 'Tab', | ||
@@ -85,0 +107,0 @@ key: 'Tab' |
@@ -5,3 +5,3 @@ import '../utils/dataTransfer/Clipboard.js'; | ||
/** | ||
* Parse key defintions per `keyboardMap` | ||
* Parse key definitions per `keyboardMap` | ||
* | ||
@@ -8,0 +8,0 @@ * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`. |
@@ -24,4 +24,6 @@ import { Buttons } from './buttons.js'; | ||
async press(instance, keyDef, position) { | ||
this.devices.get(keyDef.pointerType).addPressed(keyDef); | ||
this.buttons.down(keyDef); | ||
const pointerName = this.getPointerName(keyDef); | ||
const pointer = keyDef.pointerType === 'touch' ? this.pointers.new(pointerName, keyDef).init(instance, position) : this.pointers.get(pointerName); | ||
const pointer = keyDef.pointerType === 'touch' ? this.pointers.new(pointerName, keyDef.pointerType, this.buttons) : this.pointers.get(pointerName); | ||
// TODO: deprecate the following implicit setting of position | ||
@@ -32,8 +34,9 @@ pointer.position = position; | ||
} | ||
this.devices.get(keyDef.pointerType).addPressed(keyDef); | ||
this.buttons.down(keyDef); | ||
pointer.down(instance, keyDef); | ||
if (pointer.pointerType !== 'touch' && !pointer.isPrevented) { | ||
this.mouse.down(instance, keyDef, pointer); | ||
if (pointer.pointerType === 'touch') { | ||
pointer.init(instance); | ||
} | ||
pointer.down(instance, keyDef.button); | ||
if (pointer.pointerType !== 'touch') { | ||
this.mouse.down(instance, keyDef, pointer.isPrevented); | ||
} | ||
} | ||
@@ -47,3 +50,3 @@ async move(instance, pointerName, position) { | ||
const pointermove = pointer.move(instance, position); | ||
const mousemove = pointer.pointerType === 'touch' || pointer.isPrevented && pointer.isDown ? undefined : this.mouse.move(instance, position); | ||
const mousemove = pointer.pointerType === 'touch' ? undefined : this.mouse.move(instance, position, pointer.isPrevented); | ||
pointermove === null || pointermove === undefined ? undefined : pointermove.leave(); | ||
@@ -61,2 +64,3 @@ mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
const pointer = this.pointers.get(this.getPointerName(keyDef)); | ||
const isPrevented = pointer.isPrevented; | ||
// TODO: deprecate the following implicit setting of position | ||
@@ -68,3 +72,3 @@ pointer.position = position; | ||
if (device.countPressed === 0) { | ||
pointer.up(instance, keyDef); | ||
pointer.up(instance, keyDef.button); | ||
} | ||
@@ -74,18 +78,16 @@ if (pointer.pointerType === 'touch') { | ||
} | ||
if (!pointer.isPrevented) { | ||
if (pointer.pointerType === 'touch' && !pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, pointer.position); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.down(instance, keyDef, pointer); | ||
} | ||
if (!pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, pointer.position); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.up(instance, keyDef, pointer); | ||
} | ||
if (pointer.pointerType === 'touch' && !pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, position, isPrevented); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.down(instance, keyDef, isPrevented); | ||
} | ||
if (!pointer.isMultitouch) { | ||
const mousemove = this.mouse.move(instance, position, isPrevented); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.leave(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.enter(); | ||
mousemove === null || mousemove === undefined ? undefined : mousemove.move(); | ||
this.mouse.up(instance, keyDef, isPrevented); | ||
} | ||
} | ||
@@ -124,7 +126,7 @@ getPointerName(keyDef) { | ||
_define_property(this, "pointers", new class { | ||
new(pointerName, keyDef) { | ||
const isPrimary = keyDef.pointerType !== 'touch' || !Object.values(this.registry).some((p)=>p.pointerType === 'touch' && !p.isCancelled); | ||
new(pointerName, pointerType, buttons) { | ||
const isPrimary = pointerType !== 'touch' || !Object.values(this.registry).some((p)=>p.pointerType === 'touch' && !p.isCancelled); | ||
if (!isPrimary) { | ||
Object.values(this.registry).forEach((p)=>{ | ||
if (p.pointerType === keyDef.pointerType && !p.isCancelled) { | ||
if (p.pointerType === pointerType && !p.isCancelled) { | ||
p.isMultitouch = true; | ||
@@ -136,5 +138,5 @@ } | ||
pointerId: this.nextId++, | ||
pointerType: keyDef.pointerType, | ||
pointerType, | ||
isPrimary | ||
}); | ||
}, buttons); | ||
return this.registry[pointerName]; | ||
@@ -152,10 +154,4 @@ } | ||
constructor(){ | ||
_define_property(this, "registry", { | ||
mouse: new Pointer({ | ||
pointerId: 1, | ||
pointerType: 'mouse', | ||
isPrimary: true | ||
}) | ||
}); | ||
_define_property(this, "nextId", 2); | ||
_define_property(this, "registry", {}); | ||
_define_property(this, "nextId", 1); | ||
} | ||
@@ -166,2 +162,3 @@ }()); | ||
this.mouse = new Mouse(); | ||
this.pointers.new('mouse', 'mouse', this.buttons); | ||
} | ||
@@ -168,0 +165,0 @@ } |
@@ -33,3 +33,3 @@ import '../../event/behavior/click.js'; | ||
*/ class Mouse { | ||
move(instance, position) { | ||
move(instance, position, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const prevPosition = this.position; | ||
@@ -58,2 +58,5 @@ const prevTarget = this.getTarget(instance); | ||
move: ()=>{ | ||
if (isPrevented) { | ||
return; | ||
} | ||
instance.dispatchUIEvent(nextTarget, 'mousemove', init); | ||
@@ -64,3 +67,3 @@ this.modifySelecting(instance); | ||
} | ||
down(instance, keyDef, pointer) { | ||
down(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const button = this.buttons.down(keyDef); | ||
@@ -72,5 +75,5 @@ if (button === undefined) { | ||
this.buttonDownTarget[button] = target; | ||
const init = this.getEventInit('mousedown', keyDef.button); | ||
const disabled = isDisabled(target); | ||
const init = this.getEventInit('mousedown', keyDef.button); | ||
if (disabled || instance.dispatchUIEvent(target, 'mousedown', init)) { | ||
if (!isPrevented && (disabled || instance.dispatchUIEvent(target, 'mousedown', init))) { | ||
this.startSelecting(instance, init.detail); | ||
@@ -80,6 +83,6 @@ focusElement(target); | ||
if (!disabled && getMouseEventButton(keyDef.button) === 2) { | ||
instance.dispatchUIEvent(target, 'contextmenu', this.getEventInit('contextmenu', keyDef.button, pointer)); | ||
instance.dispatchUIEvent(target, 'contextmenu', this.getEventInit('contextmenu', keyDef.button)); | ||
} | ||
} | ||
up(instance, keyDef, pointer) { | ||
up(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) { | ||
const button = this.buttons.up(keyDef); | ||
@@ -91,7 +94,10 @@ if (button === undefined) { | ||
if (!isDisabled(target)) { | ||
instance.dispatchUIEvent(target, 'mouseup', this.getEventInit('mouseup', keyDef.button)); | ||
this.endSelecting(); | ||
if (!isPrevented) { | ||
const mouseUpInit = this.getEventInit('mouseup', keyDef.button); | ||
instance.dispatchUIEvent(target, 'mouseup', mouseUpInit); | ||
this.endSelecting(); | ||
} | ||
const clickTarget = getTreeDiff(this.buttonDownTarget[button], target)[2][0]; | ||
if (clickTarget) { | ||
const init = this.getEventInit('click', keyDef.button, pointer); | ||
const init = this.getEventInit('click', keyDef.button); | ||
if (init.detail) { | ||
@@ -112,11 +118,6 @@ instance.dispatchUIEvent(clickTarget, init.button === 0 ? 'click' : 'auxclick', init); | ||
} | ||
getEventInit(type, button, pointer) { | ||
getEventInit(type, button) { | ||
const init = { | ||
...this.position.coords | ||
}; | ||
if (pointer) { | ||
init.pointerId = pointer.pointerId; | ||
init.pointerType = pointer.pointerType; | ||
init.isPrimary = pointer.isPrimary; | ||
} | ||
init.button = getMouseEventButton(button); | ||
@@ -123,0 +124,0 @@ init.buttons = this.buttons.getButtons(); |
@@ -5,2 +5,3 @@ import '../../utils/dataTransfer/Clipboard.js'; | ||
import { isDifferentPointerPosition } from './shared.js'; | ||
import { getMouseEventButton } from './buttons.js'; | ||
@@ -21,4 +22,3 @@ function _define_property(obj, key, value) { | ||
class Pointer { | ||
init(instance, position) { | ||
this.position = position; | ||
init(instance) { | ||
const target = this.getTarget(instance); | ||
@@ -40,3 +40,3 @@ const [, enter] = getTreeDiff(null, target); | ||
const nextTarget = this.getTarget(instance); | ||
const init = this.getEventInit(); | ||
const init = this.getEventInit(-1); | ||
const [leave, enter] = getTreeDiff(prevTarget, nextTarget); | ||
@@ -64,3 +64,3 @@ return { | ||
} | ||
down(instance, _keyDef) { | ||
down(instance, button = 0) { | ||
if (this.isDown) { | ||
@@ -72,5 +72,5 @@ return; | ||
this.isDown = true; | ||
this.isPrevented = !instance.dispatchUIEvent(target, 'pointerdown', this.getEventInit()); | ||
this.isPrevented = !instance.dispatchUIEvent(target, 'pointerdown', this.getEventInit(button)); | ||
} | ||
up(instance, _keyDef) { | ||
up(instance, button = 0) { | ||
if (!this.isDown) { | ||
@@ -81,4 +81,5 @@ return; | ||
assertPointerEvents(instance, target); | ||
this.isPrevented = false; | ||
this.isDown = false; | ||
instance.dispatchUIEvent(target, 'pointerup', this.getEventInit()); | ||
instance.dispatchUIEvent(target, 'pointerup', this.getEventInit(button)); | ||
} | ||
@@ -101,3 +102,8 @@ release(instance) { | ||
} | ||
getEventInit() { | ||
getEventInit(/** | ||
* The `button` that caused the event. | ||
* | ||
* This should be `-1` if the event is not caused by a button or touch/pen contact, | ||
* e.g. a moving pointer. | ||
*/ button) { | ||
return { | ||
@@ -107,9 +113,12 @@ ...this.position.coords, | ||
pointerType: this.pointerType, | ||
isPrimary: this.isPrimary | ||
isPrimary: this.isPrimary, | ||
button: getMouseEventButton(button), | ||
buttons: this.buttons.getButtons() | ||
}; | ||
} | ||
constructor({ pointerId, pointerType, isPrimary }){ | ||
constructor({ pointerId, pointerType, isPrimary }, buttons){ | ||
_define_property(this, "pointerId", undefined); | ||
_define_property(this, "pointerType", undefined); | ||
_define_property(this, "isPrimary", undefined); | ||
_define_property(this, "buttons", undefined); | ||
_define_property(this, "isMultitouch", false); | ||
@@ -124,2 +133,3 @@ _define_property(this, "isCancelled", false); | ||
this.isMultitouch = !isPrimary; | ||
this.buttons = buttons; | ||
} | ||
@@ -126,0 +136,0 @@ } |
@@ -36,2 +36,6 @@ import { isElementType } from '../utils/misc/isElementType.js'; | ||
} | ||
// When matching files, browsers ignore case and consider jpeg/jpg interchangeable. | ||
function normalize(nameOrType) { | ||
return nameOrType.toLowerCase().replace(/(\.|\/)jpg\b/g, '$1jpeg'); | ||
} | ||
function isAcceptableFile(file, accept) { | ||
@@ -46,10 +50,10 @@ if (!accept) { | ||
]; | ||
return accept.split(',').some((acceptToken)=>{ | ||
return normalize(accept).trim().split(/\s*,\s*/).some((acceptToken)=>{ | ||
// tokens starting with a dot represent a file extension | ||
if (acceptToken.startsWith('.')) { | ||
// tokens starting with a dot represent a file extension | ||
return file.name.endsWith(acceptToken); | ||
return normalize(file.name).endsWith(acceptToken); | ||
} else if (wildcards.includes(acceptToken)) { | ||
return file.type.startsWith(acceptToken.substr(0, acceptToken.length - 1)); | ||
return normalize(file.type).startsWith(acceptToken.replace('*', '')); | ||
} | ||
return file.type === acceptToken; | ||
return normalize(file.type) === acceptToken; | ||
}); | ||
@@ -56,0 +60,0 @@ } |
@@ -10,3 +10,3 @@ import { isContentEditable } from '../edit/isContentEditable.js'; | ||
// The cursor always moves to zero offset if the focus area (contenteditable or body) ends there. | ||
// When walking foward both ignore zero offset. | ||
// When walking forward both ignore zero offset. | ||
// When walking over input elements the cursor moves before or after that element. | ||
@@ -13,0 +13,0 @@ // When walking over line breaks the cursor moves inside any following text node. |
import { keyboardKey } from '../system/keyboard'; | ||
/** | ||
* Parse key defintions per `keyboardMap` | ||
* Parse key definitions per `keyboardMap` | ||
* | ||
@@ -5,0 +5,0 @@ * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`. |
@@ -36,3 +36,3 @@ import { type keyboardKey } from './system/keyboard'; | ||
* Between some subsequent inputs like typing a series of characters | ||
* the code execution is delayed per `setTimeout` for (at least) `delay` seconds. | ||
* the code execution is delayed per `setTimeout` for (at least) `delay` milliseconds. | ||
* This moves the next changes at least to next macro task | ||
@@ -39,0 +39,0 @@ * and allows other (asynchronous) code to run between events. |
import { type Instance } from '../../setup'; | ||
import { type Pointer } from './pointer'; | ||
import { pointerKey, PointerPosition } from './shared'; | ||
@@ -13,3 +12,5 @@ /** | ||
private readonly clickCount; | ||
move(instance: Instance, position: PointerPosition): { | ||
move(instance: Instance, position: PointerPosition, | ||
/** Whether `preventDefault()` has been called on the `pointerdown` event */ | ||
isPrevented: boolean): { | ||
leave: () => void; | ||
@@ -19,4 +20,8 @@ enter: () => void; | ||
} | undefined; | ||
down(instance: Instance, keyDef: pointerKey, pointer: Pointer): void; | ||
up(instance: Instance, keyDef: pointerKey, pointer: Pointer): void; | ||
down(instance: Instance, keyDef: pointerKey, | ||
/** Whether `preventDefault()` has been called on the `pointerdown` event */ | ||
isPrevented: boolean): void; | ||
up(instance: Instance, keyDef: pointerKey, | ||
/** Whether `preventDefault()` has been called on the `pointerdown` event */ | ||
isPrevented: boolean): void; | ||
resetClickCount(): void; | ||
@@ -23,0 +28,0 @@ private getEventInit; |
import { type Instance } from '../../setup'; | ||
import { pointerKey, PointerPosition } from './shared'; | ||
import { PointerPosition } from './shared'; | ||
import { Buttons, MouseButton } from './buttons'; | ||
type PointerInit = { | ||
@@ -9,6 +10,7 @@ pointerId: number; | ||
export declare class Pointer { | ||
constructor({ pointerId, pointerType, isPrimary }: PointerInit); | ||
constructor({ pointerId, pointerType, isPrimary }: PointerInit, buttons: Buttons); | ||
readonly pointerId: number; | ||
readonly pointerType: string; | ||
readonly isPrimary: boolean; | ||
readonly buttons: Buttons; | ||
isMultitouch: boolean; | ||
@@ -19,3 +21,3 @@ isCancelled: boolean; | ||
position: PointerPosition; | ||
init(instance: Instance, position: PointerPosition): this; | ||
init(instance: Instance): this; | ||
move(instance: Instance, position: PointerPosition): { | ||
@@ -26,4 +28,4 @@ leave: () => void; | ||
} | undefined; | ||
down(instance: Instance, _keyDef: pointerKey): void; | ||
up(instance: Instance, _keyDef: pointerKey): void; | ||
down(instance: Instance, button?: MouseButton): void; | ||
up(instance: Instance, button?: MouseButton): void; | ||
release(instance: Instance): void; | ||
@@ -30,0 +32,0 @@ private getTarget; |
{ | ||
"name": "@testing-library/user-event", | ||
"version": "14.6.0", | ||
"version": "14.6.1", | ||
"description": "Fire events the same way the user does", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
437874
0.67%10860
0.71%