@mottosports/motto-video-player
Version:
React video player component for the Motto platform, powered by Shaka Player
1,698 lines (1,681 loc) • 160 kB
JavaScript
"use client";
// src/index.ts
import "shaka-player/dist/controls.css";
// #style-inject:#style-inject
function styleInject(css, { insertAt } = {}) {
if (!css || typeof document === "undefined") return;
const head = document.head || document.getElementsByTagName("head")[0];
const style = document.createElement("style");
style.type = "text/css";
if (insertAt === "top") {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
// src/index.css
styleInject(`/*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root,
:host {
--font-sans:
ui-sans-serif,
system-ui,
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji";
--font-mono:
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
"Liberation Mono",
"Courier New",
monospace;
--color-red-600: oklch(57.7% 0.245 27.325);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
--text-base: 1rem;
--text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-xl: 1.25rem;
--text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
--text-5xl: 3rem;
--text-5xl--line-height: 1;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--tracking-wide: 0.025em;
--tracking-widest: 0.1em;
--radius-md: 0.375rem;
--radius-2xl: 1rem;
--animate-spin: spin 1s linear infinite;
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
--aspect-video: 16 / 9;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
}
}
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html,
:host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp,
pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol,
ul,
menu {
list-style: none;
}
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
vertical-align: middle;
}
img,
video {
max-width: 100%;
height: auto;
}
button,
input,
select,
optgroup,
textarea,
::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit,
::-webkit-datetime-edit-year-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-minute-field,
::-webkit-datetime-edit-second-field,
::-webkit-datetime-edit-millisecond-field,
::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
:-moz-ui-invalid {
box-shadow: none;
}
button,
input:where([type=button], [type=reset], [type=submit]),
::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden=until-found])) {
display: none !important;
}
}
@layer utilities {
.pointer-events-auto {
pointer-events: auto;
}
.pointer-events-none {
pointer-events: none;
}
.visible {
visibility: visible;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.absolute {
position: absolute;
}
.fixed {
position: fixed;
}
.relative {
position: relative;
}
.static {
position: static;
}
.inset-0 {
inset: calc(var(--spacing) * 0);
}
.top-0 {
top: calc(var(--spacing) * 0);
}
.top-4 {
top: calc(var(--spacing) * 4);
}
.right-0 {
right: calc(var(--spacing) * 0);
}
.right-4 {
right: calc(var(--spacing) * 4);
}
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
.bottom-4 {
bottom: calc(var(--spacing) * 4);
}
.left-0 {
left: calc(var(--spacing) * 0);
}
.left-4 {
left: calc(var(--spacing) * 4);
}
.z-10 {
z-index: 10;
}
.z-50 {
z-index: 50;
}
.container {
width: 100%;
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
}
.m-6 {
margin: calc(var(--spacing) * 6);
}
.mt-1 {
margin-top: calc(var(--spacing) * 1);
}
.mt-3 {
margin-top: calc(var(--spacing) * 3);
}
.mb-2 {
margin-bottom: calc(var(--spacing) * 2);
}
.mb-6 {
margin-bottom: calc(var(--spacing) * 6);
}
.flex {
display: flex;
}
.grid {
display: grid;
}
.aspect-video {
aspect-ratio: var(--aspect-video);
}
.h-2 {
height: calc(var(--spacing) * 2);
}
.h-12 {
height: calc(var(--spacing) * 12);
}
.h-24 {
height: calc(var(--spacing) * 24);
}
.h-full {
height: 100%;
}
.w-2 {
width: calc(var(--spacing) * 2);
}
.w-12 {
width: calc(var(--spacing) * 12);
}
.w-24 {
width: calc(var(--spacing) * 24);
}
.w-full {
width: 100%;
}
.animate-pulse {
animation: var(--animate-pulse);
}
.animate-spin {
animation: var(--animate-spin);
}
.auto-cols-max {
grid-auto-columns: max-content;
}
.grid-flow-col {
grid-auto-flow: column;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-stretch {
justify-content: stretch;
}
.gap-1 {
gap: calc(var(--spacing) * 1);
}
.gap-5 {
gap: calc(var(--spacing) * 5);
}
.overflow-hidden {
overflow: hidden;
}
.rounded-full {
border-radius: calc(infinity * 1px);
}
.rounded-md {
border-radius: var(--radius-md);
}
.bg-\\[\\#151515\\] {
background-color: #151515;
}
.bg-black {
background-color: var(--color-black);
}
.bg-red-600 {
background-color: var(--color-red-600);
}
.bg-white {
background-color: var(--color-white);
}
.bg-gradient-to-t {
--tw-gradient-position: to top in oklab;
background-image: linear-gradient(var(--tw-gradient-stops));
}
.from-black\\/70 {
--tw-gradient-from: color-mix(in srgb, #000 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
--tw-gradient-from: color-mix(in oklab, var(--color-black) 70%, transparent);
}
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
}
.to-transparent {
--tw-gradient-to: transparent;
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
}
.bg-cover {
background-size: cover;
}
.bg-center {
background-position: center;
}
.bg-no-repeat {
background-repeat: no-repeat;
}
.p-2 {
padding: calc(var(--spacing) * 2);
}
.p-4 {
padding: calc(var(--spacing) * 4);
}
.px-2 {
padding-inline: calc(var(--spacing) * 2);
}
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
.py-1 {
padding-block: calc(var(--spacing) * 1);
}
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.font-mono {
font-family: var(--font-mono);
}
.text-2xl {
font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height));
}
.text-5xl {
font-size: var(--text-5xl);
line-height: var(--tw-leading, var(--text-5xl--line-height));
}
.text-base {
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
}
.text-lg {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
}
.text-sm {
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
.text-xl {
font-size: var(--text-xl);
line-height: var(--tw-leading, var(--text-xl--line-height));
}
.text-xs {
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
}
.text-\\[10px\\] {
font-size: 10px;
}
.font-bold {
--tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold);
}
.font-medium {
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
}
.font-semibold {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
}
.tracking-wide {
--tw-tracking: var(--tracking-wide);
letter-spacing: var(--tracking-wide);
}
.tracking-widest {
--tw-tracking: var(--tracking-widest);
letter-spacing: var(--tracking-widest);
}
.text-white {
color: var(--color-white);
}
.uppercase {
text-transform: uppercase;
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow:
var(--tw-inset-shadow),
var(--tw-inset-ring-shadow),
var(--tw-ring-offset-shadow),
var(--tw-ring-shadow),
var(--tw-shadow);
}
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.md\\:rounded-2xl {
@media (width >= 48rem) {
border-radius: var(--radius-2xl);
}
}
.md\\:rounded-2xl\\! {
@media (width >= 48rem) {
border-radius: var(--radius-2xl) !important;
}
}
.md\\:text-base {
@media (width >= 48rem) {
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
}
}
.md\\:text-sm {
@media (width >= 48rem) {
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
}
.md\\:text-xl {
@media (width >= 48rem) {
font-size: var(--text-xl);
line-height: var(--tw-leading, var(--text-xl--line-height));
}
}
}
@layer components {
video::-webkit-media-controls {
display: none !important;
}
video::-webkit-media-controls-panel {
display: none !important;
}
video::-webkit-media-controls-play-button {
display: none !important;
}
video::-webkit-media-controls-timeline {
display: none !important;
}
video::-webkit-media-controls-current-time-display {
display: none !important;
}
video::-webkit-media-controls-time-remaining-display {
display: none !important;
}
video::-webkit-media-controls-mute-button {
display: none !important;
}
video::-webkit-media-controls-volume-slider {
display: none !important;
}
video::-webkit-media-controls-fullscreen-button {
display: none !important;
}
video::-webkit-media-controls-overlay-play-button {
display: none !important;
}
video::-moz-media-controls {
display: none !important;
}
video {
outline: none !important;
}
video[controls] {
-webkit-appearance: none !important;
appearance: none !important;
}
video::-webkit-media-controls-enclosure {
display: none !important;
}
video::-webkit-media-controls-start-playback-button {
display: none !important;
}
video[controls]::-webkit-media-controls,
video[controls]::-webkit-media-controls-panel,
video[controls]::-webkit-media-controls-play-button,
video[controls]::-webkit-media-controls-timeline,
video[controls]::-webkit-media-controls-current-time-display,
video[controls]::-webkit-media-controls-time-remaining-display,
video[controls]::-webkit-media-controls-mute-button,
video[controls]::-webkit-media-controls-volume-slider,
video[controls]::-webkit-media-controls-fullscreen-button,
video[controls]::-webkit-media-controls-overlay-play-button,
video[controls]::-webkit-media-controls-enclosure,
video[controls]::-webkit-media-controls-start-playback-button {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
pointer-events: none !important;
}
video[controls]::-moz-media-controls {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}
.motto-video-container {
position: relative;
width: 100%;
min-height: 300px;
}
@supports (aspect-ratio: 16/9) {
.motto-video-container {
min-height: auto;
}
}
.motto-video-responsive {
position: absolute;
top: calc(var(--spacing) * 0);
left: calc(var(--spacing) * 0);
height: 100%;
width: 100%;
}
.motto-skip-button {
position: absolute;
top: calc(1/2 * 100%);
z-index: 10;
display: flex;
height: calc(var(--spacing) * 16);
width: calc(var(--spacing) * 16);
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
cursor: pointer;
align-items: center;
justify-content: center;
border-radius: calc(infinity * 1px);
border-style: var(--tw-border-style);
border-width: 0px;
background-color: color-mix(in srgb, #000 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-black) 70%, transparent);
}
font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height));
color: var(--color-white);
opacity: 80%;
transition-property: all;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
--tw-duration: 200ms;
transition-duration: 200ms;
&:hover {
@media (hover: hover) {
--tw-scale-x: 110%;
--tw-scale-y: 110%;
--tw-scale-z: 110%;
scale: var(--tw-scale-x) var(--tw-scale-y);
}
}
&:hover {
@media (hover: hover) {
opacity: 100%;
}
}
&:active {
--tw-scale-x: 95%;
--tw-scale-y: 95%;
--tw-scale-z: 95%;
scale: var(--tw-scale-x) var(--tw-scale-y);
}
}
.motto-skip-button-back {
left: calc(var(--spacing) * 5);
}
.motto-skip-button-forward {
right: calc(var(--spacing) * 5);
}
}
.shaka-seek-bar-container {
height: 6px !important;
width: 100% !important;
margin: 8px 0 !important;
border-radius: 4px !important;
position: relative !important;
border-top: none !important;
border-bottom: none !important;
box-shadow: none !important;
}
.shaka-seek-bar {
height: 6px !important;
width: 100% !important;
-webkit-appearance: none !important;
appearance: none !important;
background: transparent !important;
cursor: pointer !important;
border: none !important;
outline: none !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
border-radius: 4px !important;
}
.shaka-seek-bar::-webkit-slider-runnable-track {
height: 6px !important;
background: transparent !important;
border-radius: 4px !important;
border: none !important;
}
.shaka-seek-bar::-moz-range-track {
height: 6px !important;
background: transparent !important;
border-radius: 4px !important;
border: none !important;
}
.shaka-seek-bar::-webkit-slider-thumb {
-webkit-appearance: none !important;
appearance: none !important;
width: 16px !important;
height: 16px !important;
border-radius: 50% !important;
background: #ffffff !important;
cursor: pointer !important;
border: 2px solid #ffffff !important;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
margin-top: -4px !important;
}
.shaka-seek-bar::-moz-range-thumb {
width: 16px !important;
height: 16px !important;
border-radius: 50% !important;
background: #ffffff !important;
cursor: pointer !important;
border: 2px solid #ffffff !important;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
margin-top: -4px !important;
}
.motto-skip-back-button,
.motto-skip-forward-button,
.motto-native-skip-button {
background: transparent !important;
border: none !important;
padding: 4px !important;
margin: 0px !important;
cursor: pointer !important;
color: #ffffff !important;
transition: all 0.2s ease !important;
min-width: 32px !important;
height: 32px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
border-radius: 4px !important;
width: 25px;
}
.motto-skip-back-button:hover,
.motto-skip-forward-button:hover,
.motto-native-skip-button:hover {
opacity: 0.8 !important;
background: transparent !important;
transform: scale(1.05) !important;
}
.motto-skip-back-button:active,
.motto-skip-forward-button:active,
.motto-native-skip-button:active {
transform: scale(0.95) !important;
}
.motto-skip-back-button svg,
.motto-skip-forward-button svg,
.motto-native-skip-button svg {
width: 24px !important;
height: 24px !important;
}
.shaka-spinner-svg {
color: white !important;
fill: white !important;
}
.shaka-spinner-path {
stroke: white !important;
fill: none !important;
}
.shaka-spinner-container {
color: white !important;
}
.shaka-buffering-spinner {
color: white !important;
fill: white !important;
}
.shaka-buffering-spinner svg {
color: white !important;
fill: white !important;
}
.shaka-buffering-spinner path {
stroke: white !important;
fill: none !important;
}
[data-shaka-player-container] .shaka-spinner,
[data-shaka-player-container] .spinner {
color: white !important;
border-color: white !important;
}
.material-icons.shaka-spinner {
color: white !important;
}
.shaka-controls-container .shaka-spinner,
.shaka-video-container .shaka-spinner {
color: white !important;
fill: white !important;
}
.shaka-controls-container .shaka-spinner svg,
.shaka-video-container .shaka-spinner svg {
color: white !important;
fill: white !important;
}
.shaka-controls-container .shaka-spinner path,
.shaka-video-container .shaka-spinner path {
stroke: white !important;
}
.motto-video-loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
linear-gradient(
135deg,
#1a1a1a 0%,
#2d2d2d 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
transition: opacity 0.3s ease;
}
.motto-video-loading-overlay.hidden {
opacity: 0;
pointer-events: none;
}
.motto-video-loading-content {
text-align: center;
color: white;
}
.motto-video-loading-icon {
width: 64px;
height: 64px;
margin-bottom: 16px;
opacity: 0.7;
}
.motto-video-loading-text {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
}
.motto-video-loading-subtext {
font-size: 14px;
opacity: 0.7;
}
@keyframes pulse-live {
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.shaka-play-button {
background: rgba(255, 255, 255, 0.1) !important;
border: none !important;
color: white !important;
padding: 10px !important;
border-radius: 100% !important;
transition: all 0.2s ease !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
min-width: 55px !important;
height: 55px !important;
}
.shaka-play-button-container {
background: transparent;
transition: all 0.2s ease !important;
}
.motto-video-container:not(.no-cursor) .shaka-play-button-container {
background: rgba(0, 0, 0, 0.3);
transition: all 0.s ease !important;
}
.shaka-play-button:hover {
background: rgba(255, 255, 255, 0.2) !important;
transform: scale(1.05) !important;
}
.shaka-play-button:active {
transform: scale(0.95) !important;
}
.shaka-play-button > * {
display: none !important;
}
.shaka-play-button::after {
content: "" !important;
width: 35px !important;
height: 35px !important;
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z" clip-rule="evenodd" /></svg>') !important;
background-repeat: no-repeat !important;
background-size: contain !important;
background-position: center !important;
display: block !important;
}
.shaka-play-button[aria-label*=Play]::after {
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z" clip-rule="evenodd" /></svg>') !important;
}
.shaka-play-button[aria-label*=Pause]::after {
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path fill-rule="evenodd" d="M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z" clip-rule="evenodd" /></svg>') !important;
}
.motto-video-container {
background: black;
}
.motto-video-container video {
width: 100% !important;
height: 100% !important;
margin-left: auto !important;
margin-right: auto !important;
}
@property --tw-gradient-position { syntax: "*"; inherits: false; }
@property --tw-gradient-from { syntax: "<color>"; inherits: false; initial-value: #0000; }
@property --tw-gradient-via { syntax: "<color>"; inherits: false; initial-value: #0000; }
@property --tw-gradient-to { syntax: "<color>"; inherits: false; initial-value: #0000; }
@property --tw-gradient-stops { syntax: "*"; inherits: false; }
@property --tw-gradient-via-stops { syntax: "*"; inherits: false; }
@property --tw-gradient-from-position { syntax: "<length-percentage>"; inherits: false; initial-value: 0%; }
@property --tw-gradient-via-position { syntax: "<length-percentage>"; inherits: false; initial-value: 50%; }
@property --tw-gradient-to-position { syntax: "<length-percentage>"; inherits: false; initial-value: 100%; }
@property --tw-font-weight { syntax: "*"; inherits: false; }
@property --tw-tracking { syntax: "*"; inherits: false; }
@property --tw-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }
@property --tw-shadow-color { syntax: "*"; inherits: false; }
@property --tw-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --tw-inset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }
@property --tw-inset-shadow-color { syntax: "*"; inherits: false; }
@property --tw-inset-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --tw-ring-color { syntax: "*"; inherits: false; }
@property --tw-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }
@property --tw-inset-ring-color { syntax: "*"; inherits: false; }
@property --tw-inset-ring-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }
@property --tw-ring-inset { syntax: "*"; inherits: false; }
@property --tw-ring-offset-width { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --tw-ring-offset-color { syntax: "*"; inherits: false; initial-value: #fff; }
@property --tw-ring-offset-shadow { syntax: "*"; inherits: false; initial-value: 0 0 #0000; }
@property --tw-blur { syntax: "*"; inherits: false; }
@property --tw-brightness { syntax: "*"; inherits: false; }
@property --tw-contrast { syntax: "*"; inherits: false; }
@property --tw-grayscale { syntax: "*"; inherits: false; }
@property --tw-hue-rotate { syntax: "*"; inherits: false; }
@property --tw-invert { syntax: "*"; inherits: false; }
@property --tw-opacity { syntax: "*"; inherits: false; }
@property --tw-saturate { syntax: "*"; inherits: false; }
@property --tw-sepia { syntax: "*"; inherits: false; }
@property --tw-drop-shadow { syntax: "*"; inherits: false; }
@property --tw-drop-shadow-color { syntax: "*"; inherits: false; }
@property --tw-drop-shadow-alpha { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --tw-drop-shadow-size { syntax: "*"; inherits: false; }
@property --tw-translate-x { syntax: "*"; inherits: false; initial-value: 0; }
@property --tw-translate-y { syntax: "*"; inherits: false; initial-value: 0; }
@property --tw-translate-z { syntax: "*"; inherits: false; initial-value: 0; }
@property --tw-border-style { syntax: "*"; inherits: false; initial-value: solid; }
@property --tw-duration { syntax: "*"; inherits: false; }
@property --tw-scale-x { syntax: "*"; inherits: false; initial-value: 1; }
@property --tw-scale-y { syntax: "*"; inherits: false; initial-value: 1; }
@property --tw-scale-z { syntax: "*"; inherits: false; initial-value: 1; }
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
50% {
opacity: 0.5;
}
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*,
::before,
::after,
::backdrop {
--tw-gradient-position: initial;
--tw-gradient-from: #0000;
--tw-gradient-via: #0000;
--tw-gradient-to: #0000;
--tw-gradient-stops: initial;
--tw-gradient-via-stops: initial;
--tw-gradient-from-position: 0%;
--tw-gradient-via-position: 50%;
--tw-gradient-to-position: 100%;
--tw-font-weight: initial;
--tw-tracking: initial;
--tw-shadow: 0 0 #0000;
--tw-shadow-color: initial;
--tw-shadow-alpha: 100%;
--tw-inset-shadow: 0 0 #0000;
--tw-inset-shadow-color: initial;
--tw-inset-shadow-alpha: 100%;
--tw-ring-color: initial;
--tw-ring-shadow: 0 0 #0000;
--tw-inset-ring-color: initial;
--tw-inset-ring-shadow: 0 0 #0000;
--tw-ring-inset: initial;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-offset-shadow: 0 0 #0000;
--tw-blur: initial;
--tw-brightness: initial;
--tw-contrast: initial;
--tw-grayscale: initial;
--tw-hue-rotate: initial;
--tw-invert: initial;
--tw-opacity: initial;
--tw-saturate: initial;
--tw-sepia: initial;
--tw-drop-shadow: initial;
--tw-drop-shadow-color: initial;
--tw-drop-shadow-alpha: 100%;
--tw-drop-shadow-size: initial;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-translate-z: 0;
--tw-border-style: solid;
--tw-duration: initial;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-scale-z: 1;
}
}
}
`);
// src/Player.tsx
import { forwardRef, useEffect as useEffect5, useRef as useRef8, useImperativeHandle } from "react";
import shaka2 from "shaka-player/dist/shaka-player.ui";
// src/hooks/useShakePlayer.ts
import { useRef, useCallback } from "react";
import { Player as ShakaPlayer, polyfill } from "shaka-player/dist/shaka-player.ui";
var useShakePlayer = ({
src,
shakaConfig,
drmConfig,
onError,
onPlayerReady
}) => {
const playerRef = useRef(null);
const initializePlayer = useCallback(async (video) => {
try {
polyfill.installAll();
if (!ShakaPlayer.isBrowserSupported()) {
throw new Error("Browser not supported by Shaka Player");
}
const player = new ShakaPlayer();
playerRef.current = player;
await player.attach(video);
if (shakaConfig) {
player.configure(shakaConfig);
}
if (drmConfig) {
if (drmConfig.clearKeys) {
player.configure({ "drm.clearKeys": drmConfig.clearKeys });
}
if (drmConfig.servers) {
player.configure({ "drm.servers": drmConfig.servers });
}
}
player.addEventListener("error", (event) => {
const error = event.detail;
if (error?.code === 7e3) {
return;
}
console.error("Shaka Player Error:", error);
onError?.(new Error(`Shaka Player Error: ${error.message || "Unknown error"}`));
});
await player.load(src);
onPlayerReady?.(player);
return player;
} catch (error) {
if (error?.code === 7e3) {
return;
}
console.error("Error initializing Shaka Player:", error);
onError?.(error);
throw error;
}
}, [shakaConfig, drmConfig, src, onError, onPlayerReady]);
const destroyPlayer = useCallback(async () => {
if (playerRef.current) {
try {
await playerRef.current.destroy();
} catch (error) {
console.warn("Error destroying Shaka Player:", error);
} finally {
playerRef.current = null;
}
}
}, []);
return {
playerRef,
initializePlayer,
destroyPlayer
};
};
// src/hooks/useQualityControl.ts
import { useCallback as useCallback2 } from "react";
var useQualityControl = (playerRef, qualityConfig, onQualityChange) => {
const getAvailableQualities = useCallback2(() => {
if (!playerRef.current) return [];
const tracks = playerRef.current.getVariantTracks();
const qualities = tracks.filter(
(track, index, self) => index === self.findIndex((t) => t.height === track.height)
).map((track) => ({
height: track.height || 0,
bandwidth: track.bandwidth || 0,
label: `${track.height}p`
})).sort((a, b) => b.height - a.height);
return qualities;
}, [playerRef]);
const setQuality = useCallback2((height) => {
if (!playerRef.current) return;
if (height === 0) {
playerRef.current.configure({
abr: {
enabled: true,
switchInterval: 2,
// quicker re-checks
clearBufferSwitch: true,
safeMarginSwitch: 10
// leave ~10 s in front of the playhead }
}
});
} else {
playerRef.current.configure({
abr: {
enabled: false,
switchInterval: 2,
// quicker re-checks
clearBufferSwitch: true,
safeMarginSwitch: 10
// leave ~10 s in front of the playhead }
}
});
const tracks = playerRef.current.getVariantTracks();
const targetTrack = tracks.find((track) => track.height === height);
if (targetTrack) {
playerRef.current.selectVariantTrack(
targetTrack,
/* clearBuffer= */
true
);
}
}
}, [playerRef]);
const setupQualityTracking = useCallback2(() => {
if (!playerRef.current || !onQualityChange) return;
const handleQualityChange = () => {
const activeTrack = playerRef.current.getVariantTracks().find((track) => track.active);
if (activeTrack) {
onQualityChange({
height: activeTrack.height || 0,
bandwidth: activeTrack.bandwidth || 0
});
}
};
playerRef.current.addEventListener("variantchanged", handleQualityChange);
return () => {
playerRef.current?.removeEventListener("variantchanged", handleQualityChange);
};
}, [playerRef, onQualityChange]);
const configureQuality = useCallback2(() => {
if (!playerRef.current || !qualityConfig) return;
if (qualityConfig.enableAdaptation !== void 0) {
playerRef.current.configure({
abr: { enabled: qualityConfig.enableAdaptation }
});
}
if (qualityConfig.selectedQuality !== void 0) {
setQuality(qualityConfig.selectedQuality);
}
}, [playerRef, qualityConfig, setQuality]);
return {
getAvailableQualities,
setQuality,
setupQualityTracking,
configureQuality
};
};
// src/hooks/useSkipControls.ts
import { useCallback as useCallback3 } from "react";
var useSkipControls = (videoRef, onSkipBack, onSkipForward) => {
const skipDuration = 15;
const skipBack = useCallback3(() => {
const video = videoRef.current;
if (!video) return;
const newTime = Math.max(0, video.currentTime - skipDuration);
video.currentTime = newTime;
onSkipBack?.(newTime);
}, [videoRef, onSkipBack]);
const skipForward = useCallback3(() => {
const video = videoRef.current;
if (!video) return;
const newTime = Math.min(video.duration || 0, video.currentTime + skipDuration);
video.currentTime = newTime;
onSkipForward?.(newTime);
}, [videoRef, onSkipForward]);
const shouldShowSkipControls = useCallback3(() => {
return true;
}, []);
return {
skipBack,
skipForward,
skipDuration,
shouldShowSkipControls
};
};
// src/hooks/useMuxAnalytics.ts
import { useCallback as useCallback4, useRef as useRef3 } from "react";
import initShakaPlayerMux from "@mux/mux-data-shakaplayer";
import shaka from "shaka-player/dist/shaka-player.ui";
// package.json
var version = "1.0.1-rc.22";
// src/hooks/useMuxAnalytics.ts
var useMuxAnalytics = (playerRef, muxConfig, onMuxReady, onMuxDataUpdate) => {
const shakaPlayerMuxRef = useRef3(null);
const initializeMux = useCallback4(() => {
if (!muxConfig || !playerRef.current) return;
try {
const playerInitTime = initShakaPlayerMux.utils.now();
const muxOptions = {
debug: muxConfig.debug || false,
disableCookies: muxConfig.disableCookies || false,
respectDoNotTrack: muxConfig.respectDoNotTrack || false,
automaticErrorTracking: muxConfig.automaticErrorTracking !== false,
...muxConfig.beaconCollectionDomain && { beaconCollectionDomain: muxConfig.beaconCollectionDomain },
...muxConfig.errorTranslator && { errorTranslator: muxConfig.errorTranslator },
data: {
env_key: muxConfig.envKey,
player_name: muxConfig?.metadata?.player_name,
player_version: version,
player_init_time: playerInitTime,
video_title: muxConfig?.metadata?.video_title ?? "",
video_id: muxConfig?.metadata?.video_id ?? "",
viewer_user_id: muxConfig?.metadata?.viewer_user_id ?? "",
...muxConfig.metadata
}
};
shakaPlayerMuxRef.current = initShakaPlayerMux(playerRef.current, muxOptions, shaka);
onMuxReady?.();
} catch (error) {
console.error("Failed to initialize Mux Analytics:", error);
}
}, [muxConfig, onMuxReady, playerRef]);
const updateMuxData = useCallback4((data) => {
if (playerRef.current?.mux?.updateData) {
try {
playerRef.current.mux.updateData(data);
onMuxDataUpdate?.(data);
} catch (error) {
console.error("Failed to update Mux data:", error);
}
}
}, [onMuxDataUpdate, playerRef]);
const handleMuxError = useCallback4((error) => {
if (shakaPlayerMuxRef.current?.loadErrorHandler) {
shakaPlayerMuxRef.current.loadErrorHandler(error);
}
}, []);
const destroyMux = useCallback4(() => {
if (playerRef.current?.mux?.destroy) {
try {
playerRef.current.mux.destroy();
} catch (error) {
console.error("Error destroying Mux:", error);
}
}
if (shakaPlayerMuxRef.current) {
shakaPlayerMuxRef.current = null;
}
}, [playerRef]);
return {
initializeMux,
updateMuxData,
handleMuxError,
destroyMux,
shakaPlayerMuxRef
};
};
// src/hooks/useShakaUI.ts
import { useCallback as useCallback5, useRef as useRef4 } from "react";
import { ui as ShakaUI } from "shaka-player/dist/shaka-player.ui";
// src/icons/SkipBackIcon.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var SkipBackIcon = ({ size = 24, className = "" }) => {
return /* @__PURE__ */ jsxs(
"svg",
{
width: size,
height: size,
strokeWidth: "2",
viewBox: "0 0 24 24",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
className,
children: [
/* @__PURE__ */ jsx(
"path",
{
d: "M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx(
"path",
{
d: "M9 9L9 16",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx(
"path",
{
d: "M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx(
"path",
{
d: "M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}
)
]
}
);
};
// src/icons/SkipForwardIcon.tsx
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
var SkipForwardIcon = ({ size = 24, className = "" }) => {
return /* @__PURE__ */ jsxs2(
"svg",
{
width: size,
height: size,
strokeWidth: "2",
viewBox: "0 0 24 24",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
className,
children: [
/* @__PURE__ */ jsx2(
"path",
{
d: "M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4",
stroke: "currentColor",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx2(
"path",
{
d: "M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6",
stroke: "currentColor",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx2(
"path",
{
d: "M9 9L9 16",
stroke: "currentColor",
strokeLinecap: "round",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsx2(
"path",
{
d: "M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16",
stroke: "currentColor",
strokeLinecap: "round",
strokeLinejoin: "round"
}
)
]
}
);
};
// src/icons/BigPlayIcon.tsx
import { jsx as jsx3 } from "react/jsx-runtime";
var BigPlayIcon = ({ size = 40, className = "" }) => {
return /* @__PURE__ */ jsx3(
"svg",
{
width: size,
height: size,
viewBox: "0 0 24 24",
fill: "currentColor",
xmlns: "http://www.w3.org/2000/svg",
className,
children: /* @__PURE__ */ jsx3(
"path",
{
fillRule: "evenodd",
d: "M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z",
clipRule: "evenodd"
}
)
}
);
};
// src/utils/renderIcon.ts
import { renderToStaticMarkup } from "react-dom/server";
import { createElement } from "react";
var renderIcon = (Component, props = {}) => {
return renderToStaticMarkup(createElement(Component, props));
};
// src/hooks/useShakaUI.ts
var SkipBackButton = class {
constructor(parent, controls, onSkipBack, iconSize = 24) {
this.parent = parent;
this.controls = controls;
this.eventManager = { listen: (element, event, handler) => {
element.addEventListener(event, handler);
} };
this.button_ = document.createElement("button");
this.button_.className = "shaka-button motto-native-skip-button";
this.button_.innerHTML = renderIcon(SkipBackIcon, { size: iconSize });
this.button_.title = "Skip back 15 seconds";
this.button_.setAttribute("aria-label", "Skip back 15 seconds");
this.parent.appendChild(this.button_);
this.eventManager.listen(this.button_, "click", () => {
const video = this.controls.getVideo();
if (video) {
const newTime = Math.max(0, video.currentTime - 15);
video.currentTime = newTime;
onSkipBack?.(newTime);
}
});
}
// Shaka UI will call `release` when the controls are destroyed.
// Provide a no-op implementation to avoid TypeErrors.
release() {
}
};
var SkipForwardButton = class {
constructor(parent, controls, onSkipForward, iconSize = 24) {
this.parent = parent;
this.controls = controls;
this.eventManager = { listen: (element, event, handler) => {
element.addEventListener(event, handler);
} };
this.button_ = document.createElement("button");
this.button_.className = "shaka-button motto-native-skip-button";
this.button_.innerHTML = renderIcon(SkipForwardIcon, { size: iconSize });
this.button_.title = "Skip forward 15 seconds";
this.button_.setAttribute("aria-label", "Skip forward 15 seconds");
this.parent.appendChild(this.button_);
this.eventManager.listen(this.button_, "click", () => {
const video = this.controls.getVideo();
if (video) {
const newTime = Math.min(video.duration || 0, video.currentTime + 15);
video.currentTime = newTime;
onSkipForward?.(newTime);
}
});
}
release() {
}
};
var SkipBackButtonFactory = class {
constructor(onSkipBack, iconSize) {
this.onSkipBack = onSkipBack;
this.iconSize = iconSize;
}
create(rootElement, controls) {
return new SkipBackButton(rootElement, controls, this.onSkipBack, this.iconSize);
}
};
var SkipForwardButtonFactory = class {
constructor(onSkipForward, iconSize) {
this.onSkipForward = onSkipForward;
this.iconSize = iconSize;
}
create(rootElement, controls) {
return new SkipForwardButton(rootElement, controls, this.onSkipForward, this.iconSize);
}
};
var useShakaUI = (playerRef, containerRef, videoRef, controls, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes) => {
const uiRef = useRef4(null);
const registeredElements = useRef4(/* @__PURE__ */ new Set());
const initializeUI = useCallback5(async () => {
if (!controls || !containerRef.current || !playerRef.current || !videoRef.current) {
return null;
}
if (!registeredElements.current.has("skip_back_button")) {
ShakaUI.Controls.registerElement("skip_back_button", new SkipBackButtonFactory(onSkipBack, iconSizes?.skipButtons));
registeredElements.current.add("skip_back_button");
}
if (!registeredElements.current.has("skip_forward_button")) {
ShakaUI.Controls.registerElement("skip_forward_button", new SkipForwardButtonFactory(onSkipForward, iconSizes?.skipButtons));
registeredElements.current.add("skip_forward_button");
}
const ui = new ShakaUI.Overlay(playerRef.current, containerRef.current, videoRef.current);
uiRef.current = ui;
const isMobile = window.innerWidth <= 767;
const controlPanelElements = [
...isMobile ? [] : ["skip_back_button"],
...isMobile ? [] : ["play_pause"],
...isMobile ? [] : ["skip_forward_button"],
"mute",
...isMobile ? [] : ["volume"],
// Only include volume on desktop
"time_and_duration",
"spacer",
"fullscreen",
"cast",
"overflow_menu"
];
const uiConfig = {
seekBarColors: {
base: seekbarColors?.base || "rgba(255, 255, 255, 0.3)",
// Unbuffered track
buffered: seekbarColors?.buffered || "rgba(255, 255, 255, 0.5)",
// Buffered but not played
played: seekbarColors?.played || "#ffffff"
// Progress/played portion (white)
},
controlPanelElements,
addBigPlayButton: isMobile,
...chromecastConfig?.receiverApplicationId && {
"castReceiverAppId": chromecastConfig.receiverApplicationId,
"castAndroidReceiverCompatible": false
},
overflowMenuButtons: [
"quality",
"picture_in_picture",
"playback_rate"
]
};
if (chromecastConfig?.receiverApplicationId) {
uiConfig.castReceiverAppId = chromecastConfig.receiverApplicationId;
uiConfig.castAndroidReceiverCompatible = false;
}
ui.configure(uiConfig);
if (isMobile) {
const customizeBigPlayButton = () => {
const bigPlayButton = containerRef.current?.querySelector(".shaka-big-play-button");
if (bigPlayButton && !bigPlayButton.hasAttribute("data-customized")) {
const buttonSize = iconSizes?.bigPlayButton || 40;
bigPlayButton.innerHTML = renderIcon(BigPlayIcon, { size: buttonSize });
bigPlayButton.setAttribute("data-customized", "true");
const buttonElement = bigPlayButton;
buttonElement.style.display = "flex";
buttonElement.style.alignItems = "center";
buttonElement.style.justifyContent = "center";
}
};
setTimeout(customizeBigPlayButton, 100);
const observer = new MutationObserver(() => {
customizeBigPlayButton();
});
if (containerRef.current) {
observer.observe(containerRef.current, {
childList: true,
subtree: true,
attributes: false
});
}
}
return ui;
}, [controls, containerRef, playerRef, videoRef, chromecastConfig, seekbarColors, onSkipBack, onSkipForward, iconSizes]);
const destroyUI = useCallback5(() => {
if (uiRef.current) {
try {
uiRef.current.destroy();
} catch (error) {
console.error("Error destroying UI:", error);
}
uiRef.current = null;
}
}, []);
return {
uiRef,
initializeUI,
destroyUI
};
};
// src/hooks/useEventHandlers.ts
import { useCallback as useCallback6 } from "react";
var useEventHandlers = (videoRef, handlers) => {
const setupEventListeners = useCallback6(() => {
const video = videoRef.current;
if (!video) return;
const { onPlay, onPause, onEnded, onLoadStart, onCanPlay } = handlers;
if (onPlay) video.addEventListener("play", onPlay);
if (onPause) video.addEventListener("pause", onPause);
if (onEnded) video.addEventListener("ended", onEnded);
if (onLoadStart) video.addEventListener("loadstart", onLoa