Disable selection throughout the UI (#3487)

This commit is contained in:
Alexander Zinchuk 2023-07-20 15:58:24 +02:00
parent adf4f45180
commit 032f56143e
28 changed files with 72 additions and 79 deletions

View File

@ -597,7 +597,7 @@ function renderSeekline(
) {
return (
<div
className="seekline no-selection"
className="seekline"
ref={seekerRef as React.Ref<HTMLDivElement>}
>
{bufferedRanges.map(({ start, end }) => (

View File

@ -223,7 +223,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
narrow
isStatic
>
<span className="title word-break" dir="auto">
<span className="title word-break text-selection" dir="auto">
{renderText(description, ['br', 'links', 'emoji'])}
</span>
<span className="subtitle">{lang(userId ? 'UserBio' : 'Info')}</span>

View File

@ -364,13 +364,12 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
const headerClassName = buildClassName(
pickerStyles.header,
'no-selection no-scrollbar',
'no-scrollbar',
!shouldHideTopBorder && pickerStyles.headerWithBorder,
);
const listClassName = buildClassName(
pickerStyles.main,
pickerStyles.main_customEmoji,
'no-selection',
IS_TOUCH_ENV ? 'no-scrollbar' : 'custom-scroll',
pickerListClassName,
);

View File

@ -121,7 +121,7 @@ const ChatMessageResults: FC<OwnProps & StateProps> = ({
noFastList
>
{dateSearchQuery && (
<div className="chat-selection no-selection no-scrollbar">
<div className="chat-selection no-scrollbar">
<DateSuggest
searchDate={dateSearchQuery}
onSelect={onSearchDateSelect}

View File

@ -211,7 +211,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
noFastList
>
{dateSearchQuery && (
<div className="chat-selection no-selection no-scrollbar">
<div className="chat-selection no-scrollbar">
<DateSuggest
searchDate={dateSearchQuery}
onSelect={onSearchDateSelect}
@ -226,7 +226,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
)}
{Boolean(localResults.length) && (
<div
className="chat-selection no-selection no-scrollbar"
className="chat-selection no-scrollbar"
dir={lang.isRtl ? 'rtl' : undefined}
ref={chatSelectionRef}
>

View File

@ -76,7 +76,7 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
<div className="RecentContacts custom-scroll">
{topUserIds && (
<div className="top-peers-section" dir={lang.isRtl ? 'rtl' : undefined}>
<div ref={topUsersRef} className="top-peers no-selection">
<div ref={topUsersRef} className="top-peers">
{topUserIds.map((userId) => (
<div
key={userId}

View File

@ -181,7 +181,7 @@ function SettingsPerformance({
key={sectionName}
className="settings-dropdown-section"
>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name={sectionName}
value={index.toString()}

View File

@ -26,7 +26,6 @@ import {
} from '../../global/selectors';
import { stopCurrentAudio } from '../../util/audioPlayer';
import captureEscKeyListener from '../../util/captureEscKeyListener';
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import { ANIMATION_END_DELAY } from '../../config';
import { MEDIA_VIEWER_MEDIA_QUERY } from '../common/helpers/mediaDimensions';
import { disableDirectTextInput, enableDirectTextInput } from '../../util/directInputManager';
@ -178,10 +177,6 @@ const MediaViewer: FC<StateProps> = ({
if (isMobile) {
document.body.classList.toggle('is-media-viewer-open', isOpen);
}
// Disable user selection if media viewer is open, to prevent accidental text selection
if (IS_TOUCH_ENV) {
document.body.classList.toggle('no-selection', isOpen);
}
}, [isMobile, isOpen]);
// eslint-disable-next-line no-null/no-null

View File

@ -70,7 +70,9 @@ const MediaViewerFooter: FC<OwnProps> = ({
<div className={classNames} onClick={stopEvent}>
{Boolean(text) && (
<div className="media-viewer-footer-content" onClick={!isMobile ? onClick : undefined}>
<p className={`media-text custom-scroll ${isMultiline ? 'multiline' : ''}`} dir="auto">{text}</p>
<p className={`media-text custom-scroll text-selection ${isMultiline ? 'multiline' : ''}`} dir="auto">
{text}
</p>
</div>
)}
</div>

View File

@ -225,7 +225,7 @@ const EmojiPicker: FC<OwnProps & StateProps> = ({
<div
ref={containerRef}
onScroll={handleContentScroll}
className={buildClassName('EmojiPicker-main no-selection', IS_TOUCH_ENV ? 'no-scrollbar' : 'custom-scroll')}
className={buildClassName('EmojiPicker-main', IS_TOUCH_ENV ? 'no-scrollbar' : 'custom-scroll')}
>
{allCategories.map((category, i) => (
<EmojiCategory

View File

@ -332,7 +332,7 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
const headerClassName = buildClassName(
styles.header,
'no-selection no-scrollbar',
'no-scrollbar',
!shouldHideTopBorder && styles.headerWithBorder,
);
@ -348,7 +348,7 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
ref={containerRef}
onMouseMove={handleMouseMove}
onScroll={handleContentScroll}
className={buildClassName(styles.main, 'no-selection', IS_TOUCH_ENV ? 'no-scrollbar' : 'custom-scroll')}
className={buildClassName(styles.main, IS_TOUCH_ENV ? 'no-scrollbar' : 'custom-scroll')}
>
{allSets.map((stickerSet, i) => (
<StickerSet

View File

@ -565,7 +565,7 @@ const Message: FC<OwnProps & StateProps> = ({
}, [focusLastMessage, isLastInList, transcribedText, withVoiceTranscription]);
const containerClassName = buildClassName(
'Message message-list-item',
'Message message-list-item text-selection',
isFirstInGroup && 'first-in-group',
isProtected && 'is-protected',
isLastInGroup && 'last-in-group',

View File

@ -1,6 +1,7 @@
.MessageContextMenu {
position: absolute;
font-size: 1rem;
user-select: none;
&_items {
overflow: auto;

View File

@ -82,7 +82,7 @@ const ReactionPickerLimited: FC<OwnProps & StateProps> = ({
return (
<div className={styles.root} style={`height: ${pickerHeight}px`}>
<div className={buildClassName(styles.wrapper, 'no-selection', isTouchScreen ? 'no-scrollbar' : 'custom-scroll')}>
<div className={buildClassName(styles.wrapper, isTouchScreen ? 'no-scrollbar' : 'custom-scroll')}>
<div className="symbol-set-container shared-canvas-container">
<canvas ref={sharedCanvasRef} className="shared-canvas" />
<canvas ref={sharedCanvasHqRef} className="shared-canvas" />

View File

@ -23,11 +23,6 @@
margin-bottom: 0;
}
.inactive.no-selection {
user-select: auto;
-webkit-user-select: auto !important;
}
[dir="rtl"] {
.Switcher {
margin-left: 0;

View File

@ -294,7 +294,7 @@ const ManageChannel: FC<OwnProps & StateProps> = ({
{chatReactionsDescription}
</span>
</ListItem>
<div className="ListItem no-selection narrow">
<div className="ListItem narrow">
<Checkbox
checked={isSignaturesShown}
label={lang('ChannelSignMessages')}

View File

@ -441,7 +441,7 @@ const ManageGroup: FC<OwnProps & StateProps> = ({
</ListItem>
{!isPublicGroup && !hasLinkedChannel && Boolean(chatFullInfo) && (
<div className="ListItem narrow no-selection" ref={isPreHistoryHiddenCheckboxRef}>
<div className="ListItem narrow" ref={isPreHistoryHiddenCheckboxRef}>
<Checkbox
checked={!chatFullInfo.isPreHistoryHidden}
label={lang('ChatHistory')}

View File

@ -215,7 +215,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
<h3 className="section-heading mt-4" dir="auto">{lang('EditAdminWhatCanDo')}</h3>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="changeInfo"
checked={Boolean(permissions.changeInfo)}
@ -226,7 +226,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
{isChannel && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="postMessages"
checked={Boolean(permissions.postMessages)}
@ -238,7 +238,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
</div>
)}
{isChannel && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="editMessages"
checked={Boolean(permissions.editMessages)}
@ -249,7 +249,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
)}
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="deleteMessages"
checked={Boolean(permissions.deleteMessages)}
@ -260,7 +260,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
{!isChannel && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="banUsers"
checked={Boolean(permissions.banUsers)}
@ -271,7 +271,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
)}
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="inviteUsers"
checked={Boolean(permissions.inviteUsers)}
@ -282,7 +282,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
{!isChannel && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="pinMessages"
checked={Boolean(permissions.pinMessages)}
@ -293,7 +293,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
)}
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="addAdmins"
checked={Boolean(permissions.addAdmins)}
@ -303,7 +303,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
onChange={handlePermissionChange}
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="manageCall"
checked={Boolean(permissions.manageCall)}
@ -314,7 +314,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
/>
</div>
{isForum && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="manageTopics"
checked={Boolean(permissions.manageTopics)}
@ -326,7 +326,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
</div>
)}
{!isChannel && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="anonymous"
checked={Boolean(permissions.anonymous)}

View File

@ -186,7 +186,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
<div className="section without-bottom-shadow">
<h3 className="section-heading" dir="auto">{lang('ChannelPermissionsHeader')}</h3>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendPlain"
checked={!permissions.sendPlain}
@ -195,7 +195,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
onChange={handlePermissionChange}
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendMedia"
checked={!permissions.sendMedia}
@ -213,7 +213,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
isMediaDropdownOpen && 'DropdownList--open',
)}
>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendPhotos"
checked={!permissions.sendPhotos}
@ -223,7 +223,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendVideos"
checked={!permissions.sendVideos}
@ -233,7 +233,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendStickers"
checked={!permissions.sendStickers && !permissions.sendGifs}
@ -243,7 +243,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendAudios"
checked={!permissions.sendAudios}
@ -253,7 +253,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendDocs"
checked={!permissions.sendDocs}
@ -263,7 +263,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendVoices"
checked={!permissions.sendVoices}
@ -273,7 +273,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendRoundvideos"
checked={!permissions.sendRoundvideos}
@ -283,7 +283,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="embedLinks"
checked={!permissions.embedLinks}
@ -293,7 +293,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="sendPolls"
checked={!permissions.sendPolls}
@ -306,7 +306,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
</div>
<div className={buildClassName('part', isMediaDropdownOpen && 'shifted')}>
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="inviteUsers"
checked={!permissions.inviteUsers}
@ -316,7 +316,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div
className="ListItem no-selection with-checkbox"
className="ListItem with-checkbox"
onClick={shouldDisablePermissionForPublicGroup ? handleDisabledClick : undefined}
>
<Checkbox
@ -329,7 +329,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div
className="ListItem no-selection with-checkbox"
className="ListItem with-checkbox"
onClick={shouldDisablePermissionForPublicGroup ? handleDisabledClick : undefined}
>
<Checkbox
@ -342,7 +342,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
{isForum && (
<div className="ListItem no-selection with-checkbox">
<div className="ListItem with-checkbox">
<Checkbox
name="manageTopics"
checked={!permissions.manageTopics}

View File

@ -146,7 +146,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
<h3 className="section-heading mt-4" dir="auto">{lang('UserRestrictionsCanDo')}</h3>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendPlain"
checked={!permissions.sendPlain}
@ -157,7 +157,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendMedia"
checked={!permissions.sendMedia}
@ -177,7 +177,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
isMediaDropdownOpen && 'DropdownList--open',
)}
>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendPhotos"
checked={!permissions.sendPhotos}
@ -188,7 +188,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendVideos"
checked={!permissions.sendVideos}
@ -199,7 +199,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendStickers"
checked={!permissions.sendStickers && !permissions.sendGifs}
@ -210,7 +210,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendAudios"
checked={!permissions.sendAudios}
@ -221,7 +221,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendDocs"
checked={!permissions.sendDocs}
@ -232,7 +232,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendVoices"
checked={!permissions.sendVoices}
@ -243,7 +243,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendRoundvideos"
checked={!permissions.sendRoundvideos}
@ -254,7 +254,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="embedLinks"
checked={!permissions.embedLinks}
@ -265,7 +265,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="sendPolls"
checked={!permissions.sendPolls}
@ -280,7 +280,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
<div className={buildClassName('part', isMediaDropdownOpen && 'shifted')}>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="inviteUsers"
checked={!permissions.inviteUsers}
@ -290,7 +290,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
onChange={handlePermissionChange}
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="pinMessages"
checked={!permissions.pinMessages}
@ -300,7 +300,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
onChange={handlePermissionChange}
/>
</div>
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="changeInfo"
checked={!permissions.changeInfo}
@ -311,7 +311,7 @@ const ManageGroupUserPermissions: FC<OwnProps & StateProps> = ({
/>
</div>
{isForum && (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name="manageTopics"
checked={!permissions.manageTopics}

View File

@ -142,7 +142,7 @@ const ManageReactions: FC<OwnProps & StateProps> = ({
{lang('AvailableReactions')}
</h3>
{availableActiveReactions?.map(({ reaction, title }) => (
<div className="ListItem no-selection">
<div className="ListItem">
<Checkbox
name={reaction.emoticon}
checked={localEnabledReactions?.allowed.some((r) => isSameReaction(reaction, r))}

View File

@ -205,7 +205,7 @@ const ManageUser: FC<OwnProps & StateProps> = ({
onChange={handleLastNameChange}
value={lastName}
/>
<div className="ListItem no-selection narrow">
<div className="ListItem narrow">
<Checkbox
checked={isNotificationsEnabled}
label={lang('Notifications')}

View File

@ -195,7 +195,7 @@ const ListItem: FC<OwnProps> = ({
const fullClassName = buildClassName(
'ListItem',
className,
!isStatic && 'no-selection',
isStatic && 'text-selection',
ripple && 'has-ripple',
narrow && 'narrow',
disabled && 'disabled',

View File

@ -143,7 +143,7 @@ const Menu: FC<OwnProps> = ({
<div
id={id}
className={buildClassName(
'Menu no-selection',
'Menu',
!noCompact && !isTouchScreen && 'compact',
!IS_BACKDROP_BLUR_SUPPORTED && 'no-blur',
className,

View File

@ -83,7 +83,7 @@ const RangeSlider: FC<OwnProps> = ({
<div className="slider-options">
{options.map((option, index) => (
<div
className={buildClassName('slider-option no-selection', index === value && 'active')}
className={buildClassName('slider-option', index === value && 'active')}
onClick={() => onChange(index)}
>
{option}

View File

@ -75,7 +75,7 @@ const TabList: FC<OwnProps> = ({
return (
<div
className={`TabList no-selection no-scrollbar ${big ? 'big' : ''}`}
className={`TabList no-scrollbar ${big ? 'big' : ''}`}
ref={containerRef}
dir={lang.isRtl ? 'rtl' : undefined}
>

View File

@ -31,14 +31,14 @@ const useContextMenuHandlers = (
const handleBeforeContextMenu = useLastCallback((e: React.MouseEvent) => {
if (!isMenuDisabled && e.button === 2) {
requestMutation(() => {
addExtraClass(e.target as HTMLElement, 'no-selection');
removeExtraClass(e.target as HTMLElement, 'text-selection');
});
}
});
const handleContextMenu = useLastCallback((e: React.MouseEvent) => {
requestMutation(() => {
removeExtraClass(e.target as HTMLElement, 'no-selection');
addExtraClass(e.target as HTMLElement, 'text-selection');
});
if (isMenuDisabled || (shouldDisableOnLink && (e.target as HTMLElement).matches('a[href]'))) {

View File

@ -111,9 +111,8 @@ body.cursor-ew-resize {
visibility: hidden;
}
.no-selection {
user-select: none;
-webkit-user-select: none !important;
.text-selection {
user-select: text !important;
}
.clearfix::after {
@ -164,6 +163,8 @@ body.cursor-ew-resize {
}
body:not(.is-ios) {
user-select: none; // On iOS, disallowing user selection breaks focus in text input fields
.custom-scroll {
&::-webkit-scrollbar {
width: 0.375rem;