diff --git a/src/bundles/extra.ts b/src/bundles/extra.ts index 1f8d58839..3c4aaf9fe 100644 --- a/src/bundles/extra.ts +++ b/src/bundles/extra.ts @@ -32,7 +32,6 @@ export { default as MobileSearch } from '../components/middle/MobileSearch'; export { default as AttachmentModal } from '../components/middle/composer/AttachmentModal'; export { default as PollModal } from '../components/middle/composer/PollModal'; export { default as SymbolMenu } from '../components/middle/composer/SymbolMenu'; -export { default as AttachMenu } from '../components/middle/composer/AttachMenu'; export { default as BotCommandTooltip } from '../components/middle/composer/BotCommandTooltip'; export { default as BotCommandMenu } from '../components/middle/composer/BotCommandMenu'; export { default as MentionTooltip } from '../components/middle/composer/MentionTooltip'; diff --git a/src/components/middle/composer/AttachMenu.async.tsx b/src/components/middle/composer/AttachMenu.async.tsx deleted file mode 100644 index c1bb64e6e..000000000 --- a/src/components/middle/composer/AttachMenu.async.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { FC, memo } from '../../../lib/teact/teact'; -import { OwnProps } from './AttachMenu'; -import { Bundles } from '../../../util/moduleLoader'; - -import useModuleLoader from '../../../hooks/useModuleLoader'; - -const AttachMenuAsync: FC = (props) => { - const { isOpen } = props; - const AttachMenu = useModuleLoader(Bundles.Extra, 'AttachMenu', !isOpen); - - // eslint-disable-next-line react/jsx-props-no-spreading - return AttachMenu ? : undefined; -}; - -export default memo(AttachMenuAsync); diff --git a/src/components/middle/composer/AttachMenu.scss b/src/components/middle/composer/AttachMenu.scss index e306bd4ab..27e0623f3 100644 --- a/src/components/middle/composer/AttachMenu.scss +++ b/src/components/middle/composer/AttachMenu.scss @@ -1,18 +1,31 @@ .AttachMenu { - position: relative; - - .is-pointer-env & { - > .backdrop { - position: absolute; - top: -1rem; - left: auto; - right: 0; - width: 3.5rem; + &--button { + &:focus { + color: var(--color-primary); } } + &--menu { + position: relative; + top: -3.5rem; - .media-disabled > button { - white-space: normal; + @media (max-width: 600px) { + top: -2.875rem; + } + + .is-pointer-env & { + > .backdrop { + position: absolute; + top: -1rem; + left: auto; + right: 0; + width: 3.5rem; + } + } + + + .media-disabled > button { + white-space: normal; + } } } diff --git a/src/components/middle/composer/AttachMenu.tsx b/src/components/middle/composer/AttachMenu.tsx index 7290a8e91..83c9b8bb3 100644 --- a/src/components/middle/composer/AttachMenu.tsx +++ b/src/components/middle/composer/AttachMenu.tsx @@ -1,29 +1,39 @@ -import React, { FC, memo, useCallback } from '../../../lib/teact/teact'; +import React, { + FC, memo, useCallback, useEffect, +} from '../../../lib/teact/teact'; import { CONTENT_TYPES_WITH_PREVIEW } from '../../../config'; import { IS_TOUCH_ENV } from '../../../util/environment'; import { openSystemFilesDialog } from '../../../util/systemFilesDialog'; import useMouseInside from '../../../hooks/useMouseInside'; import useLang from '../../../hooks/useLang'; +import useFlag from '../../../hooks/useFlag'; +import ResponsiveHoverButton from '../../ui/ResponsiveHoverButton'; import Menu from '../../ui/Menu'; import MenuItem from '../../ui/MenuItem'; import './AttachMenu.scss'; export type OwnProps = { - isOpen: boolean; + isButtonVisible: boolean; canAttachMedia: boolean; canAttachPolls: boolean; onFileSelect: (files: File[], isQuick: boolean) => void; onPollCreate: () => void; - onClose: () => void; }; const AttachMenu: FC = ({ - isOpen, canAttachMedia, canAttachPolls, onFileSelect, onPollCreate, onClose, + isButtonVisible, canAttachMedia, canAttachPolls, onFileSelect, onPollCreate, }) => { - const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose); + const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag(); + const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu); + + useEffect(() => { + if (isAttachMenuOpen) { + markMouseInside(); + } + }, [isAttachMenuOpen, markMouseInside]); const handleFileSelect = useCallback((e: Event, isQuick: boolean) => { const { files } = e.target as HTMLInputElement; @@ -46,38 +56,58 @@ const AttachMenu: FC = ({ const lang = useLang(); + if (!isButtonVisible) { + return; + } + return ( - - {/* +
+ + + + + {/* ** Using ternary operator here causes some attributes from first clause ** transferring to the fragment content in the second clause */} - {!canAttachMedia && ( - Posting media content is not allowed in this group. - )} - {canAttachMedia && ( - <> - - {lang('AttachmentMenu.PhotoOrVideo')} - - {lang('AttachDocument')} - - )} - {canAttachPolls && ( - {lang('Poll')} - )} - + {!canAttachMedia && ( + Posting media content is not allowed in this group. + )} + {canAttachMedia && ( + <> + + {lang('AttachmentMenu.PhotoOrVideo')} + + {lang('AttachDocument')} + + )} + {canAttachPolls && ( + {lang('Poll')} + )} +
+ ); }; diff --git a/src/components/middle/composer/Composer.scss b/src/components/middle/composer/Composer.scss index ac35d51f5..411005fa2 100644 --- a/src/components/middle/composer/Composer.scss +++ b/src/components/middle/composer/Composer.scss @@ -250,6 +250,7 @@ margin-right: -0.5rem; } + > .AttachMenu > .Button, > .Button { flex-shrink: 0; background: none !important; @@ -263,7 +264,7 @@ color: var(--color-composer-button); } - + .Button { + + .Button, + .AttachMenu { margin-left: -1rem; } @@ -271,7 +272,7 @@ width: 2.875rem; height: 2.875rem; - + .Button { + + .Button, + .AttachMenu { margin-left: -0.6875rem; } } diff --git a/src/components/middle/composer/Composer.tsx b/src/components/middle/composer/Composer.tsx index e48639230..d1ea5f57d 100644 --- a/src/components/middle/composer/Composer.tsx +++ b/src/components/middle/composer/Composer.tsx @@ -84,8 +84,8 @@ import Button from '../../ui/Button'; import ResponsiveHoverButton from '../../ui/ResponsiveHoverButton'; import Spinner from '../../ui/Spinner'; import CalendarModal from '../../common/CalendarModal.async'; +import AttachMenu from './AttachMenu'; import Avatar from '../../common/Avatar'; -import AttachMenu from './AttachMenu.async'; import SymbolMenu from './SymbolMenu.async'; import InlineBotTooltip from './InlineBotTooltip.async'; import MentionTooltip from './MentionTooltip.async'; @@ -289,7 +289,6 @@ const Composer: FC = ({ const [isBotKeyboardOpen, openBotKeyboard, closeBotKeyboard] = useFlag(); const [isBotCommandMenuOpen, openBotCommandMenu, closeBotCommandMenu] = useFlag(); - const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag(); const [isSymbolMenuOpen, openSymbolMenu, closeSymbolMenu] = useFlag(); const [isSendAsMenuOpen, openSendAsMenu, closeSendAsMenu] = useFlag(); const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag(); @@ -1014,17 +1013,6 @@ const Composer: FC = ({ )} - {!activeVoiceRecording && !editingMessage && ( - - - - )} {activeVoiceRecording && currentRecordTime && ( {formatVoiceRecordDuration(currentRecordTime - startRecordTimeRef.current!)} @@ -1044,12 +1032,11 @@ const Composer: FC = ({ addRecentEmoji={addRecentEmoji} /> {botKeyboardMessageId && ( = ({ onMouseDown={handleMouseDown} onContextMenu={IS_ANDROID ? stopEvent : undefined} onTouchCancel={IS_ANDROID ? processSelection : undefined} + aria-label={placeholder} />
{!forcedPlaceholder && {placeholder}} diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index ba9b837d1..bfbdfff51 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -20,6 +20,7 @@ export type OwnProps = { 'primary' | 'secondary' | 'gray' | 'danger' | 'translucent' | 'translucent-white' | 'translucent-black' | 'dark' ); backgroundImage?: string; + id?: string; className?: string; round?: boolean; pill?: boolean; @@ -27,6 +28,8 @@ export type OwnProps = { isText?: boolean; isLoading?: boolean; ariaLabel?: string; + ariaControls?: string; + hasPopup?: boolean; href?: string; download?: string; disabled?: boolean; @@ -49,6 +52,7 @@ const CLICKED_TIMEOUT = 400; const Button: FC = ({ ref, type = 'button', + id, onClick, onContextMenu, onMouseDown, @@ -66,6 +70,8 @@ const Button: FC = ({ isText, isLoading, ariaLabel, + ariaControls, + hasPopup, href, download, disabled, @@ -122,12 +128,16 @@ const Button: FC = ({ return ( } + id={id} className={fullClassName} href={href} title={ariaLabel} download={download} tabIndex={tabIndex} dir={isRtl ? 'rtl' : undefined} + aria-label={ariaLabel} + aria-controls={ariaControls} + aria-haspopup={hasPopup} > {children} {!disabled && ripple && ( @@ -141,6 +151,7 @@ const Button: FC = ({ // eslint-disable-next-line react/button-has-type