diff --git a/bigbluebutton-html5/imports/ui/components/button/component.jsx b/bigbluebutton-html5/imports/ui/components/button/component.jsx index d78748965f4cba0992118f568b0dfd6c1a5a87ab..29c16d5dae41c0bf96b79fbe1772b0278782007d 100755 --- a/bigbluebutton-html5/imports/ui/components/button/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/button/component.jsx @@ -116,7 +116,6 @@ export default class Button extends BaseButton { label, 'aria-label': ariaLabel, 'aria-expanded': ariaExpanded, - tooltipDistance, tooltipLabel, } = this.props; @@ -126,7 +125,6 @@ export default class Button extends BaseButton { const buttonLabel = label || ariaLabel; return ( <Tooltip - tooltipDistance={tooltipDistance} title={tooltipLabel || buttonLabel} > {this[renderFuncName]()} @@ -153,7 +151,6 @@ export default class Button extends BaseButton { delete remainingProps.circle; delete remainingProps.block; delete remainingProps.hideLabel; - delete remainingProps.tooltipDistance; delete remainingProps.tooltipLabel; /* TODO: We can change this and make the button with flexbox to avoid html @@ -187,7 +184,6 @@ export default class Button extends BaseButton { delete remainingProps.circle; delete remainingProps.block; delete remainingProps.hideLabel; - delete remainingProps.tooltipDistance; delete remainingProps.tooltipLabel; return ( diff --git a/bigbluebutton-html5/imports/ui/components/fullscreen-button/component.jsx b/bigbluebutton-html5/imports/ui/components/fullscreen-button/component.jsx index 32a055035e198994d1c84cf53a2167a6b6e60cbe..e157efc3522f26d645eca194ea4341f0ba923501 100755 --- a/bigbluebutton-html5/imports/ui/components/fullscreen-button/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/fullscreen-button/component.jsx @@ -22,7 +22,6 @@ const propTypes = { elementName: PropTypes.string, className: PropTypes.string, handleToggleFullScreen: PropTypes.func.isRequired, - tooltipDistance: PropTypes.number, }; const defaultProps = { @@ -33,7 +32,6 @@ const defaultProps = { elementName: '', className: '', fullscreenRef: null, - tooltipDistance: -1, }; const FullscreenButtonComponent = ({ @@ -41,7 +39,6 @@ const FullscreenButtonComponent = ({ dark, bottom, elementName, - tooltipDistance, className, fullscreenRef, handleToggleFullScreen, @@ -73,7 +70,6 @@ const FullscreenButtonComponent = ({ label={formattedLabel} hideLabel className={cx(styles.button, styles.fullScreenButton, className)} - tooltipDistance={tooltipDistance} data-test="presentationFullscreenButton" /> </div> diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/component.jsx b/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/component.jsx index 35af787664d7e60eb152ba990903067ed097c53e..429e096d8f6278fcc34728af889c2da60c03365f 100644 --- a/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/component.jsx @@ -18,6 +18,10 @@ const intlMessages = defineMessages({ id: 'app.talkingIndicator.ariaMuteDesc', description: 'aria description for muting a user', }, + muteLabel: { + id: 'app.actionsBar.muteLabel', + description: 'indicator mute label for moderators', + }, }); class TalkingIndicator extends PureComponent { @@ -28,7 +32,9 @@ class TalkingIndicator extends PureComponent { } render() { - const { intl, talkers, openPanel } = this.props; + const { + intl, talkers, openPanel, amIModerator, + } = this.props; if (!talkers) return null; const talkingUserElements = Object.keys(talkers).map((id) => { @@ -45,6 +51,7 @@ class TalkingIndicator extends PureComponent { [styles.spoke]: !talking, [styles.muted]: muted, [styles.mobileHide]: openPanel !== '', + [styles.isViewer]: !amIModerator, }; const ariaLabel = intl.formatMessage(talking @@ -61,6 +68,10 @@ class TalkingIndicator extends PureComponent { className={cx(style)} onClick={() => this.handleMuteUser(voiceUserId)} label={callerName} + tooltipLabel={!muted && amIModerator + ? `${intl.formatMessage(intlMessages.muteLabel)} ${callerName}` + : null + } aria-label={ariaLabel} aria-describedby={talking ? 'description' : null} color="primary" diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/styles.scss b/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/styles.scss index a8d4ed4baf3f9e0dc2b4a56167dec006595a0228..da36954608917e57a32a20469ba68c099633c54f 100644 --- a/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/talking-indicator/styles.scss @@ -115,3 +115,8 @@ visibility: hidden; } } + +.isViewer { + cursor: default; +} + diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx index 6aa3414d9df4ab72ba0486308436bd85ed97bacc..6be72c60dd7815e1f2861c34dccb4cda4f3320fa 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx @@ -217,8 +217,6 @@ class PresentationToolbar extends PureComponent { const isMobileBrowser = BROWSER_RESULTS.mobile || BROWSER_RESULTS.os.includes('Android'); - const tooltipDistance = 35; - const startOfSlides = !(currentSlideNum > 1); const endOfSlides = !(currentSlideNum < numberOfSlides); @@ -248,11 +246,9 @@ class PresentationToolbar extends PureComponent { label={intl.formatMessage(intlMessages.previousSlideLabel)} hideLabel className={cx(styles.prevSlide, styles.presentationBtn)} - tooltipDistance={tooltipDistance} /> <Tooltip - tooltipDistance={tooltipDistance} title={intl.formatMessage(intlMessages.selectLabel)} className={styles.presentationBtn} > @@ -282,7 +278,6 @@ class PresentationToolbar extends PureComponent { label={intl.formatMessage(intlMessages.nextSlideLabel)} hideLabel className={cx(styles.skipSlide, styles.presentationBtn)} - tooltipDistance={tooltipDistance} /> </div> } @@ -297,7 +292,6 @@ class PresentationToolbar extends PureComponent { minBound={HUNDRED_PERCENT} maxBound={MAX_PERCENT} step={STEP} - tooltipDistance={tooltipDistance} isMeteorConnected={isMeteorConnected} /> ) @@ -322,7 +316,6 @@ class PresentationToolbar extends PureComponent { } hideLabel className={cx(styles.fitToWidth, styles.presentationBtn)} - tooltipDistance={tooltipDistance} /> { ALLOW_FULLSCREEN @@ -331,7 +324,6 @@ class PresentationToolbar extends PureComponent { fullscreenRef={fullscreenRef} isFullscreen={isFullscreen} elementName={intl.formatMessage(intlMessages.presentationLabel)} - tooltipDistance={tooltipDistance} className={styles.presentationBtn} /> ) diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/zoom-tool/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/zoom-tool/component.jsx index ef226246479389b2934cdd9f15de48221e12d9cb..9dccce65b4df69686a5b7e679a0e244bcecc2bbf 100644 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/zoom-tool/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/zoom-tool/component.jsx @@ -145,7 +145,6 @@ class ZoomTool extends PureComponent { minBound, maxBound, intl, - tooltipDistance, isMeteorConnected, step, } = this.props; @@ -181,7 +180,6 @@ class ZoomTool extends PureComponent { onClick={() => { }} disabled={(zoomValue <= minBound) || !isMeteorConnected} className={cx(styles.prevSlide, styles.presentationBtn)} - tooltipDistance={tooltipDistance} hideLabel /> <div id="zoomOutDescription" hidden>{intl.formatMessage(intlMessages.zoomOutDesc)}</div> @@ -199,7 +197,6 @@ class ZoomTool extends PureComponent { onClick={() => this.resetZoom()} label={intl.formatMessage(intlMessages.resetZoomLabel)} className={cx(styles.zoomPercentageDisplay, styles.presentationBtn)} - tooltipDistance={tooltipDistance} hideLabel /> <div id="resetZoomDescription" hidden> @@ -223,7 +220,6 @@ class ZoomTool extends PureComponent { onClick={() => { }} disabled={(zoomValue >= maxBound) || !isMeteorConnected} className={cx(styles.skipSlide, styles.presentationBtn)} - tooltipDistance={tooltipDistance} hideLabel /> <div id="zoomInDescription" hidden>{intl.formatMessage(intlMessages.zoomInDesc)}</div> @@ -242,7 +238,6 @@ const propTypes = { maxBound: PropTypes.number.isRequired, step: PropTypes.number.isRequired, isMeteorConnected: PropTypes.bool.isRequired, - tooltipDistance: PropTypes.number.isRequired, }; ZoomTool.propTypes = propTypes; diff --git a/bigbluebutton-html5/imports/ui/components/tooltip/bbbtip.css b/bigbluebutton-html5/imports/ui/components/tooltip/bbbtip.css new file mode 100644 index 0000000000000000000000000000000000000000..30cbe5d4b95e52e63f37bd843e0f0c1bdab0d772 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/tooltip/bbbtip.css @@ -0,0 +1,12 @@ +.tippy-tooltip.bbbtip-theme{ + color:#fff; + background-color:#333333; + padding: .25rem; + border-radius: 4px; +} + +.tippy-tooltip.bbbtip-theme>.tippy-svg-arrow{ + fill: #333333; + background-color: transparent; + background: transparent; +} diff --git a/bigbluebutton-html5/imports/ui/components/tooltip/component.jsx b/bigbluebutton-html5/imports/ui/components/tooltip/component.jsx index ae44b3d4acf07da8c9575995809c12b767ddd188..ee8ab37bf02d272313e68aa1723dbccd36d8df68 100755 --- a/bigbluebutton-html5/imports/ui/components/tooltip/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/tooltip/component.jsx @@ -1,39 +1,33 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import Tippy from 'tippy.js'; import _ from 'lodash'; import cx from 'classnames'; import { ESCAPE } from '/imports/utils/keyCodes'; import Settings from '/imports/ui/services/settings'; +import Tippy, { roundArrow, hideAll } from 'tippy.js'; +import 'tippy.js/dist/svg-arrow.css'; +import 'tippy.js/animations/shift-away.css'; +import './bbbtip.css'; -const DEFAULT_ANIMATION = 'shift-away'; -const ANIMATION_NONE = 'none'; const ANIMATION_DURATION = 350; const ANIMATION_DELAY = [150, 50]; +const DEFAULT_ANIMATION = 'shift-away'; +const ANIMATION_NONE = 'none'; +const TIP_OFFSET = '0, 10'; const propTypes = { title: PropTypes.string.isRequired, position: PropTypes.oneOf(['bottom']), children: PropTypes.element.isRequired, className: PropTypes.string, - tooltipDistance: PropTypes.number, }; const defaultProps = { position: 'bottom', className: null, - tooltipDistance: -1, }; class Tooltip extends Component { - static wait(tip, event) { - const tooltipTarget = event.target; - const expandedEl = tooltipTarget.parentElement.querySelector('[aria-expanded="true"]'); - const isTarget = expandedEl === tooltipTarget; - if (expandedEl && !isTarget) return; - tip.show(); - } - constructor(props) { super(props); @@ -47,35 +41,28 @@ class Tooltip extends Component { const { position, title, - tooltipDistance, } = this.props; const { animations } = Settings.application; - let distance = 0; - if (tooltipDistance < 0) { - if (animations) distance = 10; - else distance = 20; - } else { - distance = tooltipDistance; - } - const options = { - placement: position, - performance: true, + aria: null, + animation: animations ? DEFAULT_ANIMATION : ANIMATION_NONE, + arrow: roundArrow, + boundary: 'window', content: title, delay: animations ? ANIMATION_DELAY : [ANIMATION_DELAY[0], 0], duration: animations ? ANIMATION_DURATION : 0, onShow: this.onShow, onHide: this.onHide, - wait: Tooltip.wait, - touchHold: true, - size: 'regular', - distance, - arrow: true, - arrowType: 'sharp', - aria: null, - animation: animations ? DEFAULT_ANIMATION : ANIMATION_NONE, + offset: TIP_OFFSET, + placement: position, + touch: 'hold', + theme: 'bbbtip', + multiple: false, + onBeforeUpdate: () => { + hideAll(); + }, }; this.tooltip = Tippy(`#${this.tippySelectorId}`, options); } @@ -97,24 +84,16 @@ class Tooltip extends Component { return true; }).forEach((e) => { const instance = e._tippy; - instance.set({ + instance.setProps({ animation: animations ? DEFAULT_ANIMATION : ANIMATION_NONE, - distance: animations ? 10 : 20, delay: animations ? ANIMATION_DELAY : [ANIMATION_DELAY[0], 0], duration: animations ? ANIMATION_DURATION : 0, }); - - // adjusts the distance for tooltips on the presentation toolbar - Object.entries(instance.reference.classList).reduce((acc, [key]) => { - if (!instance.reference.classList[key].match(/(presentationBtn)/)) return false; - instance.set({ distance: animations ? 35 : 45 }); - return true; - }); }); const elem = document.getElementById(this.tippySelectorId); - if (elem._tippy) elem._tippy.set({ content: title }); + if (elem._tippy) elem._tippy.setProps({ content: title }); } onShow() { @@ -139,7 +118,6 @@ class Tooltip extends Component { children, className, title, - tooltipDistance, ...restProps } = this.props; diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json index 7331428fde2b84edcd98fb612ae7d687e8eee360..d4728823b158f7747d98f030a19f7c9ab953d968 100755 --- a/bigbluebutton-html5/package.json +++ b/bigbluebutton-html5/package.json @@ -73,7 +73,7 @@ "redis": "~2.8.0", "sdp-transform": "2.7.0", "string-hash": "~1.1.3", - "tippy.js": "^3.4.1", + "tippy.js": "^5.1.1", "useragent": "^2.3.0", "winston": "^3.2.1", "yaml": "^1.7.2"