Skip to content

Commit

Permalink
add MutationObserver to accordion to trigger setChildContentHeight wh…
Browse files Browse the repository at this point in the history
…en children change (elastic#947)

* add MutationObserver to accordion to trigger setChildContentHeight when children change

* remove requestAnimationFrame around MutationObserver registration and add comment to change log

* set up observer in ref creation function

* mock MutationObserver
  • Loading branch information
nreese authored Jun 27, 2018
1 parent db1b0f1 commit c64f055
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `1.0.0`.
- `EuiAccordion` use MutationObserver to re-calculate height when children DOM changes ([#947](https://github.com/elastic/eui/pull/947))

## [`1.0.0`](https://github.com/elastic/eui/tree/v1.0.0)

Expand Down
55 changes: 32 additions & 23 deletions src-docs/src/views/accordion/accordion_grow.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint react/no-multi-comp: 0 */
/* eslint react/prefer-stateless-function: 0 */

import React, { Component } from 'react';

import {
Expand All @@ -7,49 +10,55 @@ import {
EuiText,
} from '../../../../src/components';


class AccordionGrow extends Component {
class Rows extends Component {
state = {
counter: 1
}

onIncrease() {
this.setState(prevState => ({
counter: prevState.counter + 1
}));
}

onDecrease() {
this.setState(prevState => ({
counter: Math.max(0, prevState.counter - 1)
}));
}

render() {
const rows = [];
for (let i = 1; i <= this.state.counter; i++) {
rows.push(<p key={i}>Row {i}</p>);
}
return (
<EuiText>
<EuiSpacer size="s" />
<p>
<EuiButton onClick={() => this.onIncrease()}>Increase height</EuiButton>
{' '}
<EuiButton onClick={() => this.onDecrease()}>Decrease height</EuiButton>
</p>
{ rows }
</EuiText>
);
}
}

class AccordionGrow extends Component {
render() {
return (
<EuiAccordion
id="accordion1"
buttonContent="Click me to toggle close / open"
initialIsOpen={true}
paddingSize="l"
>
<EuiText>
<EuiSpacer size="s" />
<p>
<EuiButton onClick={() => this.onIncrease()}>Increase height</EuiButton>
{' '}
<EuiButton onClick={() => this.onDecrease()}>Decrease height</EuiButton>
</p>
{ rows }
</EuiText>
<Rows/>
</EuiAccordion>
);
}

onIncrease() {
this.setState(prevState => ({
counter: prevState.counter + 1
}));
}

onDecrease() {
this.setState(prevState => ({
counter: Math.max(0, prevState.counter - 1)
}));
}
}

export default AccordionGrow;
16 changes: 15 additions & 1 deletion src/components/accordion/accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ export class EuiAccordion extends Component {
}));
}

setChildContentRef = (node) => {
this.childContent = node;

if (this.observer) {
this.observer.disconnect();
this.observer = null;
}

if (node) {
this.observer = new MutationObserver(this.setChildContentHeight);
this.observer.observe(this.childContent, { childList: true, subtree: true });
}
}

render() {
const {
children,
Expand Down Expand Up @@ -140,7 +154,7 @@ export class EuiAccordion extends Component {
ref={node => { this.childWrapper = node; }}
id={id}
>
<div ref={node => { this.childContent = node; }}>
<div ref={this.setChildContentRef}>
<div className={paddingClass}>
{children}
</div>
Expand Down
12 changes: 12 additions & 0 deletions src/components/accordion/accordion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ describe('EuiAccordion', () => {
});

describe('behavior', () => {
beforeAll(() => {
global.MutationObserver = class {
constructor() {}
disconnect() {}
observe() {}
};
});

afterAll(() => {
delete global.MutationObserver;
});

it('opens when clicked once', () => {
const component = mount(
<EuiAccordion
Expand Down

0 comments on commit c64f055

Please sign in to comment.