@peter.naydenov/shortcuts 3.3.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +51 -1
- package/README.md +2 -0
- package/dist/main.d.ts +120 -0
- package/dist/methods/_normalizeWithPlugins.d.ts +2 -0
- package/dist/methods/_readShortcutWithPlugins.d.ts +2 -0
- package/dist/methods/_systemAction.d.ts +2 -0
- package/dist/methods/changeContext.d.ts +2 -0
- package/dist/methods/index.d.ts +17 -0
- package/dist/methods/listShortcuts.d.ts +17 -0
- package/dist/methods/load.d.ts +2 -0
- package/dist/methods/unload.d.ts +2 -0
- package/dist/plugins/click/_findTarget.d.ts +2 -0
- package/dist/plugins/click/_listenDOM.d.ts +5 -0
- package/dist/plugins/click/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/click/_readClickEvent.d.ts +2 -0
- package/dist/plugins/click/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/click/index.d.ts +15 -0
- package/dist/plugins/form/_defaults.d.ts +5 -0
- package/dist/plugins/form/_listenDOM.d.ts +5 -0
- package/dist/plugins/form/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/form/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/form/index.d.ts +10 -0
- package/dist/plugins/key/_listenDOM.d.ts +5 -0
- package/dist/plugins/key/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/key/_readKeyEvent.d.ts +2 -0
- package/dist/plugins/key/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/key/_specialChars.d.ts +32 -0
- package/dist/plugins/key/index.d.ts +15 -0
- package/dist/shortcuts.cjs +1 -1
- package/dist/shortcuts.esm.mjs +1 -1
- package/dist/shortcuts.umd.js +1 -1
- package/jsconfig.json +10 -0
- package/package.json +16 -7
- package/src/main.js +98 -28
- package/src/methods/_readShortcutWithPlugins.js +2 -1
- package/src/methods/changeContext.js +2 -1
- package/src/methods/listShortcuts.js +2 -1
- package/src/methods/load.js +10 -7
- package/src/methods/unload.js +3 -3
- package/src/plugins/click/_listenDOM.js +13 -3
- package/src/plugins/click/index.js +16 -6
- package/src/plugins/form/index.js +12 -17
- package/src/plugins/key/_listenDOM.js +13 -0
- package/src/plugins/key/index.js +11 -5
- package/test/01-general.test.js +158 -251
- package/test/02-key.test.js +272 -0
- package/test/03-click.test.js +352 -0
- package/test/04-form.test.js +90 -0
- package/test-helpers/setup.js +18 -0
- package/test-helpers/wait.js +8 -0
- package/tsconfig.json +23 -0
- package/vitest.config.js +21 -0
- package/vitest-example/HelloWorld.js +0 -9
- package/vitest-example/HelloWorld.test.js +0 -11
- package/vitest.workspace.js +0 -19
- /package/{test-components → test-helpers}/Block.jsx +0 -0
- /package/{test-components → test-helpers}/style.css +0 -0
package/test/01-general.test.js
CHANGED
|
@@ -1,37 +1,52 @@
|
|
|
1
|
-
import { beforeEach, describe, it,
|
|
1
|
+
import { beforeEach, afterEach, describe, it, expect } from 'vitest'
|
|
2
2
|
import { userEvent } from '@vitest/browser/context'
|
|
3
|
+
import {
|
|
4
|
+
getByLabelText,
|
|
5
|
+
getByText,
|
|
6
|
+
getByTestId,
|
|
7
|
+
queryByTestId,
|
|
8
|
+
// Tip: all queries are also exposed on an object
|
|
9
|
+
// called "queries" which you could import here as well
|
|
10
|
+
waitFor
|
|
11
|
+
} from '@testing-library/dom'
|
|
12
|
+
|
|
3
13
|
|
|
4
|
-
import Block from '../test-components/Block.jsx'
|
|
5
|
-
import VisaulController from '@peter.naydenov/visual-controller-for-react'
|
|
6
|
-
import '../test-components/style.css'
|
|
7
14
|
|
|
15
|
+
import '../test-helpers/style.css'
|
|
16
|
+
import Block from '../test-helpers/Block.jsx'
|
|
17
|
+
import VisaulController from '@peter.naydenov/visual-controller-for-react'
|
|
18
|
+
import wait from '../test-helpers/wait.js'
|
|
8
19
|
import {
|
|
9
20
|
pluginClick,
|
|
10
21
|
pluginKey
|
|
11
22
|
, pluginForm
|
|
12
23
|
, shortcuts
|
|
13
24
|
} from '../src/main.js'
|
|
14
|
-
|
|
25
|
+
|
|
15
26
|
|
|
16
27
|
import askForPromise from 'ask-for-promise'
|
|
17
28
|
|
|
18
29
|
const html = new VisaulController ();
|
|
19
|
-
|
|
20
30
|
let
|
|
21
31
|
a = false
|
|
22
32
|
, b = false
|
|
33
|
+
, c = null
|
|
23
34
|
;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function wait (ms) {
|
|
27
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const short = shortcuts ({onShortcut : ( shortcut, {context,note,type}) => console.log (shortcut, context, note, type) });
|
|
31
|
-
|
|
32
|
-
short.load ({
|
|
35
|
+
const contextDefinition = {
|
|
33
36
|
general : {
|
|
34
|
-
' key : shift+a': [
|
|
37
|
+
' key : shift+a': [
|
|
38
|
+
() => a = true,
|
|
39
|
+
() => c = 'triggered'
|
|
40
|
+
],
|
|
41
|
+
'@shortcuts-error' : ( m ) => c = m
|
|
42
|
+
}
|
|
43
|
+
, touch : {
|
|
44
|
+
// Single click with left button
|
|
45
|
+
'click: left-1': () => b = true,
|
|
46
|
+
// Double click with left button
|
|
47
|
+
'click: left-2': () => b = true,
|
|
48
|
+
// Single click with right button
|
|
49
|
+
'click: right-1': () => b = true
|
|
35
50
|
}
|
|
36
51
|
, extra : {
|
|
37
52
|
'key : p,r,o,b,a': () => b = true
|
|
@@ -47,253 +62,145 @@ short.load ({
|
|
|
47
62
|
}
|
|
48
63
|
]
|
|
49
64
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
beforeEach ( () => {
|
|
53
|
-
let container = document.createElement ( 'div' )
|
|
54
|
-
container.id = 'app'
|
|
55
|
-
document.body.appendChild ( container )
|
|
56
|
-
html.publish ( Block, {}, 'app' )
|
|
57
|
-
a = false, b = false
|
|
58
|
-
}) // beforeEach
|
|
65
|
+
}
|
|
59
66
|
|
|
60
67
|
|
|
68
|
+
|
|
69
|
+
let short = shortcuts ();
|
|
61
70
|
|
|
62
71
|
|
|
63
72
|
|
|
64
73
|
describe ( "Shortcuts", () => {
|
|
65
74
|
|
|
75
|
+
beforeEach ( async () => {
|
|
76
|
+
short.load ( contextDefinition )
|
|
77
|
+
let container = document.createElement ( 'div' )
|
|
78
|
+
container.id = 'app'
|
|
79
|
+
document.body.appendChild ( container )
|
|
80
|
+
await html.publish ( Block, {}, 'app' )
|
|
81
|
+
a = false, b = false
|
|
82
|
+
}) // beforeEach
|
|
66
83
|
|
|
67
84
|
|
|
68
|
-
test ( 'Shortcut if no plugin installed', () => {
|
|
69
|
-
let res = new Promise ( (resolve,reject) => {
|
|
70
|
-
short.changeContext ( 'general' )
|
|
71
|
-
let r = short.listShortcuts ('general')
|
|
72
|
-
expect ( r[0]).to.equal ( ' key : shift+a' ) // Shortcut name is the same as it was set
|
|
73
|
-
resolve ('success')
|
|
74
|
-
})
|
|
75
|
-
return res
|
|
76
|
-
}) // test no plugin installed
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
test ( 'Key plugin, no context selected', () => {
|
|
81
|
-
const res = new Promise ( ( resolve ) => {
|
|
82
|
-
short.enablePlugin ( pluginKey )
|
|
83
|
-
const r = short.listShortcuts ( 'general' )
|
|
84
|
-
expect ( r[0] ).to.equal ( 'KEY:A+SHIFT' ) // Shortcut name is recognized by plugin and is normalized
|
|
85
|
-
resolve ('success')
|
|
86
|
-
})
|
|
87
|
-
return res
|
|
88
|
-
}) // test key plugin installed, no context selected
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
test ( 'Key plugin with context selected', () => {
|
|
93
|
-
const res = new Promise ( (resolve) => {
|
|
94
|
-
short.enablePlugin ( pluginKey )
|
|
95
|
-
short.changeContext ( 'general' )
|
|
96
|
-
const r = short.listShortcuts ('general')
|
|
97
|
-
expect ( r[0] ).to.equal ( 'KEY:A+SHIFT' ) // Shortcut name is recognized by plugin and is normalized
|
|
98
|
-
resolve ( 'success' )
|
|
99
|
-
})
|
|
100
|
-
return res
|
|
101
|
-
}) // test key plugin installed with context selected
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
test ( 'Simple shortcut', () => {
|
|
106
|
-
const res = new Promise ( (resolve) => {
|
|
107
|
-
short.enablePlugin ( pluginKey )
|
|
108
|
-
short.changeContext ()
|
|
109
|
-
short.changeContext ( 'general' )
|
|
110
|
-
userEvent.keyboard ( '{Shift>}a</Shift>' )
|
|
111
|
-
expect ( a ).to.be.false
|
|
112
|
-
wait ( 1000 )
|
|
113
|
-
.then ( () => { // Default wait sequence timeout is 480 ms, but maxSequence is 1, so we don't need to wait for timeout
|
|
114
|
-
expect ( a ).to.be.true
|
|
115
|
-
resolve ( 'success' )
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
return res
|
|
119
|
-
}) // test simple shortcut
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
test ( 'Call sequence shortcut', async () => {
|
|
124
|
-
let res = new Promise ( async (resolve) => {
|
|
125
|
-
b = false
|
|
126
|
-
short.enablePlugin ( pluginKey )
|
|
127
|
-
short.changeContext ()
|
|
128
|
-
short.changeContext ( 'extra' )
|
|
129
|
-
await userEvent.keyboard ( 'proba' )
|
|
130
|
-
expect ( b ).to.be.true
|
|
131
|
-
resolve ( 'success' )
|
|
132
|
-
})
|
|
133
|
-
return res
|
|
134
|
-
}) // test call sequence shortcut
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
test ( 'Single mouse click', done => {
|
|
139
|
-
const res = new Promise ( async (resolve) => {
|
|
140
|
-
expect ( a ).to.be.false
|
|
141
|
-
expect ( b ).to.be.false
|
|
142
|
-
short.enablePlugin ( pluginClick )
|
|
143
|
-
|
|
144
|
-
short.load ({ 'extra' : {
|
|
145
|
-
' cLIck : left - 1 ' : () => a = true // Check if spaces, letter case can break the shortcut recognition
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
short.changeContext ()
|
|
149
|
-
short.changeContext ( 'extra' )
|
|
150
|
-
wait ( 100 )
|
|
151
|
-
.then ( async () => {
|
|
152
|
-
// Default wait mouse timeout is 320 ms, but maxClicks is 1, so we don't need to wait for timeout
|
|
153
|
-
let loc = document.querySelector('#rspan') || false
|
|
154
|
-
if ( loc ) await userEvent.click ( loc )
|
|
155
|
-
expect ( a ).to.be.true
|
|
156
|
-
resolve ( 'success' )
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
})
|
|
161
|
-
return res
|
|
162
|
-
}) // test single mouse click
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
test ( 'Double mouse click', () => {
|
|
167
|
-
let res = new Promise ( async (resolve) => {
|
|
168
|
-
expect ( a ).to.be.false
|
|
169
|
-
expect ( b ).to.be.false
|
|
170
|
-
|
|
171
|
-
short.enablePlugin ( pluginClick )
|
|
172
|
-
short.changeContext ( 'extra' )
|
|
173
|
-
short.load ({ // load will restart the selected context
|
|
174
|
-
'extra' : { // load will overwrite existing 'extra' context definition
|
|
175
|
-
'click: left-2' : () => a = true
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
wait ( 350 )
|
|
179
|
-
.then ( async () => { // Default wait mouse timeout is 320 ms
|
|
180
|
-
let loc = document.querySelector ( '#rspan' ) || false
|
|
181
|
-
// Third click is ignored. Max clicks according definition is 2.
|
|
182
|
-
if ( loc ) await userEvent.tripleClick ( loc )
|
|
183
|
-
expect ( a ).to.be.true
|
|
184
|
-
resolve ( 'success' )
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
return res
|
|
188
|
-
}) // test double mouse click
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
test ( 'Dependencies on shortcuts', () => {
|
|
193
|
-
const res = new Promise ( async (resolve) => {
|
|
194
|
-
const task = askForPromise ();
|
|
195
|
-
expect ( a ).to.be.false
|
|
196
|
-
expect ( b ).to.be.false
|
|
197
85
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
86
|
+
afterEach ( async () => {
|
|
87
|
+
short.reset ()
|
|
88
|
+
a = false, b = false, c = null;
|
|
89
|
+
}) // afterEach
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
it ( 'Load and unload context', async () => {
|
|
94
|
+
let ls = short.listContexts ()
|
|
95
|
+
expect ( ls ).to.includes ( 'general' )
|
|
96
|
+
|
|
97
|
+
short.changeContext ( 'general' )
|
|
98
|
+
// Can't not to unload current active context - sends an error on @shortcuts-error
|
|
99
|
+
// @shortcuts-error is a system error event used accross the library
|
|
100
|
+
short.unload ( 'general' )
|
|
101
|
+
expect ( c ).to.be.equal ( `Context 'general' can't be removed during is current active context. Change the context first` )
|
|
102
|
+
|
|
103
|
+
// Try to change context to non-existent one
|
|
104
|
+
// Message goes to @shortcuts-error
|
|
105
|
+
short.changeContext ( 'hhm' )
|
|
106
|
+
expect ( c ).to.be.equal ( `Context 'hhm' does not exist` )
|
|
107
|
+
|
|
108
|
+
// Change to something that exists
|
|
109
|
+
short.changeContext ( 'extra' )
|
|
110
|
+
// Free to unload 'general'
|
|
111
|
+
short.unload ( 'general' )
|
|
112
|
+
ls = short.listContexts ()
|
|
113
|
+
// Unload success
|
|
114
|
+
expect ( ls ).to.not.includes ( 'general' )
|
|
115
|
+
}) // it load and unload context
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
it ( 'List enabled plugins. Disable and enable plugins', async () => {
|
|
120
|
+
expect ( short.listPlugins () ).to.be.deep.equal ( [] )
|
|
121
|
+
// Enable list of plugins
|
|
122
|
+
let myPlugins = [ pluginKey, pluginClick ]
|
|
123
|
+
myPlugins.forEach ( plugin => short.enablePlugin ( plugin ) )
|
|
124
|
+
expect ( short.listPlugins () ).to.be.deep.equal ( [ 'key', 'click' ] )
|
|
125
|
+
// Method disablePlugin require plugin name (prefix)
|
|
126
|
+
short.disablePlugin ( 'click' )
|
|
127
|
+
expect ( short.listPlugins () ).to.be.deep.equal ( [ 'key' ] )
|
|
128
|
+
// Method enablePlugin require the plugin as a function
|
|
129
|
+
short.enablePlugin ( pluginClick )
|
|
130
|
+
expect ( short.listPlugins () ).to.be.deep.equal ( [ 'key', 'click' ] )
|
|
131
|
+
}) // it list enabled plugins
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
it ( 'Unload non existing context', () => {
|
|
136
|
+
let change = false;
|
|
137
|
+
let ls = short.listContexts ()
|
|
138
|
+
short.load ( {
|
|
139
|
+
local : {
|
|
140
|
+
'click : leff-1' : () => console.log ( 'nothing' ),
|
|
141
|
+
'@shortcuts-error': () => change = true
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
short.changeContext ( 'local' )
|
|
145
|
+
short.unload ( 'unknown' )
|
|
146
|
+
expect ( change ).to.be.true
|
|
147
|
+
}) // it unload non existing context
|
|
148
|
+
|
|
253
149
|
|
|
254
|
-
let fail = short.listShortcuts ( 'somethingNotExisting' );
|
|
255
|
-
expect ( fail ).to.be.null
|
|
256
|
-
|
|
257
|
-
let all = short.listShortcuts ();
|
|
258
|
-
expect ( all ).to.be.an ( 'array' )
|
|
259
150
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
151
|
+
it ( 'Emit custom event', () => {
|
|
152
|
+
// TODO: Check arguments for the custom event handlers
|
|
153
|
+
let result = null;
|
|
154
|
+
short.enablePlugin ( pluginClick )
|
|
155
|
+
const myAllContext = {
|
|
156
|
+
myAll: {
|
|
157
|
+
'click : leff-1' : () => console.log ( 'nothing' )
|
|
158
|
+
, 'yo' : ({msg}) => result = msg
|
|
159
|
+
}}
|
|
160
|
+
short.load ( myAllContext )
|
|
161
|
+
short.changeContext ( 'myAll' )
|
|
162
|
+
short.emit ( 'yo', { context: short.getContext(), note: 'tt', type:'custom', msg:'hello' })
|
|
163
|
+
expect ( result ).to.be.equal ( 'hello' )
|
|
164
|
+
short.changeContext ( 'general' )
|
|
165
|
+
short.unload ( 'myAll' )
|
|
166
|
+
}) // it emit custom event
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
it ( 'List shortcuts', () => {
|
|
171
|
+
short.enablePlugin ( pluginKey )
|
|
172
|
+
|
|
173
|
+
let general = short.listShortcuts ('general');
|
|
174
|
+
expect ( general ).to.be.an ( 'array' )
|
|
175
|
+
expect ( general ).to.have.lengthOf ( 2 )
|
|
176
|
+
expect ( general ).to.include ( 'KEY:A+SHIFT' )
|
|
177
|
+
|
|
178
|
+
let fail = short.listShortcuts ( 'somethingNotExisting' );
|
|
179
|
+
expect ( fail ).to.be.null
|
|
180
|
+
|
|
181
|
+
let all = short.listShortcuts ();
|
|
182
|
+
expect ( all ).to.be.an ( 'array' )
|
|
183
|
+
|
|
184
|
+
expect ( all ).to.have.lengthOf ( 4 )
|
|
185
|
+
// Property 'context' is a context name - string
|
|
186
|
+
expect ( all[0] ).to.have.property ( 'context' )
|
|
187
|
+
expect ( all[0] ).to.have.property ( 'shortcuts' )
|
|
188
|
+
expect ( all[0].shortcuts ).to.be.an ( 'array' )
|
|
189
|
+
expect ( all[0].shortcuts ).to.have.lengthOf ( 2 )
|
|
190
|
+
expect ( all[0].shortcuts ).to.include ( 'KEY:A+SHIFT' )
|
|
191
|
+
expect ( all[0].context ).to.be.equal ( 'general' )
|
|
192
|
+
}) // it list shortcuts
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
it ( 'Reset', () => {
|
|
197
|
+
short.enablePlugin ( pluginKey )
|
|
198
|
+
short.reset ()
|
|
199
|
+
expect ( short.listShortcuts () ).to.have.lengthOf ( 0 )
|
|
200
|
+
expect ( short.listShortcuts () ).to.have.lengthOf ( 0 )
|
|
201
|
+
expect ( short.getContext () ).to.be.null
|
|
202
|
+
}) // it Reset
|
|
203
|
+
|
|
297
204
|
|
|
298
205
|
}) // describe
|
|
299
206
|
|