React

by Abdul Ahmad

HTML

<div id="app"></div>

SCSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
  box-sizing: border-box;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

.accordion {
  // border: 1px dashed #ddd;
  max-width: 500px;
  
  >.title {
    padding: 10px 0;
    font-size: 18px;
  }
  
  .items {
    
  }
}

.accordion-item {
  border: 1px solid #ddd;
  border-radius: 5px;
  padding: 20px;
  margin-top: 3px;
  
  .top-row {
    display: flex;
    align-items: center;
  }
  
  .title {
    font-weight: bold;
    flex-grow: 1;
    flex-shrink: 1;
  }
  
  .collapser {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #aaa;
    transition: all 0.15s ease;

    &:hover {
      cursor: pointer;
      background: tomato;
      transition: all 0.15s ease;
    }
  }
  
  .content {
    margin-top: 10px;
  }
}

React

function AccordionItemOne(props) {
	return (
    <AccordionItem title='Item 1' { ...props }>
      Content 1
    </AccordionItem>
  );
}
function AccordionItemTwo(props) {
	return (
    <AccordionItem title='Item 2' { ...props }>
      Content 2
    </AccordionItem>
  );
}

function App() {
	const accordionItems = [
  	AccordionItemOne,
    AccordionItemTwo,
  ].map((Item, index) => (
  	<Item index={index} accordionName='Accordion1' />
  ));
  
	return (
  	<Accordion title='Accordion1'>
  	  { accordionItems }
  	</Accordion>
  );
}

function Accordion({ title, children }) {  
  const { state, setState, clearState } = useAccordionState({ 
  	numItems: children.length,
    expandedItems: [0],
  });
  
	return (
  	<div className='accordion'>
  	  <h3 className='title'>{ title }</h3>
      <div className='items'>
        { children }
      </div>
  	</div>
  );
}

function AccordionItem({ 
	title, 
  children, 
  index,
  accordionName,
}) {
	const { state } = useAccordionState({ accordionName });
	return (
  	<div className='accordion-item'>
      <div className='top-row'>
        <h4 className='title'>{ title }</h4>
        <div className='collapser' />
      </div>
      { !collapsed && (
      	<div className='content'>
          { children }
        </div>
      )}
  	</div>
  );
}

const accordionStates = {};
function getAccordionState({ accordionName, numItems, expandedItems } = {}) {
	let state = accordionStates[accordionName];
  
  if (!state) {
  	state = { 
    	numItems,
      expandedItems: expandedItems || [],
    };
    accordionStates[accordionName] = state;
  }
  
  return state;
}


function useAccordionState({ accordionName, numItems, expandedItems } = {}) {
	const initialState = getAccordionState({ accordionName, numItems, expandedItems });
	const [state, _setState] = React.useState(initialState);
  
  function submitItem() {
  	
  }
  
  function setState(newState) {
  	_setState({ ...newState });
    accordionStates[accordionName] = {...