[MM-62390] Combine the floating and transition styles into one in WithTooltip and other related minor improvements (#29730)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
06ce7b4a5a
Коммит
e0e24aaa6f
@@ -64,7 +64,6 @@ export function SendPostOptions({disabled, onSelect, channelId}: Props) {
|
||||
return (
|
||||
<Menu.Container
|
||||
menuButtonTooltip={{
|
||||
id: 'send_post_option_schedule_post',
|
||||
text: formatMessage({
|
||||
id: 'create_post_button.option.schedule_message',
|
||||
defaultMessage: 'Schedule message',
|
||||
|
||||
@@ -195,7 +195,8 @@ export default class AnnouncementBar extends React.PureComponent<Props, State> {
|
||||
barContent = (
|
||||
<WithTooltip
|
||||
title={this.props.tooltipMsg ? this.props.tooltipMsg : message}
|
||||
tooltipContentContainerClassName='announcementBarTooltip'
|
||||
className='announcementBarTooltip'
|
||||
delayClose={true}
|
||||
>
|
||||
{barContent}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.announcementBarTooltip {
|
||||
min-width: 50vw;
|
||||
max-width: 100vw;
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ function BookmarksMenu({
|
||||
id: 'channelBookmarksPlusMenuDropdown',
|
||||
}}
|
||||
menuButtonTooltip={addBookmarkTooltipText ? {
|
||||
id: 'channelBookmarksPlusMenuButtonTooltip',
|
||||
text: addBookmarkTooltipText,
|
||||
} : undefined}
|
||||
>
|
||||
|
||||
@@ -352,7 +352,6 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "PostDotMenu-ButtonTooltip-post_id_1",
|
||||
"text": "More",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
||||
onToggle: this.handleMenuToggle,
|
||||
}}
|
||||
menuButtonTooltip={{
|
||||
id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`,
|
||||
text: formatMessage({id: 'post_info.dot_menu.tooltip.more', defaultMessage: 'More'}),
|
||||
class: 'hidden-xs',
|
||||
}}
|
||||
|
||||
@@ -44,7 +44,6 @@ type MenuButtonProps = {
|
||||
}
|
||||
|
||||
type MenuButtonTooltipProps = {
|
||||
id: string;
|
||||
isVertical?: boolean;
|
||||
class?: string;
|
||||
text: string;
|
||||
|
||||
@@ -85,13 +85,7 @@ export function ProfilePopoverController<TriggerComponentType = HTMLSpanElement>
|
||||
middleware: [autoPlacement()],
|
||||
});
|
||||
|
||||
const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, {
|
||||
duration: {
|
||||
open: OverlaysTimings.FADE_IN_DURATION,
|
||||
close: OverlaysTimings.FADE_OUT_DURATION,
|
||||
},
|
||||
initial: OverlayTransitionStyles.START,
|
||||
});
|
||||
const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, TRANSITION_STYLE_PROPS);
|
||||
|
||||
const clickInteractions = useClick(floatingContext);
|
||||
const dismissInteraction = useDismiss(floatingContext);
|
||||
@@ -154,3 +148,11 @@ export function ProfilePopoverController<TriggerComponentType = HTMLSpanElement>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const TRANSITION_STYLE_PROPS = {
|
||||
duration: {
|
||||
open: OverlaysTimings.FADE_IN_DURATION,
|
||||
close: OverlaysTimings.FADE_OUT_DURATION,
|
||||
},
|
||||
initial: OverlayTransitionStyles.START,
|
||||
};
|
||||
|
||||
@@ -25,7 +25,6 @@ exports[`components/sidebar/sidebar_category/sidebar_category_sorting_menu shoul
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarCategorySortingMenu-ButtonTooltip-category_id",
|
||||
"text": "Category options",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ const SidebarCategoryGenericMenu = ({
|
||||
children: <DotsVerticalIcon size={16}/>,
|
||||
}}
|
||||
menuButtonTooltip={{
|
||||
id: `SidebarCategoryMenu-ButtonTooltip-${id}`,
|
||||
text: formatMessage({id: 'sidebar_left.sidebar_category_menu.editCategory', defaultMessage: 'Category options'}),
|
||||
class: 'hidden-xs',
|
||||
}}
|
||||
|
||||
@@ -198,7 +198,6 @@ const SidebarCategorySortingMenu = ({
|
||||
children: <DotsVerticalIcon size={16}/>,
|
||||
}}
|
||||
menuButtonTooltip={{
|
||||
id: `SidebarCategorySortingMenu-ButtonTooltip-${category.id}`,
|
||||
text: formatMessage({id: 'sidebar_left.sidebar_category_menu.editCategory', defaultMessage: 'Category options'}),
|
||||
class: 'hidden-xs',
|
||||
}}
|
||||
|
||||
@@ -22,7 +22,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -168,7 +167,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -314,7 +312,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -460,7 +457,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -574,7 +570,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -703,7 +698,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -849,7 +843,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -995,7 +988,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -1141,7 +1133,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
@@ -1287,7 +1278,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor
|
||||
menuButtonTooltip={
|
||||
Object {
|
||||
"class": "hidden-xs",
|
||||
"id": "SidebarChannelMenu-ButtonTooltip-channel_id",
|
||||
"text": "Channel options",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,6 @@ const SidebarChannelMenu = ({
|
||||
children: <DotsVerticalIcon size={16}/>,
|
||||
}}
|
||||
menuButtonTooltip={{
|
||||
id: `SidebarChannelMenu-ButtonTooltip-${channel.id}`,
|
||||
class: 'hidden-xs',
|
||||
text: formatMessage({id: 'sidebar_left.sidebar_channel_menu.editChannel', defaultMessage: 'Channel options'}),
|
||||
}}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
@use 'utils/variables';
|
||||
|
||||
#user-group-popover .popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.user-group-popover-floating-overlay {
|
||||
// 99 being the z-index of the global header
|
||||
z-index: 1060;
|
||||
z-index: variables.$z-index-user-group-popover;
|
||||
}
|
||||
|
||||
@@ -24,21 +24,17 @@ import type {ReactElement, ReactNode} from 'react';
|
||||
import type {MessageDescriptor} from 'react-intl';
|
||||
import {defineMessage} from 'react-intl';
|
||||
|
||||
import {Constants} from 'utils/constants';
|
||||
import {OverlayArrow, OverlaysTimings, OverlayTransitionStyles, RootHtmlPortalId} from 'utils/constants';
|
||||
|
||||
import TooltipContent from './tooltip_content';
|
||||
import type {ShortcutDefinition} from './tooltip_shortcut';
|
||||
|
||||
import './tooltip.scss';
|
||||
|
||||
const ARROW_WIDTH = 10; // in px
|
||||
const ARROW_HEIGHT = 6; // in px
|
||||
const ARROW_OFFSET = 8; // in px
|
||||
|
||||
const TOOLTIP_REST_TIME_BEFORE_OPEN = 400; // in ms
|
||||
const TOOLTIP_APPEAR_DURATION = 250; // in ms
|
||||
const TOOLTIP_DISAPPEAR_DURATION = 200; // in ms
|
||||
import './with_tooltip.scss';
|
||||
|
||||
/**
|
||||
* Shortcut keys map to translations that can be used in the tooltip
|
||||
* when shortcut definition is provided
|
||||
*/
|
||||
export const ShortcutKeys = {
|
||||
alt: defineMessage({
|
||||
id: 'shortcuts.generic.alt',
|
||||
@@ -68,7 +64,17 @@ interface Props {
|
||||
* This doesn't always guarantee the tooltip will be vertical, it just determines the initial placement and fallback placements
|
||||
*/
|
||||
isVertical?: boolean;
|
||||
tooltipContentContainerClassName?: string;
|
||||
|
||||
/**
|
||||
* If closing of the tooltip should be delayed,
|
||||
* Useful if tooltips contains links that need to be clicked
|
||||
*/
|
||||
delayClose?: boolean;
|
||||
|
||||
/**
|
||||
* Additional class name to be added to the tooltip container
|
||||
*/
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
|
||||
/**
|
||||
@@ -79,7 +85,7 @@ interface Props {
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
function WithTooltip({
|
||||
export default function WithTooltip({
|
||||
children,
|
||||
title,
|
||||
emoji,
|
||||
@@ -87,7 +93,8 @@ function WithTooltip({
|
||||
hint,
|
||||
shortcut,
|
||||
isVertical = true,
|
||||
tooltipContentContainerClassName,
|
||||
delayClose = false,
|
||||
className,
|
||||
onOpen,
|
||||
disabled,
|
||||
}: Props) {
|
||||
@@ -116,13 +123,13 @@ function WithTooltip({
|
||||
return {initial, fallback};
|
||||
}, [isVertical]);
|
||||
|
||||
const {refs: {setReference, setFloating}, floatingStyles, context} = useFloating({
|
||||
const {refs: {setReference, setFloating}, floatingStyles, context: floatingContext} = useFloating({
|
||||
open: disabled ? false : open,
|
||||
onOpenChange: handleChange,
|
||||
whileElementsMounted: autoUpdate,
|
||||
placement: placements.initial,
|
||||
middleware: [
|
||||
offset(ARROW_OFFSET),
|
||||
offset(OverlayArrow.OFFSET),
|
||||
flip({
|
||||
fallbackPlacements: placements.fallback,
|
||||
}),
|
||||
@@ -132,75 +139,61 @@ function WithTooltip({
|
||||
],
|
||||
});
|
||||
|
||||
const hover = useHover(context, {
|
||||
restMs: TOOLTIP_REST_TIME_BEFORE_OPEN,
|
||||
const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, TRANSITION_STYLE_PROPS);
|
||||
|
||||
const hover = useHover(floatingContext, {
|
||||
restMs: OverlaysTimings.CURSOR_REST_TIME_BEFORE_OPEN,
|
||||
delay: {
|
||||
open: Constants.OVERLAY_TIME_DELAY,
|
||||
open: OverlaysTimings.CURSOR_MOUSEOVER_TO_OPEN,
|
||||
close: delayClose ? OverlaysTimings.CURSOR_MOUSEOUT_TO_CLOSE_WITH_DELAY : OverlaysTimings.CURSOR_MOUSEOUT_TO_CLOSE,
|
||||
},
|
||||
});
|
||||
const focus = useFocus(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const role = useRole(context, {role: 'tooltip'});
|
||||
const focus = useFocus(floatingContext);
|
||||
const dismiss = useDismiss(floatingContext);
|
||||
const role = useRole(floatingContext, {role: 'tooltip'});
|
||||
|
||||
const {getReferenceProps, getFloatingProps} = useInteractions([hover, focus, dismiss, role]);
|
||||
const {isMounted, styles: transitionStyles} = useTransitionStyles(context, {
|
||||
duration: {
|
||||
open: TOOLTIP_APPEAR_DURATION,
|
||||
close: TOOLTIP_DISAPPEAR_DURATION,
|
||||
},
|
||||
initial: {
|
||||
opacity: 0,
|
||||
},
|
||||
common: {
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (!isValidElement(children)) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Children must be a valid React element for WithTooltip');
|
||||
}
|
||||
|
||||
const mergedRefs = useMergeRefs([(children as any)?.ref, setReference]);
|
||||
const mergedRefs = useMergeRefs([setReference, (children as any)?.ref]);
|
||||
|
||||
const trigger = cloneElement(children, {
|
||||
...getReferenceProps({
|
||||
const trigger = cloneElement(
|
||||
children,
|
||||
getReferenceProps({
|
||||
ref: mergedRefs,
|
||||
...children.props,
|
||||
}),
|
||||
});
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{trigger}
|
||||
|
||||
{isMounted && (
|
||||
<FloatingPortal
|
||||
id='root-portal' // This is the global portal container id
|
||||
>
|
||||
<FloatingPortal id={RootHtmlPortalId}>
|
||||
<div
|
||||
className='tooltipContainer'
|
||||
ref={setFloating}
|
||||
style={floatingStyles}
|
||||
className={classNames('tooltipContainer', className)}
|
||||
style={{...floatingStyles, ...transitionStyles}}
|
||||
{...getFloatingProps()}
|
||||
>
|
||||
<div
|
||||
className={classNames('tooltipContentContainer', tooltipContentContainerClassName)}
|
||||
style={transitionStyles}
|
||||
>
|
||||
<TooltipContent
|
||||
title={title}
|
||||
emoji={emoji}
|
||||
isEmojiLarge={isEmojiLarge}
|
||||
hint={hint}
|
||||
shortcut={shortcut}
|
||||
/>
|
||||
<FloatingArrow
|
||||
ref={arrowRef}
|
||||
context={context}
|
||||
width={ARROW_WIDTH}
|
||||
height={ARROW_HEIGHT}
|
||||
/>
|
||||
</div>
|
||||
<TooltipContent
|
||||
title={title}
|
||||
emoji={emoji}
|
||||
isEmojiLarge={isEmojiLarge}
|
||||
hint={hint}
|
||||
shortcut={shortcut}
|
||||
/>
|
||||
<FloatingArrow
|
||||
ref={arrowRef}
|
||||
context={floatingContext}
|
||||
width={OverlayArrow.WIDTH}
|
||||
height={OverlayArrow.HEIGHT}
|
||||
/>
|
||||
</div>
|
||||
</FloatingPortal>
|
||||
)}
|
||||
@@ -208,4 +201,10 @@ function WithTooltip({
|
||||
);
|
||||
}
|
||||
|
||||
export default WithTooltip;
|
||||
const TRANSITION_STYLE_PROPS = {
|
||||
duration: {
|
||||
open: OverlaysTimings.FADE_IN_DURATION,
|
||||
close: OverlaysTimings.FADE_OUT_DURATION,
|
||||
},
|
||||
initial: OverlayTransitionStyles.START,
|
||||
};
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
.tooltipContainer {
|
||||
z-index: 1070;
|
||||
|
||||
> .tooltipContentContainer {
|
||||
z-index: 1070;
|
||||
max-width: 220px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 1);
|
||||
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.12);
|
||||
line-height: 18px;
|
||||
pointer-events: none;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
|
||||
> .tooltipContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
|
||||
> .tooltipContentTitleContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
|
||||
&.isEmojiLarge {
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
> .tooltipContentEmoji {
|
||||
padding-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
> .tooltipContentEmoji {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
> .tooltipContentTitle {
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .tooltipContentShortcut {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 0;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
> .tooltipContentHint {
|
||||
color: rgba(255, 255, 255, 0.64);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
webapp/channels/src/components/with_tooltip/with_tooltip.scss
Обычный файл
68
webapp/channels/src/components/with_tooltip/with_tooltip.scss
Обычный файл
@@ -0,0 +1,68 @@
|
||||
@use 'utils/variables';
|
||||
|
||||
.tooltipContainer {
|
||||
z-index: variables.$z-index-popover;
|
||||
max-width: 220px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 1);
|
||||
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.12);
|
||||
line-height: 18px;
|
||||
pointer-events: none;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
|
||||
> .tooltipContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
|
||||
> .tooltipContentTitleContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
|
||||
&.isEmojiLarge {
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
> .tooltipContentEmoji {
|
||||
padding-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
> .tooltipContentEmoji {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
> .tooltipContentTitle {
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .tooltipContentShortcut {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 0;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
> .tooltipContentHint {
|
||||
color: rgba(255, 255, 255, 0.64);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,3 +36,9 @@ $elevation-3: var(--elevation-3);
|
||||
$elevation-4: var(--elevation-4);
|
||||
$elevation-5: var(--elevation-5);
|
||||
$elevation-6: var(--elevation-6);
|
||||
|
||||
// Z-Index
|
||||
// Central place to manage z-index values for the app, providing a consistent way to manage stacking order.
|
||||
$z-index-popover: 1070;
|
||||
$z-index-user-group-popover: 1060;
|
||||
$z-index-global-header: 99;
|
||||
|
||||
@@ -2240,6 +2240,9 @@ export const RootHtmlPortalId = 'root-portal';
|
||||
|
||||
export const OverlaysTimings = {
|
||||
CURSOR_REST_TIME_BEFORE_OPEN: 400, // in ms
|
||||
CURSOR_MOUSEOVER_TO_OPEN: 400, // in ms
|
||||
CURSOR_MOUSEOUT_TO_CLOSE: 0,
|
||||
CURSOR_MOUSEOUT_TO_CLOSE_WITH_DELAY: 200, // in ms
|
||||
FADE_IN_DURATION: 250, // in ms
|
||||
FADE_OUT_DURATION: 150, // in ms
|
||||
};
|
||||
@@ -2250,5 +2253,10 @@ export const OverlayTransitionStyles = {
|
||||
},
|
||||
};
|
||||
|
||||
export default Constants;
|
||||
export const OverlayArrow = {
|
||||
WIDTH: 10, // in px
|
||||
HEIGHT: 6, // in px
|
||||
OFFSET: 8, // in px
|
||||
};
|
||||
|
||||
export default Constants;
|
||||
|
||||
Ссылка в новой задаче
Block a user