diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d78cfdca77..17adfd2e670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # [`master`](https://github.com/elastic/eui/tree/master) -No public interface changes since `0.0.38`. +**Bug fixes** + +- Allow accordions to dynamically change height, and support values on radio inputs ([#613](https://github.com/elastic/eui/pull/613)) +- Accordion toggle layout is no longer flagged responsive, in order to prevent unwanted stacking on mobile ([#613](https://github.com/elastic/eui/pull/613)) + +**Breaking changes** + +- Support values on radio inputs. This is breaking because now the second argument to the radio `onChange` callback is the value, which bumps the change event to the third argument ([#613](https://github.com/elastic/eui/pull/613)) # [`0.0.38`](https://github.com/elastic/eui/tree/v0.0.38) diff --git a/src-docs/src/views/accordion/accordion_example.js b/src-docs/src/views/accordion/accordion_example.js index d18c4cd39d0..ece47c01b3d 100644 --- a/src-docs/src/views/accordion/accordion_example.js +++ b/src-docs/src/views/accordion/accordion_example.js @@ -27,6 +27,10 @@ import AccordionOpen from './accordion_open'; const accordionOpenSource = require('!!raw-loader!./accordion_open'); const accordionOpenHtml = renderToHtml(AccordionOpen); +import AccordionGrow from './accordion_grow'; +const accordionGrowSource = require('!!raw-loader!./accordion_grow'); +const accordionGrowHtml = renderToHtml(AccordionGrow); + export const AccordionExample = { title: 'Accordion', sections: [{ @@ -94,6 +98,22 @@ export const AccordionExample = {

), demo: , + }, { + title: 'Accordion content can dynamically change height', + source: [{ + type: GuideSectionTypes.JS, + code: accordionGrowSource, + }, { + type: GuideSectionTypes.HTML, + code: accordionGrowHtml, + }], + text: ( +

+ If an accordion’s content changes height while the accordion is open, + it will resize dynamically. +

+ ), + demo: , }, { title: 'Accordion for forms', source: [{ diff --git a/src-docs/src/views/accordion/accordion_grow.js b/src-docs/src/views/accordion/accordion_grow.js new file mode 100644 index 00000000000..b8767c1933b --- /dev/null +++ b/src-docs/src/views/accordion/accordion_grow.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; + +import { + EuiAccordion, + EuiButton, + EuiSpacer, + EuiText, +} from '../../../../src/components'; + + +class AccordionGrow extends Component { + state = { + counter: 1 + } + + render() { + const rows = []; + for (let i = 1; i <= this.state.counter; i++) { + rows.push(

Row {i}

); + } + + return ( + + + +

+ this.onIncrease()}>Increase height + {' '} + this.onDecrease()}>Decrease height +

+ { rows } +
+
+ ); + } + + onIncrease() { + this.setState(prevState => ({ + counter: prevState.counter + 1 + })); + } + + onDecrease() { + this.setState(prevState => ({ + counter: Math.max(0, prevState.counter - 1) + })); + } +} + +export default AccordionGrow; diff --git a/src/components/accordion/__snapshots__/accordion.test.js.snap b/src/components/accordion/__snapshots__/accordion.test.js.snap index 813c6c91220..532cc47649b 100644 --- a/src/components/accordion/__snapshots__/accordion.test.js.snap +++ b/src/components/accordion/__snapshots__/accordion.test.js.snap @@ -37,11 +37,11 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = ` component="div" gutterSize="s" justifyContent="flexStart" - responsive={true} + responsive={false} wrap={false} >
({ + isOpen: !prevState.isOpen + })); } render() { @@ -96,7 +94,7 @@ export class EuiAccordion extends Component { onClick={this.onToggle} className={buttonClasses} > - + {icon} diff --git a/src/components/form/radio/__snapshots__/radio.test.js.snap b/src/components/form/radio/__snapshots__/radio.test.js.snap index 005cb1b2df7..c8185389f55 100644 --- a/src/components/form/radio/__snapshots__/radio.test.js.snap +++ b/src/components/form/radio/__snapshots__/radio.test.js.snap @@ -71,3 +71,19 @@ exports[`EuiRadio props label is rendered 1`] = `
`; + +exports[`EuiRadio props value is rendered 1`] = ` +
+ +
+
+`; diff --git a/src/components/form/radio/__snapshots__/radio_group.test.js.snap b/src/components/form/radio/__snapshots__/radio_group.test.js.snap index 59d16f99958..eafc29ab7fe 100644 --- a/src/components/form/radio/__snapshots__/radio_group.test.js.snap +++ b/src/components/form/radio/__snapshots__/radio_group.test.js.snap @@ -133,3 +133,48 @@ exports[`EuiRadioGroup props options are rendered 1`] = `
`; + +exports[`EuiRadioGroup props value is propagated to radios 1`] = ` +
+
+ +
+ +
+
+ +
+ +
+
+`; diff --git a/src/components/form/radio/radio.js b/src/components/form/radio/radio.js index a4798fb5923..a6ec70fa3fd 100644 --- a/src/components/form/radio/radio.js +++ b/src/components/form/radio/radio.js @@ -8,6 +8,7 @@ export const EuiRadio = ({ name, checked, label, + value, onChange, disabled, ...rest @@ -43,6 +44,7 @@ export const EuiRadio = ({ type="radio" id={id} name={name} + value={value} checked={checked} onChange={onChange} disabled={disabled} @@ -60,6 +62,7 @@ EuiRadio.propTypes = { id: PropTypes.string.isRequired, checked: PropTypes.bool.isRequired, label: PropTypes.node, + value: PropTypes.string, onChange: PropTypes.func.isRequired, disabled: PropTypes.bool, }; diff --git a/src/components/form/radio/radio.test.js b/src/components/form/radio/radio.test.js index 153f04ac4d8..b0a36b9370c 100644 --- a/src/components/form/radio/radio.test.js +++ b/src/components/form/radio/radio.test.js @@ -33,6 +33,15 @@ describe('EuiRadio', () => { .toMatchSnapshot(); }); + test('value is rendered', () => { + const component = render( + {}} value={'bobbins'}/> + ); + + expect(component) + .toMatchSnapshot(); + }); + test('disabled is rendered', () => { const component = render( {}} disabled/> diff --git a/src/components/form/radio/radio_group.behavior.test.js b/src/components/form/radio/radio_group.behavior.test.js deleted file mode 100644 index 74664870feb..00000000000 --- a/src/components/form/radio/radio_group.behavior.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import sinon from 'sinon'; - -import { EuiRadioGroup } from './radio_group'; - -// This exists because we need to run the following tests -// without mocking the Radio component, such as testing -// an interaction that is handled by the Radio component. -describe('EuiRadioGroup behavior', () => { - test('id is bound to onChange', () => { - const onChangeHandler = sinon.stub(); - const component = mount( - - ); - - component.find('input[type="radio"]').simulate('change'); - sinon.assert.calledWith(onChangeHandler, '1'); - }); -}); diff --git a/src/components/form/radio/radio_group.js b/src/components/form/radio/radio_group.js index 044bd204142..f4be843b6b0 100644 --- a/src/components/form/radio/radio_group.js +++ b/src/components/form/radio/radio_group.js @@ -22,8 +22,9 @@ export const EuiRadioGroup = ({ name={name} checked={option.id === idSelected} label={option.label} + value={option.value} disabled={disabled} - onChange={onChange.bind(null, option.id)} + onChange={onChange.bind(null, option.id, option.value)} /> ); })} @@ -35,6 +36,7 @@ EuiRadioGroup.propTypes = { PropTypes.shape({ id: PropTypes.string.isRequired, label: PropTypes.node, + value: PropTypes.string, }), ).isRequired, idSelected: PropTypes.string, diff --git a/src/components/form/radio/radio_group.test.js b/src/components/form/radio/radio_group.test.js index de17a99e389..8c7e67dc755 100644 --- a/src/components/form/radio/radio_group.test.js +++ b/src/components/form/radio/radio_group.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { render } from 'enzyme'; +import { render, mount } from 'enzyme'; import { requiredProps } from '../../../test'; import { EuiRadioGroup } from './radio_group'; @@ -63,5 +63,65 @@ describe('EuiRadioGroup', () => { expect(component) .toMatchSnapshot(); }); + + test('value is propagated to radios', () => { + const component = render( + {}} + /> + ); + + expect(component) + .toMatchSnapshot(); + }); + }); + + describe('callbacks', () => { + test('id is used in callbacks when no value is available', () => { + const callback = jest.fn(); + + const component = mount( + + ); + + component.find('input[id="2"]').simulate('change'); + + expect(callback).toHaveBeenCalledTimes(1); + const event = expect.any(Object); + expect(callback).toHaveBeenCalledWith('2', undefined, event); + }); + + test('value is used in callbacks when available', () => { + const callback = jest.fn(); + + const component = mount( + + ); + + component.find('input[id="2"]').simulate('change'); + + expect(callback).toHaveBeenCalledTimes(1); + const event = expect.any(Object); + expect(callback).toHaveBeenCalledWith('2', 'Value #2', event); + }); }); });