diff --git a/packages/patternfly-4/react-charts/package.json b/packages/patternfly-4/react-charts/package.json index 10c03d7ea2a..b5d8edfb280 100644 --- a/packages/patternfly-4/react-charts/package.json +++ b/packages/patternfly-4/react-charts/package.json @@ -51,4 +51,4 @@ "glob": "^7.1.2", "npmlog": "^4.1.2" } -} +} \ No newline at end of file diff --git a/packages/patternfly-4/react-core/package.json b/packages/patternfly-4/react-core/package.json index 61d89709586..8d3c719ed96 100644 --- a/packages/patternfly-4/react-core/package.json +++ b/packages/patternfly-4/react-core/package.json @@ -53,4 +53,4 @@ "glob": "^7.1.2", "npmlog": "^4.1.2" } -} +} \ No newline at end of file diff --git a/packages/patternfly-4/react-core/src/components/Popover/Popover.d.ts b/packages/patternfly-4/react-core/src/components/Popover/Popover.d.ts new file mode 100644 index 00000000000..83329729270 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/Popover.d.ts @@ -0,0 +1,13 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; +import { OneOf } from '@patternfly/react-core/src/typeUtils'; + +export interface PopoverProps extends HTMLProps { + position: OneOf; + children: ReactNode; + header: string; + onClose?(event: React.SyntheticEvent): void +} + +declare const Popover: SFC; + +export default Popover; diff --git a/packages/patternfly-4/react-core/src/components/Popover/Popover.docs.txt b/packages/patternfly-4/react-core/src/components/Popover/Popover.docs.txt new file mode 100644 index 00000000000..2180a4673e4 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/Popover.docs.txt @@ -0,0 +1,30 @@ +import { + PopoverPosition, + PopoverDialog, + PopoverArrow, + PopoverContent, + PopoverCloseButton, + PopoverHeader, + PopoverBody +} from '@patternfly/react-core'; +import SimplePopover from './examples/SimplePopover'; +import HeadlessPopover from './examples/HeadlessPopover'; + +export default { + title: 'Popover', + components: { + PopoverDialog, + PopoverArrow, + PopoverContent, + PopoverCloseButton, + PopoverHeader, + PopoverBody + }, + enumValues: { + 'Object.values(PopoverPosition)': Object.values(PopoverPosition) + }, + examples: [ + { component: SimplePopover, title: 'Closable Popover Position' }, + { component: HeadlessPopover, title: 'Headless Popover' } + ] +}; diff --git a/packages/patternfly-4/react-core/src/components/Popover/Popover.js b/packages/patternfly-4/react-core/src/components/Popover/Popover.js new file mode 100644 index 00000000000..ed0e087c539 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/Popover.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css, getModifier } from '@patternfly/react-styles'; +import PopoverDialog, { PopoverPosition } from './PopoverDialog'; +import PopoverArrow from './PopoverArrow'; +import PopoverContent from './PopoverContent'; +import PopoverHeader from './PopoverHeader'; +import PopoverBody from './PopoverBody'; +import PopoverCloseButton from './PopoverCloseButton'; + +const Popover = ({ position, header, onClose, children, className }) => ( + + + + + {header} + {children} + + +); + +const propTypes = { + /** Popover position */ + position: PropTypes.oneOf(Object.values(PopoverPosition)), + /** Popover header text */ + header: PropTypes.string.isRequired, + /** Popover body text */ + children: PropTypes.string.isRequired, + /** Popover onClose function */ + onClose: PropTypes.func +}; + +Popover.propTypes = propTypes; +Popover.defaultProps = { + onClose: () => {}, + position: 'top' +}; + +export default Popover; diff --git a/packages/patternfly-4/react-core/src/components/Popover/Popover.test.js b/packages/patternfly-4/react-core/src/components/Popover/Popover.test.js new file mode 100644 index 00000000000..ae7acfe265f --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/Popover.test.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { Popover } from './index'; +import { Button } from '@patternfly/react-core'; + +test('popover renders close-button, header and body', () => { + const view = mount(popover body); + expect(view).toMatchSnapshot(); +}); + +test('popover is calling onClose when clicking the close button', () => { + const onClose = jest.fn(); + const view = mount( + + popover body + + ); + expect(onClose.mock.calls).toHaveLength(0); + view.find(Button).simulate('click'); + expect(onClose.mock.calls).toHaveLength(1); +}); diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.d.ts new file mode 100644 index 00000000000..2d3b4122685 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.d.ts @@ -0,0 +1,8 @@ +import { SFC, HTMLProps } from 'react'; + +export interface PopoverArrowProps extends HTMLProps { +} + +declare const PopoverArrow: SFC; + +export default PopoverArrow; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.js new file mode 100644 index 00000000000..28521f1a22e --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverArrow.js @@ -0,0 +1,17 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css } from '@patternfly/react-styles'; + +const PopoverArrow = ({ className, ...props }) =>
; + +PopoverArrow.propTypes = { + /** Popover arrow additional className */ + className: PropTypes.string +}; + +PopoverArrow.defaultProps = { + className: null +}; + +export default PopoverArrow; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.d.ts new file mode 100644 index 00000000000..8fe7613d9d5 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.d.ts @@ -0,0 +1,10 @@ +import { SFC, ReactNode } from 'react'; + +export interface PopoverBodyProps { + id: string + children: ReactNode; +} + +declare const PopoverBody: SFC; + +export default PopoverBody; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.js new file mode 100644 index 00000000000..75acebfb115 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverBody.js @@ -0,0 +1,19 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css } from '@patternfly/react-styles'; + +const PopoverBody = ({ children, id }) => ( +
+ {children} +
+); + +PopoverBody.propTypes = { + /** PopoverBody id */ + id: PropTypes.string.isRequired, + /** PopoverBody content */ + children: PropTypes.node.isRequired +}; + +export default PopoverBody; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.d.ts new file mode 100644 index 00000000000..0254e6ba7a1 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.d.ts @@ -0,0 +1,9 @@ +import { SFC } from 'react'; + +export interface PopoverCloseButtonProps { + onClose(event: React.SyntheticEvent): void +} + +declare const PopoverCloseButton : SFC; + +export default PopoverCloseButton; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.js new file mode 100644 index 00000000000..f6b19762232 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverCloseButton.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css } from '@patternfly/react-styles'; +import { Button } from '@patternfly/react-core'; +import { TimesIcon } from '@patternfly/react-icons'; + +const PopoverCloseButton = ({ onClose }) => ( +
+ +
+); + +PopoverCloseButton.propTypes = { + /** PopoverCloseButton onClose function */ + onClose: PropTypes.func.isRequired +}; + +export default PopoverCloseButton; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.d.ts new file mode 100644 index 00000000000..bdc166a09e2 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.d.ts @@ -0,0 +1,8 @@ +import { SFC, HTMLProps } from 'react'; + +export interface PopoverContentProps extends HTMLProps { +} + +declare const PopoverContent: SFC; + +export default PopoverContent; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.js new file mode 100644 index 00000000000..ef69a03c23c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverContent.js @@ -0,0 +1,23 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css } from '@patternfly/react-styles'; + +const PopoverContent = ({ className, children, ...props }) => ( +
+ {children} +
+); + +PopoverContent.propTypes = { + /** PopoverContent additional class */ + className: PropTypes.string, + /** PopoverContent content */ + children: PropTypes.node.isRequired, +}; + +PopoverContent.defaultProps = { + className: null +}; + +export default PopoverContent; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.d.ts new file mode 100644 index 00000000000..883247d1916 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.d.ts @@ -0,0 +1,19 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; +import { OneOf, Omit } from '../../typeUtils'; + +export const PopoverPosition: { + top: 'top'; + bottom: 'bottom'; + left: 'left'; + right: 'right'; +}; + +export interface PopoverDialogProps extends Omit, 'children'> { + children: ReactNode + position: OneOf; +} + +declare const PopoverDialog: SFC; + +export default PopoverDialog; + diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.js new file mode 100644 index 00000000000..92aba019e1b --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverDialog.js @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css, getModifier } from '@patternfly/react-styles'; + +export const PopoverPosition = { + top: 'top', + bottom: 'bottom', + left: 'left', + right: 'right' +}; + +const PopoverDialog = ({ position, children, className, ...props }) => ( +
+ {children} +
+); + +PopoverDialog.propTypes = { + /** PopoverDialog position */ + position: PropTypes.oneOf(Object.values(PopoverPosition)), + /** PopoverDialog additional class */ + className: PropTypes.string, + /** PopoverDialog body */ + children: PropTypes.node.isRequired +}; + +PopoverDialog.defaultProps = { + position: 'top', + className: null +}; + +export default PopoverDialog; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.d.ts b/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.d.ts new file mode 100644 index 00000000000..457c039cd62 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.d.ts @@ -0,0 +1,10 @@ +import { SFC, ReactNode } from 'react'; + +export interface PopoverHeaderProps { + id: string + children: ReactNode; +} + +declare const PopoverHeader: SFC; + +export default PopoverHeader; diff --git a/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.js b/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.js new file mode 100644 index 00000000000..c7fc9c7492a --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/PopoverHeader.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from '@patternfly/patternfly-next/components/Popover/popover.css'; +import { css } from '@patternfly/react-styles'; + +const PopoverHeader = ({ children, id }) => ( +
+

+ {children} +

+
+); + +PopoverHeader.propTypes = { + /** popover id */ + id: PropTypes.string.isRequired, + /** header node */ + children: PropTypes.node.isRequired +}; + +export default PopoverHeader; diff --git a/packages/patternfly-4/react-core/src/components/Popover/__snapshots__/Popover.test.js.snap b/packages/patternfly-4/react-core/src/components/Popover/__snapshots__/Popover.test.js.snap new file mode 100644 index 00000000000..1259fd799bc --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/__snapshots__/Popover.test.js.snap @@ -0,0 +1,171 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`popover renders close-button, header and body 1`] = ` +.pf-c-popover__arrow { + display: block; + position: absolute; + width: 1.5625rem; + height: 1.5625rem; + pointer-events: none; + background-color: #ffffff; + box-shadow: 0 0.0625rem 0.0625rem 0rem rgba(3, 3, 3, 0.05), 0 0.25rem 0.5rem 0.25rem rgba(3, 3, 3, 0.06); +} +.pf-c-button.pf-m-plain { + display: inline-block; + position: relative; + min-width: undefined; + min-height: undefined; + padding: 0.375rem 1rem 0.375rem 1rem; + font-size: 1rem; + font-weight: 500; + line-height: 1.5; + text-align: center; + white-space: nowrap; + border: 0px; + border-radius: 3px; + text-decoration: none; + color: #282d33; +} +.pf-c-popover__close { + display: block; + position: absolute; + top: 0.5rem; + right: 1rem; +} +.pf-c-popover__header-title { + display: block; + font-size: undefined; + font-weight: undefined; + line-height: undefined; +} +.pf-c-popover__header { + display: block; + margin-bottom: 1rem; +} +.pf-c-popover__body { + display: block; + word-wrap: break-word; +} +.pf-c-popover__content { + display: block; + position: relative; + padding: 2rem 2rem 2rem 2rem; + background-color: #ffffff; +} +.pf-c-popover.pf-m-top { + display: block; + position: relative; + min-width: 6.25rem; + max-width: 18.75rem; + box-shadow: 0 0.0625rem 0.0625rem 0rem rgba(3, 3, 3, 0.05), 0 0.25rem 0.5rem 0.25rem rgba(3, 3, 3, 0.06); +} + + + +
+ +
+ + +
+ +
+ + +
+
+ +
+

+ popover header +

+
+
+ +
+ popover body +
+
+
+
+
+ + +`; diff --git a/packages/patternfly-4/react-core/src/components/Popover/examples/HeadlessPopover.txt b/packages/patternfly-4/react-core/src/components/Popover/examples/HeadlessPopover.txt new file mode 100644 index 00000000000..016efc5fd2a --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/examples/HeadlessPopover.txt @@ -0,0 +1,61 @@ +import React from 'react'; +import { + PopoverDialog, + PopoverArrow, + PopoverContent, + PopoverCloseButton, + PopoverHeader, + PopoverBody +} from '@patternfly/react-core'; + +class HeadlessPopover extends React.Component { + constructor(props) { + super(props); + this.popoverRef = React.createRef(); + this.outsideRef = React.createRef(); + this.state = { position: 'top', show: true }; + this.handleClick = this.handleClick.bind(this); + } + + componentDidMount() { + document.addEventListener('mousedown', this.handleClick, false); + } + + componentWillUnmount() { + document.removeEventListener('mousedown', this.handleClick, false); + } + + handleClick(event) { + const node = this.popoverRef && this.popoverRef.current; + const outside = this.outsideRef && this.outsideRef.current; + if (!outside || !outside.contains(event.target)) { + return; + } + if (!node || !node.contains(event.target)) { + this.setState({ show: false }); + } + } + + render() { + return ( +
+
+ {this.state.show && ( + + + + this.setState({ show: false })} /> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla + turpis. + + + + )} +
+
+ ); + } +} + +export default HeadlessPopover; diff --git a/packages/patternfly-4/react-core/src/components/Popover/examples/SimplePopover.txt b/packages/patternfly-4/react-core/src/components/Popover/examples/SimplePopover.txt new file mode 100644 index 00000000000..671bc12572f --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/examples/SimplePopover.txt @@ -0,0 +1,75 @@ +import React from 'react'; +import { + PopoverDialog, + PopoverArrow, + PopoverContent, + PopoverCloseButton, + PopoverHeader, + PopoverBody +} from '@patternfly/react-core'; + +class SimplePopover extends React.Component { + constructor(props) { + super(props); + this.popoverRef = React.createRef(); + this.outsideRef = React.createRef(); + this.state = { position: 'top', show: true }; + this.handleClick = this.handleClick.bind(this); + } + + componentDidMount() { + document.addEventListener('mousedown', this.handleClick, false); + } + + componentWillUnmount() { + document.removeEventListener('mousedown', this.handleClick, false); + } + + handleClick(event) { + const node = this.popoverRef && this.popoverRef.current; + const outside = this.outsideRef && this.outsideRef.current; + if (!outside || !outside.contains(event.target)) { + return + } + if (!node || !node.contains(event.target)) { + this.setState({ show: false }); + } + } + + render() { + return ( +
+ Popover Position + +
+
+ {this.state.show && ( + + + + this.setState({ show: false })} /> + Popover Header + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla + turpis. + + + + )} +
+
+
+ ); + } +} + +export default SimplePopover; diff --git a/packages/patternfly-4/react-core/src/components/Popover/index.d.ts b/packages/patternfly-4/react-core/src/components/Popover/index.d.ts new file mode 100644 index 00000000000..02df6c38e8c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/index.d.ts @@ -0,0 +1 @@ +export { default as Popover } from './Popover'; diff --git a/packages/patternfly-4/react-core/src/components/Popover/index.js b/packages/patternfly-4/react-core/src/components/Popover/index.js new file mode 100644 index 00000000000..e332a5777a9 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Popover/index.js @@ -0,0 +1,7 @@ +export { default as Popover } from './Popover'; +export { default as PopoverDialog, PopoverPosition } from './PopoverDialog'; +export { default as PopoverArrow } from './PopoverArrow'; +export { default as PopoverContent } from './PopoverContent'; +export { default as PopoverHeader } from './PopoverHeader'; +export { default as PopoverBody } from './PopoverBody'; +export { default as PopoverCloseButton } from './PopoverCloseButton'; diff --git a/packages/patternfly-4/react-core/src/components/index.d.ts b/packages/patternfly-4/react-core/src/components/index.d.ts index 8bac8a25c68..1594297b368 100644 --- a/packages/patternfly-4/react-core/src/components/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/index.d.ts @@ -11,10 +11,12 @@ export * from './Card'; export * from './Checkbox'; export * from './Dropdown'; export * from './Form'; +export * from './Label'; export * from './List'; export * from './LoginPage'; export * from './Modal'; export * from './Nav'; +// export * from './Popover'; // Not ready yet export * from './Progress'; export * from './Radio'; export * from './Select'; diff --git a/packages/patternfly-4/react-core/src/components/index.js b/packages/patternfly-4/react-core/src/components/index.js index 1856683851b..1594297b368 100644 --- a/packages/patternfly-4/react-core/src/components/index.js +++ b/packages/patternfly-4/react-core/src/components/index.js @@ -16,6 +16,7 @@ export * from './List'; export * from './LoginPage'; export * from './Modal'; export * from './Nav'; +// export * from './Popover'; // Not ready yet export * from './Progress'; export * from './Radio'; export * from './Select'; diff --git a/packages/patternfly-4/react-styled-system/package.json b/packages/patternfly-4/react-styled-system/package.json index ab049dde44f..8b4d7dea718 100644 --- a/packages/patternfly-4/react-styled-system/package.json +++ b/packages/patternfly-4/react-styled-system/package.json @@ -52,4 +52,4 @@ "optionalDependencies": { "@types/styled-system": "^3.0.7" } -} +} \ No newline at end of file diff --git a/packages/patternfly-4/react-tokens/package.json b/packages/patternfly-4/react-tokens/package.json index 4e3a9c79c92..4b465767928 100644 --- a/packages/patternfly-4/react-tokens/package.json +++ b/packages/patternfly-4/react-tokens/package.json @@ -32,4 +32,4 @@ "fs-extra": "^6.0.1", "glob": "^7.1.2" } -} +} \ No newline at end of file diff --git a/packages/react-icons/package.json b/packages/react-icons/package.json index 57aa8cbcf4e..64b985458e7 100644 --- a/packages/react-icons/package.json +++ b/packages/react-icons/package.json @@ -44,4 +44,4 @@ "react": "^16.4.0", "react-dom": "^15.6.2 || ^16.4.0" } -} +} \ No newline at end of file