Fix minor UI issues with composer
This commit is contained in:
parent
3b2000a0ba
commit
4b8cb9f040
16 changed files with 172 additions and 114 deletions
|
@ -6178,6 +6178,7 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
.module-sticker-button__button {
|
.module-sticker-button__button {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
border-radius: 4px;
|
||||||
background: none;
|
background: none;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -6187,7 +6188,7 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
@include keyboard-mode {
|
@include keyboard-mode {
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 1px solid $color-ultramarine;
|
outline: 2px solid $color-ultramarine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6682,6 +6683,7 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
.module-emoji-button__button {
|
.module-emoji-button__button {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
border-radius: 4px;
|
||||||
background: none;
|
background: none;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -6691,7 +6693,7 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
@include keyboard-mode {
|
@include keyboard-mode {
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 1px solid $color-ultramarine;
|
outline: 2px solid $color-ultramarine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6829,6 +6831,8 @@ button.module-image__border-overlay:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
&__input {
|
&__input {
|
||||||
|
$border-size: 1px;
|
||||||
|
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
@ -6836,8 +6840,6 @@ button.module-image__border-overlay:focus {
|
||||||
// Override Quill styles
|
// Override Quill styles
|
||||||
.ql-container {
|
.ql-container {
|
||||||
@include font-body-1;
|
@include font-body-1;
|
||||||
line-height: 21px;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-blank::before {
|
.ql-blank::before {
|
||||||
|
@ -6863,9 +6865,11 @@ button.module-image__border-overlay:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
&__scroller {
|
&__scroller {
|
||||||
padding: 5px 11px 6px 11px;
|
$padding-top: 5px;
|
||||||
min-height: 32px;
|
padding: $padding-top 10px $padding-top 10px;
|
||||||
max-height: 80px;
|
|
||||||
|
min-height: calc(32px - 2 * $border-size);
|
||||||
|
max-height: calc(72px - 2 * $border-size);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
|
@ -6878,22 +6882,21 @@ button.module-image__border-overlay:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
&--large {
|
&--large {
|
||||||
max-height: 227px;
|
max-height: calc(212px - 2 * $border-size);
|
||||||
min-height: 227px;
|
min-height: calc(212px - 2 * $border-size);
|
||||||
|
|
||||||
.DraftEditor-root {
|
.DraftEditor-root {
|
||||||
height: 227px - 2 * 7px; // subtract padding
|
height: calc(212px - 2 * $padding-top - 2 * $border-size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus-within {
|
border: $border-size solid transparent;
|
||||||
@include light-theme() {
|
|
||||||
outline: 1px solid $color-ultramarine;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme() {
|
&:focus-within {
|
||||||
outline: 1px solid $color-ultramarine;
|
outline: 0;
|
||||||
|
@include keyboard-mode {
|
||||||
|
border: $border-size solid $color-ultramarine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6925,7 +6928,7 @@ button.module-image__border-overlay:focus {
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: end;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
&__microphone {
|
&__microphone {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: none;
|
background: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
|
|
||||||
@include keyboard-mode {
|
@include keyboard-mode {
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 1px solid $color-ultramarine;
|
outline: 2px solid $color-ultramarine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
.CompositionArea {
|
.CompositionArea {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
padding-top: 6px;
|
padding: 10px 0 10px 0;
|
||||||
|
|
||||||
&__placeholder {
|
&__placeholder {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
&__row {
|
&__row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: end;
|
||||||
|
|
||||||
&--center {
|
&--center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
&--control-row {
|
&--control-row {
|
||||||
margin-top: 8px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
&--column {
|
&--column {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -82,8 +82,8 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(50% - $width / 2);
|
left: calc(50% - $width / 2);
|
||||||
|
|
||||||
// 6px coming from padding-top, 1px from outline
|
// 6px coming from padding-top of .module-composition-input__input__scroller
|
||||||
top: calc(0px - $height / 2 - 6px - 1px);
|
top: calc(0px - $height / 2 - 6px);
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 12px 12px 0 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
|
@ -194,6 +194,7 @@
|
||||||
&__attach-file {
|
&__attach-file {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
@ -203,7 +204,7 @@
|
||||||
|
|
||||||
@include keyboard-mode {
|
@include keyboard-mode {
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 1px solid $color-ultramarine;
|
outline: 2px solid $color-ultramarine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,10 +272,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&--audio {
|
&--audio {
|
||||||
@include normal-button(
|
@include normal-button('../images/icons/v2/phone-outline-24.svg', 24px);
|
||||||
'../images/icons/v2/phone-right-outline-24.svg',
|
|
||||||
24px
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&--search {
|
&--search {
|
||||||
|
|
|
@ -35,22 +35,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__composition-area {
|
&__composition-area {
|
||||||
margin-bottom: 6px;
|
|
||||||
|
|
||||||
// We need to use the wrapper because the conversation view calculates the height of all
|
// We need to use the wrapper because the conversation view calculates the height of all
|
||||||
// things in the composition area. A margin on an inner div won't be included in that
|
// things in the composition area. A margin on an inner div won't be included in that
|
||||||
// height calculation.
|
// height calculation.
|
||||||
.quote-wrapper {
|
.quote-wrapper,
|
||||||
margin-left: 18px;
|
|
||||||
margin-right: 18px;
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-wrapper {
|
.preview-wrapper {
|
||||||
margin-top: 3px;
|
margin: 0 16px 10px 16px;
|
||||||
margin-left: 12px;
|
|
||||||
margin-right: 12px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,20 @@
|
||||||
&__button {
|
&__button {
|
||||||
@include button-reset();
|
@include button-reset();
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 16px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
opacity: 0.5;
|
|
||||||
width: 32px;
|
width: 32px;
|
||||||
|
|
||||||
&:focus,
|
@include keyboard-mode {
|
||||||
&:hover {
|
&:focus {
|
||||||
opacity: 1;
|
outline: 2px solid $color-ultramarine;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outline: none;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
.module-quote {
|
.module-quote {
|
||||||
&__container {
|
&__container {
|
||||||
margin: {
|
.module-message & {
|
||||||
left: -6px;
|
margin: {
|
||||||
right: -6px;
|
left: -6px;
|
||||||
top: 3px;
|
right: -6px;
|
||||||
bottom: 5px;
|
top: 3px;
|
||||||
|
bottom: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,17 +93,30 @@
|
||||||
border-left-color: $color-white;
|
border-left-color: $color-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-quote--compose-#{$color} {
|
||||||
|
background-color: scale-color($value, $lightness: 60%);
|
||||||
|
border-left-color: $value;
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
background-color: scale-color($value, $lightness: -40%);
|
||||||
|
border-left-color: $color-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-quote--compose-custom,
|
||||||
.module-quote--incoming-custom,
|
.module-quote--incoming-custom,
|
||||||
.module-quote--outgoing-custom {
|
.module-quote--outgoing-custom {
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@each $color, $value in $conversation-colors-gradient {
|
@each $color, $value in $conversation-colors-gradient {
|
||||||
|
.module-quote--compose-#{$color},
|
||||||
.module-quote--incoming-#{$color} {
|
.module-quote--incoming-#{$color} {
|
||||||
border-left-color: map-get($value, 'start');
|
border-left-color: map-get($value, 'start');
|
||||||
}
|
}
|
||||||
|
.module-quote--compose-#{$color},
|
||||||
.module-quote--incoming-#{$color},
|
.module-quote--incoming-#{$color},
|
||||||
.module-quote--outgoing-#{$color} {
|
.module-quote--outgoing-#{$color} {
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
|
|
|
@ -77,7 +77,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
border: solid 1px $color-ultramarine;
|
@include keyboard-mode {
|
||||||
|
border: solid 1px $color-ultramarine;
|
||||||
|
}
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -618,6 +618,7 @@ export const CompositionArea = ({
|
||||||
{quotedMessageProps && (
|
{quotedMessageProps && (
|
||||||
<div className="quote-wrapper">
|
<div className="quote-wrapper">
|
||||||
<Quote
|
<Quote
|
||||||
|
isCompose
|
||||||
{...quotedMessageProps}
|
{...quotedMessageProps}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={onClickQuotedMessage}
|
onClick={onClickQuotedMessage}
|
||||||
|
|
|
@ -188,7 +188,6 @@ export function ContextMenu<T>({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We use regular MouseEvent below, and this one uses React.MouseEvent
|
|
||||||
const handleClick = (ev: KeyboardEvent | React.MouseEvent) => {
|
const handleClick = (ev: KeyboardEvent | React.MouseEvent) => {
|
||||||
setMenuShowing(true);
|
setMenuShowing(true);
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
|
@ -40,6 +40,8 @@ type StateType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export class MainHeader extends React.Component<PropsType, StateType> {
|
export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
|
public containerRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||||
|
|
||||||
constructor(props: PropsType) {
|
constructor(props: PropsType) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
@ -55,18 +57,14 @@ export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
if (
|
if (
|
||||||
showingAvatarPopup &&
|
showingAvatarPopup &&
|
||||||
popperRoot &&
|
popperRoot &&
|
||||||
!popperRoot.contains(target as Node)
|
!popperRoot.contains(target as Node) &&
|
||||||
|
!this.containerRef.current?.contains(target as Node)
|
||||||
) {
|
) {
|
||||||
this.hideAvatarPopup();
|
this.hideAvatarPopup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public showAvatarPopup = (
|
public showAvatarPopup = (): void => {
|
||||||
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
||||||
): void => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
const popperRoot = document.createElement('div');
|
const popperRoot = document.createElement('div');
|
||||||
document.body.appendChild(popperRoot);
|
document.body.appendChild(popperRoot);
|
||||||
|
|
||||||
|
@ -142,7 +140,10 @@ export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
<Manager>
|
<Manager>
|
||||||
<Reference>
|
<Reference>
|
||||||
{({ ref }) => (
|
{({ ref }) => (
|
||||||
<div className="module-main-header__avatar--container">
|
<div
|
||||||
|
className="module-main-header__avatar--container"
|
||||||
|
ref={this.containerRef}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
acceptedMessageRequest
|
acceptedMessageRequest
|
||||||
avatarPath={avatarPath}
|
avatarPath={avatarPath}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { createPortal } from 'react-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Manager, Popper, Reference } from 'react-popper';
|
import { Manager, Popper, Reference } from 'react-popper';
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
|
import { useRefMerger } from '../hooks/useRefMerger';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
@ -26,11 +27,11 @@ export const MediaQualitySelector = ({
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
// We use regular MouseEvent below, and this one uses React.MouseEvent
|
const buttonRef = React.useRef<HTMLButtonElement | null>(null);
|
||||||
const handleClick = (ev: KeyboardEvent | React.MouseEvent) => {
|
const refMerger = useRefMerger();
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
setMenuShowing(true);
|
setMenuShowing(true);
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (ev: KeyboardEvent) => {
|
const handleKeyDown = (ev: KeyboardEvent) => {
|
||||||
|
@ -66,7 +67,10 @@ export const MediaQualitySelector = ({
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
const handleOutsideClick = (event: MouseEvent) => {
|
const handleOutsideClick = (event: MouseEvent) => {
|
||||||
if (!root.contains(event.target as Node)) {
|
if (
|
||||||
|
!root.contains(event.target as Node) &&
|
||||||
|
event.target !== buttonRef.current
|
||||||
|
) {
|
||||||
handleClose();
|
handleClose();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -97,7 +101,7 @@ export const MediaQualitySelector = ({
|
||||||
})}
|
})}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
ref={ref}
|
ref={refMerger(buttonRef, ref)}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -31,6 +31,7 @@ export type Props = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
isFromMe: boolean;
|
isFromMe: boolean;
|
||||||
isIncoming?: boolean;
|
isIncoming?: boolean;
|
||||||
|
isCompose?: boolean;
|
||||||
isStoryReply?: boolean;
|
isStoryReply?: boolean;
|
||||||
moduleClassName?: string;
|
moduleClassName?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
@ -505,6 +506,7 @@ export class Quote extends React.Component<Props, State> {
|
||||||
const {
|
const {
|
||||||
conversationColor,
|
conversationColor,
|
||||||
customColor,
|
customColor,
|
||||||
|
isCompose,
|
||||||
isIncoming,
|
isIncoming,
|
||||||
onClick,
|
onClick,
|
||||||
rawAttachment,
|
rawAttachment,
|
||||||
|
@ -516,6 +518,16 @@ export class Quote extends React.Component<Props, State> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let directionClassName: string;
|
||||||
|
if (isCompose) {
|
||||||
|
directionClassName = this.getClassName('--compose');
|
||||||
|
} else if (isIncoming) {
|
||||||
|
directionClassName = this.getClassName('--incoming');
|
||||||
|
} else {
|
||||||
|
directionClassName = this.getClassName('--outgoing');
|
||||||
|
}
|
||||||
|
const colorClassName = `${directionClassName}-${conversationColor}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={this.getClassName('__container')}>
|
<div className={this.getClassName('__container')}>
|
||||||
<button
|
<button
|
||||||
|
@ -524,12 +536,8 @@ export class Quote extends React.Component<Props, State> {
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
this.getClassName(''),
|
this.getClassName(''),
|
||||||
isIncoming
|
directionClassName,
|
||||||
? this.getClassName('--incoming')
|
colorClassName,
|
||||||
: this.getClassName('--outgoing'),
|
|
||||||
isIncoming
|
|
||||||
? this.getClassName(`--incoming-${conversationColor}`)
|
|
||||||
: this.getClassName(`--outgoing-${conversationColor}`),
|
|
||||||
!onClick && this.getClassName('--no-click'),
|
!onClick && this.getClassName('--no-click'),
|
||||||
referencedMessageNotFound &&
|
referencedMessageNotFound &&
|
||||||
this.getClassName('--with-reference-warning')
|
this.getClassName('--with-reference-warning')
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { Emoji } from './Emoji';
|
||||||
import type { Props as EmojiPickerProps } from './EmojiPicker';
|
import type { Props as EmojiPickerProps } from './EmojiPicker';
|
||||||
import { EmojiPicker } from './EmojiPicker';
|
import { EmojiPicker } from './EmojiPicker';
|
||||||
import type { LocalizerType } from '../../types/Util';
|
import type { LocalizerType } from '../../types/Util';
|
||||||
|
import { useRefMerger } from '../../hooks/useRefMerger';
|
||||||
import * as KeyboardLayout from '../../services/keyboardLayout';
|
import * as KeyboardLayout from '../../services/keyboardLayout';
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
|
@ -43,19 +44,16 @@ export const EmojiButton = React.memo(
|
||||||
const [popperRoot, setPopperRoot] = React.useState<HTMLElement | null>(
|
const [popperRoot, setPopperRoot] = React.useState<HTMLElement | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
const buttonRef = React.useRef<HTMLButtonElement | null>(null);
|
||||||
|
const refMerger = useRefMerger();
|
||||||
|
|
||||||
const handleClickButton = React.useCallback(
|
const handleClickButton = React.useCallback(() => {
|
||||||
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
if (popperRoot) {
|
||||||
event.preventDefault();
|
setOpen(false);
|
||||||
event.stopPropagation();
|
} else {
|
||||||
if (popperRoot) {
|
setOpen(true);
|
||||||
setOpen(false);
|
}
|
||||||
} else {
|
}, [popperRoot, setOpen]);
|
||||||
setOpen(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[popperRoot, setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClose = React.useCallback(() => {
|
const handleClose = React.useCallback(() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
@ -71,7 +69,10 @@ export const EmojiButton = React.memo(
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
const handleOutsideClick = (event: MouseEvent) => {
|
const handleOutsideClick = (event: MouseEvent) => {
|
||||||
if (!root.contains(event.target as Node)) {
|
if (
|
||||||
|
!root.contains(event.target as Node) &&
|
||||||
|
event.target !== buttonRef.current
|
||||||
|
) {
|
||||||
handleClose();
|
handleClose();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -124,7 +125,7 @@ export const EmojiButton = React.memo(
|
||||||
{({ ref }) => (
|
{({ ref }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
ref={ref}
|
ref={refMerger(buttonRef, ref)}
|
||||||
onClick={handleClickButton}
|
onClick={handleClickButton}
|
||||||
className={classNames(className, {
|
className={classNames(className, {
|
||||||
'module-emoji-button__button': true,
|
'module-emoji-button__button': true,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { countStickers } from './lib';
|
||||||
import { offsetDistanceModifier } from '../../util/popperUtil';
|
import { offsetDistanceModifier } from '../../util/popperUtil';
|
||||||
import { themeClassName } from '../../util/theme';
|
import { themeClassName } from '../../util/theme';
|
||||||
import * as KeyboardLayout from '../../services/keyboardLayout';
|
import * as KeyboardLayout from '../../services/keyboardLayout';
|
||||||
|
import { useRefMerger } from '../../hooks/useRefMerger';
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
|
@ -66,34 +67,30 @@ export const StickerButton = React.memo(
|
||||||
const [popperRoot, setPopperRoot] = React.useState<HTMLElement | null>(
|
const [popperRoot, setPopperRoot] = React.useState<HTMLElement | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
const buttonRef = React.useRef<HTMLButtonElement | null>(null);
|
||||||
|
const refMerger = useRefMerger();
|
||||||
|
|
||||||
const handleClickButton = React.useCallback(
|
const handleClickButton = React.useCallback(() => {
|
||||||
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
// Clear tooltip state
|
||||||
event.preventDefault();
|
clearInstalledStickerPack();
|
||||||
event.stopPropagation();
|
clearShowIntroduction();
|
||||||
|
|
||||||
// Clear tooltip state
|
// Handle button click
|
||||||
clearInstalledStickerPack();
|
if (installedPacks.length === 0) {
|
||||||
clearShowIntroduction();
|
onClickAddPack?.();
|
||||||
|
} else if (popperRoot) {
|
||||||
// Handle button click
|
setOpen(false);
|
||||||
if (installedPacks.length === 0) {
|
} else {
|
||||||
onClickAddPack?.();
|
setOpen(true);
|
||||||
} else if (popperRoot) {
|
}
|
||||||
setOpen(false);
|
}, [
|
||||||
} else {
|
clearInstalledStickerPack,
|
||||||
setOpen(true);
|
clearShowIntroduction,
|
||||||
}
|
installedPacks,
|
||||||
},
|
onClickAddPack,
|
||||||
[
|
popperRoot,
|
||||||
clearInstalledStickerPack,
|
setOpen,
|
||||||
clearShowIntroduction,
|
]);
|
||||||
installedPacks,
|
|
||||||
onClickAddPack,
|
|
||||||
popperRoot,
|
|
||||||
setOpen,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePickSticker = React.useCallback(
|
const handlePickSticker = React.useCallback(
|
||||||
(packId: string, stickerId: number, url: string) => {
|
(packId: string, stickerId: number, url: string) => {
|
||||||
|
@ -139,7 +136,11 @@ export const StickerButton = React.memo(
|
||||||
targetClassName.indexOf('module-sticker-picker__header__button') <
|
targetClassName.indexOf('module-sticker-picker__header__button') <
|
||||||
0;
|
0;
|
||||||
|
|
||||||
if (!root.contains(targetElement) && isMissingButtonClass) {
|
if (
|
||||||
|
!root.contains(targetElement) &&
|
||||||
|
isMissingButtonClass &&
|
||||||
|
targetElement !== buttonRef.current
|
||||||
|
) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -214,7 +215,7 @@ export const StickerButton = React.memo(
|
||||||
{({ ref }) => (
|
{({ ref }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
ref={ref}
|
ref={refMerger(buttonRef, ref)}
|
||||||
onClick={handleClickButton}
|
onClick={handleClickButton}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
{
|
{
|
||||||
|
|
|
@ -8687,6 +8687,22 @@
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-10-11T21:21:08.188Z"
|
"updated": "2021-10-11T21:21:08.188Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rule": "React-createRef",
|
||||||
|
"path": "ts/components/MainHeader.tsx",
|
||||||
|
"line": " public containerRef: React.RefObject<HTMLDivElement> = React.createRef();",
|
||||||
|
"reasonCategory": "usageTrusted",
|
||||||
|
"updated": "2022-06-14T22:04:43.988Z",
|
||||||
|
"reasonDetail": "Handling outside click"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "React-useRef",
|
||||||
|
"path": "ts/components/MediaQualitySelector.tsx",
|
||||||
|
"line": " const buttonRef = React.useRef<HTMLButtonElement | null>(null);",
|
||||||
|
"reasonCategory": "usageTrusted",
|
||||||
|
"updated": "2022-06-14T22:04:43.988Z",
|
||||||
|
"reasonDetail": "Handling outside click"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/Modal.tsx",
|
"path": "ts/components/Modal.tsx",
|
||||||
|
@ -8899,6 +8915,14 @@
|
||||||
"updated": "2019-11-01T22:46:33.013Z",
|
"updated": "2019-11-01T22:46:33.013Z",
|
||||||
"reasonDetail": "Used for setting focus only"
|
"reasonDetail": "Used for setting focus only"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rule": "React-useRef",
|
||||||
|
"path": "ts/components/emoji/EmojiButton.tsx",
|
||||||
|
"line": " const buttonRef = React.useRef<HTMLButtonElement | null>(null);",
|
||||||
|
"reasonCategory": "usageTrusted",
|
||||||
|
"updated": "2022-06-14T22:04:43.988Z",
|
||||||
|
"reasonDetail": "Handling outside click"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/installScreen/InstallScreenChoosingDeviceNameStep.tsx",
|
"path": "ts/components/installScreen/InstallScreenChoosingDeviceNameStep.tsx",
|
||||||
|
@ -8907,6 +8931,14 @@
|
||||||
"updated": "2021-12-06T23:07:28.947Z",
|
"updated": "2021-12-06T23:07:28.947Z",
|
||||||
"reasonDetail": "Doesn't touch the DOM."
|
"reasonDetail": "Doesn't touch the DOM."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rule": "React-useRef",
|
||||||
|
"path": "ts/components/stickers/StickerButton.tsx",
|
||||||
|
"line": " const buttonRef = React.useRef<HTMLButtonElement | null>(null);",
|
||||||
|
"reasonCategory": "usageTrusted",
|
||||||
|
"updated": "2022-06-14T22:04:43.988Z",
|
||||||
|
"reasonDetail": "Handling outside click"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/hooks/useIntersectionObserver.ts",
|
"path": "ts/hooks/useIntersectionObserver.ts",
|
||||||
|
|
Loading…
Reference in a new issue