Skip to content

Commit

Permalink
Update Popover with center alignments and Justify.Fit (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
jetpacmonkey authored Mar 26, 2020
1 parent ebc057e commit 4376034
Show file tree
Hide file tree
Showing 15 changed files with 1,879 additions and 626 deletions.
20 changes: 10 additions & 10 deletions packages/popover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ import Popover from '@leafygreen-ui/popover';

The popover component will be automatically positioned relative to its nearest parent. If `usePortal` is set to `false`, then it will be positioned relative to its nearest ancestor with the CSS property: `position: absolute | relative | fixed`.

| Prop | Type | Description | Default |
| ------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `active` | `boolean` | Determines whether the Popover is active or inactive | `false` |
| `align` | `'top'`, `'bottom'`, `'left'`, `'right'` | A string that determines the alignment of the popover relative to the `refEl`. | `'bottom'` |
| `justify` | `'start'`, `'middle'`, `'end'` | A string that determines the justification of the popover relative to the `refEl`. Justification will be defined relative to the `align` prop | `'start'` |
| `children` | `node` | Content that will appear inside of the `<Popver />` component | |
| `usePortal` | `boolean` | Will position Popover's children relative to its parent without using a Portal, if `usePortal` is set to false. NOTE: The parent element should be CSS position `relative`, `fixed`, or `absolute` if using this option. | `true` |
| `spacing` | `number` | Specifies the amount of spacing (in pixels) between the trigger element and the content element. | `10` |
| `className` | `string` | Classname to apply to popover-content container | |
| `adjustOnMutation` | `boolean` | Should the Popover auto adjust its content when the DOM changes (using MutationObserver). | `false` |
| Prop | Type | Description | Default |
| ------------------ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `active` | `boolean` | Determines whether the Popover is active or inactive | `false` |
| `align` | `'top'`, `'bottom'`, `'left'`, `'right'`, `'center-horizontal'`, `'center-vertical'` | A string that determines the alignment of the popover relative to the `refEl`. | `'bottom'` |
| `justify` | `'start'`, `'middle'`, `'end'`, `'fit'` | A string that determines the justification of the popover relative to the `refEl`. Justification will be defined relative to the `align` prop | `'start'` |
| `children` | `node` | Content that will appear inside of the `<Popver />` component | |
| `usePortal` | `boolean` | Will position Popover's children relative to its parent without using a Portal, if `usePortal` is set to false. NOTE: The parent element should be CSS position `relative`, `fixed`, or `absolute` if using this option. | `true` |
| `spacing` | `number` | Specifies the amount of spacing (in pixels) between the trigger element and the content element. | `10` |
| `className` | `string` | Classname to apply to popover-content container | |
| `adjustOnMutation` | `boolean` | Should the Popover auto adjust its content when the DOM changes (using MutationObserver). | `false` |

## Advanced Use Case

Expand Down
4 changes: 3 additions & 1 deletion packages/popover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
"@leafygreen-ui/hooks": "^2.0.0",
"@leafygreen-ui/lib": "^4.2.0",
"@leafygreen-ui/portal": "^2.0.0",
"@leafygreen-ui/theme": "^2.0.0",
"lodash": "^4.17.11"
},
"devDependencies": {
"@leafygreen-ui/palette": "^2.0.0"
},
"gitHead": "dd71a2d404218ccec2e657df9c0263dc1c15b9e0"
}
14 changes: 10 additions & 4 deletions packages/popover/src/Popover.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ import React, { useState, useRef } from 'react';
import { storiesOf } from '@storybook/react';
import { select, boolean, number, text } from '@storybook/addon-knobs';
import { css, cx } from '@leafygreen-ui/emotion';
import { colors } from '@leafygreen-ui/theme';
import { uiColors } from '@leafygreen-ui/palette';

import Popover, { Align, Justify } from '.';

const containerStyle = css`
position: absolute;
min-height: 50px;
appearance: none;
box-shadow: 0 0 4px #000;
background-color: ${uiColors.gray.light1};
`;

const popoverStyle = css`
border: 1px solid ${colors.gray[5]};
border: 1px solid ${uiColors.gray.light1};
text-align: center;
padding: 20px 20px;
background-color: ${colors.mongodb.white};
padding: 20px;
background-color: ${uiColors.white};
max-height: 100%;
overflow: hidden;
`;

const referenceElPositions = {
Expand Down
52 changes: 47 additions & 5 deletions packages/popover/src/Popover.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import React, { useMemo, Fragment } from 'react';
import React, {
useMemo,
Fragment,
useState,
useLayoutEffect,
useRef,
useEffect,
} from 'react';
import PropTypes from 'prop-types';
import { Transition } from 'react-transition-group';
import Portal from '@leafygreen-ui/portal';
Expand Down Expand Up @@ -41,8 +48,8 @@ const mutationOptions = {
* @param props.children Content to appear inside of Popover container.
* @param props.active Boolean to describe whether or not Popover is active.
* @param props.className Classname applied to Popover container.
* @param props.align Alignment of Popover component relative to another element: `top`, `bottom`, `left`, `right`.
* @param props.justify Justification of Popover component relative to another element: `start`, `middle`, `end`.
* @param props.align Alignment of Popover component relative to another element: `top`, `bottom`, `left`, `right`, `center-horizontal`, `center-vertical`.
* @param props.justify Justification of Popover component relative to another element: `start`, `middle`, `end`, `fit`.
* @param props.refEl Reference element that Popover component should be positioned against.
* @param props.usePortal Boolean to describe if content should be portaled to end of DOM, or appear in DOM tree.
* @param props.adjustOnMutation Should the Popover auto adjust its content when the DOM changes (using MutationObserver).
Expand All @@ -61,6 +68,7 @@ function Popover({
}: PopoverProps) {
const [placeholderNode, setPlaceholderNode] = useElementNode();
const [contentNode, setContentNode] = useElementNode();
const [forceUpdateCounter, setForceUpdateCounter] = useState(0);

let referenceElement: HTMLElement | null = null;

Expand Down Expand Up @@ -97,6 +105,7 @@ function Popover({
active,
align,
justify,
forceUpdateCounter,
]);

const contentElPos = useMemo(() => getElementPosition(contentNode), [
Expand All @@ -106,9 +115,38 @@ function Popover({
active,
align,
justify,
forceUpdateCounter,
]);

const { alignment, justification, positionCSS } = calculatePosition({
const prevJustifyRef = useRef<Justify>();
const prevAlignRef = useRef<Align>();
const prevJustify = prevJustifyRef.current;
const prevAlign = prevAlignRef.current;

useEffect(() => {
prevJustifyRef.current = justify;
prevAlignRef.current = align;
});

useLayoutEffect(() => {
// justify={Justify.Fit} can cause the content's height/width to change
// If we're switching to/from Fit, force an extra pass to make sure the popover is positioned correctly.
// Also if we're switching between alignments and have Justify.Fit, it may switch between setting the width and
// setting the height, so force an update in that case as well.
if (
(prevJustify !== justify &&
(justify === Justify.Fit || prevJustify === Justify.Fit)) ||
(prevAlign !== align && justify === Justify.Fit)
) {
setForceUpdateCounter(n => n + 1);
}
});

const {
align: windowSafeAlign,
justify: windowSafeJustify,
positionCSS,
} = calculatePosition({
useRelativePositioning: !usePortal,
spacing,
align,
Expand All @@ -132,7 +170,11 @@ function Popover({
}

if (typeof children === 'function') {
return children({ alignment, justification, referenceElPos });
return children({
align: windowSafeAlign,
justify: windowSafeJustify,
referenceElPos,
});
}

return children;
Expand Down
10 changes: 2 additions & 8 deletions packages/popover/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import Popover from './Popover';
import {
Align,
Justify,
Justification,
ElementPosition,
PopoverProps,
} from './types';
import { Align, Justify, ElementPosition, PopoverProps } from './types';

export default Popover;
export { Align, Justify, Justification, ElementPosition, PopoverProps };
export { Align, Justify, ElementPosition, PopoverProps };
Loading

0 comments on commit 4376034

Please sign in to comment.