From 8efc9020652bae48ca201e03733b459a0b023ba3 Mon Sep 17 00:00:00 2001 From: Serhii Date: Wed, 19 Jun 2024 11:24:36 +0300 Subject: [PATCH 01/18] fix(FEC-13729): export side panels (#891) ### Description of the Changes Export side-panels component Resolves: https://kaltura.atlassian.net/browse/FEC-13729 --- src/components/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/index.ts b/src/components/index.ts index a22f78277..9baf64ad2 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -71,6 +71,8 @@ export {VideoArea} from './video-area'; export {GuiArea} from './gui-area'; export {InteractiveArea} from './interactive-area'; +export {SidePanel} from './side-panel'; + export {Keyboard as KeyboardControl} from './keyboard'; export {Cast, Cast as CastControl}; export {Fullscreen, Fullscreen as FullscreenControl}; From fbc4b35acca149c427e649d786d5a770503d7a27 Mon Sep 17 00:00:00 2001 From: Serhii Date: Wed, 19 Jun 2024 13:54:22 +0300 Subject: [PATCH 02/18] feat(FEC-13912): Captions product analytics (#890) ### Description of the Changes Captions product analytics Resolves: https://kaltura.atlassian.net/browse/FEC-13912 Related PR https://github.com/kaltura/playkit-js-kava/pull/176 **Issue:** **Fix:** --- src/components/cvaa-overlay/cvaa-overlay.tsx | 7 ++--- .../event-dispatcher-provider.tsx | 29 ++++++++++++++++++- src/event/event-type.ts | 10 ++++++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/components/cvaa-overlay/cvaa-overlay.tsx b/src/components/cvaa-overlay/cvaa-overlay.tsx index 4e9eb0833..13e56cb35 100644 --- a/src/components/cvaa-overlay/cvaa-overlay.tsx +++ b/src/components/cvaa-overlay/cvaa-overlay.tsx @@ -90,11 +90,11 @@ class CVAAOverlay extends Component { * @memberof CVAAOverlay */ changeCaptionsStyle = (textStyle: any): void => { - this.props.updateCaptionsStyle(textStyle); - this.props.player.textStyle = textStyle; this.props.notifyClick({ textStyle: textStyle }); + this.props.updateCaptionsStyle(textStyle); + this.props.player.textStyle = textStyle; }; /** @@ -138,8 +138,7 @@ class CVAAOverlay extends Component { addAccessibleChild={this.props.addAccessibleChild} onClose={props.onClose} type="cvaa" - label={props.cvvaDialogText} - > + label={props.cvvaDialogText}> {this.state.activeWindow === cvaaOverlayState.Main ? ( { + if (collection && !isEqual(currentStyles?.[key], newStyles?.[key])) { + Object.keys(collection).some(collectionKey => { + if (isEqual(collection[collectionKey], newStyles?.[key])) { + player.dispatchEvent(new FakeEvent(eventType, collectionKey.toLowerCase())); + return true; + } + }); + } else if (currentStyles?.[key] !== newStyles?.[key]) { + player.dispatchEvent(new FakeEvent(eventType, newStyles?.[key])); + } + }); +} + /** * Handler for changeable components actions. * @param {any} store - The redux store. @@ -131,7 +158,7 @@ function onClickableComponentsHandler(store: any, action: any, player: KalturaPl break; case 'CVAAOverlay': - player.dispatchEvent(new CaptionsStyleSelectedEvent(action.payload.textStyle)); + onCaptionsStyleSelected(store, action, player); break; case 'Fullscreen': diff --git a/src/event/event-type.ts b/src/event/event-type.ts index c510eaba3..d2e622f94 100644 --- a/src/event/event-type.ts +++ b/src/event/event-type.ts @@ -29,7 +29,15 @@ const EventType = { USER_SELECTED_CAPTIONS_STYLE: `${namespace}-userselectedcaptionsstyle`, USER_SELECTED_SPEED: `${namespace}-userselectedspeed`, USER_SEEKED: `${namespace}-userseeked`, - RESIZE: `${namespace}-resize` + RESIZE: `${namespace}-resize`, + USER_SELECTED_CAPTIONS_SIZE: `${namespace}-userselectedcaptionssize`, + USER_SELECTED_CAPTIONS_ALIGNMENT: `${namespace}-userselectedcaptionsalignment`, + USER_SELECTED_CAPTIONS_FONT_COLOR: `${namespace}-userselectedcaptionsfontcolor`, + USER_SELECTED_CAPTIONS_FONT_FAMILY: `${namespace}-userselectedcaptionsfontfamily`, + USER_SELECTED_CAPTIONS_FONT_STYLE: `${namespace}-userselectedcaptionsfontstyle`, + USER_SELECTED_CAPTIONS_FONT_OPACITY: `${namespace}-userselectedcaptionsfontopacity`, + USER_SELECTED_CAPTIONS_BACKGROUND_COLOR: `${namespace}-userselectedcaptionsbackgroundcolor`, + USER_SELECTED_CAPTIONS_BACKGROUND_OPACITY: `${namespace}-userselectedcaptionsbackgroundopacity` } as const; export {EventType}; From 52fc63a0886fea911c3dcab3a4c4878307e06f8a Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Sun, 23 Jun 2024 13:13:02 +0300 Subject: [PATCH 03/18] feat(FEC-13506): Add Captions language selector in bottom bar (#871) ### Description of the Changes Add Captions language selector in bottom bar Resolves FEC-13506 --------- Co-authored-by: JonathanTGold --- .../captions-control/captions-control.tsx | 120 ++++++++++++++++++ src/components/captions-control/index.ts | 1 + .../captions-menu/captions-menu.tsx | 28 ++-- .../closed-captions/closed-captions.tsx | 4 - src/components/index.ts | 1 + src/components/settings/settings.tsx | 2 +- .../smart-container-item-type.ts | 5 + src/reducers/config.ts | 1 + src/types/ui-options.ts | 1 + src/ui-presets/playback.tsx | 1 + 10 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 src/components/captions-control/captions-control.tsx create mode 100644 src/components/captions-control/index.ts create mode 100644 src/components/smart-container/smart-container-item-type.ts diff --git a/src/components/captions-control/captions-control.tsx b/src/components/captions-control/captions-control.tsx new file mode 100644 index 000000000..9c86aa66b --- /dev/null +++ b/src/components/captions-control/captions-control.tsx @@ -0,0 +1,120 @@ +import {h} from 'preact'; +import {connect, useSelector} from 'react-redux'; +import {ClosedCaptions} from '../closed-captions'; +import {CaptionsMenu} from '../captions-menu'; +import {ButtonControl} from '../button-control'; +import {Tooltip} from '../tooltip'; +import {Button} from '../button'; +import style from '../../styles/style.scss'; +import {Icon, IconType} from '../icon'; +import {SmartContainer} from '../smart-container'; +import {Text, withText} from 'preact-i18n'; +import {useRef, useState, useEffect, useCallback} from 'preact/hooks'; +import {focusElement} from '../../utils'; +import {createPortal} from 'preact/compat'; +import {CVAAOverlay} from '../cvaa-overlay'; + +/** + * mapping state to props + * @param {*} state - redux store state + * @returns {Object} - mapped state to this component + */ +const mapStateToProps = state => ({ + textTracks: state.engine.textTracks, + showCCButton: state.config.showCCButton, + openMenuFromCCCButton: state.config.openMenuFromCCButton, + isMobile: state.shell.isMobile, + isSmallSize: state.shell.isSmallSize, + isCVAAOverlayOpen: state.shell.isCVAAOverlayOpen +}); + +const COMPONENT_NAME = 'CaptionsControl'; + +/** + * CaptionsControl component + * + * @class CaptionsControl + * @example + * @extends {Component} + */ +const CaptionsControl = connect(mapStateToProps)( + withText({ + captionsLabelText: 'captions.captions', + advancedCaptionsSettingsText: 'captions.advanced_captions_settings' + })((props, context) => { + const [smartContainerOpen, setSmartContainerOpen] = useState(false); + const [cvaaOverlay, setCVAAOverlay] = useState(false); + const [ccOn, setCCOn] = useState(false); + const buttonRef = useRef(null); + const controlCaptionsElement = useRef(null); + + const {player} = context; + const {isSmallSize, isMobile, textTracks} = props; + const activeTextTrack = textTracks.find(textTrack => textTrack.active); + + const onControlButtonClick = (e?: KeyboardEvent, byKeyboard?: boolean): void => { + setSmartContainerOpen(smartContainerOpen => !smartContainerOpen); + if (byKeyboard && smartContainerOpen) { + focusElement(buttonRef.current); + } + }; + + const toggleCVAAOverlay = (): void => { + setCVAAOverlay(cvaaOverlay => !cvaaOverlay); + }; + + const onCVAAOverlayClose = (e?: KeyboardEvent, byKeyboard?: boolean): void => { + toggleCVAAOverlay(); + onControlButtonClick(e, byKeyboard); + }; + + const handleClickOutside = (e: any) => { + if (!isMobile && !isSmallSize && !!controlCaptionsElement.current && !controlCaptionsElement.current.contains(e.target)) { + setSmartContainerOpen(false); + } + }; + + useEffect(() => { + document.addEventListener('click', handleClickOutside); + return () => document.removeEventListener('click', handleClickOutside); + }, [isSmallSize, isMobile]); + + useEffect(() => { + setCCOn(activeTextTrack?.language !== 'off'); + }, [activeTextTrack]); + + const shouldRender = !!textTracks?.length && props.showCCButton; + props.onToggle(COMPONENT_NAME, shouldRender); + if (!shouldRender) return undefined; + + const targetId: HTMLDivElement | Document = (document.getElementById(player.config.targetId) as HTMLDivElement) || document; + const portalSelector = `.overlay-portal`; + + return props.openMenuFromCCCButton ? ( + + + + + {smartContainerOpen && !cvaaOverlay && ( + setSmartContainerOpen(false)} title={}> + + + )} + {cvaaOverlay ? createPortal(, targetId.querySelector(portalSelector)!) :
} + + ) : ( + + ); + }) +); + +CaptionsControl.displayName = COMPONENT_NAME; +export {CaptionsControl}; diff --git a/src/components/captions-control/index.ts b/src/components/captions-control/index.ts new file mode 100644 index 000000000..de9a877af --- /dev/null +++ b/src/components/captions-control/index.ts @@ -0,0 +1 @@ +export {CaptionsControl} from './captions-control'; diff --git a/src/components/captions-menu/captions-menu.tsx b/src/components/captions-menu/captions-menu.tsx index 7bde5c866..abc5c6253 100644 --- a/src/components/captions-menu/captions-menu.tsx +++ b/src/components/captions-menu/captions-menu.tsx @@ -10,6 +10,8 @@ import {withEventManager} from '../../event'; import {withLogger} from '../logger'; import {withEventDispatcher} from '../event-dispatcher'; import {withKeyboardEvent} from '../../components/keyboard'; +import {KeyboardEventHandlers} from '../../types'; +import {Menu} from '../menu'; /** * mapping state to props @@ -86,17 +88,21 @@ class CaptionsMenu extends Component { textOptions.push({label: props.advancedCaptionsSettingsText, value: props.advancedCaptionsSettingsText, active: false}); } - return ( - { - props.pushRef(el); - }} - icon={IconType.Captions} - label={this.props.captionsLabelText} - options={textOptions} - onMenuChosen={textTrack => this.onCaptionsChange(textTrack)} - /> - ); + if (this.props.asDropdown) { + return ( + { + props.pushRef(el); + }} + icon={IconType.Captions} + label={this.props.captionsLabelText} + options={textOptions} + onMenuChosen={textTrack => this.onCaptionsChange(textTrack)} + /> + ); + } else { + return this.onCaptionsChange(textTrack)} onClose={() => {}} />; + } } } diff --git a/src/components/closed-captions/closed-captions.tsx b/src/components/closed-captions/closed-captions.tsx index c5181bc7b..e42b6d41f 100644 --- a/src/components/closed-captions/closed-captions.tsx +++ b/src/components/closed-captions/closed-captions.tsx @@ -16,7 +16,6 @@ import {ButtonControl} from '../button-control'; */ const mapStateToProps = state => ({ textTracks: state.engine.textTracks, - showCCButton: state.config.showCCButton }); const COMPONENT_NAME = 'ClosedCaptions'; @@ -44,9 +43,6 @@ const ClosedCaptions = connect(mapStateToProps)( setCCOn(activeTextTrack?.language !== 'off'); }, [activeTextTrack]); - const shouldRender = !!(props.textTracks?.length && props.showCCButton); - props.onToggle(COMPONENT_NAME, shouldRender); - if (!shouldRender) return undefined; return ( {ccOn ? ( diff --git a/src/components/index.ts b/src/components/index.ts index 9baf64ad2..a7fbd2068 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -84,3 +84,4 @@ export {Settings, Settings as SettingsControl}; export {Volume, Volume as VolumeControl}; export {VrStereo, VrStereo as VrStereoControl}; export {ClosedCaptions, ClosedCaptions as ClosedCaptionsControl}; +export {CaptionsControl} from './captions-control'; diff --git a/src/components/settings/settings.tsx b/src/components/settings/settings.tsx index 42f247267..4cce35700 100644 --- a/src/components/settings/settings.tsx +++ b/src/components/settings/settings.tsx @@ -248,7 +248,7 @@ class Settings extends Component { } onClose={this.onControlButtonClick}> {showAdvancedAudioDescToggle && } {showAudioMenu && } - {showCaptionsMenu && } + {showCaptionsMenu && } {showQualityMenu && } {showSpeedMenu && } diff --git a/src/components/smart-container/smart-container-item-type.ts b/src/components/smart-container/smart-container-item-type.ts new file mode 100644 index 000000000..e120ec3e6 --- /dev/null +++ b/src/components/smart-container/smart-container-item-type.ts @@ -0,0 +1,5 @@ +export enum SmartContainerItemType { + DropDown, + Menu, + ToggleSwitch +} diff --git a/src/reducers/config.ts b/src/reducers/config.ts index b857438ff..6adfcc3c9 100644 --- a/src/reducers/config.ts +++ b/src/reducers/config.ts @@ -13,6 +13,7 @@ export const initialState = { targetId: undefined as unknown as string, forceTouchUI: false, showCCButton: true, + openMenuFromCCButton: false, settings: { showAudioMenu: true, showCaptionsMenu: true, diff --git a/src/types/ui-options.ts b/src/types/ui-options.ts index cfe636363..9f1d8c4c9 100644 --- a/src/types/ui-options.ts +++ b/src/types/ui-options.ts @@ -8,6 +8,7 @@ export interface UIOptionsObject { debugActions?: boolean; forceTouchUI?: boolean; showCCButton?: boolean; + openMenuFromCCButton?: boolean; settings?: { showAudioMenu?: boolean; showCaptionsMenu?: boolean; diff --git a/src/ui-presets/playback.tsx b/src/ui-presets/playback.tsx index 79aaa555e..8646e6db2 100644 --- a/src/ui-presets/playback.tsx +++ b/src/ui-presets/playback.tsx @@ -6,6 +6,7 @@ import {PrePlaybackPlayOverlay} from '../components'; import {Loading} from '../components'; import {Rewind} from '../components'; import {Forward} from '../components'; +import {CaptionsControl} from '../components'; import {SeekBarPlaybackContainer} from '../components'; import {Volume} from '../components'; import {Settings} from '../components'; From 4521661c9a8ebd1ac4b224d94aa371a532a8fb9e Mon Sep 17 00:00:00 2001 From: Tzipi <101048005+Tzipi-kaltura@users.noreply.github.com> Date: Sun, 23 Jun 2024 18:04:33 +0300 Subject: [PATCH 04/18] fix(ADA-1084): Color contrast of v7 player icons (#894) Issue: menu controls can have very low contrast ratios Fix: make the gradient stronger and add a shadow to the icons and the text Resolves ADA-1084 --- src/components/bottom-bar/_bottom-bar.scss | 2 +- src/components/icon/icon.scss | 1 + src/components/time-display/_time-display.scss | 1 + src/components/top-bar/_top-bar.scss | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/bottom-bar/_bottom-bar.scss b/src/components/bottom-bar/_bottom-bar.scss index bbf61414b..0bb59b633 100644 --- a/src/components/bottom-bar/_bottom-bar.scss +++ b/src/components/bottom-bar/_bottom-bar.scss @@ -1,5 +1,5 @@ .player .bottom-bar { - background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%); + background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%); color: #fff; height: auto; width: 100%; diff --git a/src/components/icon/icon.scss b/src/components/icon/icon.scss index c36116bb1..83a0b6d3f 100644 --- a/src/components/icon/icon.scss +++ b/src/components/icon/icon.scss @@ -136,6 +136,7 @@ background-size: cover; background-repeat: no-repeat; background-position: 50% 50%; + filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.70)); } .badge-icon:after { diff --git a/src/components/time-display/_time-display.scss b/src/components/time-display/_time-display.scss index dd5edd69e..112b917a6 100644 --- a/src/components/time-display/_time-display.scss +++ b/src/components/time-display/_time-display.scss @@ -5,6 +5,7 @@ font-size: 14px; padding: 0 23px; font-weight: bold; + filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.70)); } .touch .time-display { diff --git a/src/components/top-bar/_top-bar.scss b/src/components/top-bar/_top-bar.scss index fdec886f9..8987513d2 100644 --- a/src/components/top-bar/_top-bar.scss +++ b/src/components/top-bar/_top-bar.scss @@ -1,5 +1,5 @@ .player .top-bar { - background: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%); + background: linear-gradient(180deg, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%); color: #fff; visibility: hidden; position: relative; From 746118ebf9d54304143f95f906ad99f1d1f80878 Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Sun, 23 Jun 2024 18:34:22 +0300 Subject: [PATCH 05/18] fix(ADA-1063): Volume slider 55.00000000000001% value (#893) ### Description of the Changes **Issue:** computer precision error in decimal numbers **Fix:** round number #### Resolves ADA-1063 --------- Co-authored-by: JonathanTGold --- src/components/volume/volume.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/volume/volume.tsx b/src/components/volume/volume.tsx index bdc36eb5f..23edfc33b 100644 --- a/src/components/volume/volume.tsx +++ b/src/components/volume/volume.tsx @@ -442,6 +442,7 @@ class Volume extends Component { if (isDraggingActive) controlButtonClasses.push(style.draggingActive); if (muted || volume === 0) controlButtonClasses.push(style.isMuted); if (this.state.hover && !smartContainerOpen) controlButtonClasses.push(style.hover); + const volumePercentage = Math.round(player.volume * 100); return ( { role="slider" aria-valuemin={0} aria-valuemax={100} - aria-valuenow={player.volume * 100} - aria-valuetext={`${player.volume * 100}% volume ${player.muted ? 'muted' : ''}`}> + aria-valuenow={volumePercentage} + aria-valuetext={`${volumePercentage}% volume ${player.muted ? 'muted' : ''}`}>
(c ? (this._volumeProgressBarElement = c) : undefined)} From 97b1aa4bff43652b61c006926b462c66911d37bc Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:35:29 +0300 Subject: [PATCH 06/18] fix(FEC-13506_REG): fix PR #871 regression (#895) ### Description of the Changes fix #871 PR regression #### Resolves FEC-13506 Co-authored-by: JonathanTGold --- src/ui-presets/live.tsx | 4 ++-- src/ui-presets/playback.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui-presets/live.tsx b/src/ui-presets/live.tsx index 90c546022..ac24c5c56 100644 --- a/src/ui-presets/live.tsx +++ b/src/ui-presets/live.tsx @@ -1,6 +1,6 @@ import style from '../styles/style.scss'; import {Component, Fragment, h, VNode} from 'preact'; -import {OverlayAction} from '../components'; +import {CaptionsControl, OverlayAction} from '../components'; import {PrePlaybackPlayOverlay} from '../components'; import {Loading} from '../components'; import {SeekBarLivePlaybackContainer} from '../components'; @@ -81,7 +81,7 @@ class LiveUI extends Component { diff --git a/src/ui-presets/playback.tsx b/src/ui-presets/playback.tsx index 8646e6db2..bb2e8fa4b 100644 --- a/src/ui-presets/playback.tsx +++ b/src/ui-presets/playback.tsx @@ -90,7 +90,7 @@ class PlaybackUI extends Component { + rightControls={[VrStereo, Volume, AdvancedAudioDesc, CaptionsControl, Settings, Cast, PictureInPicture, Fullscreen, Logo]}> From ad4a6b45fb94deb7dcdbea4b462c6c24434abaea Mon Sep 17 00:00:00 2001 From: ovp-github-actions Date: Sun, 30 Jun 2024 06:18:41 +0000 Subject: [PATCH 07/18] chore(release): 0.79.3 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d733826c6..51235969e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### 0.79.3 (2024-06-30) + + +### Bug Fixes + +* **FEC-13506_REG:** fix PR [#871](https://github.com/kaltura/playkit-js-ui/issues/871) regression ([#895](https://github.com/kaltura/playkit-js-ui/issues/895)) ([97b1aa4](https://github.com/kaltura/playkit-js-ui/commit/97b1aa4)) + + + ### 0.79.2 (2024-06-02) diff --git a/package.json b/package.json index 7990c37fe..cedc1b3ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@playkit-js/playkit-js-ui", - "version": "0.79.2", + "version": "0.79.3", "description": "", "keywords": [ "kaltura", From 7a9a78fc879ecb3522f96acfc4fbcfa73289a552 Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 2 Jul 2024 13:57:53 +0300 Subject: [PATCH 08/18] fix(FEC-14023): add strictPosition property to tooltip (#901) ### Description of the Changes Please add a detailed description of the change, whether it's an enhancement or a bugfix. If the PR is related to an open issue please link to it. **Issue:** **Fix:** resolves: https://kaltura.atlassian.net/browse/FEC-14023 --- src/components/tooltip/tooltip.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/tooltip/tooltip.tsx b/src/components/tooltip/tooltip.tsx index 0182d1a83..ff40f7bfd 100644 --- a/src/components/tooltip/tooltip.tsx +++ b/src/components/tooltip/tooltip.tsx @@ -16,6 +16,7 @@ interface TooltipOwnProps { type?: ToolTipPosition; maxWidth?: string; label: string; + strictPosition?: boolean; } type TooltipProps = ReduxStateProps & TooltipOwnProps; @@ -69,7 +70,8 @@ class Tooltip extends Component { */ static defaultProps = { type: ToolTipType.Top, - maxWidth: '240px' + maxWidth: '240px', + strictPosition: false }; /** @@ -174,6 +176,9 @@ class Tooltip extends Component { * @returns {string} is in boundaries */ isToolTipInBoundaries(): boolean { + if (this.props.strictPosition) { + return true; + } const tooltipBoundingRect = this.textElement.getBoundingClientRect(); const playerContainerRect = this.props.playerClientRect; @@ -275,8 +280,7 @@ class Tooltip extends Component { className={style.tooltip} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave} - ref={el => (el ? (this.tooltipElement = el) : undefined)} - > + ref={el => (el ? (this.tooltipElement = el) : undefined)}> {children} (el ? (this.textElement = el) : undefined)} className={className.join(' ')}> {props.label} From 56062134d2a89786132f570bfdcbaa1cec5f7764 Mon Sep 17 00:00:00 2001 From: ovp-github-actions Date: Thu, 4 Jul 2024 08:39:15 +0000 Subject: [PATCH 09/18] chore(release): 0.79.4 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51235969e..08936b2bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### 0.79.4 (2024-07-04) + + +### Bug Fixes + +* **FEC-14023:** add strictPosition property to tooltip ([#901](https://github.com/kaltura/playkit-js-ui/issues/901)) ([7a9a78f](https://github.com/kaltura/playkit-js-ui/commit/7a9a78f)) + + + ### 0.79.3 (2024-06-30) diff --git a/package.json b/package.json index cedc1b3ba..bdce7fce3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@playkit-js/playkit-js-ui", - "version": "0.79.3", + "version": "0.79.4", "description": "", "keywords": [ "kaltura", From 3a60b135943ab5d963eb978b79bc263e1271356c Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Sun, 7 Jul 2024 12:53:11 +0300 Subject: [PATCH 10/18] fix(ADA-1296): [ACE] V7 Player keyboard accessibility not working properly (#892) ### Description of the Changes Please add a detailed description of the change, whether it's an enhancement or a bug fix. If the PR is related to an open issue please link to it. **Issue:** Shift+ was not working since the events registrations were done inside the speed-menu comp which does not exist until the menu and the submenu are pressed/navigated **Fix:** Move the event listener to the parent (settings ) comp which is always existing on the UI #### Resolves ADA-1296 --------- Co-authored-by: JonathanTGold --- src/components/settings/settings.tsx | 73 ++++++++++++++++++- src/components/speed-menu/speed-menu.tsx | 89 +----------------------- src/utils/index.ts | 2 +- src/utils/key-map.ts | 44 +++++++++++- 4 files changed, 117 insertions(+), 91 deletions(-) diff --git a/src/components/settings/settings.tsx b/src/components/settings/settings.tsx index 4cce35700..f8ec4dcc5 100644 --- a/src/components/settings/settings.tsx +++ b/src/components/settings/settings.tsx @@ -23,9 +23,10 @@ import {Button} from '../button'; import {ButtonControl} from '../button-control'; import {createPortal} from 'preact/compat'; import {focusElement} from '../../utils'; -import {withKeyboardEvent} from '../../components/keyboard'; +import {withKeyboardEvent} from '../keyboard'; import {KeyboardEventHandlers} from '../../types'; import {withLogger} from '../logger'; +import {SpeedSelectedEvent} from '../../event/events/speed-selected-event'; /** * mapping state to props @@ -87,6 +88,33 @@ class Settings extends Component { } } } + }, + { + key: { + code: KeyMap.PERIOD, + shiftKey: true + }, + action: event => { + this.handleKeydown(event); + } + }, + { + key: { + code: KeyMap.SEMI_COLON, + shiftKey: true + }, + action: event => { + this.handleKeydown(event); + } + }, + { + key: { + code: KeyMap.COMMA, + shiftKey: true + }, + action: event => { + this.handleKeydown(event); + } } ]; @@ -112,6 +140,49 @@ class Settings extends Component { this.props.registerKeyboardEvents(this._keyboardEventHandlers); } + /** + * on settings control key down, update the settings in case of up/down keys + * + * @method handleKeydown + * @param {KeyboardEvent} event - keyboardEvent event + * @returns {void} + * @memberof SpeedMenu + */ + handleKeydown(event: KeyboardEvent): void { + const {player, logger} = this.props; + let playbackRate, index; + switch (event.keyCode) { + case KeyMap.PERIOD: + playbackRate = player.playbackRate; + index = player.playbackRates.indexOf(playbackRate); + if (index < player.playbackRates.length - 1) { + logger.debug(`Changing playback rate. ${playbackRate} => ${player.playbackRates[index + 1]}`); + player.playbackRate = player.playbackRates[index + 1]; + this.props.updateOverlayActionIcon(IconType.SpeedUp); + player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); + } + break; + case KeyMap.SEMI_COLON: + if (player.playbackRate !== player.defaultPlaybackRate) { + logger.debug(`Changing playback rate. ${player.playbackRate} => ${player.defaultPlaybackRate}`); + player.playbackRate = player.defaultPlaybackRate; + this.props.updateOverlayActionIcon(IconType.Speed); + player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); + } + break; + case KeyMap.COMMA: + playbackRate = player.playbackRate; + index = player.playbackRates.indexOf(playbackRate); + if (index > 0) { + logger.debug(`Changing playback rate. ${playbackRate} => ${player.playbackRates[index - 1]}`); + player.playbackRate = player.playbackRates[index - 1]; + this.props.updateOverlayActionIcon(IconType.SpeedDown); + player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); + } + break; + } + } + /** * We update the last language selected here upon trackTracks props change. This is done to make sure we update the * last text track lanague upon language menu selection and using the (C) keyboard key. diff --git a/src/components/speed-menu/speed-menu.tsx b/src/components/speed-menu/speed-menu.tsx index d3ce46c35..2c1d183a9 100644 --- a/src/components/speed-menu/speed-menu.tsx +++ b/src/components/speed-menu/speed-menu.tsx @@ -1,16 +1,13 @@ import {h, Component, VNode} from 'preact'; import {withText} from 'preact-i18n'; import {connect} from 'react-redux'; -import {bindActions, KeyMap} from '../../utils'; +import {bindActions} from '../../utils'; import {actions} from '../../reducers/settings'; import {SmartContainerItem} from '../../components'; import {IconType} from '../icon'; import {withPlayer} from '../player'; import {withLogger} from '../logger'; import {withEventDispatcher} from '../event-dispatcher'; -import {withKeyboardEvent} from '../keyboard'; -import {SpeedSelectedEvent} from '../../event/events/speed-selected-event'; -import {KeyboardEventHandlers} from '../../types'; const COMPONENT_NAME = 'SpeedMenu'; @@ -23,7 +20,6 @@ const COMPONENT_NAME = 'SpeedMenu'; */ @connect(null, bindActions(actions)) @withPlayer -@withKeyboardEvent(COMPONENT_NAME) @withLogger(COMPONENT_NAME) @withEventDispatcher(COMPONENT_NAME) @withText({ @@ -31,89 +27,6 @@ const COMPONENT_NAME = 'SpeedMenu'; speedNormalLabelText: 'settings.speedNormal' }) class SpeedMenu extends Component { - _keyboardEventHandlers: Array = [ - { - key: { - code: KeyMap.PERIOD, - shiftKey: true - }, - action: event => { - this.handleKeydown(event); - } - }, - { - key: { - code: KeyMap.SEMI_COLON, - shiftKey: true - }, - action: event => { - this.handleKeydown(event); - } - }, - { - key: { - code: KeyMap.COMMA, - shiftKey: true - }, - action: event => { - this.handleKeydown(event); - } - } - ]; - - /** - * after component mounted, set event listener to click outside of the component - * - * @returns {void} - * @memberof SpeedMenu - */ - componentDidMount() { - this.props.registerKeyboardEvents(this._keyboardEventHandlers); - } - - /** - * on settings control key down, update the settings in case of up/down keys - * - * @method handleKeydown - * @param {KeyboardEvent} event - keyboardEvent event - * @returns {void} - * @memberof SpeedMenu - */ - handleKeydown(event: KeyboardEvent): void { - const {player, logger} = this.props; - let playbackRate, index; - switch (event.keyCode) { - case KeyMap.PERIOD: - playbackRate = player.playbackRate; - index = player.playbackRates.indexOf(playbackRate); - if (index < player.playbackRates.length - 1) { - logger.debug(`Changing playback rate. ${playbackRate} => ${player.playbackRates[index + 1]}`); - player.playbackRate = player.playbackRates[index + 1]; - this.props.updateOverlayActionIcon(IconType.SpeedUp); - player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); - } - break; - case KeyMap.SEMI_COLON: - if (player.playbackRate !== player.defaultPlaybackRate) { - logger.debug(`Changing playback rate. ${player.playbackRate} => ${player.defaultPlaybackRate}`); - player.playbackRate = player.defaultPlaybackRate; - this.props.updateOverlayActionIcon(IconType.Speed); - player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); - } - break; - case KeyMap.COMMA: - playbackRate = player.playbackRate; - index = player.playbackRates.indexOf(playbackRate); - if (index > 0) { - logger.debug(`Changing playback rate. ${playbackRate} => ${player.playbackRates[index - 1]}`); - player.playbackRate = player.playbackRates[index - 1]; - this.props.updateOverlayActionIcon(IconType.SpeedDown); - player.dispatchEvent(new SpeedSelectedEvent(player.playbackRate)); - } - break; - } - } - /** * change player playback rate and update it in the store state * diff --git a/src/utils/index.ts b/src/utils/index.ts index 6d8d926b3..1ae313129 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,6 @@ export {bindActions} from './bind-actions'; export {focusElement} from './focus-element'; -export {KeyMap} from './key-map'; +export {KeyMap, KeyCode} from './key-map'; export {default as getLogger} from './logger'; export {withKeyboardA11y} from './popup-keyboard-accessibility'; export * from './time-format'; diff --git a/src/utils/key-map.ts b/src/utils/key-map.ts index 9f695c8dc..e303ef738 100644 --- a/src/utils/key-map.ts +++ b/src/utils/key-map.ts @@ -1,4 +1,9 @@ -/* eslint-disable @typescript-eslint/no-use-before-define */ +/** + * @deprecated Use the `KeyCode` object instead. + * see here: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode + * For more information on keyboard event codes, refer to the MDN documentation: + * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values + */ export const KeyMap: {[key: string]: number} = { TAB: 9, ENTER: 13, @@ -19,6 +24,43 @@ export const KeyMap: {[key: string]: number} = { PERIOD: 190 }; +export const KeyCode = { + Backspace: 'Backspace', + Tab: 'Tab', + Enter: 'Enter', + ShiftLeft: 'ShiftLeft', + ShiftRight: 'ShiftRight', + ControlLeft: 'ControlLeft', + ControlRight: 'ControlRight', + AltLeft: 'AltLeft', + AltRight: 'AltRight', + Pause: 'Pause', + CapsLock: 'CapsLock', + Escape: 'Escape', + Space: 'Space', + PageUp: 'PageUp', + PageDown: 'PageDown', + End: 'End', + Home: 'Home', + ArrowLeft: 'ArrowLeft', + ArrowUp: 'ArrowUp', + ArrowRight: 'ArrowRight', + ArrowDown: 'ArrowDown', + Insert: 'Insert', + Delete: 'Delete', + KeyP: 'KeyP', + KeyC: 'KeyC', + KeyF: 'KeyF', + KeyM: 'KeyM', + Numpad0: 'Numpad0', + Semicolon: 'Semicolon', + Equal: 'Equal', + Comma: 'Comma', + Minus: 'Minus', + Period: 'Period', + Slash: 'Slash' +}; + /** * set env for keymap * @param {Object} env - env object From 91e5b697040240a35ddf8001d494326aac0abc36 Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:52:31 +0300 Subject: [PATCH 11/18] fix(FEC-14027): ExpandableText Comp fire onExpand on comp init even though was not clicked by the user (#902) ### Description of the Changes Please add a detailed description of the change, whether it's an enhancement or a bugfix. If the PR is related to an open issue please link to it. **Issue:** **Fix:** #### Resolves FEC-14027 --------- Co-authored-by: JonathanTGold --- .../expandable-text/expandable-text.tsx | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/components/expandable-text/expandable-text.tsx b/src/components/expandable-text/expandable-text.tsx index 1a2e06481..0ae910f47 100644 --- a/src/components/expandable-text/expandable-text.tsx +++ b/src/components/expandable-text/expandable-text.tsx @@ -49,27 +49,26 @@ const ExpandableText: new (props?: any, context?: any) => any = withText({ } }, [isFinalized]); - useEffect(() => { - if (props.onExpand) { - props.onExpand(isTextExpanded); - } - }, [isTextExpanded]); - - const onClick = (e: MouseEvent) => { + const handleExpand = (e: MouseEvent | KeyboardEvent) => { if (props.onClick) { props.onClick(e); } + setIsTextExpanded(prevState => { + const newState = !prevState; + if (props.onExpand) { + props.onExpand(newState); + } + return newState; + }); + }; - setIsTextExpanded(!isTextExpanded); + const onClick = (e: MouseEvent) => { + handleExpand(e); }; const onKeyDown = (e: KeyboardEvent) => { if (e.keyCode === SPACE || e.keyCode === ENTER) { - if (props.onClick) { - props.onClick(e); - } - - setIsTextExpanded(!isTextExpanded); + handleExpand(e); } }; From b7262ee3a7d0277f939cb364bbed473d8701f499 Mon Sep 17 00:00:00 2001 From: Tzipi <101048005+Tzipi-kaltura@users.noreply.github.com> Date: Mon, 8 Jul 2024 12:21:24 +0300 Subject: [PATCH 12/18] =?UTF-8?q?fix(ADA-1335):=20Accessibility-=20?= =?UTF-8?q?=E2=80=9CClose=E2=80=9D=20button=20within=20the=20info=20video?= =?UTF-8?q?=20panel.=20(#900)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding boolean var to check if push to the beginning or to the end. part of - kaltura/playkit-js-info#101 Resolves ADA-1335 --- src/utils/popup-keyboard-accessibility.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/popup-keyboard-accessibility.tsx b/src/utils/popup-keyboard-accessibility.tsx index c06180cfa..b9d9e8fd2 100644 --- a/src/utils/popup-keyboard-accessibility.tsx +++ b/src/utils/popup-keyboard-accessibility.tsx @@ -130,12 +130,13 @@ export const withKeyboardA11y = (WrappedComponent): any => /** * sets the accessible children elements * @param {HTMLElement} element - a child element to be accessible through keyboard nav + * @param {?boolean} pushToBeginning - push to beginning of the array or to the end * @returns {void} * @memberof HOC */ - addAccessibleChild = (element: HTMLElement): void => { + addAccessibleChild = (element: HTMLElement, pushToBeginning?: boolean): void => { if (element && this._accessibleChildren.indexOf(element) == -1) { - this._accessibleChildren.push(element); + pushToBeginning ? this._accessibleChildren.unshift(element) : this._accessibleChildren.push(element); } }; From c8d64d79ac28618af29c95e93d7cb95fae336796 Mon Sep 17 00:00:00 2001 From: Serhii Date: Wed, 10 Jul 2024 01:04:03 +0300 Subject: [PATCH 13/18] fix(SUP-43378): volume control bar issue (#903) ### Description of the Changes show volume slider only on focus or hover. However JAWS with virtual cursor can reach volume slider that has height 0 and change volume level **Issue:** resolves https://kaltura.atlassian.net/browse/SUP-43378 --- src/components/volume/_volume.scss | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/volume/_volume.scss b/src/components/volume/_volume.scss index aa0eb7c72..2c507d20c 100644 --- a/src/components/volume/_volume.scss +++ b/src/components/volume/_volume.scss @@ -1,3 +1,13 @@ +@mixin hover { + display: block !important; + opacity: 1; + height: 112px; + padding: 6px; + &:before { + height: 14px; + } +} + .control-button-container { &.control-volume, &.volume-control { @@ -5,8 +15,7 @@ &.hover { .volume-control-bar { - display: block !important; - opacity: 1; + @include hover; } } @@ -28,8 +37,7 @@ &.dragging-active { .volume-control-bar { - display: block; - opacity: 1; + @include hover; } } @@ -66,18 +74,18 @@ z-index: 2; bottom: 38px; left: 0; - height: 112px; + height: 0px; width: 34px; border-radius: 4px; box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.3); background-color: #333333; - padding: 6px; + padding: 0px; opacity: 0; &:before { position: absolute; width: 34px; - height: 14px; + height: 0px; bottom: -8px; left: 0; content: ' '; From 3ec2143819c17c6adb8ccaca9e7873317330718a Mon Sep 17 00:00:00 2001 From: Serhii Date: Wed, 10 Jul 2024 10:38:24 +0300 Subject: [PATCH 14/18] Revert "fix(SUP-43378): volume control bar issue" (#904) Reverts kaltura/playkit-js-ui#903 --- src/components/volume/_volume.scss | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/components/volume/_volume.scss b/src/components/volume/_volume.scss index 2c507d20c..aa0eb7c72 100644 --- a/src/components/volume/_volume.scss +++ b/src/components/volume/_volume.scss @@ -1,13 +1,3 @@ -@mixin hover { - display: block !important; - opacity: 1; - height: 112px; - padding: 6px; - &:before { - height: 14px; - } -} - .control-button-container { &.control-volume, &.volume-control { @@ -15,7 +5,8 @@ &.hover { .volume-control-bar { - @include hover; + display: block !important; + opacity: 1; } } @@ -37,7 +28,8 @@ &.dragging-active { .volume-control-bar { - @include hover; + display: block; + opacity: 1; } } @@ -74,18 +66,18 @@ z-index: 2; bottom: 38px; left: 0; - height: 0px; + height: 112px; width: 34px; border-radius: 4px; box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.3); background-color: #333333; - padding: 0px; + padding: 6px; opacity: 0; &:before { position: absolute; width: 34px; - height: 0px; + height: 14px; bottom: -8px; left: 0; content: ' '; From be28ea219c248fcaca72c890a7ce53c7689ae90c Mon Sep 17 00:00:00 2001 From: JonathanTGold <62672270+JonathanTGold@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:51:59 +0300 Subject: [PATCH 15/18] =?UTF-8?q?fix(FEC-14034):=20Player=20v7=20|=20Safar?= =?UTF-8?q?i=20|=20Opening=20the=20CC=20menu=20cause=20size=20a=E2=80=A6?= =?UTF-8?q?=20(#905)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description of the Changes founding: - it is not a reggaeton - it is reproduced on [0.79.2](https://github.com/kaltura/playkit-js-ui/commit/7c7d4db698e2f2baa38c3829c4a5da476bf9f1cf) as well (prior to [#871)](https://github.com/kaltura/playkit-js-ui/pull/871) PR ) on any dropdown menu click - ti is happen only when the menu items on menu component are of a huge number that overflowing that player size - it is caused by the focus element that triggers on Menu Component mount from the Al11y wrapper that wraps the Menu component #### Resolves FEC-14034 Co-authored-by: JonathanTGold --- src/components/menu/menu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx index 21ec81d8a..04975561b 100644 --- a/src/components/menu/menu.tsx +++ b/src/components/menu/menu.tsx @@ -279,7 +279,7 @@ class MenuItem extends Component { ref={element => { this.props.addAccessibleChild(element); if (props.isSelected(props.data)) { - props.setDefaultFocusedElement(element); + setTimeout(() => props.setDefaultFocusedElement(element)) } }} className={props.isSelected(props.data) ? [style.dropdownMenuItem, style.active].join(' ') : style.dropdownMenuItem} From 4320555be1f592f80198f17785e6396965843167 Mon Sep 17 00:00:00 2001 From: ovp-github-actions Date: Thu, 11 Jul 2024 09:00:44 +0000 Subject: [PATCH 16/18] chore(release): 0.79.5 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08936b2bc..00c31f2c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### 0.79.5 (2024-07-11) + + +### Bug Fixes + +* **FEC-14034:** Player v7 | Safari | Opening the CC menu cause size a… ([#905](https://github.com/kaltura/playkit-js-ui/issues/905)) ([be28ea2](https://github.com/kaltura/playkit-js-ui/commit/be28ea2)), closes [#871](https://github.com/kaltura/playkit-js-ui/issues/871) + + + ### 0.79.4 (2024-07-04) diff --git a/package.json b/package.json index bdce7fce3..e470a19b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@playkit-js/playkit-js-ui", - "version": "0.79.4", + "version": "0.79.5", "description": "", "keywords": [ "kaltura", From d2aa5cf80b5c39a25d2b49be6846ebe405aeaa42 Mon Sep 17 00:00:00 2001 From: lianbenjamin <79077248+lianbenjamin@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:12:17 +0300 Subject: [PATCH 17/18] feat(FEC-13945): move core controls to upper bar (#898) ### Description of the Changes **New requirement:** if there is not enough space for controls in bottom bar, instead of removing them- move them to the upper bar. This was requested for A11y purposes. - keep 10sec FWD and BWD controls in bottom bar (do not remove them) - new service to register relevant core components - new redux state to update the controls that need to be moved from bottom bar to upper bar - new interface that registers the components to the new service - a special implementation for `TimeDisplay` component (different behavior) related PR: https://github.com/kaltura/playkit-js-ui-managers/pull/59 #### Resolves FEC-13945 --- karma.conf.js | 4 + package.json | 2 +- .../advanced-audio-desc.tsx | 37 +++++- src/components/bottom-bar/_bottom-bar.scss | 19 +-- .../bottom-bar/bottom-bar-registry-manager.ts | 42 +++++++ src/components/bottom-bar/bottom-bar.tsx | 21 +++- src/components/bottom-bar/index.ts | 1 + .../captions-control-mini.tsx | 112 ++++++++++++++++++ .../captions-control/captions-control.tsx | 60 +++++----- .../closed-captions/closed-captions.tsx | 55 ++++++++- .../engine-connector/engine-connector.tsx | 7 +- .../picture-in-picture/picture-in-picture.tsx | 42 ++++++- src/components/scrollable/scrollable.tsx | 17 ++- src/components/tooltip/tooltip.tsx | 4 + src/components/top-bar/_top-bar.scss | 4 +- src/components/vr-stereo/vr-stereo.tsx | 43 ++++++- src/reducers/bottom-bar.ts | 27 +++++ src/reducers/index.ts | 3 +- src/reducers/settings.ts | 15 ++- src/store.ts | 4 +- src/styles/_variables.scss | 1 + src/types/reducers/bottom-bar.ts | 3 + src/types/reducers/root-state.ts | 2 + src/ui-presets/live.tsx | 2 +- src/ui-presets/playback.tsx | 2 +- tests/e2e/bottom-bar-registry-manager.spec.js | 57 +++++++++ 26 files changed, 522 insertions(+), 64 deletions(-) create mode 100644 src/components/bottom-bar/bottom-bar-registry-manager.ts create mode 100644 src/components/captions-control/captions-control-mini.tsx create mode 100644 src/reducers/bottom-bar.ts create mode 100644 src/types/reducers/bottom-bar.ts create mode 100644 tests/e2e/bottom-bar-registry-manager.spec.js diff --git a/karma.conf.js b/karma.conf.js index 493df6588..af4d8639b 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -33,6 +33,10 @@ module.exports = function (config) { ChromeHeadlessWithFlags: { base: 'ChromeHeadless', flags: ['--no-sandbox', '--autoplay-policy=no-user-gesture-required', '--mute-audio', '--max-web-media-player-count=1000'] + }, + ChromeWithFlags: { + base: 'Chrome', + flags: ['--no-sandbox', '--autoplay-policy=no-user-gesture-required', '--mute-audio', '--max-web-media-player-count=1000'] } }, browsers: ['ChromeHeadlessWithFlags'], diff --git a/package.json b/package.json index e470a19b8..5b40b83a8 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "prettier": "prettier --write .", "test": "karma start karma.conf.js", "test:debug": "DEBUG_UNIT_TESTS=1 karma start karma.conf.js --auto-watch --no-single-run --browsers Chrome", - "test:watch": "karma start karma.conf.js --auto-watch --no-single-run", + "test:watch": "karma start karma.conf.js --auto-watch --no-single-run --browsers ChromeWithFlags", "clean": "rimraf ./dist", "prebuild": "npm run clean", "precommit": "npm run build:prod && npm run type-check && npm run lint:fix", diff --git a/src/components/advanced-audio-desc/advanced-audio-desc.tsx b/src/components/advanced-audio-desc/advanced-audio-desc.tsx index 1cbb4c55a..a1e783438 100644 --- a/src/components/advanced-audio-desc/advanced-audio-desc.tsx +++ b/src/components/advanced-audio-desc/advanced-audio-desc.tsx @@ -9,6 +9,9 @@ import {connect} from 'react-redux'; import {ButtonControl} from '../button-control'; import {bindActions} from '../../utils'; import {actions} from '../../reducers/settings'; +import {IconComponent, registerToBottomBar} from '../bottom-bar'; +import {redux} from '../../index'; +import {withPlayer} from '../player'; const COMPONENT_NAME = 'AdvancedAudioDesc'; @@ -29,12 +32,38 @@ const mapStateToProps = state => ({ * @extends {Component} */ @connect(mapStateToProps, bindActions(actions)) +@withPlayer @withEventDispatcher(COMPONENT_NAME) @withText({AdvancedAudioDescText: 'settings.advancedAudioDescription'}) -class AdvancedAudioDesc extends Component { +class AdvancedAudioDesc extends Component implements IconComponent { constructor(props: any) { super(); this.state = {toggle: false}; + registerToBottomBar(COMPONENT_NAME, props.player, () => this.registerComponent()); + } + + registerComponent(): any { + return { + ariaLabel: () => this.getComponentText(), + displayName: COMPONENT_NAME, + order: 5, + svgIcon: () => this.getSvgIcon(), + onClick: () => this.onClick(), + component: () => { + return getComponent({...this.props, classNames: [style.upperBarIcon]}); + }, + shouldHandleOnClick: false + }; + } + + getComponentText = (): any => { + return this.props.AdvancedAudioDescText; + } + + getSvgIcon = (): any => { + return { + type: redux.useStore().getState().settings.advancedAudioDesc ? IconType.AdvancedAudioDescriptionActive : IconType.AdvancedAudioDescription + }; } /** @@ -69,7 +98,7 @@ class AdvancedAudioDesc extends Component { */ render({AdvancedAudioDescText, innerRef}: any): VNode | undefined { return !this._shouldRender() ? undefined : ( - + + + + ) : undefined; +}); + +const getComponent = (props: any): VNode => { + return ; +} + +CaptionsControlMini.displayName = COMPONENT_NAME; +export {CaptionsControlMini}; diff --git a/src/components/captions-control/captions-control.tsx b/src/components/captions-control/captions-control.tsx index 9c86aa66b..88496d0e0 100644 --- a/src/components/captions-control/captions-control.tsx +++ b/src/components/captions-control/captions-control.tsx @@ -1,6 +1,5 @@ -import {h} from 'preact'; -import {connect, useSelector} from 'react-redux'; -import {ClosedCaptions} from '../closed-captions'; +import {h, Fragment} from 'preact'; +import {connect} from 'react-redux'; import {CaptionsMenu} from '../captions-menu'; import {ButtonControl} from '../button-control'; import {Tooltip} from '../tooltip'; @@ -9,10 +8,11 @@ import style from '../../styles/style.scss'; import {Icon, IconType} from '../icon'; import {SmartContainer} from '../smart-container'; import {Text, withText} from 'preact-i18n'; -import {useRef, useState, useEffect, useCallback} from 'preact/hooks'; +import {useRef, useState, useEffect} from 'preact/hooks'; import {focusElement} from '../../utils'; import {createPortal} from 'preact/compat'; import {CVAAOverlay} from '../cvaa-overlay'; +import {CaptionsControlMini} from './captions-control-mini'; /** * mapping state to props @@ -22,7 +22,7 @@ import {CVAAOverlay} from '../cvaa-overlay'; const mapStateToProps = state => ({ textTracks: state.engine.textTracks, showCCButton: state.config.showCCButton, - openMenuFromCCCButton: state.config.openMenuFromCCButton, + openMenuFromCCButton: state.config.openMenuFromCCButton, isMobile: state.shell.isMobile, isSmallSize: state.shell.isSmallSize, isCVAAOverlayOpen: state.shell.isCVAAOverlayOpen @@ -39,8 +39,7 @@ const COMPONENT_NAME = 'CaptionsControl'; */ const CaptionsControl = connect(mapStateToProps)( withText({ - captionsLabelText: 'captions.captions', - advancedCaptionsSettingsText: 'captions.advanced_captions_settings' + captionsLabelText: 'captions.captions' })((props, context) => { const [smartContainerOpen, setSmartContainerOpen] = useState(false); const [cvaaOverlay, setCVAAOverlay] = useState(false); @@ -83,35 +82,36 @@ const CaptionsControl = connect(mapStateToProps)( setCCOn(activeTextTrack?.language !== 'off'); }, [activeTextTrack]); - const shouldRender = !!textTracks?.length && props.showCCButton; + const shouldRender = !!textTracks?.length && props.showCCButton && props.openMenuFromCCButton; props.onToggle(COMPONENT_NAME, shouldRender); if (!shouldRender) return undefined; const targetId: HTMLDivElement | Document = (document.getElementById(player.config.targetId) as HTMLDivElement) || document; const portalSelector = `.overlay-portal`; - return props.openMenuFromCCCButton ? ( - - - - - {smartContainerOpen && !cvaaOverlay && ( - setSmartContainerOpen(false)} title={}> - - - )} - {cvaaOverlay ? createPortal(, targetId.querySelector(portalSelector)!) :
} - - ) : ( - + return ( + <> + + + + + {smartContainerOpen && !cvaaOverlay && ( + setSmartContainerOpen(false)} title={}> + + + )} + {cvaaOverlay ? createPortal(, targetId.querySelector(portalSelector)!) :
} + + + ); }) ); diff --git a/src/components/closed-captions/closed-captions.tsx b/src/components/closed-captions/closed-captions.tsx index e42b6d41f..d58054f6e 100644 --- a/src/components/closed-captions/closed-captions.tsx +++ b/src/components/closed-captions/closed-captions.tsx @@ -1,5 +1,5 @@ import style from '../../styles/style.scss'; -import {h} from 'preact'; +import {h, VNode} from 'preact'; import {useEffect, useState} from 'preact/hooks'; import {withText} from 'preact-i18n'; import {Icon, IconType} from '../icon'; @@ -9,6 +9,9 @@ import {withLogger} from '../logger'; import {Tooltip} from '../tooltip'; import {Button} from '../button'; import {ButtonControl} from '../button-control'; +import {registerToBottomBar} from '../bottom-bar'; +import {redux} from '../../index'; + /** * mapping state to props * @param {*} state - redux store state @@ -16,6 +19,8 @@ import {ButtonControl} from '../button-control'; */ const mapStateToProps = state => ({ textTracks: state.engine.textTracks, + showCCButton: state.config.showCCButton, + openMenuFromCCButton: state.config.openMenuFromCCButton }); const COMPONENT_NAME = 'ClosedCaptions'; @@ -43,8 +48,50 @@ const ClosedCaptions = connect(mapStateToProps)( setCCOn(activeTextTrack?.language !== 'off'); }, [activeTextTrack]); + useEffect(() => { + registerToBottomBar(COMPONENT_NAME, player, () => registerComponent()); + }, []); + + const registerComponent = (): any => { + return { + ariaLabel: () => getAriaLabel(), + displayName: COMPONENT_NAME, + order: 5, + svgIcon: () => getSvgIcon(), + onClick: () => onClick(), + component: () => { + return getComponent({...props, classNames: [style.upperBarIcon]}); + }, + shouldHandleOnClick: false + }; + }; + + const isCaptionsEnabled = (): boolean => { + return redux.useStore().getState().settings.isCaptionsEnabled; + }; + + const getAriaLabel = (): any => { + return isCaptionsEnabled() ? props.closedCaptionsOnText : props.closedCaptionsOffText; + }; + + const getSvgIcon = (): any => { + return { + type: isCaptionsEnabled() ? IconType.ClosedCaptionsOn : IconType.ClosedCaptionsOff + }; + }; + + const onClick = () => { + const isCCOn = isCaptionsEnabled(); + props.notifyClick(isCCOn); + isCCOn ? player.hideTextTrack() : player.showTextTrack(); + }; + + const shouldRender = !!textTracks?.length && props.showCCButton && !props.openMenuFromCCButton; + props.onToggle(COMPONENT_NAME, shouldRender); + if (!shouldRender) return undefined; + return ( - + {ccOn ? (