Skip to content

Instantly share code, notes, and snippets.

@reneviering
Created May 26, 2019 18:36
Show Gist options
  • Save reneviering/96d89716c445d641ccf6ca8217b42787 to your computer and use it in GitHub Desktop.
Save reneviering/96d89716c445d641ccf6ca8217b42787 to your computer and use it in GitHub Desktop.
import React, { useEffect, useRef } from 'react';
import { useBooleanState } from './useBooleanState';
import { PopoverTrigger } from './PopoverTrigger';
import { PopoverContent } from './PopoverContent';
import { PopoverContext } from './PopoverContext';
const ESC_KEY = 27;
const Popover = ({ children }) => {
const [isOpen, closePopover, togglePopover] = useBooleanState(false);
const containerRef = useRef(null);
useEffect(() => {
const handleKeydown = event => {
if (event.keyCode === ESC_KEY) {
closePopover();
}
};
const handleClick = event => {
const didClickHappenInsidePopover =
containerRef && containerRef.current.contains(event.target);
if (!didClickHappenInsidePopover) {
closePopover();
}
};
document.addEventListener('keydown', handleKeydown);
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('keydown', handleKeydown);
document.removeEventListener('click', handleClick);
};
}, [closePopover]);
return (
<PopoverContext.Provider value={{ isOpen, closePopover, togglePopover }}>
<div ref={containerRef}>{children}</div>
</PopoverContext.Provider>
);
};
const PopoverExample = () => {
return (
<Popover>
<PopoverTrigger>
<button>Filter</button>
</PopoverTrigger>
<PopoverContent>
<div>
<button>asdflkjasdlfkj</button>
</div>
</PopoverContent>
</Popover>
);
};
export { PopoverExample as Popover };
import React, { useContext } from 'react';
import { PopoverContext } from '../PopoverContext';
export const PopoverContent = ({ children }) => {
const popoverContext = useContext(PopoverContext);
if (!popoverContext) {
throw new Error('Do not use PopoverContent without Popover Provider');
}
const { isOpen } = popoverContext;
if (!isOpen) return null;
return <div>{children}</div>;
};
import React, { useContext } from 'react';
import { PopoverContext } from '../PopoverContext';
export const PopoverTrigger = ({ children }) => {
const popoverContext = useContext(PopoverContext);
if (!popoverContext) {
throw new Error('Do not use PopoverContent without Popover Provider');
}
const { togglePopover } = popoverContext;
return <div onClick={togglePopover}>{children}</div>;
};
import { useState } from 'react';
/* Just a little hooks helper for boolean state */
export const useBooleanState = defaultValue => {
const [state, setState] = useState(defaultValue);
const toggleState = () => {
const newState = !state;
setState(newState);
};
const deactivate = newState => setState(false);
return [state, deactivate, toggleState];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment