Added the ability to accept on scroll. Fixes #21

This commit is contained in:
Rick van Lieshout 2018-07-13 22:50:43 +02:00
parent ace3cf2886
commit 3f6c47ae6d
3 changed files with 117 additions and 31 deletions

View File

@ -4,26 +4,23 @@ A small, simple and customizable cookie consent bar for use in React application
[![NPM](https://nodei.co/npm/react-cookie-consent.png)](https://npmjs.org/package/react-cookie-consent) [![NPM](https://nodei.co/npm/react-cookie-consent.png)](https://npmjs.org/package/react-cookie-consent)
Demo: https://mastermindzh.github.io/react-cookie-consent/ Demo: https://mastermindzh.github.io/react-cookie-consent/
Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/example Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/example
## Default look ## Default look
![default look](https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/master/images/default.png) ![default look](https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/master/images/default.png)
## Installation ## Installation
``` ``` shell
npm install react-cookie-consent npm install react-cookie-consent
``` ```
or use yarn: or use yarn:
``` ``` shell
yarn add react-cookie-consent yarn add react-cookie-consent
``` ```
@ -31,21 +28,24 @@ yarn add react-cookie-consent
You can import the cookie bar like this: You can import the cookie bar like this:
```js ``` js
import CookieConsent from "react-cookie-consent"; import CookieConsent from "react-cookie-consent";
``` ```
If you want to set/remove cookies yourself you can optionally import Cookie (straight from js-cookie) like this: If you want to set/remove cookies yourself you can optionally import Cookie (straight from js-cookie) like this:
```js
``` js
import CookieConsent, { Cookies } from "react-cookie-consent"; import CookieConsent, { Cookies } from "react-cookie-consent";
``` ```
Then you can use the component anywhere in your React app like so: Then you can use the component anywhere in your React app like so:
```js ```jsx
<CookieConsent> <CookieConsent>
This website uses cookies to enhance the user experience. This website uses cookies to enhance the user experience.
</CookieConsent> </CookieConsent>
``` ```
You can optionally set some props like this (next chapter will show all props): You can optionally set some props like this (next chapter will show all props):
```js ```js
@ -81,19 +81,20 @@ One of the props (onAccept) is a function, this function will be called after th
| children | string or React component | | Content to appear inside the bar | | children | string or React component | | Content to appear inside the bar |
| disableStyles | boolean | false | If enabled the component will have no default style. (you can still supply style through props) | | disableStyles | boolean | false | If enabled the component will have no default style. (you can still supply style through props) |
| hideOnAccept | boolean | true | If disabled the component will not hide it self after the accept button has been clicked. You will need to hide yourself (see onAccept)| | hideOnAccept | boolean | true | If disabled the component will not hide it self after the accept button has been clicked. You will need to hide yourself (see onAccept)|
| buttonText | string or React component | "I understand" | Text to appear on the button | | acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) |
| cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. | | acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled |
| onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. | | buttonText | string or React component | "I understand" | Text to appear on the button |
| debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. | | cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. |
| expires | number | 365 | Number of days before the cookie expires. | | onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. |
| containerClasses| string | "" | CSS classes to apply to the surrounding container | | debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. |
| buttonClasses | string | "" | CSS classes to apply to the button| | expires | number | 365 | Number of days before the cookie expires. |
| contentClasses| string | "" | CSS classes to apply to the content | | containerClasses| string | "" | CSS classes to apply to the surrounding container |
| buttonClasses | string | "" | CSS classes to apply to the button |
| contentClasses| string | "" | CSS classes to apply to the content |
| style | object | [look at source][style] | React styling object for the bar. | | style | object | [look at source][style] | React styling object for the bar. |
| buttonStyle | object | [look at source][buttonStyle] | React styling object for the button. | | buttonStyle | object | [look at source][buttonStyle] | React styling object for the button. |
| contentStyle | object | [look at source][contentStyle] | React styling object for the content. | | contentStyle | object | [look at source][contentStyle] | React styling object for the content. |
## Debugging it ## Debugging it
Because the cookie consent bar will be hidden once accepted, you will have to set the prop `debug={true}` to evaluate styling changes: Because the cookie consent bar will be hidden once accepted, you will have to set the prop `debug={true}` to evaluate styling changes:
@ -107,7 +108,6 @@ Because the cookie consent bar will be hidden once accepted, you will have to se
**Note:** Dont forget to remove the `debug`-property for production. **Note:** Dont forget to remove the `debug`-property for production.
## Styling it ## Styling it
You can provide styling for the bar, the button and the content. Note that the bar has a `display: flex` property as default and is parent to its children "content" and "button". You can provide styling for the bar, the button and the content. Note that the bar has a `display: flex` property as default and is parent to its children "content" and "button".
@ -131,6 +131,7 @@ You can use `disableStyles={true}` to disable any built-in styling.
``` ```
#### changing the button font-weight to bold #### changing the button font-weight to bold
```js ```js
<CookieConsent <CookieConsent
buttonStyle={{ fontWeight: "bold" }} buttonStyle={{ fontWeight: "bold" }}
@ -139,6 +140,7 @@ You can use `disableStyles={true}` to disable any built-in styling.
``` ```
#### Using predefined CSS classes #### Using predefined CSS classes
You can pass predefined CSS classes to the components using the `containerClasses`, `buttonClasses` and `contentClasses` props. The example below uses bootstrap classes: You can pass predefined CSS classes to the components using the `containerClasses`, `buttonClasses` and `contentClasses` props. The example below uses bootstrap classes:
```js ```js
@ -158,7 +160,7 @@ You can pass predefined CSS classes to the components using the `containerClasse
Which results in: Which results in:
![bootstrap styling](./images/css_classes.png) ![bootstrap styling](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/css_classes.png?raw=true)
#### rainbows! #### rainbows!

View File

@ -573,6 +573,8 @@ var CookieConsent = function (_Component) {
margin: "15px" margin: "15px"
} }
}; };
_this.handleScroll = _this.handleScroll.bind(_this);
return _this; return _this;
} }
@ -588,6 +590,37 @@ var CookieConsent = function (_Component) {
if (_jsCookie2.default.get(cookieName) === undefined || debug) { if (_jsCookie2.default.get(cookieName) === undefined || debug) {
this.setState({ visible: true }); this.setState({ visible: true });
} }
// if acceptOnScroll is set to true, add a listener
if (this.props.acceptOnScroll) {
window.addEventListener("scroll", this.handleScroll, { passive: true });
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
// remove listener if still set
window.removeEventListener("scroll", this.handleScroll);
}
/**
* checks whether scroll has exceeded set amount and fire accept if so.
*/
}, {
key: "handleScroll",
value: function handleScroll() {
// (top / height) - height * 100
var rootNode = document.documentElement,
body = document.body,
top = "scrollTop",
height = "scrollHeight";
var percentage = (rootNode[top] || body[top]) / ((rootNode[height] || body[height]) - rootNode.clientHeight) * 100;
if (percentage > this.props.acceptOnScrollPercentage) {
this.accept();
}
} }
/** /**
@ -600,8 +633,14 @@ var CookieConsent = function (_Component) {
var _props2 = this.props, var _props2 = this.props,
cookieName = _props2.cookieName, cookieName = _props2.cookieName,
expires = _props2.expires, expires = _props2.expires,
hideOnAccept = _props2.hideOnAccept; hideOnAccept = _props2.hideOnAccept,
onAccept = _props2.onAccept;
// fire onAccept
onAccept();
// remove listener if set
window.removeEventListener("scroll", this.handleScroll);
_jsCookie2.default.set(cookieName, true, { expires: expires }); _jsCookie2.default.set(cookieName, true, { expires: expires });
if (hideOnAccept) { if (hideOnAccept) {
@ -624,7 +663,6 @@ var CookieConsent = function (_Component) {
buttonStyle = _props3.buttonStyle, buttonStyle = _props3.buttonStyle,
contentStyle = _props3.contentStyle, contentStyle = _props3.contentStyle,
disableStyles = _props3.disableStyles, disableStyles = _props3.disableStyles,
onAccept = _props3.onAccept,
buttonText = _props3.buttonText, buttonText = _props3.buttonText,
containerClasses = _props3.containerClasses, containerClasses = _props3.containerClasses,
contentClasses = _props3.contentClasses, contentClasses = _props3.contentClasses,
@ -675,7 +713,6 @@ var CookieConsent = function (_Component) {
className: buttonClasses, className: buttonClasses,
onClick: function onClick() { onClick: function onClick() {
_this2.accept(); _this2.accept();
onAccept();
} }
}, },
buttonText buttonText
@ -702,12 +739,16 @@ CookieConsent.propTypes = {
expires: _propTypes2.default.number, expires: _propTypes2.default.number,
containerClasses: _propTypes2.default.string, containerClasses: _propTypes2.default.string,
contentClasses: _propTypes2.default.string, contentClasses: _propTypes2.default.string,
buttonClasses: _propTypes2.default.string buttonClasses: _propTypes2.default.string,
acceptOnScroll: _propTypes2.default.bool,
acceptOnScrollPercentage: _propTypes2.default.number
}; };
CookieConsent.defaultProps = { CookieConsent.defaultProps = {
disableStyles: false, disableStyles: false,
hideOnAccept: true, hideOnAccept: true,
acceptOnScroll: false,
acceptOnScrollPercentage: 25,
location: OPTIONS.BOTTOM, location: OPTIONS.BOTTOM,
onAccept: function onAccept() {}, onAccept: function onAccept() {},
cookieName: "CookieConsent", cookieName: "CookieConsent",

View File

@ -42,6 +42,8 @@ class CookieConsent extends Component {
margin: "15px" margin: "15px"
} }
}; };
this.handleScroll = this.handleScroll.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -51,13 +53,48 @@ class CookieConsent extends Component {
if (Cookies.get(cookieName) === undefined || debug) { if (Cookies.get(cookieName) === undefined || debug) {
this.setState({ visible: true }); this.setState({ visible: true });
} }
// if acceptOnScroll is set to true, add a listener
if (this.props.acceptOnScroll) {
window.addEventListener("scroll", this.handleScroll, { passive: true });
}
}
componentWillUnmount() {
// remove listener if still set
window.removeEventListener("scroll", this.handleScroll);
}
/**
* checks whether scroll has exceeded set amount and fire accept if so.
*/
handleScroll() {
// (top / height) - height * 100
let rootNode = document.documentElement,
body = document.body,
top = "scrollTop",
height = "scrollHeight";
let percentage =
((rootNode[top] || body[top]) /
((rootNode[height] || body[height]) - rootNode.clientHeight)) *
100;
if (percentage > this.props.acceptOnScrollPercentage) {
this.accept();
}
} }
/** /**
* Set a persistent cookie * Set a persistent cookie
*/ */
accept() { accept() {
const { cookieName, expires, hideOnAccept } = this.props; const { cookieName, expires, hideOnAccept, onAccept } = this.props;
// fire onAccept
onAccept();
// remove listener if set
window.removeEventListener("scroll", this.handleScroll);
Cookies.set(cookieName, true, { expires: expires }); Cookies.set(cookieName, true, { expires: expires });
if (hideOnAccept) { if (hideOnAccept) {
@ -77,7 +114,6 @@ class CookieConsent extends Component {
buttonStyle, buttonStyle,
contentStyle, contentStyle,
disableStyles, disableStyles,
onAccept,
buttonText, buttonText,
containerClasses, containerClasses,
contentClasses, contentClasses,
@ -123,7 +159,6 @@ class CookieConsent extends Component {
className={buttonClasses} className={buttonClasses}
onClick={() => { onClick={() => {
this.accept(); this.accept();
onAccept();
}} }}
> >
{buttonText} {buttonText}
@ -142,27 +177,35 @@ CookieConsent.propTypes = {
disableStyles: PropTypes.bool, disableStyles: PropTypes.bool,
hideOnAccept: PropTypes.bool, hideOnAccept: PropTypes.bool,
onAccept: PropTypes.func, onAccept: PropTypes.func,
buttonText: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.element]), buttonText: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.element
]),
cookieName: PropTypes.string, cookieName: PropTypes.string,
debug: PropTypes.bool, debug: PropTypes.bool,
expires: PropTypes.number, expires: PropTypes.number,
containerClasses: PropTypes.string, containerClasses: PropTypes.string,
contentClasses: PropTypes.string, contentClasses: PropTypes.string,
buttonClasses: PropTypes.string buttonClasses: PropTypes.string,
acceptOnScroll: PropTypes.bool,
acceptOnScrollPercentage: PropTypes.number
}; };
CookieConsent.defaultProps = { CookieConsent.defaultProps = {
disableStyles: false, disableStyles: false,
hideOnAccept: true, hideOnAccept: true,
acceptOnScroll: false,
acceptOnScrollPercentage: 25,
location: OPTIONS.BOTTOM, location: OPTIONS.BOTTOM,
onAccept: () => {}, onAccept: () => {},
cookieName: "CookieConsent", cookieName: "CookieConsent",
buttonText: "I understand", buttonText: "I understand",
debug: false, debug: false,
expires: 365, expires: 365,
containerClasses:"", containerClasses: "",
contentClasses:"", contentClasses: "",
buttonClasses:"" buttonClasses: ""
}; };
export default CookieConsent; export default CookieConsent;