Skip to content

Commit

Permalink
fix(player): use voice reader friendly labels
Browse files Browse the repository at this point in the history
  • Loading branch information
mihar-22 committed Feb 20, 2024
1 parent 2503c5d commit 6b9d999
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 65 deletions.
28 changes: 13 additions & 15 deletions packages/react/src/components/layouts/default/shared-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,10 @@ function DefaultPlayButton({ tooltip }: DefaultMediaButtonProps) {
playText = useDefaultLayoutWord('Play'),
pauseText = useDefaultLayoutWord('Pause'),
$paused = useMediaState('paused'),
$ended = useMediaState('ended'),
label = $paused ? playText : pauseText;
$ended = useMediaState('ended');
return (
<DefaultTooltip content={$paused ? playText : pauseText} placement={tooltip}>
<PlayButton className="vds-play-button vds-button" aria-label={label}>
<PlayButton className="vds-play-button vds-button" aria-label={playText}>
{$ended ? (
<Icons.PlayButton.Replay className="vds-icon" />
) : $paused ? (
Expand All @@ -173,11 +172,10 @@ const DefaultMuteButton = React.forwardRef<HTMLButtonElement, DefaultMediaButton
muteText = useDefaultLayoutWord('Mute'),
unmuteText = useDefaultLayoutWord('Unmute'),
$muted = useMediaState('muted'),
$volume = useMediaState('volume'),
label = $muted ? unmuteText : muteText;
$volume = useMediaState('volume');
return (
<DefaultTooltip content={$muted ? unmuteText : muteText} placement={tooltip}>
<MuteButton className="vds-mute-button vds-button" aria-label={label} ref={forwardRef}>
<MuteButton className="vds-mute-button vds-button" aria-label={muteText} ref={forwardRef}>
{$muted || $volume == 0 ? (
<Icons.MuteButton.Mute className="vds-icon" />
) : $volume < 0.5 ? (
Expand All @@ -200,14 +198,14 @@ export { DefaultMuteButton };

function DefaultCaptionButton({ tooltip }: DefaultMediaButtonProps) {
const { icons: Icons } = useDefaultLayoutContext(),
captionsText = useDefaultLayoutWord('Captions'),
onText = useDefaultLayoutWord('Closed-Captions On'),
offText = useDefaultLayoutWord('Closed-Captions Off'),
$track = useMediaState('textTrack'),
isOn = $track && isTrackCaptionKind($track),
label = $track ? offText : onText;
isOn = $track && isTrackCaptionKind($track);
return (
<DefaultTooltip content={isOn ? onText : offText} placement={tooltip}>
<CaptionButton className="vds-caption-button vds-button" aria-label={label}>
<CaptionButton className="vds-caption-button vds-button" aria-label={captionsText}>
{isOn ? (
<Icons.CaptionButton.On className="vds-icon" />
) : (
Expand All @@ -227,13 +225,13 @@ export { DefaultCaptionButton };

function DefaultPIPButton({ tooltip }: DefaultMediaButtonProps) {
const { icons: Icons } = useDefaultLayoutContext(),
pipText = useDefaultLayoutWord('PiP'),
enterText = useDefaultLayoutWord('Enter PiP'),
exitText = useDefaultLayoutWord('Exit PiP'),
$pip = useMediaState('pictureInPicture'),
label = $pip ? exitText : enterText;
$pip = useMediaState('pictureInPicture');
return (
<DefaultTooltip content={$pip ? exitText : enterText} placement={tooltip}>
<PIPButton className="vds-pip-button vds-button" aria-label={label}>
<PIPButton className="vds-pip-button vds-button" aria-label={pipText}>
{$pip ? (
<Icons.PIPButton.Exit className="vds-icon" />
) : (
Expand All @@ -253,13 +251,13 @@ export { DefaultPIPButton };

function DefaultFullscreenButton({ tooltip }: DefaultMediaButtonProps) {
const { icons: Icons } = useDefaultLayoutContext(),
fullscreenText = useDefaultLayoutWord('Fullscreen'),
enterText = useDefaultLayoutWord('Enter Fullscreen'),
exitText = useDefaultLayoutWord('Exit Fullscreen'),
$fullscreen = useMediaState('fullscreen'),
label = $fullscreen ? exitText : enterText;
$fullscreen = useMediaState('fullscreen');
return (
<DefaultTooltip content={$fullscreen ? exitText : enterText} placement={tooltip}>
<FullscreenButton className="vds-fullscreen-button vds-button" aria-label={label}>
<FullscreenButton className="vds-fullscreen-button vds-button" aria-label={fullscreenText}>
{$fullscreen ? (
<Icons.FullscreenButton.Exit className="vds-icon" />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type DefaultLayoutWord =
| 'Font Family'
| 'Font Size'
| 'Font Styles'
| 'Fullscreen'
| 'Google Cast'
| 'Green'
| 'LIVE'
Expand All @@ -36,6 +37,7 @@ export type DefaultLayoutWord =
| 'Off'
| 'Pause'
| 'Play'
| 'PiP'
| 'Quality'
| 'Red'
| 'Replay'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class CaptionButton extends Component<CaptionButtonProps, {}, CaptionButt

protected override onAttach(el: HTMLElement): void {
el.setAttribute('data-media-tooltip', 'caption');
setARIALabel(el, this._getDefaultLabel.bind(this));
setARIALabel(el, 'Captions');
}

private _onPress(event: Event) {
Expand All @@ -65,9 +65,4 @@ export class CaptionButton extends Component<CaptionButtonProps, {}, CaptionButt
const { hasCaptions } = this._media.$state;
return !hasCaptions();
}

private _getDefaultLabel() {
const { textTrack } = this._media.$state;
return textTrack() ? 'Closed-Captions Off' : 'Closed-Captions On';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class FullscreenButton extends Component<FullscreenButtonProps, {}, Fulls

protected override onAttach(el: HTMLElement): void {
el.setAttribute('data-media-tooltip', 'fullscreen');
setARIALabel(el, this._getDefaultLabel.bind(this));
setARIALabel(el, 'Fullscreen');
}

private _onPress(event: Event) {
Expand All @@ -87,9 +87,4 @@ export class FullscreenButton extends Component<FullscreenButtonProps, {}, Fulls
const { canFullscreen } = this._media.$state;
return canFullscreen();
}

private _getDefaultLabel() {
const { fullscreen } = this._media.$state;
return fullscreen() ? 'Exit Fullscreen' : 'Enter Fullscreen';
}
}
6 changes: 1 addition & 5 deletions packages/vidstack/src/components/ui/buttons/mute-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class MuteButton extends Component<MuteButtonProps, {}, MuteButtonEvents>
protected override onAttach(el: HTMLElement): void {
el.setAttribute('data-media-mute-button', '');
el.setAttribute('data-media-tooltip', 'mute');
setARIALabel(el, this._getDefaultLabel.bind(this));
setARIALabel(el, 'Mute');
}

private _onPress(event: Event) {
Expand All @@ -59,10 +59,6 @@ export class MuteButton extends Component<MuteButtonProps, {}, MuteButtonEvents>
return muted() || volume() === 0;
}

private _getDefaultLabel() {
return this._isPressed() ? 'Unmute' : 'Mute';
}

private _getState() {
const { muted, volume } = this._media.$state,
$volume = volume();
Expand Down
7 changes: 1 addition & 6 deletions packages/vidstack/src/components/ui/buttons/pip-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class PIPButton extends Component<PIPButtonProps, {}, PIPButtonEvents> {

protected override onAttach(el: HTMLElement): void {
el.setAttribute('data-media-tooltip', 'pip');
setARIALabel(el, this._getDefaultLabel.bind(this));
setARIALabel(el, 'PiP');
}

private _onPress(event: Event) {
Expand All @@ -68,9 +68,4 @@ export class PIPButton extends Component<PIPButtonProps, {}, PIPButtonEvents> {
const { canPictureInPicture } = this._media.$state;
return canPictureInPicture();
}

private _getDefaultLabel() {
const { pictureInPicture } = this._media.$state;
return pictureInPicture() ? 'Exit Picture In Picture' : 'Enter Picture In Picture';
}
}
7 changes: 1 addition & 6 deletions packages/vidstack/src/components/ui/buttons/play-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class PlayButton extends Component<PlayButtonProps, {}, PlayButtonEvents>

protected override onAttach(el: HTMLElement): void {
el.setAttribute('data-media-tooltip', 'play');
setARIALabel(el, this._getDefaultLabel.bind(this));
setARIALabel(el, 'Play');
}

private _onPress(event: Event) {
Expand All @@ -59,9 +59,4 @@ export class PlayButton extends Component<PlayButtonProps, {}, PlayButtonEvents>
const { paused } = this._media.$state;
return !paused();
}

private _getDefaultLabel() {
const { paused } = this._media.$state;
return paused() ? 'Play' : 'Pause';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,15 @@ export function DefaultGoogleCastButton({ tooltip }: { tooltip: TooltipPlacement

export function DefaultPlayButton({ tooltip }: { tooltip: TooltipPlacement }) {
const { translations } = useDefaultLayoutContext(),
{ paused } = useMediaState(),
$label = $signal(() => i18n(translations, paused() ? 'Play' : 'Pause')),
$playText = $i18n(translations, 'Play'),
$pauseText = $i18n(translations, 'Pause');
return html`
<media-tooltip class="vds-play-tooltip vds-tooltip">
<media-tooltip-trigger>
<media-play-button class="vds-play-button vds-button" aria-label=${$label}>
<media-play-button
class="vds-play-button vds-button"
aria-label=${$i18n(translations, 'Play')}
>
<slot name="play-icon" data-class="vds-play-icon"></slot>
<slot name="pause-icon" data-class="vds-pause-icon"></slot>
<slot name="replay-icon" data-class="vds-replay-icon"></slot>
Expand All @@ -98,14 +99,16 @@ export function DefaultMuteButton({
ref?: RefOrCallback;
}) {
const { translations } = useDefaultLayoutContext(),
{ muted } = useMediaState(),
$label = $signal(() => i18n(translations, muted() ? 'Unmute' : 'Unmute')),
$muteText = $i18n(translations, 'Mute'),
$unmuteText = $i18n(translations, 'Unmute');
return html`
<media-tooltip class="vds-mute-tooltip vds-tooltip">
<media-tooltip-trigger>
<media-mute-button class="vds-mute-button vds-button" aria-label=${$label} ${$ref(ref)}>
<media-mute-button
class="vds-mute-button vds-button"
aria-label=${$i18n(translations, 'Mute')}
${$ref(ref)}
>
<slot name="mute-icon" data-class="vds-mute-icon"></slot>
<slot name="volume-low-icon" data-class="vds-volume-low-icon"></slot>
<slot name="volume-high-icon" data-class="vds-volume-high-icon"></slot>
Expand All @@ -121,16 +124,15 @@ export function DefaultMuteButton({

export function DefaultCaptionButton({ tooltip }: { tooltip: TooltipPlacement }) {
const { translations } = useDefaultLayoutContext(),
{ textTrack } = useMediaState(),
$label = $signal(() =>
i18n(translations, textTrack() ? 'Closed-Captions Off' : 'Closed-Captions On'),
),
$ccOnText = $i18n(translations, 'Closed-Captions On'),
$ccOffText = $i18n(translations, 'Closed-Captions Off');
return html`
<media-tooltip class="vds-caption-tooltip vds-tooltip">
<media-tooltip-trigger>
<media-caption-button class="vds-caption-button vds-button" aria-label=${$label}>
<media-caption-button
class="vds-caption-button vds-button"
aria-label=${$i18n(translations, 'Captions')}
>
<slot name="cc-on-icon" data-class="vds-cc-on-icon"></slot>
<slot name="cc-off-icon" data-class="vds-cc-off-icon"></slot>
</media-caption-button>
Expand All @@ -145,14 +147,15 @@ export function DefaultCaptionButton({ tooltip }: { tooltip: TooltipPlacement })

export function DefaultPIPButton() {
const { translations } = useDefaultLayoutContext(),
{ pictureInPicture } = useMediaState(),
$label = $signal(() => i18n(translations, pictureInPicture() ? 'Exit PiP' : 'Enter PiP')),
$enterText = $i18n(translations, 'Enter PiP'),
$exitText = $i18n(translations, 'Exit PiP');
return html`
<media-tooltip class="vds-pip-tooltip vds-tooltip">
<media-tooltip-trigger>
<media-pip-button class="vds-pip-button vds-button" aria-label=${$label}>
<media-pip-button
class="vds-pip-button vds-button"
aria-label=${$i18n(translations, 'PiP')}
>
<slot name="pip-enter-icon" data-class="vds-pip-enter-icon"></slot>
<slot name="pip-exit-icon" data-class="vds-pip-exit-icon"></slot>
</media-pip-button>
Expand All @@ -167,16 +170,15 @@ export function DefaultPIPButton() {

export function DefaultFullscreenButton({ tooltip }: { tooltip: TooltipPlacement }) {
const { translations } = useDefaultLayoutContext(),
{ fullscreen } = useMediaState(),
$label = $signal(() =>
i18n(translations, fullscreen() ? 'Exit Fullscreen' : 'Enter Fullscreen'),
),
$enterText = $i18n(translations, 'Enter Fullscreen'),
$exitText = $i18n(translations, 'Exit Fullscreen');
return html`
<media-tooltip class="vds-fullscreen-tooltip vds-tooltip">
<media-tooltip-trigger>
<media-fullscreen-button class="vds-fullscreen-button vds-button" aria-label=${$label}>
<media-fullscreen-button
class="vds-fullscreen-button vds-button"
aria-label=${$i18n(translations, 'Fullscreen')}
>
<slot name="fs-enter-icon" data-class="vds-fs-enter-icon"></slot>
<slot name="fs-exit-icon" data-class="vds-fs-exit-icon"></slot>
</media-fullscreen-button>
Expand Down
10 changes: 8 additions & 2 deletions packages/vidstack/src/utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from 'maverick.js';
import {
animationFrameThrottle,
isFunction,
isKeyboardClick,
isTouchEvent,
listenEvent,
Expand All @@ -41,11 +42,16 @@ export function setAttributeIfEmpty(target: Element, name: string, value: string
if (!target.hasAttribute(name)) target.setAttribute(name, value);
}

export function setARIALabel(target: Element, $label: () => string | null) {
export function setARIALabel(target: Element, $label: string | null | ReadSignal<string | null>) {
if (target.hasAttribute('aria-label') || target.hasAttribute('data-no-label')) return;

if (!isFunction($label)) {
setAttribute(target, 'aria-label', $label);
return;
}

function updateAriaDescription() {
setAttribute(target, 'aria-label', $label());
setAttribute(target, 'aria-label', ($label as ReadSignal<string | null>)());
}

if (__SERVER__) updateAriaDescription();
Expand Down

0 comments on commit 6b9d999

Please sign in to comment.