Skip to content

Commit

Permalink
feat: add keybindingDescription exploration
Browse files Browse the repository at this point in the history
  • Loading branch information
joshblack committed Jan 30, 2025
1 parent 124f88a commit 2fa118d
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 10 deletions.
6 changes: 3 additions & 3 deletions packages/react/src/Button/ButtonBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,11 @@ const ButtonBase = forwardRef(
</>
)}
</Box>
{loading && (
{loading ? (
<VisuallyHidden>
<AriaStatus id={loadingAnnouncementID}>{loadingAnnouncement}</AriaStatus>
</VisuallyHidden>
)}
) : null}
</ConditionalWrapper>
)
}
Expand Down Expand Up @@ -228,7 +228,7 @@ const ButtonBase = forwardRef(
data-variant={variant}
data-label-wrap={labelWrap}
data-has-count={count !== undefined ? true : undefined}
aria-describedby={[loadingAnnouncementID, ariaDescribedBy]
aria-describedby={[loading && loadingAnnouncementID, ariaDescribedBy]
.filter(descriptionID => Boolean(descriptionID))
.join(' ')}
// aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state.
Expand Down
5 changes: 4 additions & 1 deletion packages/react/src/Button/IconButton.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ export const KeybindingHintOnDescription = () => (
aria-label="Notifications"
description="You have unread notifications"
keybindingHint="G+N"
keybindingDescription="G, N"
/>
)

export const KeybindingHint = () => <IconButton icon={BoldIcon} aria-label="Bold" keybindingHint="Mod+B" />
export const KeybindingHint = () => (
<IconButton icon={BoldIcon} aria-label="Bold" keybindingHint="Mod+B" keybindingDescription="Command, B" />
)
2 changes: 2 additions & 0 deletions packages/react/src/Button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const IconButton = forwardRef(
unsafeDisableTooltip = false,
keyshortcuts,
keybindingHint,
keybindingDescription,
className,
...props
},
Expand Down Expand Up @@ -67,6 +68,7 @@ const IconButton = forwardRef(
type={description ? undefined : 'label'}
direction={tooltipDirection}
keybindingHint={keybindingHint ?? keyshortcuts}
keybindingDescription={keybindingDescription}
>
<ButtonBase
icon={Icon}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/Button/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export type IconButtonProps = ButtonA11yProps & {
/** @deprecated Use `keybindingHint` instead. */
keyshortcuts?: string
keybindingHint?: string
keybindingDescription?: string
} & Omit<ButtonBaseProps, 'aria-label' | 'aria-labelledby'>

// adopted from React.AnchorHTMLAttributes
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/KeybindingHint/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export type KeybindingHintFormat = 'condensed' | 'full'
export type KeybindingHintVariant = 'normal' | 'onEmphasis' | 'onPrimary'

export interface KeybindingHintProps {
description?: string

/**
* The keys involved in this keybinding. These should be the full names of the keys as would
* be returned by `KeyboardEvent.key` (e.g. "Control", "Shift", "ArrowUp", "a", etc.).
Expand Down
29 changes: 23 additions & 6 deletions packages/react/src/TooltipV2/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export type TooltipProps = React.PropsWithChildren<
text: string
type?: 'label' | 'description'
keybindingHint?: KeybindingHintProps['keys']
keybindingDescription?: KeybindingHintProps['description']
} & SxProp
> &
React.HTMLAttributes<HTMLElement>
Expand Down Expand Up @@ -201,10 +202,21 @@ export const TooltipContext = React.createContext<{tooltipId?: string}>({})

export const Tooltip = React.forwardRef(
(
{direction = 's', text, type = 'description', children, id, className, keybindingHint, ...rest}: TooltipProps,
{
direction = 's',
text,
type = 'description',
children,
id,
className,
keybindingHint,
keybindingDescription,
...rest
}: TooltipProps,
forwardedRef,
) => {
const tooltipId = useId(id)
const controlHintId = useId()
const child = Children.only(children)
const triggerRef = useProvidedRefOrCreate(forwardedRef as React.RefObject<HTMLElement>)
const tooltipElRef = useRef<HTMLDivElement>(null)
Expand Down Expand Up @@ -355,7 +367,10 @@ export const Tooltip = React.forwardRef(
React.cloneElement(child as React.ReactElement<TriggerPropsType>, {
ref: triggerRef,
// If it is a type description, we use tooltip to describe the trigger
'aria-describedby': type === 'description' ? tooltipId : child.props['aria-describedby'],
'aria-describedby':
type === 'description'
? [tooltipId, controlHintId].join(' ')
: [child.props['aria-describedby'], controlHintId].filter(Boolean).join(' '),
// If it is a label type, we use tooltip to label the trigger
'aria-labelledby': type === 'label' ? tooltipId : child.props['aria-labelledby'],
onBlur: (event: React.FocusEvent) => {
Expand Down Expand Up @@ -400,19 +415,21 @@ export const Tooltip = React.forwardRef(
role={type === 'description' ? 'tooltip' : undefined}
// stop AT from announcing the tooltip twice: when it is a label type it will be announced with "aria-labelledby",when it is a description type it will be announced with "aria-describedby"
aria-hidden={true}
id={tooltipId}
// mouse leave and enter on the tooltip itself is needed to keep the tooltip open when the mouse is over the tooltip
onMouseEnter={openTooltip}
onMouseLeave={closeTooltip}
>
{text}
{keybindingHint && (
<span id={tooltipId}>{text}</span>
{keybindingHint ? (
<span className={clsx(classes.keybindingHintContainer, text && classes.hasTextBefore)}>
<VisuallyHidden>(</VisuallyHidden>
<KeybindingHint keys={keybindingHint} format="condensed" variant="onEmphasis" size="small" />
<VisuallyHidden>)</VisuallyHidden>
</span>
)}
) : null}
{keybindingDescription ? (
<VisuallyHidden id={controlHintId}>. {keybindingDescription}</VisuallyHidden>
) : null}
</StyledTooltip>
</>
</TooltipContext.Provider>
Expand Down

0 comments on commit 2fa118d

Please sign in to comment.