[MM-56599] Upgrade to "@floating-ui/react" for advanced_text_editor/formatting_bar component (#25970)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
62064e3bf7
Коммит
797fe9b917
@@ -6,6 +6,7 @@
|
||||
"version": "9.3.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.26.6",
|
||||
"@floating-ui/react-dom": "1.0.0",
|
||||
"@floating-ui/react-dom-interactions": "0.10.3",
|
||||
"@giphy/js-fetch-api": "5.1.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useFloating, offset} from '@floating-ui/react-dom';
|
||||
import {useFloating, offset, useClick, useDismiss, useInteractions} from '@floating-ui/react';
|
||||
import classNames from 'classnames';
|
||||
import React, {memo, useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
@@ -13,7 +13,7 @@ import {DotsHorizontalIcon} from '@mattermost/compass-icons/components';
|
||||
import type {ApplyMarkdownOptions} from 'utils/markdown/apply_markdown';
|
||||
|
||||
import FormattingIcon, {IconContainer} from './formatting_icon';
|
||||
import {useFormattingBarControls, useGetLatest} from './hooks';
|
||||
import {useFormattingBarControls} from './hooks';
|
||||
|
||||
export const Separator = styled.div`
|
||||
display: block;
|
||||
@@ -147,38 +147,22 @@ const FormattingBar = (props: FormattingBarProps): JSX.Element => {
|
||||
const {formatMessage} = useIntl();
|
||||
const HiddenControlsButtonAriaLabel = formatMessage({id: 'accessibility.button.hidden_controls_button', defaultMessage: 'show hidden formatting options'});
|
||||
|
||||
const {x, y, reference, floating, strategy, update, refs: {reference: buttonRef, floating: floatingRef}} = useFloating<HTMLButtonElement>({
|
||||
const {x, y, strategy, update, context, refs: {setReference, setFloating}} = useFloating<HTMLButtonElement>({
|
||||
open: showHiddenControls,
|
||||
onOpenChange: setShowHiddenControls,
|
||||
placement: 'top',
|
||||
middleware: [offset({mainAxis: 4})],
|
||||
});
|
||||
|
||||
// this little helper hook always returns the latest refs and does not mess with the popper placement calculation
|
||||
const getLatest = useGetLatest({
|
||||
showHiddenControls,
|
||||
buttonRef,
|
||||
floatingRef,
|
||||
});
|
||||
const click = useClick(context);
|
||||
const {getReferenceProps: getClickReferenceProps, getFloatingProps: getClickFloatingProps} = useInteractions([
|
||||
click,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside: EventListener = (event) => {
|
||||
const {floatingRef, buttonRef} = getLatest();
|
||||
const target = event.composedPath?.()?.[0] || event.target;
|
||||
if (target instanceof Node) {
|
||||
if (
|
||||
floatingRef !== null &&
|
||||
buttonRef !== null &&
|
||||
!floatingRef.current?.contains(target) &&
|
||||
!buttonRef.current?.contains(target)
|
||||
) {
|
||||
setShowHiddenControls(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, [getLatest, setShowHiddenControls]);
|
||||
const dismiss = useDismiss(context);
|
||||
const {getReferenceProps: getDismissReferenceProps, getFloatingProps: getDismissFloatingProps} = useInteractions([
|
||||
dismiss,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
update?.();
|
||||
@@ -186,13 +170,6 @@ const FormattingBar = (props: FormattingBarProps): JSX.Element => {
|
||||
|
||||
const hasHiddenControls = wideMode !== 'wide';
|
||||
|
||||
const toggleHiddenControls = useCallback((event?) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
setShowHiddenControls(!showHiddenControls);
|
||||
}, [showHiddenControls]);
|
||||
|
||||
/**
|
||||
* wrapping this factory in useCallback prevents it from constantly getting a new
|
||||
* function signature as if we would define it directly in the props of
|
||||
@@ -222,9 +199,9 @@ const FormattingBar = (props: FormattingBarProps): JSX.Element => {
|
||||
|
||||
// if hidden controls are currently open close them
|
||||
if (showHiddenControls) {
|
||||
toggleHiddenControls();
|
||||
setShowHiddenControls(true);
|
||||
}
|
||||
}, [getCurrentSelection, getCurrentMessage, applyMarkdown, showHiddenControls, toggleHiddenControls, disableControls]);
|
||||
}, [getCurrentSelection, getCurrentMessage, applyMarkdown, showHiddenControls, disableControls]);
|
||||
|
||||
const leftPosition = wideMode === 'min' ? (x ?? 0) + DEFAULT_MIN_MODE_X_COORD : x ?? 0;
|
||||
|
||||
@@ -263,10 +240,11 @@ const FormattingBar = (props: FormattingBarProps): JSX.Element => {
|
||||
<>
|
||||
<IconContainer
|
||||
id={'HiddenControlsButton' + location}
|
||||
ref={reference}
|
||||
ref={setReference}
|
||||
className={classNames({active: showHiddenControls})}
|
||||
onClick={toggleHiddenControls}
|
||||
aria-label={HiddenControlsButtonAriaLabel}
|
||||
{...getClickReferenceProps()}
|
||||
{...getDismissReferenceProps()}
|
||||
>
|
||||
<DotsHorizontalIcon
|
||||
color={'currentColor'}
|
||||
@@ -282,8 +260,10 @@ const FormattingBar = (props: FormattingBarProps): JSX.Element => {
|
||||
in={showHiddenControls}
|
||||
>
|
||||
<HiddenControlsContainer
|
||||
ref={floating}
|
||||
ref={setFloating}
|
||||
style={hiddenControlsContainerStyles}
|
||||
{...getClickFloatingProps()}
|
||||
{...getDismissFloatingProps()}
|
||||
>
|
||||
{hiddenControls.map((mode) => {
|
||||
return (
|
||||
|
||||
@@ -3,18 +3,13 @@
|
||||
|
||||
import type {Instance} from '@popperjs/core';
|
||||
import {debounce} from 'lodash';
|
||||
import React, {useCallback, useEffect, useLayoutEffect, useState} from 'react';
|
||||
import type React from 'react';
|
||||
import {useCallback, useEffect, useLayoutEffect, useState} from 'react';
|
||||
|
||||
import type {MarkdownMode} from 'utils/markdown/apply_markdown';
|
||||
|
||||
type WideMode = 'wide' | 'normal' | 'narrow' | 'min';
|
||||
|
||||
export function useGetLatest<T>(val: T) {
|
||||
const ref = React.useRef<T>(val);
|
||||
ref.current = val;
|
||||
return React.useCallback(() => ref.current, []);
|
||||
}
|
||||
|
||||
const useResponsiveFormattingBar = (ref: React.RefObject<HTMLDivElement>): WideMode => {
|
||||
const [wideMode, setWideMode] = useState<WideMode>('wide');
|
||||
const handleResize = useCallback(debounce(() => {
|
||||
|
||||
Ссылка в новой задаче
Block a user