hotkeys-rails 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +18 -0
- data/README.md +78 -0
- data/lib/generators/hotkeys_rails/install_generator.rb +15 -0
- data/lib/generators/hotkeys_rails/templates/hotkey.css +16 -0
- data/lib/generators/hotkeys_rails/templates/hotkey_controller.js +22 -0
- data/lib/hotkeys_rails/engine.rb +9 -0
- data/lib/hotkeys_rails/helper.rb +99 -0
- data/lib/hotkeys_rails/version.rb +3 -0
- data/lib/hotkeys_rails.rb +6 -0
- metadata +66 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0e144f56e44055cc18278c5250a6297519b873bde607c51b24dd5521a40f176e
|
|
4
|
+
data.tar.gz: 601a217fb719cffca22d8869eee811cf2052d3f63d45e5a46f0b94812bc8605d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 72d1774b2efa3e4c85a6fddf37729a91e16c36e455a8d8cd4e5e519d680e20ccb71515e51899f7e7cbe45321ac5baacf190b02770ae995810299060f5c8968ea
|
|
7
|
+
data.tar.gz: a96373911237b3d209f714a9088762c78cc7f7a209b4c16fdd1740d9d5647fbf7f94a5ed61a0c501ed9c4a27582ff1a6e39d7867a82526c419d23937b27bf5d5
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2024-12-02
|
|
6
|
+
|
|
7
|
+
Initial release.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `hotkey` option for `link_to`, `button_to`, and `button_tag` helpers
|
|
12
|
+
- `hotkey(*keys)` helper for explicit data attribute generation
|
|
13
|
+
- `hotkey_label(*keys)` for platform-aware keyboard shortcut labels
|
|
14
|
+
- `hotkey_hint(*keys)` for rendering `<kbd>` elements
|
|
15
|
+
- Dual binding for `:ctrl` modifier (Ctrl on Windows/Linux, Cmd on Mac)
|
|
16
|
+
- Focus action support via `hotkey(:key, action: :focus)`
|
|
17
|
+
- Rails generator for installing Stimulus controller
|
|
18
|
+
- Demo app for testing with Playwright
|
data/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Hotkeys Rails
|
|
2
|
+
|
|
3
|
+
Keyboard shortcuts for Hotwire apps. No dependencies. No configuration. Just HTML.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "hotkeys-rails"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bundle install
|
|
17
|
+
rails generate hotkeys_rails:install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```erb
|
|
23
|
+
<%= link_to "Back", root_path, hotkey: :esc %>
|
|
24
|
+
<%= button_to "New Card", cards_path, hotkey: :c %>
|
|
25
|
+
<%= button_tag "Save", hotkey: [:ctrl, :enter] %>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The `:ctrl` modifier binds both Ctrl (Windows/Linux) and Cmd (Mac).
|
|
29
|
+
|
|
30
|
+
### Visual Hints
|
|
31
|
+
|
|
32
|
+
```erb
|
|
33
|
+
<%= link_to cards_path, hotkey: :c do %>
|
|
34
|
+
Add a card <%= hotkey_hint(:c) %>
|
|
35
|
+
<% end %>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Labels for Tooltips
|
|
39
|
+
|
|
40
|
+
```erb
|
|
41
|
+
<%= button_tag "Save",
|
|
42
|
+
title: "Save (#{hotkey_label(:ctrl, :enter)})",
|
|
43
|
+
hotkey: [:ctrl, :enter] %>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Focus Instead of Click
|
|
47
|
+
|
|
48
|
+
```erb
|
|
49
|
+
<%= text_field_tag :search, data: hotkey(:f, action: :focus) %>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Works with Other Data Attributes
|
|
53
|
+
|
|
54
|
+
```erb
|
|
55
|
+
<%= link_to "Edit", edit_path,
|
|
56
|
+
hotkey: :e,
|
|
57
|
+
data: { turbo_frame: "modal" } %>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Helpers
|
|
61
|
+
|
|
62
|
+
- `hotkey(*keys)` - Returns data attributes for Stimulus controller
|
|
63
|
+
- `hotkey_label(*keys)` - Platform-aware label (⌘ on Mac, Ctrl+ elsewhere)
|
|
64
|
+
- `hotkey_hint(*keys)` - Renders `<kbd>` element with hide-on-touch class
|
|
65
|
+
|
|
66
|
+
## How It Works
|
|
67
|
+
|
|
68
|
+
This gem overrides `link_to`, `button_to`, and `button_tag` to support the `:hotkey` option. When you use `hotkey: :esc`, it extracts the option and merges the Stimulus data attributes into the element.
|
|
69
|
+
|
|
70
|
+
If you prefer explicit control, use the `hotkey()` helper directly:
|
|
71
|
+
|
|
72
|
+
```erb
|
|
73
|
+
<%= link_to "Back", root_path, data: hotkey(:esc) %>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
|
|
3
|
+
module HotkeysRails
|
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
|
5
|
+
source_root File.expand_path("templates", __dir__)
|
|
6
|
+
|
|
7
|
+
def copy_controller
|
|
8
|
+
copy_file "hotkey_controller.js", "app/javascript/controllers/hotkey_controller.js"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def copy_stylesheet
|
|
12
|
+
copy_file "hotkey.css", "app/assets/stylesheets/hotkey.css"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
kbd {
|
|
2
|
+
border: 1px solid currentColor;
|
|
3
|
+
border-radius: 0.3em;
|
|
4
|
+
box-shadow: 0 0.1em 0 currentColor;
|
|
5
|
+
font-family: ui-monospace, monospace;
|
|
6
|
+
font-size: 0.8em;
|
|
7
|
+
font-weight: 600;
|
|
8
|
+
opacity: 0.7;
|
|
9
|
+
padding: 0 0.4em;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@media (any-hover: none) {
|
|
13
|
+
.hide-on-touch {
|
|
14
|
+
display: none;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
click(event) {
|
|
5
|
+
if (this.#shouldHandle(event)) {
|
|
6
|
+
event.preventDefault()
|
|
7
|
+
this.element.click()
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
focus(event) {
|
|
12
|
+
if (this.#shouldHandle(event)) {
|
|
13
|
+
event.preventDefault()
|
|
14
|
+
this.element.focus()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#shouldHandle(event) {
|
|
19
|
+
return !event.defaultPrevented &&
|
|
20
|
+
!event.target.closest("input, textarea, [contenteditable]")
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module HotkeysRails
|
|
2
|
+
module Helper
|
|
3
|
+
# Returns data attributes for Stimulus hotkey controller
|
|
4
|
+
#
|
|
5
|
+
# hotkey(:esc)
|
|
6
|
+
# # => { controller: "hotkey", action: "keydown.esc@document->hotkey#click" }
|
|
7
|
+
#
|
|
8
|
+
# hotkey(:ctrl, :enter)
|
|
9
|
+
# # => { controller: "hotkey", action: "keydown.ctrl+enter@document->hotkey#click keydown.meta+enter@document->hotkey#click" }
|
|
10
|
+
#
|
|
11
|
+
def hotkey(*keys, action: :click)
|
|
12
|
+
keys = keys.flatten.map(&:to_s)
|
|
13
|
+
|
|
14
|
+
actions = if keys.include?("ctrl")
|
|
15
|
+
chord = keys.join("+")
|
|
16
|
+
meta_chord = keys.map { |k| k == "ctrl" ? "meta" : k }.join("+")
|
|
17
|
+
"keydown.#{chord}@document->hotkey##{action} keydown.#{meta_chord}@document->hotkey##{action}"
|
|
18
|
+
else
|
|
19
|
+
"keydown.#{keys.join("+")}@document->hotkey##{action}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
{ controller: "hotkey", action: actions }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Platform-aware label for keyboard shortcuts
|
|
26
|
+
#
|
|
27
|
+
# hotkey_label(:ctrl, :enter)
|
|
28
|
+
# # => "⌘Return" on Mac, "Ctrl+Enter" elsewhere
|
|
29
|
+
#
|
|
30
|
+
def hotkey_label(*keys)
|
|
31
|
+
keys.flatten.map do |key|
|
|
32
|
+
case key.to_s
|
|
33
|
+
when "ctrl" then mac? ? "⌘" : "Ctrl+"
|
|
34
|
+
when "meta" then mac? ? "⌘" : "Win+"
|
|
35
|
+
when "alt" then mac? ? "⌥" : "Alt+"
|
|
36
|
+
when "shift" then mac? ? "⇧" : "Shift+"
|
|
37
|
+
when "enter" then mac? ? "Return" : "Enter"
|
|
38
|
+
when "esc" then "Esc"
|
|
39
|
+
else key.to_s.upcase
|
|
40
|
+
end
|
|
41
|
+
# Mac symbols (⌘⌥⇧) don't need + separator, Windows modifiers do (Ctrl+, Alt+, Shift+)
|
|
42
|
+
# gsub removes trailing + from Mac symbols: "⌘+" -> "⌘"
|
|
43
|
+
end.join.gsub(/[⌘⌥⇧]\+/, &:chop)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Renders <kbd> element with hide-on-touch class
|
|
47
|
+
#
|
|
48
|
+
# hotkey_hint(:ctrl, :s)
|
|
49
|
+
# # => <kbd class="hide-on-touch">⌘S</kbd>
|
|
50
|
+
#
|
|
51
|
+
def hotkey_hint(*keys)
|
|
52
|
+
content_tag(:kbd, hotkey_label(*keys), class: "hide-on-touch")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def link_to(name = nil, options = nil, html_options = nil, &block)
|
|
56
|
+
if block_given?
|
|
57
|
+
# link_to(url, html_options) { content }
|
|
58
|
+
html_options = extract_hotkey_option(options)
|
|
59
|
+
super(name, html_options, &block)
|
|
60
|
+
else
|
|
61
|
+
# link_to(name, url, html_options)
|
|
62
|
+
html_options = extract_hotkey_option(html_options)
|
|
63
|
+
super(name, options, html_options)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def button_to(name = nil, options = nil, html_options = nil, &block)
|
|
68
|
+
html_options = extract_hotkey_option(html_options)
|
|
69
|
+
super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def button_tag(content_or_options = nil, options = nil, &block)
|
|
73
|
+
if content_or_options.is_a?(Hash)
|
|
74
|
+
options = extract_hotkey_option(content_or_options)
|
|
75
|
+
super(nil, options, &block)
|
|
76
|
+
else
|
|
77
|
+
options = extract_hotkey_option(options)
|
|
78
|
+
super(content_or_options, options, &block)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def extract_hotkey_option(html_options)
|
|
85
|
+
return {} if html_options.nil?
|
|
86
|
+
html_options = html_options.dup
|
|
87
|
+
|
|
88
|
+
if hotkey_keys = html_options.delete(:hotkey)
|
|
89
|
+
html_options[:data] = (html_options[:data] || {}).merge(hotkey(*Array(hotkey_keys)))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
html_options
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def mac?
|
|
96
|
+
request.user_agent.to_s.include?("Mac")
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: hotkeys-rails
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Kieran Klaassen
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
description: No dependencies. No configuration. Just HTML.
|
|
27
|
+
email:
|
|
28
|
+
- kieran@kieranklaassen.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- CHANGELOG.md
|
|
34
|
+
- README.md
|
|
35
|
+
- lib/generators/hotkeys_rails/install_generator.rb
|
|
36
|
+
- lib/generators/hotkeys_rails/templates/hotkey.css
|
|
37
|
+
- lib/generators/hotkeys_rails/templates/hotkey_controller.js
|
|
38
|
+
- lib/hotkeys_rails.rb
|
|
39
|
+
- lib/hotkeys_rails/engine.rb
|
|
40
|
+
- lib/hotkeys_rails/helper.rb
|
|
41
|
+
- lib/hotkeys_rails/version.rb
|
|
42
|
+
homepage: https://github.com/kieranklaassen/hotkeys-rails
|
|
43
|
+
licenses:
|
|
44
|
+
- MIT
|
|
45
|
+
metadata:
|
|
46
|
+
homepage_uri: https://github.com/kieranklaassen/hotkeys-rails
|
|
47
|
+
source_code_uri: https://github.com/kieranklaassen/hotkeys-rails
|
|
48
|
+
changelog_uri: https://github.com/kieranklaassen/hotkeys-rails/blob/main/CHANGELOG.md
|
|
49
|
+
rdoc_options: []
|
|
50
|
+
require_paths:
|
|
51
|
+
- lib
|
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '3.1'
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
requirements: []
|
|
63
|
+
rubygems_version: 3.6.9
|
|
64
|
+
specification_version: 4
|
|
65
|
+
summary: Keyboard shortcuts for Hotwire apps
|
|
66
|
+
test_files: []
|