1
- import * as eventTypes from 'dom-event-types'
1
+ import eventTypes from 'dom-event-types'
2
2
3
3
interface TriggerOptions {
4
4
code ?: String
@@ -9,11 +9,47 @@ interface TriggerOptions {
9
9
10
10
interface EventParams {
11
11
eventType : string
12
- modifier : string
13
- meta : any
12
+ modifiers : string [ ]
14
13
options ?: TriggerOptions
15
14
}
16
15
16
+ // modifiers to keep an eye on
17
+ const ignorableKeyModifiers = [ 'stop' , 'prevent' , 'self' , 'exact' ]
18
+ const systemKeyModifiers = [ 'ctrl' , 'shift' , 'alt' , 'meta' ]
19
+ const mouseKeyModifiers = [ 'left' , 'middle' , 'right' ]
20
+
21
+ /**
22
+ * Groups modifiers into lists
23
+ */
24
+ function generateModifiers ( modifiers : string [ ] , isOnClick : boolean ) {
25
+ const keyModifiers : string [ ] = [ ]
26
+ const systemModifiers : string [ ] = [ ]
27
+
28
+ for ( let i = 0 ; i < modifiers . length ; i ++ ) {
29
+ const modifier = modifiers [ i ]
30
+
31
+ // addEventListener() options, e.g. .passive & .capture, that we dont need to handle
32
+ if ( ignorableKeyModifiers . includes ( modifier ) ) {
33
+ continue
34
+ }
35
+ // modifiers that require special conversion
36
+ // if passed a left/right key modifier with onClick, add it here as well.
37
+ if (
38
+ systemKeyModifiers . includes ( modifier ) ||
39
+ ( mouseKeyModifiers . includes ( modifier ) && isOnClick )
40
+ ) {
41
+ systemModifiers . push ( modifier )
42
+ } else {
43
+ keyModifiers . push ( modifier )
44
+ }
45
+ }
46
+
47
+ return {
48
+ keyModifiers,
49
+ systemModifiers
50
+ }
51
+ }
52
+
17
53
export const keyCodesByKeyName = {
18
54
backspace : 8 ,
19
55
tab : 9 ,
@@ -33,52 +69,90 @@ export const keyCodesByKeyName = {
33
69
}
34
70
35
71
function getEventProperties ( eventParams : EventParams ) {
36
- const { modifier, meta, options } = eventParams
72
+ let { modifiers, options = { } , eventType } = eventParams
73
+
74
+ let isOnClick = eventType === 'click'
75
+
76
+ const { keyModifiers, systemModifiers } = generateModifiers (
77
+ modifiers ,
78
+ isOnClick
79
+ )
80
+
81
+ if ( isOnClick ) {
82
+ // if it's a right click, it should fire a `contextmenu` event
83
+ if ( systemModifiers . includes ( 'right' ) ) {
84
+ eventType = 'contextmenu'
85
+ options . button = 2
86
+ // if its a middle click, fire a `mouseup` event
87
+ } else if ( systemModifiers . includes ( 'middle' ) ) {
88
+ eventType = 'mouseup'
89
+ options . button = 1
90
+ }
91
+ }
92
+
93
+ const meta = eventTypes [ eventType ] || {
94
+ eventInterface : 'Event' ,
95
+ cancelable : true ,
96
+ bubbles : true
97
+ }
98
+
99
+ // convert `shift, ctrl` to `shiftKey, ctrlKey`
100
+ // allows trigger('keydown.shift.ctrl.n') directly
101
+ const systemModifiersMeta = systemModifiers . reduce ( ( all , key ) => {
102
+ all [ `${ key } Key` ] = true
103
+ return all
104
+ } , { } )
105
+
106
+ // get the keyCode for backwards compat
37
107
const keyCode =
38
- keyCodesByKeyName [ modifier ] ||
108
+ keyCodesByKeyName [ keyModifiers [ 0 ] ] ||
39
109
( options && ( options . keyCode || options . code ) )
40
110
41
- return {
111
+ const eventProperties = {
112
+ ...systemModifiersMeta , // shiftKey, metaKey etc
42
113
...options , // What the user passed in as the second argument to #trigger
43
114
bubbles : meta . bubbles ,
44
115
meta : meta . cancelable ,
45
116
// Any derived options should go here
46
117
keyCode,
47
- code : keyCode
118
+ code : keyCode ,
119
+ // if we have a `key`, use it, otherwise dont set anything (allows user to pass custom key)
120
+ ...( keyModifiers [ 0 ] ? { key : keyModifiers [ 0 ] } : { } )
121
+ }
122
+
123
+ return {
124
+ eventProperties,
125
+ meta,
126
+ eventType
48
127
}
49
128
}
50
129
51
130
function createEvent ( eventParams : EventParams ) {
52
- const { eventType, meta } = eventParams
131
+ const { eventProperties, meta, eventType } = getEventProperties ( eventParams )
132
+
133
+ // user defined eventInterface
53
134
const metaEventInterface = window [ meta . eventInterface ]
54
135
55
136
const SupportedEventInterface =
56
137
typeof metaEventInterface === 'function' ? metaEventInterface : window . Event
57
138
58
- const eventProperties = getEventProperties ( eventParams )
59
-
60
- const event = new SupportedEventInterface (
139
+ return new SupportedEventInterface (
61
140
eventType ,
62
141
// event properties can only be added when the event is instantiated
63
142
// custom properties must be added after the event has been instantiated
64
143
eventProperties
65
144
)
66
-
67
- return event
68
145
}
69
146
70
147
function createDOMEvent ( eventString : String , options ?: TriggerOptions ) {
71
- const [ eventType , modifier ] = eventString . split ( '.' )
72
- const meta = eventTypes [ eventType ] || {
73
- eventInterface : 'Event' ,
74
- cancelable : true ,
75
- bubbles : true
76
- }
148
+ // split eventString like `keydown.ctrl.shift.c` into `keydown` and array of modifiers
149
+ const [ eventType , ...modifiers ] = eventString . split ( '.' )
77
150
78
- const eventParams : EventParams = { eventType, modifier , meta , options }
151
+ const eventParams : EventParams = { eventType, modifiers , options }
79
152
const event : Event = createEvent ( eventParams )
80
153
const eventPrototype = Object . getPrototypeOf ( event )
81
154
155
+ // attach custom options to the event, like `relatedTarget` and so on.
82
156
options &&
83
157
Object . keys ( options ) . forEach ( ( key ) => {
84
158
const propertyDescriptor = Object . getOwnPropertyDescriptor (
0 commit comments