Skip to content

Commit

Permalink
feat(DataList): Add simple data list (patternfly#927)
Browse files Browse the repository at this point in the history
Signed-off-by: Boaz Shuster <boaz.shuster.github@gmail.com>
  • Loading branch information
boaz0 authored and jschuler committed Dec 7, 2018
1 parent 2070327 commit cd25279
Show file tree
Hide file tree
Showing 25 changed files with 830 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SFC, HTMLProps } from 'react';
import { Omit } from '../../typeUtils';

export interface DataListProps extends Omit<HTMLProps<HTMLUListElement>, 'aria-label'> {
'aria-label': string;
}

declare const DataList: SFC<DataListProps>;

export default DataList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
DataList,
DataListItem,
DataListCell,
DataListCheck,
DataListAction,
DataListContent,
DataListToggle
} from '@patternfly/react-core';
import Simple from './examples/SimpleDataList';
import CheckboxAction from './examples/CheckboxActionDataList';
import Expandable from './examples/ExpandableDataList';
import Modifiers from './examples/ModifiersDataList';

export default {
title: 'DataList',
components: {
DataList,
DataListItem,
DataListCell,
DataListCheck,
DataListAction,
DataListContent,
DataListToggle
},
examples: [
{
component: Simple,
title: 'Data List Simple'
},
{
component: CheckboxAction,
title: 'Data List Checkboxes, Actions and Additional Cells'
},
{
component: Expandable,
title: 'Data List Expandable'
},
{
component: Modifiers,
title: 'Data List Width Modifiers'
}
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly-next/components/DataList/styles.css';
import boxShStyles from '@patternfly/patternfly-next//utilities/BoxShadow/box-shadow.css';

const DataList = ({ children, className, 'aria-label': ariaLabel, ...props }) => {
return (
<ul className={css(styles.dataList, boxShStyles.boxShadowMd, className)} role="list" aria-label={ariaLabel} {...props}>
{children}
</ul>
);
};

DataList.propTypes = {
/** Content rendered inside the DataList list */
children: PropTypes.node,
/** Additional classes added to the DataList list */
className: PropTypes.string,
/** Adds accessible text to the DataList list */
'aria-label': PropTypes.string.isRequired
};

DataList.defaultProps = {
children: null,
className: '',
};

export default DataList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from 'react';
import { shallow } from 'enzyme';
import DataList from './DataList';
import DataListItem from './DataListItem';
import DataListCell from './DataListCell';
import DataListToggle from './DataListToggle';
import { Button } from '../Button';

describe('DataList', () => {
test('List default', () => {
const view = shallow(<DataList aria-label="this is a simple list" />);
expect(view).toMatchSnapshot();
});

test('List', () => {
const view = shallow(<DataList key="list-id-1" className="data-list-custom" aria-label="this is a simple list" />);
expect(view).toMatchSnapshot();
});

test('Item default', () => {
const view = shallow(<DataListItem key="item-id-1" aria-labelledby="item-1" />);
expect(view).toMatchSnapshot();
});

test('Item expanded', () => {
const view = shallow(<DataListItem aria-labelledby="item-1" isExpanded />);
expect(view.props().className).toBe('pf-c-data-list__item pf-m-expanded');
});

test('Item', () => {
const view = shallow(<DataListItem className="data-list-item-custom" aria-labelledby="item-1" />);
expect(view).toMatchSnapshot();
});

test('Cell default', () => {
const view = shallow(<DataListCell>Secondary</DataListCell>);
expect(view).toMatchSnapshot();
});

test('Cell', () => {
const view = shallow(
<DataListCell key="list-id-1" id="primary-item" className="data-list-custom">
Primary Id
</DataListCell>
);
expect(view).toMatchSnapshot();
});

test('Cell with width modifier', () => {
[
{ width: 1, class: '' },
{ width: 2, class: 'pf-m-flex-2' },
{ width: 3, class: 'pf-m-flex-3' },
{ width: 4, class: 'pf-m-flex-4' },
{ width: 5, class: 'pf-m-flex-5' }
].forEach(testCase => {
const view = shallow(
<DataListCell width={testCase.width} key="list-id-1" id="primary-item">
Primary Id
</DataListCell>
);
testCase.class === ''
? expect(view.props().className).toBe('pf-c-data-list__cell')
: expect(view.props().className).toBe(`pf-c-data-list__cell ${testCase.class}`);
});
});

test('Toggle default', () => {
const view = shallow(
<DataListToggle aria-label="Toggle details for" aria-labelledby="ex-toggle2 ex-item2" id="ex-toggle2" />
);

expect(view.find(Button).props()['aria-label']).toBe('Toggle details for');
expect(view.find(Button).props()['aria-labelledby']).toBe('ex-toggle2 ex-item2');
expect(view.find(Button).props()['aria-expanded']).toBe('false');
expect(view.find(Button).props().id).toBe('ex-toggle2');
expect(view.find(Button).props().id).toBe('ex-toggle2');
});

test('Toggle expanded', () => {
const view = shallow(
<DataListToggle
aria-label="Toggle details for"
aria-labelledby="ex-toggle2 ex-item2"
id="ex-toggle2"
isExpanded
/>
);
expect(view.find(Button).props()['aria-expanded']).toBe('true');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SFC, HTMLProps } from 'react';

export interface DataListActionProps extends HTMLProps<HTMLDivElement> {
'aria-labelledby': string;
'aria-label': string;
id: string;
}

declare const DataListAction: SFC<DataListActionProps>;

export default DataListAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly-next/components/DataList/styles.css';
import { EllipsisVIcon } from '@patternfly/react-icons';
import { Button } from '../Button';

const DataListAction = ({ className, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }) => (
<div className={css(styles.dataListAction, className)} {...props}>
<Button variant="plain" id={id} aria-labelledby={ariaLabelledBy} aria-label={ariaLabel}>
<EllipsisVIcon />
</Button>
</div>
);

DataListAction.propTypes = {
/** Content rendered inside the DataList list */
children: PropTypes.node,
/** Additional classes added to the DataList list */
className: PropTypes.string,
/** Identify the DataList toggle number */
id: PropTypes.string.isRequired,
/** Adds accessible text to the DataList item */
'aria-labelledby': PropTypes.string.isRequired,
/** Adds accessible text to the DataList item */
'aria-label': PropTypes.string.isRequired
};

DataListAction.defaultProps = {
children: null,
className: ''
};

export default DataListAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { SFC, HTMLProps } from 'react';

export interface DataListCellProps extends HTMLProps<HTMLDivElement> {
width: 1 | 2 | 3 | 4 | 5;
}

declare const DataListCell: SFC<DataListCellProps>;

export default DataListCell;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { css, getModifier } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly-next/components/DataList/styles.css';

const DataListCell = ({ children, className, width, ...props }) => (
<div
className={css(styles.dataListCell, width > 1 && getModifier(styles, `flex_${width}`, ''), className)}
{...props}
>
{children}
</div>
);

DataListCell.propTypes = {
/** Content rendered inside the DataList cell */
children: PropTypes.node,
/** Additional classes added to the DataList cell */
className: PropTypes.string,
/** Width (from 1-5) to the DataList cell */
width: PropTypes.oneOf([1, 2, 3, 4, 5])
};

DataListCell.defaultProps = {
children: null,
className: '',
width: 1
};

export default DataListCell;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { HTMLProps, FormEvent, ReactNode } from 'react';
import { Omit } from '../../typeUtils';

export interface DataListCheckProps
extends Omit<HTMLProps<HTMLInputElement>, 'type' | 'onChange' | 'disabled' | 'aria-labelledby'> {
isDisabled?: boolean;
isValid?: boolean;
isChecked?: boolean;
onChange?(checked: boolean, event: FormEvent<HTMLInputElement>): void;
'aria-labelledby': string;
}

declare const DataListCheck: React.SFC<DataListCheckProps>;

export default DataListCheck;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly-next/components/DataList/styles.css';
import checkboxStyles from '@patternfly/patternfly-next/components/Check/check.css';

const DataListCheck = ({ className, onChange, isValid, isDisabled, isChecked, checked, ...props }) => (
<div className={css(styles.dataListCheck, className)}>
<input
{...props}
className={css(checkboxStyles.checkInput)}
type="checkbox"
onChange={event => onChange(event.currentTarget.checked, event)}
aria-invalid={!isValid}
disabled={isDisabled}
checked={isChecked || checked}
/>
</div>
);

DataListCheck.propTypes = {
/** Additional classes added to the DataList item checkbox */
className: PropTypes.string,
/** Flag to show if the DataList checkbox selection is valid or invalid */
isValid: PropTypes.bool,
/** Flag to show if the DataList checkbox is disabled */
isDisabled: PropTypes.bool,
/** Flag to show if the DataList checkbox is checked */
isChecked: PropTypes.bool,
/** A callback for when the DataList checkbox selection changes */
onChange: PropTypes.func,
/** Aria-labelledby of the DataList checkbox */
'aria-labelledby': PropTypes.string.isRequired
};

DataListCheck.defaultProps = {
className: '',
isValid: true,
isDisabled: false,
isChecked: null,
onChange: () => undefined
};

export default DataListCheck;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SFC, HTMLProps } from 'react';
import { Omit } from '../../typeUtils';

export interface DataListContentProps extends Omit<HTMLProps<HTMLElement>, 'aria-label'> {
isHidden: boolean;
'aria-label': string;
}

declare const DataListContent: SFC<DataListContentProps>;

export default DataListContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/patternfly-next/components/DataList/styles.css';

const DataListContent = ({ className, children, isHidden, 'aria-label': ariaLabel, ...props }) => (
<section
className={css(styles.dataListExpandableContent, className)}
hidden={isHidden}
aria-label={ariaLabel}
{...props}
>
{children}
</section>
);

DataListContent.propTypes = {
/** Content rendered inside the DataList item */
children: PropTypes.node,
/** Additional classes added to the DataList cell */
className: PropTypes.string,
/** Flag to show if the expanded content of the DataList item is visible */
isHidden: PropTypes.bool,
/** Adds accessible text to the DataList toggle */
'aria-label': PropTypes.string.isRequired
};

DataListContent.defaultProps = {
className: '',
isHidden: false
};

export default DataListContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SFC, HTMLProps } from 'react';
import { Omit } from '../../typeUtils';

export interface DataListItemProps extends Omit<HTMLProps<HTMLLIElement>, 'aria-label'> {
isExpanded: boolean;
'aria-labelledby': string;
}

declare const DataListItem: SFC<DataListItemProps>;

export default DataListItem;
Loading

0 comments on commit cd25279

Please sign in to comment.