Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | import * as React from "react"; import styled from "styled-components"; import { Box } from "rimble-ui"; import { baseColors, colors } from "../../../themes"; const PopupBox = styled(Box)` display: none; position: absolute; right: ${(props) => props.popupRightPos}px; top: ${(props) => props.popupTopPos}; background: ${baseColors.white}; border: 1px solid ${colors.lightGray}; border-radius: 4px; min-width: 180px; font-size: 14px; &:before { content: ""; position: absolute; right: ${(props) => props.arrowOffset - 1}px; top: -10px; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 10px solid ${colors.lightGray}; } &:after { content: ""; position: absolute; right: ${(props) => props.arrowOffset}px; top: -9px; border-left: 9px solid transparent; border-right: 9px solid transparent; border-bottom: 9px solid ${baseColors.white}; } `; const PopupWrap = styled(Box)` position: relative; z-index: 1; &:hover ${PopupBox}.hoverable, ${PopupBox}.open { display: block; } `; export const PopupGroup = styled.div` padding: 12px 16px; border-bottom: 1px solid ${colors.lightGray}; &:last-child { border-bottom: 0; } & > a { display: block; margin-bottom: 12px; text-decoration: none; cursor: pointer; color: ${baseColors.black}; &:hover { color: ${baseColors.blurple}; } &.selected { cursor: default; font-weight: bold; color: ${baseColors.black}; } } & > a:last-child { margin-bottom: 0; } `; export interface PopupProps { popupContents: JSX.Element; /** Default is trigger on hover. */ triggerOnClick?: boolean; remainOpenOnClick?: boolean; rimbleProps?: { [prop: string]: any }; popupRimbleProps?: { [prop: string]: any }; /** CSS "top" property of popup, default "calc(100% + 10px)". **/ popupTopPos?: string; /** CSS "right" property of popup in px, default 0. **/ popupRightPos?: number; /** Offset of arrow from right edge of popup, in px. **/ arrowOffset?: number; } export const Popup: React.FunctionComponent<PopupProps> = (props) => { const node = React.useRef() as React.MutableRefObject<HTMLDivElement>; const [isOpen, setIsOpen] = React.useState(false); const onClickOutside = React.useMemo( () => (e: any) => { if (!isOpen || node.current.contains(e.target)) { return; } setIsOpen(false); }, [node, isOpen], ); React.useEffect(() => { if (props.triggerOnClick) { document.addEventListener("mousedown", onClickOutside); return () => { document.removeEventListener("mousedown", onClickOutside); }; } }, [onClickOutside, props.triggerOnClick]); return ( <PopupWrap ref={node} {...props.rimbleProps} onClick={() => setIsOpen(!isOpen)}> {props.children} <PopupBox className={!props.triggerOnClick ? "hoverable" : isOpen ? "open" : undefined} arrowOffset={props.arrowOffset || 10} popupTopPos={props.popupTopPos || "calc(100% + 10px)"} popupRightPos={props.popupRightPos || 0} onClick={props.remainOpenOnClick && ((e: Event) => e.stopPropagation())} {...props.popupRimbleProps} > {props.popupContents} </PopupBox> </PopupWrap> ); }; |