Skip to content
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
Expand Up @@ -11,6 +11,7 @@ import Simple from './examples/SimpleDataList';
import CheckboxAction from './examples/CheckboxActionDataList';
import Expandable from './examples/ExpandableDataList';
import Modifiers from './examples/ModifiersDataList';
import Actions from './examples/ActionsDataList';

export default {
title: 'DataList',
Expand All @@ -33,6 +34,10 @@ export default {
component: CheckboxAction,
title: 'Data List Checkboxes, Actions and Additional Cells'
},
{
component: Actions,
title: 'Data List Actions: single and multiple'
},
{
component: Expandable,
title: 'Data List Expandable'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React from 'react';
import { shallow } from 'enzyme';
import DataList from './DataList';
import DataListItem from './DataListItem';
import DataListAction from './DataListAction';
import DataListCell from './DataListCell';
import DataListToggle from './DataListToggle';
import { Button } from '../Button';
import { DropdownItem } from '../Dropdown';

describe('DataList', () => {
test('List default', () => {
Expand Down Expand Up @@ -78,13 +80,35 @@ describe('DataList', () => {
});

test('Toggle expanded', () => {
const view = shallow(<DataListToggle aria-label="Toggle details for" id="ex-toggle2" isExpanded />);
expect(view.find(Button).props()['aria-expanded']).toBe(true);
});

test('DataListAction dropdown', () => {
const view = shallow(
<DataListToggle
aria-label="Toggle details for"
id="ex-toggle2"
isExpanded
<DataListAction
aria-label="Actions"
aria-labelledby="ex-action"
id="ex-action"
actions={[
<DropdownItem component="button" onClick={jest.fn()} key="action-1">
action-1
</DropdownItem>,
<DropdownItem component="button" onClick={jest.fn()} key="action-2">
action-2
</DropdownItem>
]}
/>
);
expect(view.find(Button).props()['aria-expanded']).toBe(true);
expect(view).toMatchSnapshot();
});

test('DataListAction button', () => {
const view = shallow(
<DataListAction aria-label="Actions" aria-labelledby="ex-action" id="ex-action">
<Button id="delete-item-1">Delete</Button>
</DataListAction>
);
expect(view).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { FunctionComponent, HTMLProps } from 'react';
import { FunctionComponent, HTMLProps, ReactNode } from 'react';

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

declare const DataListAction: FunctionComponent<DataListActionProps>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,61 @@ import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly/components/DataList/data-list.css';
import { EllipsisVIcon } from '@patternfly/react-icons';
import { Button, ButtonVariant } from '../Button';
import { Dropdown, DropdownPosition, KebabToggle } from '../Dropdown';

const DataListAction = ({ className, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, rowid, ...props }) => (
<div className={css(styles.dataListAction, className)} {...props}>
<Button variant={ButtonVariant.plain} id={id} aria-labelledby={ariaLabelledBy} aria-label={ariaLabel}>
<EllipsisVIcon />
</Button>
</div>
);
class DataListAction extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}

onToggle = isOpen => {
this.setState({ isOpen });
};

onSelect = event => {
this.setState(prevState => ({
isOpen: !prevState.isOpen
}));
};

render() {
const {
children,
actions,
className,
id,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
...props
} = this.props;

return children ? (
children
) : (
<div className={css(styles.dataListAction, className)} {...props}>
<Dropdown
isPlain
position={DropdownPosition.right}
isOpen={this.state.isOpen}
onSelect={this.onSelect}
toggle={<KebabToggle onToggle={this.onToggle} />}
dropdownItems={actions}
/>
</div>
);
}
}

DataListAction.propTypes = {
/** Content rendered inside the DataList list */
children: PropTypes.node,
/** Additional classes added to the DataList list */
className: PropTypes.string,
/** DataList actions to show in the dropdown */
actions: PropTypes.arrayOf(PropTypes.node).isRequired,
/** Identify the DataList toggle number */
id: PropTypes.string.isRequired,
/** Adds accessible text to the DataList item */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,84 @@ exports[`DataList Cell default 1`] = `
</div>
`;

exports[`DataList DataListAction button 1`] = `
<Button
aria-label={null}
className=""
component="button"
id="delete-item-1"
isActive={false}
isBlock={false}
isDisabled={false}
isFocus={false}
isHover={false}
type="button"
variant="primary"
>
Delete
</Button>
`;

exports[`DataList DataListAction dropdown 1`] = `
.pf-c-data-list__action {
display: block;
flex: 0 0 auto;
margin-left: 1.5rem;
}

<div
className="pf-c-data-list__action"
>
<Dropdown
className=""
direction="down"
dropdownItems={
Array [
<Item
className=""
component="button"
href="#"
isDisabled={false}
isHovered={false}
onClick={[MockFunction]}
>
action-1
</Item>,
<Item
className=""
component="button"
href="#"
isDisabled={false}
isHovered={false}
onClick={[MockFunction]}
>
action-2
</Item>,
]
}
isOpen={false}
isPlain={true}
onSelect={[Function]}
position="right"
toggle={
<Kebab
aria-label="Actions"
className=""
id=""
isActive={false}
isDisabled={false}
isFocused={false}
isHovered={false}
isOpen={false}
isPlain={false}
onToggle={[Function]}
parentRef={null}
/>
}
/>
</div>
`;

exports[`DataList Item 1`] = `
.pf-c-data-list__item.data-list-item-custom {
display: flex;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react';
import {
Button,
Dropdown,
KebabToggle,
DropdownItem,
DataList,
DataListItem,
DataListCell,
DataListCheck,
DataListAction
} from '@patternfly/react-core';

class ActionsDataList extends React.Component {
state = { isOpen: false, isDeleted: false };
render() {
return (
<React.Fragment>
<DataList aria-label="single action data list example ">
{!this.state.isDeleted && (
<DataListItem aria-labelledby="single-action-item1">
<DataListCell>
<span id="single-action-item1">Single actionable Primary content</span>
</DataListCell>
<DataListCell>Single actionable Secondary content</DataListCell>
<DataListAction
aria-labelledby="single-action-item1 single-action-action1"
id="single-action-action1"
aria-label="Actions"
>
<Button
onClick={() => {
if (confirm('Are you sure?')) {
this.setState({ isDeleted: true });
}
}}
variant="primary"
key="delete-action"
>
Delete
</Button>
</DataListAction>
</DataListItem>
)}
<DataListItem aria-labelledby="multi-actions-item1">
<DataListCell>
<span id="multi-actions-item1">Multi actions Primary content</span>
</DataListCell>
<DataListCell>Multi actions Secondary content</DataListCell>
<DataListAction
aria-labelledby="multi-actions-item1 multi-actions-action1"
id="multi-actions-action1"
aria-label="Actions"
actions={[
<DropdownItem key="link">Link</DropdownItem>,
<DropdownItem key="action" component="button">
Action
</DropdownItem>,
<DropdownItem key="disabled link" isDisabled>
Disabled Link
</DropdownItem>
]}
/>
} />
</DataListItem>
</DataList>
</React.Fragment>
);
}
}

export default ActionsDataList;