UNPKG

3.92 kBTypeScriptView Raw
1import * as React from 'react';
2import * as PropTypes from 'prop-types';
3import { PopoverProps as ReakitPopoverProps } from 'reakit/ts/Popover/Popover';
4
5import { InlineBlock } from '../primitives';
6import Pane from '../Pane';
7import { isFunction } from '../_utils/assert';
8import { Omit } from '../types';
9
10import PopoverContainer, { PopoverContainerProps, PopoverContainerRenderProps } from './PopoverContainer';
11import PopoverClose, { PopoverCloseProps } from './PopoverClose';
12import PopoverPopover, {
13 LocalPopoverPopoverProps,
14 PopoverPopoverProps,
15 popoverPopoverDefaultProps,
16 popoverPopoverPropTypes
17} from './PopoverPopover';
18import PopoverShow, { PopoverShowProps } from './PopoverShow';
19import PopoverHide, { PopoverHideProps } from './PopoverHide';
20import PopoverToggle, { PopoverToggleProps } from './PopoverToggle';
21
22export type LocalPopoverProps = LocalPopoverPopoverProps & {
23 children:
24 | React.ReactNode
25 | (({ use, ...args }: PopoverContainerRenderProps & { use: React.ReactElement<any> }) => React.ReactNode);
26 className?: string;
27 content:
28 | string
29 | React.ReactElement<any>
30 | (({
31 initialFocusRef,
32 ...args
33 }: { initialFocusRef?: React.RefObject<any> } & PopoverContainerRenderProps) => React.ReactNode);
34 isFullWidth?: boolean;
35 /** Displays a cross button in the top right corner of the popover content. */
36 showCloseButton?: boolean;
37};
38export type PopoverProps = Omit<ReakitPopoverProps, 'content'> & LocalPopoverProps;
39export type PopoverComponents = {
40 Popover: React.FunctionComponent<PopoverPopoverProps>;
41 Container: React.FunctionComponent<PopoverContainerProps>;
42 Close: React.FunctionComponent<PopoverCloseProps>;
43 Hide: React.FunctionComponent<PopoverHideProps>;
44 Show: React.FunctionComponent<PopoverShowProps>;
45 Toggle: React.FunctionComponent<PopoverToggleProps>;
46};
47
48export const Popover: React.FunctionComponent<LocalPopoverProps> & PopoverComponents = ({
49 children,
50 content,
51 isFullWidth,
52 showCloseButton,
53 ...props
54}) => (
55 <PopoverContainer>
56 {popover => (
57 <InlineBlock relative width={isFullWidth ? '100%' : undefined}>
58 {isFunction(children)
59 ? /*
60 // @ts-ignore */
61 children({ use: PopoverToggle, ...popover })
62 : children
63 ? React.cloneElement(children as React.ReactElement<any>, { use: PopoverToggle, ...popover })
64 : null}
65 <PopoverPopover elevation="200" {...props} {...popover} use={Pane}>
66 {({ initialFocusRef }) => (
67 <React.Fragment>
68 {showCloseButton && <PopoverClose elementRef={initialFocusRef} {...popover} />}
69 {/* eslint-disable-line */}
70 {typeof content === 'function' ? content({ initialFocusRef, ...popover }) : content}
71 </React.Fragment>
72 )}
73 </PopoverPopover>
74 </InlineBlock>
75 )}
76 </PopoverContainer>
77);
78
79Popover.Popover = PopoverPopover;
80Popover.Container = PopoverContainer;
81Popover.Close = PopoverClose;
82Popover.Hide = PopoverHide;
83Popover.Show = PopoverShow;
84Popover.Toggle = PopoverToggle;
85
86export const popoverPropTypes = {
87 ...popoverPopoverPropTypes,
88 className: PropTypes.string,
89 children: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired as PropTypes.Validator<
90 LocalPopoverProps['children']
91 >,
92 content: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.func]) as PropTypes.Validator<
93 LocalPopoverProps['content']
94 >,
95 isFullWidth: PropTypes.bool,
96 showCloseButton: PropTypes.bool
97};
98Popover.propTypes = popoverPropTypes;
99
100export const popoverDefaultProps = {
101 ...popoverPopoverDefaultProps,
102 children: undefined,
103 className: undefined,
104 isFullWidth: false,
105 showCloseButton: false
106};
107Popover.defaultProps = popoverDefaultProps;
108
109// @ts-ignore
110const C: React.FunctionComponent<PopoverProps> & PopoverComponents = Popover;
111export default C;