import type { ElementReference } from '@wdio/protocols'
import type { BaseActionParams, KeyActionType } from './base.js'
import BaseAction from './base.js'
import type { ChainablePromiseElement } from '../../types.js'
const buttonNumbers = [0, 1, 2] as const
const buttonNames = ['left', 'middle', 'right'] as const
export const buttonValue = [...buttonNumbers, ...buttonNames] as const
export type ButtonNames = 'left' | 'middle' | 'right'
export type Button = 0 | 1 | 2
export type Origin = 'pointer' | 'viewport'
const ORIGIN_DEFAULT: Origin = 'viewport'
const BUTTON_DEFAULT: Button = 0
const POINTER_TYPE_DEFAULT: KeyActionType = 'mouse'
interface PointerActionUpParams {
* The button to press (e.g. 0 for left, 1 for middle or 2 for right)
* @default 0
*/
button: Button | ButtonNames
}
const UP_PARAM_DEFAULTS = {
button: BUTTON_DEFAULT
} as PointerActionUpParams
const PARAM_DEFAULTS = {
...UP_PARAM_DEFAULTS,
width: 0,
height: 0,
pressure: 0,
tangentialPressure: 0,
tiltX: 0,
tiltY: 0,
twist: 0,
altitudeAngle: 0,
azimuthAngle: 0
}
const MOVE_PARAM_DEFAULTS = {
x: 0,
y: 0,
duration: 100,
origin: ORIGIN_DEFAULT as (Origin | ElementReference | ChainablePromiseElement | WebdriverIO.Element)
}
type PointerActionParams = Partial<typeof PARAM_DEFAULTS> & Partial<PointerActionUpParams>
type PointerActionMoveParams = Partial<typeof MOVE_PARAM_DEFAULTS> & PointerActionParams
function removeDefaultParams(seq: Record<string, unknown>) {
for (const [key, value] of Object.entries(seq)) {
if (value === 0 && !['x', 'y', 'button', 'duration'].includes(key)) {
delete seq[key]
}
}
}
function mapButton(params: PointerActionParams | ButtonNames | Button) {
const buttons = {
left: 0,
middle: 1,
right: 2
}
if (typeof params === 'number') {
return { button: params }
}
if (typeof params === 'string') {
return { button: buttons[params] }
}
if (typeof params === 'object' && typeof params.button === 'string') {
return { ...params, button: buttons[params.button] }
}
return params
}
export default class PointerAction extends BaseAction {
constructor (instance: WebdriverIO.Browser, params: BaseActionParams = {}) {
if (!params.parameters) {
params.parameters = { pointerType: POINTER_TYPE_DEFAULT }
}
super(instance, 'pointer', params)
}
* Creates an action for moving the pointer `x` and `y` pixels from the specified
* `origin`. The `origin` may be defined as the pointers current position (e.g. "pointer"),
* the viewport (e.g. "viewport") or the center of a specific element.
* @param params PointerActionMoveParams
*/
move (params: PointerActionMoveParams): PointerAction
move (x: number, y: number): PointerAction
move (params: PointerActionMoveParams | number = {}, y?: number) {
const seq = {
type: 'pointerMove',
...PARAM_DEFAULTS,
...UP_PARAM_DEFAULTS,
...MOVE_PARAM_DEFAULTS,
}
if (typeof params === 'number') {
Object.assign(seq, { x: params, y })
} else if (params) {
Object.assign(seq, params)
}
removeDefaultParams(seq)
this.sequence.push(seq)
return this
}
* Creates an action to release a single key.
* @param params PointerActionUpParams
*/
up (button?: Button): PointerAction
up (button?: ButtonNames): PointerAction
up (params?: PointerActionUpParams): PointerAction
up (params: PointerActionUpParams | ButtonNames | Button = UP_PARAM_DEFAULTS) {
this.sequence.push({
type: 'pointerUp',
...mapButton(params)
})
return this
}
* Creates an action to press a single key
* @param params PointerActionParams
*/
down (button?: Button): PointerAction
down (button?: ButtonNames): PointerAction
down (params?: PointerActionParams): PointerAction
down (params: PointerActionParams | Button | ButtonNames = {}) {
const seq = {
type: 'pointerDown',
...PARAM_DEFAULTS,
...mapButton(params),
}
removeDefaultParams(seq)
this.sequence.push(seq)
return this
}
* An action that cancels this pointer's current input.
*/
cancel () {
this.sequence.push({ type: 'pointerCancel' })
return this
}
}