-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
navigateRegions: Convert to TypeScript #48632
Conversation
const regions = Array.from( | ||
ref.current.querySelectorAll( '[role="region"][tabindex="-1"]' ) | ||
ref.current?.querySelectorAll< HTMLElement >( | ||
'[role="region"][tabindex="-1"]' | ||
) ?? [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just making the fallback explicit here.
const wrappingRegion = | ||
ref.current?.ownerDocument?.activeElement?.closest< HTMLElement >( | ||
'[role="region"][tabindex="-1"]' | ||
) | ||
); | ||
); | ||
const selectedIndex = wrappingRegion | ||
? regions.indexOf( wrappingRegion ) | ||
: -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just making the fallback explicit, as .indexOf()
will return -1 when wrappingRegion
is undefined.
packages/keycodes/src/index.js
Outdated
@@ -42,7 +42,7 @@ import { isAppleOS } from './platform'; | |||
* | |||
* @typedef {(character: string, isApple?: () => boolean) => T} WPKeyHandler | |||
*/ | |||
/** @typedef {(event: KeyboardEvent, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */ | |||
/** @typedef {(event: import('react').KeyboardEvent<HTMLElement>, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is what we want, given that it's meant to handle React synthetic events? Let me know if you disagree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhh, this is a tricky one.
For sure, the onKeyDown
property returned by useNavigateRegions
needs to take a React.KeyboardEvent< HTMLDivElement >
as its argument.
Personally, I'm almost tempted to introduce a runtime change to the navigateRegions
component and avoid making changes to the @wordpress/keycodes
package, since from a quick look it seems that the package is not assuming react as a web dependency (only react-native
is mentioned).
With this in mind, as an alternative approach we could use the `nativeEvent` property in `useNavigateRegions`
diff --git a/packages/components/src/higher-order/navigate-regions/index.tsx b/packages/components/src/higher-order/navigate-regions/index.tsx
index f2b9c31bfb..44afd39f4c 100644
--- a/packages/components/src/higher-order/navigate-regions/index.tsx
+++ b/packages/components/src/higher-order/navigate-regions/index.tsx
@@ -96,13 +96,19 @@ export function useNavigateRegions( shortcuts: Shortcuts = defaultShortcuts ) {
onKeyDown( event: React.KeyboardEvent< HTMLDivElement > ) {
if (
shortcuts.previous.some( ( { modifier, character } ) => {
- return isKeyboardEvent[ modifier ]( event, character );
+ return isKeyboardEvent[ modifier ](
+ event.nativeEvent,
+ character
+ );
} )
) {
focusRegion( -1 );
} else if (
shortcuts.next.some( ( { modifier, character } ) => {
- return isKeyboardEvent[ modifier ]( event, character );
+ return isKeyboardEvent[ modifier ](
+ event.nativeEvent,
+ character
+ );
} )
) {
focusRegion( 1 );
diff --git a/packages/keycodes/src/index.js b/packages/keycodes/src/index.js
index 15e96dca77..cd31fef5fa 100644
--- a/packages/keycodes/src/index.js
+++ b/packages/keycodes/src/index.js
@@ -42,7 +42,7 @@ import { isAppleOS } from './platform';
*
* @typedef {(character: string, isApple?: () => boolean) => T} WPKeyHandler
*/
-/** @typedef {(event: import('react').KeyboardEvent<HTMLElement>, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */
+/** @typedef {(event: KeyboardEvent, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */
/** @typedef {( isApple: () => boolean ) => WPModifierPart[]} WPModifier */
@@ -346,7 +346,7 @@ export const shortcutAriaLabel = mapValues(
* From a given KeyboardEvent, returns an array of active modifier constants for
* the event.
*
- * @param {import('react').KeyboardEvent<HTMLElement>} event Keyboard event.
+ * @param {KeyboardEvent} event Keyboard event.
*
* @return {Array<WPModifierPart>} Active modifier constants.
*/
Basically, trading off a small runtime change in exchange for not changing another package's APIs. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for digging deeper here! I looked into the codebase to see how isKeyboardEvent()
is being used, and it is in fact handling both native and synthetic events. The synthetic usages would all be errors if they were typechecked. So I think it would be best to correct the types so it matches the actual usage 👉 b94985a
How does that sound?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me!
Size Change: +62 B (0%) Total Size: 1.34 MB
ℹ️ View Unchanged
|
Flaky tests detected in a763cd9. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4306024342
|
const selectedIndex = regions.indexOf( | ||
ref.current.ownerDocument.activeElement.closest( | ||
const wrappingRegion = | ||
ref.current?.ownerDocument?.activeElement?.closest< HTMLElement >( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotta love optional chaining ❓ ⛓️
packages/keycodes/src/index.js
Outdated
@@ -42,7 +42,7 @@ import { isAppleOS } from './platform'; | |||
* | |||
* @typedef {(character: string, isApple?: () => boolean) => T} WPKeyHandler | |||
*/ | |||
/** @typedef {(event: KeyboardEvent, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */ | |||
/** @typedef {(event: import('react').KeyboardEvent<HTMLElement>, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhh, this is a tricky one.
For sure, the onKeyDown
property returned by useNavigateRegions
needs to take a React.KeyboardEvent< HTMLDivElement >
as its argument.
Personally, I'm almost tempted to introduce a runtime change to the navigateRegions
component and avoid making changes to the @wordpress/keycodes
package, since from a quick look it seems that the package is not assuming react as a web dependency (only react-native
is mentioned).
With this in mind, as an alternative approach we could use the `nativeEvent` property in `useNavigateRegions`
diff --git a/packages/components/src/higher-order/navigate-regions/index.tsx b/packages/components/src/higher-order/navigate-regions/index.tsx
index f2b9c31bfb..44afd39f4c 100644
--- a/packages/components/src/higher-order/navigate-regions/index.tsx
+++ b/packages/components/src/higher-order/navigate-regions/index.tsx
@@ -96,13 +96,19 @@ export function useNavigateRegions( shortcuts: Shortcuts = defaultShortcuts ) {
onKeyDown( event: React.KeyboardEvent< HTMLDivElement > ) {
if (
shortcuts.previous.some( ( { modifier, character } ) => {
- return isKeyboardEvent[ modifier ]( event, character );
+ return isKeyboardEvent[ modifier ](
+ event.nativeEvent,
+ character
+ );
} )
) {
focusRegion( -1 );
} else if (
shortcuts.next.some( ( { modifier, character } ) => {
- return isKeyboardEvent[ modifier ]( event, character );
+ return isKeyboardEvent[ modifier ](
+ event.nativeEvent,
+ character
+ );
} )
) {
focusRegion( 1 );
diff --git a/packages/keycodes/src/index.js b/packages/keycodes/src/index.js
index 15e96dca77..cd31fef5fa 100644
--- a/packages/keycodes/src/index.js
+++ b/packages/keycodes/src/index.js
@@ -42,7 +42,7 @@ import { isAppleOS } from './platform';
*
* @typedef {(character: string, isApple?: () => boolean) => T} WPKeyHandler
*/
-/** @typedef {(event: import('react').KeyboardEvent<HTMLElement>, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */
+/** @typedef {(event: KeyboardEvent, character: string, isApple?: () => boolean) => boolean} WPEventKeyHandler */
/** @typedef {( isApple: () => boolean ) => WPModifierPart[]} WPModifier */
@@ -346,7 +346,7 @@ export const shortcutAriaLabel = mapValues(
* From a given KeyboardEvent, returns an array of active modifier constants for
* the event.
*
- * @param {import('react').KeyboardEvent<HTMLElement>} event Keyboard event.
+ * @param {KeyboardEvent} event Keyboard event.
*
* @return {Array<WPModifierPart>} Active modifier constants.
*/
Basically, trading off a small runtime change in exchange for not changing another package's APIs. What do you think?
# Conflicts: # packages/components/tsconfig.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
Part of #35744
What?
Converts the
navigateRegions
HOC to TypeScript.Testing Instructions
✅ Static checks pass.