Skip to content

Commit 051fe20

Browse files
authored
fix!: remove legacy modifier implementations (#783)
BREAKING CHANGE: `{ctrl}`, `{del}`, `{esc}` no longer describe a key. Use `{Control}`, `{Delete}`, `{Escape}` instead. BREAKING CHANGE: `{alt}`, `{ctrl}`, `{meta}`, `{shift}` no longer imply not releasing the key. Use `{Alt>}`, `{Control>}`, `{Meta>}`, `{Shift>}` instead.
1 parent d598fb6 commit 051fe20

File tree

3 files changed

+50
-91
lines changed

3 files changed

+50
-91
lines changed

src/keyboard/getNextKeyDef.ts

+2-28
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
11
import {readNextDescriptor} from '../utils'
22
import {keyboardKey, keyboardOptions} from './types'
33

4-
enum legacyModifiers {
5-
'alt' = 'alt',
6-
'ctrl' = 'ctrl',
7-
'meta' = 'meta',
8-
'shift' = 'shift',
9-
}
10-
11-
enum legacyKeyMap {
12-
ctrl = 'Control',
13-
del = 'Delete',
14-
esc = 'Escape',
15-
space = ' ',
16-
}
17-
184
/**
195
* Get the next key from keyMap
206
*
@@ -24,7 +10,6 @@ enum legacyKeyMap {
2410
* Keeping the key pressed can be written as `{key>}`.
2511
* When keeping the key pressed you can choose how long (how many keydown and keypress) the key is pressed `{key>3}`.
2612
* You can then release the key per `{key>3/}` or keep it pressed and continue with the next key.
27-
* Modifiers like `{shift}` imply being kept pressed. This can be turned of per `{shift/}`.
2813
*/
2914
export function getNextKeyDef(
3015
text: string,
@@ -41,18 +26,15 @@ export function getNextKeyDef(
4126
descriptor,
4227
consumedLength,
4328
releasePrevious,
44-
releaseSelf = !(
45-
type === '{' && getEnumValue(legacyModifiers, descriptor.toLowerCase())
46-
),
29+
releaseSelf = true,
4730
repeat,
4831
} = readNextDescriptor(text)
4932

5033
const keyDef = options.keyboardMap.find(def => {
5134
if (type === '[') {
5235
return def.code?.toLowerCase() === descriptor.toLowerCase()
5336
} else if (type === '{') {
54-
const key = mapLegacyKey(descriptor)
55-
return def.key?.toLowerCase() === key.toLowerCase()
37+
return def.key?.toLowerCase() === descriptor.toLowerCase()
5638
}
5739
return def.key === descriptor
5840
}) ?? {
@@ -69,11 +51,3 @@ export function getNextKeyDef(
6951
repeat,
7052
}
7153
}
72-
73-
function getEnumValue<T>(f: Record<string, T>, key: string): T | undefined {
74-
return f[key]
75-
}
76-
77-
function mapLegacyKey(descriptor: string) {
78-
return getEnumValue(legacyKeyMap, descriptor) ?? descriptor
79-
}

tests/keyboard/getNextKeyDef.ts

-9
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ cases(
3737
'unimplemented code': {text: '[Foo]', key: 'Unknown', code: 'Foo'},
3838
key: {text: '{Control}', key: 'Control', code: 'ControlLeft'},
3939
'unimplemented key': {text: '{Foo}', key: 'Foo', code: 'Unknown'},
40-
'legacy modifier': {text: '{ctrl}', key: 'Control', code: 'ControlLeft'},
4140
'printable character': {text: 'a', key: 'a', code: 'KeyA'},
4241
'modifiers as printable characters': {text: '/', key: '/', code: 'Unknown'},
4342
'{ as printable': {text: '{{', key: '{', code: 'Unknown'},
@@ -85,14 +84,6 @@ cases(
8584
text: '{Control>2/}',
8685
modifiers: {releaseSelf: true},
8786
},
88-
'no releaseSelf on legacy modifier': {
89-
text: '{ctrl}',
90-
modifiers: {releaseSelf: false},
91-
},
92-
'release legacy modifier': {
93-
text: '{ctrl/}',
94-
modifiers: {releaseSelf: true},
95-
},
9687
},
9788
)
9889

tests/type/modifiers.js

+48-54
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
import userEvent from '#src'
22
import {setup} from '#testHelpers/utils'
33

4-
// Note, use the setup function at the bottom of the file...
5-
// but don't hurt yourself trying to read it 😅
6-
7-
// keep in mind that we do not handle modifier interactions. This is primarily
8-
// because modifiers behave differently on different operating systems.
9-
// For example: {alt}{backspace}{/alt} will remove everything from the current
10-
// cursor position to the beginning of the word on Mac, but you need to use
11-
// {ctrl}{backspace}{/ctrl} to do that on Windows. And that doesn't appear to
12-
// be consistent within an OS either 🙃
13-
// So we're not going to even try.
14-
15-
// This also means that '{shift}a' will fire an input event with the shiftKey,
16-
// but will not capitalize "a".
17-
18-
test('{esc} triggers typing the escape character', () => {
4+
// This test suite contains a lot of legacy code.
5+
// A lot of tests performed here could be skipped
6+
// as the current keyboard implementation merged different previous implementations
7+
// that needed to be tested seperately.
8+
// What will be left should be moved into keyboard/plugins.
9+
// Keeping these for now to demonstrate changes.
10+
// TODO: clean up this test suite
11+
12+
test('{escape} triggers typing the escape character', () => {
1913
const {element, getEventSnapshot} = setup('<input />')
2014

21-
userEvent.type(element, '{esc}')
15+
userEvent.type(element, '{escape}')
2216

2317
expect(getEventSnapshot()).toMatchInlineSnapshot(`
2418
Events fired on: input[value=""]
@@ -231,10 +225,10 @@ test('{backspace} on an input type that does not support selection ranges', () =
231225
expect(element).toHaveValue('[email protected]')
232226
})
233227

234-
test('{alt}a{/alt}', () => {
228+
test('{alt>}a{/alt}', () => {
235229
const {element, getEventSnapshot} = setup('<input />')
236230

237-
userEvent.type(element, '{alt}a{/alt}')
231+
userEvent.type(element, '{alt>}a{/alt}')
238232

239233
expect(getEventSnapshot()).toMatchInlineSnapshot(`
240234
Events fired on: input[value=""]
@@ -259,10 +253,10 @@ test('{alt}a{/alt}', () => {
259253
`)
260254
})
261255

262-
test('{meta}a{/meta}', () => {
256+
test('{meta>}a{/meta}', () => {
263257
const {element, getEventSnapshot} = setup('<input />')
264258

265-
userEvent.type(element, '{meta}a{/meta}')
259+
userEvent.type(element, '{meta>}a{/meta}')
266260

267261
expect(getEventSnapshot()).toMatchInlineSnapshot(`
268262
Events fired on: input[value="a"]
@@ -289,10 +283,10 @@ test('{meta}a{/meta}', () => {
289283
`)
290284
})
291285

292-
test('{ctrl}a{/ctrl}', () => {
286+
test('{control>}a{/control}', () => {
293287
const {element, getEventSnapshot} = setup('<input />')
294288

295-
userEvent.type(element, '{ctrl}a{/ctrl}')
289+
userEvent.type(element, '{control>}a{/control}')
296290

297291
expect(getEventSnapshot()).toMatchInlineSnapshot(`
298292
Events fired on: input[value=""]
@@ -317,10 +311,10 @@ test('{ctrl}a{/ctrl}', () => {
317311
`)
318312
})
319313

320-
test('{shift}a{/shift}', () => {
314+
test('{shift>}a{/shift}', () => {
321315
const {element, getEventSnapshot} = setup('<input />')
322316

323-
userEvent.type(element, '{shift}a{/shift}')
317+
userEvent.type(element, '{shift>}a{/shift}')
324318

325319
expect(getEventSnapshot()).toMatchInlineSnapshot(`
326320
Events fired on: input[value="a"]
@@ -530,10 +524,10 @@ test('{enter} on a button when keypress calls prevent default', () => {
530524
`)
531525
})
532526

533-
test('{space} on a button', () => {
527+
test('[space] on a button', () => {
534528
const {element, getEventSnapshot} = setup('<button />')
535529

536-
userEvent.type(element, '{space}')
530+
userEvent.type(element, '[space]')
537531

538532
expect(getEventSnapshot()).toMatchInlineSnapshot(`
539533
Events fired on: button
@@ -558,7 +552,7 @@ test('{space} on a button', () => {
558552
`)
559553
})
560554

561-
test(`' ' on a button is the same as '{space}'`, () => {
555+
test(`' ' on a button is the same as '[space]'`, () => {
562556
const {element, getEventSnapshot} = setup('<button />')
563557

564558
userEvent.type(element, ' ')
@@ -586,14 +580,14 @@ test(`' ' on a button is the same as '{space}'`, () => {
586580
`)
587581
})
588582

589-
test('{space} with preventDefault keydown on button', () => {
583+
test('[space] with preventDefault keydown on button', () => {
590584
const {element, getEventSnapshot} = setup('<button />', {
591585
eventHandlers: {
592586
keyDown: e => e.preventDefault(),
593587
},
594588
})
595589

596-
userEvent.type(element, '{space}')
590+
userEvent.type(element, '[space]')
597591

598592
expect(getEventSnapshot()).toMatchInlineSnapshot(`
599593
Events fired on: button
@@ -616,14 +610,14 @@ test('{space} with preventDefault keydown on button', () => {
616610
`)
617611
})
618612

619-
test('{space} with preventDefault keyup on button', () => {
613+
test('[space] with preventDefault keyup on button', () => {
620614
const {element, getEventSnapshot} = setup('<button />', {
621615
eventHandlers: {
622616
keyUp: e => e.preventDefault(),
623617
},
624618
})
625619

626-
userEvent.type(element, '{space}')
620+
userEvent.type(element, '[space]')
627621

628622
expect(getEventSnapshot()).toMatchInlineSnapshot(`
629623
Events fired on: button
@@ -647,10 +641,10 @@ test('{space} with preventDefault keyup on button', () => {
647641
`)
648642
})
649643

650-
test('{space} on an input', () => {
644+
test('[space] on an input', () => {
651645
const {element, getEventSnapshot} = setup(`<input value="" />`)
652646

653-
userEvent.type(element, '{space}')
647+
userEvent.type(element, '[space]')
654648

655649
expect(getEventSnapshot()).toMatchInlineSnapshot(`
656650
Events fired on: input[value=" "]
@@ -705,12 +699,12 @@ test('{enter} on an input type="color" fires same events as a button', () => {
705699
`)
706700
})
707701

708-
test('{space} on an input type="color" fires same events as a button', () => {
702+
test('[space] on an input type="color" fires same events as a button', () => {
709703
const {element, getEventSnapshot} = setup(
710704
`<input value="#ffffff" type="color" />`,
711705
)
712706

713-
userEvent.type(element, '{space}')
707+
userEvent.type(element, '[space]')
714708

715709
expect(getEventSnapshot()).toMatchInlineSnapshot(`
716710
Events fired on: input[value="#ffffff"]
@@ -735,7 +729,7 @@ test('{space} on an input type="color" fires same events as a button', () => {
735729
`)
736730
})
737731

738-
test(`' ' on input type="color" is the same as '{space}'`, () => {
732+
test(`' ' on input type="color" is the same as '[space]'`, () => {
739733
const {element, getEventSnapshot} = setup(
740734
`<input value="#ffffff" type="color" />`,
741735
)
@@ -850,10 +844,10 @@ test('{enter} on a textarea when keypress calls prevent default', () => {
850844
`)
851845
})
852846

853-
test('{meta}{enter}{/meta} on a button', () => {
847+
test('{meta>}{enter}{/meta} on a button', () => {
854848
const {element, getEventSnapshot} = setup('<button />')
855849

856-
userEvent.type(element, '{meta}{enter}{/meta}')
850+
userEvent.type(element, '{meta>}{enter}{/meta}')
857851

858852
expect(getEventSnapshot()).toMatchInlineSnapshot(`
859853
Events fired on: button
@@ -880,10 +874,10 @@ test('{meta}{enter}{/meta} on a button', () => {
880874
`)
881875
})
882876

883-
test('{meta}{alt}{ctrl}a{/ctrl}{/alt}{/meta}', () => {
877+
test('{meta>}{alt>}{control>}a{/control}{/alt}{/meta}', () => {
884878
const {element, getEventSnapshot} = setup('<input />')
885879

886-
userEvent.type(element, '{meta}{alt}{ctrl}a{/ctrl}{/alt}{/meta}')
880+
userEvent.type(element, '{meta>}{alt>}{control>}a{/control}{/alt}{/meta}')
887881

888882
expect(getEventSnapshot()).toMatchInlineSnapshot(`
889883
Events fired on: input[value=""]
@@ -912,10 +906,10 @@ test('{meta}{alt}{ctrl}a{/ctrl}{/alt}{/meta}', () => {
912906
`)
913907
})
914908

915-
test('{del} at the start of the input', () => {
909+
test('{delete} at the start of the input', () => {
916910
const {element, getEventSnapshot} = setup(`<input value="hello" />`)
917911

918-
userEvent.type(element, '{del}', {
912+
userEvent.type(element, '{delete}', {
919913
initialSelectionStart: 0,
920914
initialSelectionEnd: 0,
921915
})
@@ -947,10 +941,10 @@ test('{del} at the start of the input', () => {
947941
`)
948942
})
949943

950-
test('{del} at end of the input', () => {
944+
test('{delete} at end of the input', () => {
951945
const {element, getEventSnapshot} = setup(`<input value="hello" />`)
952946

953-
userEvent.type(element, '{del}')
947+
userEvent.type(element, '{delete}')
954948

955949
expect(element.selectionStart).toBe(element.value.length)
956950
expect(element.selectionEnd).toBe(element.value.length)
@@ -976,10 +970,10 @@ test('{del} at end of the input', () => {
976970
`)
977971
})
978972

979-
test('{del} in the middle of the input', () => {
973+
test('{delete} in the middle of the input', () => {
980974
const {element, getEventSnapshot} = setup(`<input value="hello" />`)
981975

982-
userEvent.type(element, '{del}', {
976+
userEvent.type(element, '{delete}', {
983977
initialSelectionStart: 2,
984978
initialSelectionEnd: 2,
985979
})
@@ -1011,10 +1005,10 @@ test('{del} in the middle of the input', () => {
10111005
`)
10121006
})
10131007

1014-
test('{del} with a selection range', () => {
1008+
test('{delete} with a selection range', () => {
10151009
const {element, getEventSnapshot} = setup(`<input value="hello" />`)
10161010

1017-
userEvent.type(element, '{del}', {
1011+
userEvent.type(element, '{delete}', {
10181012
initialSelectionStart: 1,
10191013
initialSelectionEnd: 3,
10201014
})
@@ -1049,20 +1043,20 @@ test('{del} with a selection range', () => {
10491043
// TODO: eventually we'll want to support this, but currently we cannot
10501044
// because selection ranges are (intentially) unsupported in certain input types
10511045
// per the spec.
1052-
test('{del} on an input that does not support selection range does not change the value', () => {
1046+
test('{delete} on an input that does not support selection range does not change the value', () => {
10531047
const {element, eventWasFired} = setup(`<input type="email" value="[email protected]" />`)
10541048

1055-
userEvent.type(element, '{del}')
1049+
userEvent.type(element, '{delete}')
10561050
expect(element).toHaveValue('[email protected]')
10571051
expect(eventWasFired('input')).not.toBe(true)
10581052
})
10591053

1060-
test('{del} does not delete if keydown is prevented', () => {
1054+
test('{delete} does not delete if keydown is prevented', () => {
10611055
const {element, eventWasFired} = setup(`<input value="hello" />`, {
10621056
eventHandlers: {keyDown: e => e.preventDefault()},
10631057
})
10641058

1065-
userEvent.type(element, '{del}', {
1059+
userEvent.type(element, '{delete}', {
10661060
initialSelectionStart: 2,
10671061
initialSelectionEnd: 2,
10681062
})
@@ -1075,7 +1069,7 @@ test('{del} does not delete if keydown is prevented', () => {
10751069
test('any remaining type modifiers are automatically released at the end', () => {
10761070
const {element, getEventSnapshot} = setup('<input />')
10771071

1078-
userEvent.type(element, '{meta}{alt}{ctrl}a{/alt}')
1072+
userEvent.type(element, '{meta>}{alt>}{control>}a{/alt}')
10791073

10801074
expect(getEventSnapshot()).toMatchInlineSnapshot(`
10811075
Events fired on: input[value=""]
@@ -1107,7 +1101,7 @@ test('any remaining type modifiers are automatically released at the end', () =>
11071101
test('modifiers will not be closed if skipAutoClose is enabled', () => {
11081102
const {element, getEventSnapshot} = setup('<input />')
11091103

1110-
userEvent.type(element, '{meta}a', {skipAutoClose: true})
1104+
userEvent.type(element, '{meta>}a', {skipAutoClose: true})
11111105

11121106
expect(getEventSnapshot()).toMatchInlineSnapshot(`
11131107
Events fired on: input[value="a"]

0 commit comments

Comments
 (0)