Ran linter
This commit is contained in:
@ -19,7 +19,7 @@ Here's what you can do to help:
|
|||||||
- All snippet titles must be prefixed with `###` and be at the very first line of your 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).
|
- 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.
|
- 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.
|
- **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.
|
- Follow snippet descriptions with an empty line.
|
||||||
- **Snippet code** must be enclosed inside ` ```jsx ` and ` ``` `.
|
- **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.
|
- If your snippet is accompanied by CSS code, enclose it inside ` ```css ` and ` ``` ` and present it before the JS/JSX code.
|
||||||
@ -31,8 +31,8 @@ Here's what you can do to help:
|
|||||||
- 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(<MyComponent />, document.getElementById("root"));`. Use multiline examples only if necessary.
|
- 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(<MyComponent />, 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.
|
- 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 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_ solve real-world problems, no matter how simple.
|
||||||
- Snippets *should* be abstract enough to be applied to different scenarios.
|
- 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.
|
- 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
|
### Additional guidelines and conventions regarding snippets
|
||||||
|
|||||||
384
README.md
384
README.md
@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
> Curated collection of useful React snippets that you can understand in 30 seconds or less.
|
> Curated collection of useful React snippets that you can understand in 30 seconds or less.
|
||||||
|
|
||||||
* Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet.
|
- Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet.
|
||||||
* Contributions welcome, please read the [contribution guide](CONTRIBUTING.md).
|
- Contributions welcome, please read the [contribution guide](CONTRIBUTING.md).
|
||||||
* Snippets are written in React 16.8+, using hooks.
|
- Snippets are written in React 16.8+, using hooks.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
To import a snippet into your project, you must import `React` and copy-paste the component's JavaScript code like this:
|
To import a snippet into your project, you must import `React` and copy-paste the component's JavaScript code like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@ -20,89 +21,86 @@ 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:
|
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
|
```js
|
||||||
import './MyComponent.css';
|
import './MyComponent.css';
|
||||||
```
|
```
|
||||||
|
|
||||||
To render your component, make sure there is a node with and id of `"root"` present in your element (preferrably a `<div>`) and that you have imported `ReactDOM`, like this:
|
To render your component, make sure there is a node with and id of `"root"` present in your element (preferrably a `<div>`) and that you have imported `ReactDOM`, like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Related projects
|
#### Related projects
|
||||||
|
|
||||||
* [30 Seconds of Code](https://30secondsofcode.org)
|
- [30 Seconds of Code](https://30secondsofcode.org)
|
||||||
* [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/)
|
- [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/)
|
||||||
* [30 Seconds of Interviews](https://30secondsofinterviews.org/)
|
- [30 Seconds of Interviews](https://30secondsofinterviews.org/)
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
|
|
||||||
### Array
|
### Array
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View contents</summary>
|
<summary>View contents</summary>
|
||||||
|
|
||||||
* [DataList](#datalist)
|
- [DataList](#datalist)
|
||||||
* [DataTable](#datatable)
|
- [DataTable](#datatable)
|
||||||
* [MappedTable](#mappedtable)
|
- [MappedTable](#mappedtable)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
### Input
|
### Input
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View contents</summary>
|
<summary>View contents</summary>
|
||||||
|
|
||||||
* [Input](#input)
|
- [Input](#input)
|
||||||
* [LimitedTextarea](#limitedtextarea)
|
- [LimitedTextarea](#limitedtextarea)
|
||||||
* [LimitedWordTextarea](#limitedwordtextarea)
|
- [LimitedWordTextarea](#limitedwordtextarea)
|
||||||
* [MultiselectCheckbox](#multiselectcheckbox)
|
- [MultiselectCheckbox](#multiselectcheckbox)
|
||||||
* [PasswordRevealer](#passwordrevealer)
|
- [PasswordRevealer](#passwordrevealer)
|
||||||
* [Select](#select)
|
- [Select](#select)
|
||||||
* [TextArea](#textarea)
|
- [TextArea](#textarea)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
### Object
|
### Object
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View contents</summary>
|
<summary>View contents</summary>
|
||||||
|
|
||||||
* [TreeView](#treeview)
|
- [TreeView](#treeview)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
### String
|
### String
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View contents</summary>
|
<summary>View contents</summary>
|
||||||
|
|
||||||
* [AutoLink](#autolink)
|
- [AutoLink](#autolink)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
### Visual
|
### Visual
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>View contents</summary>
|
<summary>View contents</summary>
|
||||||
|
|
||||||
* [Carousel](#carousel)
|
- [Carousel](#carousel)
|
||||||
* [Collapse](#collapse)
|
- [Collapse](#collapse)
|
||||||
* [CountDown](#countdown)
|
- [CountDown](#countdown)
|
||||||
* [FileDrop](#filedrop)
|
- [FileDrop](#filedrop)
|
||||||
* [Mailto](#mailto)
|
- [Mailto](#mailto)
|
||||||
* [StarRating](#starrating)
|
- [StarRating](#starrating)
|
||||||
* [Tab](#tab)
|
- [Tab](#tab)
|
||||||
* [Ticker](#ticker)
|
- [Ticker](#ticker)
|
||||||
* [Toggle](#toggle)
|
- [Toggle](#toggle)
|
||||||
* [Tooltip](#tooltip)
|
- [Tooltip](#tooltip)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Array
|
## Array
|
||||||
|
|
||||||
### DataList
|
### DataList
|
||||||
|
|
||||||
Renders a list of elements from an array of primitives.
|
Renders a list of elements from an array of primitives.
|
||||||
@ -113,9 +111,7 @@ Omit the `isOrdered` prop to render a `<ul>` list by default.
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function DataList({ isOrdered, data }) {
|
function DataList({ isOrdered, data }) {
|
||||||
const list = data.map((val, i) => (
|
const list = data.map((val, i) => <li key={`${i}_${val}`}>{val}</li>);
|
||||||
<li key={`${i}_${val}`}>{val}</li>
|
|
||||||
));
|
|
||||||
return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
|
return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -128,6 +124,7 @@ const names = ['John', 'Paul', 'Mary'];
|
|||||||
ReactDOM.render(<DataList data={names} />, document.getElementById('root'));
|
ReactDOM.render(<DataList data={names} />, document.getElementById('root'));
|
||||||
ReactDOM.render(<DataList data={names} isOrdered />, document.getElementById('root'));
|
ReactDOM.render(<DataList data={names} isOrdered />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -150,12 +147,12 @@ function DataTable({ data }) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{data.map((val, i) =>
|
{data.map((val, i) => (
|
||||||
<tr key={`${i}_${val}`}>
|
<tr key={`${i}_${val}`}>
|
||||||
<td>{i}</td>
|
<td>{i}</td>
|
||||||
<td>{val}</td>
|
<td>{val}</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
@ -167,11 +164,9 @@ function DataTable({ data }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const people = ['John', 'Jesse'];
|
const people = ['John', 'Jesse'];
|
||||||
ReactDOM.render(
|
ReactDOM.render(<DataTable data={people} />, document.getElementById('root'));
|
||||||
<DataTable data={people} />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -195,12 +190,18 @@ function MappedTable({ data, propertyNames }) {
|
|||||||
return (
|
return (
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>{propertyNames.map(val => <th key={`h_${val}`}>{val}</th>)}</tr>
|
<tr>
|
||||||
|
{propertyNames.map(val => (
|
||||||
|
<th key={`h_${val}`}>{val}</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{filteredData.map((val, i) => (
|
{filteredData.map((val, i) => (
|
||||||
<tr key={`i_${i}`}>
|
<tr key={`i_${i}`}>
|
||||||
{propertyNames.map(p => <td key={`i_${i}_${p}`}>{val[p]}</td>)}
|
{propertyNames.map(p => (
|
||||||
|
<td key={`i_${i}_${p}`}>{val[p]}</td>
|
||||||
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -208,6 +209,7 @@ function MappedTable({ data, propertyNames }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Notes
|
#### 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 -->,<!-expertise: 1 -->
|
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 -->,<!-expertise: 1 -->
|
||||||
@ -226,12 +228,13 @@ ReactDOM.render(
|
|||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
|
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
### Input
|
### Input
|
||||||
|
|
||||||
Renders an `<input>` element that uses a callback function to pass its value to the parent component.
|
Renders an `<input>` element that uses a callback function to pass its value to the parent component.
|
||||||
@ -258,10 +261,11 @@ function Input ({ callback, type = 'text', disabled = false, readOnly = false, p
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Input type='text' placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,
|
<Input type="text" placeholder="Insert some text here..." callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -307,11 +311,9 @@ function LimitedTextarea({ rows, cols, value, limit }) {
|
|||||||
<summary>Examples</summary>
|
<summary>Examples</summary>
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(<LimitedTextarea limit={32} value="Hello!" />, document.getElementById('root'));
|
||||||
<LimitedTextarea limit={32} value='Hello!' />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -332,13 +334,13 @@ function LimitedWordTextarea({ rows, cols, value, limit }) {
|
|||||||
const [wordCount, setWordCount] = React.useState(0);
|
const [wordCount, setWordCount] = React.useState(0);
|
||||||
|
|
||||||
const setFormattedContent = text => {
|
const setFormattedContent = text => {
|
||||||
let words = text.split(" ");
|
let words = text.split(' ');
|
||||||
if (words.filter(Boolean).length > limit) {
|
if (words.filter(Boolean).length > limit) {
|
||||||
setContent(
|
setContent(
|
||||||
text
|
text
|
||||||
.split(" ")
|
.split(' ')
|
||||||
.slice(0, limit)
|
.slice(0, limit)
|
||||||
.join(" ")
|
.join(' ')
|
||||||
);
|
);
|
||||||
setWordCount(limit);
|
setWordCount(limit);
|
||||||
} else {
|
} else {
|
||||||
@ -372,10 +374,11 @@ function LimitedWordTextarea({ rows, cols, value, limit }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<LimitedWordTextArea limit={5} value='Hello there!' />,
|
<LimitedWordTextArea limit={5} value="Hello there!" />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -404,25 +407,20 @@ const style = {
|
|||||||
function MultiselectCheckbox({ options, onChange }) {
|
function MultiselectCheckbox({ options, onChange }) {
|
||||||
const [data, setData] = React.useState(options);
|
const [data, setData] = React.useState(options);
|
||||||
|
|
||||||
const toggle = (item) => {
|
const toggle = item => {
|
||||||
data.map((_, key) => {
|
data.map((_, key) => {
|
||||||
if (data[key].label === item.label)
|
if (data[key].label === item.label) data[key].checked = !item.checked;
|
||||||
data[key].checked = !item.checked;
|
|
||||||
});
|
});
|
||||||
setData([...data]);
|
setData([...data]);
|
||||||
onChange(data);
|
onChange(data);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul style={style.listContainer}>
|
<ul style={style.listContainer}>
|
||||||
{data.map(item => {
|
{data.map(item => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={item.label} style={style.itemStyle} onClick={() => toggle(item)}>
|
||||||
key={item.label}
|
<input readOnly type="checkbox" checked={item.checked || false} />
|
||||||
style={style.itemStyle}
|
|
||||||
onClick={() => toggle(item)}
|
|
||||||
>
|
|
||||||
<input readOnly type='checkbox' checked={item.checked || false} />
|
|
||||||
{item.label}
|
{item.label}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@ -436,7 +434,7 @@ function MultiselectCheckbox ({ options, onChange }) {
|
|||||||
<summary>Examples</summary>
|
<summary>Examples</summary>
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const options = [{ label: "Item One" }, { label: "Item Two" }];
|
const options = [{ label: 'Item One' }, { label: 'Item Two' }];
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<MultiselectCheckbox
|
<MultiselectCheckbox
|
||||||
@ -445,9 +443,10 @@ ReactDOM.render(
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -465,11 +464,7 @@ function PasswordRevealer({ value }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input type={shown ? 'text' : 'password'} value={value} onChange={() => {}} />
|
||||||
type={shown ? "text" : "password"}
|
|
||||||
value={value}
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<button onClick={() => setShown(!shown)}>Show/Hide</button>
|
<button onClick={() => setShown(!shown)}>Show/Hide</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -482,6 +477,7 @@ function PasswordRevealer({ value }) {
|
|||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(<PasswordRevealer />, document.getElementById('root'));
|
ReactDOM.render(<PasswordRevealer />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -502,7 +498,11 @@ function Select ({ values, callback, disabled = false, readonly = false, selecte
|
|||||||
readOnly={readonly}
|
readOnly={readonly}
|
||||||
onChange={({ target: { value } }) => callback(value)}
|
onChange={({ target: { value } }) => callback(value)}
|
||||||
>
|
>
|
||||||
{values.map(([value, text]) => <option selected={selected === value}value={value}>{text}</option>)}
|
{values.map(([value, text]) => (
|
||||||
|
<option selected={selected === value} value={value}>
|
||||||
|
{text}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -519,10 +519,11 @@ let choices = [
|
|||||||
['mango', 'Mango']
|
['mango', 'Mango']
|
||||||
];
|
];
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Select values={choices} selected='lime' callback={(val) => console.log(val)}/>,
|
<Select values={choices} selected="lime" callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -535,7 +536,14 @@ Use object destructuring to set defaults for certain attributes of the `<textare
|
|||||||
Render 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.
|
Render 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.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function TextArea ({ callback, cols = 20, rows = 2, disabled = false, readOnly = false, placeholder='' }) {
|
function TextArea({
|
||||||
|
callback,
|
||||||
|
cols = 20,
|
||||||
|
rows = 2,
|
||||||
|
disabled = false,
|
||||||
|
readOnly = false,
|
||||||
|
placeholder = ''
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
cols={cols}
|
cols={cols}
|
||||||
@ -554,16 +562,17 @@ function TextArea ({ callback, cols = 20, rows = 2, disabled = false, readOnly =
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<TextArea placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,
|
<TextArea placeholder="Insert some text here..." callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
|
|
||||||
|
|
||||||
## Object
|
## Object
|
||||||
|
|
||||||
### TreeView
|
### TreeView
|
||||||
|
|
||||||
Renders a tree view of a JSON object or array with collapsible content.
|
Renders a tree view of a JSON object or array with collapsible content.
|
||||||
@ -625,19 +634,18 @@ function TreeView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ marginLeft: isChildElement ? 16 : 4 + "px" }}
|
style={{ marginLeft: isChildElement ? 16 : 4 + 'px' }}
|
||||||
className={isParentToggled ? "tree-element" : "tree-element collapsed"}
|
className={isParentToggled ? 'tree-element' : 'tree-element collapsed'}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={isToggled ? "toggler" : "toggler closed"}
|
className={isToggled ? 'toggler' : 'toggler closed'}
|
||||||
onClick={() => setIsToggled(!isToggled)}
|
onClick={() => setIsToggled(!isToggled)}
|
||||||
/>
|
/>
|
||||||
{name ? <strong> {name}: </strong> : <span> </span>}
|
{name ? <strong> {name}: </strong> : <span> </span>}
|
||||||
{Array.isArray(data) ? "[" : "{"}
|
{Array.isArray(data) ? '[' : '{'}
|
||||||
{!isToggled && "..."}
|
{!isToggled && '...'}
|
||||||
{Object.keys(data).map(
|
{Object.keys(data).map((v, i, a) =>
|
||||||
(v, i, a) =>
|
typeof data[v] == 'object' ? (
|
||||||
typeof data[v] == "object" ? (
|
|
||||||
<TreeView
|
<TreeView
|
||||||
data={data[v]}
|
data={data[v]}
|
||||||
isLast={i === a.length - 1}
|
isLast={i === a.length - 1}
|
||||||
@ -647,17 +655,17 @@ function TreeView({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<p
|
<p
|
||||||
style={{ marginLeft: 16 + "px" }}
|
style={{ marginLeft: 16 + 'px' }}
|
||||||
className={isToggled ? "tree-element" : "tree-element collapsed"}
|
className={isToggled ? 'tree-element' : 'tree-element collapsed'}
|
||||||
>
|
>
|
||||||
{Array.isArray(data) ? "" : <strong>{v}: </strong>}
|
{Array.isArray(data) ? '' : <strong>{v}: </strong>}
|
||||||
{data[v]}
|
{data[v]}
|
||||||
{i === a.length - 1 ? "" : ","}
|
{i === a.length - 1 ? '' : ','}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{Array.isArray(data) ? "]" : "}"}
|
{Array.isArray(data) ? ']' : '}'}
|
||||||
{!isLast ? "," : ""}
|
{!isLast ? ',' : ''}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -669,34 +677,35 @@ function TreeView({
|
|||||||
```jsx
|
```jsx
|
||||||
let data = {
|
let data = {
|
||||||
lorem: {
|
lorem: {
|
||||||
ipsum: "dolor sit",
|
ipsum: 'dolor sit',
|
||||||
amet: {
|
amet: {
|
||||||
consectetur: "adipiscing",
|
consectetur: 'adipiscing',
|
||||||
elit: [
|
elit: [
|
||||||
"duis",
|
'duis',
|
||||||
"vitae",
|
'vitae',
|
||||||
{
|
{
|
||||||
semper: "orci"
|
semper: 'orci'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
est: "sed ornare"
|
est: 'sed ornare'
|
||||||
},
|
},
|
||||||
"etiam",
|
'etiam',
|
||||||
["laoreet", "tincidunt"],
|
['laoreet', 'tincidunt'],
|
||||||
["vestibulum", "ante"]
|
['vestibulum', 'ante']
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
ipsum: "primis"
|
ipsum: 'primis'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ReactDOM.render(<TreeView data={data} name='data'/>, document.getElementById("root"));
|
ReactDOM.render(<TreeView data={data} name="data" />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
|
|
||||||
|
|
||||||
## String
|
## String
|
||||||
|
|
||||||
### AutoLink
|
### AutoLink
|
||||||
|
|
||||||
Renders a string as plaintext, with URLs converted to appropriate `<a>` elements.
|
Renders a string as plaintext, with URLs converted to appropriate `<a>` elements.
|
||||||
@ -714,9 +723,7 @@ function AutoLink({ text }) {
|
|||||||
let match = word.match(delimiter);
|
let match = word.match(delimiter);
|
||||||
if (match) {
|
if (match) {
|
||||||
let url = match[0];
|
let url = match[0];
|
||||||
return (
|
return <a href={url.startsWith('http') ? url : `http://${url}`}>{url}</a>;
|
||||||
<a href={url.startsWith("http") ? url : `http://${url}`}>{url}</a>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return word;
|
return word;
|
||||||
})}
|
})}
|
||||||
@ -730,16 +737,17 @@ function AutoLink({ text }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AutoLink text='foo bar baz http://example.org bar' />,
|
<AutoLink text="foo bar baz http://example.org bar" />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
|
|
||||||
|
|
||||||
## Visual
|
## Visual
|
||||||
|
|
||||||
### Carousel
|
### Carousel
|
||||||
|
|
||||||
Renders a carousel component.
|
Renders a carousel component.
|
||||||
@ -756,14 +764,14 @@ function Carousel(props) {
|
|||||||
let scrollInterval = null;
|
let scrollInterval = null;
|
||||||
const style = {
|
const style = {
|
||||||
carousel: {
|
carousel: {
|
||||||
position: "relative"
|
position: 'relative'
|
||||||
},
|
},
|
||||||
carouselItem: {
|
carouselItem: {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
visibility: "hidden"
|
visibility: 'hidden'
|
||||||
},
|
},
|
||||||
visible: {
|
visible: {
|
||||||
visibility: "visible"
|
visibility: 'visible'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -802,9 +810,10 @@ ReactDOM.render(
|
|||||||
<div>carousel item 3</div>
|
<div>carousel item 3</div>
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -825,24 +834,21 @@ function Collapse(props) {
|
|||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
collapsed: {
|
collapsed: {
|
||||||
display: "none"
|
display: 'none'
|
||||||
},
|
},
|
||||||
expanded: {
|
expanded: {
|
||||||
display: "block"
|
display: 'block'
|
||||||
},
|
},
|
||||||
buttonStyle: {
|
buttonStyle: {
|
||||||
display: "block",
|
display: 'block',
|
||||||
width: "100%"
|
width: '100%'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button style={style.buttonStyle} onClick={() => setIsCollapsed(!isCollapsed)}>
|
||||||
style={style.buttonStyle}
|
{isCollapsed ? 'Show' : 'Hide'} content
|
||||||
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
||||||
>
|
|
||||||
{isCollapsed ? "Show" : "Hide"} content
|
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
className="collapse-content"
|
className="collapse-content"
|
||||||
@ -868,6 +874,7 @@ ReactDOM.render(
|
|||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -897,8 +904,7 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
|
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
if (paused || over) return;
|
if (paused || over) return;
|
||||||
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0)
|
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0) setOver(true);
|
||||||
setOver(true);
|
|
||||||
else if (time.minutes == 0 && time.seconds == 0)
|
else if (time.minutes == 0 && time.seconds == 0)
|
||||||
setTime({
|
setTime({
|
||||||
hours: time.hours - 1,
|
hours: time.hours - 1,
|
||||||
@ -936,15 +942,11 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{`${time.hours
|
<p>{`${time.hours.toString().padStart(2, '0')}:${time.minutes
|
||||||
.toString()
|
.toString()
|
||||||
.padStart(2, "0")}:${time.minutes
|
.padStart(2, '0')}:${time.seconds.toString().padStart(2, '0')}`}</p>
|
||||||
.toString()
|
<div>{over ? "Time's up!" : ''}</div>
|
||||||
.padStart(2, "0")}:${time.seconds.toString().padStart(2, "0")}`}</p>
|
<button onClick={() => setPaused(!paused)}>{paused ? 'Resume' : 'Pause'}</button>
|
||||||
<div>{over ? "Time's up!" : ""}</div>
|
|
||||||
<button onClick={() => setPaused(!paused)}>
|
|
||||||
{paused ? "Resume" : "Pause"}
|
|
||||||
</button>
|
|
||||||
<button onClick={() => reset()}>Restart</button>
|
<button onClick={() => reset()}>Restart</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -955,11 +957,9 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
<summary>Examples</summary>
|
<summary>Examples</summary>
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(<CountDown hours="1" minutes="45" />, document.getElementById('root'));
|
||||||
<CountDown hours="1" minutes="45" />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -978,11 +978,10 @@ Each of the methods will handle a specific event, the listeners for which are cr
|
|||||||
Return an appropriately styled `<div>` and use `drag` and `filename` to determine its contents and style.
|
Return an appropriately styled `<div>` and use `drag` and `filename` to determine its contents and style.
|
||||||
Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
||||||
|
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.filedrop {
|
.filedrop {
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
border: 3px solid #D3D3D3;
|
border: 3px solid #d3d3d3;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
@ -990,11 +989,11 @@ Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filedrop.drag {
|
.filedrop.drag {
|
||||||
border: 3px dashed #1E90FF;
|
border: 3px dashed #1e90ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filedrop.ready {
|
.filedrop.ready {
|
||||||
border: 3px solid #32CD32;
|
border: 3px solid #32cd32;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1038,24 +1037,22 @@ function FileDrop(props) {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
let div = dropRef.current;
|
let div = dropRef.current;
|
||||||
div.addEventListener("dragenter", handleDragIn);
|
div.addEventListener('dragenter', handleDragIn);
|
||||||
div.addEventListener("dragleave", handleDragOut);
|
div.addEventListener('dragleave', handleDragOut);
|
||||||
div.addEventListener("dragover", handleDrag);
|
div.addEventListener('dragover', handleDrag);
|
||||||
div.addEventListener("drop", handleDrop);
|
div.addEventListener('drop', handleDrop);
|
||||||
return function cleanup() {
|
return function cleanup() {
|
||||||
div.removeEventListener("dragenter", handleDragIn);
|
div.removeEventListener('dragenter', handleDragIn);
|
||||||
div.removeEventListener("dragleave", handleDragOut);
|
div.removeEventListener('dragleave', handleDragOut);
|
||||||
div.removeEventListener("dragover", handleDrag);
|
div.removeEventListener('dragover', handleDrag);
|
||||||
div.removeEventListener("drop", handleDrop);
|
div.removeEventListener('drop', handleDrop);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={dropRef}
|
ref={dropRef}
|
||||||
className={
|
className={drag ? 'filedrop drag' : filename ? 'filedrop ready' : 'filedrop'}
|
||||||
drag ? "filedrop drag" : filename ? "filedrop ready" : "filedrop"
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{filename && !drag ? <div>{filename}</div> : <div>Drop files here!</div>}
|
{filename && !drag ? <div>{filename}</div> : <div>Drop files here!</div>}
|
||||||
</div>
|
</div>
|
||||||
@ -1069,6 +1066,7 @@ function FileDrop(props) {
|
|||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(<FileDrop handleDrop={console.log} />, document.getElementById('root'));
|
ReactDOM.render(<FileDrop handleDrop={console.log} />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1083,9 +1081,7 @@ Render the link with `props.children` as its content.
|
|||||||
```jsx
|
```jsx
|
||||||
function Mailto({ email, subject, body, ...props }) {
|
function Mailto({ email, subject, body, ...props }) {
|
||||||
return (
|
return (
|
||||||
<a href={`mailto:${email}?subject=${subject || ""}&body=${body || ""}`}>
|
<a href={`mailto:${email}?subject=${subject || ''}&body=${body || ''}`}>{props.children}</a>
|
||||||
{props.children}
|
|
||||||
</a>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -1098,9 +1094,10 @@ ReactDOM.render(
|
|||||||
<Mailto email="foo@bar.baz" subject="Hello" body="Hello world!">
|
<Mailto email="foo@bar.baz" subject="Hello" body="Hello world!">
|
||||||
Mail me!
|
Mail me!
|
||||||
</Mailto>,
|
</Mailto>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1118,29 +1115,25 @@ Finally, pass the appropriate values to each `<Star>` component (`starId` and `m
|
|||||||
```jsx
|
```jsx
|
||||||
function Star({ marked, starId }) {
|
function Star({ marked, starId }) {
|
||||||
return (
|
return (
|
||||||
<span star-id={starId} style={{ color: "#ff9933" }} role="button">
|
<span star-id={starId} style={{ color: '#ff9933' }} role="button">
|
||||||
{marked ? "\u2605" : "\u2606"}
|
{marked ? '\u2605' : '\u2606'}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function StarRating(props) {
|
function StarRating(props) {
|
||||||
const [rating, setRating] = React.useState(
|
const [rating, setRating] = React.useState(typeof props.rating == 'number' ? props.rating : 0);
|
||||||
typeof props.rating == "number" ? props.rating : 0
|
|
||||||
);
|
|
||||||
const [selection, setSelection] = React.useState(0);
|
const [selection, setSelection] = React.useState(0);
|
||||||
const hoverOver = event => {
|
const hoverOver = event => {
|
||||||
let val = 0;
|
let val = 0;
|
||||||
if (event && event.target && event.target.getAttribute("star-id"))
|
if (event && event.target && event.target.getAttribute('star-id'))
|
||||||
val = event.target.getAttribute("star-id");
|
val = event.target.getAttribute('star-id');
|
||||||
setSelection(val);
|
setSelection(val);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onMouseOut={() => hoverOver(null)}
|
onMouseOut={() => hoverOver(null)}
|
||||||
onClick={() =>
|
onClick={() => setRating(event.target.getAttribute('star-id') || this.state.rating)}
|
||||||
setRating(event.target.getAttribute("star-id") || this.state.rating)
|
|
||||||
}
|
|
||||||
onMouseOver={hoverOver}
|
onMouseOver={hoverOver}
|
||||||
>
|
>
|
||||||
{Array.from({ length: 5 }, (v, i) => (
|
{Array.from({ length: 5 }, (v, i) => (
|
||||||
@ -1162,6 +1155,7 @@ function StarRating(props) {
|
|||||||
ReactDOM.render(<StarRating />, document.getElementById('root'));
|
ReactDOM.render(<StarRating />, document.getElementById('root'));
|
||||||
ReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));
|
ReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1185,10 +1179,10 @@ Define `changeTab`, which will be executed when clicking a `<button>` from the `
|
|||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
.tab-menu > button.focus {
|
.tab-menu > button.focus {
|
||||||
border-bottom: 2px solid #007BEF;
|
border-bottom: 2px solid #007bef;
|
||||||
}
|
}
|
||||||
.tab-menu > button:hover {
|
.tab-menu > button:hover {
|
||||||
border-bottom: 2px solid #007BEF;
|
border-bottom: 2px solid #007bef;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1200,19 +1194,16 @@ function TabItem(props) {
|
|||||||
function Tabs(props) {
|
function Tabs(props) {
|
||||||
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
||||||
const changeTab = newIndex => {
|
const changeTab = newIndex => {
|
||||||
if (typeof props.onTabClick === "function") props.onTabClick(newIndex);
|
if (typeof props.onTabClick === 'function') props.onTabClick(newIndex);
|
||||||
setBindIndex(newIndex);
|
setBindIndex(newIndex);
|
||||||
};
|
};
|
||||||
const items = props.children.filter(item => item.type.name === "TabItem");
|
const items = props.children.filter(item => item.type.name === 'TabItem');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<div className="tab-menu">
|
<div className="tab-menu">
|
||||||
{items.map(({ props: { index, label } }) => (
|
{items.map(({ props: { index, label } }) => (
|
||||||
<button
|
<button onClick={() => changeTab(index)} className={bindIndex === index ? 'focus' : ''}>
|
||||||
onClick={() => changeTab(index)}
|
|
||||||
className={bindIndex === index ? "focus" : ""}
|
|
||||||
>
|
|
||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
@ -1223,7 +1214,7 @@ function Tabs(props) {
|
|||||||
{...props}
|
{...props}
|
||||||
className="tab-view_item"
|
className="tab-view_item"
|
||||||
key={props.index}
|
key={props.index}
|
||||||
style={{ display: bindIndex === props.index ? "block" : "none" }}
|
style={{ display: bindIndex === props.index ? 'block' : 'none' }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -1245,10 +1236,10 @@ ReactDOM.render(
|
|||||||
Dolor sit amet
|
Dolor sit amet
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>,
|
</Tabs>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1269,17 +1260,15 @@ function Ticker(props) {
|
|||||||
const tick = () => {
|
const tick = () => {
|
||||||
reset();
|
reset();
|
||||||
interval = setInterval(() => {
|
interval = setInterval(() => {
|
||||||
if (ticker < props.times)
|
if (ticker < props.times) setTicker(ticker + 1);
|
||||||
setTicker(ticker + 1);
|
else clearInterval(interval);
|
||||||
else
|
|
||||||
clearInterval(interval);
|
|
||||||
}, props.interval);
|
}, props.interval);
|
||||||
}
|
};
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setTicker(0);
|
setTicker(0);
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -1297,6 +1286,7 @@ function Ticker(props) {
|
|||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));
|
ReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1314,19 +1304,16 @@ function Toggle(props) {
|
|||||||
const [isToggleOn, setIsToggleOn] = React.useState(false);
|
const [isToggleOn, setIsToggleOn] = React.useState(false);
|
||||||
style = {
|
style = {
|
||||||
on: {
|
on: {
|
||||||
backgroundColor: "green"
|
backgroundColor: 'green'
|
||||||
},
|
},
|
||||||
off: {
|
off: {
|
||||||
backgroundColor: "grey"
|
backgroundColor: 'grey'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button onClick={() => setIsToggleOn(!isToggleOn)} style={isToggleOn ? style.on : style.off}>
|
||||||
onClick={() => setIsToggleOn(!isToggleOn)}
|
{isToggleOn ? 'ON' : 'OFF'}
|
||||||
style={isToggleOn ? style.on : style.off}
|
|
||||||
>
|
|
||||||
{isToggleOn ? "ON" : "OFF"}
|
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1338,6 +1325,7 @@ function Toggle(props) {
|
|||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(<Toggle />, document.getElementById('root'));
|
ReactDOM.render(<Toggle />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
@ -1375,15 +1363,11 @@ function Tooltip({ children, text, ...rest }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="tooltip" style={show ? { visibility: "visible" } : {}}>
|
<div className="tooltip" style={show ? { visibility: 'visible' } : {}}>
|
||||||
{text}
|
{text}
|
||||||
<span className="tooltip-arrow" />
|
<span className="tooltip-arrow" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div {...rest} onMouseEnter={() => setShow(true)} onMouseLeave={() => setShow(false)}>
|
||||||
{...rest}
|
|
||||||
onMouseEnter={() => setShow(true)}
|
|
||||||
onMouseLeave={() => setShow(false)}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1396,19 +1380,19 @@ function Tooltip({ children, text, ...rest }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Tooltip text='Simple tooltip'>
|
<Tooltip text="Simple tooltip">
|
||||||
<button>Hover me!</button>
|
<button>Hover me!</button>
|
||||||
</Tooltip>,
|
</Tooltip>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<br>[⬆ Back to top](#table-of-contents)
|
<br>[⬆ Back to top](#table-of-contents)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
-----
|
_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!_
|
||||||
|
|
||||||
*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!*
|
_This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder)._
|
||||||
|
|
||||||
*This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder).*
|
|
||||||
|
|||||||
@ -8,11 +8,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <AutoLink text='foo bar baz http://example.org bar' />,\n document.getElementById('root')\n);\n```"
|
"```jsx\nReactDOM.render(\n <AutoLink text='foo bar baz http://example.org bar' />,\n document.getElementById('root')\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 2,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["string", "fragment", "regexp"],
|
||||||
"string",
|
|
||||||
"fragment",
|
|
||||||
"regexp"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -24,12 +20,7 @@
|
|||||||
"```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 ```"
|
"```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,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["visual", "children", "state", "effect"],
|
||||||
"visual",
|
|
||||||
"children",
|
|
||||||
"state",
|
|
||||||
"effect"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -41,11 +32,7 @@
|
|||||||
"```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```"
|
"```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,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["visual", "children", "state"],
|
||||||
"visual",
|
|
||||||
"children",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -57,10 +44,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <CountDown hours=\"1\" minutes=\"45\" />,\n document.getElementById('root')\n);\n```"
|
"```jsx\nReactDOM.render(\n <CountDown hours=\"1\" minutes=\"45\" />,\n document.getElementById('root')\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 2,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["visual", "state"],
|
||||||
"visual",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -72,9 +56,7 @@
|
|||||||
"```jsx\nconst names = ['John', 'Paul', 'Mary'];\nReactDOM.render(<DataList data={names}/>, document.getElementById('root'));\nReactDOM.render(<DataList data={names} isOrdered/>, document.getElementById('root'));\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,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["array"],
|
||||||
"array"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -86,9 +68,7 @@
|
|||||||
"```jsx\nconst people = ['John', 'Jesse'];\nReactDOM.render(\n <DataTable data={people} />,\n document.getElementById('root')\n);\n```"
|
"```jsx\nconst people = ['John', 'Jesse'];\nReactDOM.render(\n <DataTable data={people} />,\n document.getElementById('root')\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 0,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["array"],
|
||||||
"array"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -101,12 +81,7 @@
|
|||||||
"```jsx\nReactDOM.render(<FileDrop handleDrop={console.log}/>, document.getElementById('root'));\n```"
|
"```jsx\nReactDOM.render(<FileDrop handleDrop={console.log}/>, document.getElementById('root'));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 2,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["visual", "input", "state", "effect"],
|
||||||
"visual",
|
|
||||||
"input",
|
|
||||||
"state",
|
|
||||||
"effect"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -118,9 +93,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <Input type='text' placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,\n document.getElementById('root')\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,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input"],
|
||||||
"input"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -132,11 +105,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <LimitedTextarea limit={32} value='Hello!' />,\n document.getElementById('root')\n);\n```"
|
"```jsx\nReactDOM.render(\n <LimitedTextarea limit={32} value='Hello!' />,\n document.getElementById('root')\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 0,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input", "state", "effect"],
|
||||||
"input",
|
|
||||||
"state",
|
|
||||||
"effect"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -148,11 +117,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <LimitedWordTextArea limit={5} value='Hello there!' />,\n document.getElementById('root')\n);\n```"
|
"```jsx\nReactDOM.render(\n <LimitedWordTextArea limit={5} value='Hello there!' />,\n document.getElementById('root')\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 0,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input", "state", "effect"],
|
||||||
"input",
|
|
||||||
"state",
|
|
||||||
"effect"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -164,9 +129,7 @@
|
|||||||
"```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```"
|
"```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,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["visual"],
|
||||||
"visual"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -178,10 +141,7 @@
|
|||||||
"```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```"
|
"```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,
|
"expertise": 1,
|
||||||
"tags": [
|
"tags": ["array", "object"],
|
||||||
"array",
|
|
||||||
"object"
|
|
||||||
],
|
|
||||||
"notes": [
|
"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`.",
|
"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 -->",
|
"<!-tags: array,object -->",
|
||||||
@ -197,11 +157,7 @@
|
|||||||
"```jsx\nconst options = [{ label: \"Item One\" }, { label: \"Item Two\" }];\n\nReactDOM.render(\n <MultiselectCheckbox\n options={options}\n onChange={data => {\n console.log(data);\n }}\n />,\n document.getElementById(\"root\")\n);\n```"
|
"```jsx\nconst options = [{ label: \"Item One\" }, { label: \"Item Two\" }];\n\nReactDOM.render(\n <MultiselectCheckbox\n options={options}\n onChange={data => {\n console.log(data);\n }}\n />,\n document.getElementById(\"root\")\n);\n```"
|
||||||
],
|
],
|
||||||
"expertise": 1,
|
"expertise": 1,
|
||||||
"tags": [
|
"tags": ["input", "state", "array"],
|
||||||
"input",
|
|
||||||
"state",
|
|
||||||
"array"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -213,10 +169,7 @@
|
|||||||
"```jsx\nReactDOM.render(<PasswordRevealer />, document.getElementById('root'));\n```"
|
"```jsx\nReactDOM.render(<PasswordRevealer />, document.getElementById('root'));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 0,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input", "state"],
|
||||||
"input",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -228,9 +181,7 @@
|
|||||||
"```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```"
|
"```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,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input"],
|
||||||
"input"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -242,12 +193,7 @@
|
|||||||
"```jsx\nReactDOM.render(<StarRating/>, document.getElementById('root'));\nReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));\n```"
|
"```jsx\nReactDOM.render(<StarRating/>, document.getElementById('root'));\nReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 2,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["visual", "children", "input", "state"],
|
||||||
"visual",
|
|
||||||
"children",
|
|
||||||
"input",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -260,11 +206,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <Tabs 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 </Tabs>,\n document.getElementById(\"root\")\n);\n\n```"
|
"```jsx\nReactDOM.render(\n <Tabs 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 </Tabs>,\n document.getElementById(\"root\")\n);\n\n```"
|
||||||
],
|
],
|
||||||
"expertise": 1,
|
"expertise": 1,
|
||||||
"tags": [
|
"tags": ["visual", "state", "children"],
|
||||||
"visual",
|
|
||||||
"state",
|
|
||||||
"children"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -276,9 +218,7 @@
|
|||||||
"```jsx\nReactDOM.render(\n <TextArea placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,\n document.getElementById('root')\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,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["input"],
|
||||||
"input"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -290,10 +230,7 @@
|
|||||||
"```jsx\nReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));\n```"
|
"```jsx\nReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 1,
|
"expertise": 1,
|
||||||
"tags": [
|
"tags": ["visual", "state"],
|
||||||
"visual",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -305,10 +242,7 @@
|
|||||||
"```jsx\nReactDOM.render(<Toggle />, document.getElementById('root'));\n```"
|
"```jsx\nReactDOM.render(<Toggle />, document.getElementById('root'));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 0,
|
"expertise": 0,
|
||||||
"tags": [
|
"tags": ["visual", "state"],
|
||||||
"visual",
|
|
||||||
"state"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -321,11 +255,7 @@
|
|||||||
"```jsx\n ReactDOM.render(\n <Tooltip text='Simple tooltip'>\n <button>Hover me!</button>\n </Tooltip>,\n document.getElementById('root')\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,
|
"expertise": 1,
|
||||||
"tags": [
|
"tags": ["visual", "state", "children"],
|
||||||
"visual",
|
|
||||||
"state",
|
|
||||||
"children"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -338,12 +268,7 @@
|
|||||||
"```jsx\nlet data = {\n lorem: {\n ipsum: \"dolor sit\",\n amet: {\n consectetur: \"adipiscing\",\n elit: [\n \"duis\",\n \"vitae\",\n {\n semper: \"orci\"\n },\n {\n est: \"sed ornare\"\n },\n \"etiam\",\n [\"laoreet\", \"tincidunt\"],\n [\"vestibulum\", \"ante\"]\n ]\n },\n ipsum: \"primis\"\n }\n};\nReactDOM.render(<TreeView data={data} name='data'/>, document.getElementById(\"root\"));\n```"
|
"```jsx\nlet data = {\n lorem: {\n ipsum: \"dolor sit\",\n amet: {\n consectetur: \"adipiscing\",\n elit: [\n \"duis\",\n \"vitae\",\n {\n semper: \"orci\"\n },\n {\n est: \"sed ornare\"\n },\n \"etiam\",\n [\"laoreet\", \"tincidunt\"],\n [\"vestibulum\", \"ante\"]\n ]\n },\n ipsum: \"primis\"\n }\n};\nReactDOM.render(<TreeView data={data} name='data'/>, document.getElementById(\"root\"));\n```"
|
||||||
],
|
],
|
||||||
"expertise": 2,
|
"expertise": 2,
|
||||||
"tags": [
|
"tags": ["object", "visual", "state", "recursion"],
|
||||||
"object",
|
|
||||||
"visual",
|
|
||||||
"state",
|
|
||||||
"recursion"
|
|
||||||
],
|
|
||||||
"notes": []
|
"notes": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1,19 +1,21 @@
|
|||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("path");
|
const path = require('path');
|
||||||
const chalk = require("chalk");
|
const chalk = require('chalk');
|
||||||
const util = require("./util.js");
|
const util = require('./util.js');
|
||||||
const markdown = require("markdown-builder");
|
const markdown = require('markdown-builder');
|
||||||
const snippets = require("../data/snippet_data.json")
|
const snippets = require('../data/snippet_data.json');
|
||||||
|
|
||||||
const { headers, misc, lists } = markdown;
|
const { headers, misc, lists } = markdown;
|
||||||
const TAG_NAMES = [...new Set(snippets.reduce((acc,v) => [...acc,v.tags[0]],[]))].sort((a,b) => a.localeCompare(b));
|
const TAG_NAMES = [...new Set(snippets.reduce((acc, v) => [...acc, v.tags[0]], []))].sort((a, b) =>
|
||||||
|
a.localeCompare(b)
|
||||||
|
);
|
||||||
console.log(TAG_NAMES);
|
console.log(TAG_NAMES);
|
||||||
|
|
||||||
const STATIC_PARTS_PATH = "./static-parts";
|
const STATIC_PARTS_PATH = './static-parts';
|
||||||
|
|
||||||
let startPart = "";
|
let startPart = '';
|
||||||
let endPart = "";
|
let endPart = '';
|
||||||
let output = "";
|
let output = '';
|
||||||
|
|
||||||
const detailsTOC = (title, snippetsArray) =>
|
const detailsTOC = (title, snippetsArray) =>
|
||||||
`\n${misc
|
`\n${misc
|
||||||
@ -23,13 +25,13 @@ const detailsTOC = (title, snippetsArray) =>
|
|||||||
.ul(snippetsArray, snippet =>
|
.ul(snippetsArray, snippet =>
|
||||||
misc.link(
|
misc.link(
|
||||||
snippet.title
|
snippet.title
|
||||||
.replace("\n", "")
|
.replace('\n', '')
|
||||||
.split("```")[0]
|
.split('```')[0]
|
||||||
.trim(),
|
.trim(),
|
||||||
misc.anchor(
|
misc.anchor(
|
||||||
snippet.title
|
snippet.title
|
||||||
.replace("\n", "")
|
.replace('\n', '')
|
||||||
.split("```")[0]
|
.split('```')[0]
|
||||||
.trim()
|
.trim()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -38,19 +40,13 @@ const detailsTOC = (title, snippetsArray) =>
|
|||||||
)
|
)
|
||||||
.trim()}\n\n`;
|
.trim()}\n\n`;
|
||||||
|
|
||||||
console.time("Builder");
|
console.time('Builder');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startPart = fs.readFileSync(
|
startPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-start.md'), 'utf8');
|
||||||
path.join(STATIC_PARTS_PATH, "README-start.md"),
|
endPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-end.md'), 'utf8');
|
||||||
"utf8"
|
|
||||||
);
|
|
||||||
endPart = fs.readFileSync(
|
|
||||||
path.join(STATIC_PARTS_PATH, "README-end.md"),
|
|
||||||
"utf8"
|
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`${chalk.red("ERROR!")} During static part loading: ${err}`);
|
console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +56,13 @@ try {
|
|||||||
|
|
||||||
const snippetsInTag = {};
|
const snippetsInTag = {};
|
||||||
|
|
||||||
TAG_NAMES.forEach(tag => snippetsInTag[tag] = snippets.filter(v => v.tags[0] == tag));
|
TAG_NAMES.forEach(tag => (snippetsInTag[tag] = snippets.filter(v => v.tags[0] == tag)));
|
||||||
|
|
||||||
// write Table of Contents
|
// write Table of Contents
|
||||||
TAG_NAMES.forEach(tag => {
|
TAG_NAMES.forEach(tag => {
|
||||||
const taggedSnippets = snippetsInTag[tag];
|
const taggedSnippets = snippetsInTag[tag];
|
||||||
output += headers.h3(util.capitalize(tag));
|
output += headers.h3(util.capitalize(tag));
|
||||||
output += detailsTOC("View contents", taggedSnippets);
|
output += detailsTOC('View contents', taggedSnippets);
|
||||||
});
|
});
|
||||||
|
|
||||||
// delimeter after TOC
|
// delimeter after TOC
|
||||||
@ -84,21 +80,18 @@ try {
|
|||||||
output += `\n${snippet.notes}`;
|
output += `\n${snippet.notes}`;
|
||||||
}
|
}
|
||||||
output += misc.collapsible('Examples', snippet.codeBlocks.slice(-1));
|
output += misc.collapsible('Examples', snippet.codeBlocks.slice(-1));
|
||||||
output += `\n<br>${misc.link(
|
output += `\n<br>${misc.link('⬆ Back to top', misc.anchor('Table of Contents'))}\n\n`;
|
||||||
"⬆ Back to top",
|
});
|
||||||
misc.anchor("Table of Contents")
|
|
||||||
)}\n\n`
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// add static part for end
|
// add static part for end
|
||||||
output += `\n${endPart}\n`;
|
output += `\n${endPart}\n`;
|
||||||
|
|
||||||
fs.writeFileSync("README.md", output);
|
fs.writeFileSync('README.md', output);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`${chalk.red("ERROR!")} During README generation: ${err}`);
|
console.log(`${chalk.red('ERROR!')} During README generation: ${err}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`${chalk.green("SUCCESS!")} README file generated!`);
|
console.log(`${chalk.green('SUCCESS!')} README file generated!`);
|
||||||
console.timeEnd("Builder");
|
console.timeEnd('Builder');
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const fs = require("fs-extra")
|
const fs = require('fs-extra');
|
||||||
const path = require("path")
|
const path = require('path');
|
||||||
const chalk = require("chalk")
|
const chalk = require('chalk');
|
||||||
const {
|
const {
|
||||||
attempt,
|
attempt,
|
||||||
readSnippets,
|
readSnippets,
|
||||||
@ -8,36 +8,35 @@ const {
|
|||||||
getSection,
|
getSection,
|
||||||
getTitle,
|
getTitle,
|
||||||
getTextualContent
|
getTextualContent
|
||||||
} = require("./util");
|
} = require('./util');
|
||||||
|
|
||||||
console.time("Extractor");
|
console.time('Extractor');
|
||||||
|
|
||||||
attempt("snippet_data.json generation", () => {
|
attempt('snippet_data.json generation', () => {
|
||||||
const output = Object.entries(readSnippets()).map(([name, contents]) => {
|
const output = Object.entries(readSnippets()).map(([name, contents]) => {
|
||||||
const title = getTitle(contents);
|
const title = getTitle(contents);
|
||||||
const text = getTextualContent(contents);
|
const text = getTextualContent(contents);
|
||||||
const codeBlocks = getCodeBlocks(contents);
|
const codeBlocks = getCodeBlocks(contents);
|
||||||
const notes = getSection("#### Notes", contents, false)
|
const notes = getSection('#### Notes', contents, false)
|
||||||
.split("\n")
|
.split('\n')
|
||||||
.map(v => v.replace(/[*-] /g, ""))
|
.map(v => v.replace(/[*-] /g, ''))
|
||||||
.filter(v => v.trim() !== "")
|
.filter(v => v.trim() !== '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
title,
|
title,
|
||||||
text,
|
text,
|
||||||
codeBlocks,
|
codeBlocks,
|
||||||
expertise: parseInt(
|
expertise: parseInt((contents.match(/<!--\s*expertise:\s*\(*(.+)\)*/) || [])[1], 10),
|
||||||
(contents.match(/<!--\s*expertise:\s*\(*(.+)\)*/) || [])[1],
|
tags: (contents.match(/<!--\s*tags:\s*\(*(.+)\)*\s*-->/) || [])[1]
|
||||||
10
|
.split(',')
|
||||||
),
|
.map(v => v.trim()),
|
||||||
tags: (contents.match(/<!--\s*tags:\s*\(*(.+)\)*\s*-->/) || [])[1].split(",").map(v => v.trim()),
|
|
||||||
notes
|
notes
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
fs.writeFileSync("./data/snippet_data.json", JSON.stringify(output, null, 2))
|
fs.writeFileSync('./data/snippet_data.json', JSON.stringify(output, null, 2));
|
||||||
})
|
});
|
||||||
|
|
||||||
console.log(`${chalk.green("SUCCESS!")} snippet_data.json file generated!`);
|
console.log(`${chalk.green('SUCCESS!')} snippet_data.json file generated!`);
|
||||||
console.timeEnd("Extractor");
|
console.timeEnd('Extractor');
|
||||||
|
|||||||
@ -1,31 +1,29 @@
|
|||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("path");
|
const path = require('path');
|
||||||
const chalk = require("chalk");
|
const chalk = require('chalk');
|
||||||
|
|
||||||
const SNIPPETS_PATH = "./snippets";
|
const SNIPPETS_PATH = './snippets';
|
||||||
|
|
||||||
const attempt = (task, cb) => {
|
const attempt = (task, cb) => {
|
||||||
try {
|
try {
|
||||||
return cb();
|
return cb();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`${chalk.red("ERROR!")} During ${task}: ${e}`);
|
console.log(`${chalk.red('ERROR!')} During ${task}: ${e}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const capitalize = ([first, ...rest], lowerRest = false) =>
|
const capitalize = ([first, ...rest], lowerRest = false) =>
|
||||||
first.toUpperCase() + (lowerRest ? rest.join("").toLowerCase() : rest.join(""));
|
first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''));
|
||||||
|
|
||||||
const readSnippets = () =>
|
const readSnippets = () =>
|
||||||
attempt("read snippets", () =>
|
attempt('read snippets', () =>
|
||||||
fs
|
fs
|
||||||
.readdirSync(SNIPPETS_PATH)
|
.readdirSync(SNIPPETS_PATH)
|
||||||
.sort((a, b) => (a.toLowerCase() < b.toLowerCase() ? -1 : 1))
|
.sort((a, b) => (a.toLowerCase() < b.toLowerCase() ? -1 : 1))
|
||||||
.reduce((acc, name) => {
|
.reduce((acc, name) => {
|
||||||
acc[name] = fs
|
acc[name] = fs.readFileSync(path.join(SNIPPETS_PATH, name), 'utf8').replace(/\r\n/g, '\n');
|
||||||
.readFileSync(path.join(SNIPPETS_PATH, name), "utf8")
|
|
||||||
.replace(/\r\n/g, "\n");
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
);
|
);
|
||||||
@ -41,16 +39,16 @@ const getCodeBlocks = str => {
|
|||||||
m.forEach(match => results.push(match));
|
m.forEach(match => results.push(match));
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getSection = (searchString, contents, includeSubsections = true) => {
|
const getSection = (searchString, contents, includeSubsections = true) => {
|
||||||
const indexOfSearch = contents.indexOf(searchString);
|
const indexOfSearch = contents.indexOf(searchString);
|
||||||
if (indexOfSearch < 0) return "";
|
if (indexOfSearch < 0) return '';
|
||||||
|
|
||||||
let endSearch = "\\n#"
|
let endSearch = '\\n#';
|
||||||
if (includeSubsections) {
|
if (includeSubsections) {
|
||||||
let i;
|
let i;
|
||||||
for (i = 0; searchString[i] === "#" && i < searchString.length; i++);
|
for (i = 0; searchString[i] === '#' && i < searchString.length; i++);
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
endSearch += `{${i - 1},${i}}[^#]`;
|
endSearch += `{${i - 1},${i}}[^#]`;
|
||||||
@ -63,15 +61,14 @@ const getSection = (searchString, contents, includeSubsections = true) => {
|
|||||||
const sliceEnd = endIndex === -1 ? undefined : endIndex + sliceStart;
|
const sliceEnd = endIndex === -1 ? undefined : endIndex + sliceStart;
|
||||||
|
|
||||||
return contents.slice(sliceStart, sliceEnd).trim();
|
return contents.slice(sliceStart, sliceEnd).trim();
|
||||||
}
|
};
|
||||||
|
|
||||||
const getTextualContent = str => {
|
const getTextualContent = str => {
|
||||||
const regex = /###.*\n*([\s\S]*?)```/g;
|
const regex = /###.*\n*([\s\S]*?)```/g;
|
||||||
const results = [];
|
const results = [];
|
||||||
let m = null;
|
let m = null;
|
||||||
while ((m = regex.exec(str)) !== null) {
|
while ((m = regex.exec(str)) !== null) {
|
||||||
if (m.index === regex.lastIndex)
|
if (m.index === regex.lastIndex) regex.lastIndex += 1;
|
||||||
regex.lastIndex += 1;
|
|
||||||
|
|
||||||
m.forEach((match, groupIndex) => {
|
m.forEach((match, groupIndex) => {
|
||||||
results.push(match);
|
results.push(match);
|
||||||
@ -80,8 +77,7 @@ const getTextualContent = str => {
|
|||||||
return results[1];
|
return results[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTitle = (contents) =>
|
const getTitle = contents => contents.split('\n')[0].replace(/^#+\s+/g, '');
|
||||||
contents.split('\n')[0].replace(/^#+\s+/g,'');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
attempt,
|
attempt,
|
||||||
|
|||||||
@ -11,18 +11,20 @@ function ComponentName(props) {
|
|||||||
setState(0);
|
setState(0);
|
||||||
});
|
});
|
||||||
return <div>{props}</div>;
|
return <div>{props}</div>;
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(<ComponentName />, document.getElementById("root"));
|
ReactDOM.render(<ComponentName />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- OPTIONAL -->
|
<!-- OPTIONAL -->
|
||||||
|
|
||||||
#### Notes:
|
#### Notes:
|
||||||
* Things to remember when using this
|
|
||||||
* Other options that might be less appealing or have lower compatibility
|
- Things to remember when using this
|
||||||
* Common mistakes and issues
|
- Other options that might be less appealing or have lower compatibility
|
||||||
|
- Common mistakes and issues
|
||||||
|
|
||||||
<!-- tags: (separate each by a comma) -->
|
<!-- tags: (separate each by a comma) -->
|
||||||
|
|
||||||
|
|||||||
@ -15,9 +15,7 @@ function AutoLink({ text }) {
|
|||||||
let match = word.match(delimiter);
|
let match = word.match(delimiter);
|
||||||
if (match) {
|
if (match) {
|
||||||
let url = match[0];
|
let url = match[0];
|
||||||
return (
|
return <a href={url.startsWith('http') ? url : `http://${url}`}>{url}</a>;
|
||||||
<a href={url.startsWith("http") ? url : `http://${url}`}>{url}</a>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return word;
|
return word;
|
||||||
})}
|
})}
|
||||||
@ -28,7 +26,7 @@ function AutoLink({ text }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AutoLink text='foo bar baz http://example.org bar' />,
|
<AutoLink text="foo bar baz http://example.org bar" />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@ -14,14 +14,14 @@ function Carousel(props) {
|
|||||||
let scrollInterval = null;
|
let scrollInterval = null;
|
||||||
const style = {
|
const style = {
|
||||||
carousel: {
|
carousel: {
|
||||||
position: "relative"
|
position: 'relative'
|
||||||
},
|
},
|
||||||
carouselItem: {
|
carouselItem: {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
visibility: "hidden"
|
visibility: 'hidden'
|
||||||
},
|
},
|
||||||
visible: {
|
visible: {
|
||||||
visibility: "visible"
|
visibility: 'visible'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -57,11 +57,10 @@ ReactDOM.render(
|
|||||||
<div>carousel item 3</div>
|
<div>carousel item 3</div>
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: visual,children,state,effect -->
|
<!-- tags: visual,children,state,effect -->
|
||||||
|
|
||||||
<!-- expertise: 2 -->
|
<!-- expertise: 2 -->
|
||||||
|
|
||||||
|
|||||||
@ -14,24 +14,21 @@ function Collapse(props) {
|
|||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
collapsed: {
|
collapsed: {
|
||||||
display: "none"
|
display: 'none'
|
||||||
},
|
},
|
||||||
expanded: {
|
expanded: {
|
||||||
display: "block"
|
display: 'block'
|
||||||
},
|
},
|
||||||
buttonStyle: {
|
buttonStyle: {
|
||||||
display: "block",
|
display: 'block',
|
||||||
width: "100%"
|
width: '100%'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button style={style.buttonStyle} onClick={() => setIsCollapsed(!isCollapsed)}>
|
||||||
style={style.buttonStyle}
|
{isCollapsed ? 'Show' : 'Hide'} content
|
||||||
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
||||||
>
|
|
||||||
{isCollapsed ? "Show" : "Hide"} content
|
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
className="collapse-content"
|
className="collapse-content"
|
||||||
|
|||||||
@ -23,8 +23,7 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
|
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
if (paused || over) return;
|
if (paused || over) return;
|
||||||
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0)
|
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0) setOver(true);
|
||||||
setOver(true);
|
|
||||||
else if (time.minutes == 0 && time.seconds == 0)
|
else if (time.minutes == 0 && time.seconds == 0)
|
||||||
setTime({
|
setTime({
|
||||||
hours: time.hours - 1,
|
hours: time.hours - 1,
|
||||||
@ -62,15 +61,11 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{`${time.hours
|
<p>{`${time.hours.toString().padStart(2, '0')}:${time.minutes
|
||||||
.toString()
|
.toString()
|
||||||
.padStart(2, "0")}:${time.minutes
|
.padStart(2, '0')}:${time.seconds.toString().padStart(2, '0')}`}</p>
|
||||||
.toString()
|
<div>{over ? "Time's up!" : ''}</div>
|
||||||
.padStart(2, "0")}:${time.seconds.toString().padStart(2, "0")}`}</p>
|
<button onClick={() => setPaused(!paused)}>{paused ? 'Resume' : 'Pause'}</button>
|
||||||
<div>{over ? "Time's up!" : ""}</div>
|
|
||||||
<button onClick={() => setPaused(!paused)}>
|
|
||||||
{paused ? "Resume" : "Pause"}
|
|
||||||
</button>
|
|
||||||
<button onClick={() => reset()}>Restart</button>
|
<button onClick={() => reset()}>Restart</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -78,10 +73,7 @@ function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(<CountDown hours="1" minutes="45" />, document.getElementById('root'));
|
||||||
<CountDown hours="1" minutes="45" />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: visual,state -->
|
<!-- tags: visual,state -->
|
||||||
|
|||||||
@ -8,9 +8,7 @@ Omit the `isOrdered` prop to render a `<ul>` list by default.
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function DataList({ isOrdered, data }) {
|
function DataList({ isOrdered, data }) {
|
||||||
const list = data.map((val, i) => (
|
const list = data.map((val, i) => <li key={`${i}_${val}`}>{val}</li>);
|
||||||
<li key={`${i}_${val}`}>{val}</li>
|
|
||||||
));
|
|
||||||
return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
|
return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -16,12 +16,12 @@ function DataTable({ data }) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{data.map((val, i) =>
|
{data.map((val, i) => (
|
||||||
<tr key={`${i}_${val}`}>
|
<tr key={`${i}_${val}`}>
|
||||||
<td>{i}</td>
|
<td>{i}</td>
|
||||||
<td>{val}</td>
|
<td>{val}</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
@ -30,10 +30,7 @@ function DataTable({ data }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const people = ['John', 'Jesse'];
|
const people = ['John', 'Jesse'];
|
||||||
ReactDOM.render(
|
ReactDOM.render(<DataTable data={people} />, document.getElementById('root'));
|
||||||
<DataTable data={people} />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: array -->
|
<!-- tags: array -->
|
||||||
|
|||||||
@ -12,11 +12,10 @@ Each of the methods will handle a specific event, the listeners for which are cr
|
|||||||
Return an appropriately styled `<div>` and use `drag` and `filename` to determine its contents and style.
|
Return an appropriately styled `<div>` and use `drag` and `filename` to determine its contents and style.
|
||||||
Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
||||||
|
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.filedrop {
|
.filedrop {
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
border: 3px solid #D3D3D3;
|
border: 3px solid #d3d3d3;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
@ -24,11 +23,11 @@ Finally, bind the `ref` of the created `<div>` to `dropRef`.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filedrop.drag {
|
.filedrop.drag {
|
||||||
border: 3px dashed #1E90FF;
|
border: 3px dashed #1e90ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filedrop.ready {
|
.filedrop.ready {
|
||||||
border: 3px solid #32CD32;
|
border: 3px solid #32cd32;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -72,24 +71,22 @@ function FileDrop(props) {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
let div = dropRef.current;
|
let div = dropRef.current;
|
||||||
div.addEventListener("dragenter", handleDragIn);
|
div.addEventListener('dragenter', handleDragIn);
|
||||||
div.addEventListener("dragleave", handleDragOut);
|
div.addEventListener('dragleave', handleDragOut);
|
||||||
div.addEventListener("dragover", handleDrag);
|
div.addEventListener('dragover', handleDrag);
|
||||||
div.addEventListener("drop", handleDrop);
|
div.addEventListener('drop', handleDrop);
|
||||||
return function cleanup() {
|
return function cleanup() {
|
||||||
div.removeEventListener("dragenter", handleDragIn);
|
div.removeEventListener('dragenter', handleDragIn);
|
||||||
div.removeEventListener("dragleave", handleDragOut);
|
div.removeEventListener('dragleave', handleDragOut);
|
||||||
div.removeEventListener("dragover", handleDrag);
|
div.removeEventListener('dragover', handleDrag);
|
||||||
div.removeEventListener("drop", handleDrop);
|
div.removeEventListener('drop', handleDrop);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={dropRef}
|
ref={dropRef}
|
||||||
className={
|
className={drag ? 'filedrop drag' : filename ? 'filedrop ready' : 'filedrop'}
|
||||||
drag ? "filedrop drag" : filename ? "filedrop ready" : "filedrop"
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{filename && !drag ? <div>{filename}</div> : <div>Drop files here!</div>}
|
{filename && !drag ? <div>{filename}</div> : <div>Drop files here!</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -21,7 +21,7 @@ function Input ({ callback, type = 'text', disabled = false, readOnly = false, p
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Input type='text' placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,
|
<Input type="text" placeholder="Insert some text here..." callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@ -36,12 +36,9 @@ function LimitedTextarea({ rows, cols, value, limit }) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(<LimitedTextarea limit={32} value="Hello!" />, document.getElementById('root'));
|
||||||
<LimitedTextarea limit={32} value='Hello!' />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: input,state,effect -->
|
<!-- tags: input,state,effect -->
|
||||||
|
|
||||||
<!-- expertise: 0 -->
|
<!-- expertise: 0 -->
|
||||||
|
|
||||||
|
|||||||
@ -14,13 +14,13 @@ function LimitedWordTextarea({ rows, cols, value, limit }) {
|
|||||||
const [wordCount, setWordCount] = React.useState(0);
|
const [wordCount, setWordCount] = React.useState(0);
|
||||||
|
|
||||||
const setFormattedContent = text => {
|
const setFormattedContent = text => {
|
||||||
let words = text.split(" ");
|
let words = text.split(' ');
|
||||||
if (words.filter(Boolean).length > limit) {
|
if (words.filter(Boolean).length > limit) {
|
||||||
setContent(
|
setContent(
|
||||||
text
|
text
|
||||||
.split(" ")
|
.split(' ')
|
||||||
.slice(0, limit)
|
.slice(0, limit)
|
||||||
.join(" ")
|
.join(' ')
|
||||||
);
|
);
|
||||||
setWordCount(limit);
|
setWordCount(limit);
|
||||||
} else {
|
} else {
|
||||||
@ -51,11 +51,11 @@ function LimitedWordTextarea({ rows, cols, value, limit }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<LimitedWordTextArea limit={5} value='Hello there!' />,
|
<LimitedWordTextArea limit={5} value="Hello there!" />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: input,state,effect -->
|
<!-- tags: input,state,effect -->
|
||||||
|
|
||||||
<!-- expertise: 0 -->
|
<!-- expertise: 0 -->
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,7 @@ Render the link with `props.children` as its content.
|
|||||||
```jsx
|
```jsx
|
||||||
function Mailto({ email, subject, body, ...props }) {
|
function Mailto({ email, subject, body, ...props }) {
|
||||||
return (
|
return (
|
||||||
<a href={`mailto:${email}?subject=${subject || ""}&body=${body || ""}`}>
|
<a href={`mailto:${email}?subject=${subject || ''}&body=${body || ''}`}>{props.children}</a>
|
||||||
{props.children}
|
|
||||||
</a>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -20,7 +18,7 @@ ReactDOM.render(
|
|||||||
<Mailto email="foo@bar.baz" subject="Hello" body="Hello world!">
|
<Mailto email="foo@bar.baz" subject="Hello" body="Hello world!">
|
||||||
Mail me!
|
Mail me!
|
||||||
</Mailto>,
|
</Mailto>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -17,12 +17,18 @@ function MappedTable({ data, propertyNames }) {
|
|||||||
return (
|
return (
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>{propertyNames.map(val => <th key={`h_${val}`}>{val}</th>)}</tr>
|
<tr>
|
||||||
|
{propertyNames.map(val => (
|
||||||
|
<th key={`h_${val}`}>{val}</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{filteredData.map((val, i) => (
|
{filteredData.map((val, i) => (
|
||||||
<tr key={`i_${i}`}>
|
<tr key={`i_${i}`}>
|
||||||
{propertyNames.map(p => <td key={`i_${i}_${p}`}>{val[p]}</td>)}
|
{propertyNames.map(p => (
|
||||||
|
<td key={`i_${i}_${p}`}>{val[p]}</td>
|
||||||
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -44,7 +50,8 @@ ReactDOM.render(
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Notes:
|
#### 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`.
|
|
||||||
|
- 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 -->
|
<!-- tags: array,object -->
|
||||||
|
|
||||||
|
|||||||
@ -22,25 +22,20 @@ const style = {
|
|||||||
function MultiselectCheckbox({ options, onChange }) {
|
function MultiselectCheckbox({ options, onChange }) {
|
||||||
const [data, setData] = React.useState(options);
|
const [data, setData] = React.useState(options);
|
||||||
|
|
||||||
const toggle = (item) => {
|
const toggle = item => {
|
||||||
data.map((_, key) => {
|
data.map((_, key) => {
|
||||||
if (data[key].label === item.label)
|
if (data[key].label === item.label) data[key].checked = !item.checked;
|
||||||
data[key].checked = !item.checked;
|
|
||||||
});
|
});
|
||||||
setData([...data]);
|
setData([...data]);
|
||||||
onChange(data);
|
onChange(data);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul style={style.listContainer}>
|
<ul style={style.listContainer}>
|
||||||
{data.map(item => {
|
{data.map(item => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={item.label} style={style.itemStyle} onClick={() => toggle(item)}>
|
||||||
key={item.label}
|
<input readOnly type="checkbox" checked={item.checked || false} />
|
||||||
style={style.itemStyle}
|
|
||||||
onClick={() => toggle(item)}
|
|
||||||
>
|
|
||||||
<input readOnly type='checkbox' checked={item.checked || false} />
|
|
||||||
{item.label}
|
{item.label}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@ -51,7 +46,7 @@ function MultiselectCheckbox ({ options, onChange }) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const options = [{ label: "Item One" }, { label: "Item Two" }];
|
const options = [{ label: 'Item One' }, { label: 'Item Two' }];
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<MultiselectCheckbox
|
<MultiselectCheckbox
|
||||||
@ -60,7 +55,7 @@ ReactDOM.render(
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,7 @@ function PasswordRevealer({ value }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input type={shown ? 'text' : 'password'} value={value} onChange={() => {}} />
|
||||||
type={shown ? "text" : "password"}
|
|
||||||
value={value}
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<button onClick={() => setShown(!shown)}>Show/Hide</button>
|
<button onClick={() => setShown(!shown)}>Show/Hide</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -29,4 +25,3 @@ ReactDOM.render(<PasswordRevealer />, document.getElementById('root'));
|
|||||||
<!--tags: input,state -->
|
<!--tags: input,state -->
|
||||||
|
|
||||||
<!--expertise: 0 -->
|
<!--expertise: 0 -->
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,11 @@ function Select ({ values, callback, disabled = false, readonly = false, selecte
|
|||||||
readOnly={readonly}
|
readOnly={readonly}
|
||||||
onChange={({ target: { value } }) => callback(value)}
|
onChange={({ target: { value } }) => callback(value)}
|
||||||
>
|
>
|
||||||
{values.map(([value, text]) => <option selected={selected === value}value={value}>{text}</option>)}
|
{values.map(([value, text]) => (
|
||||||
|
<option selected={selected === value} value={value}>
|
||||||
|
{text}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -28,7 +32,7 @@ let choices = [
|
|||||||
['mango', 'Mango']
|
['mango', 'Mango']
|
||||||
];
|
];
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Select values={choices} selected='lime' callback={(val) => console.log(val)}/>,
|
<Select values={choices} selected="lime" callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@ -11,29 +11,25 @@ Finally, pass the appropriate values to each `<Star>` component (`starId` and `m
|
|||||||
```jsx
|
```jsx
|
||||||
function Star({ marked, starId }) {
|
function Star({ marked, starId }) {
|
||||||
return (
|
return (
|
||||||
<span star-id={starId} style={{ color: "#ff9933" }} role="button">
|
<span star-id={starId} style={{ color: '#ff9933' }} role="button">
|
||||||
{marked ? "\u2605" : "\u2606"}
|
{marked ? '\u2605' : '\u2606'}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function StarRating(props) {
|
function StarRating(props) {
|
||||||
const [rating, setRating] = React.useState(
|
const [rating, setRating] = React.useState(typeof props.rating == 'number' ? props.rating : 0);
|
||||||
typeof props.rating == "number" ? props.rating : 0
|
|
||||||
);
|
|
||||||
const [selection, setSelection] = React.useState(0);
|
const [selection, setSelection] = React.useState(0);
|
||||||
const hoverOver = event => {
|
const hoverOver = event => {
|
||||||
let val = 0;
|
let val = 0;
|
||||||
if (event && event.target && event.target.getAttribute("star-id"))
|
if (event && event.target && event.target.getAttribute('star-id'))
|
||||||
val = event.target.getAttribute("star-id");
|
val = event.target.getAttribute('star-id');
|
||||||
setSelection(val);
|
setSelection(val);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onMouseOut={() => hoverOver(null)}
|
onMouseOut={() => hoverOver(null)}
|
||||||
onClick={() =>
|
onClick={() => setRating(event.target.getAttribute('star-id') || this.state.rating)}
|
||||||
setRating(event.target.getAttribute("star-id") || this.state.rating)
|
|
||||||
}
|
|
||||||
onMouseOver={hoverOver}
|
onMouseOver={hoverOver}
|
||||||
>
|
>
|
||||||
{Array.from({ length: 5 }, (v, i) => (
|
{Array.from({ length: 5 }, (v, i) => (
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
### Tab
|
### Tab
|
||||||
|
|
||||||
Renders a tabbed menu and view component.
|
Renders a tabbed menu and view component.
|
||||||
|
|
||||||
Define a `TabItem` component, pass it to the `Tab` and remove unnecessary nodes expect for `TabItem` by identifying the function's name in `props.children`.
|
Define a `TabItem` component, pass it to the `Tab` and remove unnecessary nodes expect for `TabItem` by identifying the function's name in `props.children`.
|
||||||
@ -16,10 +17,10 @@ Define `changeTab`, which will be executed when clicking a `<button>` from the `
|
|||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
.tab-menu > button.focus {
|
.tab-menu > button.focus {
|
||||||
border-bottom: 2px solid #007BEF;
|
border-bottom: 2px solid #007bef;
|
||||||
}
|
}
|
||||||
.tab-menu > button:hover {
|
.tab-menu > button:hover {
|
||||||
border-bottom: 2px solid #007BEF;
|
border-bottom: 2px solid #007bef;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -31,19 +32,16 @@ function TabItem(props) {
|
|||||||
function Tabs(props) {
|
function Tabs(props) {
|
||||||
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
||||||
const changeTab = newIndex => {
|
const changeTab = newIndex => {
|
||||||
if (typeof props.onTabClick === "function") props.onTabClick(newIndex);
|
if (typeof props.onTabClick === 'function') props.onTabClick(newIndex);
|
||||||
setBindIndex(newIndex);
|
setBindIndex(newIndex);
|
||||||
};
|
};
|
||||||
const items = props.children.filter(item => item.type.name === "TabItem");
|
const items = props.children.filter(item => item.type.name === 'TabItem');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<div className="tab-menu">
|
<div className="tab-menu">
|
||||||
{items.map(({ props: { index, label } }) => (
|
{items.map(({ props: { index, label } }) => (
|
||||||
<button
|
<button onClick={() => changeTab(index)} className={bindIndex === index ? 'focus' : ''}>
|
||||||
onClick={() => changeTab(index)}
|
|
||||||
className={bindIndex === index ? "focus" : ""}
|
|
||||||
>
|
|
||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
@ -54,7 +52,7 @@ function Tabs(props) {
|
|||||||
{...props}
|
{...props}
|
||||||
className="tab-view_item"
|
className="tab-view_item"
|
||||||
key={props.index}
|
key={props.index}
|
||||||
style={{ display: bindIndex === props.index ? "block" : "none" }}
|
style={{ display: bindIndex === props.index ? 'block' : 'none' }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -62,6 +60,7 @@ function Tabs(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Tabs defaultIndex="1" onTabClick={console.log}>
|
<Tabs defaultIndex="1" onTabClick={console.log}>
|
||||||
@ -72,9 +71,8 @@ ReactDOM.render(
|
|||||||
Dolor sit amet
|
Dolor sit amet
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>,
|
</Tabs>,
|
||||||
document.getElementById("root")
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: visual,state,children -->
|
<!-- tags: visual,state,children -->
|
||||||
|
|||||||
@ -6,7 +6,14 @@ Use object destructuring to set defaults for certain attributes of the `<textare
|
|||||||
Render 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.
|
Render 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.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function TextArea ({ callback, cols = 20, rows = 2, disabled = false, readOnly = false, placeholder='' }) {
|
function TextArea({
|
||||||
|
callback,
|
||||||
|
cols = 20,
|
||||||
|
rows = 2,
|
||||||
|
disabled = false,
|
||||||
|
readOnly = false,
|
||||||
|
placeholder = ''
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
cols={cols}
|
cols={cols}
|
||||||
@ -22,7 +29,7 @@ function TextArea ({ callback, cols = 20, rows = 2, disabled = false, readOnly =
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<TextArea placeholder='Insert some text here...' callback={(val) => console.log(val)}/>,
|
<TextArea placeholder="Insert some text here..." callback={val => console.log(val)} />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@ -14,17 +14,15 @@ function Ticker(props) {
|
|||||||
const tick = () => {
|
const tick = () => {
|
||||||
reset();
|
reset();
|
||||||
interval = setInterval(() => {
|
interval = setInterval(() => {
|
||||||
if (ticker < props.times)
|
if (ticker < props.times) setTicker(ticker + 1);
|
||||||
setTicker(ticker + 1);
|
else clearInterval(interval);
|
||||||
else
|
|
||||||
clearInterval(interval);
|
|
||||||
}, props.interval);
|
}, props.interval);
|
||||||
}
|
};
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setTicker(0);
|
setTicker(0);
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -11,19 +11,16 @@ function Toggle(props) {
|
|||||||
const [isToggleOn, setIsToggleOn] = React.useState(false);
|
const [isToggleOn, setIsToggleOn] = React.useState(false);
|
||||||
style = {
|
style = {
|
||||||
on: {
|
on: {
|
||||||
backgroundColor: "green"
|
backgroundColor: 'green'
|
||||||
},
|
},
|
||||||
off: {
|
off: {
|
||||||
backgroundColor: "grey"
|
backgroundColor: 'grey'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button onClick={() => setIsToggleOn(!isToggleOn)} style={isToggleOn ? style.on : style.off}>
|
||||||
onClick={() => setIsToggleOn(!isToggleOn)}
|
{isToggleOn ? 'ON' : 'OFF'}
|
||||||
style={isToggleOn ? style.on : style.off}
|
|
||||||
>
|
|
||||||
{isToggleOn ? "ON" : "OFF"}
|
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,21 +24,18 @@ Handle the `onMouseEnter` and `onMouseLeave` methods, by altering the value of t
|
|||||||
border-color: rgba(0, 0, 0, 0.7) transparent transparent;
|
border-color: rgba(0, 0, 0, 0.7) transparent transparent;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function Tooltip({ children, text, ...rest }) {
|
function Tooltip({ children, text, ...rest }) {
|
||||||
const [show, setShow] = React.useState(false);
|
const [show, setShow] = React.useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="tooltip" style={show ? { visibility: "visible" } : {}}>
|
<div className="tooltip" style={show ? { visibility: 'visible' } : {}}>
|
||||||
{text}
|
{text}
|
||||||
<span className="tooltip-arrow" />
|
<span className="tooltip-arrow" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div {...rest} onMouseEnter={() => setShow(true)} onMouseLeave={() => setShow(false)}>
|
||||||
{...rest}
|
|
||||||
onMouseEnter={() => setShow(true)}
|
|
||||||
onMouseLeave={() => setShow(false)}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -48,7 +45,7 @@ function Tooltip({ children, text, ...rest }) {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Tooltip text='Simple tooltip'>
|
<Tooltip text="Simple tooltip">
|
||||||
<button>Hover me!</button>
|
<button>Hover me!</button>
|
||||||
</Tooltip>,
|
</Tooltip>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
|
|||||||
@ -59,19 +59,18 @@ function TreeView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ marginLeft: isChildElement ? 16 : 4 + "px" }}
|
style={{ marginLeft: isChildElement ? 16 : 4 + 'px' }}
|
||||||
className={isParentToggled ? "tree-element" : "tree-element collapsed"}
|
className={isParentToggled ? 'tree-element' : 'tree-element collapsed'}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={isToggled ? "toggler" : "toggler closed"}
|
className={isToggled ? 'toggler' : 'toggler closed'}
|
||||||
onClick={() => setIsToggled(!isToggled)}
|
onClick={() => setIsToggled(!isToggled)}
|
||||||
/>
|
/>
|
||||||
{name ? <strong> {name}: </strong> : <span> </span>}
|
{name ? <strong> {name}: </strong> : <span> </span>}
|
||||||
{Array.isArray(data) ? "[" : "{"}
|
{Array.isArray(data) ? '[' : '{'}
|
||||||
{!isToggled && "..."}
|
{!isToggled && '...'}
|
||||||
{Object.keys(data).map(
|
{Object.keys(data).map((v, i, a) =>
|
||||||
(v, i, a) =>
|
typeof data[v] == 'object' ? (
|
||||||
typeof data[v] == "object" ? (
|
|
||||||
<TreeView
|
<TreeView
|
||||||
data={data[v]}
|
data={data[v]}
|
||||||
isLast={i === a.length - 1}
|
isLast={i === a.length - 1}
|
||||||
@ -81,17 +80,17 @@ function TreeView({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<p
|
<p
|
||||||
style={{ marginLeft: 16 + "px" }}
|
style={{ marginLeft: 16 + 'px' }}
|
||||||
className={isToggled ? "tree-element" : "tree-element collapsed"}
|
className={isToggled ? 'tree-element' : 'tree-element collapsed'}
|
||||||
>
|
>
|
||||||
{Array.isArray(data) ? "" : <strong>{v}: </strong>}
|
{Array.isArray(data) ? '' : <strong>{v}: </strong>}
|
||||||
{data[v]}
|
{data[v]}
|
||||||
{i === a.length - 1 ? "" : ","}
|
{i === a.length - 1 ? '' : ','}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{Array.isArray(data) ? "]" : "}"}
|
{Array.isArray(data) ? ']' : '}'}
|
||||||
{!isLast ? "," : ""}
|
{!isLast ? ',' : ''}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,27 +99,27 @@ function TreeView({
|
|||||||
```jsx
|
```jsx
|
||||||
let data = {
|
let data = {
|
||||||
lorem: {
|
lorem: {
|
||||||
ipsum: "dolor sit",
|
ipsum: 'dolor sit',
|
||||||
amet: {
|
amet: {
|
||||||
consectetur: "adipiscing",
|
consectetur: 'adipiscing',
|
||||||
elit: [
|
elit: [
|
||||||
"duis",
|
'duis',
|
||||||
"vitae",
|
'vitae',
|
||||||
{
|
{
|
||||||
semper: "orci"
|
semper: 'orci'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
est: "sed ornare"
|
est: 'sed ornare'
|
||||||
},
|
},
|
||||||
"etiam",
|
'etiam',
|
||||||
["laoreet", "tincidunt"],
|
['laoreet', 'tincidunt'],
|
||||||
["vestibulum", "ante"]
|
['vestibulum', 'ante']
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
ipsum: "primis"
|
ipsum: 'primis'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ReactDOM.render(<TreeView data={data} name='data'/>, document.getElementById("root"));
|
ReactDOM.render(<TreeView data={data} name="data" />, document.getElementById('root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- tags: object,visual,state,recursion -->
|
<!-- tags: object,visual,state,recursion -->
|
||||||
|
|||||||
@ -8,9 +8,10 @@ Define `close` and `modalClick` to toggle the visibility of the modal dialog, ba
|
|||||||
Use the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.
|
Use the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.
|
||||||
|
|
||||||
The `show()` method accepts an argument, that should contain three parameters:
|
The `show()` method accepts an argument, that should contain three parameters:
|
||||||
* `title`, a string for the dialog's title
|
|
||||||
* `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the *X* button
|
- `title`, a string for the dialog's title
|
||||||
* `content`, which is the JSX content to be rendered inside the dialog
|
- `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the _X_ button
|
||||||
|
- `content`, which is the JSX content to be rendered inside the dialog
|
||||||
|
|
||||||
Finally, in the `render()` method, use a `<div>` to wrap everything and render the modal dialog with the content passed to `show()`.
|
Finally, in the `render()` method, use a `<div>` to wrap everything and render the modal dialog with the content passed to `show()`.
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ Finally, in the `render()` method, use a `<div>` to wrap everything and render t
|
|||||||
class ModalDialog extends React.Component {
|
class ModalDialog extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.modalHandler = (e) => {
|
this.modalHandler = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
data: e.detail.data,
|
data: e.detail.data,
|
||||||
visible: true
|
visible: true
|
||||||
@ -79,16 +80,19 @@ class ModalDialog extends React.Component {
|
|||||||
this.modalClick = this.modalClick.bind(this);
|
this.modalClick = this.modalClick.bind(this);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return !this.state.visible ? null : <div className="modal" onClick={this.modalClick}>
|
return !this.state.visible ? null : (
|
||||||
|
<div className="modal" onClick={this.modalClick}>
|
||||||
<div className="dialog">
|
<div className="dialog">
|
||||||
<div className="dialog-title">{ this.state.data.title }<span className="dialog-close" onClick={this.close}>+</span></div>
|
<div className="dialog-title">
|
||||||
<div className="dialog-content">
|
{this.state.data.title}
|
||||||
{
|
<span className="dialog-close" onClick={this.close}>
|
||||||
this.state.data.content
|
+
|
||||||
}
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="dialog-content">{this.state.data.content}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.addEventListener('modal', this.modalHandler);
|
document.addEventListener('modal', this.modalHandler);
|
||||||
@ -107,11 +111,13 @@ class ModalDialog extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
static show(data) {
|
static show(data) {
|
||||||
document.dispatchEvent(new CustomEvent('modal', {
|
document.dispatchEvent(
|
||||||
|
new CustomEvent('modal', {
|
||||||
detail: {
|
detail: {
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
modalClick() {
|
modalClick() {
|
||||||
if (this.state.data.closeOnClick) this.close();
|
if (this.state.data.closeOnClick) this.close();
|
||||||
@ -121,7 +127,7 @@ class ModalDialog extends React.Component {
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
// add to render function
|
// add to render function
|
||||||
<ModalDialog />
|
<ModalDialog />;
|
||||||
|
|
||||||
// every time you wanna call the dialog
|
// every time you wanna call the dialog
|
||||||
// content is a jsx element
|
// content is a jsx element
|
||||||
@ -133,8 +139,9 @@ ModalDialog.show({
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Notes:
|
#### 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+.
|
- 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 -->
|
<!-- tags: visual,static,children,state,class -->
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
-----
|
---
|
||||||
|
|
||||||
*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!*
|
_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!_
|
||||||
|
|
||||||
*This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder).*
|
_This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder)._
|
||||||
|
|||||||
@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
> Curated collection of useful React snippets that you can understand in 30 seconds or less.
|
> Curated collection of useful React snippets that you can understand in 30 seconds or less.
|
||||||
|
|
||||||
* Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet.
|
- Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet.
|
||||||
* Contributions welcome, please read the [contribution guide](CONTRIBUTING.md).
|
- Contributions welcome, please read the [contribution guide](CONTRIBUTING.md).
|
||||||
* Snippets are written in React 16.8+, using hooks.
|
- Snippets are written in React 16.8+, using hooks.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
To import a snippet into your project, you must import `React` and copy-paste the component's JavaScript code like this:
|
To import a snippet into your project, you must import `React` and copy-paste the component's JavaScript code like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@ -20,19 +21,21 @@ 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:
|
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
|
```js
|
||||||
import './MyComponent.css';
|
import './MyComponent.css';
|
||||||
```
|
```
|
||||||
|
|
||||||
To render your component, make sure there is a node with and id of `"root"` present in your element (preferrably a `<div>`) and that you have imported `ReactDOM`, like this:
|
To render your component, make sure there is a node with and id of `"root"` present in your element (preferrably a `<div>`) and that you have imported `ReactDOM`, like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Related projects
|
#### Related projects
|
||||||
|
|
||||||
* [30 Seconds of Code](https://30secondsofcode.org)
|
- [30 Seconds of Code](https://30secondsofcode.org)
|
||||||
* [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/)
|
- [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/)
|
||||||
* [30 Seconds of Interviews](https://30secondsofinterviews.org/)
|
- [30 Seconds of Interviews](https://30secondsofinterviews.org/)
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|||||||
Reference in New Issue
Block a user