Add EditorOptionsGroup component (#18812)

* Add EditorOptionsGroup component

* Add actions and more tests

* Add initialIsCollapsed property
This commit is contained in:
Tim Roes 2018-05-08 15:29:41 +02:00 committed by GitHub
parent 74868ebb2f
commit cbbb4dc221
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 409 additions and 0 deletions

View file

@ -20,6 +20,7 @@ export default {
],
moduleNameMapper: {
'^ui/(.*)': '<rootDir>/src/ui/public/$1',
'^test_utils/(.*)': '<rootDir>/src/test_utils/public/$1',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/dev/jest/mocks/file_mock.js',
'\\.(css|less|scss)$': '<rootDir>/src/dev/jest/mocks/style_mock.js',
},

View file

@ -0,0 +1,18 @@
/**
* Import this test utility in your jest test (and only there!) if you want the
* htmlIdGenerator from EUI to generate static ids. That will be needed if you
* want to use snapshot tests for a component, that uses the htmlIdGenerator.
* By default every test run would result in different ids and thus not be comparable.
* You can solve this by just importing this file. It will mock the htmlIdGenerator
* for the test file that imported it to produce static, but therfore potentially
* duplicate ids.
*
* import 'test_utils/html_id_generator';
*/
/* global jest */
jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
htmlIdGenerator: (prefix = 'staticGenerator') => {
return (suffix = 'staticId') => `${prefix}_${suffix}`;
}
}));

View file

@ -0,0 +1,271 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<EditorOptionsGroup/> renders as expected 1`] = `
<div
class="euiPanel euiPanel--paddingMedium euiPanel--flexGrowZero editorOptionsGroup__panel"
>
<div
class="euiAccordion euiAccordion-isOpen"
>
<div
class="euiFlexGroup euiFlexGroup--alignItemsCenter euiFlexGroup--responsive"
>
<div
class="euiFlexItem"
>
<button
aria-controls="eog_staticId"
aria-expanded="true"
class="euiAccordion__button"
>
<div
class="euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter"
>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<svg
class="euiIcon euiIcon--medium"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M13.069 5.157L8.384 9.768a.546.546 0 0 1-.768 0L2.93 5.158a.552.552 0 0 0-.771 0 .53.53 0 0 0 0 .759l4.684 4.61c.641.631 1.672.63 2.312 0l4.684-4.61a.53.53 0 0 0 0-.76.552.552 0 0 0-.771 0z"
id="arrow_down-a"
/>
</defs>
<use
fill-rule="nonzero"
href="#arrow_down-a"
/>
</svg>
</div>
<div
class="euiFlexItem euiAccordion__buttonContent"
>
<h2
class="euiTitle euiTitle--xsmall"
>
Some options
</h2>
</div>
</div>
</button>
</div>
</div>
<div
class="euiAccordion__childWrapper"
id="eog_staticId"
>
<div>
<div
class=""
>
<div
class="euiSpacer euiSpacer--m"
/>
<span>
Children
</span>
<span>
within the editor group
</span>
</div>
</div>
</div>
</div>
</div>
`;
exports[`<EditorOptionsGroup/> renders as expected with actions 1`] = `
<div
class="euiPanel euiPanel--paddingMedium euiPanel--flexGrowZero editorOptionsGroup__panel"
>
<div
class="euiAccordion euiAccordion-isOpen"
>
<div
class="euiFlexGroup euiFlexGroup--alignItemsCenter euiFlexGroup--responsive"
>
<div
class="euiFlexItem"
>
<button
aria-controls="eog_staticId"
aria-expanded="true"
class="euiAccordion__button"
>
<div
class="euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter"
>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<svg
class="euiIcon euiIcon--medium"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M13.069 5.157L8.384 9.768a.546.546 0 0 1-.768 0L2.93 5.158a.552.552 0 0 0-.771 0 .53.53 0 0 0 0 .759l4.684 4.61c.641.631 1.672.63 2.312 0l4.684-4.61a.53.53 0 0 0 0-.76.552.552 0 0 0-.771 0z"
id="arrow_down-a"
/>
</defs>
<use
fill-rule="nonzero"
href="#arrow_down-a"
/>
</svg>
</div>
<div
class="euiFlexItem euiAccordion__buttonContent"
>
<h2
class="euiTitle euiTitle--xsmall"
>
Some actions
</h2>
</div>
</div>
</button>
</div>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<button
aria-label="Remove"
class="euiButtonIcon euiButtonIcon--text"
type="button"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiButtonIcon__icon"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M11 3h5v1H0V3h5V1a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2zm-7.056 8H7v1H4.1l.392 2.519c.042.269.254.458.493.458h6.03c.239 0 .451-.189.493-.458l1.498-9.576H14l-1.504 9.73c-.116.747-.74 1.304-1.481 1.304h-6.03c-.741 0-1.365-.557-1.481-1.304l-1.511-9.73H9V5.95H3.157L3.476 8H8v1H3.632l.312 2zM6 3h4V1H6v2z"
id="trash-a"
/>
</defs>
<use
href="#trash-a"
/>
</svg>
</button>
</div>
</div>
<div
class="euiAccordion__childWrapper"
id="eog_staticId"
>
<div>
<div
class=""
>
<div
class="euiSpacer euiSpacer--m"
/>
<span>
Some children
</span>
</div>
</div>
</div>
</div>
</div>
`;
exports[`<EditorOptionsGroup/> renders as expected with initial collapsed 1`] = `
<div
class="euiPanel euiPanel--paddingMedium euiPanel--flexGrowZero editorOptionsGroup__panel"
>
<div
class="euiAccordion"
>
<div
class="euiFlexGroup euiFlexGroup--alignItemsCenter euiFlexGroup--responsive"
>
<div
class="euiFlexItem"
>
<button
aria-controls="eog_staticId"
aria-expanded="false"
class="euiAccordion__button"
>
<div
class="euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter"
>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<svg
class="euiIcon euiIcon--medium"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M13.069 5.157L8.384 9.768a.546.546 0 0 1-.768 0L2.93 5.158a.552.552 0 0 0-.771 0 .53.53 0 0 0 0 .759l4.684 4.61c.641.631 1.672.63 2.312 0l4.684-4.61a.53.53 0 0 0 0-.76.552.552 0 0 0-.771 0z"
id="arrow_right-a"
/>
</defs>
<use
fill-rule="nonzero"
href="#arrow_right-a"
transform="matrix(0 1 1 0 0 0)"
/>
</svg>
</div>
<div
class="euiFlexItem euiAccordion__buttonContent"
>
<h2
class="euiTitle euiTitle--xsmall"
>
Some options
</h2>
</div>
</div>
</button>
</div>
</div>
<div
class="euiAccordion__childWrapper"
id="eog_staticId"
>
<div>
<div
class=""
>
<div
class="euiSpacer euiSpacer--m"
/>
<span>
Children
</span>
<span>
within the editor group
</span>
</div>
</div>
</div>
</div>
</div>
`;

View file

@ -0,0 +1,62 @@
import React from 'react';
import PropTypes from 'prop-types';
import './editor_options_group.less';
import {
EuiAccordion,
EuiPanel,
EuiSpacer,
EuiTitle,
htmlIdGenerator,
} from '@elastic/eui';
/**
* A component to group different options in an editor together and give them
* a title. Should be used for all visualize editors when grouping options,
* to produce an aligned look and feel.
*/
function EditorOptionsGroup(props) {
return (
<EuiPanel
grow={false}
className="editorOptionsGroup__panel"
>
<EuiAccordion
id={htmlIdGenerator('eog')()}
initialIsOpen={!props.initialIsCollapsed}
extraAction={props.actions}
buttonContent={
<EuiTitle size="xs">
<h2>{props.title}</h2>
</EuiTitle>
}
>
<EuiSpacer size="m"/>
{ props.children }
</EuiAccordion>
</EuiPanel>
);
}
EditorOptionsGroup.propTypes = {
/**
* The title of this options group, which will be shown with the group.
*/
title: PropTypes.string.isRequired,
/**
* Add additional elements as actions to the group.
*/
actions: PropTypes.node,
/**
* Whether the panel should be collapsed by default.
*/
initialIsCollapsed: PropTypes.bool,
/**
* All elements that should be within this group.
*/
children: PropTypes.node.isRequired,
};
export { EditorOptionsGroup };

View file

@ -0,0 +1,3 @@
.editorOptionsGroup__panel + .editorOptionsGroup__panel {
margin-top: 8px;
}

View file

@ -0,0 +1,52 @@
import React from 'react';
import { render } from 'enzyme';
import 'test_utils/static_html_id_generator';
import { EuiButtonIcon } from '@elastic/eui';
import { EditorOptionsGroup } from './editor_options_group';
describe('<EditorOptionsGroup/>', () => {
it('renders as expected', () => {
const group = render(
<EditorOptionsGroup
title="Some options"
>
<span>Children</span>
<span>within the editor group</span>
</EditorOptionsGroup>
);
expect(group).toMatchSnapshot();
});
it('renders as expected with actions', () => {
const group = render(
<EditorOptionsGroup
title="Some actions"
actions={
<EuiButtonIcon
iconType="trash"
color="text"
aria-label="Remove"
/>
}
>
<span>Some children</span>
</EditorOptionsGroup>
);
expect(group).toMatchSnapshot();
});
it('renders as expected with initial collapsed', () => {
const group = render(
<EditorOptionsGroup
title="Some options"
initialIsCollapsed={true}
>
<span>Children</span>
<span>within the editor group</span>
</EditorOptionsGroup>
);
expect(group).toMatchSnapshot();
});
});

View file

@ -0,0 +1 @@
export { EditorOptionsGroup } from './editor_options_group';

View file

@ -0,0 +1 @@
export { EditorOptionsGroup } from './components';