From 4921691b977532962b598fc80a8f2e6e71bec2fb Mon Sep 17 00:00:00 2001 From: Omri Bernstein Date: Wed, 15 Apr 2020 18:10:57 -0400 Subject: [PATCH 1/7] Update options overlay to close on escape, or click or focus elsewhere --- src/components/menu/OptionsOverlay.js | 121 +++++++++++++++++--------- 1 file changed, 82 insertions(+), 39 deletions(-) diff --git a/src/components/menu/OptionsOverlay.js b/src/components/menu/OptionsOverlay.js index 334ef42e..d6427ded 100644 --- a/src/components/menu/OptionsOverlay.js +++ b/src/components/menu/OptionsOverlay.js @@ -29,6 +29,8 @@ class OptionsOverlay extends Component { ); this.updateState = this.updateState.bind(this); this.handleSelectItem = this.handleSelectItem.bind(this); + this.handleRefChange = this.handleRefChange.bind(this); + this.handleKeyUp = this.handleKeyUp.bind(this); this.state = this.getTextTrackItems(); } @@ -80,6 +82,43 @@ class OptionsOverlay extends Component { return textTrackItems; } + close() { + if (this.props.player.isOptionsOverlayOpen) { + this.props.actions.handleOptionsOverlayChange(); + } + } + + listenClose(optionsOverlayElem) { + // Close the panel upon focus or click elsewhere on the DOM. + const handleActivityElsewhere = event => { + 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(); + } + } + + handleRefChange(optionsOverlayElem) { + if (this.stopListeningForClose) { + this.stopListeningForClose(); + } + if (optionsOverlayElem) { + optionsOverlayElem.focus(); + this.stopListeningForClose = this.listenClose(optionsOverlayElem); + } + } + updateState() { const textTrackItems = this.getTextTrackItems(); if ( @@ -139,52 +178,56 @@ 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) => ( + + ))} + + )}
); From 87fc76be66aa8d92617dd2a5700d9d3a744cdc6f Mon Sep 17 00:00:00 2001 From: Omri Bernstein Date: Wed, 15 Apr 2020 19:00:12 -0400 Subject: [PATCH 2/7] Remove warnings from console --- src/components/control-bar/ControlBar.js | 2 +- src/utils/index.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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/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 From 02f5b57e041e7dceab72b7902d905e8f03d0be41 Mon Sep 17 00:00:00 2001 From: Omri Bernstein Date: Wed, 15 Apr 2020 19:07:29 -0400 Subject: [PATCH 3/7] Apply white font to options panel header instead of its container --- styles/scss/components/menu/menu-overlay.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/styles/scss/components/menu/menu-overlay.scss b/styles/scss/components/menu/menu-overlay.scss index 3bbe9159..86c756b8 100644 --- a/styles/scss/components/menu/menu-overlay.scss +++ b/styles/scss/components/menu/menu-overlay.scss @@ -29,9 +29,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; } From 220b03685bfb1e7223b498c044797ef1a0f01488 Mon Sep 17 00:00:00 2001 From: Omri Bernstein Date: Thu, 16 Apr 2020 09:04:35 -0400 Subject: [PATCH 4/7] Prevent shortcuts for keyboard events in options overlay --- src/components/Shortcut.js | 37 ++++++++++++++------------- src/components/menu/OptionsOverlay.js | 6 +++++ 2 files changed, 25 insertions(+), 18 deletions(-) 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/menu/OptionsOverlay.js b/src/components/menu/OptionsOverlay.js index d6427ded..6610ed8b 100644 --- a/src/components/menu/OptionsOverlay.js +++ b/src/components/menu/OptionsOverlay.js @@ -31,6 +31,7 @@ class OptionsOverlay extends Component { this.handleSelectItem = this.handleSelectItem.bind(this); this.handleRefChange = this.handleRefChange.bind(this); this.handleKeyUp = this.handleKeyUp.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); this.state = this.getTextTrackItems(); } @@ -109,6 +110,10 @@ class OptionsOverlay extends Component { } } + handleKeyDown(event) { + event.stopPropagation(); + } + handleRefChange(optionsOverlayElem) { if (this.stopListeningForClose) { this.stopListeningForClose(); @@ -182,6 +187,7 @@ class OptionsOverlay extends Component { className={classNames('video-react-options-overlay', className)} ref={this.handleRefChange} onKeyUp={this.handleKeyUp} + onKeyDown={this.handleKeyDown} tabIndex="-1" >

diff --git a/styles/scss/components/menu/menu-overlay.scss b/styles/scss/components/menu/menu-overlay.scss index 77aef8e2..c0138900 100644 --- a/styles/scss/components/menu/menu-overlay.scss +++ b/styles/scss/components/menu/menu-overlay.scss @@ -1,21 +1,34 @@ -$menu-item-height: 1.4em; +$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%; } } @@ -24,7 +37,7 @@ $radio-inner-padding: 2px; top: 0; right: 0; height: 100%; - width: 325px; + min-width: 225px; background: rgba(#000000, 0.8); z-index: 1; display: flex; @@ -53,7 +66,7 @@ $radio-inner-padding: 2px; cursor: pointer; &:not(.video-react-menu-item-selected):hover { - background-color: #545454; + background-color: $hover-bg-color; } .video-react-menu-item-radio {