Skip to content
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

Merged
merged 26 commits into from
Aug 16, 2024
Merged

Add KeybindingHint component #4750

merged 26 commits into from
Aug 16, 2024

Conversation

iansan5653
Copy link
Contributor

@iansan5653 iansan5653 commented Jul 18, 2024

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 from KeyboardKey to KeybindingHint to better indicate its purpose and flexibility. I've also refactored the code, splitting it into smaller files.

Changelog

New

  • New KeybindingHint component for indicating an available keybinding

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Merge checklist

Copy link

changeset-bot bot commented Jul 18, 2024

🦋 Changeset detected

Latest commit: c378c1e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Minor

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

@iansan5653 iansan5653 self-assigned this Jul 18, 2024
Copy link
Contributor

github-actions bot commented Jul 18, 2024

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 96.09 KB (-0.11% 🔽)
packages/react/dist/browser.umd.js 96.39 KB (-0.07% 🔽)

Comment on lines 4 to 16
/**
* 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
}
Copy link
Contributor Author

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 to true (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.

@iansan5653 iansan5653 marked this pull request as ready for review July 18, 2024 18:00
@iansan5653 iansan5653 requested a review from a team as a code owner July 18, 2024 18:00
Copy link
Member

@keithamus keithamus left a 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={{
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

@iansan5653 iansan5653 Aug 6, 2024

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.

Copy link
Member

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.

@iansan5653

This comment was marked as resolved.

<Sequence {...props} />
</Kbd>
))
KeybindingHint.displayName = 'KeybindingHint'
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Member

@broccolinisoup broccolinisoup left a 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={{
Copy link
Member

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.

Comment on lines +18 to +19
<VisuallyHidden>{accessibleKeyName(name, isMacOS)}</VisuallyHidden>
<span aria-hidden>{format === 'condensed' ? condensedKeyName(name, isMacOS) : fullKeyName(name, isMacOS)}</span>
Copy link
Member

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

Tooltip is open on a button and it has keyboard shortcuts on the tooltip. The text colour of the keybinding component doesn't create enough contrast on the tooltip background

tagging @mperrotti here for design 👀

Comment on lines +18 to +19
<VisuallyHidden>{accessibleKeyName(name, isMacOS)}</VisuallyHidden>
<span aria-hidden>{format === 'condensed' ? condensedKeyName(name, isMacOS) : fullKeyName(name, isMacOS)}</span>
Copy link
Member

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) =>
Copy link
Member

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'
Copy link
Member

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
Copy link
Member

@siddharthkp siddharthkp Aug 16, 2024

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)

Copy link
Member

@broccolinisoup broccolinisoup left a 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.

@iansan5653
Copy link
Contributor Author

I assume we don't have any usages at dotcom

To be clear, this is upstreaming a component that's in dotcom, so we do have a few existing usages (under the name KeyboardKey). I'll handle migrating them after this is shipped.

@iansan5653 iansan5653 added this pull request to the merge queue Aug 16, 2024
Merged via the queue into main with commit 414c140 Aug 16, 2024
30 checks passed
@iansan5653 iansan5653 deleted the add-keybinding-hint branch August 16, 2024 14:26
@primer primer bot mentioned this pull request Aug 16, 2024
@primer primer bot mentioned this pull request Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants