change(ui) - floating ui
This commit is contained in:
parent
afe43842fc
commit
55edc0b592
13 changed files with 401 additions and 200 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import stl from './notifications.module.css';
|
||||
import { connect } from 'react-redux';
|
||||
import { Icon, Popup } from 'UI';
|
||||
import { Icon, Popup, Tooltip } from 'UI';
|
||||
import { fetchList, setViewed, clearAll } from 'Duck/notifications';
|
||||
import { setLastRead } from 'Duck/announcements';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
|
|
@ -29,7 +29,7 @@ function Notifications(props: Props) {
|
|||
}, []);
|
||||
|
||||
return useObserver(() => (
|
||||
<Popup content={`Alerts`}>
|
||||
<Tooltip tooltip={`Alerts`}>
|
||||
<div
|
||||
className={stl.button}
|
||||
onClick={() => showModal(<AlertTriggersModal />, { right: true })}
|
||||
|
|
@ -39,7 +39,7 @@ function Notifications(props: Props) {
|
|||
</div>
|
||||
<Icon name="bell" size="18" color="gray-dark" />
|
||||
</div>
|
||||
</Popup>
|
||||
</Tooltip>
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useModal } from 'App/components/Modal';
|
||||
import React from 'react';
|
||||
import SessionSettings from 'Shared/SessionSettings';
|
||||
import { Button } from 'UI';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import { Button, Tooltip } from 'UI';
|
||||
// import { Tooltip } from 'react-tippy';
|
||||
|
||||
function SessionSettingButton(props: any) {
|
||||
const { showModal } = useModal();
|
||||
|
|
@ -14,7 +14,7 @@ function SessionSettingButton(props: any) {
|
|||
return (
|
||||
<div className="cursor-pointer ml-4" onClick={handleClick}>
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip title="Session Settings" unmountHTMLWhenHide>
|
||||
<Tooltip tooltip="Session Settings">
|
||||
<Button icon="sliders" variant="text" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { toast } from 'react-toastify';
|
||||
import { connectPlayer } from 'Player';
|
||||
import withRequest from 'HOCs/withRequest';
|
||||
import { Icon, Button } from 'UI';
|
||||
import { Icon, Button, Popover } from 'UI';
|
||||
import styles from './sharePopup.module.css';
|
||||
import IntegrateSlackButton from '../IntegrateSlackButton/IntegrateSlackButton';
|
||||
import SessionCopyLink from './SessionCopyLink';
|
||||
import Select from 'Shared/Select';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import cn from 'classnames';
|
||||
import { fetchList, init } from 'Duck/integrations/slack';
|
||||
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
|
||||
import { fetchList } from 'Duck/integrations/slack';
|
||||
|
||||
// @connectPlayer((state) => ({
|
||||
// time: state.time,
|
||||
// }))
|
||||
@connect(
|
||||
(state) => ({
|
||||
channels: state.getIn(['slack', 'list']),
|
||||
|
|
@ -75,84 +69,67 @@ export default class SharePopup extends React.PureComponent {
|
|||
const options = channels
|
||||
.map(({ webhookId, name }) => ({ value: webhookId, label: name }))
|
||||
.toJS();
|
||||
return (
|
||||
<OutsideClickDetectingDiv
|
||||
className={cn('relative flex items-center')}
|
||||
onClickOutside={() => {
|
||||
this.setState({ isOpen: false });
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
open={isOpen}
|
||||
theme="light"
|
||||
interactive
|
||||
position="bottom"
|
||||
unmountHTMLWhenHide
|
||||
useContext
|
||||
arrow
|
||||
trigger="click"
|
||||
shown={this.handleOpen}
|
||||
className="h-full w-full p-3"
|
||||
// beforeHidden={this.handleClose}
|
||||
html={
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.header}>
|
||||
<div className={cn(styles.title, 'text-lg')}>Share this session link to Slack</div>
|
||||
</div>
|
||||
{options.length === 0 ? (
|
||||
<>
|
||||
<div className={styles.body}>
|
||||
<IntegrateSlackButton />
|
||||
</div>
|
||||
{showCopyLink && (
|
||||
<div className={styles.footer}>
|
||||
<SessionCopyLink />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<div className={styles.body}>
|
||||
<textarea
|
||||
name="message"
|
||||
id="message"
|
||||
cols="30"
|
||||
rows="4"
|
||||
resize="none"
|
||||
onChange={this.editMessage}
|
||||
value={comment}
|
||||
placeholder="Add Message (Optional)"
|
||||
className="p-4"
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Select
|
||||
options={options}
|
||||
defaultValue={channelId}
|
||||
onChange={this.changeChannel}
|
||||
className="mr-4"
|
||||
/>
|
||||
<div>
|
||||
<Button onClick={this.share} variant="primary">
|
||||
<div className="flex items-center">
|
||||
<Icon name="integrations/slack-bw" size="18" marginRight="10" />
|
||||
{loading ? 'Sending...' : 'Send'}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<Popover
|
||||
render={() => (
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.header}>
|
||||
<div className={cn(styles.title, 'text-lg')}>Share this session link to Slack</div>
|
||||
</div>
|
||||
{options.length === 0 ? (
|
||||
<>
|
||||
<div className={styles.body}>
|
||||
<IntegrateSlackButton />
|
||||
</div>
|
||||
{showCopyLink && (
|
||||
<div className={styles.footer}>
|
||||
<SessionCopyLink />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<div className={styles.body}>
|
||||
<textarea
|
||||
name="message"
|
||||
id="message"
|
||||
cols="30"
|
||||
rows="4"
|
||||
resize="none"
|
||||
onChange={this.editMessage}
|
||||
value={comment}
|
||||
placeholder="Add Message (Optional)"
|
||||
className="p-4"
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Select
|
||||
options={options}
|
||||
defaultValue={channelId}
|
||||
onChange={this.changeChannel}
|
||||
className="mr-4"
|
||||
/>
|
||||
<div>
|
||||
<Button onClick={this.share} variant="primary">
|
||||
<div className="flex items-center">
|
||||
<Icon name="integrations/slack-bw" size="18" marginRight="10" />
|
||||
{loading ? 'Sending...' : 'Send'}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div onClick={this.onClickHandler}>{trigger}</div>
|
||||
</Tooltip>
|
||||
</OutsideClickDetectingDiv>
|
||||
<div className={styles.footer}>
|
||||
<SessionCopyLink />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="p-3 w-full">{trigger}</div>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Icon } from 'UI';
|
||||
import { Icon, Popover } from 'UI';
|
||||
import styles from './itemMenu.module.css';
|
||||
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
|
||||
import cn from 'classnames';
|
||||
|
||||
interface Item {
|
||||
|
|
@ -58,71 +57,69 @@ export default class ItemMenu extends React.PureComponent<Props> {
|
|||
const parentStyles = label ? 'rounded px-2 py-2 hover:bg-gray-light' : '';
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<OutsideClickDetectingDiv onClickOutside={this.closeMenu}>
|
||||
<Popover
|
||||
render={() => (
|
||||
<div
|
||||
onClick={this.toggleMenu}
|
||||
className={cn(
|
||||
'flex items-center cursor-pointer select-none hover rounded-full',
|
||||
!this.props.flat ? parentStyles : '',
|
||||
{ 'bg-gray-light': !this.props.flat && displayed && label }
|
||||
)}
|
||||
className={cn(styles.menu, { [styles.menuDim]: !bold })}
|
||||
// style={{
|
||||
// top: this.props.flat ? 24 : undefined,
|
||||
// }}
|
||||
// data-displayed={displayed}
|
||||
>
|
||||
{label && (
|
||||
<span
|
||||
className={cn(
|
||||
'mr-1',
|
||||
bold ? 'font-medium color-gray-darkest' : 'color-gray-medium'
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{this.props.flat ? null : (
|
||||
<div
|
||||
ref={(ref) => {
|
||||
this.menuBtnRef = ref;
|
||||
}}
|
||||
className={cn('rounded-full flex items-center justify-center', {
|
||||
'bg-gray-light': displayed,
|
||||
'w-10 h-10': !label,
|
||||
})}
|
||||
role="button"
|
||||
>
|
||||
<Icon name="ellipsis-v" size="16" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</OutsideClickDetectingDiv>
|
||||
<div
|
||||
className={cn(styles.menu, { [styles.menuDim]: !bold })}
|
||||
style={{
|
||||
top: this.props.flat ? 24 : undefined,
|
||||
}}
|
||||
data-displayed={displayed}
|
||||
>
|
||||
{items
|
||||
.filter(({ hidden }) => !hidden)
|
||||
.map(({ onClick, text, icon, disabled = false }) => (
|
||||
<div
|
||||
key={text}
|
||||
onClick={!disabled ? this.onClick(onClick) : () => {}}
|
||||
className={disabled ? 'cursor-not-allowed' : ''}
|
||||
role="menuitem"
|
||||
>
|
||||
<div className={cn(styles.menuItem, 'text-neutral-700', { disabled: disabled })}>
|
||||
{icon && (
|
||||
<div className={styles.iconWrapper}>
|
||||
{/* @ts-ignore */}
|
||||
<Icon name={icon} size="13" color="gray-dark" />
|
||||
</div>
|
||||
)}
|
||||
<div>{text}</div>
|
||||
{items
|
||||
.filter(({ hidden }) => !hidden)
|
||||
.map(({ onClick, text, icon, disabled = false }) => (
|
||||
<div
|
||||
key={text}
|
||||
onClick={!disabled ? this.onClick(onClick) : () => {}}
|
||||
className={disabled ? 'cursor-not-allowed' : ''}
|
||||
role="menuitem"
|
||||
>
|
||||
<div className={cn(styles.menuItem, 'text-neutral-700', { disabled: disabled })}>
|
||||
{icon && (
|
||||
<div className={styles.iconWrapper}>
|
||||
{/* @ts-ignore */}
|
||||
<Icon name={icon} size="13" color="gray-dark" />
|
||||
</div>
|
||||
)}
|
||||
<div>{text}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div
|
||||
// onClick={this.toggleMenu}
|
||||
className={cn(
|
||||
'flex items-center cursor-pointer select-none hover rounded-full',
|
||||
!this.props.flat ? parentStyles : '',
|
||||
{ 'bg-gray-light': !this.props.flat && displayed && label }
|
||||
)}
|
||||
>
|
||||
{label && (
|
||||
<span
|
||||
className={cn('mr-1', bold ? 'font-medium color-gray-darkest' : 'color-gray-medium')}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{this.props.flat ? null : (
|
||||
<div
|
||||
ref={(ref) => {
|
||||
this.menuBtnRef = ref;
|
||||
}}
|
||||
className={cn('rounded-full flex items-center justify-center', {
|
||||
'bg-gray-light': displayed,
|
||||
'w-10 h-10': !label,
|
||||
})}
|
||||
role="button"
|
||||
>
|
||||
<Icon name="ellipsis-v" size="16" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@
|
|||
|
||||
white-space: nowrap;
|
||||
z-index: 20;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 37px;
|
||||
/* position: absolute; */
|
||||
/* right: 0px; */
|
||||
/* top: 37px; */
|
||||
min-width: 150px;
|
||||
background-color: $white;
|
||||
border-radius: 3px;
|
||||
|
|
|
|||
84
frontend/app/components/ui/Popover/Popover.tsx
Normal file
84
frontend/app/components/ui/Popover/Popover.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import React, { cloneElement, useMemo, useState } from 'react';
|
||||
import {
|
||||
Placement,
|
||||
offset,
|
||||
flip,
|
||||
shift,
|
||||
autoUpdate,
|
||||
useFloating,
|
||||
useInteractions,
|
||||
useRole,
|
||||
useDismiss,
|
||||
useId,
|
||||
useClick,
|
||||
FloatingFocusManager,
|
||||
} from '@floating-ui/react-dom-interactions';
|
||||
import { mergeRefs } from 'react-merge-refs';
|
||||
|
||||
interface Props {
|
||||
render: (data: { close: () => void; labelId: string; descriptionId: string }) => React.ReactNode;
|
||||
placement?: Placement;
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
const Popover = ({ children, render, placement }: Props) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { x, y, reference, floating, strategy, context } = useFloating({
|
||||
open,
|
||||
onOpenChange: setOpen,
|
||||
middleware: [offset(5), flip(), shift()],
|
||||
placement,
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
const id = useId();
|
||||
const labelId = `${id}-label`;
|
||||
const descriptionId = `${id}-description`;
|
||||
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([
|
||||
useClick(context),
|
||||
useRole(context),
|
||||
useDismiss(context),
|
||||
]);
|
||||
|
||||
// Preserve the consumer's ref
|
||||
const ref = useMemo(() => mergeRefs([reference, (children as any).ref]), [reference, children]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{cloneElement(children, getReferenceProps({ ref, ...children.props }))}
|
||||
{open && (
|
||||
<FloatingFocusManager
|
||||
context={context}
|
||||
modal={false}
|
||||
order={['reference', 'content']}
|
||||
returnFocus={false}
|
||||
>
|
||||
<div
|
||||
ref={floating}
|
||||
className="rounded border shadow"
|
||||
style={{
|
||||
position: strategy,
|
||||
top: y ?? 0,
|
||||
left: x ?? 0,
|
||||
}}
|
||||
aria-labelledby={labelId}
|
||||
aria-describedby={descriptionId}
|
||||
{...getFloatingProps()}
|
||||
>
|
||||
{render({
|
||||
labelId,
|
||||
descriptionId,
|
||||
close: () => {
|
||||
setOpen(false);
|
||||
},
|
||||
})}
|
||||
</div>
|
||||
</FloatingFocusManager>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Popover;
|
||||
1
frontend/app/components/ui/Popover/index.ts
Normal file
1
frontend/app/components/ui/Popover/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './Popover';
|
||||
109
frontend/app/components/ui/Tooltip/FloatingTooltip.tsx
Normal file
109
frontend/app/components/ui/Tooltip/FloatingTooltip.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import * as React from 'react';
|
||||
import { mergeRefs } from 'react-merge-refs';
|
||||
import {
|
||||
useFloating,
|
||||
autoUpdate,
|
||||
offset,
|
||||
flip,
|
||||
shift,
|
||||
useHover,
|
||||
useFocus,
|
||||
useDismiss,
|
||||
useRole,
|
||||
useInteractions,
|
||||
FloatingPortal,
|
||||
} from '@floating-ui/react-dom-interactions';
|
||||
import type { Placement } from '@floating-ui/react-dom-interactions';
|
||||
|
||||
export function useTooltipState({
|
||||
initialOpen = false,
|
||||
placement = 'top',
|
||||
}: {
|
||||
initialOpen?: boolean;
|
||||
placement?: Placement;
|
||||
} = {}) {
|
||||
const [open, setOpen] = React.useState(initialOpen);
|
||||
|
||||
const data = useFloating({
|
||||
placement,
|
||||
open,
|
||||
onOpenChange: setOpen,
|
||||
whileElementsMounted: autoUpdate,
|
||||
middleware: [offset(5), flip(), shift()],
|
||||
});
|
||||
|
||||
const context = data.context;
|
||||
|
||||
const hover = useHover(context, { move: false, restMs: 500 });
|
||||
const focus = useFocus(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const role = useRole(context, { role: 'tooltip' });
|
||||
|
||||
const interactions = useInteractions([hover, focus, dismiss, role]);
|
||||
|
||||
return React.useMemo(
|
||||
() => ({
|
||||
open,
|
||||
setOpen,
|
||||
...interactions,
|
||||
...data,
|
||||
}),
|
||||
[open, setOpen, interactions, data]
|
||||
);
|
||||
}
|
||||
|
||||
type TooltipState = ReturnType<typeof useTooltipState>;
|
||||
|
||||
export const TooltipAnchor = React.forwardRef<
|
||||
HTMLElement,
|
||||
React.HTMLProps<HTMLElement> & {
|
||||
state: TooltipState;
|
||||
asChild?: boolean;
|
||||
}
|
||||
>(function TooltipAnchor({ children, state, asChild = false, ...props }, propRef) {
|
||||
const childrenRef = (children as any).ref;
|
||||
const ref = React.useMemo(
|
||||
() => mergeRefs([state.reference, propRef, childrenRef]),
|
||||
[state.reference, propRef, childrenRef]
|
||||
);
|
||||
|
||||
// `asChild` allows the user to pass any element as the anchor
|
||||
if (asChild && React.isValidElement(children)) {
|
||||
return React.cloneElement(
|
||||
children,
|
||||
state.getReferenceProps({ ref, ...props, ...children.props })
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button ref={ref} {...state.getReferenceProps(props)}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
export const FloatingTooltip = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLProps<HTMLDivElement> & { state: TooltipState }
|
||||
>(function Tooltip({ state, ...props }, propRef) {
|
||||
const ref = React.useMemo(() => mergeRefs([state.floating, propRef]), [state.floating, propRef]);
|
||||
|
||||
return (
|
||||
<FloatingPortal>
|
||||
{state.open && (
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
position: state.strategy,
|
||||
top: state.y ?? 0,
|
||||
left: state.x ?? 0,
|
||||
visibility: state.x == null ? 'hidden' : 'visible',
|
||||
transition: 'opacity 1s',
|
||||
...props.style,
|
||||
}}
|
||||
{...state.getFloatingProps(props)}
|
||||
/>
|
||||
)}
|
||||
</FloatingPortal>
|
||||
);
|
||||
});
|
||||
|
|
@ -1,51 +1,21 @@
|
|||
import React from 'react';
|
||||
import { Popup } from 'UI';
|
||||
import { useTooltipState, TooltipAnchor, FloatingTooltip } from './FloatingTooltip';
|
||||
|
||||
interface Props {
|
||||
timeout: number
|
||||
position: string
|
||||
tooltip: string
|
||||
trigger: React.ReactNode
|
||||
// position: string;
|
||||
tooltip: string;
|
||||
children: any;
|
||||
}
|
||||
function Tooltip(props: Props) {
|
||||
const state = useTooltipState();
|
||||
return (
|
||||
<>
|
||||
<TooltipAnchor state={state}>{props.children}</TooltipAnchor>
|
||||
<FloatingTooltip state={state} className="bg-gray-darkest color-white rounded py-1 px-2 animate-fade">
|
||||
{props.tooltip}
|
||||
</FloatingTooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default class Tooltip extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
timeout: 500,
|
||||
}
|
||||
state = {
|
||||
open: false,
|
||||
}
|
||||
mouseOver = false
|
||||
onMouseEnter = () => {
|
||||
this.mouseOver = true;
|
||||
setTimeout(() => {
|
||||
if (this.mouseOver) this.setState({ open: true });
|
||||
}, this.props.timeout)
|
||||
}
|
||||
onMouseLeave = () => {
|
||||
this.mouseOver = false;
|
||||
this.setState({
|
||||
open: false,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { trigger, tooltip, position } = this.props;
|
||||
const { open } = this.state;
|
||||
return (
|
||||
<Popup
|
||||
open={open}
|
||||
content={tooltip}
|
||||
disabled={!tooltip}
|
||||
position={position}
|
||||
>
|
||||
<span //TODO: no wrap component around
|
||||
onMouseEnter={ this.onMouseEnter }
|
||||
onMouseLeave={ this.onMouseLeave }
|
||||
>
|
||||
{ trigger }
|
||||
</span>
|
||||
</Popup>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Tooltip;
|
||||
|
|
|
|||
47
frontend/app/components/ui/Tooltip/Tooltip.tsx_
Normal file
47
frontend/app/components/ui/Tooltip/Tooltip.tsx_
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react';
|
||||
import { Popup } from 'UI';
|
||||
import { useTooltipState, TooltipAnchor, FloatingTooltip } from './FloatingTooltip';
|
||||
|
||||
interface Props {
|
||||
timeout: number;
|
||||
position: string;
|
||||
tooltip: string;
|
||||
trigger: React.ReactNode;
|
||||
}
|
||||
|
||||
export default class Tooltip extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
timeout: 500,
|
||||
};
|
||||
state = {
|
||||
open: false,
|
||||
};
|
||||
mouseOver = false;
|
||||
onMouseEnter = () => {
|
||||
this.mouseOver = true;
|
||||
setTimeout(() => {
|
||||
if (this.mouseOver) this.setState({ open: true });
|
||||
}, this.props.timeout);
|
||||
};
|
||||
onMouseLeave = () => {
|
||||
this.mouseOver = false;
|
||||
this.setState({
|
||||
open: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { trigger, tooltip, position } = this.props;
|
||||
const { open } = this.state;
|
||||
return (
|
||||
<Popup open={open} content={tooltip} disabled={!tooltip} position={position}>
|
||||
<span //TODO: no wrap component around
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
>
|
||||
{trigger}
|
||||
</span>
|
||||
</Popup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -56,4 +56,5 @@ export { default as Toggler } from './Toggler';
|
|||
export { default as Input } from './Input';
|
||||
export { default as Form } from './Form';
|
||||
export { default as Modal } from './Modal';
|
||||
export { default as Message } from './Message';
|
||||
export { default as Message } from './Message';
|
||||
export { default as Popover } from './Popover';
|
||||
|
|
|
|||
|
|
@ -334,4 +334,17 @@ p {
|
|||
#ccc 2px,
|
||||
#ccc 4px
|
||||
);
|
||||
}
|
||||
|
||||
.animate-fade {
|
||||
animation: fade 0.1s cubic-bezier(0.4, 0, 0.6, 1);
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
"postinstall": "yarn gen:icons && yarn gen:colors"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom-interactions": "^0.10.3",
|
||||
"@sentry/browser": "^5.21.1",
|
||||
"@svg-maps/world": "^1.0.1",
|
||||
"@svgr/webpack": "^6.2.1",
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
"react-highlight": "^0.14.0",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-lazyload": "^3.2.0",
|
||||
"react-merge-refs": "^2.0.1",
|
||||
"react-redux": "^5.1.2",
|
||||
"react-router": "^5.3.3",
|
||||
"react-router-dom": "^5.3.3",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue