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