Skip to content

Commit

Permalink
fix: themable popup arrow
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Oct 26, 2020
1 parent 73c79d3 commit ca4f734
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 59 deletions.
12 changes: 8 additions & 4 deletions ui/components/src/Popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { FC } from 'react';
import TooltipTrigger from 'react-popper-tooltip';
import { TooltipTriggerProps } from 'react-popper-tooltip/dist/types';
import { jsx, Box } from 'theme-ui';
import { jsx, Box, SxStyleProp } from 'theme-ui';
import { Arrow, Wrapper } from './PopoverUtils';

export interface PopoverOwnProps {
Expand Down Expand Up @@ -52,15 +52,19 @@ export const Popover: FC<PopoverProps> = ({
borderColor={borderColor}
hidden={hidden}
ref={tooltipRef as any}
{...containerProps}
sx={{ backgroundColor: 'background' }}
sx={{
...(containerProps.style as SxStyleProp),
backgroundColor: 'background',
}}
>
{arrowVisible && (
<Arrow
placement={placement}
borderColor={borderColor}
ref={arrowRef as any}
{...getArrowProps()}
sx={{
...(getArrowProps().style as SxStyleProp),
}}
/>
)}
{typeof tooltip === 'function' ? tooltip(tooltipProps) : tooltip}
Expand Down
139 changes: 84 additions & 55 deletions ui/components/src/Popover/PopoverUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import styled from '@emotion/styled';
/** @jsx jsx */
import { FC, forwardRef, Ref } from 'react';
import { jsx, Box, BoxProps } from 'theme-ui';

const SPACING = 8;

Expand All @@ -9,68 +11,95 @@ const match = (
fallback: number | string = 0,
) => (actual.split('-')[0] === requested ? value : fallback);

export const Arrow = styled.div<{ placement: string; borderColor: string }>(
({ placement, borderColor }) => ({
position: 'absolute',
borderStyle: 'solid',
background: 'white',
marginBottom: `${match('top', placement, '0', SPACING)}px`,
marginTop: `${match('bottom', placement, '0', SPACING)}px`,
marginRight: `${match('left', placement, '0', SPACING)}px`,
marginLeft: `${match('right', placement, '0', SPACING)}px`,
const matchPx = (
requested: string,
actual: string,
value: number | string,
fallback: number | string = 0,
) => {
const result = match(requested, actual, value, fallback);
return typeof result === 'number' ? `${result}px` : result;
};

bottom: `${match('top', placement, SPACING * -1, 'auto')}px`,
top: `${match('bottom', placement, SPACING * -1, 'auto')}px`,
right: `${match('left', placement, SPACING * -1, 'auto')}px`,
left: `${match('right', placement, SPACING * -1, 'auto')}px`,
export const Arrow: FC<{
placement: string;
borderColor: string;
} & BoxProps> = forwardRef(
({ placement, borderColor, ...rest }, ref: Ref<HTMLDivElement>) => (
<Box
sx={{
position: 'absolute',
borderStyle: 'solid',
background: 'background',
marginBottom: matchPx('top', placement, 0, SPACING),
marginTop: matchPx('bottom', placement, 0, SPACING),
marginRight: matchPx('left', placement, 0, SPACING),
marginLeft: matchPx('right', placement, 0, SPACING),

borderBottomWidth: `${match('top', placement, '0', SPACING)}px`,
borderTopWidth: `${match('bottom', placement, '0', SPACING)}px`,
borderRightWidth: `${match('left', placement, '0', SPACING)}px`,
borderLeftWidth: `${match('right', placement, '0', SPACING)}px`,
bottom: matchPx('top', placement, SPACING * -1, 'auto'),
top: matchPx('bottom', placement, SPACING * -1, 'auto'),
right: matchPx('left', placement, SPACING * -1, 'auto'),
left: matchPx('right', placement, SPACING * -1, 'auto'),

borderTopColor: match(
'top',
placement,
borderColor,
'transparent',
) as string,
borderBottomColor: match(
'bottom',
placement,
borderColor,
'transparent',
) as string,
borderLeftColor: match(
'left',
placement,
borderColor,
'transparent',
) as string,
borderRightColor: match(
'right',
placement,
borderColor,
'transparent',
) as string,
}),
borderBottomWidth: matchPx('top', placement, 0, SPACING),
borderTopWidth: matchPx('bottom', placement, 0, SPACING),
borderRightWidth: matchPx('left', placement, 0, SPACING),
borderLeftWidth: matchPx('right', placement, 0, SPACING),

borderTopColor: match(
'top',
placement,
borderColor,
'transparent',
) as string,
borderBottomColor: match(
'bottom',
placement,
borderColor,
'transparent',
) as string,
borderLeftColor: match(
'left',
placement,
borderColor,
'transparent',
) as string,
borderRightColor: match(
'right',
placement,
borderColor,
'transparent',
) as string,
}}
ref={ref}
{...rest}
/>
),
);

export const Wrapper = styled.div<{
export const Wrapper: FC<{
placement: string;
borderColor: string;
hidden: boolean;
}>(({ placement, borderColor, hidden }) => ({
display: hidden ? 'none' : 'inline-block',
background: 'white',
marginTop: `${match('bottom', placement, SPACING + 2, 0)}px`,
marginLeft: `${match('right', placement, SPACING + 2, 0)}px`,
marginRight: `${match('left', placement, SPACING + 2, 0)}px`,
filter: `
} & BoxProps> = forwardRef(
({ placement, borderColor, hidden, ...rest }, ref: Ref<HTMLDivElement>) => (
<Box
sx={{
display: hidden ? 'none' : 'inline-block',
background: 'background',
marginTop: matchPx('bottom', placement, SPACING + 2, 0),
marginLeft: matchPx('right', placement, SPACING + 2, 0),
marginRight: matchPx('left', placement, SPACING + 2, 0),
filter: `
drop-shadow(0px 5px 5px rgba(0,0,0,0.05))
drop-shadow(0 1px 3px rgba(0,0,0,0.1))
`,
borderRadius: 8,
fontSize: 12,
border: `1px solid ${borderColor}`,
}));
borderRadius: 8,
fontSize: 12,
border: `1px solid ${borderColor}`,
}}
ref={ref}
{...rest}
/>
),
);

0 comments on commit ca4f734

Please sign in to comment.