Update StarRating
This commit is contained in:
206
README.md
206
README.md
@ -64,7 +64,6 @@
|
||||
* [Collapse](#collapse)
|
||||
* [FileDrop](#filedrop)
|
||||
* [Mailto](#mailto)
|
||||
* [ModalDialog](#modaldialog)
|
||||
* [StarRating](#starrating)
|
||||
* [Tab](#tab)
|
||||
* [Ticker](#ticker)
|
||||
@ -850,215 +849,54 @@ ReactDOM.render(
|
||||
|
||||
<br>[⬆ Back to top](#table-of-contents)
|
||||
|
||||
### ModalDialog
|
||||
|
||||
Renders a dialog component in a modal, controllable through events.
|
||||
To use the component, import `ModalDialog` only once and then display it using `ModalDialog.show()`, passing the JSX templates and data as parameters.
|
||||
|
||||
Define `modalHandler`, a method that will handle showing the modal dialog, set `state` to the default values initially and bind the `close` and `modalClick` methods to the component's context.
|
||||
Define `close` and `modalClick` to toggle the visibility of the modal dialog, based on `state.closeOnClick`.
|
||||
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:
|
||||
* `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
|
||||
* `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()`.
|
||||
|
||||
```css
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
z-index: 9998;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.dialog {
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dialog-title {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
border-bottom: 0.5px solid #c3c3c3;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.dialog-close {
|
||||
font-size: 32px;
|
||||
color: #c3c3c3;
|
||||
cursor: pointer;
|
||||
transform: rotate(45deg);
|
||||
user-select: none;
|
||||
}
|
||||
.dialog-close:hover {
|
||||
color: red;
|
||||
}
|
||||
.dialog-content {
|
||||
min-width: 300px;
|
||||
}
|
||||
```
|
||||
|
||||
```jsx
|
||||
class ModalDialog extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.modalHandler = (e) => {
|
||||
this.setState({
|
||||
data: e.detail.data,
|
||||
visible: true
|
||||
});
|
||||
};
|
||||
this.state = {
|
||||
data: {
|
||||
title: '',
|
||||
closeOnClick: false,
|
||||
content: ''
|
||||
},
|
||||
visible: false
|
||||
};
|
||||
this.close = this.close.bind(this);
|
||||
this.modalClick = this.modalClick.bind(this);
|
||||
}
|
||||
render() {
|
||||
return !this.state.visible ? null : <div className="modal" onClick={this.modalClick}>
|
||||
<div className="dialog">
|
||||
<div className="dialog-title">{ this.state.data.title }<span className="dialog-close" onClick={this.close}>+</span></div>
|
||||
<div className="dialog-content">
|
||||
{
|
||||
this.state.data.content
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
componentDidMount() {
|
||||
document.addEventListener('modal', this.modalHandler);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('modal', this.modalHandler);
|
||||
}
|
||||
close() {
|
||||
this.setState({
|
||||
visible: false,
|
||||
data: {
|
||||
title: '',
|
||||
closeOnClick: false,
|
||||
content: ''
|
||||
}
|
||||
});
|
||||
}
|
||||
static show(data) {
|
||||
document.dispatchEvent(new CustomEvent('modal', {
|
||||
detail: {
|
||||
data
|
||||
}
|
||||
}));
|
||||
}
|
||||
modalClick() {
|
||||
if (this.state.data.closeOnClick) this.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
#### Notes
|
||||
|
||||
This component includes a lot of CSS, which might conflict with other CSS in your project. It is recomended for the modal to be a direct child of the body tag.,A more up-to-date method with lower compatibility is to use [Portals](https://reactjs.org/docs/portals.html) in React 16+.,<!-tags: visual,static,children,state,class -->,<!-expertise: 1 -->
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
```jsx
|
||||
// add to render function
|
||||
<ModalDialog />
|
||||
|
||||
// every time you wanna call the dialog
|
||||
// content is a jsx element
|
||||
ModalDialog.show({
|
||||
title: 'Hello, world!',
|
||||
closeOnClick: true,
|
||||
content: <img src="https://github.com/30-seconds/30-seconds-of-react/blob/master/logo.png"/>
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
<br>[⬆ Back to top](#table-of-contents)
|
||||
|
||||
### StarRating
|
||||
|
||||
Renders a star rating component.
|
||||
|
||||
Use and IIFE to define a functional component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's `state` and return the class component `StarRating`.
|
||||
Use the value of the `rating` prop to determine if a valid rating is supplied and store it in `state.rating` (or `0` if invalid or not supplied).
|
||||
Initialize `state.selection` to `0`.
|
||||
Create two methods, `hoverOver` and `setRating`, that take an event as argument and update `state.selected` and `state.rating` according to it, bind them both to the component's context.
|
||||
In the `render()` method, create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `state.selection` to `0`, the `onClick` event to set
|
||||
the `state.rating` and the `onMouseOver` event to set `state.selection` to the `star-id` attribute of the `event.target` respectively.
|
||||
Define a component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's state.
|
||||
In the `StarRating` component, use the `React.setState()` hook to define the `rating` and `selection` state variables with the initial values of `props.rating` (or `0` if invalid or not supplied) and `0`.
|
||||
Create a method, `hoverOver`, that updates `selected` and `rating` according to the provided `event`.
|
||||
Create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `selection` to `0`, the `onClick` event to set the `rating` and the `onMouseOver` event to set `selection` to the `star-id` attribute of the `event.target` respectively.
|
||||
Finally, pass the appropriate values to each `<Star>` component (`starId` and `marked`).
|
||||
|
||||
```jsx
|
||||
const StarRating = (function() {
|
||||
function Star({ marked, starId }) {
|
||||
return (
|
||||
<span star-id={starId} style={{ color: '#ff9933' }} role='button'>
|
||||
{marked ? '\u2605' : '\u2606'}
|
||||
<span star-id={starId} style={{ color: "#ff9933" }} role="button">
|
||||
{marked ? "\u2605" : "\u2606"}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return class StarRating extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
rating: typeof props.rating == 'number' ? props.rating : 0,
|
||||
selection: 0
|
||||
};
|
||||
this.hoverOver = this.hoverOver.bind(this);
|
||||
this.hoverOut = this.hoverOver.bind(this, null);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
hoverOver(event) {
|
||||
function StarRating(props) {
|
||||
const [rating, setRating] = React.useState(
|
||||
typeof props.rating == "number" ? props.rating : 0
|
||||
);
|
||||
const [selection, setSelection] = React.useState(0);
|
||||
const hoverOver = event => {
|
||||
let val = 0;
|
||||
if (event && event.target && event.target.getAttribute('star-id'))
|
||||
val = event.target.getAttribute('star-id');
|
||||
this.setState(state => ({ selection: val }));
|
||||
}
|
||||
handleClick(event) {
|
||||
const val = event.target.getAttribute('star-id') || this.state.rating;
|
||||
this.setState(state => ({ rating: val }));
|
||||
}
|
||||
render() {
|
||||
if (event && event.target && event.target.getAttribute("star-id"))
|
||||
val = event.target.getAttribute("star-id");
|
||||
setSelection(val);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
onMouseOut={this.hoverOut}
|
||||
onClick={this.handleClick}
|
||||
onMouseOver={this.hoverOver}
|
||||
onMouseOut={() => hoverOver(null)}
|
||||
onClick={() =>
|
||||
setRating(event.target.getAttribute("star-id") || this.state.rating)
|
||||
}
|
||||
onMouseOver={hoverOver}
|
||||
>
|
||||
{Array.from({ length: 5 }, (v, i) => (
|
||||
<Star
|
||||
starId={i + 1}
|
||||
key={`star_${i + 1} `}
|
||||
marked={
|
||||
this.state.selection
|
||||
? this.state.selection >= i+1
|
||||
: this.state.rating >= i+1
|
||||
}
|
||||
marked={selection ? selection >= i + 1 : rating >= i + 1}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
})();
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
@ -163,30 +163,6 @@
|
||||
"<!-expertise: 1 -->"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ModalDialog.md",
|
||||
"title": "ModalDialog",
|
||||
"text": "Renders a dialog component in a modal, controllable through events. \nTo use the component, import `ModalDialog` only once and then display it using `ModalDialog.show()`, passing the JSX templates and data as parameters.\n\nDefine `modalHandler`, a method that will handle showing the modal dialog, set `state` to the default values initially and bind the `close` and `modalClick` methods to the component's context.\nDefine `close` and `modalClick` to toggle the visibility of the modal dialog, based on `state.closeOnClick`.\nUse the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.\n\nThe `show()` method accepts an argument, that should contain three parameters:\n* `title`, a string for the dialog's title\n* `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the *X* button\n* `content`, which is the JSX content to be rendered inside the dialog\n\nFinally, in the `render()` method, use a `<div>` to wrap everything and render the modal dialog with the content passed to `show()`.\n\n",
|
||||
"codeBlocks": [
|
||||
"```css\n .modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.6);\n z-index: 9998;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .dialog {\n background-color: white;\n border-radius: 5px;\n overflow: hidden;\n }\n .dialog-title {\n box-sizing: border-box;\n width: 100%;\n height: 48px;\n padding: 0 16px;\n border-bottom: 0.5px solid #c3c3c3;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .dialog-close {\n font-size: 32px;\n color: #c3c3c3;\n cursor: pointer;\n transform: rotate(45deg);\n user-select: none;\n }\n .dialog-close:hover {\n color: red;\n }\n .dialog-content {\n min-width: 300px;\n }\n```",
|
||||
"```jsx\nclass ModalDialog extends React.Component {\n constructor() {\n super();\n this.modalHandler = (e) => {\n this.setState({\n data: e.detail.data,\n visible: true\n });\n };\n this.state = {\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n },\n visible: false\n };\n this.close = this.close.bind(this);\n this.modalClick = this.modalClick.bind(this);\n }\n render() {\n return !this.state.visible ? null : <div className=\"modal\" onClick={this.modalClick}>\n <div className=\"dialog\">\n <div className=\"dialog-title\">{ this.state.data.title }<span className=\"dialog-close\" onClick={this.close}>+</span></div>\n <div className=\"dialog-content\">\n {\n this.state.data.content\n }\n </div>\n </div>\n </div>\n }\n componentDidMount() {\n document.addEventListener('modal', this.modalHandler);\n }\n componentWillUnmount() {\n document.removeEventListener('modal', this.modalHandler);\n }\n close() {\n this.setState({\n visible: false,\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n }\n });\n }\n static show(data) {\n document.dispatchEvent(new CustomEvent('modal', {\n detail: {\n data\n }\n }));\n }\n modalClick() {\n if (this.state.data.closeOnClick) this.close();\n }\n}\n```",
|
||||
"```jsx\n// add to render function\n<ModalDialog />\n\n// every time you wanna call the dialog\n// content is a jsx element\nModalDialog.show({\n title: 'Hello, world!',\n closeOnClick: true,\n content: <img src=\"https://github.com/30-seconds/30-seconds-of-react/blob/master/logo.png\"/>\n}); \n```"
|
||||
],
|
||||
"expertise": 1,
|
||||
"tags": [
|
||||
"visual",
|
||||
"static",
|
||||
"children",
|
||||
"state",
|
||||
"class"
|
||||
],
|
||||
"notes": [
|
||||
"This component includes a lot of CSS, which might conflict with other CSS in your project. It is recomended for the modal to be a direct child of the body tag.",
|
||||
"A more up-to-date method with lower compatibility is to use [Portals](https://reactjs.org/docs/portals.html) in React 16+.",
|
||||
"<!-tags: visual,static,children,state,class -->",
|
||||
"<!-expertise: 1 -->"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PasswordRevealer.md",
|
||||
"title": "PasswordRevealer",
|
||||
@ -221,9 +197,9 @@
|
||||
{
|
||||
"name": "StarRating.md",
|
||||
"title": "StarRating",
|
||||
"text": "Renders a star rating component.\n\nUse and IIFE to define a functional component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's `state` and return the class component `StarRating`.\nUse the value of the `rating` prop to determine if a valid rating is supplied and store it in `state.rating` (or `0` if invalid or not supplied).\nInitialize `state.selection` to `0`.\nCreate two methods, `hoverOver` and `setRating`, that take an event as argument and update `state.selected` and `state.rating` according to it, bind them both to the component's context.\nIn the `render()` method, create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `state.selection` to `0`, the `onClick` event to set\nthe `state.rating` and the `onMouseOver` event to set `state.selection` to the `star-id` attribute of the `event.target` respectively. \nFinally, pass the appropriate values to each `<Star>` component (`starId` and `marked`).\n\n",
|
||||
"text": "Renders a star rating component.\n\nDefine a component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's state.\nIn the `StarRating` component, use the `React.setState()` hook to define the `rating` and `selection` state variables with the initial values of `props.rating` (or `0` if invalid or not supplied) and `0`.\nCreate a method, `hoverOver`, that updates `selected` and `rating` according to the provided `event`.\nCreate a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `selection` to `0`, the `onClick` event to set the `rating` and the `onMouseOver` event to set `selection` to the `star-id` attribute of the `event.target` respectively. \nFinally, pass the appropriate values to each `<Star>` component (`starId` and `marked`).\n\n",
|
||||
"codeBlocks": [
|
||||
"```jsx\nconst StarRating = (function() {\n function Star({ marked, starId }) {\n return (\n <span star-id={starId} style={{ color: '#ff9933' }} role='button'>\n {marked ? '\\u2605' : '\\u2606'}\n </span>\n );\n }\n\n return class StarRating extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n rating: typeof props.rating == 'number' ? props.rating : 0,\n selection: 0\n };\n this.hoverOver = this.hoverOver.bind(this);\n this.hoverOut = this.hoverOver.bind(this, null);\n this.handleClick = this.handleClick.bind(this);\n }\n hoverOver(event) {\n let val = 0;\n if (event && event.target && event.target.getAttribute('star-id'))\n val = event.target.getAttribute('star-id');\n this.setState(state => ({ selection: val }));\n }\n handleClick(event) {\n const val = event.target.getAttribute('star-id') || this.state.rating;\n this.setState(state => ({ rating: val }));\n }\n render() {\n return (\n <div\n onMouseOut={this.hoverOut}\n onClick={this.handleClick}\n onMouseOver={this.hoverOver}\n >\n {Array.from({ length: 5 }, (v, i) => (\n <Star\n starId={i+1}\n key={`star_${i+1} `}\n marked={\n this.state.selection\n ? this.state.selection >= i+1\n : this.state.rating >= i+1\n }\n />\n ))}\n </div>\n );\n }\n };\n})();\n```",
|
||||
"```jsx\nfunction Star({ marked, starId }) {\n return (\n <span star-id={starId} style={{ color: \"#ff9933\" }} role=\"button\">\n {marked ? \"\\u2605\" : \"\\u2606\"}\n </span>\n );\n}\n\nfunction StarRating(props) {\n const [rating, setRating] = React.useState(\n typeof props.rating == \"number\" ? props.rating : 0\n );\n const [selection, setSelection] = React.useState(0);\n const hoverOver = event => {\n let val = 0;\n if (event && event.target && event.target.getAttribute(\"star-id\"))\n val = event.target.getAttribute(\"star-id\");\n setSelection(val);\n };\n return (\n <div\n onMouseOut={() => hoverOver(null)}\n onClick={() =>\n setRating(event.target.getAttribute(\"star-id\") || this.state.rating)\n }\n onMouseOver={hoverOver}\n >\n {Array.from({ length: 5 }, (v, i) => (\n <Star\n starId={i + 1}\n key={`star_${i + 1} `}\n marked={selection ? selection >= i + 1 : rating >= i + 1}\n />\n ))}\n </div>\n );\n}\n```",
|
||||
"```jsx\nReactDOM.render(<StarRating/>, document.getElementById('root'));\nReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));\n```"
|
||||
],
|
||||
"expertise": 2,
|
||||
|
||||
@ -2,68 +2,50 @@
|
||||
|
||||
Renders a star rating component.
|
||||
|
||||
Use and IIFE to define a functional component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's `state` and return the class component `StarRating`.
|
||||
Use the value of the `rating` prop to determine if a valid rating is supplied and store it in `state.rating` (or `0` if invalid or not supplied).
|
||||
Initialize `state.selection` to `0`.
|
||||
Create two methods, `hoverOver` and `setRating`, that take an event as argument and update `state.selected` and `state.rating` according to it, bind them both to the component's context.
|
||||
In the `render()` method, create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `state.selection` to `0`, the `onClick` event to set
|
||||
the `state.rating` and the `onMouseOver` event to set `state.selection` to the `star-id` attribute of the `event.target` respectively.
|
||||
Define a component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's state.
|
||||
In the `StarRating` component, use the `React.setState()` hook to define the `rating` and `selection` state variables with the initial values of `props.rating` (or `0` if invalid or not supplied) and `0`.
|
||||
Create a method, `hoverOver`, that updates `selected` and `rating` according to the provided `event`.
|
||||
Create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map` on an array of 5 elements, created using `Array.from`, and handle the `onMouseLeave` event to set `selection` to `0`, the `onClick` event to set the `rating` and the `onMouseOver` event to set `selection` to the `star-id` attribute of the `event.target` respectively.
|
||||
Finally, pass the appropriate values to each `<Star>` component (`starId` and `marked`).
|
||||
|
||||
```jsx
|
||||
const StarRating = (function() {
|
||||
function Star({ marked, starId }) {
|
||||
return (
|
||||
<span star-id={starId} style={{ color: '#ff9933' }} role='button'>
|
||||
{marked ? '\u2605' : '\u2606'}
|
||||
<span star-id={starId} style={{ color: "#ff9933" }} role="button">
|
||||
{marked ? "\u2605" : "\u2606"}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return class StarRating extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
rating: typeof props.rating == 'number' ? props.rating : 0,
|
||||
selection: 0
|
||||
};
|
||||
this.hoverOver = this.hoverOver.bind(this);
|
||||
this.hoverOut = this.hoverOver.bind(this, null);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
hoverOver(event) {
|
||||
function StarRating(props) {
|
||||
const [rating, setRating] = React.useState(
|
||||
typeof props.rating == "number" ? props.rating : 0
|
||||
);
|
||||
const [selection, setSelection] = React.useState(0);
|
||||
const hoverOver = event => {
|
||||
let val = 0;
|
||||
if (event && event.target && event.target.getAttribute('star-id'))
|
||||
val = event.target.getAttribute('star-id');
|
||||
this.setState(state => ({ selection: val }));
|
||||
}
|
||||
handleClick(event) {
|
||||
const val = event.target.getAttribute('star-id') || this.state.rating;
|
||||
this.setState(state => ({ rating: val }));
|
||||
}
|
||||
render() {
|
||||
if (event && event.target && event.target.getAttribute("star-id"))
|
||||
val = event.target.getAttribute("star-id");
|
||||
setSelection(val);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
onMouseOut={this.hoverOut}
|
||||
onClick={this.handleClick}
|
||||
onMouseOver={this.hoverOver}
|
||||
onMouseOut={() => hoverOver(null)}
|
||||
onClick={() =>
|
||||
setRating(event.target.getAttribute("star-id") || this.state.rating)
|
||||
}
|
||||
onMouseOver={hoverOver}
|
||||
>
|
||||
{Array.from({ length: 5 }, (v, i) => (
|
||||
<Star
|
||||
starId={i + 1}
|
||||
key={`star_${i + 1} `}
|
||||
marked={
|
||||
this.state.selection
|
||||
? this.state.selection >= i+1
|
||||
: this.state.rating >= i+1
|
||||
}
|
||||
marked={selection ? selection >= i + 1 : rating >= i + 1}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
})();
|
||||
```
|
||||
|
||||
```jsx
|
||||
|
||||
Reference in New Issue
Block a user