diff --git a/css/_audio-preview.scss b/css/_audio-preview.scss index 293bc48dc..4ece182b3 100644 --- a/css/_audio-preview.scss +++ b/css/_audio-preview.scss @@ -22,11 +22,7 @@ } &-entry-text { - display: inline-block; - text-overflow: ellipsis; max-width: 213px; - overflow: hidden; - white-space: nowrap; &.left-margin { margin-left: 36px; diff --git a/react/features/base/ui/components/web/ContextMenuItem.tsx b/react/features/base/ui/components/web/ContextMenuItem.tsx index 779cebabc..b29377487 100644 --- a/react/features/base/ui/components/web/ContextMenuItem.tsx +++ b/react/features/base/ui/components/web/ContextMenuItem.tsx @@ -5,6 +5,9 @@ import { makeStyles } from 'tss-react/mui'; import { showOverflowDrawer } from '../../../../toolbox/functions.web'; import Icon from '../../../icons/components/Icon'; import { withPixelLineHeight } from '../../../styles/functions.web'; +import { TEXT_OVERFLOW_TYPES } from '../../constants.any'; + +import TextWithOverflow from './TextWithOverflow'; export interface IProps { @@ -59,6 +62,11 @@ export interface IProps { */ onKeyPress?: (e?: React.KeyboardEvent) => void; + /** + * Overflow type for item text. + */ + overflowType?: TEXT_OVERFLOW_TYPES; + /** * Whether the item is marked as selected. */ @@ -149,6 +157,7 @@ const ContextMenuItem = ({ onClick, onKeyDown, onKeyPress, + overflowType, selected, testId, text, @@ -180,12 +189,13 @@ const ContextMenuItem = ({ size = { 20 } src = { icon } />} {text && ( - + _overflowDrawer && styles.drawerText, + textClassName) } + overflowType = { overflowType } > {text} - + )} {children} diff --git a/react/features/base/ui/components/web/TextWithOverflow.tsx b/react/features/base/ui/components/web/TextWithOverflow.tsx new file mode 100644 index 000000000..a05706d99 --- /dev/null +++ b/react/features/base/ui/components/web/TextWithOverflow.tsx @@ -0,0 +1,74 @@ +import React, { ReactNode, useRef } from 'react'; +import { keyframes } from 'styled-components'; +import { makeStyles } from 'tss-react/mui'; + +import { TEXT_OVERFLOW_TYPES } from '../../constants.web'; + +interface ITextWithOverflowProps { + children: ReactNode; + className?: string; + overflowType?: TEXT_OVERFLOW_TYPES; +} + +const useStyles = makeStyles<{ translateDiff: number; }>()((_, { translateDiff }) => { + return { + animation: { + '&:hover': { + animation: `${keyframes` + 0%, 20% { + transform: translateX(0%); + left: 0%; + } + 80%, 100% { + transform: translateX(-${translateDiff}px); + left: 100%; + } + `} ${Math.max(translateDiff * 50, 2000)}ms infinite alternate linear;` + } + }, + textContainer: { + overflow: 'hidden' + }, + [TEXT_OVERFLOW_TYPES.ELLIPSIS]: { + display: 'block', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap' + }, + [TEXT_OVERFLOW_TYPES.SCROLL_ON_HOVER]: { + display: 'inline-block', + overflow: 'visible', + whiteSpace: 'nowrap' + } + }; +}); + +const TextWithOverflow = ({ + className, + overflowType = TEXT_OVERFLOW_TYPES.ELLIPSIS, + children +}: ITextWithOverflowProps) => { + const containerRef = useRef(null); + const contentRef = useRef(null); + const shouldAnimateOnHover = overflowType === TEXT_OVERFLOW_TYPES.SCROLL_ON_HOVER + && containerRef.current + && contentRef.current + && containerRef.current.clientWidth < contentRef.current.clientWidth; + + const translateDiff = shouldAnimateOnHover ? contentRef.current.clientWidth - containerRef.current.clientWidth : 0; + const { classes: styles, cx } = useStyles({ translateDiff }); + + return ( +
+ + {children} + +
+ ); +}; + +export default TextWithOverflow; diff --git a/react/features/base/ui/constants.any.ts b/react/features/base/ui/constants.any.ts index 8e634954b..26a75e8ee 100644 --- a/react/features/base/ui/constants.any.ts +++ b/react/features/base/ui/constants.any.ts @@ -8,6 +8,14 @@ export enum BUTTON_TYPES { TERTIARY = 'tertiary' } +/** + * Behaviour types for showing overflow text content. + */ +export enum TEXT_OVERFLOW_TYPES { + ELLIPSIS = 'ellipsis', + SCROLL_ON_HOVER = 'scroll-on-hover' +} + /** * The modes of the buttons. */ diff --git a/react/features/settings/components/web/audio/MicrophoneEntry.tsx b/react/features/settings/components/web/audio/MicrophoneEntry.tsx index 7403ace9c..789865e17 100644 --- a/react/features/settings/components/web/audio/MicrophoneEntry.tsx +++ b/react/features/settings/components/web/audio/MicrophoneEntry.tsx @@ -7,6 +7,7 @@ import { IconCheck, IconExclamationSolid } from '../../../../base/icons/svg'; // @ts-ignore import JitsiMeetJS from '../../../../base/lib-jitsi-meet/_'; import ContextMenuItem from '../../../../base/ui/components/web/ContextMenuItem'; +import { TEXT_OVERFLOW_TYPES } from '../../../../base/ui/constants.any'; import Meter from './Meter'; @@ -231,6 +232,7 @@ export default class MicrophoneEntry extends Component { diff --git a/react/features/settings/components/web/audio/SpeakerEntry.tsx b/react/features/settings/components/web/audio/SpeakerEntry.tsx index 3d0965ce0..af9daa193 100644 --- a/react/features/settings/components/web/audio/SpeakerEntry.tsx +++ b/react/features/settings/components/web/audio/SpeakerEntry.tsx @@ -4,7 +4,7 @@ import React, { useRef } from 'react'; import { IconCheck } from '../../../../base/icons/svg'; import Button from '../../../../base/ui/components/web/Button'; import ContextMenuItem from '../../../../base/ui/components/web/ContextMenuItem'; -import { BUTTON_TYPES } from '../../../../base/ui/constants.any'; +import { BUTTON_TYPES, TEXT_OVERFLOW_TYPES } from '../../../../base/ui/constants.any'; import logger from '../../../logger'; const TEST_SOUND_PATH = 'sounds/ring.mp3'; @@ -118,6 +118,7 @@ const SpeakerEntry = (props: IProps) => {