diff --git a/package.json b/package.json index 35a23c21d36..cc0ada4b68b 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "cz-lerna-changelog": "^1.2.1", "enzyme": "^3.3.0", "enzyme-adapter-react-16": "^1.1.1", + "enzyme-context-patch": "^0.0.9", "enzyme-to-json": "^3.3.3", "fs-extra": "^6.0.1", "glob": "^7.1.2", diff --git a/packages/patternfly-4/react-core/src/components/Avatar/index.d.ts b/packages/patternfly-4/react-core/src/components/Avatar/index.d.ts new file mode 100644 index 00000000000..cd8e00c3fc1 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Avatar/index.d.ts @@ -0,0 +1 @@ +export { default as Avatar, AvatarProps } from './Avatar'; diff --git a/packages/patternfly-4/react-core/src/components/Brand/index.d.ts b/packages/patternfly-4/react-core/src/components/Brand/index.d.ts new file mode 100644 index 00000000000..56188f3a069 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Brand/index.d.ts @@ -0,0 +1 @@ +export { default as Brand, BrandProps } from './Brand'; diff --git a/packages/patternfly-4/react-core/src/components/Checkbox/index.d.ts b/packages/patternfly-4/react-core/src/components/Checkbox/index.d.ts index 8edbc502f99..4ecd9ef1694 100644 --- a/packages/patternfly-4/react-core/src/components/Checkbox/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/Checkbox/index.d.ts @@ -1 +1 @@ -export { default as Checkbox } from './Checkbox'; +export { default as Checkbox, CheckboxProps } from './Checkbox'; diff --git a/packages/patternfly-4/react-core/src/components/Dropdown/index.d.ts b/packages/patternfly-4/react-core/src/components/Dropdown/index.d.ts index 5180427eb2b..aead68ccd40 100644 --- a/packages/patternfly-4/react-core/src/components/Dropdown/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/Dropdown/index.d.ts @@ -1,9 +1,10 @@ export { default as Dropdown, DropdownPosition, - DropdownDirection + DropdownDirection, + DropdownProps } from './Dropdown'; -export { default as DropdownItem } from './Item'; -export { default as DropdownSeparator } from './Separator'; -export { default as KebabToggle } from './KebabToggle'; -export { default as DropdownToggle } from './DropdownToggle'; +export { default as DropdownItem, ItemProps } from './Item'; +export { default as DropdownSeparator, SeparatorProps } from './Separator'; +export { default as KebabToggle, KebabProps } from './KebabToggle'; +export { default as DropdownToggle, DropdownToggleProps } from './DropdownToggle'; diff --git a/packages/patternfly-4/react-core/src/components/List/index.d.ts b/packages/patternfly-4/react-core/src/components/List/index.d.ts new file mode 100644 index 00000000000..0dfabf223e8 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/List/index.d.ts @@ -0,0 +1,2 @@ +export { default as List, ListProps } from './List'; +export { default as ListItem, ListItemProps } from './ListItem'; diff --git a/packages/patternfly-4/react-core/src/components/Nav/Nav.d.ts b/packages/patternfly-4/react-core/src/components/Nav/Nav.d.ts new file mode 100644 index 00000000000..2a2eb327845 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/Nav.d.ts @@ -0,0 +1,14 @@ +import { SFC, HTMLProps, ReactNode, FormEvent } from 'react'; +import { Omit } from '../../typeUtils'; + +export interface NavProps extends Omit, 'onSelect'> { + children?: ReactNode; + className?: string; + onSelect(groupId: number, itemId: number, event: FormEvent): void; + onToggle(groupId: number, expanded: boolean, event: FormEvent): void; + 'aria-label': string; +} + +declare const Nav: SFC; + +export default Nav; diff --git a/packages/patternfly-4/react-core/src/components/Nav/Nav.docs.js b/packages/patternfly-4/react-core/src/components/Nav/Nav.docs.js new file mode 100644 index 00000000000..94a708bf38c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/Nav.docs.js @@ -0,0 +1,33 @@ +import { Nav, NavGroup, NavList, NavItem, NavExpandable, NavVariants } from '@patternfly/react-core'; +import SimpleList from './examples/NavSimpleList'; +import GroupedList from './examples/NavGroupedList'; +import ExpandableList from './examples/NavExpandableList'; +import ExpandableTitlesList from './examples/NavExpandableTitlesList'; +import MixedList from './examples/NavMixedList'; +import DefaultList from './examples/NavDefaultList'; +import HorizontalList from './examples/NavHorizontalList'; +import TertiaryList from './examples/NavTertiaryList'; + +export default { + title: 'Nav', + components: { + Nav, + NavGroup, + NavList, + NavExpandable, + NavItem + }, + enumValues: { + 'Object.values(NavVariants)': Object.values(NavVariants) + }, + examples: [ + SimpleList, + GroupedList, + DefaultList, + ExpandableList, + ExpandableTitlesList, + MixedList, + HorizontalList, + TertiaryList + ] +}; diff --git a/packages/patternfly-4/react-core/src/components/Nav/Nav.js b/packages/patternfly-4/react-core/src/components/Nav/Nav.js new file mode 100644 index 00000000000..fef96509798 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/Nav.js @@ -0,0 +1,70 @@ +import React from 'react'; +import styles from '@patternfly/patternfly-next/components/Nav/styles.css'; +import { css } from '@patternfly/react-styles'; +import PropTypes from 'prop-types'; + +const propTypes = { + /** Anything that can be rendered inside of the nav */ + children: PropTypes.node, + /** Additional classes added to the container */ + className: PropTypes.string, + /** Callback for updating when item selection changes */ + onSelect: PropTypes.func, + /** Callback for when a list is expanded or collapsed */ + onToggle: PropTypes.func, + /** Accessibility label */ + 'aria-label': PropTypes.string.isRequired +}; + +const defaultProps = { + children: null, + className: '', + onSelect: () => undefined, + onToggle: () => undefined +}; + +export const NavContext = React.createContext(); + +class Nav extends React.Component { + // Callback from NavItem + onSelect(event, groupId, itemId) { + event.stopPropagation(); + this.props.onSelect({ + event, + itemId, + groupId + }); + } + + // Callback from NavExpandable + onToggle(event, groupId, isExpanded) { + event.stopPropagation(); + this.props.onToggle({ + event, + groupId, + isExpanded + }); + } + + render() { + const { children, className, ...props } = this.props; + + return ( + this.onSelect(event, groupId, itemId), + onToggle: (event, groupId, expanded) => this.onToggle(event, groupId, expanded) + }} + > + + + ); + } +} + +Nav.propTypes = propTypes; +Nav.defaultProps = defaultProps; + +export default Nav; diff --git a/packages/patternfly-4/react-core/src/components/Nav/Nav.test.js b/packages/patternfly-4/react-core/src/components/Nav/Nav.test.js new file mode 100644 index 00000000000..618214efd7a --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/Nav.test.js @@ -0,0 +1,211 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import Nav from './Nav'; +import NavList from './NavList'; +import NavGroup from './NavGroup'; +import NavItem from './NavItem'; +import NavExpandable from './NavExpandable'; + +const props = { + items: [ + { to: '#link1', label: 'Link 1' }, + { to: '#link2', label: 'Link 2' }, + { to: '#link3', label: 'Link 3' }, + { to: '#link4', label: 'Link 4' } + ] +}; + +beforeEach(() => { + window.location.hash = '#link1'; +}); + +const context = { + onSelect: () => undefined, + onToggle: () => undefined +}; + +test('Default Nav List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Default Nav List - Trigger item active update', () => { + window.location.hash = '#link2'; + const view = mount( + , + { context } + ); + view + .find({ href: '#link2' }) + .first() + .simulate('click'); + expect(view).toMatchSnapshot(); +}); + +test('Simple Nav List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Expandable Nav List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Expandable Nav List - Trigger toggle', () => { + window.location.hash = '#link2'; + const view = mount( + , + { context } + ); + view + .find('li.expandable-group') + .first() + .simulate('click'); + expect(view).toMatchSnapshot(); +}); + +test('Expandable Nav List with aria label', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Nav Grouped List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Horizontal Nav List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Tertiary Nav List', () => { + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); + +test('Nav List with custom item nodes', () => { + const CustomNode = () =>
My custom node
; + const view = mount( + , + { context } + ); + expect(view).toMatchSnapshot(); +}); diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.d.ts b/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.d.ts new file mode 100644 index 00000000000..e0b048d62e5 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.d.ts @@ -0,0 +1,16 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; + +export interface NavExpandableProps extends HTMLProps { + title: string; + srText?: string; + isExpanded?: boolean; + children?: ReactNode; + className?: string; + groupId?: string | number; + isActive?: boolean; + id?: string; +} + +declare const NavExpandable: SFC; + +export default NavExpandable; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.js b/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.js new file mode 100644 index 00000000000..90ca45c3a4a --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavExpandable.js @@ -0,0 +1,107 @@ +import React from 'react'; +import styles from '@patternfly/patternfly-next/components/Nav/styles.css'; +import a11yStyles from '@patternfly/patternfly-next/utilities/Accessibility/styles.css'; +import { css } from '@patternfly/react-styles'; +import PropTypes from 'prop-types'; +import NavToggle from './NavToggle'; +import { AngleRightIcon } from '@patternfly/react-icons'; +import { NavContext } from './Nav'; + +const propTypes = { + /** Title shown for the expandable list */ + title: PropTypes.string.isRequired, + /** If defined, screen readers will read this text instead of the list title */ + srText: PropTypes.string, + /** If true will default the list to be expanded */ + isExpanded: PropTypes.bool, + /** Anything that can be rendered inside of the expandable list */ + children: PropTypes.node, + /** Additional classes added to the container */ + className: PropTypes.string, + /** Group identifier, will be returned with the onToggle and onSelect callback passed to the Nav component */ + groupId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + /** If true makes the expandable list title active */ + isActive: PropTypes.bool, + /** Identifier to use for the section aria label */ + id: PropTypes.string +}; + +const defaultProps = { + srText: '', + isExpanded: false, + children: null, + className: '', + groupId: null, + isActive: false, + id: '' +}; + +class NavExpandable extends React.Component { + constructor(props) { + super(props); + + this.uniqueId = + props.id || + new Date().getTime() + + Math.random() + .toString(36) + .slice(2); + } + + render() { + const { title, srText, isExpanded: defaultExpanded, children, className, groupId, isActive, ...props } = this.props; + + return ( + + {context => ( + + {({ value: isExpanded, toggle }) => ( +
  • + e.preventDefault()} + onMouseDown={e => e.preventDefault()} + aria-expanded={isExpanded} + > + {title} + + + + +
  • + )} +
    + )} +
    + ); + } +} + +NavExpandable.propTypes = propTypes; +NavExpandable.defaultProps = defaultProps; +NavExpandable.componentType = 'NavExpandable'; + +export default NavExpandable; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavGroup.d.ts b/packages/patternfly-4/react-core/src/components/Nav/NavGroup.d.ts new file mode 100644 index 00000000000..fe744bc38ab --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavGroup.d.ts @@ -0,0 +1,12 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; + +export interface NavGroupProps extends HTMLProps { + title: string; + children?: ReactNode; + className?: string; + id?: string; +} + +declare const NavGroup: SFC; + +export default NavGroup; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavGroup.js b/packages/patternfly-4/react-core/src/components/Nav/NavGroup.js new file mode 100644 index 00000000000..5de2c7b2370 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavGroup.js @@ -0,0 +1,53 @@ +import React from 'react'; +import styles from '@patternfly/patternfly-next/components/Nav/styles.css'; +import { css } from '@patternfly/react-styles'; +import PropTypes from 'prop-types'; + +const propTypes = { + /** Title shown for the group */ + title: PropTypes.string.isRequired, + /** Anything that can be rendered inside of the group */ + children: PropTypes.node, + /** Additional classes added to the container */ + className: PropTypes.string, + /** Identifier to use for the section aria label */ + id: PropTypes.string +}; + +const defaultProps = { + children: null, + className: '', + id: '' +}; + +class NavGroup extends React.Component { + constructor(props) { + super(props); + + this.uniqueId = + props.id || + new Date().getTime() + + Math.random() + .toString(36) + .slice(2); + } + + render() { + const { title, children, className, ...props } = this.props; + + return ( +
    +

    + {title} +

    +
      {children}
    +
    + ); + } +} + +NavGroup.propTypes = propTypes; +NavGroup.defaultProps = defaultProps; +NavGroup.componentType = 'NavGroup'; + +export default NavGroup; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavItem.d.ts b/packages/patternfly-4/react-core/src/components/Nav/NavItem.d.ts new file mode 100644 index 00000000000..24d1a2d96b4 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavItem.d.ts @@ -0,0 +1,14 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; + +export interface NavItemProps extends HTMLProps { + children?: ReactNode | string; + className?: string; + to?: string; + isActive?: boolean; + groupId?: string | number; + itemId?: string | number; +} + +declare const NavItem: SFC; + +export default NavItem; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavItem.js b/packages/patternfly-4/react-core/src/components/Nav/NavItem.js new file mode 100644 index 00000000000..cde40d9c2b3 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavItem.js @@ -0,0 +1,68 @@ +import React from 'react'; +import styles from '@patternfly/patternfly-next/components/Nav/styles.css'; +import { css } from '@patternfly/react-styles'; +import PropTypes from 'prop-types'; +import { NavContext } from './Nav'; + +const propTypes = { + /** Content rendered inside the nav item */ + children: PropTypes.node, + /** Additional classes added to the nav item */ + className: PropTypes.string, + /** Target navigation link */ + to: PropTypes.string, + /** Flag indicating whether the item is active */ + isActive: PropTypes.bool, + /** Group identifier, will be returned with the onToggle and onSelect callback passed to the Nav component */ + groupId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + /** Item identifier, will be returned with the onToggle and onSelect callback passed to the Nav component */ + itemId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) +}; + +const defaultProps = { + children: null, + className: '', + to: '#', + isActive: false, + groupId: null, + itemId: null +}; + +const NavItem = ({ className, children, to, isActive, groupId, itemId, ...props }) => { + const defaultLink = ( + + {context => ( + context.onSelect(e, groupId, itemId)} + className={css(styles.navLink, isActive && styles.modifiers.current, className)} + aria-current={isActive ? 'page' : null} + > + {children} + + )} + + ); + const reactElement = React.isValidElement(children); + const clonedChild = ( + + {context => + React.cloneElement(children, { + onClick: e => context.onSelect(e, groupId, itemId), + className: css(styles.navLink, isActive && styles.modifiers.current, className) + }) + } + + ); + return ( +
  • + {reactElement ? clonedChild : defaultLink} +
  • + ); +}; + +NavItem.propTypes = propTypes; +NavItem.defaultProps = defaultProps; +NavItem.componentType = 'NavItem'; + +export default NavItem; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavList.d.ts b/packages/patternfly-4/react-core/src/components/Nav/NavList.d.ts new file mode 100644 index 00000000000..c5cbab9c74c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavList.d.ts @@ -0,0 +1,20 @@ +import { SFC, HTMLProps, ReactNode } from 'react'; +import { OneOf } from '../../typeUtils'; +import { NavVariants } from './NavVariants'; + +export interface NavListProps extends HTMLProps { + variant?: OneOf; + id?: string; + srText?: string; + children?: ReactNode; + className?: string; + innerClassName?: string; + title?: string; + isExpandable?: boolean; + isExpanded?: boolean; + isActive?: boolean; +} + +declare const NavList: SFC; + +export default NavList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavList.js b/packages/patternfly-4/react-core/src/components/Nav/NavList.js new file mode 100644 index 00000000000..e004f8e858c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavList.js @@ -0,0 +1,42 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { NavVariants } from './NavVariants'; +import styles from '@patternfly/patternfly-next/components/Nav/styles.css'; +import { css } from '@patternfly/react-styles'; + +const propTypes = { + /** Indicates the list type. */ + variant: PropTypes.oneOf(Object.values(NavVariants)), + /** Children nodes */ + children: PropTypes.node, + /** Additional classes added to the list */ + className: PropTypes.string +}; + +const defaultProps = { + variant: 'default', + children: null, + className: '' +}; + +const NavList = ({ variant, children, className, ...props }) => { + + const variantStyle = { + [NavVariants.default]: styles.navList, + [NavVariants.simple]: styles.navSimpleList, + [NavVariants.horizontal]: styles.navHorizontalList, + [NavVariants.tertiary]: styles.navTertiaryList + }; + + return ( +
      + {children} +
    + ); +} + +NavList.propTypes = propTypes; +NavList.defaultProps = defaultProps; +NavList.componentType = 'NavList'; + +export default NavList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavToggle.js b/packages/patternfly-4/react-core/src/components/Nav/NavToggle.js new file mode 100644 index 00000000000..ed2c2c33748 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavToggle.js @@ -0,0 +1,41 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + children: PropTypes.func.isRequired, + defaultValue: PropTypes.bool, + groupId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + onToggle: PropTypes.func +}; + +const defaultProps = { + defaultValue: true, + groupId: 0, + onToggle: () => undefined +}; + +class NavToggle extends React.Component { + static propTypes = propTypes; + static defaultProps = defaultProps; + state = { + value: this.props.defaultValue + }; + + handleToggle = e => { + const { value } = this.state; + const { groupId, onToggle } = this.props; + this.setState({ + value: !value + }); + onToggle(e, groupId, !value); + }; + + render() { + return this.props.children({ + value: this.state.value, + toggle: this.handleToggle + }); + } +} + +export default NavToggle; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavVariants.d.ts b/packages/patternfly-4/react-core/src/components/Nav/NavVariants.d.ts new file mode 100644 index 00000000000..19d2a1b8dc6 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavVariants.d.ts @@ -0,0 +1,6 @@ +export const NavVariants: { + default: 'default'; + simple: 'simple'; + horizontal: 'horizontal'; + tertiary: 'tertiary'; +}; diff --git a/packages/patternfly-4/react-core/src/components/Nav/NavVariants.js b/packages/patternfly-4/react-core/src/components/Nav/NavVariants.js new file mode 100644 index 00000000000..ba16db27f70 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/NavVariants.js @@ -0,0 +1,6 @@ +export const NavVariants = { + default: 'default', + simple: 'simple', + horizontal: 'horizontal', + tertiary: 'tertiary' +}; diff --git a/packages/patternfly-4/react-core/src/components/Nav/__snapshots__/Nav.test.js.snap b/packages/patternfly-4/react-core/src/components/Nav/__snapshots__/Nav.test.js.snap new file mode 100644 index 00000000000..10ff96dd9ba --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/__snapshots__/Nav.test.js.snap @@ -0,0 +1,1819 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Default Nav List - Trigger item active update 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Default Nav List 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Expandable Nav List - Trigger toggle 1`] = ` +.pf-c-nav__toggle { + display: block; + padding-right: 0.5rem; + padding-left: 0.5rem; + margin-left: auto; + font-size: 1.25rem; + line-height: 1; + pointer-events: none; + border: 0px; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav__subnav { + display: block; + max-height: 0; + margin-top: 0px; + overflow: hidden; + opacity: 0; +} +.pf-c-nav__item.expandable-group { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Expandable Nav List 1`] = ` +.pf-c-nav__toggle { + display: block; + padding-right: 0.5rem; + padding-left: 0.5rem; + margin-left: auto; + font-size: 1.25rem; + line-height: 1; + pointer-events: none; + border: 0px; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav__subnav { + display: block; + max-height: 0; + margin-top: 0px; + overflow: hidden; + opacity: 0; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Expandable Nav List with aria label 1`] = ` +.pf-c-nav__toggle { + display: block; + padding-right: 0.5rem; + padding-left: 0.5rem; + margin-left: auto; + font-size: 1.25rem; + line-height: 1; + pointer-events: none; + border: 0px; +} +.pf-c-nav__link { + display: block; +} +.pf-u-sr-only { + display: block; + position: fixed; + overflow: hidden; + clip: rect(0px, 0px, 0px, 0px); + white-space: nowrap; + border: 0px; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav__subnav { + display: block; + max-height: 0; + margin-top: 0px; + overflow: hidden; + opacity: 0; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Horizontal Nav List 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__horizontal-list { + display: inline-flex; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Nav Grouped List 1`] = ` +.pf-c-nav__section-title { + display: block; + padding: 0.5rem 2rem 0.5rem 2rem; + font-size: 0.875rem; + font-weight: 500; + color: #72767b; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav__section { + display: block; +} +.pf-c-nav__section-title { + display: block; + padding: 0.5rem 2rem 0.5rem 2rem; + font-size: 0.875rem; + font-weight: 500; + color: #72767b; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__list { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav__section { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Nav List with custom item nodes 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__tertiary-list { + display: inline-flex; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Simple Nav List 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__simple-list { + display: block; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; + +exports[`Tertiary Nav List 1`] = ` +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__link { + display: block; +} +.pf-c-nav__item { + display: block; +} +.pf-c-nav__tertiary-list { + display: inline-flex; +} +.pf-c-nav { + display: block; + overflow-x: auto; +} + + +`; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavDefaultList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavDefaultList.js new file mode 100644 index 00000000000..a3fcf6dc51c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavDefaultList.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { Nav, NavList, NavItem } from '@patternfly/react-core'; + +class NavDefaultList extends React.Component { + static title = 'Default Nav'; + + state = { + activeItem: 0 + }; + + onSelect = result => { + this.setState({ + activeItem: result.itemId + }); + }; + + render() { + const { activeItem } = this.state; + return ( + + ); + } +} + +export default NavDefaultList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableList.js new file mode 100644 index 00000000000..ea8773c42a1 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableList.js @@ -0,0 +1,57 @@ +import React from 'react'; +import { Nav, NavList, NavExpandable, NavItem } from '@patternfly/react-core'; + +class NavExpandableList extends React.Component { + static title = 'Expandable Nav'; + + state = { + activeGroup: 'grp-1', + activeItem: 'grp-1_itm-1' + }; + + onSelect = result => { + this.setState({ + activeGroup: result.groupId, + activeItem: result.itemId + }); + }; + + onToggle = result => { + // eslint-disable-next-line no-console + console.log(`Group ${result.groupId} expanded? ${result.isExpanded}`); + }; + + render() { + const { activeGroup, activeItem } = this.state; + return ( + + ); + } +} + +export default NavExpandableList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableTitlesList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableTitlesList.js new file mode 100644 index 00000000000..966b55bcd5c --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavExpandableTitlesList.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { Nav, NavList, NavExpandable, NavItem } from '@patternfly/react-core'; + +class NavExpandableTitlesList extends React.Component { + static title = 'Expandable Nav (w/subnav titles)'; + + state = { + activeGroup: 'grp-1', + activeItem: 'grp-1_itm-1' + }; + + onSelect = result => { + this.setState({ + activeGroup: result.groupId, + activeItem: result.itemId + }); + }; + + render() { + const { activeGroup, activeItem } = this.state; + return ( + + ); + } +} + +export default NavExpandableTitlesList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavGroupedList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavGroupedList.js new file mode 100644 index 00000000000..282b487dd28 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavGroupedList.js @@ -0,0 +1,48 @@ +import React from 'react'; +import { Nav, NavList, NavGroup, NavItem } from '@patternfly/react-core'; + +class NavGroupedList extends React.Component { + static title = 'Grouped Nav'; + + state = { + activeItem: 'grp-1_itm-1' + }; + + onSelect = result => { + this.setState({ + activeItem: result.itemId + }); + }; + + render() { + const { activeItem } = this.state; + return ( + + ); + } +} + +export default NavGroupedList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavHorizontalList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavHorizontalList.js new file mode 100644 index 00000000000..90a5803325f --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavHorizontalList.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { Nav, NavList, NavItem, NavVariants } from '@patternfly/react-core'; + +class NavHorizontalList extends React.Component { + static title = 'Horizontal List'; + + state = { + activeItem: 0 + }; + + onSelect = result => { + this.setState({ + activeItem: result.itemId + }); + }; + + render() { + const { activeItem } = this.state; + return ( +
    + +
    + ); + } +} + +export default NavHorizontalList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavMixedList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavMixedList.js new file mode 100644 index 00000000000..40cc27a12c0 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavMixedList.js @@ -0,0 +1,55 @@ +import React from 'react'; +import { Nav, NavList, NavExpandable, NavItem } from '@patternfly/react-core'; + +class NavMixedList extends React.Component { + static title = 'Nav Mixed'; + + state = { + activeGroup: '', + activeItem: 'itm-1' + }; + + onSelect = result => { + this.setState({ + activeGroup: result.groupId, + activeItem: result.itemId + }); + }; + + render() { + const { activeGroup, activeItem } = this.state; + return ( + + ); + } +} + +export default NavMixedList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavSimpleList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavSimpleList.js new file mode 100644 index 00000000000..1730f528cdf --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavSimpleList.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { Nav, NavList, NavItem, NavVariants } from '@patternfly/react-core'; + +class NavSimpleList extends React.Component { + static title = 'Simple Nav'; + + state = { + activeItem: 0 + }; + + onSelect = result => { + this.setState({ + activeItem: result.itemId + }); + }; + + render() { + const { activeItem } = this.state; + return ( + + ); + } +} + +export default NavSimpleList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/examples/NavTertiaryList.js b/packages/patternfly-4/react-core/src/components/Nav/examples/NavTertiaryList.js new file mode 100644 index 00000000000..982f6d72bd6 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/examples/NavTertiaryList.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { Nav, NavList, NavItem, NavVariants } from '@patternfly/react-core'; + +class NavTertiaryList extends React.Component { + static title = 'Tertiary List'; + + state = { + activeItem: 0 + }; + + onSelect = result => { + this.setState({ + activeItem: result.itemId + }); + }; + + render() { + const { activeItem } = this.state; + return ( + + ); + } +} + +export default NavTertiaryList; diff --git a/packages/patternfly-4/react-core/src/components/Nav/index.d.ts b/packages/patternfly-4/react-core/src/components/Nav/index.d.ts new file mode 100644 index 00000000000..754271cc5a2 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/index.d.ts @@ -0,0 +1,6 @@ +export { default as Nav, NavProps } from './Nav'; +export { default as NavList, NavListProps } from './NavList'; +export { default as NavGroup, NavGroupProps } from './NavGroup'; +export { default as NavItem, NavItemProps } from './NavItem'; +export { default as NavExpandable, NavExpandableProps } from './NavExpandable'; +export { NavVariants } from './NavVariants'; diff --git a/packages/patternfly-4/react-core/src/components/Nav/index.js b/packages/patternfly-4/react-core/src/components/Nav/index.js new file mode 100644 index 00000000000..fc33590613f --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/Nav/index.js @@ -0,0 +1,6 @@ +export { default as Nav } from './Nav'; +export { default as NavList } from './NavList'; +export { default as NavGroup } from './NavGroup'; +export { default as NavItem } from './NavItem'; +export { default as NavExpandable } from './NavExpandable'; +export { NavVariants } from './NavVariants'; diff --git a/packages/patternfly-4/react-core/src/components/Radio/index.d.ts b/packages/patternfly-4/react-core/src/components/Radio/index.d.ts index fe25e2ea8a8..e21cd41b995 100644 --- a/packages/patternfly-4/react-core/src/components/Radio/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/Radio/index.d.ts @@ -1 +1 @@ -export { default as Radio } from './Radio'; +export { default as Radio, RadioProps } from './Radio'; diff --git a/packages/patternfly-4/react-core/src/components/Select/index.d.ts b/packages/patternfly-4/react-core/src/components/Select/index.d.ts index 19f56730d0e..2cde27c9461 100644 --- a/packages/patternfly-4/react-core/src/components/Select/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/Select/index.d.ts @@ -1,3 +1,3 @@ -export { default as Select } from './Select'; -export { default as SelectOption } from './SelectOption'; -export { default as SelectOptionGroup } from './SelectOptionGroup'; +export { default as Select, SelectProps } from './Select'; +export { default as SelectOption, SelectOptionProps } from './SelectOption'; +export { default as SelectOptionGroup, SelectOptionGroupProps } from './SelectOptionGroup'; diff --git a/packages/patternfly-4/react-core/src/components/TextArea/TextArea.d.ts b/packages/patternfly-4/react-core/src/components/TextArea/TextArea.d.ts new file mode 100644 index 00000000000..447112e4196 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/TextArea/TextArea.d.ts @@ -0,0 +1,15 @@ +import { SFC, HTMLProps, FormEvent } from 'react'; +import { Omit } from '../../typeUtils'; + +export interface TextAreaProps extends Omit, 'onChange'> { + className?: string; + isRequired?: boolean; + isValid?: boolean; + value?: string | number; + onChange(checked: boolean, event: FormEvent): void; + 'aria-label'?: string; +} + +declare const TextArea: SFC; + +export default TextArea; diff --git a/packages/patternfly-4/react-core/src/components/TextArea/index.d.ts b/packages/patternfly-4/react-core/src/components/TextArea/index.d.ts new file mode 100644 index 00000000000..a295bac41ca --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/TextArea/index.d.ts @@ -0,0 +1 @@ +export { default as TextArea, TextAreaProps } from './TextArea'; diff --git a/packages/patternfly-4/react-core/src/components/TextInput/TextInput.d.ts b/packages/patternfly-4/react-core/src/components/TextInput/TextInput.d.ts new file mode 100644 index 00000000000..d5660b8d528 --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/TextInput/TextInput.d.ts @@ -0,0 +1,19 @@ +import { SFC, HTMLProps, FormEvent } from 'react'; +import { Omit } from '../../typeUtils'; + +export interface TextInputProps extends Omit, 'type' | 'onChange' | 'disabled'> { + className?: string; + isRequired?: boolean; + type?: string; + value?: string | number; + isValid?: boolean; + isDisabled?: boolean; + isAlt?: boolean; + onChange(checked: boolean, event: FormEvent): void; + isReadOnly?: boolean; + 'aria-label'?: string; +} + +declare const TextInput: SFC; + +export default TextInput; diff --git a/packages/patternfly-4/react-core/src/components/TextInput/index.d.ts b/packages/patternfly-4/react-core/src/components/TextInput/index.d.ts new file mode 100644 index 00000000000..8aa666afeea --- /dev/null +++ b/packages/patternfly-4/react-core/src/components/TextInput/index.d.ts @@ -0,0 +1 @@ +export { default as TextInput, TextInputProps } from './TextInput'; 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 7d4c8097fe4..055d69c6ad2 100644 --- a/packages/patternfly-4/react-core/src/components/index.d.ts +++ b/packages/patternfly-4/react-core/src/components/index.d.ts @@ -1,12 +1,17 @@ +/** Keep alphabetically sorted */ export * from './Alert'; +export * from './Avatar'; export * from './Badge'; +export * from './Brand'; export * from './Button'; export * from './Card'; export * from './Checkbox'; +export * from './Dropdown'; +export * from './List'; export * from './Modal'; +export * from './Nav'; export * from './Radio'; -export * from './Title'; -export * from './Alert'; -export * from './Dropdown'; export * from './Select'; -export * from './List'; +export * from './TextArea'; +export * from './TextInput'; +export * from './Title'; diff --git a/packages/patternfly-4/react-core/src/components/index.js b/packages/patternfly-4/react-core/src/components/index.js index 8014b277b00..055d69c6ad2 100644 --- a/packages/patternfly-4/react-core/src/components/index.js +++ b/packages/patternfly-4/react-core/src/components/index.js @@ -1,15 +1,17 @@ +/** Keep alphabetically sorted */ export * from './Alert'; +export * from './Avatar'; export * from './Badge'; +export * from './Brand'; export * from './Button'; export * from './Card'; export * from './Checkbox'; +export * from './Dropdown'; +export * from './List'; export * from './Modal'; +export * from './Nav'; export * from './Radio'; -export * from './Title'; -export * from './TextInput'; -export * from './TextArea'; -export * from './Dropdown'; export * from './Select'; -export * from './Avatar'; -export * from './Brand'; -export * from './List'; +export * from './TextArea'; +export * from './TextInput'; +export * from './Title'; diff --git a/packages/patternfly-4/react-docs/src/components/componentDocs/componentDocs.js b/packages/patternfly-4/react-docs/src/components/componentDocs/componentDocs.js index c02a0795bdc..997bbed11b1 100644 --- a/packages/patternfly-4/react-docs/src/components/componentDocs/componentDocs.js +++ b/packages/patternfly-4/react-docs/src/components/componentDocs/componentDocs.js @@ -29,35 +29,41 @@ const defaultProps = { fullPageOnly: false }; -const ComponentDocs = ({ title, description, examples, components, enumValues, fullPageOnly, rawExamples, images }) => ( - - {title} - {Boolean(description) &&

    {description}

    } -
    - {examples.map((ComponentExample, i) => { - const { __docgenInfo: componentDocs } = ComponentExample; - const rawExample = rawExamples.find(example => example.name === componentDocs.displayName); - return ( - - - - ); - })} -
    - {Object.entries(components).map(([componentName, { __docgenInfo: componentDocs }]) => ( - - ))} -
    -); +class ComponentDocs extends React.PureComponent { + + render() { + const { title, description, examples, components, enumValues, fullPageOnly, rawExamples, images } = this.props; + return ( + + {title} + {Boolean(description) &&

    {description}

    } +
    + {examples.map((ComponentExample, i) => { + const { __docgenInfo: componentDocs } = ComponentExample; + const rawExample = rawExamples.find(example => example.name === componentDocs.displayName); + return ( + + + + ); + })} +
    + {Object.entries(components).map(([componentName, { __docgenInfo: componentDocs }]) => ( + + ))} +
    + ); + } +} ComponentDocs.propTypes = propTypes; ComponentDocs.defaultProps = defaultProps; diff --git a/yarn.lock b/yarn.lock index 6c4117600dd..b937608add3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5308,6 +5308,10 @@ enzyme-adapter-utils@^1.3.0: object.assign "^4.0.4" prop-types "^15.6.0" +enzyme-context-patch@^0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/enzyme-context-patch/-/enzyme-context-patch-0.0.9.tgz#0661659148bdf0af420631930f9e488ce2ba224f" + enzyme-to-json@^3.3.3: version "3.3.4" resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.3.4.tgz#67c6040e931182f183418af2eb9f4323258aa77f"