kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
				
				
				
			First pass at Hoverable component
							rodzic
							
								
									69de2aad55
								
							
						
					
					
						commit
						1742236074
					
				| 
						 | 
				
			
			@ -19,7 +19,7 @@ import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
 | 
			
		|||
 | 
			
		||||
import { openModal } from '../actions/modals';
 | 
			
		||||
 | 
			
		||||
import { IconButton, Text } from './ui';
 | 
			
		||||
import { IconButton, Text, Hoverable } from './ui';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +547,6 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
			
		|||
 | 
			
		||||
  render() {
 | 
			
		||||
    const { status, intl, allowedEmoji, emojiSelectorFocused, handleEmojiSelectorUnfocus, features, me } = this.props;
 | 
			
		||||
    const { emojiSelectorVisible } = this.state;
 | 
			
		||||
 | 
			
		||||
    const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -664,18 +663,17 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
			
		|||
          {reblogCount !== 0 && <Text size='xs' theme='muted' role='presentation' onClick={this.handleOpenReblogsModal}>{reblogCount}</Text>}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
        <Hoverable
 | 
			
		||||
          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'
 | 
			
		||||
          onMouseEnter={this.handleLikeButtonHover}
 | 
			
		||||
          onMouseLeave={this.handleLikeButtonLeave}
 | 
			
		||||
          component={(
 | 
			
		||||
            <EmojiSelector
 | 
			
		||||
              onReact={this.handleReact}
 | 
			
		||||
              focused={emojiSelectorFocused}
 | 
			
		||||
              onUnfocus={handleEmojiSelectorUnfocus}
 | 
			
		||||
            />
 | 
			
		||||
          )}
 | 
			
		||||
        >
 | 
			
		||||
          <EmojiSelector
 | 
			
		||||
            onReact={this.handleReact}
 | 
			
		||||
            visible={features.emojiReacts && emojiSelectorVisible}
 | 
			
		||||
            focused={emojiSelectorFocused}
 | 
			
		||||
            onUnfocus={handleEmojiSelectorUnfocus}
 | 
			
		||||
          />
 | 
			
		||||
          <IconButton
 | 
			
		||||
            className={classNames({
 | 
			
		||||
              'text-gray-400 hover:text-gray-600 dark:hover:text-white': !meEmojiReact,
 | 
			
		||||
| 
						 | 
				
			
			@ -698,7 +696,7 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
			
		|||
              <span className='detailed-status__link'>{emojiReactCount}</span>
 | 
			
		||||
            )
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
        </Hoverable>
 | 
			
		||||
 | 
			
		||||
        {shareButton}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
import Portal from '@reach/portal';
 | 
			
		||||
import React, { useState, useRef } from 'react';
 | 
			
		||||
 | 
			
		||||
interface IHoverable {
 | 
			
		||||
  component: React.Component,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Wrapper to render a given component when hovered */
 | 
			
		||||
const Hoverable: React.FC<IHoverable> = ({
 | 
			
		||||
  component,
 | 
			
		||||
  children,
 | 
			
		||||
}): JSX.Element => {
 | 
			
		||||
 | 
			
		||||
  const [portalActive, setPortalActive] = useState(false);
 | 
			
		||||
  const ref = useRef<HTMLDivElement>(null);
 | 
			
		||||
 | 
			
		||||
  const handleMouseEnter = () => {
 | 
			
		||||
    setPortalActive(true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleMouseLeave = () => {
 | 
			
		||||
    setPortalActive(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const setPortalPosition = (): React.CSSProperties => {
 | 
			
		||||
    if (!ref.current) return {};
 | 
			
		||||
 | 
			
		||||
    const { top, height, left, width } = ref.current.getBoundingClientRect();
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      top: top + height,
 | 
			
		||||
      left,
 | 
			
		||||
      width,
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      onMouseEnter={handleMouseEnter}
 | 
			
		||||
      onMouseLeave={handleMouseLeave}
 | 
			
		||||
      ref={ref}
 | 
			
		||||
    >
 | 
			
		||||
      {children}
 | 
			
		||||
      {portalActive && <Portal><div className='fixed' style={setPortalPosition()}>{component}</div></Portal>}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Hoverable;
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ export { default as EmojiSelector } from './emoji-selector/emoji-selector';
 | 
			
		|||
export { default as Form } from './form/form';
 | 
			
		||||
export { default as FormActions } from './form-actions/form-actions';
 | 
			
		||||
export { default as FormGroup } from './form-group/form-group';
 | 
			
		||||
export { default as Hoverable } from './hoverable/hoverable';
 | 
			
		||||
export { default as HStack } from './hstack/hstack';
 | 
			
		||||
export { default as Icon } from './icon/icon';
 | 
			
		||||
export { default as IconButton } from './icon-button/icon-button';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue