diff --git a/src/components/Shortcut.js b/src/components/Shortcut.js index dd66d964..1c798503 100644 --- a/src/components/Shortcut.js +++ b/src/components/Shortcut.js @@ -189,7 +189,7 @@ export default class Shortcut extends Component { componentDidMount() { this.mergeShortcuts(); - document.addEventListener('keydown', this.handleKeyPress); + window.addEventListener('keydown', this.handleKeyPress); document.addEventListener('click', this.handleClick); document.addEventListener('dblclick', this.handleDoubleClick); } @@ -201,7 +201,7 @@ export default class Shortcut extends Component { } componentWillUnmount() { - document.removeEventListener('keydown', this.handleKeyPress); + window.removeEventListener('keydown', this.handleKeyPress); document.removeEventListener('click', this.handleClick); document.removeEventListener('dblclick', this.handleDoubleClick); } @@ -215,9 +215,10 @@ export default class Shortcut extends Component { alt = false }) => `${keyCode}:${ctrl}:${shift}:${alt}`; const defaultShortcuts = this.defaultShortcuts.reduce( - (shortcuts, shortcut) => Object.assign(shortcuts, { - [getShortcutKey(shortcut)]: shortcut - }), + (shortcuts, shortcut) => + Object.assign(shortcuts, { + [getShortcutKey(shortcut)]: shortcut + }), {} ); const mergedShortcuts = (this.props.shortcuts || []).reduce( @@ -233,10 +234,10 @@ export default class Shortcut extends Component { defaultShortcuts ); - const gradeShortcut = (s) => { + const gradeShortcut = s => { let score = 0; const ps = ['ctrl', 'shift', 'alt']; - ps.forEach((key) => { + ps.forEach(key => { if (s[key]) { score++; } @@ -273,11 +274,11 @@ export default class Shortcut extends Component { return; } if ( - document.activeElement - && (hasClass(document.activeElement, 'video-react-control') - || hasClass(document.activeElement, 'video-react-menu-button-active') + document.activeElement && + (hasClass(document.activeElement, 'video-react-control') || + hasClass(document.activeElement, 'video-react-menu-button-active') || // || hasClass(document.activeElement, 'video-react-slider') - || hasClass(document.activeElement, 'video-react-big-play-button')) + hasClass(document.activeElement, 'video-react-big-play-button')) ) { return; } @@ -287,14 +288,14 @@ export default class Shortcut extends Component { const shift = e.shiftKey; const alt = e.altKey; - const shortcut = this.shortcuts.filter((s) => { + const shortcut = this.shortcuts.filter(s => { if (!s.keyCode || s.keyCode - keyCode !== 0) { return false; } if ( - (s.ctrl !== undefined && s.ctrl !== ctrl) - || (s.shift !== undefined && s.shift !== shift) - || (s.alt !== undefined && s.alt !== alt) + (s.ctrl !== undefined && s.ctrl !== ctrl) || + (s.shift !== undefined && s.shift !== shift) || + (s.alt !== undefined && s.alt !== alt) ) { return false; } @@ -310,9 +311,9 @@ export default class Shortcut extends Component { // only if player is active and player is ready canBeClicked(player, e) { if ( - !player.isActive - || e.target.nodeName !== 'VIDEO' - || player.readyState !== 4 + !player.isActive || + e.target.nodeName !== 'VIDEO' || + player.readyState !== 4 ) { return false; } diff --git a/src/components/control-bar/ControlBar.js b/src/components/control-bar/ControlBar.js index 332ccec4..fa1c4873 100644 --- a/src/components/control-bar/ControlBar.js +++ b/src/components/control-bar/ControlBar.js @@ -74,7 +74,7 @@ export default class ControlBar extends Component { const defaultChildren = this.props.disableDefaultControls ? [] : this.getDefaultChildren(); - const { className, ...parentProps } = this.props; // remove className + const parentProps = { player: this.props.player }; return mergeAndSortChildren(defaultChildren, children, parentProps); } diff --git a/src/components/menu/MenuItem.js b/src/components/menu/MenuItem.js index 9785b6a1..cdc305ed 100644 --- a/src/components/menu/MenuItem.js +++ b/src/components/menu/MenuItem.js @@ -14,21 +14,37 @@ export default class MenuItem extends Component { super(props, context); this.handleClick = this.handleClick.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); } - handleClick() { + select() { const { index, onSelectItem } = this.props; onSelectItem(index); } + handleClick() { + this.select(); + } + + handleKeyDown(event) { + if (event.key === ' ' || event.key === 'Enter') { + event.preventDefault(); + this.select(); + } + } + render() { const { label, index, activateIndex } = this.props; return (
{ + if (optionsOverlayElem.contains(event.target)) return; + this.close(); + }; + document.addEventListener('focusin', handleActivityElsewhere); + document.addEventListener('click', handleActivityElsewhere); + const stopListening = () => { + document.removeEventListener('focusin', handleActivityElsewhere); + document.removeEventListener('click', handleActivityElsewhere); + }; + return stopListening; + } + + handleKeyUp(event) { + if (event.key === 'Escape') { + this.close(); + } + } + + handleKeyDown(event) { + event.stopPropagation(); + } + + handleRefChange(optionsOverlayElem) { + if (this.stopListeningForClose) { + this.stopListeningForClose(); + } + if (optionsOverlayElem) { + optionsOverlayElem.focus(); + this.stopListeningForClose = this.listenClose(optionsOverlayElem); + } + } + updateState() { const textTrackItems = this.getTextTrackItems(); if ( @@ -139,52 +183,57 @@ class OptionsOverlay extends Component { if (!player.isOptionsOverlayOpen) return null; return ( -
+
-
-
-

- Closed Captions -

- {items && ( - - {items.map((item, i) => ( - - ))} - - )} -
- -
-

- Audio Description -

- {player.audioDescriptions && ( - - {player.audioDescriptions.map((description, i) => ( - - ))} - - )} -
+
+

+ Closed Captions +

+ {items && ( + + {items.map((item, i) => ( + + ))} + + )} +
+ +
+

+ Audio Description +

+ {player.audioDescriptions && ( + + {player.audioDescriptions.map((description, i) => ( + + ))} + + )}
); diff --git a/src/utils/index.js b/src/utils/index.js index 8c7cfdc1..36e76296 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -100,6 +100,7 @@ export function mergeAndSortChildren( const defaultProps = defaultComponent ? defaultComponent.props : {}; const props = { + ref: defaultComponent ? defaultComponent.ref : undefined, ...parentProps, // inherit from parent component ...defaultProps, // inherit from default component ...element.props // element's own props diff --git a/styles/scss/components/menu/menu-overlay.scss b/styles/scss/components/menu/menu-overlay.scss index 3bbe9159..c0138900 100644 --- a/styles/scss/components/menu/menu-overlay.scss +++ b/styles/scss/components/menu/menu-overlay.scss @@ -1,16 +1,34 @@ +$menu-item-height: 1.5em; +$menu-item-radio-dimensions: 1em; +$menu-item-left-padding: ($menu-item-height - $menu-item-radio-dimensions) / 2; +$radio-inner-padding: 2px; +$hover-bg-color: rgba(84, 84, 84, 0.7); + .video-react-options-close { position: absolute; - top: 0.4em; - right: 0.5em; + top: 0.25em; + right: 0.25em; color: white; background: none; border: none; font-size: 2.5em; z-index: 2; + height: 1em; + width: 1em; + display: flex; + justify-content: center; + align-items: center; + + > span { + line-height: 1em; + font-size: 0.7em; + font-weight: bold; + } &:hover { cursor: pointer; - opacity: 0.8; + background-color: $hover-bg-color; + border-radius: 50%; } } @@ -19,7 +37,7 @@ top: 0; right: 0; height: 100%; - width: 325px; + min-width: 225px; background: rgba(#000000, 0.8); z-index: 1; display: flex; @@ -29,9 +47,9 @@ .video-react-options-menu-section { width: 80%; align-self: center; - color: #ffffff; - + .video-react-menu-section-header { + color: #ffffff; font-weight: normal; margin: 0.25em 0; } @@ -39,24 +57,40 @@ .video-react-menu-item { display: flex; align-items: center; + font-size: 16px; + padding-left: $menu-item-left-padding; + transform: translateX(-$menu-item-left-padding); + height: $menu-item-height; + border-radius: 1em; + margin: 0.5em 0; cursor: pointer; + &:not(.video-react-menu-item-selected):hover { + background-color: $hover-bg-color; + } + .video-react-menu-item-radio { - width: 1em; - height: 1em; - border-radius: 0.5em; + width: $menu-item-radio-dimensions; + height: $menu-item-radio-dimensions; border: 1px solid white; + border-radius: 50%; display: block; margin-right: 0.5em; + position: relative; - &.video-react-menu-item-radio-selected, &:hover { - background-color: blue; + &.video-react-menu-item-radio-selected::after { + content: ''; + position: absolute; + border-radius: 50%; + top: $radio-inner-padding; + left: $radio-inner-padding; + width: calc(#{$menu-item-radio-dimensions} - 2px - #{$radio-inner-padding} * 2); + height: calc(#{$menu-item-radio-dimensions} - 2px - #{$radio-inner-padding} * 2); + background-color: #2C83FB; } } p { - font-size: 1.3em; - margin: 0.25em 0; font-weight: bold; } }