302 lines
34 KiB
JSON
302 lines
34 KiB
JSON
[
|
|
{
|
|
"name": "AutoLink.md",
|
|
"title": "AutoLink",
|
|
"text": "Renders a string as plaintext, with URLs converted to appropriate `<a>` elements.\n\nUse `String.prototype.split()` and `String.prototype.match()` with a regular expression to find URLs in a string.\nReturn a `<React.Fragment>` with matched URLs rendered as `<a>` elements, dealing with missing protocol prefixes if necessary, and the rest of the string rendered as plaintext.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction AutoLink({ text }) {\n const delimiter = /((?:https?:\\/\\/)?(?:(?:[a-z0-9]?(?:[a-z0-9\\-]{1,61}[a-z0-9])?\\.[^\\.|\\s])+[a-z\\.]*[a-z]+|(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})(?::\\d{1,5})*[a-z0-9.,_\\/~#&=;%+?\\-\\\\(\\\\)]*)/gi;\n\n return (\n <React.Fragment>\n {text.split(delimiter).map(word => {\n let match = word.match(delimiter);\n if (match) {\n let url = match[0];\n return (\n <a href={url.startsWith(\"http\") ? url : `http://${url}`}>{url}</a>\n );\n }\n return word;\n })}\n </React.Fragment>\n );\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <AutoLink text='foo bar baz http://example.org bar' />,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 2,
|
|
"tags": [
|
|
"string",
|
|
"fragment",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Carousel.md",
|
|
"title": "Carousel",
|
|
"text": "Renders a carousel component.\n\nInitially set `state.active` to `0` (index of the first item).\nUse an object, `style`, to hold the styles for the individual components.\nDefine a method, `setActiveItem`, which uses `this.setState` to change the state's `active` property to the index of the next item.\nDefine another method, `changeItem`, which is called by `setActiveItem` after updating the state each time and also when the component\nfirst renders (on `ComponentDidMount`).\nIn the `render()` method, destructure `state`, `style` and `props`, compute if visibility style should be set to `visible` or not for each carousel item while mapping over and applying the combined style to the carousel item component accordingly.\nRender the carousel items using [React.cloneElement](https://reactjs.org/docs/react-api.html#cloneelement) and pass down rest\n`props` along with the computed styles.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass Carousel extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n active: 0\n };\n this.scrollInterval = null;\n this.style = {\n carousel: {\n position: \"relative\"\n },\n carouselItem: {\n position: \"absolute\",\n visibility: \"hidden\"\n },\n visible: {\n visibility: \"visible\"\n }\n };\n }\n componentDidMount() {\n this.changeItem();\n }\n setActiveItem = () => {\n const { carouselItems } = this.props;\n this.setState(\n prevState => ({\n active: (prevState.active + 1) % carouselItems.length\n }),\n this.changeItem\n );\n };\n changeItem = () => {\n this.scrollInterval = setTimeout(this.setActiveItem, 2000);\n };\n render() {\n const { carouselItems, ...rest } = this.props;\n const { active } = this.state;\n const { visible, carousel, carouselItem } = this.style;\n return (\n <div style={carousel}>\n {carouselItems.map((item, index) => {\n const activeStyle = active === index ? visible : {};\n return React.cloneElement(item, {\n ...rest,\n style: {\n ...carouselItem,\n ...activeStyle\n }\n });\n })}\n </div>\n );\n }\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <Carousel\n carouselItems={[\n <div>carousel item 1</div>,\n <div>carousel item 2</div>,\n <div>carousel item 3</div>\n ]}\n />,\n document.getElementById(\"root\")\n);\n ```"
|
|
],
|
|
"expertise": 2,
|
|
"tags": [
|
|
"visual",
|
|
"children",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Collapse.md",
|
|
"title": "Collapse",
|
|
"text": "Renders a component with collapsible content.\n\nUse the value of the `collapsed` prop to determine the initial state of the content (collapsed/expanded).\nSet the `state` of the component to the value of the `collapsed` prop (cast to a boolean value) and bind the `toggleCollapse` method to the component's context.\nUse an object, `style`, to hold the styles for individual components and their states.\nCreate a method, `toggleCollapse`, which uses `Component.prototype.setState` to change the component's `state` from collapsed to expanded and vice versa.\nIn the `render()` method, use a `<div>` to wrap both the `<button>` that alters the component's `state` and the content of the component, passed down via `props.children`.\nDetermine the appearance of the content, based on `state.collapsed` and apply the appropriate CSS rules from the `style` object.\nFinally, update the value of the `aria-expanded` attribute based on `state.collapsed` to make the component accessible.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass Collapse extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n collapsed: !!props.collapsed\n };\n this.style = {\n collapsed: {\n display: 'none'\n },\n expanded: {\n display: 'block'\n },\n buttonStyle: {\n display: 'block',\n width: '100%'\n }\n };\n this.toggleCollapse = this.toggleCollapse.bind(this);\n }\n \n toggleCollapse() {\n this.setState(state => ({ collapsed: !state.collapsed }));\n }\n \n render() {\n return (\n <div>\n <button style={this.style.buttonStyle} onClick={this.toggleCollapse}>\n {this.state.collapsed ? 'Show' : 'Hide'} content\n </button>\n <div \n style= {this.state.collapsed ? this.style.collapsed : this.style.expanded} \n aria-expanded = {this.state.collapsed}\n >\n {this.props.children}\n </div>\n </div>\n );\n }\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <Collapse>\n <h1>This is a collapse</h1>\n <p>Hello world!</p>\n </Collapse>,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 2,
|
|
"tags": [
|
|
"visual",
|
|
"children",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "DataList.md",
|
|
"title": "DataList",
|
|
"text": "Renders a list of elements from an array of primitives.\n\nUse the value of the `isOrdered` prop to conditionally render a `<ol>` or `<ul>` list.\nUse `Array.prototype.map` to render every item in `data` as a `<li>` element, give it a `key` produced from the concatenation of the its index and value.\nOmit the `isOrdered` prop to render a `<ul>` list by default.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction DataList({ isOrdered, data }) {\n const list = data.map((val, i) => (\n <li key={`${i}_${val}`}>{val}</li>\n ));\n return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;\n}\n```",
|
|
"```jsx\nconst names = ['John', 'Paul', 'Mary'];\nReactDOM.render(<DataList data={names}/>, document.getElementById('root'));\nReactDOM.render(<DataList data={names} isOrdered/>, document.getElementById('root'));\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"array",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "DataTable.md",
|
|
"title": "DataTable",
|
|
"text": "Renders a table with rows dynamically created from an array of primitives.\n\nRender a `<table>` element with two columns (`ID` and `Value`).\nUse `Array.prototype.map` to render every item in `data` as a `<tr>` element, consisting of its index and value, give it a `key` produced from the concatenation of the two.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction DataTable({ data }) {\n return (\n <table>\n <thead>\n <tr>\n <th>ID</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n {data.map((val, i) =>\n <tr key={`${i}_${val}`}>\n <td>{i}</td>\n <td>{val}</td>\n </tr>\n )}\n </tbody>\n </table>\n );\n}\n```",
|
|
"```jsx\nconst people = ['John', 'Jesse'];\nReactDOM.render(\n <DataTable data={people} />,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"array",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Input.md",
|
|
"title": "Input",
|
|
"text": "Renders an `<input>` element that uses a callback function to pass its value to the parent component.\n\nUse object destructuring to set defaults for certain attributes of the `<input>` element.\nRender an `<input>` element with the appropriate attributes and use the `callback` function in the `onChange` event to pass the value of the input to the parent.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction Input ({ callback, type = 'text', disabled = false, readOnly = false, placeholder = '' }) {\n return (\n <input\n type={type}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n onChange={({ target: { value } }) => callback(value)}\n />\n );\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <Input type='text' placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"input",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "LimitedTextarea.md",
|
|
"title": "LimitedTextarea",
|
|
"text": "Renders a textarea component with a character limit.\n\nUse 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`.\nCreate 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.\nIn the`render()` method, use a`<div>` to wrap both the`<textarea>` and the `<p>` element that displays the character count and bind the `onChange` event of the `<textarea>` to the `handleChange` method.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass LimitedTextarea extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n content: props.value,\n characterCount: props.value.length,\n limit: props.limit\n };\n this.handleChange = this.handleChange.bind(this);\n }\n \n handleChange(event) {\n let newContent = event.target.value;\n if(newContent.length >= this.state.limit) newContent = newContent.slice(0, this.state.limit);\n this.setState(state => ({ content: newContent, characterCount: newContent.length }));\n }\n render() {\n return (\n <div>\n <textarea \n rows={this.props.rows} \n cols={this.props.cols} \n onChange={this.handleChange} \n value={this.state.content}\n >\n </textarea>\n <p>{this.state.characterCount}/{this.props.limit}</p>\n </div>\n );\n }\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <LimitedTextarea limit={32} value='Hello!' />,\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 `<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 <a href={`mailto:${email}?subject=${subject || \"\"}&body=${body || \"\"}`}>\n {props.children}\n </a>\n );\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <Mailto email=\"foo@bar.baz\" subject=\"Hello\" body=\"Hello world!\">\n Mail me!\n </Mailto>,\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 `<table>` 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 `<th>` element.\nUse `Array.prototype.map` to render each object in the `filteredData` array as a `<tr>` element, containing a `<td>` 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 <table>\n <thead>\n <tr>{propertyNames.map(val => <th key={`h_${val}`}>{val}</th>)}</tr>\n </thead>\n <tbody>\n {filteredData.map((val, i) => (\n <tr key={`i_${i}`}>\n {propertyNames.map(p => <td key={`i_${i}_${p}`}>{val[p]}</td>)}\n </tr>\n ))}\n </tbody>\n </table>\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 <MappedTable data={people} propertyNames={propertyNames} />,\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`.",
|
|
"<!-tags: array,object,functional -->",
|
|
"<!-expertise: 1 -->"
|
|
]
|
|
},
|
|
{
|
|
"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 `<div>` 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 : <div className=\"modal\" onClick={this.modalClick}>\n <div className=\"dialog\">\n <div className=\"dialog-title\">{ this.state.data.title }<span className=\"dialog-close\" onClick={this.close}>+</span></div>\n <div className=\"dialog-content\">\n {\n this.state.data.content\n }\n </div>\n </div>\n </div>\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<ModalDialog />\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: <img src=\"https://github.com/30-seconds/30-seconds-of-react/blob/master/logo.png\"/>\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+.",
|
|
"<!-tags: visual,static,children,state,class -->",
|
|
"<!-expertise: 1 -->"
|
|
]
|
|
},
|
|
{
|
|
"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`<div>` to wrap both the`<input>` and the `<button>` element that toggles the type of the input field.\nFinally, bind the `<button>`'s `onClick` event to the `toggleShown` method.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass PasswordRevealer extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n shown: false\n };\n this.toggleShown = this.toggleShown.bind(this);\n }\n\n toggleShown() {\n this.setState(state => ({ shown: !state.shown }));\n }\n\n render() {\n return (\n <div>\n <input\n type={this.state.shown ? 'text' : 'password'}\n value={this.props.value}\n />\n <button onClick={this.toggleShown}>Show/Hide</button>\n </div>\n );\n }\n}\n```",
|
|
"```jsx\nReactDOM.render(<PasswordRevealer />, document.getElementById('root'));\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"input",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Select.md",
|
|
"title": "Select",
|
|
"text": "Renders a `<select>` element that uses a callback function to pass its value to the parent component.\n\nUse object destructuring to set defaults for certain attributes of the `<select>` element.\nRender a `<select>` element with the appropriate attributes and use the `callback` function in the `onChange` event to pass the value of the textarea to the parent.\nUse destructuring on the `values` array to pass an array of `value` and `text` elements and the `selected` attribute to define the initial `value` of the `<select>` element.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction Select ({ values, callback, disabled = false, readonly = false, selected }) {\n return (\n <select\n disabled={disabled}\n readOnly={readonly}\n onChange={({ target : { value } }) => callback(value)}\n >\n {values.map(([value, text]) => <option selected={selected === value}value={value}>{text}</option>)}\n </select>\n );\n}\n```",
|
|
"```jsx\nlet choices = [\n ['grapefruit', 'Grapefruit'],\n ['lime', 'Lime'],\n ['coconut', 'Coconut'],\n ['mango', 'Mango']\n];\nReactDOM.render(\n <Select values={choices} selected='lime' callback={(val) => console.log(val)}/>,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"input",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "StarRating.md",
|
|
"title": "StarRating",
|
|
"text": "Renders a star rating component.\n\nUse and IIFE to define a functional component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's `state` and return the class component `StarRating`.\nUse the value of the `rating` prop to determine if a valid rating is supplied and store it in `state.rating` (or `0` if invalid or not supplied).\nInitialize `state.selection` to `0`.\nCreate two methods, `hoverOver` and `setRating`, that take an event as argument and update `state.selected` and `state.rating` according to it, bind them both to the component's context.\nIn the `render()` method, create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `state.selection` to `0`, the `onClick` event to set\nthe `state.rating` and the `onMouseOver` event to set `state.selection` to the `star-id` attribute of the `event.target` respectively. \nFinally, pass the appropriate values to each `<Star>` component (`starId` and `marked`).\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nconst StarRating = (function() {\n function Star({ marked, starId }) {\n return (\n <span star-id={starId} style={{ color: '#ff9933' }} role='button'>\n {marked ? '\\u2605' : '\\u2606'}\n </span>\n );\n }\n\n return class StarRating extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n rating: typeof props.rating == 'number' ? props.rating : 0,\n selection: 0\n };\n this.hoverOver = this.hoverOver.bind(this);\n this.hoverOut = this.hoverOver.bind(this, null);\n this.handleClick = this.handleClick.bind(this);\n }\n hoverOver(event) {\n let val = 0;\n if (event && event.target && event.target.getAttribute('star-id'))\n val = event.target.getAttribute('star-id');\n this.setState(state => ({ selection: val }));\n }\n handleClick(event) {\n const val = event.target.getAttribute('star-id') || this.state.rating;\n this.setState(state => ({ rating: val }));\n }\n render() {\n return (\n <div\n onMouseOut={this.hoverOut}\n onClick={this.handleClick}\n onMouseOver={this.hoverOver}\n >\n {Array.from({ length: 5 }, (v, i) => (\n <Star\n starId={i+1}\n key={`star_${i+1} `}\n marked={\n this.state.selection\n ? this.state.selection >= i+1\n : this.state.rating >= i+1\n }\n />\n ))}\n </div>\n );\n }\n };\n})();\n```",
|
|
"```jsx\nReactDOM.render(<StarRating/>, document.getElementById('root'));\nReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));\n```"
|
|
],
|
|
"expertise": 2,
|
|
"tags": [
|
|
"visual",
|
|
"children",
|
|
"input",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Tabs.md",
|
|
"title": "Tab",
|
|
"text": "Renders a tabbed menu and view component.\n\nDefine `TabItem` as a middleware, pass it to the `Tab` and remove unnecessary nodes expect for `TabItem` by identifying the function's name in `props.children`.\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 `state.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```",
|
|
"```jsx\nclass Tab extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n bindIndex: props.defaultIndex\n };\n }\n changeTab(newIndex) {\n if (typeof this.props.onTabClick === \"function\")\n this.props.onTabClick(newIndex);\n this.setState({\n bindIndex: newIndex\n });\n }\n buttonClass(index) {\n return this.state.bindIndex === index ? \"focus\" : \"\";\n }\n itemStyle(index) {\n return {\n display: this.state.bindIndex === index ? \"block\" : \"none\"\n };\n }\n render() {\n const items = this.props.children.filter(\n item => item.type.name === \"TabItem\"\n );\n return (\n <div className=\"wrapper\">\n <div className=\"tab-menu\">\n {items.map(({ props: { index, label } }) => (\n <button\n onClick={() => this.changeTab(index)}\n className={this.buttonClass(index)}\n >\n {label}\n </button>\n ))}\n </div>\n <div className=\"tab-view\">\n {items.map(({ props }) => (\n <div\n {...props}\n className=\"tab-view_item\"\n key={props.index}\n style={this.itemStyle(props.index)}\n />\n ))}\n </div>\n </div>\n );\n }\n}\nfunction TabItem(props) {\n return <div {...props} />;\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <Tab defaultIndex=\"1\" onTabClick={console.log}>\n <TabItem label=\"A\" index=\"1\">\n Lorem ipsum\n </TabItem>\n <TabItem label=\"B\" index=\"2\">\n Dolor sit amet\n </TabItem>\n </Tab>,\n document.getElementById(\"root\")\n);\n\n```"
|
|
],
|
|
"expertise": 1,
|
|
"tags": [
|
|
"visual",
|
|
"children",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "TextArea.md",
|
|
"title": "TextArea",
|
|
"text": "Renders a `<textarea>` element that uses a callback function to pass its value to the parent component.\n\nUse object destructuring to set defaults for certain attributes of the `<textarea>` element.\nRender a `<textarea>` element with the appropriate attributes and use the `callback` function in the `onChange` event to pass the value of the textarea to the parent.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nfunction TextArea ({ callback, cols = 20, rows = 2, disabled = false, readOnly = false, placeholder='' }) {\n return (\n <textarea\n cols={cols}\n rows={rows}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n onChange={({ target : { value } }) => callback(value)}\n />\n );\n}\n```",
|
|
"```jsx\nReactDOM.render(\n <TextArea placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,\n document.getElementById('root')\n);\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"input",
|
|
"functional"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Ticker.md",
|
|
"title": "Ticker",
|
|
"text": "Renders a ticker component.\n\n- The ticker state is initially set to zero \n- When the `Tick!` button is clicked, `timer` is incremented periodically at the given `interval`\n- When the `Reset` button is clicked, the value of the timer is set to zero and the `setInterval` is cleared\n- The `setInterval` is cleared once the desired `time` is reached\n- `time` and `interval` are the required props\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass Ticker extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\t\tthis.state = {ticker: 0}\n\t\tthis.interval = null\n\t}\n\n\ttick = () => {\n\t\tthis.reset()\n\t\tthis.interval = setInterval(() => {\n\t\t\tif (this.state.ticker < this.props.times) {\n\t\t\t\tthis.setState(({ ticker }) => ({ticker: ticker + 1}))\n\t\t\t}else{\n\t\t\t\tclearInterval(this.interval)\n\t\t\t}\n\t\t}, this.props.interval)\n\t}\n\n\treset = () => {\n\t\tthis.setState({ticker: 0})\n\t\tclearInterval(this.interval)\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t<div>\n\t\t\t\t<span style={{fontSize: 100}}>{this.state.ticker}</span> \n\t\t\t\t<button onClick={this.tick}>Tick!</button>\n\t\t\t\t<button onClick={this.reset}>Reset</button>\n\t\t\t</div>\n\t\t);\n\t}\n}\n```",
|
|
"```jsx\nReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));\n```"
|
|
],
|
|
"expertise": 1,
|
|
"tags": [
|
|
"visual",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Toggle.md",
|
|
"title": "Toggle",
|
|
"text": "Renders a toggle component.\n\nInitialize `state.isToggleOn` to `false`, bind the `handleClick` method to the component's context.\nUse an object, `style`, to hold the styles for individual components and their states.\nCreate a method, `handleClick`, which uses `Component.prototype.setState` to change the component's `state.toggleOn`.\nIn the `render()` method, destructure `state` and `style`, create a `<button>` that alters the component's `state` and determine the appearance of the content based on `state.isToggleOn`, applying the appropriate CSS rules from the `style` object.\n\n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass Toggle extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n isToggleOn: false\n };\n this.style = {\n on: {\n backgroundColor: 'green'\n },\n off: {\n backgroundColor: 'grey'\n }\n };\n\n this.handleClick = this.handleClick.bind(this);\n }\n\n handleClick() {\n this.setState(state => ({\n isToggleOn: !state.isToggleOn\n }));\n }\n\n render() {\n const { isToggleOn } = this.state;\n const { on, off } = this.style;\n\n return (\n <button\n onClick={this.handleClick}\n style={isToggleOn ? on : off}\n >\n {isToggleOn ? 'ON' : 'OFF'}\n </button>\n );\n }\n}\n```",
|
|
"```jsx\nReactDOM.render(<Toggle />, document.getElementById('root'));\n```"
|
|
],
|
|
"expertise": 0,
|
|
"tags": [
|
|
"visual",
|
|
"state",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
},
|
|
{
|
|
"name": "Tooltip.md",
|
|
"title": "Tooltip",
|
|
"text": "Renders a tooltip component.\n\nSet the `state` of the component to `show: false` initially, define an object, `style`, to hold the styles for individual components and their states.\nCreate a method, `toggleTooltip`, which uses `this.setState` to change the state's `show` property from `true` to `false` and vice versa.\nBind `showTooltip` and `hideTooltip` to the component's context with the respective values of `true` and `false`.\nIn the `render()` method, compute if the tooltip should be shown or hidden, render the content of the tooltip and bind the `onMouseEnter` and `onMouseLeave` events to `showTooltip` and `hideTooltip` respectively.\n \n",
|
|
"codeBlocks": [
|
|
"```jsx\nclass Tooltip extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n show: false\n };\n this.style = {\n tooltip: {\n position: 'relative',\n backgroundColor: \"rgba(0,0,0,0.7)\",\n color: \"white\",\n visibility: \"hidden\",\n width: \"fit-content\",\n padding: 5,\n borderRadius: 5\n },\n tooltipArrow: {\n position: 'absolute',\n top: '100%',\n left: '50%',\n borderWidth: 5,\n borderStyle: 'solid',\n borderColor: \"rgba(0,0,0,0.7) transparent transparent\",\n },\n visible: {\n visibility: \"visible\"\n },\n };\n this.showTooltip = this.toggleTooltip.bind(this, true);\n this.hideTooltip = this.toggleTooltip.bind(this, false);\n }\n\n toggleTooltip = tooltipState => {\n this.setState({\n show: tooltipState\n });\n };\n\n render() {\n const { children, text, ...rest } = this.props;\n const { show } = this.state;\n const { visible, tooltip, tooltipArrow } = this.style;\n const showTooltip = show ? visible : {};\n return (\n <div>\n <div style={{ ...tooltip, ...showTooltip }}>\n {text}\n <span style={tooltipArrow}/>\n </div>\n <div {...rest} onMouseEnter={this.showTooltip} onMouseLeave={this.hideTooltip}>\n {children}\n </div>\n </div>\n );\n }\n}\n```",
|
|
"```jsx\n ReactDOM.render(\n <Tooltip text='Simple tooltip'>\n <button>Hover me!</button>\n </Tooltip>,\n document.getElementById('root')\n );\n```"
|
|
],
|
|
"expertise": 1,
|
|
"tags": [
|
|
"visual",
|
|
"state",
|
|
"children",
|
|
"class"
|
|
],
|
|
"notes": []
|
|
}
|
|
] |