Releases: greena13/react-hotkeys
v2.0.0
This release represents a complete re-write of the internals and much of the interface of react-hotkeys
. Mousetrap has been removed as a dependency, and instead react-hotkeys
works on the top of the React SyntheticEvent
events system.
Upgrading from v1.*?
This release is the same as the
v2.0.0-pre9
and these release notes contain a summary of the changes moving from v1.* tov2.0.0
.Upgrading from v2.0.0-pre*?
Ignore this set of release notes, and follow the notes for each each pre-release starting from the version you are using, up to
v2.0.0-pre9
.
Breaking Changes
__mousetrap__ is no longer available
Rather unsurprisingly, with the removal of Mousetrap, it's no longer possible to access the private Mousetrap instance to configure it. Many of the use-cases for needing to do so have been covered by API updates described below. If your use-case is not covered, however, please create a new issue.
HotKeyMapMixin has been removed
This was an internal part of react-hotkeys
and is no longer used, and so it does not makes sense to continue to provide it.
FocusTrap has been removed
Similar to HotKeyMapMixin
, this was an internal part of react-hotkeys
and is no longer used, and so it does not makes sense to continue to provide it.
withHotKeys has been replaced
The old withHotKeys
function has been repurposed and should not be used in the same way the old one was (more on this later). The old implementation is still available as deprecatedWithHotKeys
, but it is no longer officially supported and will be removed in future versions.
Before:
import {withHotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
withHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
After (suggested):
You can write your own function or HoC that supplies the same keyMap to a component passed to it.
import {HotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
function withActions(keyMap, Component) {
return function(props) {
return(
<HotKeys keyMap={keyMap}>
<Component {...props} />
</HotKeys>
);
}
}
deprecatedWithHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
After (to restore old behaviour):
import {deprecatedWithHotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
deprecatedWithHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
focused and attach props hav been removed
The focused
and attach
props were introduced as a way to bind keymaps that were either always active, or available outside of the React application. They are no longer needed with the introduction of GlobalHotkeys
.
Before:
import {HotKeys} from 'react-hotkeys';
<HotKeys focused={true} attach={document} keyMap={keyMap} handlers={handlers}>
<div>
My content
</div>
</HotKeys>
After:
import {GlobalHotKeys} from 'react-hotkeys';
<GlobalHotKeys keyMap={keyMap} handlers={handlers} />
<div>
My content
</div>
Hard sequences are deprecated and turned off by default
Hard sequences (handlers associated to actions with names that are valid key sequence strings that implicitly define actions that are matched by the corresponding key sequence) are now deprecated and turned off by default. They can be re-enabled (at a performance penalty) using the enableHardSequences
configuration option:
import {configure} from 'react-hotkeys';
configure({
enableHardSequences: true
});
Default key event is now always keydown
react-hotkeys
used to rely on the implicit behaviour of Mousetrap to guess the best key event based on the keys involved (this was, roughly speaking, keydown
for non-modifier keys and keypress
for modifier keys). Now by default, react-hotkeys
will match hotkey sequences on the keydown
event (or, more precisely: on the keydown
event of the last key to complete the last combination in a sequence).
If you want to trigger a single action on a different key event, you can use the object syntax and the action
attribute to explicitly set which key event you wish to bind to:
const keyMap = {
CONTRACT: 'alt+down',
COMMAND_DOWN: {sequence: 'command', action: 'keydown'},
};
If you want to change the default key event for all hotkeys, you can use the defaultKeyEvent
option of the configuration API.
Keypress events are now simulated for modifier keys
Before, you had to rely on Mousetrap guessing the best key event for your key combination (unless you explicitly defined an event) and if you bound to a key combination to a keypress event, it did not work (the browser does not emit these events for modifier keys).
react-hotkeys
now simulates these events internally (they aren't emitted to the rest of your React components) so you do not have to worry about if your key combination includes a modifier key when binding to keypress.
This shouldn't affect most library consumers, but is listed as a breaking change as it can conceivably cause different behaviour for the same application code.
stopPropagation() is now observed
Because react-hotkeys
now uses the React event system, event.stopPropagation()
now works as expected. If you have event listeners in your React application that call event.stopPropagation()
before the event reaches a <HotKeys />
or <GlobalHotkeys />
component that has a keyMap
prop, react-hotkeys
never sees it.
If you want to hide that a key has been pressed at all, you will need to capture all 3 of the keydown
, keypress
and keyup
events.
Key events from input, select and textarea tags are ignored by default
If you were ignoring key events from certain inputs by overriding the stopCallback
function on mousetrap as has been previously suggested, you no longer need to.
By default, all key events that originate from <input>
, <select>
or <textarea>
, or have a isContentEditable
attribute of true
are ignored by react-hotkeys
.
If this is not what you want for your application, you can modify the list of tags using the ignoreTags
configuration option or if you need additional control, you can specify a brand new function using the ignoreEventsCondition
configuration option.
Before:
const mousetrap = this.hotKeys.__mousetrap__;
mousetrap.__proto__.stopCallback = (e, element) => {
// Your custom logic here
};
After:
(After you've confirmed the default function does not match your use-case):
import {configure} from 'react-hotkeys';
configure({
ignoreEventsCondition: function(event) {
const { target: element } = event;
// Your custom logic here
}
});
stopPropagation() is called on events that are ignored
By default, react-hotkeys
calls stopPropagation()
on keyboard events that it ignores, at the first <HotKeys>
component with a non-empty keyMap
prop (or a hard sequence defined in the handlers
prop, if hard sequences are enabled). This makes react-hotkeys
more efficient, but may be hiding keyboard events from other key listeners you have in place in your React app.
You can disable this behaviour using the stopEventPropagationAfterIgnoring
configuration option:
import {configure} from 'react-hotkeys';
configure({
stopEventPropagationAfterIgnoring: false
});
Updates to keyMaps and handlers after focus are ignored by default
For performance reasons, by default react-hotkeys
takes the keyMap
and handlers
prop values when <HotKeys>
components are focused and when <GlobalHotKeys>
components are mounted. It ignores all subsequent updates to their values when these props change.
If you need the ability to change them while a <HotKeys>
component is still in focus, or while <GlobalHotKeys>
is still mounted, then you can pass the allowChanges
prop, permitting this behaviour for the particular component.
import {HotKeys} from 'react-hotkeys';
class MyComponent extends React.Component {
render() {
return (
<HotKeys keyMap={keyMapThatChanges} handler={handlersThatChange} allowChanges>
</HotKeys>
);
}
}
If you need to do this for all your <HotKeys>
and <GlobalHotKeys>
components, you can use the ignoreKeymapAndHandlerChangesByDefault
option for the Configuration API. This should normally never be done, as it can have significant performance implications.
import {configure} from 'react-hotkeys';
configure({
ignoreKeymapAndHandlerChangesByDefault: false
});
New features
Browser keynames are now supported in key sequence definitions
You can now use browser key names when defining your sequences, in addition to Mousetrap's name for the...
v2.0.0-pre9
Potentially Breaking Changes
- The configuration option
allowCombinationSubmatches
is now ignored when theCmd
key is pressed down (submatches are always allowed whenCmd
is pressed). This is to fix the following bug.
Bugfixes
- Fix moving between actions bound to the
Cmd
(Meta
) key (e.g.cmd+1
->cmd+2
without releasingCmd
) #201
v2.0.0-pre8
Potentially breaking changes
- Repeated keydown events that occur when a key is held down are now ignored by default (#177). If you want the old behaviour, you can use the
ignoreRepeatedEventsWhenKeyHeldDown
configuration option.
New features
SHOW_DIALOG: {
name: 'Display keyboard shortcuts',
sequence: 'shift+?',
action: 'keyup'
}
import {configure} from 'react-hotkeys';
configure({
customKeyCodes: {
10009: 'BackTV'
}
})
Bug fixes
- Action handlers that use
useState
now work correctly (#182, #196) - Fix some key combinations involving
cmd
acting as if those keys were still pressed down after they've been released (#183) - Fix some keys being incorrectly declared as invalid when used with the
except
oronly
options ofObserveKeys
andIgnoreKeys
(#198)
v2.0.0-pre7
Potentially breaking changes
react-hotkeys
now ignores key combination submatches #186 by default.
This resolves the issue of when an application has a context-dependent action, bound to a short key combination (e.g.?
) and a longer global action bound to a longer key combination (e.g. shift+?
), and the longer key combination is hidden behind the shorter one and never triggered whenever a child of the component that defines the shorter combination is in focus (#161, #181, #175).
If you would like the old behaviour, you can re-enable submatches with the allowCombinationSubmatches
configuration option:
configure({
allowCombinationSubmatches: true,
})
For a full description of what this change means, and the tradeoffs, see the How combinations and sequences are matched section of the Readme.
Bugfixes
- Fix bug that prevented binding to keydown and key for the same key combination #166
New features
HotKeys root prop
A new root
prop is now available for HotKeys
that allows placing HotKeys
components at the root of the app without actually defining any key maps or handlers, to ensure all key events are recorded (#188):
<HotKeys root>
//... application
</HotKeys>
For details of when you may want to use this, see the React Hotkeys thinks I'm holding down a key I've released section of the readme.
GlobalHotKeys report missed keyboard events
GlobalHotKeys
components now report key events that may have been missed by HotKeys
, to avoid hanging key combinations when an action handler changes focus outside of the part of the React app below the highest HotKeys
component.
Again, you can see the React Hotkeys thinks I'm holding down a key I've released section of the readme for more details.
v2.0.0-pre6
This release still has a number of known issues, but hopefully it will go some way to addressing some of the issues people are experiencing.
Bugfixes
- Legacy context API has been detected within a strict-mode tree: in StrictMode #151
ref
prop now has correct TypeScript type (Thanks @natew!) #168ignoreEventsCondition
now has correct argument TypeScript definition (Thanks @taromurao!) #170- Global hotkeys throwing errors after dom changes (Thanks @mrlubos & @StephenHaney!) #150
- IgnoreKeys can't handle Backspace #172
- Duplicate focus tree IDs cause keypresses to be ignored #173
Improvements
- Added Preventing default browser behaviour to Readme
- Added contents table to Readme
- Add Support section to Readme
v2.0.0-pre5
Breaking changes
Delete
andBackspace
(and the variantdel
) are no longer treated as aliases for one another. You will need to bind handlers to both, if you want to maintain backwards compatibility. #145, #159
Bugfixes (that may be breaking changes if you depended on them)
- When resetting key history, the mapping of key aliases for the keys that had already been pressed was being lost. This has now been fixed.
- When the window loses focus, all keys that are currently pressed down are automatically released. This resolves the issue people were experiencing where React Hotkeys was prematurely triggering handlers for key combinations that caused the window to lose focus (e.g. displaying an alert), after that handler had been already called once #143
Bugfixes
v2.0.0-pre4
Breaking Changes
<HotKeysIgnore />
component has been renamed to<IgnoreKeys />
withHotKeysIgnore
has been renamed towithIgnoreKeys
- Standardised ignoring events - explained in What it actually means to ignore an event
Bugfixes
- HotKeys not working for form fields/inputs #138
- Fix a number of issues with the TypeScript definitions in index.d.ts
- Fix Escape not being treated as a "special key" (non single char key name)
- Fix incorrect JSDoc
@private
annotations - Fix incorrect object JSDoc @typedefs
New Features
cmd
is now an accepted alias forCommand
/Meta
key- Added a way of filtering key maps to the example app
- Add an
<ObserveKeys />
component (and correspondingwithObserveKeys
method to avoid wrapper div) for defining white-list exceptions to the the defaultignoreEventsCondition
<ObserveKeys only={'Escape'}>
<input
autoFocus
onChange={({target: {value}}) => this.setState({ filter: value })}
value={filter}
placeholder='Filter'
/>
</ObserveKeys>
Improvements
v2.0.0-pre3
Bugfixes
- Fixed some logging messages
- Fixed
<HotKeys>
passing thecomponent
prop down to its children - Fixed blurred components unnecessarily holding on to their focus tree ids when a key event has yet to occur
Improvements
- Make warning about Readme relating to pre-release more obvious
v2.0.0-pre2
Potentially breaking changes
- Removed upper limit on React peer dependency version.
New features
Can now generate an application key map
It's now possible to generate a list of hotkeys for the application to display to the user.
New innerRef prop
Thanks to #124, <ReactHotkeys />
now accepts an innerRef
prop:
class MyComponent extends Component {
componentDidMount() {
this._container.focus();
}
render() {
return (
<HotKeys innerRef={ (c) => this._container = c } >
My focusable content
</div>
)
}
}
v2.0.0-pre1
This release represents a complete re-write of the internals and much of the interface of react-hotkeys
. Mousetrap has been removed as a dependency, and instead react-hotkeys
works on the top of the React SyntheticEvent
events system.
This is a pre-release, so it not yet ready for use in production applications, but it does represent the future direction of the library.
Breaking Changes
__mousetrap__ is no longer available
Rather unsurprisingly, with the removal of Mousetrap, it's no longer possible to access the private Mousetrap instance to configure it. Many of the use-cases for needing to do so have been covered by API updates described below. If your use-case is not covered, however, please create a new issue.
HotKeyMapMixin has been removed
This was an internal part of react-hotkeys
and is no longer used, and so it does not makes sense to continue to supply.
FocusTrap has been removed
Similar to HotKeyMapMixin
, this was an internal part of react-hotkeys
and is no longer used, and so it does not makes sense to continue to supply.
withHotKeys has been replaced
The old withHotKeys
function has been repurposed and should not be used in the same way the old one was (more on this later). The old implementation is still available as deprecatedWithHotKeys
, but it is no longer officially supported and will be removed in future versions.
Before:
import {withHotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
withHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
After (suggested):
You can write your own function or HoC that supplies the same keyMap to a component passed to it.
import {HotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
function withActions(keyMap, Component) {
return function(props) {
return(
<HotKeys keyMap={keyMap}>
<Component {...props} />
</HotKeys>
);
}
}
deprecatedWithHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
After (to restore old behaviour):
import {deprecatedWithHotKeys} from 'react-hotkeys';
const ACTION_KEY_MAP = {
'changeColor': 'alt+c',
};
deprecatedWithHotKeys(ACTION_KEY_MAP)(HOCWrappedNode);
focused and attach props hav been removed
The focused
and attach
props were introduced as a way to bind keymaps that were either always active, or available outside of the React application. They are no longer needed with the introduction of GlobalHotkeys
.
Before:
import {HotKeys} from 'react-hotkeys';
<HotKeys focused={true} attach={document} keyMap={keyMap} handlers={handlers}>
<div>
My content
</div>
</HotKeys>
After:
import {GlobalHotKeys} from 'react-hotkeys';
<GlobalHotKeys keyMap={keyMap} handlers={handlers} />
<div>
My content
</div>
Hard sequences are deprecated and turned off by default
Hard sequences (handlers associated to actions with names that are valid key sequence strings that implicitly define actions that are matched by the corresponding key sequence) are now deprecated and turned off by default. They can be re-enabled (at a performance penalty) using the enableHardSequences
configuration option:
import {configure} from 'react-hotkeys';
configure({
enableHardSequences: true
});
Default key event is now always keydown
react-hotkeys
used to rely on the implicit behaviour of Mousetrap to guess the best key event based on the keys involved (this was, roughly speaking, keydown
for non-modifier keys and keypress
for modifier keys). Now by default, react-hotkeys
will match hotkey sequences on the keydown
event (or, more precisely: on the keydown
event of the last key to complete the last combination in a sequence).
If you want to trigger a single action on a different key event, you can use the object syntax and the action
attribute to explicitly set which key event you wish to bind to:
const keyMap = {
CONTRACT: 'alt+down',
COMMAND_DOWN: {sequence: 'command', action: 'keydown'},
};
If you want to change the default key event for all hotkeys, you can use the defaultKeyEvent
option of the configuration API.
Keypress events are now simulated for modifier keys
Before, you had to rely on Mousetrap guessing the best key event for your key combination (unless you explicitly defined an event) and if you bound to a key combination to a keypress event, it did not work (the browser does not emit these events for modifier keys).
react-hotkeys
now simulates these events internally (they aren't emitted to the rest of your React components) so you do not have to worry about if your key combination includes a modifier key when binding to keypress.
This shouldn't affect most library consumers, but is listed as a breaking change as it can conceivably cause different behaviour for the same application code.
stopPropagation() is now observed
Because react-hotkeys
now uses the React event system, event.stopPropagation()
now works as expected. If you have event listeners in your React application that call event.stopPropagation()
before the event reaches a <HotKeys />
or <GlobalHotkeys />
component that has a keyMap
prop, react-hotkeys
never sees it.
If you want to hide that a key has been pressed at all, you will need to capture all 3 of the keydown
, keypress
and keyup
events.
Key events from input, select and textarea tags are ignored by default
If you were ignoring key events from certain inputs by overriding the stopCallback
function on mousetrap as has been previously suggested, you no longer need to.
By default, all key events that originate from <input>
, <select>
or <textarea>
, or have a isContentEditable
attribute of true
are ignored by react-hotkeys
.
If this is not what you want for your application, you can modify the list of tags using the ignoreTags
configuration option or if you need additional control, you can specify a brand new function using the ignoreEventsCondition
configuration option.
Before:
const mousetrap = this.hotKeys.__mousetrap__;
mousetrap.__proto__.stopCallback = (e, element) => {
// Your custom logic here
};
After:
(After you've confirmed the default function does not match your use-case):
import {configure} from 'react-hotkeys';
configure({
ignoreEventsCondition: function(event) {
const { target: element } = event;
// Your custom logic here
}
});
stopPropagation() is called on events that are ignored
By default, react-hotkeys
calls stopPropagation()
on keyboard events that it ignores, at the first <HotKeys>
component with a non-empty keyMap
prop (or a hard sequence defined in the handlers
prop, if hard sequences are enabled). This makes react-hotkeys
more efficient, but may be hiding keyboard events from other key listeners you have in place in your React app.
You can disable this behaviour using the stopEventPropagationAfterIgnoring
configuration option:
import {configure} from 'react-hotkeys';
configure({
stopEventPropagationAfterIgnoring: false
});
Updates to keyMaps and handlers after focus are ignored by default
For performance reasons, by default react-hotkeys
takes the keyMap
and handlers
prop values when <HotKeys>
components are focused and when <GlobalHotKeys>
components are mounted. It ignores all subsequent updates
to their values when these props change.
If you need the ability to change them while a <HotKeys>
component is still in focus, or while <GlobalHotKeys>
is still mounted, then you can pass the allowChanges
prop, permitting this behaviour for the particular component.
import {HotKeys} from 'react-hotkeys';
class MyComponent extends React.Component {
render() {
return (
<HotKeys keyMap={keyMapThatChanges} handler={handlersThatChange} allowChanges>
</HotKeys>
);
}
}
If you need to do this for all your <HotKeys>
and <GlobalHotKeys>
components, you can use the ignoreKeymapAndHandlerChangesByDefault
option for the Configuration API. This should normally never be done, as it can have significant performance implications.
import {configure} from 'react-hotkeys';
configure({
ignoreKeymapAndHandlerChangesByDefault: false
});
New features
Browser keynames are now supported in key sequence definitions
You can now use browser key names when defining your sequences, in addition to Mousetrap's name for the keys.
New withHotKeys HoC - a way to avoid rendering a wrapping div
If wrapping your component in a DOM-mountable node is not acceptable, or you need more control over how the react-hotkeys
props are app...