Keyboard shortcuts - #390
Conversation
This way it's handled in one central place, and it reduces the number of event listeners added when we have multiple shortcuts on one page.
This also fixes the arrow, such that it's slightly pushed in to avoid a gap between it and the rounded edges of the tooltip body.
WalkthroughThe PR adds a shortcut-mode system with provider state, keyboard tracking, badges, tooltips, and shortcut triggers. Buttons accept typed hotkey configurations. Event editors, painting forms, navigation controls, attendee actions, header links, event selection, and sharing now expose keyboard shortcuts. Desktop and mobile controls use separate shortcut behavior. Mobile detection controls shortcut activation and drawer rendering. The share menu now uses an action button for link copying. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 01066e22-bcbd-4e78-aafc-cbdd14827ae8
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (30)
frontend/package.jsonfrontend/src/app/(event)/[event-code]/page-client.tsxfrontend/src/app/(event)/[event-code]/painting/page-client.tsxfrontend/src/app/layout.tsxfrontend/src/components/copy-toast-button.tsxfrontend/src/components/text-input-field.tsxfrontend/src/features/button/components/base.tsxfrontend/src/features/button/props.tsfrontend/src/features/dashboard/components/event-grid.tsxfrontend/src/features/event/components/selectors/timezone.tsxfrontend/src/features/event/editor/advanced-options.tsxfrontend/src/features/event/editor/date-range/selector.tsxfrontend/src/features/event/editor/editor.tsxfrontend/src/features/event/grid/schedule-header.tsxfrontend/src/features/event/results/attendees/panel-header.tsxfrontend/src/features/event/results/attendees/remove-participant.tsxfrontend/src/features/event/results/components/display-settings.tsxfrontend/src/features/header/components/buttons/dashboard.tsxfrontend/src/features/header/components/buttons/new-event.tsxfrontend/src/features/share-menu/content.tsxfrontend/src/features/system-feedback/hotkeys/components/hotkey-badge.tsxfrontend/src/features/system-feedback/hotkeys/components/shortcut-mode-indicator.tsxfrontend/src/features/system-feedback/hotkeys/components/shortcut-tooltip.tsxfrontend/src/features/system-feedback/hotkeys/components/shortcut-trigger.tsxfrontend/src/features/system-feedback/hotkeys/constants.tsfrontend/src/features/system-feedback/hotkeys/context.tsfrontend/src/features/system-feedback/hotkeys/provider.tsxfrontend/src/features/system-feedback/tooltip/base.tsxfrontend/src/lib/providers.tsxfrontend/src/lib/utils/is-apple-os.ts
💤 Files with no reviewable changes (1)
- frontend/src/components/copy-toast-button.tsx
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b6773585-d801-47c9-84d9-4cd022d1a51b
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (12)
frontend/package.jsonfrontend/src/app/(event)/[event-code]/painting/page-client.tsxfrontend/src/components/text-input-field.tsxfrontend/src/features/button/components/base.tsxfrontend/src/features/event/editor/advanced-options.tsxfrontend/src/features/event/editor/date-range/selector.tsxfrontend/src/features/event/editor/editor.tsxfrontend/src/features/system-feedback/hotkeys/components/hotkey-badge.tsxfrontend/src/features/system-feedback/hotkeys/components/shortcut-mode-indicator.tsxfrontend/src/features/system-feedback/hotkeys/components/shortcut-trigger.tsxfrontend/src/features/system-feedback/hotkeys/provider.tsxfrontend/src/lib/providers.tsx
💤 Files with no reviewable changes (3)
- frontend/src/components/text-input-field.tsx
- frontend/src/app/(event)/[event-code]/painting/page-client.tsx
- frontend/src/features/event/editor/editor.tsx
This PR introduces keyboard shortcuts to the site, which not only empowers power users but also makes the site more accessible.
Hotkeys and Shortcuts
On our site, we have "hotkeys" and "shortcuts". The former is a key combination that can always be activated, while the latter is only available during "Shortcut Mode".
Shortcut Mode is triggered with "Ctrl/Cmd+K", and it enables tooltips across the page denoting which elements/buttons have shortcuts. Pressing one of those keys will trigger the action and deactivate Shortcut Mode.
Both hotkeys and shortcuts are disabled on the mobile interface. You could make an argument that someone might use a narrow window on desktop, but I don't think there's enough people like that to justify figuring out a separate mobile layout for the tooltips.
Confirmation Skipping
When removing participants, you can now hold shift to skip the confirmation. This is also explained in the confirmation dialog.
Affected Pages/Components
New Components
HotkeyBadge- Displays a set of keys required to activate a hotkey. I had some fun with it and made the keys visibly "press" when you press the corresponding key on your keyboard.classNameprops for the keys when they are pressed or not.ShortcutTooltip- A tooltip that displays aHotkeyBadgewhen Shortcut Mode is active.ShortcutTrigger- A component that, when the assigned key combination is pressed, activates either its provided action or a click and focus on its child.selectorprop can be specified to isolate a specific element within the trigger, so you're still able to position the tooltip where you wish while avoiding messing with internal component implementations.ShortcutModeIndicator- When Shortcut Mode is active, this is displayed on the bottom middle of the screen.New Context
A new context called
ShortcutsContexthandlesHotkeyBadgekey presses and Shortcut Mode activation in a centralized place.Button Integration
Hotkeys were integrated into our buttons. In the
hotkeyprop, you can specify properties such as the key combination, how it's displayed (always on the button, in a tooltip, etc.), and if it's a shortcut or not.Hotkeys are supported on all types of buttons, calling the
onClickon action and empty buttons, and pushing the specified route on link buttons.The hotkey badge, when displayed on the button, has custom styling for each button theme.
Tooltip Updates
To better support shortcuts, the
Tooltipcomponent now has support for a controlled open state, collision allowance, and displaying on all 4 sides.Because of the rounded corners, I had to move the arrow into the tooltip body by a single pixel, which is basically unnoticeable.
Text Field Auto Focus
The
autoFocusprop was added toTextInputField, which focuses the text field on page load (on desktop only). This follows the theme of making the site more keyboard-accessible by starting the focus within the content, and it also encourages users to fill out the text first before anything else.This feature was added to the event name and display name fields.
Escape Keystroke Consumption Fix
On the results page, escape key presses would do nothing because the mobile results drawer was intercepting the event. This means you couldn't press escape to close a dropdown. The fix for this was conditionally mounting the mobile results drawer only when the screen was narrow enough.
New Package
The
react-hotkeys-hookpackage was added to avoid reinventing the wheel. It handles hotkey activation with many options for customization and a robust system to map hotkey definitions to actual keys.