Create Accordion
This commit is contained in:
91
README.md
91
README.md
@ -91,13 +91,14 @@ import ReactDOM from 'react-dom';
|
||||
<details>
|
||||
<summary>View contents</summary>
|
||||
|
||||
* [Accordion](#accordion)
|
||||
* [Carousel](#carousel)
|
||||
* [Collapse](#collapse)
|
||||
* [CountDown](#countdown)
|
||||
* [FileDrop](#filedrop)
|
||||
* [Mailto](#mailto)
|
||||
* [StarRating](#starrating)
|
||||
* [Tab](#tab)
|
||||
* [Tabs](#tabs)
|
||||
* [Ticker](#ticker)
|
||||
* [Toggle](#toggle)
|
||||
* [Tooltip](#tooltip)
|
||||
@ -771,6 +772,92 @@ ReactDOM.render(
|
||||
|
||||
|
||||
## Visual
|
||||
### Accordion
|
||||
|
||||
Renders an accordion menu with multiple collapsible content components.
|
||||
|
||||
Define an `AccordionItem` component, pass it to the `Accordion` and remove unnecessary nodes expect for `AccordionItem` by identifying the function's name in `props.children`.
|
||||
Each `AccordionItem` component renders a `<button>` that is used to update the `Accordion` via the `props.handleClick` callback and the content of the component, passed down via `props.children`, while its appearance is determined by `props.isCollapsed` and based on `style`.
|
||||
In the `Accordion` component, use the `React.useState()` hook to initialize the value of the `bindIndex` state variable to `props.defaultIndex`.
|
||||
Use `Array.prototype.map` on the collected nodes to render the individual collapsiple elements.
|
||||
Define `changeItem`, which will be executed when clicking an `AccordionItem`'s `<button>`.
|
||||
`changeItem` executes the passed callback, `onItemClick` and updates `bindIndex` based on the clicked element.
|
||||
|
||||
```jsx
|
||||
function AccordionItem(props) {
|
||||
const style = {
|
||||
collapsed: {
|
||||
display: 'none'
|
||||
},
|
||||
expanded: {
|
||||
display: 'block'
|
||||
},
|
||||
buttonStyle: {
|
||||
display: 'block',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button style={style.buttonStyle} onClick={() => props.handleClick()}>
|
||||
{props.label}
|
||||
</button>
|
||||
<div
|
||||
className="collapse-content"
|
||||
style={props.isCollapsed ? style.collapsed : style.expanded}
|
||||
aria-expanded={props.isCollapsed}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Accordion(props) {
|
||||
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
||||
|
||||
const changeItem = itemIndex => {
|
||||
if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);
|
||||
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
|
||||
};
|
||||
const items = props.children.filter(item => item.type.name === 'AccordionItem');
|
||||
|
||||
return (
|
||||
<div className="wrapper">
|
||||
{items.map(({ props }) => (
|
||||
<AccordionItem
|
||||
isCollapsed={bindIndex === props.index}
|
||||
label={props.label}
|
||||
handleClick={() => changeItem(props.index)}
|
||||
children={props.children}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
```jsx
|
||||
ReactDOM.render(
|
||||
<Accordion defaultIndex="1" onItemClick={console.log}>
|
||||
<AccordionItem label="A" index="1">
|
||||
Lorem ipsum
|
||||
</AccordionItem>
|
||||
<AccordionItem label="B" index="2">
|
||||
Dolor sit amet
|
||||
</AccordionItem>
|
||||
</Accordion>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
</details>
|
||||
|
||||
<br>[⬆ Back to top](#table-of-contents)
|
||||
|
||||
### Carousel
|
||||
|
||||
Renders a carousel component.
|
||||
@ -1177,7 +1264,7 @@ ReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));
|
||||
|
||||
<br>[⬆ Back to top](#table-of-contents)
|
||||
|
||||
### Tab
|
||||
### Tabs
|
||||
|
||||
Renders a tabbed menu and view component.
|
||||
|
||||
|
||||
@ -1,4 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "Accordion.md",
|
||||
"title": "Accordion",
|
||||
"text": "Renders an accordion menu with multiple collapsible content components.\n\nDefine an `AccordionItem` component, pass it to the `Accordion` and remove unnecessary nodes expect for `AccordionItem` by identifying the function's name in `props.children`.\nEach `AccordionItem` component renders a `<button>` that is used to update the `Accordion` via the `props.handleClick` callback and the content of the component, passed down via `props.children`, while its appearance is determined by `props.isCollapsed` and based on `style`.\nIn the `Accordion` component, use the `React.useState()` hook to initialize the value of the `bindIndex` state variable to `props.defaultIndex`.\nUse `Array.prototype.map` on the collected nodes to render the individual collapsiple elements.\nDefine `changeItem`, which will be executed when clicking an `AccordionItem`'s `<button>`.\n`changeItem` executes the passed callback, `onItemClick` and updates `bindIndex` based on the clicked element.\n\n",
|
||||
"codeBlocks": [
|
||||
"```jsx\nfunction AccordionItem(props) {\n const style = {\n collapsed: {\n display: 'none'\n },\n expanded: {\n display: 'block'\n },\n buttonStyle: {\n display: 'block',\n width: '100%'\n }\n };\n\n return (\n <div>\n <button style={style.buttonStyle} onClick={() => props.handleClick()}>\n {props.label}\n </button>\n <div\n className=\"collapse-content\"\n style={props.isCollapsed ? style.collapsed : style.expanded}\n aria-expanded={props.isCollapsed}\n >\n {props.children}\n </div>\n </div>\n );\n}\n\nfunction Accordion(props) {\n const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);\n\n const changeItem = itemIndex => {\n if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);\n if (itemIndex !== bindIndex) setBindIndex(itemIndex);\n };\n const items = props.children.filter(item => item.type.name === 'AccordionItem');\n\n return (\n <div className=\"wrapper\">\n {items.map(({ props }) => (\n <AccordionItem\n isCollapsed={bindIndex === props.index}\n label={props.label}\n handleClick={() => changeItem(props.index)}\n children={props.children}\n />\n ))}\n </div>\n );\n}\n```",
|
||||
"```jsx\nReactDOM.render(\n <Accordion defaultIndex=\"1\" onItemClick={console.log}>\n <AccordionItem label=\"A\" index=\"1\">\n Lorem ipsum\n </AccordionItem>\n <AccordionItem label=\"B\" index=\"2\">\n Dolor sit amet\n </AccordionItem>\n </Accordion>,\n document.getElementById('root')\n);\n```"
|
||||
],
|
||||
"expertise": 2,
|
||||
"tags": [
|
||||
"visual",
|
||||
"children",
|
||||
"state"
|
||||
],
|
||||
"notes": []
|
||||
},
|
||||
{
|
||||
"name": "AutoLink.md",
|
||||
"title": "AutoLink",
|
||||
@ -266,7 +282,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Tabs.md",
|
||||
"title": "Tab",
|
||||
"title": "Tabs",
|
||||
"text": "Renders a tabbed menu and view component.\n\nDefine a `TabItem` component, pass it to the `Tab` and remove unnecessary nodes expect for `TabItem` by identifying the function's name in `props.children`.\nUse the `React.useState()` hook to initialize the value of the `bindIndex` state variable to `props.defaultIndex`.\nUse `Array.prototype.map` on the collected nodes to render the `tab-menu` and `tab-view`.\nDefine `changeTab`, which will be executed when clicking a `<button>` from the `tab-menu`.\n`changeTab` executes the passed callback, `onTabClick` and updates `bindIndex`, which in turn causes a re-render, evaluating the `style` and `className` of the `tab-view` items and `tab-menu` buttons according to their `index`.\n\n",
|
||||
"codeBlocks": [
|
||||
"```css\n.tab-menu > button {\n cursor: pointer;\n padding: 8px 16px;\n border: 0;\n border-bottom: 2px solid transparent;\n background: none;\n}\n.tab-menu > button.focus {\n border-bottom: 2px solid #007bef;\n}\n.tab-menu > button:hover {\n border-bottom: 2px solid #007bef;\n}\n```",
|
||||
|
||||
83
snippets/Accordion.md
Normal file
83
snippets/Accordion.md
Normal file
@ -0,0 +1,83 @@
|
||||
### Accordion
|
||||
|
||||
Renders an accordion menu with multiple collapsible content components.
|
||||
|
||||
Define an `AccordionItem` component, pass it to the `Accordion` and remove unnecessary nodes expect for `AccordionItem` by identifying the function's name in `props.children`.
|
||||
Each `AccordionItem` component renders a `<button>` that is used to update the `Accordion` via the `props.handleClick` callback and the content of the component, passed down via `props.children`, while its appearance is determined by `props.isCollapsed` and based on `style`.
|
||||
In the `Accordion` component, use the `React.useState()` hook to initialize the value of the `bindIndex` state variable to `props.defaultIndex`.
|
||||
Use `Array.prototype.map` on the collected nodes to render the individual collapsiple elements.
|
||||
Define `changeItem`, which will be executed when clicking an `AccordionItem`'s `<button>`.
|
||||
`changeItem` executes the passed callback, `onItemClick` and updates `bindIndex` based on the clicked element.
|
||||
|
||||
```jsx
|
||||
function AccordionItem(props) {
|
||||
const style = {
|
||||
collapsed: {
|
||||
display: 'none'
|
||||
},
|
||||
expanded: {
|
||||
display: 'block'
|
||||
},
|
||||
buttonStyle: {
|
||||
display: 'block',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button style={style.buttonStyle} onClick={() => props.handleClick()}>
|
||||
{props.label}
|
||||
</button>
|
||||
<div
|
||||
className="collapse-content"
|
||||
style={props.isCollapsed ? style.collapsed : style.expanded}
|
||||
aria-expanded={props.isCollapsed}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Accordion(props) {
|
||||
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
||||
|
||||
const changeItem = itemIndex => {
|
||||
if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);
|
||||
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
|
||||
};
|
||||
const items = props.children.filter(item => item.type.name === 'AccordionItem');
|
||||
|
||||
return (
|
||||
<div className="wrapper">
|
||||
{items.map(({ props }) => (
|
||||
<AccordionItem
|
||||
isCollapsed={bindIndex === props.index}
|
||||
label={props.label}
|
||||
handleClick={() => changeItem(props.index)}
|
||||
children={props.children}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```jsx
|
||||
ReactDOM.render(
|
||||
<Accordion defaultIndex="1" onItemClick={console.log}>
|
||||
<AccordionItem label="A" index="1">
|
||||
Lorem ipsum
|
||||
</AccordionItem>
|
||||
<AccordionItem label="B" index="2">
|
||||
Dolor sit amet
|
||||
</AccordionItem>
|
||||
</Accordion>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
<!-- tags: visual,children,state -->
|
||||
|
||||
<!-- expertise: 2 -->
|
||||
Reference in New Issue
Block a user