WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 5ae7b85

Browse files
committed
Add system-modifier key-combo listeners
1 parent fce2f94 commit 5ae7b85

File tree

6 files changed

+49
-7
lines changed

6 files changed

+49
-7
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
1414

1515
**From CDN:** Add the following script to the end of your `<head>` section.
1616
```html
17-
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected].1/dist/alpine.js" defer></script>
17+
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected].2/dist/alpine.js" defer></script>
1818
```
1919

2020
That's it. It will initialize itself.
@@ -234,6 +234,8 @@ You can specify specific keys to listen for using keydown modifiers appended to
234234

235235
Examples: `enter`, `escape`, `arrow-up`, `arrow-down`
236236

237+
> Note: You can also listen for system-modifier key combinations like: `x-on:keydown.cmd.enter="foo"`
238+
237239
**`.away` modifier**
238240

239241
**Example:** `<div x-on:click.away="showModal = false"></div>`

dist/alpine.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/alpine.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"main": "dist/alpine.js",
33
"name": "alpinejs",
4-
"version": "1.8.1",
4+
"version": "1.8.2",
55
"repository": {
66
"type": "git",
77
"url": "git://github.com/alpinejs/alpine.git"

src/component.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,28 @@ export default class Component {
294294
? window : (modifiers.includes('document') ? document : el)
295295

296296
const handler = e => {
297-
const modifiersWithoutWindowOrDocument = modifiers
298-
.filter(i => i !== 'window').filter(i => i !== 'document')
297+
const keyModifiers = modifiers.filter(i => i !== 'window').filter(i => i !== 'document')
299298

300-
if (event === 'keydown' && modifiersWithoutWindowOrDocument.length > 0 && ! modifiersWithoutWindowOrDocument.includes(keyToModifier(e.key))) return
299+
// The user is scoping the keydown listener to a specific key using modifiers.
300+
if (event === 'keydown' && keyModifiers.length > 0) {
301+
// The user is listening for a specific key.
302+
if (keyModifiers.length === 1 && ! keyModifiers.includes(keyToModifier(e.key))) return
303+
304+
// The user is listening for key combinations.
305+
const systemKeyModifiers = ['ctrl', 'shift', 'alt', 'meta', 'cmd', 'super']
306+
const selectedSystemKeyModifiers = systemKeyModifiers.filter(modifier => keyModifiers.includes(modifier))
307+
308+
if (selectedSystemKeyModifiers.length > 0) {
309+
const activelyPressedKeyModifiers = selectedSystemKeyModifiers.filter(modifier => {
310+
// Alias "cmd" and "super" to "meta"
311+
if (modifier === 'cmd' || modifier === 'super') modifier = 'meta'
312+
313+
return e[`${modifier}Key`]
314+
})
315+
316+
if (activelyPressedKeyModifiers.length === 0) return
317+
}
318+
}
301319

302320
if (modifiers.includes('prevent')) e.preventDefault()
303321
if (modifiers.includes('stop')) e.stopPropagation()

test/on.spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,28 @@ test('keydown modifiers', async () => {
169169
await wait(() => { expect(document.querySelector('span').innerText).toEqual(7) })
170170
})
171171

172+
test('keydown combo modifiers', async () => {
173+
document.body.innerHTML = `
174+
<div x-data="{ count: 0 }">
175+
<input type="text" x-on:keydown.cmd.enter="count++">
176+
177+
<span x-text="count"></span>
178+
</div>
179+
`
180+
181+
Alpine.start()
182+
183+
expect(document.querySelector('span').innerText).toEqual(0)
184+
185+
fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' })
186+
187+
await wait(() => { expect(document.querySelector('span').innerText).toEqual(0) })
188+
189+
fireEvent.keyDown(document.querySelector('input'), { key: 'Enter', metaKey: true })
190+
191+
await wait(() => { expect(document.querySelector('span').innerText).toEqual(1) })
192+
})
193+
172194
test('click away', async () => {
173195
// Because jsDom doesn't support .offsetHeight and offsetWidth, we have to
174196
// make our own implementation using a specific class added to the class. Ugh.

0 commit comments

Comments
 (0)