From c9d1d1a898c436a3bc12c15523ada4a75563a1ba Mon Sep 17 00:00:00 2001 From: le-mahf <46358903+le-mahf@users.noreply.github.com> Date: Wed, 6 Feb 2019 07:58:09 +0000 Subject: [PATCH 1/7] Add hooks version --- snippets/PasswordRevealer.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/snippets/PasswordRevealer.md b/snippets/PasswordRevealer.md index 731f1030b..bc973b696 100644 --- a/snippets/PasswordRevealer.md +++ b/snippets/PasswordRevealer.md @@ -2,6 +2,8 @@ Renders a password input field with a reveal button. +#### Class version + Initially set `state.shown` to `false` to ensure that the password is not shown by default. Create a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context. In the`render()` method, use a`
` to wrap both the`` and the ` +
+ ) +} +``` + +```jsx +ReactDOM.render( + , + document.getElementById('root') +); +``` + + From c81c326ec204ee4cecdecadbeba1b5b6d0e15c1e Mon Sep 17 00:00:00 2001 From: le-mahf <46358903+le-mahf@users.noreply.github.com> Date: Wed, 6 Feb 2019 12:39:31 +0000 Subject: [PATCH 2/7] Create CountDown.md --- snippets/CountDown.md | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 snippets/CountDown.md diff --git a/snippets/CountDown.md b/snippets/CountDown.md new file mode 100644 index 000000000..a6568c62f --- /dev/null +++ b/snippets/CountDown.md @@ -0,0 +1,94 @@ +### CountDown + +Renders a countdown timer that prints a message when it reaches zero. + +- The timer starts automatically with the initial value passed through the `props` +- Each second, `tick()` is called. It updates the timer, decreasing the time by one second each time. +- If the `pause` button is clicked, `tick()` refrains from updating the time until the `resume` button is clicked. +- If the `restart` button is clicked, the timer starts over from step 1 +- If the time hits zero, the message 'Time's up!' is printed + +```jsx +class CountDown extends React.Component { + constructor(props) { + super(props); + this.state = { + paused: false, + done: false, + s: parseInt(this.props.seconds), + m: parseInt(this.props.minutes), + h: parseInt(this.props.hours) + }; + + this.tick = this.tick.bind(this); + this.pause = this.pause.bind(this); + this.reset = this.reset.bind(this); + + this.timerID = setInterval(this.tick, 1000); + } + + tick() { + if (this.state.paused) { + return; + } + + if (this.state.s === 0 && this.state.m === 0 && this.state.h === 0) { + clearInterval(this.timerID); + this.setState({ + done: true + }); + } else if (this.state.m === 0 && this.state.s === 0) { + this.setState(state => ({ + h: state.h - 1, + m: 59, + s: 59 + })); + } else if (this.state.s === 0) { + this.setState(state => ({ + m: state.m - 1, + s: 59 + })); + } else { + this.setState(state => ({ + s: state.s - 1 + })) + } + } + + pause() { + this.setState(state => ({ + paused: !state.paused + })) + } + + reset() { + clearInterval(this.timerID); + this.setState({ + paused: false, + done: false, + s: parseInt(this.props.seconds), + m: parseInt(this.props.minutes), + h: parseInt(this.props.hours) + }); + this.timerID = setInterval(this.tick, 1000); + } + + render() { + return ( +
+

{this.state.h.toString().padStart(2, '0') + ':' + this.state.m.toString().padStart(2, '0') + ':' + this.state.s.toString().padStart(2, '0')}

+ + +

{this.state.done ? "Time's up!" : ''}

+
+ ) + } +} +``` + +```jsx +ReactDOM.render( + , + document.getElementById('root') +); +``` From 2f79031e0e5abbd13dd7898b617cf726149f7b03 Mon Sep 17 00:00:00 2001 From: Mahf Date: Wed, 6 Feb 2019 13:09:02 +0000 Subject: [PATCH 3/7] Revert "Merge pull request #1 from 30-seconds/master" This reverts commit 285b5b96237275feb8ca83130f3211fe3d5f453b, reversing changes made to b9382db30bd1725298eb11dc4c7ba6ad9906349d. --- .gitignore | 1 - README.md | 1174 +--------------------------------- data/snippet_data.json | 302 --------- package-lock.json | 521 --------------- package.json | 30 - scripts/build.js | 104 --- scripts/extract.js | 59 -- scripts/util.js | 95 --- snippets/Collapse.md | 2 +- snippets/FileDrop.md | 117 ---- snippets/LimitedTextarea.md | 4 +- snippets/Mailto.md | 2 +- snippets/Ticker.md | 4 - static-parts/README-end.md | 5 - static-parts/README-start.md | 13 - 15 files changed, 5 insertions(+), 2428 deletions(-) delete mode 100644 .gitignore delete mode 100644 data/snippet_data.json delete mode 100644 package-lock.json delete mode 100644 package.json delete mode 100644 scripts/build.js delete mode 100644 scripts/extract.js delete mode 100644 scripts/util.js delete mode 100644 snippets/FileDrop.md delete mode 100644 static-parts/README-end.md delete mode 100644 static-parts/README-start.md diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b512c09d4..000000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/README.md b/README.md index e307f7443..6dc107662 100644 --- a/README.md +++ b/README.md @@ -4,1176 +4,4 @@ > Curated collection of useful React snippets that you can understand in 30 seconds or less. -#### Related projects - -* [30 Seconds of Code](https://30secondsofcode.org) -* [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/) -* [30 Seconds of Interviews](https://30secondsofinterviews.org/) - -## Table of Contents - - -### Array - -
-View contents - -* [DataList](#datalist) -* [DataTable](#datatable) -* [MappedTable](#mappedtable) -
- - -### Input - -
-View contents - -* [Input](#input) -* [LimitedTextarea](#limitedtextarea) -* [PasswordRevealer](#passwordrevealer) -* [Select](#select) -* [TextArea](#textarea) -
- - -### String - -
-View contents - -* [AutoLink](#autolink) -
- - -### Visual - -
-View contents - -* [Carousel](#carousel) -* [Collapse](#collapse) -* [Mailto](#mailto) -* [ModalDialog](#modaldialog) -* [StarRating](#starrating) -* [Tab](#tab) -* [Ticker](#ticker) -* [Toggle](#toggle) -* [Tooltip](#tooltip) -
- - ---- - -## Array -### DataList - -Renders a list of elements from an array of primitives. - -Use the value of the `isOrdered` prop to conditionally render a `
    ` or `
      ` list. -Use `Array.prototype.map` to render every item in `data` as a `
    • ` element, give it a `key` produced from the concatenation of the its index and value. -Omit the `isOrdered` prop to render a `
        ` list by default. - -```jsx -function DataList({ isOrdered, data }) { - const list = data.map((val, i) => ( -
      • {val}
      • - )); - return isOrdered ?
          {list}
        :
          {list}
        ; -} -``` - -
        -Examples - -```jsx -const names = ['John', 'Paul', 'Mary']; -ReactDOM.render(, document.getElementById('root')); -ReactDOM.render(, document.getElementById('root')); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - -### DataTable - -Renders a table with rows dynamically created from an array of primitives. - -Render a `` element with two columns (`ID` and `Value`). -Use `Array.prototype.map` to render every item in `data` as a `` element, consisting of its index and value, give it a `key` produced from the concatenation of the two. - -```jsx -function DataTable({ data }) { - return ( -
        - - - - - - - - {data.map((val, i) => - - - - - )} - -
        IDValue
        {i}{val}
        - ); -} -``` - -
        -Examples - -```jsx -const people = ['John', 'Jesse']; -ReactDOM.render( - , - document.getElementById('root') -); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - -### MappedTable - -Renders a table with rows dynamically created from an array of objects and a list of property names. - -Use `Object.keys()`, `Array.prototype.filter()`, `Array.prototype.includes()` and `Array.prototype.reduce()` to produce a `filteredData` array, containing all objects with the keys specified in `propertyNames`. -Render a `` element with a set of columns equal to the amount of values in `propertyNames`. -Use `Array.prototype.map` to render each value in the `propertyNames` array as a `` element, containing a `
        ` element. -Use `Array.prototype.map` to render each object in the `filteredData` array as a `
        ` for each key in the object. - -```jsx -function MappedTable({ data, propertyNames }) { - let filteredData = data.map(v => - Object.keys(v) - .filter(k => propertyNames.includes(k)) - .reduce((acc, key) => ((acc[key] = v[key]), acc), {}) - ); - return ( - - - {propertyNames.map(val => )} - - - {filteredData.map((val, i) => ( - - {propertyNames.map(p => )} - - ))} - -
        {val}
        {val[p]}
        - ); -} -``` -#### Notes - -This component does not work with nested objects and will break if there are nested objects inside any of the properties specified in `propertyNames`.,, - -
        -Examples - -```jsx -const people = [ - { name: 'John', surname: 'Smith', age: 42 }, - { name: 'Adam', surname: 'Smith', gender: 'male' } -]; -const propertyNames = ['name', 'surname', 'age']; -ReactDOM.render( - , - document.getElementById('root') -); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - - -## Input -### Input - -Renders an `` element that uses a callback function to pass its value to the parent component. - -Use object destructuring to set defaults for certain attributes of the `` element. -Render an `` element with the appropriate attributes and use the `callback` function in the `onChange` event to pass the value of the input to the parent. - -```jsx -function Input ({ callback, type = 'text', disabled = false, readOnly = false, placeholder = '' }) { - return ( - callback(value)} - /> - ); -} -``` - -
        -Examples - -```jsx -ReactDOM.render( - console.log(val)}/>, - document.getElementById('root') -); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - -### LimitedTextarea - -Renders a textarea component with a character limit. - -Use the value of the `value` prop to determine the initial `state.content` and `state.characterCount` and the value of the `limit` props to determine the value of `state.limit`. -Create a method, `handleChange`, which trims the `event.target.value` data if necessary and uses `Component.prototype.setState` to update `state.content` and `state.characterCount`, and bind it to the component's context. -In the`render()` method, use a`
        ` to wrap both the` -

        {this.state.characterCount}/{this.props.limit}

        -
        - ); - } -} -``` - -
        -Examples - -```jsx -ReactDOM.render( - , - document.getElementById('root') -); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - -### PasswordRevealer - -Renders a password input field with a reveal button. - -Initially set `state.shown` to `false` to ensure that the password is not shown by default. -Create a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context. -In the`render()` method, use a`
        ` to wrap both the`` and the ` -
        - ); - } -} -``` - -
        -Examples - -```jsx -ReactDOM.render(, document.getElementById('root')); -``` -
        - -
        [⬆ Back to top](#table-of-contents) - -### Select - -Renders a `` element. -Render a `` element. - -```jsx -function Select ({ values, callback, disabled = false, readonly = false, selected }) { - return ( - - ); -} -``` - -
        -Examples - -```jsx -let choices = [ - ['grapefruit', 'Grapefruit'], - ['lime', 'Lime'], - ['coconut', 'Coconut'], - ['mango', 'Mango'] -]; -ReactDOM.render( - \n

        {this.state.characterCount}/{this.props.limit}

        \n \n );\n }\n}\n```", - "```jsx\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" - ], - "expertise": 0, - "tags": [ - "input", - "state", - "class" - ], - "notes": [] - }, - { - "name": "Mailto.md", - "title": "Mailto", - "text": "Renders a link formatted to send an email.\n\nDestructure the component's props, use `email`, `subject` and `body` to create a `` element with an appropriate `href` attribute.\nRender the link with `props.children` as its content.\n\n", - "codeBlocks": [ - "```jsx\nfunction Mailto({ email, subject, body, ...props }) {\n return (\n \n {props.children}\n \n );\n}\n```", - "```jsx\nReactDOM.render(\n \n Mail me!\n ,\n document.getElementById(\"root\")\n);\n```" - ], - "expertise": 0, - "tags": [ - "visual", - "functional" - ], - "notes": [] - }, - { - "name": "MappedTable.md", - "title": "MappedTable", - "text": "Renders a table with rows dynamically created from an array of objects and a list of property names.\n\nUse `Object.keys()`, `Array.prototype.filter()`, `Array.prototype.includes()` and `Array.prototype.reduce()` to produce a `filteredData` array, containing all objects with the keys specified in `propertyNames`.\nRender a `` element with a set of columns equal to the amount of values in `propertyNames`.\nUse `Array.prototype.map` to render each value in the `propertyNames` array as a `` element, containing a `
        ` element.\nUse `Array.prototype.map` to render each object in the `filteredData` array as a `
        ` for each key in the object.\n\n", - "codeBlocks": [ - "```jsx\nfunction MappedTable({ data, propertyNames }) {\n let filteredData = data.map(v =>\n Object.keys(v)\n .filter(k => propertyNames.includes(k))\n .reduce((acc, key) => ((acc[key] = v[key]), acc), {})\n );\n return (\n \n \n {propertyNames.map(val => )}\n \n \n {filteredData.map((val, i) => (\n \n {propertyNames.map(p => )}\n \n ))}\n \n
        {val}
        {val[p]}
        \n );\n}\n```", - "```jsx\nconst people = [\n { name: 'John', surname: 'Smith', age: 42 },\n { name: 'Adam', surname: 'Smith', gender: 'male' }\n];\nconst propertyNames = ['name', 'surname', 'age'];\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" - ], - "expertise": 1, - "tags": [ - "array", - "object", - "functional" - ], - "notes": [ - "This component does not work with nested objects and will break if there are nested objects inside any of the properties specified in `propertyNames`.", - "", - "" - ] - }, - { - "name": "ModalDialog.md", - "title": "ModalDialog", - "text": "Renders a dialog component in a modal, controllable through events. \nTo use the component, import `ModalDialog` only once and then display it using `ModalDialog.show()`, passing the JSX templates and data as parameters.\n\nDefine `modalHandler`, a method that will handle showing the modal dialog, set `state` to the default values initially and bind the `close` and `modalClick` methods to the component's context.\nDefine `close` and `modalClick` to toggle the visibility of the modal dialog, based on `state.closeOnClick`.\nUse the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.\n\nThe `show()` method accepts an argument, that should contain three parameters:\n* `title`, a string for the dialog's title\n* `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the *X* button\n* `content`, which is the JSX content to be rendered inside the dialog\n\nFinally, in the `render()` method, use a `
        ` to wrap everything and render the modal dialog with the content passed to `show()`.\n\n", - "codeBlocks": [ - "```css\n .modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.6);\n z-index: 9998;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .dialog {\n background-color: white;\n border-radius: 5px;\n overflow: hidden;\n }\n .dialog-title {\n box-sizing: border-box;\n width: 100%;\n height: 48px;\n padding: 0 16px;\n border-bottom: 0.5px solid #c3c3c3;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .dialog-close {\n font-size: 32px;\n color: #c3c3c3;\n cursor: pointer;\n transform: rotate(45deg);\n user-select: none;\n }\n .dialog-close:hover {\n color: red;\n }\n .dialog-content {\n min-width: 300px;\n }\n```", - "```jsx\nclass ModalDialog extends React.Component {\n constructor() {\n super();\n this.modalHandler = (e) => {\n this.setState({\n data: e.detail.data,\n visible: true\n });\n };\n this.state = {\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n },\n visible: false\n };\n this.close = this.close.bind(this);\n this.modalClick = this.modalClick.bind(this);\n }\n render() {\n return !this.state.visible ? null :
        \n
        \n
        { this.state.data.title }+
        \n
        \n {\n this.state.data.content\n }\n
        \n
        \n
        \n }\n componentDidMount() {\n document.addEventListener('modal', this.modalHandler);\n }\n componentWillUnmount() {\n document.removeEventListener('modal', this.modalHandler);\n }\n close() {\n this.setState({\n visible: false,\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n }\n });\n }\n static show(data) {\n document.dispatchEvent(new CustomEvent('modal', {\n detail: {\n data\n }\n }));\n }\n modalClick() {\n if (this.state.data.closeOnClick) this.close();\n }\n}\n```", - "```jsx\n// add to render function\n\n\n// every time you wanna call the dialog\n// content is a jsx element\nModalDialog.show({\n title: 'Hello, world!',\n closeOnClick: true,\n content: \n}); \n```" - ], - "expertise": 1, - "tags": [ - "visual", - "static", - "children", - "state", - "class" - ], - "notes": [ - "This component includes a lot of CSS, which might conflict with other CSS in your project. It is recomended for the modal to be a direct child of the body tag.", - "A more up-to-date method with lower compatibility is to use [Portals](https://reactjs.org/docs/portals.html) in React 16+.", - "", - "" - ] - }, - { - "name": "PasswordRevealer.md", - "title": "PasswordRevealer", - "text": "Renders a password input field with a reveal button.\n\nInitially set `state.shown` to `false` to ensure that the password is not shown by default.\nCreate a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context.\nIn the`render()` method, use a`
        ` to wrap both the`` and the `\n
        \n );\n }\n}\n```", - "```jsx\nReactDOM.render(, document.getElementById('root'));\n```" - ], - "expertise": 0, - "tags": [ - "input", - "state", - "class" - ], - "notes": [] - }, - { - "name": "Select.md", - "title": "Select", - "text": "Renders a `` element.\nRender a `` element.\n\n", - "codeBlocks": [ - "```jsx\nfunction Select ({ values, callback, disabled = false, readonly = false, selected }) {\n return (\n callback(value)}\n >\n {values.map(([value, text]) => )}\n \n );\n}\n```", - "```jsx\nlet choices = [\n ['grapefruit', 'Grapefruit'],\n ['lime', 'Lime'],\n ['coconut', 'Coconut'],\n ['mango', 'Mango']\n];\nReactDOM.render(\n +

        {this.state.characterCount}/{this.props.limit}

        +
        + ); + } +} +``` + +
        +Examples + +```jsx +ReactDOM.render( + , + document.getElementById('root') +); +``` +
        + +
        [⬆ Back to top](#table-of-contents) + +### PasswordRevealer + +Renders a password input field with a reveal button. + +Initially set `state.shown` to `false` to ensure that the password is not shown by default. +Create a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context. +In the`render()` method, use a`
        ` to wrap both the`` and the ` +
        + ); + } +} +``` + +
        +Examples + +```jsx +ReactDOM.render(, document.getElementById('root')); +``` +
        + +
        [⬆ Back to top](#table-of-contents) + +### Select + +Renders a `` element. +Render a `` element. + +```jsx +function Select ({ values, callback, disabled = false, readonly = false, selected }) { + return ( + + ); +} +``` + +
        +Examples + +```jsx +let choices = [ + ['grapefruit', 'Grapefruit'], + ['lime', 'Lime'], + ['coconut', 'Coconut'], + ['mango', 'Mango'] +]; +ReactDOM.render( + \n

        {this.state.characterCount}/{this.props.limit}

        \n \n );\n }\n}\n```", + "```jsx\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 0, + "tags": [ + "input", + "state", + "class" + ], + "notes": [] + }, + { + "name": "Mailto.md", + "title": "Mailto", + "text": "Renders a link formatted to send an email.\n\nDestructure the component's props, use `email`, `subject` and `body` to create a `` element with an appropriate `href` attribute.\nRender the link with `props.children` as its content.\n\n", + "codeBlocks": [ + "```jsx\nfunction Mailto({ email, subject, body, ...props }) {\n return (\n \n {props.children}\n \n );\n}\n```", + "```jsx\nReactDOM.render(\n \n Mail me!\n ,\n document.getElementById(\"root\")\n);\n```" + ], + "expertise": 0, + "tags": [ + "visual", + "functional" + ], + "notes": [] + }, + { + "name": "MappedTable.md", + "title": "MappedTable", + "text": "Renders a table with rows dynamically created from an array of objects and a list of property names.\n\nUse `Object.keys()`, `Array.prototype.filter()`, `Array.prototype.includes()` and `Array.prototype.reduce()` to produce a `filteredData` array, containing all objects with the keys specified in `propertyNames`.\nRender a `` element with a set of columns equal to the amount of values in `propertyNames`.\nUse `Array.prototype.map` to render each value in the `propertyNames` array as a `` element, containing a `
        ` element.\nUse `Array.prototype.map` to render each object in the `filteredData` array as a `
        ` for each key in the object.\n\n", + "codeBlocks": [ + "```jsx\nfunction MappedTable({ data, propertyNames }) {\n let filteredData = data.map(v =>\n Object.keys(v)\n .filter(k => propertyNames.includes(k))\n .reduce((acc, key) => ((acc[key] = v[key]), acc), {})\n );\n return (\n \n \n {propertyNames.map(val => )}\n \n \n {filteredData.map((val, i) => (\n \n {propertyNames.map(p => )}\n \n ))}\n \n
        {val}
        {val[p]}
        \n );\n}\n```", + "```jsx\nconst people = [\n { name: 'John', surname: 'Smith', age: 42 },\n { name: 'Adam', surname: 'Smith', gender: 'male' }\n];\nconst propertyNames = ['name', 'surname', 'age'];\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 1, + "tags": [ + "array", + "object", + "functional" + ], + "notes": [ + "This component does not work with nested objects and will break if there are nested objects inside any of the properties specified in `propertyNames`.", + "", + "" + ] + }, + { + "name": "ModalDialog.md", + "title": "ModalDialog", + "text": "Renders a dialog component in a modal, controllable through events. \nTo use the component, import `ModalDialog` only once and then display it using `ModalDialog.show()`, passing the JSX templates and data as parameters.\n\nDefine `modalHandler`, a method that will handle showing the modal dialog, set `state` to the default values initially and bind the `close` and `modalClick` methods to the component's context.\nDefine `close` and `modalClick` to toggle the visibility of the modal dialog, based on `state.closeOnClick`.\nUse the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.\n\nThe `show()` method accepts an argument, that should contain three parameters:\n* `title`, a string for the dialog's title\n* `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the *X* button\n* `content`, which is the JSX content to be rendered inside the dialog\n\nFinally, in the `render()` method, use a `
        ` to wrap everything and render the modal dialog with the content passed to `show()`.\n\n", + "codeBlocks": [ + "```css\n .modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.6);\n z-index: 9998;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .dialog {\n background-color: white;\n border-radius: 5px;\n overflow: hidden;\n }\n .dialog-title {\n box-sizing: border-box;\n width: 100%;\n height: 48px;\n padding: 0 16px;\n border-bottom: 0.5px solid #c3c3c3;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .dialog-close {\n font-size: 32px;\n color: #c3c3c3;\n cursor: pointer;\n transform: rotate(45deg);\n user-select: none;\n }\n .dialog-close:hover {\n color: red;\n }\n .dialog-content {\n min-width: 300px;\n }\n```", + "```jsx\nclass ModalDialog extends React.Component {\n constructor() {\n super();\n this.modalHandler = (e) => {\n this.setState({\n data: e.detail.data,\n visible: true\n });\n };\n this.state = {\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n },\n visible: false\n };\n this.close = this.close.bind(this);\n this.modalClick = this.modalClick.bind(this);\n }\n render() {\n return !this.state.visible ? null :
        \n
        \n
        { this.state.data.title }+
        \n
        \n {\n this.state.data.content\n }\n
        \n
        \n
        \n }\n componentDidMount() {\n document.addEventListener('modal', this.modalHandler);\n }\n componentWillUnmount() {\n document.removeEventListener('modal', this.modalHandler);\n }\n close() {\n this.setState({\n visible: false,\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n }\n });\n }\n static show(data) {\n document.dispatchEvent(new CustomEvent('modal', {\n detail: {\n data\n }\n }));\n }\n modalClick() {\n if (this.state.data.closeOnClick) this.close();\n }\n}\n```", + "```jsx\n// add to render function\n\n\n// every time you wanna call the dialog\n// content is a jsx element\nModalDialog.show({\n title: 'Hello, world!',\n closeOnClick: true,\n content: \n}); \n```" + ], + "expertise": 1, + "tags": [ + "visual", + "static", + "children", + "state", + "class" + ], + "notes": [ + "This component includes a lot of CSS, which might conflict with other CSS in your project. It is recomended for the modal to be a direct child of the body tag.", + "A more up-to-date method with lower compatibility is to use [Portals](https://reactjs.org/docs/portals.html) in React 16+.", + "", + "" + ] + }, + { + "name": "PasswordRevealer.md", + "title": "PasswordRevealer", + "text": "Renders a password input field with a reveal button.\n\nInitially set `state.shown` to `false` to ensure that the password is not shown by default.\nCreate a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context.\nIn the`render()` method, use a`
        ` to wrap both the`` and the `\n
        \n );\n }\n}\n```", + "```jsx\nReactDOM.render(, document.getElementById('root'));\n```" + ], + "expertise": 0, + "tags": [ + "input", + "state", + "class" + ], + "notes": [] + }, + { + "name": "Select.md", + "title": "Select", + "text": "Renders a `` element.\nRender a `` element.\n\n", + "codeBlocks": [ + "```jsx\nfunction Select ({ values, callback, disabled = false, readonly = false, selected }) {\n return (\n callback(value)}\n >\n {values.map(([value, text]) => )}\n \n );\n}\n```", + "```jsx\nlet choices = [\n ['grapefruit', 'Grapefruit'],\n ['lime', 'Lime'],\n ['coconut', 'Coconut'],\n ['mango', 'Mango']\n];\nReactDOM.render(\n