diff --git a/.gitignore b/.gitignore index bee7d76fc..c221276eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# Created by https://www.gitignore.io/api/node - -### Node ### # Logs logs *.log @@ -74,6 +71,3 @@ typings/ # Serverless directories .serverless - - -# End of https://www.gitignore.io/api/node \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..e7e82126a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,81 @@ +# Contribution Guidelines + +**30 seconds of React** is a community effort, so feel free to contribute in any way you can. Every contribution helps! + +Here's what you can do to help: + +- Submit [pull requests](https://github.com/30-seconds/30-seconds-of-react/pulls) with snippets that you have created (see below for guidelines). +- [Open issues](https://github.com/30-seconds/30-seconds-of-react/issues/new) for things you want to see added or modified. +- Be part of the discussion by helping out with [existing issues](https://github.com/30-seconds/30-seconds-of-react/issues). +- Fix typos in existing snippets, improve snippet descriptions and explanations or provide better examples. + +### Snippet submission and Pull request guidelines + +- **DO NOT MODIFY THE README.md or index.html FILES!** Make changes to individual snippet files. **Travis CI** will automatically build the `README.md` and `index.html` files when your pull request is merged. +- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `### AwesomeComponent` the filename should be `AwesomeComponent.md`. + - Use `TitleCase`, not `camelCase`, `kebab-case` or `snake_case` when naming components. + - Avoid capitalization of words, except if the whole word is capitalized (e.g. `URL` should be capitalized in the filename and the snippet title). +- **Snippet titles** should be the same as the name of the component that is present in the snippet. + - All snippet titles must be prefixed with `###` and be at the very first line of your snippet. + - Snippet titles must be unique (although if you cannot find a better title, just add some placeholder at the end of the filename and title and we will figure it out). + - Follow snippet titles with an empty line. +- **Snippet descriptions** must be short and to the point. Try to explain *what* the snippet does and *how* the snippet works and what Javascript/React features are used. Remember to include what functions you are using and why. + - Follow snippet descriptions with an empty line. +- **Snippet code** must be enclosed inside ` ```jsx ` and ` ``` `. + - If your snippet is accompanied by CSS code, enclose it inside ` ```css ` and ` ``` ` and present it before the JS/JSX code. + - Remember to start your snippet's code on a new line below the opening backticks. + - Use standard function notation to define your component. For example `function MyComponent(props) { ... }`. + - Do not write components using classes, use [React Hooks](https://reactjs.org/docs/hooks-intro.html) instead. + - Please use Javascript [Semi-Standard Style](https://github.com/Flet/semistandard). + - Try to keep your snippets' code short and to the point. Use modern techniques and features. Make sure to test your code before submitting. + - All snippets must be followed by one (more if necessary) test case after the code, in a new block enclosed inside ` ```jsx ` and ` ``` `. The syntax for this is `ReactDOM.render(, document.getElementById("root"));`. Use multiline examples only if necessary. + - Try to make your component name unique, so that it does not conflict with existing snippets. +- Snippets should be as brief as possible, without sacrificing functionality. If your snippet seems longer than most, you can still submit it, and we can help you shorten it or figure out ways to improve it. +- Snippets *should* solve real-world problems, no matter how simple. +- Snippets *should* be abstract enough to be applied to different scenarios. +- You can start creating a new snippet, by using the [snippet template](snippet-template.md) to format your snippets. + +### Additional guidelines and conventions regarding snippets + +- When describing snippets, refer to methods, using their full name. For example, use `Array.prototype.reduce()`, instead of `reduce()`. +- When using React Hooks, refer to the specific hooks with their full names, such as `React.useState()` and `React.useEffect()`. +- When using `React.useState()`, try matching the name of the state variable to the function that sets it. For example, use `[isShown, setIsShown]` instead of `[isShown, setShown]`. +- When using `React.useEffect()`, only return a function if you have to clean up. In that case, name that function `cleanup()`. +- Destructure your component's `props` whenever possible. If any of your props take default parameters, specify their default values in the destructured object. +- If your snippet uses recursion, explain the base cases. +- Always use `function MyComponent(props)` or `function MyComponent({ ... })` for function definitions. +- Use variables only when necessary. Prefer `const` when the values are not altered after assignment, otherwise, use `let`. Avoid using `var`. +- Use `camelCase` for function and variable names, if they consist of more than one word. +- Use `TitleCase` for component names. +- Try to give meaningful names to variables. For example use `letter`, instead of `lt`. Some exceptions to convention are: + - `arr` for arrays (usually as the snippet function's argument). + - `str` for strings. + - `num` or `n` for a numeric value (usually as the snippet function's argument). + - `el` for DOM elements (usually as the snippet function's argument). + - `val` or `v` for value (usually when iterating a list, mapping, sorting etc.). + - `acc` for accumulators in `Array.prototype.reduce()`. + - `(a,b)` for the two values compared when using `Array.prototype.sort()`. + - `i` for indexes. + - `fn` for function arguments. + - `nums` for arrays of numbers. +- Use `()` if your function takes no arguments. +- Use `_` if an argument inside some function (e.g. `Array.prototype.reduce()`) is not used anywhere in your code. +- Specify default parameters for arguments, if necessary. It is preferred to put default parameters last unless you have a pretty good reason not to. +- If your snippet's function takes variadic arguments, use `...args` or `...rest` (although in certain cases, it might be needed to use a different name). +- Always use soft tabs (2 spaces), never hard tabs. +- Omit curly braces (`{` and `}`) whenever possible. +- Always use single quotes for string literals. Use template literals, instead, if necessary. +- When rendering JSX, use double quotes, instead of single quotes. +- Prefer using `Array` methods whenever possible. +- Prefer `Array.prototype.concat()` instead of `Array.prototype.push()` when working with `Array.prototype.reduce()`. +- Use strict equality checking (`===` and `!==` instead of `==` and `!=`), unless you specifically have reason not to. +- Prefer using the ternary operator (`condition ? trueResult : falseResult`) instead of `if else` statements whenever possible. +- Avoid nesting ternary operators (but you can do it if you feel like you should). +- You should define multiple variables (e.g. `const x = 0, y = 0`) on the same line whenever possible. +- Do not use trailing or leading underscores in variable names. +- Use dot notation (`object.property`) for object properties, when possible. Use bracket notation (`object[variable]`) when accessing object properties using a variable. +- Use arrow functions as much as possible, except when you can't. +- Use semicolons whenever necessary. +- Leave a single space after a comma (`,`) character. +- Try to strike a balance between readability, brevity, and performance. +- Never use `eval()`. Your snippet will be disqualified immediately. \ No newline at end of file diff --git a/README.md b/README.md index 6dc107662..0918b5193 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,1411 @@ > Curated collection of useful React snippets that you can understand in 30 seconds or less. -**This repository is a work in progress. If you want to contribute, please check the open issues to see where and how you can help out!** +* Use Ctrl + F or command + F to search for a snippet. +* Contributions welcome, please read the [contribution guide](CONTRIBUTING.md). +* Snippets are written in React 16.8+, using hooks. + +### Prerequisites + +To import a snippet into your project, you must import `React` and copy-paste the component's JavaScript code like this: +```js +import React from 'react'; + +function MyComponent(props) { + /* ... */ +} +``` + +If there is any CSS related to your component, copy-paste it to a new file with the same name and the appropriate extension, then import it like this: +```js +import './MyComponent.css'; +``` + +To render your component, make sure there is a node with and id of `"root"` present in your element (preferrably a `
`) and that you have imported `ReactDOM`, like this: +```js +import ReactDOM from 'react-dom'; +``` + +#### 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) +* [LimitedWordTextarea](#limitedwordtextarea) +* [MultiselectCheckbox](#multiselectcheckbox) +* [PasswordRevealer](#passwordrevealer) +* [Select](#select) +* [TextArea](#textarea) +
+ + +### Object + +
+View contents + +* [TreeView](#treeview) +
+ + +### String + +
+View contents + +* [AutoLink](#autolink) +
+ + +### Visual + +
+View contents + +* [Carousel](#carousel) +* [Collapse](#collapse) +* [CountDown](#countdown) +* [FileDrop](#filedrop) +* [Mailto](#mailto) +* [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 `React.useState()` hook to create the `content` state variable and set its value to `value`. +Create a method `setFormattedContent`, which trims the content of the input if it's longer than `limit`. +Use the `React.useEffect()` hook to call the `setFormattedContent` method on the value of the `content` state variable. +Use a`
        ` to wrap both the`