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 {
max-width: 500px;
}
.accordion-step {
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px;
margin-top: 5px;
&:first-child {
margin-top: 0;
}
.top-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.toggle {
width: 15px;
height: 15px;
background: #ddd;
border-radius: 50%;
&:hover {
cursor: pointer;
background: teal;
}
}
.title {
font-weight: bold;
}
.content {
margin-top: 10px;
}
}
React
function SomeForm({ submitCallback }) {
const handleSubmit = React.useCallback(e => {
e.preventDefault();
submitCallback();
}, []);
return (
<form onSubmit={handleSubmit}>
<button type='submit'>
submit
</button>
</form>
);
}
function App() {
return (
<Accordion
initialExpandedItems={[0]}
steps={[
{ title: 'Step 1', content: ({ submitCallback }) => <SomeForm submitCallback={submitCallback} /> },
{ title: 'Step 2', content: 'step 2 content' },
{ title: 'Step 3', content: 'step 3 content' },
]}
/>
);
}
ReactDOM.render((<App />), document.querySelector("#app"));
function AccordionStep({ title, children, expanded, onClickToggle, onComplete, index }) {
const handleClick = React.useCallback(() => {
onClickToggle({ index });
}, [index, onClickToggle]);
return (
<div className='accordion-step'>
<div className='top-row'>
<h3 className='title'>
{ title }
</h3>
<div className='toggle' onClick={handleClick} />
</div>
{
expanded && (
<div className='content'>
{ children }
</div>
)
}
</div>
);
}
function Accordion({ steps, initialExpandedItems }) {
const [expandedItems, setExpandedItems] = React.useState([ ...initialExpandedItems ]);
const [enabledItems, setEnabledItems] = React.useState([...initialExpandedItems]);
const toggle = React.useCallback(({ index } = {}) => {
const itemIsEnabled = enabledItems.findIndex(i => i === index) !== -1;
if (!itemIsEnabled) return;
const expandedItemIndex = expandedItems.findIndex(i => i === index);
let newExpandedItems;
if (expandedItemIndex !== -1) {
newExpandedItems = [...expandedItems];
newExpandedItems.splice(expandedItemIndex, 1);
} else {
newExpandedItems = [...expandedItems, index];
}
setExpandedItems(newExpandedItems);
}, [expandedItems]);
const...