Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DataList): Add simple data list #927

Merged
merged 1 commit into from
Dec 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not an issue in your code, but i think this css should have a more specific name, will address with Core

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this box shadow class is rolled into the data list class so we wouldn't have to import it. Also addressing with Core

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{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>;
boaz0 marked this conversation as resolved.
Show resolved Hide resolved

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)}
boaz0 marked this conversation as resolved.
Show resolved Hide resolved
{...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