-
Notifications
You must be signed in to change notification settings - Fork 535
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
Add KeybindingHint
component
#4750
Conversation
🦋 Changeset detectedLatest commit: c378c1e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
size-limit report 📦
|
8777a58
to
8a37a6f
Compare
/** | ||
* SSR-safe hook for determining if the current platform is MacOS. When rendering | ||
* server-side, will default to non-MacOS and then re-render in an effect if the | ||
* client turns out to be a MacOS device. | ||
*/ | ||
export function useIsMacOS() { | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
const [isMacOS, setIsMacOS] = useState(() => (window !== undefined ? ssrUnsafeIsMacOS() : false)) | ||
|
||
useEffect(() => setIsMacOS(ssrUnsafeIsMacOS()), []) | ||
|
||
return isMacOS | ||
} |
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.
In the current usage of this component internally, we call isMacOS
directly at the top level of the file. This is obviously not good for SSR-compatibility, so I've introduced this new hook:
- In non-SSR, it causes no extra renders and returns
isMacOS
directly - In SSR, it initially returns
false
, then causes a re-render after hydration if the value would change totrue
(if the client is using a Mac)
I exposed this hook publicly so that we can also use it elsewhere when actually binding keyboard shortcuts.
badc0a7
to
b0e1e7a
Compare
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 will look at this more closely this week but for now...
|
||
export const Chord = ({keys, format = 'condensed', variant = 'normal'}: KeybindingHintProps) => ( | ||
<Text | ||
sx={{ |
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.
Maybe we can make this use a CSS module? @joshblack
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'm definitely open to this. I didn't see any other CSS modules in the package so I figured I'd keep it consistent for now, but happy to make the change.
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.
The work we do for CSS modules is still WIP, hopefully should come in soon though 🤞🏻
I wonder if we can write the styles migration in mind? 🤔 What I mean is that for example instead of styling the color conditionally
color: variant === 'onEmphasis' ? 'fg.onEmphasis' : 'fg.muted',
Can we use data attributes so that we can load the styles all at once rather than rendering conditionally and can create a good path for moving them into a css file?
I'll tag @joshblack and @langermank to see what they think if this is worth doing and get a second opinion.
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.
Do you have any prior art for using data attributes for this? I'm not sure I've seen that approach before.
FWIW this should be pretty easy to migrate - we will just introduce an additional class like onEmphasis
for the variant.
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.
Ah sorry I didn't provide any example. We use data attributes heavily for the Button
FWIW this should be pretty easy to migrate - we will just introduce an additional class like onEmphasis for the variant.
Okay then. That sounds good. Let's keep the styles as is and we can migrate later.
This comment was marked as resolved.
This comment was marked as resolved.
<Sequence {...props} /> | ||
</Kbd> | ||
)) | ||
KeybindingHint.displayName = 'KeybindingHint' |
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.
Why are we setting the displayName
property when it already matches the name of the function?
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.
The engine can infer a function name for simple named declarations like function Component() {}
and const Component = ()=> {}
.
But in this case we are declaring an anonymous function without a name, then sending it through memo
and assigning it to a named constant. There's no way for the engine to infer a name for the function so the component would be anonymous without a displayName
. This is actually required by the linter.
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 addressing all these comments quickly 🙏🏻 Left a few more comments - looking forward to hearing your thoughts!!
|
||
export const Chord = ({keys, format = 'condensed', variant = 'normal'}: KeybindingHintProps) => ( | ||
<Text | ||
sx={{ |
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.
Ah sorry I didn't provide any example. We use data attributes heavily for the Button
FWIW this should be pretty easy to migrate - we will just introduce an additional class like onEmphasis for the variant.
Okay then. That sounds good. Let's keep the styles as is and we can migrate later.
<VisuallyHidden>{accessibleKeyName(name, isMacOS)}</VisuallyHidden> | ||
<span aria-hidden>{format === 'condensed' ? condensedKeyName(name, isMacOS) : fullKeyName(name, isMacOS)}</span> |
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.
Wonderful! I have played with it as well and it works great ✨
I have one comment though regarding using this in Tooltip:
I quickly implemented it to see how that would work and looks in Tooltip and I think we need to work through the colours if this is how we are going to use this component in Tooltip
tagging @mperrotti here for design 👀
<VisuallyHidden>{accessibleKeyName(name, isMacOS)}</VisuallyHidden> | ||
<span aria-hidden>{format === 'condensed' ? condensedKeyName(name, isMacOS) : fullKeyName(name, isMacOS)}</span> |
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.
Regarding using getAccessibleKeybindingHintString
, is there a way to handle determining isMacOS
under the hood so that we don't worry about it every time when we use this function?
Let me know if there is anything I am missing here
* readers from expressing punctuation in speech, ie, reading a long pause instead of the | ||
* word "period". | ||
*/ | ||
export const accessibleKeyName = (key: string, isMacOS: boolean) => |
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.
Thank you! I'll share this with the team to see if we need to cross check this again with the Accessibility team. Thanks for your patience 🙏🏻
@@ -0,0 +1,97 @@ | |||
import React from 'react' |
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.
(not blocking) You can move these inside packages/react/src/KeyboardHint/__tests__
, that's the preferred location
@@ -82,6 +82,8 @@ | |||
url: /Heading | |||
- title: IconButton | |||
url: /IconButton | |||
- title: KeybindingHint | |||
url: /KeybindingHint |
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.
Should this be under drafts as well in the nav?
(non blocking because these docs are going away soon anyways in favor of https://primer.style/components)
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 assume we don't have any usages at dotcom since it is a new component and the overall PR and the API looks good to me.! 🚀
We can always address later if any issues come up or if there is anything we want to improve.
To be clear, this is upstreaming a component that's in dotcom, so we do have a few existing usages (under the name |
Adds a new component called
KeybindingHint
. This is upstreamed from our internal codebase, where it is used in production in several locations. As part of the upstreaming, I've taken the liberty of renaming the component fromKeyboardKey
toKeybindingHint
to better indicate its purpose and flexibility. I've also refactored the code, splitting it into smaller files.Changelog
New
KeybindingHint
component for indicating an available keybindingRollout strategy
Testing & Reviewing
Merge checklist