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

Show VideoPlayer tooltips when associated control receives focus #872

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/react/src/VideoPlayer/VideoPlayer.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@
color: var(--base-color-scale-gray-9);
}

.VideoPlayer__tooltip-visible {
opacity: 1;
}

.VideoPlayer__controlTextColor {
color: var(--base-color-scale-white-0);
}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/VideoPlayer/VideoPlayer.module.css.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ declare const styles: {
readonly "VideoPlayer__rangeProgress": string;
readonly "VideoPlayer__tooltipContent": string;
readonly "VideoPlayer__tooltipText": string;
readonly "VideoPlayer__tooltip-visible": string;
readonly "VideoPlayer__controlTextColor": string;
readonly "VideoPlayer__seekTime": string;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ export const CCButton = ({className, ...props}: HTMLAttributes<HTMLButtonElement
!ccEnabled && styles.VideoPlayer__ccOff,
)}
onClick={toggleCC}
aria-label={ccEnabled ? 'Disable captions' : 'Enable captions'}
{...props}
>
<Text className={styles.VideoPlayer__ccText}>CC</Text>
<Text className={styles.VideoPlayer__ccText} aria-hidden="true">
CC
</Text>
<VideoTooltip>{ccEnabled ? 'Disable captions' : 'Enable captions'}</VideoTooltip>
</button>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ type IconControlProps = {
} & HTMLAttributes<HTMLButtonElement>

export const IconControl = ({tooltip, children, className, ...rest}: IconControlProps) => (
<button className={clsx(styles.VideoPlayer__iconControl, className)} {...rest} aria-label={tooltip}>
<button className={clsx(styles.VideoPlayer__iconControl, className)} {...rest}>
{children}
<span className="visually-hidden">{tooltip}</span>
<VideoTooltip>{tooltip}</VideoTooltip>
</button>
)
10 changes: 6 additions & 4 deletions packages/react/src/VideoPlayer/components/Range/Range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ export const Range = ({
}, [startValue])

useEffect(() => {
if (!max || !tooltip || !inputRef.current) {
const input = inputRef.current

if (!max || !tooltip || !input) {
return
}

const handleMouseMove = event => {
if (event.target !== inputRef.current) {
if (event.target !== input) {
setHoverValue(0)
setMousePos(0)
return
Expand All @@ -53,10 +55,10 @@ export const Range = ({
setHoverValue((event.offsetX / event.target.clientWidth) * max)
}

window.addEventListener('mousemove', handleMouseMove)
input.addEventListener('mousemove', handleMouseMove)

return () => {
window.removeEventListener('mousemove', handleMouseMove)
input.removeEventListener('mousemove', handleMouseMove)
}
}, [max, tooltip, inputRef])

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,60 @@
import React, {type HTMLAttributes} from 'react'
import React, {useEffect, useRef, useState, type HTMLAttributes} from 'react'
import clsx from 'clsx'

import {Text} from '../../../Text'
import styles from '../../VideoPlayer.module.css'

type VideoTooltipProps = HTMLAttributes<HTMLDivElement>

export const VideoTooltip = ({children, className, ...rest}: VideoTooltipProps) => (
<div className={clsx(styles.VideoPlayer__tooltip, className)} {...rest}>
<span className={styles.VideoPlayer__tooltipContent}>
<Text className={styles.VideoPlayer__tooltipText} weight="medium">
{children}
</Text>
</span>
</div>
)
export const VideoTooltip = ({children, className, ...rest}: VideoTooltipProps) => {
const tooltipRef = useRef<HTMLDivElement>(null)
const [hasFocus, setHasFocus] = useState(false)

useEffect(() => {
const tooltip = tooltipRef.current
const parent = tooltip?.parentElement

if (!tooltip || !parent) {
return
}

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setHasFocus(false)
}
}

const checkFocus = () => {
const isFocused = parent === document.activeElement || parent.contains(document.activeElement)
setHasFocus(isFocused)
}

parent.addEventListener('focus', checkFocus)
parent.addEventListener('blur', checkFocus)
parent.addEventListener('focusin', checkFocus)
parent.addEventListener('focusout', checkFocus)
window.addEventListener('keydown', handleKeyDown)

return () => {
parent.removeEventListener('focus', checkFocus)
parent.removeEventListener('blur', checkFocus)
parent.removeEventListener('focusin', checkFocus)
parent.removeEventListener('focusout', checkFocus)
window.removeEventListener('keydown', handleKeyDown)
}
}, [tooltipRef])

return (
<div
className={clsx(styles.VideoPlayer__tooltip, hasFocus && styles['VideoPlayer__tooltip-visible'], className)}
ref={tooltipRef}
{...rest}
>
<span className={styles.VideoPlayer__tooltipContent}>
<Text className={styles.VideoPlayer__tooltipText} weight="medium">
{children}
</Text>
</span>
</div>
)
}
Loading