Hoverable component: we've come full circle
This commit is contained in:
parent
1742236074
commit
6c8bc3f329
3 changed files with 54 additions and 36 deletions
|
@ -663,30 +663,34 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
{reblogCount !== 0 && <Text size='xs' theme='muted' role='presentation' onClick={this.handleOpenReblogsModal}>{reblogCount}</Text>}
|
{reblogCount !== 0 && <Text size='xs' theme='muted' role='presentation' onClick={this.handleOpenReblogsModal}>{reblogCount}</Text>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Hoverable
|
<div
|
||||||
ref={this.setRef}
|
ref={this.setRef}
|
||||||
className='flex relative items-center space-x-0.5 p-1 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500'
|
className='flex relative items-center space-x-0.5 p-1 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500'
|
||||||
component={(
|
|
||||||
<EmojiSelector
|
|
||||||
onReact={this.handleReact}
|
|
||||||
focused={emojiSelectorFocused}
|
|
||||||
onUnfocus={handleEmojiSelectorUnfocus}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<IconButton
|
<Hoverable
|
||||||
className={classNames({
|
component={(
|
||||||
'text-gray-400 hover:text-gray-600 dark:hover:text-white': !meEmojiReact,
|
<EmojiSelector
|
||||||
'text-accent-300 hover:text-accent-300': Boolean(meEmojiReact),
|
onReact={this.handleReact}
|
||||||
})}
|
focused={emojiSelectorFocused}
|
||||||
title={meEmojiTitle}
|
onUnfocus={handleEmojiSelectorUnfocus}
|
||||||
src={require('@tabler/icons/icons/heart.svg')}
|
/>
|
||||||
iconClassName={classNames({
|
)}
|
||||||
'fill-accent-300': Boolean(meEmojiReact),
|
>
|
||||||
})}
|
<IconButton
|
||||||
// emoji={meEmojiReact}
|
className={classNames({
|
||||||
onClick={this.handleLikeButtonClick}
|
'text-gray-400 hover:text-gray-600 dark:hover:text-white': !meEmojiReact,
|
||||||
/>
|
'text-accent-300 hover:text-accent-300': Boolean(meEmojiReact),
|
||||||
|
})}
|
||||||
|
title={meEmojiTitle}
|
||||||
|
src={require('@tabler/icons/icons/heart.svg')}
|
||||||
|
iconClassName={classNames({
|
||||||
|
'fill-accent-300': Boolean(meEmojiReact),
|
||||||
|
})}
|
||||||
|
// emoji={meEmojiReact}
|
||||||
|
onClick={this.handleLikeButtonClick}
|
||||||
|
/>
|
||||||
|
</Hoverable>
|
||||||
|
|
||||||
{emojiReactCount !== 0 && (
|
{emojiReactCount !== 0 && (
|
||||||
(features.exposableReactions && !features.emojiReacts) ? (
|
(features.exposableReactions && !features.emojiReacts) ? (
|
||||||
<Link to={`/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}/likes`} className='pointer-events-none'>
|
<Link to={`/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}/likes`} className='pointer-events-none'>
|
||||||
|
@ -696,7 +700,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
<span className='detailed-status__link'>{emojiReactCount}</span>
|
<span className='detailed-status__link'>{emojiReactCount}</span>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</Hoverable>
|
</div>
|
||||||
|
|
||||||
{shareButton}
|
{shareButton}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ const EmojiSelector: React.FC<IEmojiSelector> = ({ emojis, onReact, visible = fa
|
||||||
return (
|
return (
|
||||||
<HStack
|
<HStack
|
||||||
space={2}
|
space={2}
|
||||||
className={classNames('bg-white dark:bg-slate-900 p-3 rounded-full shadow-md w-max')}
|
className={classNames('bg-white dark:bg-slate-900 p-3 rounded-full shadow-md z-[999] w-max')}
|
||||||
>
|
>
|
||||||
{emojis.map((emoji, i) => (
|
{emojis.map((emoji, i) => (
|
||||||
<EmojiButton
|
<EmojiButton
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Portal from '@reach/portal';
|
import classNames from 'classnames';
|
||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { usePopper } from 'react-popper';
|
||||||
|
|
||||||
interface IHoverable {
|
interface IHoverable {
|
||||||
component: React.Component,
|
component: React.Component,
|
||||||
|
@ -12,7 +13,9 @@ const Hoverable: React.FC<IHoverable> = ({
|
||||||
}): JSX.Element => {
|
}): JSX.Element => {
|
||||||
|
|
||||||
const [portalActive, setPortalActive] = useState(false);
|
const [portalActive, setPortalActive] = useState(false);
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const popperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = () => {
|
||||||
setPortalActive(true);
|
setPortalActive(true);
|
||||||
|
@ -22,17 +25,18 @@ const Hoverable: React.FC<IHoverable> = ({
|
||||||
setPortalActive(false);
|
setPortalActive(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPortalPosition = (): React.CSSProperties => {
|
const { styles, attributes } = usePopper(ref.current, popperRef.current, {
|
||||||
if (!ref.current) return {};
|
placement: 'top-start',
|
||||||
|
strategy: 'fixed',
|
||||||
const { top, height, left, width } = ref.current.getBoundingClientRect();
|
modifiers: [
|
||||||
|
{
|
||||||
return {
|
name: 'offset',
|
||||||
top: top + height,
|
options: {
|
||||||
left,
|
offset: [-10, 0],
|
||||||
width,
|
},
|
||||||
};
|
},
|
||||||
};
|
],
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -41,7 +45,17 @@ const Hoverable: React.FC<IHoverable> = ({
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
{portalActive && <Portal><div className='fixed' style={setPortalPosition()}>{component}</div></Portal>}
|
|
||||||
|
<div
|
||||||
|
className={classNames('fixed z-50 transition-opacity duration-100', {
|
||||||
|
'opacity-0 pointer-events-none': !portalActive,
|
||||||
|
})}
|
||||||
|
ref={popperRef}
|
||||||
|
style={styles.popper}
|
||||||
|
{...attributes.popper}
|
||||||
|
>
|
||||||
|
{component}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue