I want to make a kind of accordion expanding panel: but I don't want to have a component for accordion and another for a single expanding panel. my objective is to make something like this:
note: I have it working in another environment that uses named event listeners from a specific framework but I want to make it without frameworks, only react ES6
<ExpandingGroup id={'groupOne'} uniqOpen={true}>
  <ExpandingPanel id={'panelOne'}  />
  <ExpandingPanel id={'panelTwo'}  />
  <ExpandingPanel id={'panelThree'}/>
  <ExpandingPanel id={'panelFour'} />
</ExpandingGroup>
So when I click to expand the panel one, it expands it self and when I click on panel two (and uniqOpen flag is on) the panel two will open and panel one will be closed; My problem to play with props and callbacks is that I'll have to pollute the code and have two different components the do the same thing. Why not just nest a group of ExpandingPanels inside a ExpandingGroup scope.
this is my code for the ExpandingPanel: (ignore Row, Column and Label layouts)
import React from 'react';
import PropTypes from 'prop-types';
import Label from 'Base/Components/Label';
import Column from 'Base/Layouts/Column';
import Row from 'Base/Layouts/Row';
class ExpandPanel extends React.Component {
    constructor(props) {
        super(props);
        this.id = this.props.id;
        this.groupId = undefined;
        this.anchorId = `anchor_${this.id}`;
        this.panelId = `panel_${this.id}`;
        this.colors = {
            white: '#ffffff',
            border: '#333333',
        };
        this.dim = {
            minWidth: 40
        }
        this.styles = styles.bind(this);
        this.getMaxHeight = getMaxHeight.bind(this);
        this.handleUniq = handleUniq.bind(this);
        this.handleClose = handleClose.bind(this);
        this.handleOpenPanel = handleOpenPanel.bind(this);
        this.handleToggle = handleToggle.bind(this);
        this.checkExpanded = checkExpanded.bind(this);
        this.setMyGroup = setMyGroup.bind(this);
        this.state = {
            isDrawerOpen: this.props.startOpen,
            height: 'fit-content',
        }
    };
    componentDidMount() {
        setTimeout(() => {
            this.setState({ height: this.getMaxHeight() });
        });
        let myInstance = document.getElementById(this.anchorId);
        this.setMyGroup(myInstance.parentNode.parentNode.parentNode.id);
        window.addEventListener('click', this.checkExpanded);
    };
    componentWillUnmount() {
        window.removeEventListener('click', this.checkExpanded);
    };
    renderAnchor() {
        return (
            <Row id={this.anchorId} height={this.props.anchorHeight} onClick={ this.handleToggle } style={ this.styles('anchor') } >
                {this.props.anchor}
            </Row>
        );
    };
    renderPanel() {
        let height = this.props.autoHeight ? 'auto' : this.props.panelHeight;
        return (
            <Column id={this.panelId} height={height} style={ this.styles('panel') } >
                {this.props.panel}
            </Column>
        )
    };
    render() {
        return (
            <div style={this.styles('margin')}>
                <Column id={'ExpandPanel'} width={'100%'} height={'auto'} boxShadow={true} style={this.styles('root')}>
                    { this.renderAnchor() }
                    { this.renderPanel() }
                </Column>
            </div>
        );
    };
};
function setMyGroup(id) {
    this.groupId = id;
}
function checkExpanded(click) {
    let groupNode = click.path.filter( c => c && c.id && c.id.includes('ExpandGroup_') )[0];
    let groupName = '';
    if (groupNode && groupNode.id) groupName = groupNode.id;
    else {
        console.log('Not ExpandGroup click');
        return null;
    }
    let isUniq = groupName.split('_');
        isUniq = !!(isUniq[isUniq.length -1]);
    if (isUniq) {
        let isMyGroup = groupName === this.groupId;
        if (!isMyGroup) return null;
        let anchorNode = click.path.filter( c => c && c.id && c.id.includes('ExpandPanel') )[0];
        let anchorName = anchorNode.firstChild.id;
        if (isMyGroup && anchorName !== this.anchorId) this.handleClose();
    } else return null;
};
function handleToggle(e) {
    if (this.state.isDrawerOpen) this.handleClose();
    else this.handleOpenPanel();
    this.props.anchorClickCB({id: this.id, isDrawerOpen: !this.state.isDrawerOpen })
};
function handleClose() {
    this.setState({isDrawerOpen: false}, this.props.onClose);
};
function handleOpenPanel() {
    this.setState({isDrawerOpen: true});
};
function handleUniq({paramId, paramGroup}) {
    let sameGroup = this.props.uniqGroup === paramGroup;
    let otherId = this.id !== paramId;
    if ( sameGroup && otherId ) this.handleClose();
};
function getMaxHeight() {
    let panel = document.getElementById(this.panelId);
    if (this.props.autoHeight && panel) {
        return (panel.clientHeight + this.props.anchorHeight);
    }
    return (this.props.panelHeight + this.props.anchorHeight);
};
function styles(option) {
    let rootMargin = this.props.showMargin && this.state.isDrawerOpen ? 10 : 0;
    let panelHeightToogle = this.state.isDrawerOpen ? this.state.height : this.props.anchorHeight;
    let anchorHeight = this.props.anchorHeight < this.dim.minWidth ? this.dim.minWidth : this.props.anchorHeight;
    const styleObject = {
        root: {
            maxHeight: panelHeightToogle,
            minHeight: anchorHeight,
            transition: `max-height ${this.props.transition}s linear`,
            overflow: 'hidden',
            ...this.props.style
        },
        anchor: {
            cursor: 'pointer',
            minHeight: anchorHeight,
            ...this.props.anchorStyle
        },
        panel: {
            width: "100%",
            overflow: 'auto',
            ...this.props.panelStyle
        },
        margin:{
            marginBottom: rootMargin,
            marginTop: rootMargin,
            transition: `margin 0.15s linear`,
        }
    };
    return styleObject[option]
};
ExpandPanel.defaultProps = {
    id: 0,
    uniqOpen: false,
    uniqGroup: 'ExpandPanel',
    anchor: <Row><Label text={'Default Anchor'}/></Row>,
    anchorClickCB: ()=>{},
    onClose: ()=>{},
    anchorHeight: 50,
    anchorStyle: {},
    panel: <Column><Label text={'Default Panel'}/></Column>,
    panelHeight: 200,
    autoHeight: false,
    panelStyle: {},
    showMargin: false,
    startOpen: false,
    transition: 0.45,
    style: {},
};
ExpandPanel.propTypes = {
    id: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]),
    uniqOpen: PropTypes.bool,
    uniqGroup: PropTypes.string,
    anchor: PropTypes.object,
    anchorHeight: PropTypes.number,
    anchorClickCB: PropTypes.func,
    anchorStyle: PropTypes.object,
    panel: PropTypes.object,
    panelHeight: PropTypes.number,
    autoHeight: PropTypes.bool,
    panelStyle: PropTypes.object,
    startOpen: PropTypes.bool,
    transition: PropTypes.number,
    style: PropTypes.object,
};
export default ExpandPanel;
and this is my code for the ExpandGroup:
import React from 'react';
import PropTypes from 'prop-types';
class ExpandGroup extends React.Component {
    constructor(props) {
        super(props);
        this.id = `ExpandGroup_${this.props.id}_${this.props.uniqOpen}`;
    };
    render() {
        return (
            <div id={this.id}>
                {this.props.children}
            </div>
        );
    };
};
ExpandGroup.defaultProps = {
    id: 'default',
    uniqOpen: false,
};
ExpandGroup.propTypes = {
    id: PropTypes.string,
    uniqOpen: PropTypes.bool,
};
export default ExpandGroup;
and this is the call:
render() {
    return (
        <ExpandGroup id={'group-01'} uniqOpen={true}>
            <ExpandPanel id={'bloc-01'}/>,
            <ExpandPanel id={'bloc-02'}/>,
            <ExpandPanel id={'bloc-03'}/>,
        </ExpandGroup>
    );
};
