-
Notifications
You must be signed in to change notification settings - Fork 656
Update IconButton to support multiple keybinding hints #7623
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
base: main
Are you sure you want to change the base?
Changes from all commits
ead88e2
194087c
6818499
d83f1db
d0bf446
baacf61
464c69d
c1bcdf4
6a26db7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@primer/react": minor | ||
| --- | ||
|
|
||
| `IconButton`: `keybindingHint` now accepts `string[]` in addition to `string`. Multiple hints are rendered joined with "or". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,7 +91,7 @@ export type IconButtonProps = ButtonA11yProps & { | |
| tooltipDirection?: TooltipDirection | ||
| /** @deprecated Use `keybindingHint` instead. */ | ||
| keyshortcuts?: string | ||
| keybindingHint?: string | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct type in iconbutton.docs.json as well
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 464c69d. Updated |
||
| keybindingHint?: string | string[] | ||
| } & Omit<ButtonBaseProps, 'aria-label' | 'aria-labelledby'> | ||
|
|
||
| // adopted from React.AnchorHTMLAttributes | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,7 @@ export type TooltipProps = React.PropsWithChildren<{ | |
| direction?: TooltipDirection | ||
| text: string | ||
| type?: 'label' | 'description' | ||
| keybindingHint?: KeybindingHintProps['keys'] | ||
| keybindingHint?: KeybindingHintProps['keys'] | Array<KeybindingHintProps['keys']> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct type on tooltip.docs.json as well
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 464c69d. Updated |
||
| /** | ||
| * Delay in milliseconds before showing the tooltip | ||
| * @default short (50ms) | ||
|
|
@@ -103,6 +103,8 @@ const isInteractive = (element: HTMLElement) => { | |
| } | ||
| export const TooltipContext = React.createContext<{tooltipId?: string}>({}) | ||
|
|
||
| const emptyKeybindingHints: Array<KeybindingHintProps['keys']> = [] | ||
|
|
||
| export const Tooltip: ForwardRefExoticComponent< | ||
| React.PropsWithoutRef<TooltipProps> & React.RefAttributes<HTMLElement> | ||
| > & | ||
|
|
@@ -115,7 +117,7 @@ export const Tooltip: ForwardRefExoticComponent< | |
| children, | ||
| id, | ||
| className, | ||
| keybindingHint, | ||
| keybindingHint = emptyKeybindingHints, | ||
| delay = 'short', | ||
| _privateDisableTooltip = false, | ||
| ...rest | ||
|
|
@@ -273,6 +275,9 @@ export const Tooltip: ForwardRefExoticComponent< | |
| const isMacOS = useIsMacOS() | ||
| const hasAriaLabel = 'aria-label' in rest | ||
|
|
||
| // Normalize keybindingHint to an array for uniform rendering | ||
| const keybindingHints = Array.isArray(keybindingHint) ? keybindingHint : [keybindingHint] | ||
|
|
||
| return ( | ||
| <TooltipContext.Provider value={value}> | ||
| <> | ||
|
|
@@ -353,21 +358,35 @@ export const Tooltip: ForwardRefExoticComponent< | |
| onMouseEnter={openTooltip} | ||
| onMouseLeave={closeTooltip} | ||
| // If there is an aria-label prop, always assign the ID to the parent so the accessible label can be overridden | ||
| id={hasAriaLabel || !keybindingHint ? tooltipId : undefined} | ||
| id={hasAriaLabel || keybindingHints.length === 0 ? tooltipId : undefined} | ||
| > | ||
| {keybindingHint ? ( | ||
| {keybindingHints.length > 0 ? ( | ||
| <> | ||
| <span id={hasAriaLabel ? undefined : tooltipId}> | ||
| {text} | ||
| {/* There is a bug in Chrome browsers where `aria-hidden` text inside the target of an `aria-labelledby` | ||
| still gets included in the accessible label. `KeybindingHint` renders the symbols as `aria-hidden` text | ||
| and renders full key names as `VisuallyHidden` text. Due to the browser bug this causes the label text | ||
| to duplicate the symbols and key names. To work around this, we exclude the hint from being part of the | ||
| label and instead render the plain keybinding description string. */} | ||
| <VisuallyHidden>({getAccessibleKeybindingHintString(keybindingHint, isMacOS)})</VisuallyHidden> | ||
| still gets included in the accessible label. `KeybindingHint` renders the symbols as `aria-hidden` text | ||
| and renders full key names as `VisuallyHidden` text. Due to the browser bug this causes the label text | ||
| to duplicate the symbols and key names. To work around this, we exclude the hint from being part of the | ||
| label and instead render the plain keybinding description string. */} | ||
| <VisuallyHidden> | ||
| ({keybindingHints.map(hint => getAccessibleKeybindingHintString(hint, isMacOS)).join(' or ')}) | ||
| </VisuallyHidden> | ||
| </span> | ||
| <span className={clsx(classes.KeybindingHintContainer, text && classes.HasTextBefore)} aria-hidden> | ||
| <KeybindingHint keys={keybindingHint} format="condensed" variant="onEmphasis" size="small" /> | ||
| <span | ||
| className={clsx( | ||
| classes.KeybindingHintContainer, | ||
| text && classes.HasTextBefore, | ||
| keybindingHints.length > 1 && classes.HasMultipleHints, | ||
| )} | ||
| aria-hidden | ||
| > | ||
| {keybindingHints.map((hint, i) => ( | ||
| <React.Fragment key={`${i}-${hint}`}> | ||
| {i > 0 && ' or '} | ||
| <KeybindingHint keys={hint} format="condensed" variant="onEmphasis" size="small" /> | ||
| </React.Fragment> | ||
| ))} | ||
| </span> | ||
| </> | ||
| ) : ( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.