Compare commits

...

8 Commits

Author SHA1 Message Date
Sam Potts
0c9759455c chore(release): 3.7.8 2023-03-24 23:02:41 +11:00
Sam Potts
ae59c117b5 feat: demo style tweaks 2023-03-24 22:35:49 +11:00
Sam Potts
8da1a78342 feat: minor style tweaks 2023-03-18 23:51:12 +11:00
Sam Potts
747c5f5f31 chore(release): 3.7.7 2023-03-11 22:35:17 +11:00
Sam Potts
39c6049850 chore: minor syntax tweaks 2023-03-11 22:28:24 +11:00
Sam Potts
0202e8efb0 fix(a11y): leverage native :focus-visible in CSS 2023-03-11 21:15:32 +11:00
Sam Potts
e17d0220c0 fix(a11y): add timer role to time elements 2023-03-11 21:14:43 +11:00
Sam Potts
aa4eaec742 fix(a11y): don’t set tabindex on parent container 2023-03-11 21:14:13 +11:00
34 changed files with 139 additions and 242 deletions

View File

@ -1,3 +1,16 @@
# Changelog
### v3.7.8
- Feat: Minor demo style tweaks
- Fix: Minor style fixes related to backgrounds and border radii (🚨 Requires a SCSS/CSS update 🚨)
### v3.7.7
- Fix (Accessibility): Dont set tabindex on parent container
- Fix (Accessibility): Add `role="timer"` to time elements
- Fix (Accessibility): Leverage native `:focus-visible` in CSS, instead of a custom solution (🚨 Requires a SCSS/CSS update 🚨)
### v3.7.6 ### v3.7.6
- Fix: Revert postinstall script - Fix: Revert postinstall script

View File

@ -137,13 +137,13 @@ See [initialising](#initializing) for more information on advanced setups.
You can use our CDN (provided by [Cloudflare](https://www.cloudflare.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills separately as part of your application but to make life easier you can use the polyfilled build. You can use our CDN (provided by [Cloudflare](https://www.cloudflare.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills separately as part of your application but to make life easier you can use the polyfilled build.
```html ```html
<script src="https://cdn.plyr.io/3.7.6/plyr.js"></script> <script src="https://cdn.plyr.io/3.7.8/plyr.js"></script>
``` ```
...or... ...or...
```html ```html
<script src="https://cdn.plyr.io/3.7.6/plyr.polyfilled.js"></script> <script src="https://cdn.plyr.io/3.7.8/plyr.polyfilled.js"></script>
``` ```
## CSS ## CSS
@ -157,13 +157,13 @@ Include the `plyr.css` stylesheet into your `<head>`.
If you want to use our CDN (provided by [Cloudflare](https://www.cloudflare.com/)) for the default CSS, you can use the following: If you want to use our CDN (provided by [Cloudflare](https://www.cloudflare.com/)) for the default CSS, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/3.7.6/plyr.css" /> <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
``` ```
## SVG Sprite ## SVG Sprite
The SVG sprite is loaded automatically from our CDN (provided by [Cloudflare](https://www.cloudflare.com/)). To change this, see the [options](#options) below. For The SVG sprite is loaded automatically from our CDN (provided by [Cloudflare](https://www.cloudflare.com/)). To change this, see the [options](#options) below. For
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.7.6/plyr.svg`. reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.7.8/plyr.svg`.
### Self hosting ### Self hosting
@ -197,11 +197,10 @@ Here's a list of the properties and what they are used for:
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `--plyr-color-main` | The primary UI color. | ![#f03c15](https://place-hold.it/15/00b3ff/000000?text=+) `#00b3ff` | | `--plyr-color-main` | The primary UI color. | ![#f03c15](https://place-hold.it/15/00b3ff/000000?text=+) `#00b3ff` |
| `--plyr-video-background` | The background color of video and poster wrappers for using alpha channel videos and poster images. | `rgba(0, 0, 0, 1)` | | `--plyr-video-background` | The background color of video and poster wrappers for using alpha channel videos and poster images. | `rgba(0, 0, 0, 1)` |
| `--plyr-tab-focus-color` | The color used for the dotted outline when an element is `:focus-visible` (equivalent) keyboard focus. | `--plyr-color-main` | | `--plyr-focus-visible-color` | The color used for the focus styles when an element is `:focus-visible` (keyboard focused). | `--plyr-color-main` |
| `--plyr-badge-background` | The background color for badges in the menu. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` | | `--plyr-badge-background` | The background color for badges in the menu. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` |
| `--plyr-badge-text-color` | The text color for badges. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-badge-text-color` | The text color for badges. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-badge-border-radius` | The border radius used for badges. | `2px` | | `--plyr-badge-border-radius` | The border radius used for badges. | `2px` |
| `--plyr-tab-focus-color` | The color used to highlight tab (keyboard) focus. | `--plyr-color-main` |
| `--plyr-captions-background` | The color for the background of captions. | `rgba(0, 0, 0, 0.8)` | | `--plyr-captions-background` | The color for the background of captions. | `rgba(0, 0, 0, 0.8)` |
| `--plyr-captions-text-color` | The color used for the captions text. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-captions-text-color` | The color used for the captions text. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-control-icon-size` | The size of the icons used in the controls. | `18px` | | `--plyr-control-icon-size` | The size of the icons used in the controls. | `18px` |

View File

@ -66,42 +66,46 @@
<h1>Pl<span>a</span>y<span>e</span>r</h1> <h1>Pl<span>a</span>y<span>e</span>r</h1>
<p> <p>
A simple, accessible and customisable media player for A simple, accessible and customisable media player for
<button type="button" class="faux-link" data-source="video"> <button type="button" class="link" data-source="video">
<svg class="icon"> <svg class="icon">
<title>HTML5</title> <title>HTML5</title>
<path <path
d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z" d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"
></path></svg ></path>
>Video</button </svg>
Video</button
>, >,
<button type="button" class="faux-link" data-source="audio"> <button type="button" class="link" data-source="audio">
<svg class="icon"> <svg class="icon">
<title>HTML5</title> <title>HTML5</title>
<path <path
d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z" d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"
></path></svg ></path>
>Audio</button </svg>
Audio</button
>, >,
<button type="button" class="faux-link" data-source="youtube"> <button type="button" class="link" data-source="youtube">
<svg class="icon" role="presentation"> <svg class="icon" role="presentation">
<title>YouTube</title> <title>YouTube</title>
<path <path
d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8 d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8
s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z
M6,11V5l5,3L6,11z" M6,11V5l5,3L6,11z"
></path></svg ></path>
>YouTube </svg>
YouTube
</button> </button>
and and
<button type="button" class="faux-link" data-source="vimeo"> <button type="button" class="link" data-source="vimeo">
<svg class="icon" role="presentation"> <svg class="icon" role="presentation">
<title>Vimeo</title> <title>Vimeo</title>
<path <path
d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5 d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5
C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4 C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4
c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z" c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z"
></path></svg ></path>
>Vimeo </svg>
Vimeo
</button> </button>
</p> </p>
@ -177,7 +181,10 @@
d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z" d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"
></path> ></path>
</svg> </svg>
<a href="https://itunes.apple.com/au/movie/view-from-a-blue-moon/id1041586323" target="_blank" <a
href="https://itunes.apple.com/au/movie/view-from-a-blue-moon/id1041586323"
target="_blank"
class="link"
>View From A Blue Moon</a >View From A Blue Moon</a
> >
&copy; Brainfarm &copy; Brainfarm
@ -191,7 +198,7 @@
d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z" d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"
></path> ></path>
</svg> </svg>
<a href="http://www.kishibashi.com/" target="_blank" <a href="http://www.kishibashi.com/" target="_blank" class="link"
>Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a >Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a
> >
&copy; Kishi Bashi &copy; Kishi Bashi
@ -215,7 +222,7 @@
</li> </li>
<li class="plyr__cite plyr__cite--vimeo" hidden> <li class="plyr__cite plyr__cite--vimeo" hidden>
<small> <small>
<a href="https://vimeo.com/40648169" target="_blank">Toob “Wavaphon” Music Video</a> <a href="https://vimeo.com/40648169" target="_blank" class="link">Toob “Wavaphon” Music Video</a>
on&nbsp; on&nbsp;
<span class="color--vimeo"> <span class="color--vimeo">
<svg class="icon" role="presentation"> <svg class="icon" role="presentation">
@ -248,7 +255,7 @@
<a <a
href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&amp;url=http%3A%2F%2Fplyr.io&amp;via=Sam_Potts" href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&amp;url=http%3A%2F%2Fplyr.io&amp;via=Sam_Potts"
target="_blank" target="_blank"
class="js-shr" class="link js-shr"
>tweet it</a >tweet it</a
> >
👍 👍

View File

@ -4,7 +4,6 @@
// Please see README.md in the root or github.com/sampotts/plyr // Please see README.md in the root or github.com/sampotts/plyr
// ========================================================================== // ==========================================================================
import './tab-focus';
import 'custom-event-polyfill'; import 'custom-event-polyfill';
import 'url-polyfill'; import 'url-polyfill';
@ -13,7 +12,6 @@ import Shr from 'shr-buttons';
import Plyr from '../../../src/js/plyr'; import Plyr from '../../../src/js/plyr';
import sources from './sources'; import sources from './sources';
import toggleClass from './toggle-class';
(() => { (() => {
const production = 'plyr.io'; const production = 'plyr.io';
@ -108,10 +106,10 @@ import toggleClass from './toggle-class';
function render(type) { function render(type) {
// Remove active classes // Remove active classes
Array.from(buttons).forEach((button) => toggleClass(button.parentElement, 'active', false)); Array.from(buttons).forEach((button) => button.parentElement.classList.toggle('active', false));
// Set active on parent // Set active on parent
toggleClass(document.querySelector(`[data-source="${type}"]`), 'active', true); document.querySelector(`[data-source="${type}"]`).classList.toggle('active', true);
// Show cite // Show cite
Array.from(document.querySelectorAll('.plyr__cite')).forEach((cite) => { Array.from(document.querySelectorAll('.plyr__cite')).forEach((cite) => {

View File

@ -1,31 +0,0 @@
// Setup tab focus
const container = document.getElementById('container');
const tabClassName = 'tab-focus';
// Remove class on blur
document.addEventListener('focusout', (event) => {
if (!event.target.classList || container.contains(event.target)) {
return;
}
event.target.classList.remove(tabClassName);
});
// Add classname to tabbed elements
document.addEventListener('keydown', (event) => {
if (event.key !== 'Tab') {
return;
}
// Delay the adding of classname until the focus has changed
// This event fires before the focusin event
setTimeout(() => {
const focused = document.activeElement;
if (!focused || !focused.classList || container.contains(focused)) {
return;
}
focused.classList.add(tabClassName);
}, 10);
});

View File

@ -1,5 +0,0 @@
// Toggle class on an element
const toggleClass = (element, className = '', toggle = false) =>
element && element.classList[toggle ? 'add' : 'remove'](className);
export default toggleClass;

View File

@ -7,8 +7,7 @@
.button__count { .button__count {
align-items: center; align-items: center;
border: 0; border: 0;
border-radius: $border-radius-base; border-radius: $border-radius-medium;
box-shadow: 0 1px 1px rgba(#000, 0.1);
display: inline-flex; display: inline-flex;
padding: ($spacing-base * 0.75); padding: ($spacing-base * 0.75);
position: relative; position: relative;
@ -19,45 +18,49 @@
// Buttons // Buttons
.button { .button {
background: $color-button-background; --shadow-color: 0deg 0% 20%;
align-items: center;
background-color: $color-button-background;
background-image: linear-gradient(0deg, transparent, rgba(255, 255, 255, 0.05));
border: 1px solid darken($color-button-background, 5);
box-shadow: 0 0.8px 1px hsl(var(--shadow-color) / 0.05), 0 1.3px 1.6px -1px hsl(var(--shadow-color) / 0.06),
0 2.8px 3.4px -2px hsl(var(--shadow-color) / 0.07);
color: $color-button-text; color: $color-button-text;
display: inline-flex;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
gap: 0.25rem;
padding-left: ($spacing-base * 1.25); padding-left: ($spacing-base * 1.25);
padding-right: ($spacing-base * 1.25); padding-right: ($spacing-base * 1.25);
text-decoration: none;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease; transition: all 0.2s ease;
&:hover, &:hover,
&:focus { &:focus {
background: $color-button-background-hover; background: $color-button-background-hover;
border-color: darken($color-button-background, 7);
// Remove the underline/border // Remove the underline/border
&::after { &::after {
display: none; display: none !important;
} }
} }
&:hover {
box-shadow: 0 2px 2px rgba(#000, 0.1);
}
&:focus { &:focus {
outline: 0; outline: 0;
} }
&.tab-focus { &:focus-visible {
@include tab-focus; @include focus-visible($color-button-background);
} }
&:active { &:active {
box-shadow: none;
top: 1px; top: 1px;
} }
}
// Button group .icon {
.button--with-count { filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1));
display: inline-flex;
.button .icon {
flex-shrink: 0; flex-shrink: 0;
} }
} }
@ -66,19 +69,21 @@
.button__count { .button__count {
animation: fade-in 0.2s ease; animation: fade-in 0.2s ease;
background: $color-button-count-background; background: $color-button-count-background;
border: 1px solid $color-gray-100;
color: $color-button-count-text; color: $color-button-count-text;
margin-left: ($spacing-base * 0.75); margin-left: ($spacing-base * 0.75);
&::before { &::before {
border: $arrow-size solid transparent; background-color: $color-button-count-background;
border-left-width: 0; border: inherit;
border-right-color: $color-button-count-background; border-width: 0 0 1px 1px;
content: ''; content: '';
height: 0; display: block;
height: 8px;
position: absolute; position: absolute;
right: 100%; right: 100%;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%) translateX(50%) translateX(-1px) rotate(45deg);
width: 0; width: 8px;
} }
} }

View File

@ -2,15 +2,9 @@
// Links // Links
// ========================================================================== // ==========================================================================
// Make a <button> look like an <a> .link {
button.faux-link { align-items: center;
@extend a; // stylelint-disable-line border-bottom: 1px dashed currentColor;
@include cancel-button-styles;
}
// Links
a {
border-bottom: 1px dotted currentColor;
color: $color-link; color: $color-link;
position: relative; position: relative;
text-decoration: none; text-decoration: none;
@ -38,8 +32,8 @@ a {
} }
} }
&.tab-focus { &:focus-visible {
@include tab-focus; @include focus-visible($color-link);
} }
&.no-border::after { &.no-border::after {

View File

@ -6,8 +6,10 @@
// Example players // Example players
.plyr { .plyr {
border-radius: $border-radius-large; --shadow-color: 197deg 32% 65%;
box-shadow: 0 2px 15px rgba(#000, 0.1); border-radius: $border-radius-2x-large;
box-shadow: 0 0.5px 0.6px hsl(var(--shadow-color) / 0.36), 0 1.7px 1.9px -0.8px hsl(var(--shadow-color) / 0.36),
0 4.3px 4.8px -1.7px hsl(var(--shadow-color) / 0.36), -0.1px 10.6px 11.9px -2.5px hsl(var(--shadow-color) / 0.36);
margin: $spacing-base auto; margin: $spacing-base auto;
&.plyr--audio { &.plyr--audio {
@ -17,6 +19,7 @@
.plyr__video-wrapper::after { .plyr__video-wrapper::after {
border: 1px solid rgba(#000, 0.15); border: 1px solid rgba(#000, 0.15);
border-bottom-color: rgba(#000, 0.25);
border-radius: inherit; border-radius: inherit;
bottom: 0; bottom: 0;
content: ''; content: '';

View File

@ -37,6 +37,7 @@ main {
aside { aside {
align-items: center; align-items: center;
background: #fff; background: #fff;
box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.05);
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
justify-content: center; justify-content: center;
@ -58,8 +59,8 @@ aside {
a { a {
color: $color-twitter; color: $color-twitter;
&.tab-focus { &:focus-visible {
@include tab-focus($color-twitter); @include focus-visible($color-twitter);
} }
} }
} }

View File

@ -4,30 +4,11 @@
@use 'sass:math'; @use 'sass:math';
// Convert a <button> into an <a>
// ---------------------------------------
@mixin cancel-button-styles() {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
font: inherit;
line-height: $line-height-base;
margin: 0;
padding: 0;
position: relative;
text-align: inherit;
text-shadow: inherit;
user-select: text;
vertical-align: baseline;
width: auto;
}
// Nicer focus styles // Nicer focus styles
// --------------------------------------- // ---------------------------------------
@mixin tab-focus($color: $tab-focus-default-color) { @mixin focus-visible($color: $focus-default-color) {
box-shadow: 0 0 0 3px rgba($color, 0.35); outline: 2px dashed $color;
outline: 0; outline-offset: 2px;
} }
// Use rems for font sizing // Use rems for font sizing

View File

@ -9,3 +9,7 @@
*::before { *::before {
box-sizing: border-box; box-sizing: border-box;
} }
button {
all: unset;
}

View File

@ -39,4 +39,4 @@ $color-button-count-background: #fff;
$color-button-count-text: $color-gray-600; $color-button-count-text: $color-gray-600;
// Focus // Focus
$tab-focus-default-color: #fff; $focus-default-color: $color-brand-primary;

View File

@ -6,8 +6,9 @@
$arrow-size: 5px; $arrow-size: 5px;
// Radii // Radii
$border-radius-base: 4px; $border-radius-small: 4px;
$border-radius-large: 8px; $border-radius-medium: 6px;
$border-radius-2x-large: 12px;
// Background // Background
$page-background: linear-gradient(to left top, $color-background-from, $color-background-to); $page-background: linear-gradient(to left top, $color-background-from, $color-background-to);

View File

@ -0,0 +1,4 @@
*:focus-visible {
outline: 2px dotted $color-brand-primary;
outline-offset: 2px;
}

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "3.7.6", "version": "3.7.8",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io", "homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>", "author": "Sam Potts <sam@potts.es>",

View File

@ -60,7 +60,7 @@ const defaults = {
// Sprite (for icons) // Sprite (for icons)
loadSprite: true, loadSprite: true,
iconPrefix: 'plyr', iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.7.6/plyr.svg', iconUrl: 'https://cdn.plyr.io/3.7.8/plyr.svg',
// Blank video (used to prevent errors on source change) // Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4', blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
@ -379,7 +379,6 @@ const defaults = {
supported: 'plyr--airplay-supported', supported: 'plyr--airplay-supported',
active: 'plyr--airplay-active', active: 'plyr--airplay-active',
}, },
tabFocus: 'plyr__tab-focus',
previewThumbnails: { previewThumbnails: {
// Tooltip thumbs // Tooltip thumbs
thumbContainer: 'plyr__preview-thumb', thumbContainer: 'plyr__preview-thumb',

9
src/js/controls.js vendored
View File

@ -383,6 +383,7 @@ const controls = {
extend(attributes, { extend(attributes, {
class: `${attributes.class ? attributes.class : ''} ${this.config.classNames.display.time} `.trim(), class: `${attributes.class ? attributes.class : ''} ${this.config.classNames.display.time} `.trim(),
'aria-label': i18n.get(type, this.config), 'aria-label': i18n.get(type, this.config),
role: 'timer',
}), }),
'00:00', '00:00',
); );
@ -1105,7 +1106,7 @@ const controls = {
}, },
// Focus the first menu item in a given (or visible) menu // Focus the first menu item in a given (or visible) menu
focusFirstMenuItem(pane, tabFocus = false) { focusFirstMenuItem(pane, focusVisible = false) {
if (this.elements.settings.popup.hidden) { if (this.elements.settings.popup.hidden) {
return; return;
} }
@ -1118,7 +1119,7 @@ const controls = {
const firstItem = target.querySelector('[role^="menuitem"]'); const firstItem = target.querySelector('[role^="menuitem"]');
setFocus.call(this, firstItem, tabFocus); setFocus.call(this, firstItem, focusVisible);
}, },
// Show/hide menu // Show/hide menu
@ -1195,7 +1196,7 @@ const controls = {
}, },
// Show a panel in the menu // Show a panel in the menu
showMenuPanel(type = '', tabFocus = false) { showMenuPanel(type = '', focusVisible = false) {
const target = this.elements.container.querySelector(`#plyr-settings-${this.id}-${type}`); const target = this.elements.container.querySelector(`#plyr-settings-${this.id}-${type}`);
// Nothing to show, bail // Nothing to show, bail
@ -1246,7 +1247,7 @@ const controls = {
toggleHidden(target, false); toggleHidden(target, false);
// Focus the first item // Focus the first item
controls.focusFirstMenuItem.call(this, target, tabFocus); controls.focusFirstMenuItem.call(this, target, focusVisible);
}, },
// Set the download URL // Set the download URL

View File

@ -21,7 +21,6 @@ class Listeners {
this.handleKey = this.handleKey.bind(this); this.handleKey = this.handleKey.bind(this);
this.toggleMenu = this.toggleMenu.bind(this); this.toggleMenu = this.toggleMenu.bind(this);
this.setTabFocus = this.setTabFocus.bind(this);
this.firstTouch = this.firstTouch.bind(this); this.firstTouch = this.firstTouch.bind(this);
} }
@ -194,57 +193,6 @@ class Listeners {
toggleClass(elements.container, player.config.classNames.isTouch, true); toggleClass(elements.container, player.config.classNames.isTouch, true);
}; };
setTabFocus = (event) => {
const { player } = this;
const { elements } = player;
const { key, type, timeStamp } = event;
clearTimeout(this.focusTimer);
// Ignore any key other than tab
if (type === 'keydown' && key !== 'Tab') {
return;
}
// Store reference to event timeStamp
if (type === 'keydown') {
this.lastKeyDown = timeStamp;
}
// Remove current classes
const removeCurrent = () => {
const className = player.config.classNames.tabFocus;
const current = getElements.call(player, `.${className}`);
toggleClass(current, className, false);
};
// Determine if a key was pressed to trigger this event
const wasKeyDown = timeStamp - this.lastKeyDown <= 20;
// Ignore focus events if a key was pressed prior
if (type === 'focus' && !wasKeyDown) {
return;
}
// Remove all current
removeCurrent();
// Delay the adding of classname until the focus has changed
// This event fires before the focusin event
if (type !== 'focusout') {
this.focusTimer = setTimeout(() => {
const focused = document.activeElement;
// Ignore if current focus element isn't inside the player
if (!elements.container.contains(focused)) {
return;
}
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10);
}
};
// Global window & document listeners // Global window & document listeners
global = (toggle = true) => { global = (toggle = true) => {
const { player } = this; const { player } = this;
@ -259,9 +207,6 @@ class Listeners {
// Detect touch by events // Detect touch by events
once.call(player, document.body, 'touchstart', this.firstTouch); once.call(player, document.body, 'touchstart', this.firstTouch);
// Tab focus detection
toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);
}; };
// Container listeners // Container listeners

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v3.7.6 // plyr.js v3.7.8
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -267,7 +267,7 @@ class Plyr {
// Wrap media // Wrap media
if (!is.element(this.elements.container)) { if (!is.element(this.elements.container)) {
this.elements.container = createElement('div', { tabindex: 0 }); this.elements.container = createElement('div');
wrap(this.media, this.elements.container); wrap(this.media, this.elements.container);
} }

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr Polyfilled Build // Plyr Polyfilled Build
// plyr.js v3.7.6 // plyr.js v3.7.8
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================

View File

@ -37,9 +37,7 @@ export function wrap(elements, wrapper) {
// Set attributes // Set attributes
export function setAttributes(element, attributes) { export function setAttributes(element, attributes) {
if (!is.element(element) || is.empty(attributes)) { if (!is.element(element) || is.empty(attributes)) return;
return;
}
// Assume null and undefined attributes should be left out, // Assume null and undefined attributes should be left out,
// Setting them would otherwise convert them to "null" and "undefined" // Setting them would otherwise convert them to "null" and "undefined"
@ -69,18 +67,14 @@ export function createElement(type, attributes, text) {
// Insert an element after another // Insert an element after another
export function insertAfter(element, target) { export function insertAfter(element, target) {
if (!is.element(element) || !is.element(target)) { if (!is.element(element) || !is.element(target)) return;
return;
}
target.parentNode.insertBefore(element, target.nextSibling); target.parentNode.insertBefore(element, target.nextSibling);
} }
// Insert a DocumentFragment // Insert a DocumentFragment
export function insertElement(type, parent, attributes, text) { export function insertElement(type, parent, attributes, text) {
if (!is.element(parent)) { if (!is.element(parent)) return;
return;
}
parent.appendChild(createElement(type, attributes, text)); parent.appendChild(createElement(type, attributes, text));
} }
@ -101,9 +95,7 @@ export function removeElement(element) {
// Remove all child elements // Remove all child elements
export function emptyElement(element) { export function emptyElement(element) {
if (!is.element(element)) { if (!is.element(element)) return;
return;
}
let { length } = element.childNodes; let { length } = element.childNodes;
@ -115,9 +107,7 @@ export function emptyElement(element) {
// Replace element // Replace element
export function replaceElement(newChild, oldChild) { export function replaceElement(newChild, oldChild) {
if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) { if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) return null;
return null;
}
oldChild.parentNode.replaceChild(newChild, oldChild); oldChild.parentNode.replaceChild(newChild, oldChild);
@ -131,9 +121,7 @@ export function getAttributesFromSelector(sel, existingAttributes) {
// '#test' to { id: 'test' } // '#test' to { id: 'test' }
// '[data-test="test"]' to { 'data-test': 'test' } // '[data-test="test"]' to { 'data-test': 'test' }
if (!is.string(sel) || is.empty(sel)) { if (!is.string(sel) || is.empty(sel)) return {};
return {};
}
const attributes = {}; const attributes = {};
const existing = extend({}, existingAttributes); const existing = extend({}, existingAttributes);
@ -181,9 +169,7 @@ export function getAttributesFromSelector(sel, existingAttributes) {
// Toggle hidden // Toggle hidden
export function toggleHidden(element, hidden) { export function toggleHidden(element, hidden) {
if (!is.element(element)) { if (!is.element(element)) return;
return;
}
let hide = hidden; let hide = hidden;
@ -268,16 +254,9 @@ export function getElement(selector) {
} }
// Set focus and tab focus class // Set focus and tab focus class
export function setFocus(element = null, tabFocus = false) { export function setFocus(element = null, focusVisible = false) {
if (!is.element(element)) { if (!is.element(element)) return;
return;
}
// Set regular focus // Set regular focus
element.focus({ preventScroll: true }); element.focus({ preventScroll: true, focusVisible });
// If we want to mimic keyboard focus via tab
if (tabFocus) {
toggleClass(element, this.config.classNames.tabFocus);
}
} }

View File

@ -28,8 +28,8 @@
} }
// Tab focus // Tab focus
&.plyr__tab-focus { &:focus-visible {
@include plyr-tab-focus; @include plyr-focus-visible;
} }
} }

View File

@ -100,7 +100,7 @@
right: calc((#{$plyr-control-padding} * 1.5) - #{$plyr-menu-item-arrow-size}); right: calc((#{$plyr-control-padding} * 1.5) - #{$plyr-menu-item-arrow-size});
} }
&.plyr__tab-focus::after, &:focus-visible::after,
&:hover::after { &:hover::after {
border-left-color: currentColor; border-left-color: currentColor;
} }
@ -132,7 +132,7 @@
top: 100%; top: 100%;
} }
&.plyr__tab-focus::after, &:focus-visible::after,
&:hover::after { &:hover::after {
border-right-color: currentColor; border-right-color: currentColor;
} }
@ -181,7 +181,7 @@
} }
} }
&.plyr__tab-focus::before, &:focus-visible::before,
&:hover::before { &:hover::before {
background: rgba($plyr-color-gray-900, 0.1); background: rgba($plyr-color-gray-900, 0.1);
} }

View File

@ -83,17 +83,17 @@
outline: 0; outline: 0;
} }
&.plyr__tab-focus { &:focus-visible {
&::-webkit-slider-runnable-track { &::-webkit-slider-runnable-track {
@include plyr-tab-focus; @include plyr-focus-visible;
} }
&::-moz-range-track { &::-moz-range-track {
@include plyr-tab-focus; @include plyr-focus-visible;
} }
&::-ms-track { &::-ms-track {
@include plyr-tab-focus; @include plyr-focus-visible;
} }
} }
} }

View File

@ -42,7 +42,7 @@
// Displaying // Displaying
.plyr .plyr__control:hover .plyr__tooltip, .plyr .plyr__control:hover .plyr__tooltip,
.plyr .plyr__control.plyr__tab-focus .plyr__tooltip, .plyr .plyr__control:focus-visible .plyr__tooltip,
.plyr__tooltip--visible { .plyr__tooltip--visible {
opacity: 1; opacity: 1;
transform: translate(-50%, 0) scale(1); transform: translate(-50%, 0) scale(1);
@ -82,7 +82,7 @@
.plyr__controls > .plyr__control:first-child + .plyr__control, .plyr__controls > .plyr__control:first-child + .plyr__control,
.plyr__controls > .plyr__control:last-child { .plyr__controls > .plyr__control:last-child {
&:hover .plyr__tooltip, &:hover .plyr__tooltip,
&.plyr__tab-focus .plyr__tooltip, &:focus-visible .plyr__tooltip,
.plyr__tooltip--visible { .plyr__tooltip--visible {
transform: translate(0, 0) scale(1); transform: translate(0, 0) scale(1);
} }

View File

@ -4,8 +4,8 @@
// Nicer focus styles // Nicer focus styles
// --------------------------------------- // ---------------------------------------
@mixin plyr-tab-focus($color: $plyr-tab-focus-color) { @mixin plyr-focus-visible($color: $plyr-focus-visible-color) {
outline: $color dotted 3px; outline: 2px dashed $color;
outline-offset: 2px; outline-offset: 2px;
} }

View File

@ -4,7 +4,7 @@
$plyr-preview-padding: $plyr-tooltip-padding !default; $plyr-preview-padding: $plyr-tooltip-padding !default;
$plyr-preview-background: $plyr-tooltip-background !default; $plyr-preview-background: $plyr-tooltip-background !default;
$plyr-preview-radius: $plyr-tooltip-radius !default; $plyr-preview-radius: $plyr-menu-radius !default;
$plyr-preview-shadow: $plyr-tooltip-shadow !default; $plyr-preview-shadow: $plyr-tooltip-shadow !default;
$plyr-preview-arrow-size: $plyr-tooltip-arrow-size !default; $plyr-preview-arrow-size: $plyr-tooltip-arrow-size !default;
$plyr-preview-image-background: $plyr-color-gray-200 !default; $plyr-preview-image-background: $plyr-color-gray-200 !default;

View File

@ -6,7 +6,7 @@ $plyr-control-icon-size: var(--plyr-control-icon-size, 18px) !default;
$plyr-control-spacing: var(--plyr-control-spacing, 10px) !default; $plyr-control-spacing: var(--plyr-control-spacing, 10px) !default;
$plyr-control-padding: calc(#{$plyr-control-spacing} * 0.7); $plyr-control-padding: calc(#{$plyr-control-spacing} * 0.7);
$plyr-control-padding: var(--plyr-control-padding, $plyr-control-padding) !default; $plyr-control-padding: var(--plyr-control-padding, $plyr-control-padding) !default;
$plyr-control-radius: var(--plyr-control-radius, 3px) !default; $plyr-control-radius: var(--plyr-control-radius, 4px) !default;
$plyr-control-toggle-checked-background: var( $plyr-control-toggle-checked-background: var(
--plyr-control-toggle-checked-background, --plyr-control-toggle-checked-background,
var(--plyr-color-main, $plyr-color-main) var(--plyr-color-main, $plyr-color-main)

View File

@ -2,4 +2,4 @@
// Cosmetic // Cosmetic
// ========================================================================== // ==========================================================================
$plyr-tab-focus-color: var(--plyr-tab-focus-color, var(--plyr-color-main, $plyr-color-main)) !default; $plyr-focus-visible-color: var(--plyr-focus-visible-color, var(--plyr-color-main, $plyr-color-main)) !default;

View File

@ -3,7 +3,7 @@
// ========================================================================== // ==========================================================================
$plyr-menu-background: var(--plyr-menu-background, rgba(#fff, 0.9)) !default; $plyr-menu-background: var(--plyr-menu-background, rgba(#fff, 0.9)) !default;
$plyr-menu-radius: var(--plyr-menu-radius, 4px) !default; $plyr-menu-radius: var(--plyr-menu-radius, 8px) !default;
$plyr-menu-color: var(--plyr-menu-color, $plyr-color-gray-700) !default; $plyr-menu-color: var(--plyr-menu-color, $plyr-color-gray-700) !default;
$plyr-menu-shadow: var(--plyr-menu-shadow, 0 1px 2px rgba(#000, 0.15)) !default; $plyr-menu-shadow: var(--plyr-menu-shadow, 0 1px 2px rgba(#000, 0.15)) !default;
$plyr-menu-arrow-size: var(--plyr-menu-arrow-size, 4px) !default; $plyr-menu-arrow-size: var(--plyr-menu-arrow-size, 4px) !default;

View File

@ -2,7 +2,7 @@
// Tooltips // Tooltips
// ========================================================================== // ==========================================================================
$plyr-tooltip-background: var(--plyr-tooltip-background, rgba(#fff, 0.9)) !default; $plyr-tooltip-background: var(--plyr-tooltip-background, #fff) !default;
$plyr-tooltip-color: var(--plyr-tooltip-color, $plyr-color-gray-700) !default; $plyr-tooltip-color: var(--plyr-tooltip-color, $plyr-color-gray-700) !default;
$plyr-tooltip-padding: calc(#{$plyr-control-spacing} / 2); $plyr-tooltip-padding: calc(#{$plyr-control-spacing} / 2);
$plyr-tooltip-padding: var(--plyr-tooltip-padding, $plyr-tooltip-padding) !default; $plyr-tooltip-padding: var(--plyr-tooltip-padding, $plyr-tooltip-padding) !default;

View File

@ -17,7 +17,7 @@
// Control elements // Control elements
.plyr--audio .plyr__control { .plyr--audio .plyr__control {
&.plyr__tab-focus, &:focus-visible,
&:hover, &:hover,
&[aria-expanded='true'] { &[aria-expanded='true'] {
background: $plyr-audio-control-background-hover; background: $plyr-audio-control-background-hover;

View File

@ -6,7 +6,6 @@
// Container // Container
.plyr--video { .plyr--video {
background: var(--plyr-video-background, $plyr-video-background);
overflow: hidden; overflow: hidden;
&.plyr--menu-open { &.plyr--menu-open {
@ -16,6 +15,7 @@
.plyr__video-wrapper { .plyr__video-wrapper {
background: var(--plyr-video-background, $plyr-video-background); background: var(--plyr-video-background, $plyr-video-background);
border-radius: inherit;
height: 100%; height: 100%;
margin: auto; margin: auto;
overflow: hidden; overflow: hidden;
@ -87,8 +87,7 @@ $embed-padding: (math.div(100, 16) * 9);
// Control elements // Control elements
.plyr--video .plyr__control { .plyr--video .plyr__control {
// Hover and tab focus &:focus-visible,
&.plyr__tab-focus,
&:hover, &:hover,
&[aria-expanded='true'] { &[aria-expanded='true'] {
background: $plyr-video-control-background-hover; background: $plyr-video-control-background-hover;