@cloudnest/redxplyr 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/.editorconfig +10 -0
  2. package/.gitpod.yml +6 -0
  3. package/.node-version +1 -0
  4. package/.prettierrc +7 -0
  5. package/.stickler.yml +5 -0
  6. package/.stylelintrc.json +26 -0
  7. package/CHANGELOG.md +16 -0
  8. package/CONTRIBUTING.md +34 -0
  9. package/CONTROLS.md +49 -0
  10. package/Dockerfile +32 -0
  11. package/LICENSE.md +22 -0
  12. package/README.md +194 -0
  13. package/cspell.json +48 -0
  14. package/dist/redxplyr.css +1 -0
  15. package/dist/redxplyr.js +8801 -0
  16. package/dist/redxplyr.min.js +2 -0
  17. package/dist/redxplyr.min.js.map +1 -0
  18. package/dist/redxplyr.min.mjs +1 -0
  19. package/dist/redxplyr.min.mjs.map +1 -0
  20. package/dist/redxplyr.mjs +8793 -0
  21. package/dist/redxplyr.polyfilled.js +9294 -0
  22. package/dist/redxplyr.polyfilled.min.js +2 -0
  23. package/dist/redxplyr.polyfilled.min.js.map +1 -0
  24. package/dist/redxplyr.polyfilled.min.mjs +1 -0
  25. package/dist/redxplyr.polyfilled.min.mjs.map +1 -0
  26. package/dist/redxplyr.polyfilled.mjs +9286 -0
  27. package/dist/redxplyr.svg +1 -0
  28. package/eslint.config.mjs +39 -0
  29. package/gulpfile.js +8 -0
  30. package/package.json +114 -0
  31. package/pnpm-workspace.yaml +8 -0
  32. package/src/js/captions.js +411 -0
  33. package/src/js/config/defaults.js +459 -0
  34. package/src/js/config/states.js +10 -0
  35. package/src/js/config/types.js +34 -0
  36. package/src/js/console.js +28 -0
  37. package/src/js/controls.js +1870 -0
  38. package/src/js/fullscreen.js +305 -0
  39. package/src/js/html5.js +148 -0
  40. package/src/js/listeners.js +854 -0
  41. package/src/js/media.js +61 -0
  42. package/src/js/plugins/ads.js +647 -0
  43. package/src/js/plugins/preview-thumbnails.js +706 -0
  44. package/src/js/plugins/vimeo.js +443 -0
  45. package/src/js/plugins/youtube.js +451 -0
  46. package/src/js/plyr.d.ts +729 -0
  47. package/src/js/plyr.js +1291 -0
  48. package/src/js/plyr.polyfilled.js +13 -0
  49. package/src/js/source.js +155 -0
  50. package/src/js/storage.js +70 -0
  51. package/src/js/support.js +100 -0
  52. package/src/js/ui.js +297 -0
  53. package/src/js/utils/animation.js +33 -0
  54. package/src/js/utils/arrays.js +23 -0
  55. package/src/js/utils/browser.js +21 -0
  56. package/src/js/utils/elements.js +263 -0
  57. package/src/js/utils/events.js +116 -0
  58. package/src/js/utils/fetch.js +45 -0
  59. package/src/js/utils/i18n.js +47 -0
  60. package/src/js/utils/is.js +81 -0
  61. package/src/js/utils/load-image.js +19 -0
  62. package/src/js/utils/load-script.js +14 -0
  63. package/src/js/utils/load-sprite.js +77 -0
  64. package/src/js/utils/numbers.js +17 -0
  65. package/src/js/utils/objects.js +43 -0
  66. package/src/js/utils/promise.js +14 -0
  67. package/src/js/utils/strings.js +80 -0
  68. package/src/js/utils/style.js +148 -0
  69. package/src/js/utils/time.js +36 -0
  70. package/src/js/utils/urls.js +40 -0
  71. package/src/sass/base.scss +69 -0
  72. package/src/sass/components/badges.scss +12 -0
  73. package/src/sass/components/captions.scss +58 -0
  74. package/src/sass/components/control.scss +52 -0
  75. package/src/sass/components/controls.scss +65 -0
  76. package/src/sass/components/menus.scss +205 -0
  77. package/src/sass/components/poster.scss +27 -0
  78. package/src/sass/components/progress.scss +107 -0
  79. package/src/sass/components/sliders.scss +99 -0
  80. package/src/sass/components/times.scss +20 -0
  81. package/src/sass/components/tooltips.scss +91 -0
  82. package/src/sass/components/volume.scss +18 -0
  83. package/src/sass/lib/animation.scss +31 -0
  84. package/src/sass/lib/css-vars.scss +103 -0
  85. package/src/sass/lib/functions.scss +3 -0
  86. package/src/sass/lib/mixins.scss +82 -0
  87. package/src/sass/plugins/ads.scss +53 -0
  88. package/src/sass/plugins/preview-thumbnails/index.scss +121 -0
  89. package/src/sass/plugins/preview-thumbnails/settings.scss +17 -0
  90. package/src/sass/plyr.scss +46 -0
  91. package/src/sass/settings/badges.scss +7 -0
  92. package/src/sass/settings/breakpoints.scss +9 -0
  93. package/src/sass/settings/captions.scss +10 -0
  94. package/src/sass/settings/colors.scss +18 -0
  95. package/src/sass/settings/controls.scss +30 -0
  96. package/src/sass/settings/cosmetics.scss +5 -0
  97. package/src/sass/settings/helpers.scss +7 -0
  98. package/src/sass/settings/menus.scss +13 -0
  99. package/src/sass/settings/progress.scss +18 -0
  100. package/src/sass/settings/sliders.scss +39 -0
  101. package/src/sass/settings/tooltips.scss +11 -0
  102. package/src/sass/settings/type.scss +16 -0
  103. package/src/sass/states/fullscreen.scss +15 -0
  104. package/src/sass/types/audio.scss +61 -0
  105. package/src/sass/types/video.scss +170 -0
  106. package/src/sass/utils/animation.scss +7 -0
  107. package/src/sass/utils/hidden.scss +28 -0
  108. package/src/sprite/plyr-airplay.svg +8 -0
  109. package/src/sprite/plyr-captions-off.svg +7 -0
  110. package/src/sprite/plyr-captions-on.svg +7 -0
  111. package/src/sprite/plyr-download.svg +8 -0
  112. package/src/sprite/plyr-enter-fullscreen.svg +4 -0
  113. package/src/sprite/plyr-exit-fullscreen.svg +4 -0
  114. package/src/sprite/plyr-fast-forward.svg +3 -0
  115. package/src/sprite/plyr-logo-vimeo.svg +6 -0
  116. package/src/sprite/plyr-logo-youtube.svg +6 -0
  117. package/src/sprite/plyr-muted.svg +8 -0
  118. package/src/sprite/plyr-pause.svg +8 -0
  119. package/src/sprite/plyr-pip.svg +6 -0
  120. package/src/sprite/plyr-play.svg +5 -0
  121. package/src/sprite/plyr-restart.svg +5 -0
  122. package/src/sprite/plyr-rewind.svg +3 -0
  123. package/src/sprite/plyr-settings.svg +5 -0
  124. package/src/sprite/plyr-volume.svg +11 -0
  125. package/tasks/build.js +226 -0
  126. package/tasks/deploy.js +216 -0
  127. package/tasks/utils/publish.js +34 -0
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Returns a number whose value is limited to the given range.
3
+ *
4
+ * Example: limit the output of this computation to between 0 and 255
5
+ * (x * 255).clamp(0, 255)
6
+ *
7
+ * @param {number} input
8
+ * @param {number} min The lower boundary of the output range
9
+ * @param {number} max The upper boundary of the output range
10
+ * @returns A number within the bounds of min and max
11
+ * @type Number
12
+ */
13
+ export function clamp(input = 0, min = 0, max = 255) {
14
+ return Math.min(Math.max(input, min), max);
15
+ }
16
+
17
+ export default { clamp };
@@ -0,0 +1,43 @@
1
+ // ==========================================================================
2
+ // Object utils
3
+ // ==========================================================================
4
+
5
+ import is from './is';
6
+
7
+ // Clone nested objects
8
+ export function cloneDeep(object) {
9
+ return JSON.parse(JSON.stringify(object));
10
+ }
11
+
12
+ // Get a nested value in an object
13
+ export function getDeep(object, path) {
14
+ return path.split('.').reduce((obj, key) => obj && obj[key], object);
15
+ }
16
+
17
+ // Deep extend destination object with N more objects
18
+ export function extend(target = {}, ...sources) {
19
+ if (!sources.length) {
20
+ return target;
21
+ }
22
+
23
+ const source = sources.shift();
24
+
25
+ if (!is.object(source)) {
26
+ return target;
27
+ }
28
+
29
+ Object.keys(source).forEach((key) => {
30
+ if (is.object(source[key])) {
31
+ if (!Object.keys(target).includes(key)) {
32
+ Object.assign(target, { [key]: {} });
33
+ }
34
+
35
+ extend(target[key], source[key]);
36
+ }
37
+ else {
38
+ Object.assign(target, { [key]: source[key] });
39
+ }
40
+ });
41
+
42
+ return extend(target, ...sources);
43
+ }
@@ -0,0 +1,14 @@
1
+ import is from './is';
2
+ /**
3
+ * Silence a Promise-like object.
4
+ * This is useful for avoiding non-harmful, but potentially confusing "uncaught
5
+ * play promise" rejection error messages.
6
+ * @param {object} value An object that may or may not be `Promise`-like.
7
+ */
8
+ export function silencePromise(value) {
9
+ if (is.promise(value)) {
10
+ value.then(null, () => {});
11
+ }
12
+ }
13
+
14
+ export default { silencePromise };
@@ -0,0 +1,80 @@
1
+ // ==========================================================================
2
+ // String utils
3
+ // ==========================================================================
4
+
5
+ import is from './is';
6
+
7
+ // Generate a random ID
8
+ export function generateId(prefix) {
9
+ return `${prefix}-${Math.floor(Math.random() * 10000)}`;
10
+ }
11
+
12
+ // Format string
13
+ export function format(input, ...args) {
14
+ if (is.empty(input)) return input;
15
+
16
+ return input.toString().replace(/\{(\d+)\}/g, (_, i) => args[i].toString());
17
+ }
18
+
19
+ // Get percentage
20
+ export function getPercentage(current, max) {
21
+ if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {
22
+ return 0;
23
+ }
24
+
25
+ return ((current / max) * 100).toFixed(2);
26
+ }
27
+
28
+ // Replace all occurrences of a string in a string
29
+ export function replaceAll(input = '', find = '', replace = '') {
30
+ return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
31
+ }
32
+
33
+ // Convert to title case
34
+ export function toTitleCase(input = '') {
35
+ return input.toString().replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.slice(1).toLowerCase());
36
+ }
37
+
38
+ // Convert string to pascalCase
39
+ export function toPascalCase(input = '') {
40
+ let string = input.toString();
41
+
42
+ // Convert kebab case
43
+ string = replaceAll(string, '-', ' ');
44
+
45
+ // Convert snake case
46
+ string = replaceAll(string, '_', ' ');
47
+
48
+ // Convert to title case
49
+ string = toTitleCase(string);
50
+
51
+ // Convert to pascal case
52
+ return replaceAll(string, ' ', '');
53
+ }
54
+
55
+ // Convert string to pascalCase
56
+ export function toCamelCase(input = '') {
57
+ let string = input.toString();
58
+
59
+ // Convert to pascal case
60
+ string = toPascalCase(string);
61
+
62
+ // Convert first character to lowercase
63
+ return string.charAt(0).toLowerCase() + string.slice(1);
64
+ }
65
+
66
+ // Remove HTML from a string
67
+ export function stripHTML(source) {
68
+ const fragment = document.createDocumentFragment();
69
+ const element = document.createElement('div');
70
+ fragment.appendChild(element);
71
+ element.innerHTML = source;
72
+ return fragment.firstChild.textContent;
73
+ }
74
+
75
+ // Like outerHTML, but also works for DocumentFragment
76
+ export function getHTML(element) {
77
+ const wrapper = document.createElement('div');
78
+ wrapper.appendChild(element);
79
+ return wrapper.innerHTML;
80
+ }
@@ -0,0 +1,148 @@
1
+ // ==========================================================================
2
+ // Style utils
3
+ // ==========================================================================
4
+
5
+ import { closest } from './arrays';
6
+ import is from './is';
7
+
8
+ // Check support for a CSS declaration
9
+ export function supportsCSS(declaration) {
10
+ if (!window || !window.CSS) {
11
+ return false;
12
+ }
13
+
14
+ return window.CSS.supports(declaration);
15
+ }
16
+
17
+ // Standard/common aspect ratios
18
+ const standardRatios = [
19
+ [1, 1],
20
+ [4, 3],
21
+ [3, 4],
22
+ [5, 4],
23
+ [4, 5],
24
+ [3, 2],
25
+ [2, 3],
26
+ [16, 10],
27
+ [10, 16],
28
+ [16, 9],
29
+ [9, 16],
30
+ [21, 9],
31
+ [9, 21],
32
+ [32, 9],
33
+ [9, 32],
34
+ ].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {});
35
+
36
+ // Validate an aspect ratio
37
+ export function validateAspectRatio(input) {
38
+ if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
39
+ return false;
40
+ }
41
+
42
+ const ratio = is.array(input) ? input : input.split(':');
43
+
44
+ return ratio.map(Number).every(is.number);
45
+ }
46
+
47
+ // Reduce an aspect ratio to it's lowest form
48
+ export function reduceAspectRatio(ratio) {
49
+ if (!is.array(ratio) || !ratio.every(is.number)) {
50
+ return null;
51
+ }
52
+
53
+ const [width, height] = ratio;
54
+ const getDivider = (w, h) => (h === 0 ? w : getDivider(h, w % h));
55
+ const divider = getDivider(width, height);
56
+
57
+ return [width / divider, height / divider];
58
+ }
59
+
60
+ // Calculate an aspect ratio
61
+ export function getAspectRatio(input) {
62
+ const parse = ratio => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null);
63
+ // Try provided ratio
64
+ let ratio = parse(input);
65
+
66
+ // Get from config
67
+ if (ratio === null) {
68
+ ratio = parse(this.config.ratio);
69
+ }
70
+
71
+ // Get from embed
72
+ if (ratio === null && !is.empty(this.embed) && is.array(this.embed.ratio)) {
73
+ ({ ratio } = this.embed);
74
+ }
75
+
76
+ // Get from HTML5 video
77
+ if (ratio === null && this.isHTML5) {
78
+ const { videoWidth, videoHeight } = this.media;
79
+ ratio = [videoWidth, videoHeight];
80
+ }
81
+
82
+ return reduceAspectRatio(ratio);
83
+ }
84
+
85
+ // Set aspect ratio for responsive container
86
+ export function setAspectRatio(input) {
87
+ if (!this.isVideo) {
88
+ return {};
89
+ }
90
+
91
+ const { wrapper } = this.elements;
92
+ const ratio = getAspectRatio.call(this, input);
93
+
94
+ if (!is.array(ratio)) {
95
+ return {};
96
+ }
97
+
98
+ const [x, y] = reduceAspectRatio(ratio);
99
+ const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`);
100
+ const padding = (100 / x) * y;
101
+
102
+ if (useNative) {
103
+ wrapper.style.aspectRatio = `${x}/${y}`;
104
+ }
105
+ else {
106
+ wrapper.style.paddingBottom = `${padding}%`;
107
+ }
108
+
109
+ // For Vimeo we have an extra <div> to hide the standard controls and UI
110
+ if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
111
+ const height = (100 / this.media.offsetWidth) * Number.parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
112
+ const offset = (height - padding) / (height / 50);
113
+
114
+ if (this.fullscreen.active) {
115
+ wrapper.style.paddingBottom = null;
116
+ }
117
+ else {
118
+ this.media.style.transform = `translateY(-${offset}%)`;
119
+ }
120
+ }
121
+ else if (this.isHTML5) {
122
+ wrapper.classList.add(this.config.classNames.videoFixedRatio);
123
+ }
124
+
125
+ return { padding, ratio };
126
+ }
127
+
128
+ // Round an aspect ratio to closest standard ratio
129
+ export function roundAspectRatio(x, y, tolerance = 0.05) {
130
+ const ratio = x / y;
131
+ const closestRatio = closest(Object.keys(standardRatios), ratio);
132
+
133
+ // Check match is within tolerance
134
+ if (Math.abs(closestRatio - ratio) <= tolerance) {
135
+ return standardRatios[closestRatio];
136
+ }
137
+
138
+ // No match
139
+ return [x, y];
140
+ }
141
+
142
+ // Get the size of the viewport
143
+ // https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions
144
+ export function getViewportSize() {
145
+ const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
146
+ const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
147
+ return [width, height];
148
+ }
@@ -0,0 +1,36 @@
1
+ // ==========================================================================
2
+ // Time utils
3
+ // ==========================================================================
4
+
5
+ import is from './is';
6
+
7
+ // Time helpers
8
+ export const getHours = value => Math.trunc((value / 60 / 60) % 60, 10);
9
+ export const getMinutes = value => Math.trunc((value / 60) % 60, 10);
10
+ export const getSeconds = value => Math.trunc(value % 60, 10);
11
+
12
+ // Format time to UI friendly string
13
+ export function formatTime(time = 0, displayHours = false, inverted = false) {
14
+ // Bail if the value isn't a number
15
+ if (!is.number(time)) {
16
+ return formatTime(undefined, displayHours, inverted);
17
+ }
18
+
19
+ // Format time component to add leading zero
20
+ const format = value => `0${value}`.slice(-2);
21
+ // Breakdown to hours, mins, secs
22
+ let hours = getHours(time);
23
+ const mins = getMinutes(time);
24
+ const secs = getSeconds(time);
25
+
26
+ // Do we need to display hours?
27
+ if (displayHours || hours > 0) {
28
+ hours = `${hours}:`;
29
+ }
30
+ else {
31
+ hours = '';
32
+ }
33
+
34
+ // Render
35
+ return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;
36
+ }
@@ -0,0 +1,40 @@
1
+ // ==========================================================================
2
+ // URL utils
3
+ // ==========================================================================
4
+
5
+ import is from './is';
6
+
7
+ /**
8
+ * Parse a string to a URL object
9
+ * @param {string} input - the URL to be parsed
10
+ * @param {boolean} safe - failsafe parsing
11
+ */
12
+ export function parseUrl(input, safe = true) {
13
+ let url = input;
14
+
15
+ if (safe) {
16
+ const parser = document.createElement('a');
17
+ parser.href = url;
18
+ url = parser.href;
19
+ }
20
+
21
+ try {
22
+ return new URL(url);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ // Convert object to URLSearchParams
30
+ export function buildUrlParams(input) {
31
+ const params = new URLSearchParams();
32
+
33
+ if (is.object(input)) {
34
+ Object.entries(input).forEach(([key, value]) => {
35
+ params.set(key, value);
36
+ });
37
+ }
38
+
39
+ return params;
40
+ }
@@ -0,0 +1,69 @@
1
+ // --------------------------------------------------------------
2
+ // Base styling
3
+ // --------------------------------------------------------------
4
+
5
+ // Base
6
+ .plyr {
7
+ @include plyr-font-smoothing($plyr-font-smoothing);
8
+
9
+ align-items: center;
10
+ direction: ltr;
11
+ display: flex;
12
+ flex-direction: column;
13
+ font-family: $plyr-font-family;
14
+ font-variant-numeric: tabular-nums; // Force monosace-esque number widths
15
+ font-weight: $plyr-font-weight-regular;
16
+ line-height: $plyr-line-height;
17
+ max-width: 100%;
18
+ min-width: 200px;
19
+ position: relative;
20
+ text-shadow: none;
21
+ transition: box-shadow 0.3s ease;
22
+ z-index: 0; // Force any border radius
23
+
24
+ // Media elements
25
+ video,
26
+ audio,
27
+ iframe {
28
+ display: block;
29
+ height: 100%;
30
+ width: 100%;
31
+ }
32
+
33
+ button {
34
+ font: inherit;
35
+ line-height: inherit;
36
+ width: auto;
37
+ }
38
+
39
+ // Ignore focus
40
+ &:focus {
41
+ outline: 0;
42
+ }
43
+ }
44
+
45
+ // border-box everything
46
+ // http://paulirish.com/2012/box-sizing-border-box-ftw/
47
+ @if $plyr-border-box {
48
+ .plyr--full-ui {
49
+ box-sizing: border-box;
50
+
51
+ *,
52
+ *::after,
53
+ *::before {
54
+ box-sizing: inherit;
55
+ }
56
+ }
57
+ }
58
+
59
+ // Fix 300ms delay
60
+ @if $plyr-touch-action {
61
+ .plyr--full-ui {
62
+ a,
63
+ button,
64
+ input,
65
+ label {
66
+ touch-action: manipulation;
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,12 @@
1
+ // --------------------------------------------------------------
2
+ // Badges
3
+ // --------------------------------------------------------------
4
+
5
+ .plyr__badge {
6
+ background: $plyr-badge-background;
7
+ border-radius: $plyr-badge-border-radius;
8
+ color: $plyr-badge-text-color;
9
+ font-size: $plyr-font-size-badge;
10
+ line-height: 1;
11
+ padding: 3px 4px;
12
+ }
@@ -0,0 +1,58 @@
1
+ // --------------------------------------------------------------
2
+ // Captions
3
+ // --------------------------------------------------------------
4
+
5
+ // Hide default captions
6
+ .plyr--full-ui ::-webkit-media-text-track-container {
7
+ display: none;
8
+ }
9
+
10
+ .plyr__captions {
11
+ animation: plyr-fade-in 0.3s ease;
12
+ bottom: 0;
13
+ display: none;
14
+ font-size: $plyr-font-size-captions-small;
15
+ left: 0;
16
+ padding: $plyr-control-spacing;
17
+ position: absolute;
18
+ text-align: center;
19
+ transition: transform 0.4s ease-in-out;
20
+ width: 100%;
21
+
22
+ span:empty {
23
+ display: none;
24
+ }
25
+
26
+ @media (min-width: $plyr-bp-sm) {
27
+ font-size: $plyr-font-size-captions-base;
28
+ padding: calc(#{$plyr-control-spacing} * 2);
29
+ }
30
+
31
+ @media (min-width: $plyr-bp-md) {
32
+ font-size: $plyr-font-size-captions-medium;
33
+ }
34
+ }
35
+
36
+ .plyr--captions-active .plyr__captions {
37
+ display: block;
38
+ }
39
+
40
+ // If the lower controls are shown and not empty
41
+ .plyr:not(.plyr--hide-controls) .plyr__controls:not(:empty) ~ .plyr__captions {
42
+ transform: translateY(calc(#{$plyr-control-spacing} * -4));
43
+ }
44
+
45
+ .plyr__caption {
46
+ background: $plyr-captions-background;
47
+ border-radius: 4px;
48
+ box-decoration-break: clone;
49
+ color: $plyr-captions-text-color;
50
+ line-height: 185%;
51
+ padding: 0.2em 0.5em;
52
+ white-space: pre-wrap;
53
+
54
+ // Firefox adds a <div> when using getCueAsHTML()
55
+ div {
56
+ display: inline;
57
+ }
58
+ }
@@ -0,0 +1,52 @@
1
+ // --------------------------------------------------------------
2
+ // Control buttons
3
+ // --------------------------------------------------------------
4
+
5
+ .plyr__control {
6
+ background: transparent;
7
+ border: 0;
8
+ border-radius: $plyr-control-radius;
9
+ color: inherit;
10
+ cursor: pointer;
11
+ flex-shrink: 0;
12
+ overflow: visible; // IE11
13
+ padding: $plyr-control-padding;
14
+ position: relative;
15
+ transition: all 0.1s ease-in-out;
16
+
17
+ svg {
18
+ display: block;
19
+ fill: currentColor;
20
+ height: $plyr-control-icon-size;
21
+ pointer-events: none;
22
+ width: $plyr-control-icon-size;
23
+ }
24
+
25
+ // Default focus
26
+ &:focus {
27
+ outline: 0;
28
+ }
29
+
30
+ // Tab focus
31
+ &:focus-visible {
32
+ @include plyr-focus-visible;
33
+ }
34
+ }
35
+
36
+ // Remove any link styling
37
+ a.plyr__control {
38
+ text-decoration: none;
39
+
40
+ &::after,
41
+ &::before {
42
+ display: none;
43
+ }
44
+ }
45
+
46
+ // Change icons on state change
47
+ .plyr__control:not(.plyr__control--pressed) .icon--pressed,
48
+ .plyr__control.plyr__control--pressed .icon--not-pressed,
49
+ .plyr__control:not(.plyr__control--pressed) .label--pressed,
50
+ .plyr__control.plyr__control--pressed .label--not-pressed {
51
+ display: none;
52
+ }
@@ -0,0 +1,65 @@
1
+ // --------------------------------------------------------------
2
+ // Controls
3
+ // --------------------------------------------------------------
4
+
5
+ // Hide native controls
6
+ .plyr--full-ui ::-webkit-media-controls {
7
+ display: none;
8
+ }
9
+
10
+ // Playback controls
11
+ .plyr__controls {
12
+ align-items: center;
13
+ display: flex;
14
+ justify-content: flex-end;
15
+ text-align: center;
16
+
17
+ .plyr__progress__container {
18
+ flex: 1;
19
+ min-width: 0; // Fix for Edge issue where content would overflow
20
+ }
21
+
22
+ // Spacing
23
+ .plyr__controls__item {
24
+ margin-left: calc(#{$plyr-control-spacing} / 4);
25
+
26
+ &:first-child {
27
+ margin-left: 0;
28
+ margin-right: auto;
29
+ }
30
+
31
+ &.plyr__progress__container {
32
+ padding-left: calc(#{$plyr-control-spacing} / 4);
33
+ }
34
+
35
+ &.plyr__time {
36
+ padding: 0 calc(#{$plyr-control-spacing} / 2);
37
+ }
38
+
39
+ &.plyr__progress__container:first-child,
40
+ &.plyr__time:first-child,
41
+ &.plyr__time + .plyr__time {
42
+ padding-left: 0;
43
+ }
44
+ }
45
+
46
+ // Hide empty controls
47
+ &:empty {
48
+ display: none;
49
+ }
50
+ }
51
+
52
+ // Some options are hidden by default
53
+ .plyr [data-plyr='captions'],
54
+ .plyr [data-plyr='pip'],
55
+ .plyr [data-plyr='airplay'],
56
+ .plyr [data-plyr='fullscreen'] {
57
+ display: none;
58
+ }
59
+
60
+ .plyr--captions-enabled [data-plyr='captions'],
61
+ .plyr--pip-supported [data-plyr='pip'],
62
+ .plyr--airplay-supported [data-plyr='airplay'],
63
+ .plyr--fullscreen-enabled [data-plyr='fullscreen'] {
64
+ display: inline-block;
65
+ }