mirror of
https://github.com/Mastermindzh/react-cookie-consent.git
synced 2025-04-19 21:44:01 +02:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
a5f421b8bc | |||
7937a90662 | |||
7f5989a539 | |||
123affe057 | |||
|
c14e8274ad | ||
|
4a1ac1ed8f | ||
|
823cfb143f | ||
a9612771f2 | |||
42184054c5 | |||
6a122704ac | |||
582a18bb4d | |||
f83c3a7227 | |||
2a1973c008 | |||
38deb77dfd | |||
a2fd789751 | |||
78411dcf57 | |||
c544f19c41 | |||
c6799ea446 | |||
d7fce12ea4 | |||
|
d05509bf04 | ||
|
a7ce2de923 | ||
d8993bead2 | |||
ecb5f30a7c | |||
|
d1c7252546 | ||
602a9bfe62 | |||
c9a6e1f0ce | |||
|
fefe28e288 | ||
|
d63cb81fb7 | ||
e96b4fe4c0 |
8
.babelrc
8
.babelrc
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["@babel/preset-env"],
|
|
||||||
"plugins": [
|
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
|
||||||
"@babel/plugin-transform-react-jsx",
|
|
||||||
"@babel/plugin-transform-object-assign"
|
|
||||||
]
|
|
||||||
}
|
|
68
.eslintrc
Normal file
68
.eslintrc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"jest": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"plugins": ["import"],
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"prettier/@typescript-eslint",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
"eslint:recommended",
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2020,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"react/react-in-jsx-scope": "off",
|
||||||
|
"no-console": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"allow": ["debug", "error"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-eval": "error",
|
||||||
|
"import/first": "error",
|
||||||
|
"camelcase": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"ignoreImports": true,
|
||||||
|
"ignoreDestructuring": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consistent-return": "warn",
|
||||||
|
"constructor-super": "error",
|
||||||
|
"curly": "error",
|
||||||
|
"eol-last": "warn",
|
||||||
|
"eqeqeq": ["error", "smart"],
|
||||||
|
"import/order": 1,
|
||||||
|
"new-parens": "error",
|
||||||
|
"no-debugger": "error",
|
||||||
|
"no-fallthrough": "off",
|
||||||
|
"max-len": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"code": 120
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-shadow": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"hoist": "all"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-trailing-spaces": "warn",
|
||||||
|
"no-underscore-dangle": "error",
|
||||||
|
"no-unsafe-finally": "error",
|
||||||
|
"no-var": "error",
|
||||||
|
"object-shorthand": "error",
|
||||||
|
"one-var": ["error", "never"],
|
||||||
|
"prefer-arrow/prefer-arrow-functions": "off",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"radix": "off",
|
||||||
|
"space-in-parens": ["off", "never"]
|
||||||
|
}
|
||||||
|
}
|
17
.github/stale.yml
vendored
Normal file
17
.github/stale.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 30
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
20
.github/workflows/gh-pages.yml
vendored
Normal file
20
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Build and Deploy storybook
|
||||||
|
on: [push]
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout 🛎️
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install and Build 🔧
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run build-storybook
|
||||||
|
|
||||||
|
- name: Deploy 🚀
|
||||||
|
uses: JamesIves/github-pages-deploy-action@v4
|
||||||
|
with:
|
||||||
|
folder: storybook-static
|
32
.github/workflows/main.yml
vendored
Normal file
32
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: CI
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node: ["10.x", "12.x", "14.x"]
|
||||||
|
os: [ubuntu-latest, macOS-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Use Node ${{ matrix.node }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node }}
|
||||||
|
|
||||||
|
- name: Install deps and build (with cache)
|
||||||
|
uses: bahmutov/npm-install@v1
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: yarn lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: yarn test --ci --coverage --maxWorkers=2
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: yarn build
|
12
.github/workflows/size.yml
vendored
Normal file
12
.github/workflows/size.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
name: size
|
||||||
|
on: [pull_request]
|
||||||
|
jobs:
|
||||||
|
size:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
CI_JOB_NUMBER: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- uses: andresz1/size-limit-action@v1
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
build/index.js.LICENSE.txt
|
storybook-static
|
||||||
example/*
|
|
||||||
|
6
.husky/pre-commit
Executable file
6
.husky/pre-commit
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npm test
|
||||||
|
npm run lint
|
||||||
|
npm run build
|
10
.storybook/main.js
Normal file
10
.storybook/main.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
stories: ["../stories/**/*.stories.@(ts|tsx|js|jsx)"],
|
||||||
|
addons: [
|
||||||
|
// '@storybook/addon-links', '@storybook/addon-essentials'
|
||||||
|
],
|
||||||
|
// https://storybook.js.org/docs/react/configure/typescript#mainjs-configuration
|
||||||
|
typescript: {
|
||||||
|
check: true, // type-check stories during Storybook build
|
||||||
|
},
|
||||||
|
};
|
5
.storybook/preview.js
Normal file
5
.storybook/preview.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters
|
||||||
|
export const parameters = {
|
||||||
|
// https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args
|
||||||
|
actions: { argTypesRegex: '^on.*' },
|
||||||
|
};
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"sonarlint.connectedMode.project": {
|
||||||
|
"connectionId": "public-sonarcloud",
|
||||||
|
"projectKey": "Mastermindzh_react-cookie-consent"
|
||||||
|
}
|
||||||
|
}
|
37
CHANGELOG.md
37
CHANGELOG.md
@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [[9.0.0]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/9.0.0)]
|
||||||
|
|
||||||
|
Made all props optional and fixed documentation.
|
||||||
|
Fixes [#191](https://github.com/Mastermindzh/react-cookie-consent/issues/191) and [#193](https://github.com/Mastermindzh/react-cookie-consent/issues/193)
|
||||||
|
|
||||||
|
## [[8.0.1]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/8.0.1)]
|
||||||
|
|
||||||
|
~~Second try of [np](https://github.com/sindresorhus/np)...~~
|
||||||
|
Removed postinstall
|
||||||
|
np is not my thing.. reverted to old release strategy
|
||||||
|
|
||||||
|
## [[8.0.0]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/8.0.0)]
|
||||||
|
|
||||||
|
- Switched to tsdx and Typescript
|
||||||
|
- Added storybook with examples from readme
|
||||||
|
|
||||||
|
## [[7.6.0]](<https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.6.0>]
|
||||||
|
|
||||||
|
- Added `customButtonWrapperAttributes` prop which allows to add custom attributes to the button wrapper div
|
||||||
|
|
||||||
|
## [[7.5.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.5.0)
|
||||||
|
|
||||||
|
- Added `customDeclineButtonProps` to add custom properties to the decline button
|
||||||
|
|
||||||
|
## [[7.4.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.4.1)
|
||||||
|
|
||||||
|
- Small version error in package.json that actually didn't make it work with React 18
|
||||||
|
|
||||||
|
## [[7.4.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.4.0)
|
||||||
|
|
||||||
|
- Added support for React 18
|
||||||
|
- Updated example and codebase to use React 18
|
||||||
|
|
||||||
|
## [[7.3.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.3.1)
|
||||||
|
|
||||||
|
- Added type annotations on public functions
|
||||||
|
|
||||||
## [[7.3.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.3.0)
|
## [[7.3.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.3.0)
|
||||||
|
|
||||||
- added `customButtonProps` that allows to use custom props with the button component. Specifically useful for library buttons components, for e.g. MUI Button.
|
- added `customButtonProps` that allows to use custom props with the button component. Specifically useful for library buttons components, for e.g. MUI Button.
|
||||||
|
146
README.md
146
README.md
@ -4,9 +4,7 @@ A small, simple and customizable cookie consent bar for use in React application
|
|||||||
|
|
||||||
[](https://npmjs.org/package/react-cookie-consent)
|
[](https://npmjs.org/package/react-cookie-consent)
|
||||||
|
|
||||||
Demo: https://mastermindzh.github.io/react-cookie-consent/
|
Demo (storybook): <https://mastermindzh.github.io/react-cookie-consent/>
|
||||||
|
|
||||||
Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/example
|
|
||||||
|
|
||||||
     
|
     
|
||||||
|
|
||||||
@ -18,24 +16,28 @@ Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/exampl
|
|||||||
|
|
||||||
<!-- toc -->
|
<!-- toc -->
|
||||||
|
|
||||||
- [Installation](#installation)
|
- [:cookie: react-cookie-consent :cookie:](#cookie-react-cookie-consent-cookie)
|
||||||
- [Using it](#using-it)
|
- [Default look](#default-look)
|
||||||
- [getting the cookies value in your own code](#getting-the-cookies-value-in-your-own-code)
|
- [Table of contents](#table-of-contents)
|
||||||
- [Props](#props)
|
- [Installation](#installation)
|
||||||
- [Debugging it](#debugging-it)
|
- [Using it](#using-it)
|
||||||
- [Why are there two cookies? One of which named "Legacy"](#why-are-there-two-cookies-one-of-which-named-legacy)
|
- [getting the cookies value in your own code](#getting-the-cookies-value-in-your-own-code)
|
||||||
- [Styling it](#styling-it)
|
- [reset the cookies value in your own code](#reset-the-cookies-value-in-your-own-code)
|
||||||
- [Examples](#examples)
|
- [Props](#props)
|
||||||
- [Changing the bar background to red](#changing-the-bar-background-to-red)
|
- [Debugging it](#debugging-it)
|
||||||
- [Changing the button font-weight to bold](#changing-the-button-font-weight-to-bold)
|
- [Why are there two cookies? One of which named "Legacy"](#why-are-there-two-cookies-one-of-which-named-legacy)
|
||||||
- [Using predefined CSS classes](#using-predefined-css-classes)
|
- [Styling it](#styling-it)
|
||||||
- [Accept on scroll](#accept-on-scroll)
|
- [Examples](#examples)
|
||||||
- [Flipping the buttons](#flipping-the-buttons)
|
- [Changing the bar background to red](#changing-the-bar-background-to-red)
|
||||||
- [Extra cookie options](#extra-cookie-options)
|
- [Changing the button font-weight to bold](#changing-the-button-font-weight-to-bold)
|
||||||
- [Rainbows!](#rainbows)
|
- [Using predefined CSS classes](#using-predefined-css-classes)
|
||||||
- [Overlay](#overlay)
|
- [Accept on scroll](#accept-on-scroll)
|
||||||
- [Contributor information](#contributor-information)
|
- [Flipping the buttons](#flipping-the-buttons)
|
||||||
- [Projects using react-cookie-consent](#projects-using-react-cookie-consent)
|
- [Extra cookie options](#extra-cookie-options)
|
||||||
|
- [Rainbows](#rainbows)
|
||||||
|
- [Overlay](#overlay)
|
||||||
|
- [Contributor information](#contributor-information)
|
||||||
|
- [Projects using react-cookie-consent](#projects-using-react-cookie-consent)
|
||||||
|
|
||||||
<!-- tocstop -->
|
<!-- tocstop -->
|
||||||
|
|
||||||
@ -115,12 +117,12 @@ If the decline button is enabled then the (onDecline) prop function can be used,
|
|||||||
|
|
||||||
### getting the cookies value in your own code
|
### getting the cookies value in your own code
|
||||||
|
|
||||||
react-cookie-consent exports a function called `getCookieConsentValue`. You can use it in your own code like so:
|
react-cookie-consent exports a function called `getCookieConsentValue(cookieName: string)`. You can use it in your own code like so:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import CookieConsent, { Cookies, getCookieConsentValue } from "react-cookie-consent";
|
import CookieConsent, { Cookies, getCookieConsentValue } from "react-cookie-consent";
|
||||||
|
|
||||||
console.log(getCookieConsentValue());
|
console.log(getCookieConsentValue("your_custom_cookie_name"));
|
||||||
```
|
```
|
||||||
|
|
||||||
### reset the cookies value in your own code
|
### reset the cookies value in your own code
|
||||||
@ -137,53 +139,55 @@ That option would be interesting if you want to allow user to change their conse
|
|||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
| Prop | Type | Default value | Description |
|
| Prop | Type | Default value | Description |
|
||||||
| ------------------------- | :-----------------------------------------: | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------------------------- | :-----------------------------------------: | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| location | string, "top", "bottom" or "none" | "bottom" | Syntactic sugar to easily enable you to place the bar at the top or the bottom of the browser window. Use "none" to disable. |
|
| location | string, "top", "bottom" or "none" | "bottom" | Syntactic sugar to easily enable you to place the bar at the top or the bottom of the browser window. Use "none" to disable. |
|
||||||
| visible | string, "show", "hidden" or "byCookieValue" | "byCookieValue" | Force the consent bar visibility. If "byCookieValue", visibility are defined by cookie consent existence. |
|
| visible | string, "show", "hidden" or "byCookieValue" | "byCookieValue" | Force the consent bar visibility. If "byCookieValue", visibility are defined by cookie consent existence. |
|
||||||
| 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 |
|
| buttonText | string or React component | "I understand" | Text to appear on the button |
|
||||||
| declineButtonText | string or React component | "I decline" | Text to appear on the decline button |
|
| declineButtonText | string or React component | "I decline" | Text to appear on the decline button |
|
||||||
| cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. |
|
| cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. Note that you also have to pass this to the `getCookieConsentValue` and `resetCookieConsentValue` functions as they default to "CookieConsent" as well. |
|
||||||
| cookieValue | string or boolean or number | true | Value to be saved under the cookieName. |
|
| cookieValue | string or boolean or number | true | Value to be saved under the cookieName. |
|
||||||
| declineCookieValue | string or boolean or number | false | Value to be saved under the cookieName when declined. |
|
| declineCookieValue | string or boolean or number | false | Value to be saved under the cookieName when declined. |
|
||||||
| setDeclineCookie | boolean | true | Whether to set a cookie when the user clicks "decline" |
|
| setDeclineCookie | boolean | true | Whether to set a cookie when the user clicks "decline" |
|
||||||
| onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. |
|
| onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. |
|
||||||
| onDecline | function | `() => {}` | Function to be called after the decline button has been clicked. |
|
| onDecline | function | `() => {}` | Function to be called after the decline button has been clicked. |
|
||||||
| debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. |
|
| debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. |
|
||||||
| expires | number | 365 | Number of days before the cookie expires. |
|
| expires | number | 365 | Number of days before the cookie expires. |
|
||||||
| extraCookieOptions | object | `{}` | Extra info (apart from expiry date) to add to the cookie |
|
| extraCookieOptions | object | `{}` | Extra info (apart from expiry date) to add to the cookie |
|
||||||
| overlay | boolean | false | Whether to show a page obscuring overlay or not. |
|
| overlay | boolean | false | Whether to show a page obscuring overlay or not. |
|
||||||
| containerClasses | string | "" | CSS classes to apply to the surrounding container |
|
| containerClasses | string | "" | CSS classes to apply to the surrounding container |
|
||||||
| buttonClasses | string | "" | CSS classes to apply to the button |
|
| buttonClasses | string | "" | CSS classes to apply to the button |
|
||||||
| buttonWrapperClasses | string | "" | CSS classes to apply to the div wrapping the buttons |
|
| buttonWrapperClasses | string | "" | CSS classes to apply to the div wrapping the buttons |
|
||||||
| declineButtonClasses | string | "" | CSS classes to apply to the decline button |
|
| customButtonWrapperAttributes | `React.HTMLAttributes<HTMLDivElement>` | `{}` | Allows you to set custom (data) attributes on the button wrapper div |
|
||||||
| buttonId | string | "" | Id to apply to the button |
|
| declineButtonClasses | string | "" | CSS classes to apply to the decline button |
|
||||||
| declineButtonId | string | "" | Id to apply to the decline button |
|
| buttonId | string | "" | Id to apply to the button |
|
||||||
| contentClasses | string | "" | CSS classes to apply to the content |
|
| declineButtonId | string | "" | Id to apply to the decline button |
|
||||||
| overlayClasses | string | "" | CSS classes to apply to the surrounding overlay |
|
| contentClasses | string | "" | CSS classes to apply to the content |
|
||||||
| style | object | [look at source][style] | React styling object for the bar. |
|
| overlayClasses | string | "" | CSS classes to apply to the surrounding overlay |
|
||||||
| buttonStyle | object | [look at source][buttonstyle] | React styling object for the button. |
|
| style | object | [look at source][style] | React styling object for the bar. |
|
||||||
| declineButtonStyle | object | [look at source][declinebuttonstyle] | React styling object for the decline 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. |
|
| declineButtonStyle | object | [look at source][declinebuttonstyle] | React styling object for the decline button. |
|
||||||
| overlayStyle | object | [look at source][overlaystyle] | React styling object for the overlay. |
|
| contentStyle | object | [look at source][contentstyle] | React styling object for the content. |
|
||||||
| disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) |
|
| overlayStyle | object | [look at source][overlaystyle] | React styling object for the overlay. |
|
||||||
| enableDeclineButton | boolean | false | If enabled the decline button will be rendered |
|
| disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) |
|
||||||
| flipButtons | boolean | false | If enabled the accept and decline buttons will be flipped |
|
| enableDeclineButton | boolean | false | If enabled the decline button will be rendered |
|
||||||
| ButtonComponent | React component | button | React Component to render as a button. |
|
| flipButtons | boolean | false | If enabled the accept and decline buttons will be flipped |
|
||||||
| sameSite | string, "strict", "lax" or "none" | none | Cookies sameSite attribute value |
|
| ButtonComponent | React component | button | React Component to render as a button. |
|
||||||
| cookieSecurity | boolean ¡ | undefined | Cookie security level. Defaults to true unless running on http. |
|
| sameSite | string, "strict", "lax" or "none" | none | Cookies sameSite attribute value |
|
||||||
| ariaAcceptLabel | string | Accept cookies | Aria label to set on the accept button |
|
| cookieSecurity | boolean | undefined | Cookie security level. Defaults to true unless running on http. |
|
||||||
| ariaDeclineLabel | string | Decline cookies | Aria label to set on the decline button |
|
| ariaAcceptLabel | string | Accept cookies | Aria label to set on the accept button |
|
||||||
| acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) |
|
| ariaDeclineLabel | string | Decline cookies | Aria label to set on the decline button |
|
||||||
| acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled |
|
| acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) |
|
||||||
| customContentAttributes | object | `{}` | Allows you to set custom (data) attributes on the content div |
|
| acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled |
|
||||||
| customContainerAttributes | object | `{}` | Allows you to set custom (data) attributes on the container div |
|
| customContentAttributes | object | `{}` | Allows you to set custom (data) attributes on the content div |
|
||||||
| onOverlayClick | function | `() => {}` | allows you to react to a click on the overlay |
|
| customContainerAttributes | object | `{}` | Allows you to set custom (data) attributes on the container div |
|
||||||
| acceptOnOverlayClick | boolean | false | Determines whether the cookies should be accepted after clicking on the overlay |
|
| onOverlayClick | function | `() => {}` | allows you to react to a click on the overlay |
|
||||||
| customButtonProps | object | `{}` | Allows you to set custom props on the button component |
|
| acceptOnOverlayClick | boolean | false | Determines whether the cookies should be accepted after clicking on the overlay |
|
||||||
|
| customButtonProps | object | `{}` | Allows you to set custom props on the button component |
|
||||||
|
| customDeclineButtonProps | object | `{}` | Allows you to set custom props on the decline button component |
|
||||||
|
|
||||||
## Debugging it
|
## Debugging it
|
||||||
|
|
||||||
@ -296,7 +300,7 @@ You can add more cookie options using the extraCookieOptions parameter like so:
|
|||||||
<CookieConsent extraCookieOptions={{ domain: "myexample.com" }}>cookie bar</CookieConsent>
|
<CookieConsent extraCookieOptions={{ domain: "myexample.com" }}>cookie bar</CookieConsent>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Rainbows!
|
#### Rainbows
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
76
build/index.d.ts
vendored
76
build/index.d.ts
vendored
@ -1,76 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import Cookies from "js-cookie";
|
|
||||||
|
|
||||||
export interface CookieConsentProps {
|
|
||||||
location?: "top" | "bottom" | "none";
|
|
||||||
sameSite?: "strict" | "lax" | "none";
|
|
||||||
visible?: "hidden" | "show" | "byCookieValue";
|
|
||||||
cookieSecurity?: boolean;
|
|
||||||
style?: object;
|
|
||||||
buttonStyle?: object;
|
|
||||||
declineButtonStyle?: object;
|
|
||||||
contentStyle?: object;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
disableStyles?: boolean;
|
|
||||||
hideOnAccept?: boolean;
|
|
||||||
hideOnDecline?: boolean;
|
|
||||||
onAccept?: (acceptedByScrolling?: boolean) => void;
|
|
||||||
onDecline?: Function;
|
|
||||||
buttonText?: Function | React.ReactNode;
|
|
||||||
declineButtonText?: Function | React.ReactNode;
|
|
||||||
cookieName?: string;
|
|
||||||
cookieValue?: string | boolean | number;
|
|
||||||
declineCookieValue?: string | boolean | number;
|
|
||||||
setDeclineCookie?: boolean;
|
|
||||||
debug?: boolean;
|
|
||||||
expires?: number;
|
|
||||||
containerClasses?: string;
|
|
||||||
contentClasses?: string;
|
|
||||||
buttonWrapperClasses?: string;
|
|
||||||
buttonClasses?: string;
|
|
||||||
declineButtonClasses?: string;
|
|
||||||
buttonId?: string;
|
|
||||||
declineButtonId?: string;
|
|
||||||
extraCookieOptions?: object;
|
|
||||||
disableButtonStyles?: boolean;
|
|
||||||
enableDeclineButton?: boolean;
|
|
||||||
flipButtons?: boolean;
|
|
||||||
ButtonComponent?: React.ElementType;
|
|
||||||
overlay?: boolean;
|
|
||||||
overlayClasses?: string;
|
|
||||||
overlayStyle?: object;
|
|
||||||
onOverlayClick?: () => void;
|
|
||||||
acceptOnOverlayClick?: boolean;
|
|
||||||
ariaAcceptLabel?: string;
|
|
||||||
ariaDeclineLabel?: string;
|
|
||||||
acceptOnScroll?: boolean;
|
|
||||||
acceptOnScrollPercentage?: number;
|
|
||||||
customContentAttributes?: object;
|
|
||||||
customContainerAttributes?: object;
|
|
||||||
customButtonProps?: object;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class CookieConsent extends React.Component<CookieConsentProps, {}> {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the consent cookie
|
|
||||||
* Retrieves the regular value first and if not found the legacy one according
|
|
||||||
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export function getCookieConsentValue(name?: string): string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the consent cookie
|
|
||||||
* Remove the cookie on browser in order to allow user to change their consent
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export function resetCookieConsentValue(name?: string);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the legacy cookie name by the regular cookie name
|
|
||||||
* @param {string} name of cookie to get
|
|
||||||
*/
|
|
||||||
export function getLegacyCookieName(name: string);
|
|
||||||
|
|
||||||
export { Cookies };
|
|
File diff suppressed because one or more lines are too long
1
example
1
example
@ -1 +0,0 @@
|
|||||||
Subproject commit bff8dd76c5c13a0bf38a555b2d551e11540d30f0
|
|
44624
package-lock.json
generated
44624
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
139
package.json
139
package.json
@ -1,74 +1,103 @@
|
|||||||
{
|
{
|
||||||
"name": "react-cookie-consent",
|
"name": "react-cookie-consent",
|
||||||
"author": {
|
"version": "9.0.0",
|
||||||
"name": "Rick van Lieshout",
|
|
||||||
"email": "info@rickvanlieshout.com"
|
|
||||||
},
|
|
||||||
"version": "7.3.0",
|
|
||||||
"description": "A small, simple and customizable cookie consent bar for use in React applications.",
|
"description": "A small, simple and customizable cookie consent bar for use in React applications.",
|
||||||
"main": "build/index.js",
|
|
||||||
"types": "build/index.d.ts",
|
|
||||||
"dependencies": {
|
|
||||||
"js-cookie": "^2.2.1",
|
|
||||||
"prop-types": "^15.7.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.13.1 || ^17.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack",
|
|
||||||
"prettier": "prettier 'src/**/*.{js*,ts*,htm*,md,scss}' --write",
|
|
||||||
"patch": "npm --no-git-tag-version version patch",
|
|
||||||
"minor": "npm --no-git-tag-version version minor",
|
|
||||||
"major": "npm --no-git-tag-version version major",
|
|
||||||
"preversion": "grep \"\\[$npm_package_version\\]\" CHANGELOG.md > /dev/null || ( echo 'You need to add an entry in CHANGELOG.md for this version.' && false )",
|
|
||||||
"release": "npm run build && git add -A && git tag $npm_package_version && git commit -m \"release $npm_package_version\" && git push && git push --tags && npm publish",
|
|
||||||
"release-patch": "npm run patch && npm run release",
|
|
||||||
"release-minor": "npm run minor && npm run release",
|
|
||||||
"release-major": "npm run major && npm run release"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/Mastermindzh/react-cookie-consent.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"cookie",
|
"cookie",
|
||||||
"consent",
|
"consent",
|
||||||
"cookiebar"
|
"cookiebar"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"homepage": "https://github.com/Mastermindzh/react-cookie-consent#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/Mastermindzh/react-cookie-consent/issues"
|
"url": "https://github.com/Mastermindzh/react-cookie-consent/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/Mastermindzh/react-cookie-consent#readme",
|
"repository": {
|
||||||
"devDependencies": {
|
"type": "git",
|
||||||
"@babel/cli": "^7.12.1",
|
"url": "git+https://github.com/Mastermindzh/react-cookie-consent.git"
|
||||||
"@babel/core": "^7.12.3",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
|
||||||
"@babel/plugin-transform-object-assign": "^7.12.1",
|
|
||||||
"@babel/plugin-transform-react-jsx": "^7.12.1",
|
|
||||||
"@babel/preset-env": "^7.12.1",
|
|
||||||
"@mastermindzh/prettier-config": "^1.0.0",
|
|
||||||
"@types/js-cookie": "^2.2.6",
|
|
||||||
"babel-loader": "^8.1.0",
|
|
||||||
"copy-webpack-plugin": "^6.2.1",
|
|
||||||
"husky": "^4.3.0",
|
|
||||||
"lint-staged": "^10.5.1",
|
|
||||||
"prettier": "^2.1.2",
|
|
||||||
"react": "^16.13.1",
|
|
||||||
"webpack": "^5.3.2",
|
|
||||||
"webpack-cli": "^4.1.0"
|
|
||||||
},
|
},
|
||||||
"prettier": "@mastermindzh/prettier-config",
|
"license": "MIT",
|
||||||
"husky": {
|
"author": {
|
||||||
"hooks": {
|
"name": "Rick van Lieshout",
|
||||||
"pre-commit": "lint-staged --allow-empty"
|
"email": "info@rickvanlieshout.com"
|
||||||
}
|
},
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/react-cookie-consent.esm.js",
|
||||||
|
"typings": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"analyze": "size-limit --why",
|
||||||
|
"build": "tsdx build",
|
||||||
|
"build-storybook": "build-storybook",
|
||||||
|
"install-husky": "npx husky install",
|
||||||
|
"lint": "tsdx lint",
|
||||||
|
"major": "npm --no-git-tag-version version major",
|
||||||
|
"minor": "npm --no-git-tag-version version minor",
|
||||||
|
"organize": "npx format-package -w && npx sort-package-json",
|
||||||
|
"patch": "npm --no-git-tag-version version patch",
|
||||||
|
"prepare": "tsdx build",
|
||||||
|
"prettier": "prettier 'src/**/*.{js*,ts*,htm*,md,scss}' --write",
|
||||||
|
"publish": "npx np",
|
||||||
|
"release": "npm run build && git add -A && git tag $npm_package_version && git commit -m \"release $npm_package_version\" && git push && git push --tags && npm publish",
|
||||||
|
"release-major": "npm run major && npm run release",
|
||||||
|
"release-minor": "npm run minor && npm run release",
|
||||||
|
"release-patch": "npm run patch && npm run release",
|
||||||
|
"size": "size-limit",
|
||||||
|
"start": "tsdx watch",
|
||||||
|
"storybook": "start-storybook -p 6006",
|
||||||
|
"test": "tsdx test --passWithNoTests",
|
||||||
|
"preversion": "grep \"\\[$npm_package_version\\]\" CHANGELOG.md > /dev/null || ( echo 'You need to add an entry in CHANGELOG.md for this version.' && false )"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js*,ts*,htm*,md,scss}": [
|
"*.{js*,ts*,htm*,md,scss}": [
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"prettier": "@mastermindzh/prettier-config",
|
||||||
|
"dependencies": {
|
||||||
|
"js-cookie": "^2.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@emotion/react": "^11.9.3",
|
||||||
|
"@emotion/styled": "^11.9.3",
|
||||||
|
"@mastermindzh/prettier-config": "^1.0.0",
|
||||||
|
"@mui/material": "^5.9.2",
|
||||||
|
"@size-limit/preset-small-lib": "^7.0.8",
|
||||||
|
"@storybook/addon-essentials": "^6.5.9",
|
||||||
|
"@storybook/addons": "^6.5.9",
|
||||||
|
"@storybook/react": "^6.5.9",
|
||||||
|
"@types/js-cookie": "^2.2.6",
|
||||||
|
"@types/react": "^18.0.15",
|
||||||
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"babel-loader": "^8.2.5",
|
||||||
|
"gh-pages": "^4.0.0",
|
||||||
|
"husky": "^8.0.1",
|
||||||
|
"prettier": "^2.6.2",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-is": "^18.2.0",
|
||||||
|
"size-limit": "^7.0.8",
|
||||||
|
"tsdx": "^0.14.1",
|
||||||
|
"tslib": "^2.4.0",
|
||||||
|
"typescript": "^3.9.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"size-limit": [
|
||||||
|
{
|
||||||
|
"path": "dist/react-cookie-consent.cjs.production.min.js",
|
||||||
|
"limit": "10 KB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "dist/react-cookie-consent.esm.js",
|
||||||
|
"limit": "10 KB"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
115
src/CookieConsent.props.tsx
Normal file
115
src/CookieConsent.props.tsx
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import React, { FunctionComponent, ReactNode } from "react";
|
||||||
|
import {
|
||||||
|
defaultCookieConsentName,
|
||||||
|
POSITION_OPTIONS,
|
||||||
|
SAME_SITE_OPTIONS,
|
||||||
|
VISIBILITY_OPTIONS,
|
||||||
|
} from "./models/constants";
|
||||||
|
|
||||||
|
export interface CookieConsentProps {
|
||||||
|
children?: ReactNode;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
buttonStyle?: React.CSSProperties;
|
||||||
|
declineButtonStyle?: React.CSSProperties;
|
||||||
|
contentStyle?: React.CSSProperties;
|
||||||
|
disableStyles?: boolean;
|
||||||
|
hideOnAccept?: boolean;
|
||||||
|
hideOnDecline?: boolean;
|
||||||
|
onAccept?: (acceptedByScrolling: boolean) => void;
|
||||||
|
onDecline?: () => void;
|
||||||
|
buttonText?: string | ReactNode | Function;
|
||||||
|
declineButtonText?: string | ReactNode | Function;
|
||||||
|
cookieName?: string;
|
||||||
|
cookieValue?: string | object;
|
||||||
|
declineCookieValue?: string | object;
|
||||||
|
setDeclineCookie?: boolean;
|
||||||
|
debug?: boolean;
|
||||||
|
expires?: number;
|
||||||
|
containerClasses?: string;
|
||||||
|
contentClasses?: string;
|
||||||
|
buttonClasses?: string;
|
||||||
|
buttonWrapperClasses?: string;
|
||||||
|
declineButtonClasses?: string;
|
||||||
|
buttonId?: string;
|
||||||
|
declineButtonId?: string;
|
||||||
|
overlayClasses?: string;
|
||||||
|
ariaAcceptLabel?: string;
|
||||||
|
ariaDeclineLabel?: string;
|
||||||
|
disableButtonStyles?: boolean;
|
||||||
|
enableDeclineButton?: boolean;
|
||||||
|
flipButtons?: boolean;
|
||||||
|
cookieSecurity?: boolean;
|
||||||
|
overlay?: boolean;
|
||||||
|
acceptOnOverlayClick?: boolean;
|
||||||
|
acceptOnScroll?: boolean;
|
||||||
|
acceptOnScrollPercentage?: number;
|
||||||
|
ButtonComponent?: any;
|
||||||
|
extraCookieOptions?: Object;
|
||||||
|
overlayStyle?: Object;
|
||||||
|
customContentAttributes?: Object;
|
||||||
|
customContainerAttributes?: Object;
|
||||||
|
customButtonProps?: Object;
|
||||||
|
customDeclineButtonProps?: Object;
|
||||||
|
customButtonWrapperAttributes?: Object;
|
||||||
|
onOverlayClick?: () => void;
|
||||||
|
// these should be enums
|
||||||
|
location?: string;
|
||||||
|
visible?: string;
|
||||||
|
sameSite?: "strict" | "Strict" | "lax" | "Lax" | "none" | "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultButtonComponent: FunctionComponent<{ children: ReactNode; [x: string]: any }> = ({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return <button {...props}>{children}</button>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultCookieConsentProps = {
|
||||||
|
disableStyles: false,
|
||||||
|
hideOnAccept: true,
|
||||||
|
hideOnDecline: true,
|
||||||
|
location: POSITION_OPTIONS.BOTTOM,
|
||||||
|
visible: VISIBILITY_OPTIONS.BY_COOKIE_VALUE,
|
||||||
|
onAccept: (_acceptedByScrolling: boolean) => {},
|
||||||
|
onDecline: () => {},
|
||||||
|
cookieName: defaultCookieConsentName,
|
||||||
|
cookieValue: "true",
|
||||||
|
declineCookieValue: "false",
|
||||||
|
setDeclineCookie: true,
|
||||||
|
buttonText: "I understand",
|
||||||
|
declineButtonText: "I decline",
|
||||||
|
debug: false,
|
||||||
|
expires: 365,
|
||||||
|
containerClasses: "CookieConsent",
|
||||||
|
contentClasses: "",
|
||||||
|
buttonClasses: "",
|
||||||
|
buttonWrapperClasses: "",
|
||||||
|
declineButtonClasses: "",
|
||||||
|
buttonId: "rcc-confirm-button",
|
||||||
|
declineButtonId: "rcc-decline-button",
|
||||||
|
extraCookieOptions: {},
|
||||||
|
disableButtonStyles: false,
|
||||||
|
enableDeclineButton: false,
|
||||||
|
flipButtons: false,
|
||||||
|
sameSite: SAME_SITE_OPTIONS.LAX,
|
||||||
|
ButtonComponent: DefaultButtonComponent,
|
||||||
|
overlay: false,
|
||||||
|
overlayClasses: "",
|
||||||
|
onOverlayClick: () => {},
|
||||||
|
acceptOnOverlayClick: false,
|
||||||
|
ariaAcceptLabel: "Accept cookies",
|
||||||
|
ariaDeclineLabel: "Decline cookies",
|
||||||
|
acceptOnScroll: false,
|
||||||
|
acceptOnScrollPercentage: 25,
|
||||||
|
customContentAttributes: {},
|
||||||
|
customContainerAttributes: {},
|
||||||
|
customButtonProps: {},
|
||||||
|
customDeclineButtonProps: {},
|
||||||
|
customButtonWrapperAttributes: {},
|
||||||
|
style: {},
|
||||||
|
buttonStyle: {},
|
||||||
|
declineButtonStyle: {},
|
||||||
|
contentStyle: {},
|
||||||
|
overlayStyle: {},
|
||||||
|
};
|
59
src/CookieConsent.state.ts
Normal file
59
src/CookieConsent.state.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
export interface CookieConsentState {
|
||||||
|
visible: boolean;
|
||||||
|
style: React.CSSProperties;
|
||||||
|
buttonStyle: React.CSSProperties;
|
||||||
|
declineButtonStyle: React.CSSProperties;
|
||||||
|
contentStyle: React.CSSProperties;
|
||||||
|
overlayStyle: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultState: CookieConsentState = {
|
||||||
|
visible: false,
|
||||||
|
style: {
|
||||||
|
alignItems: "baseline",
|
||||||
|
background: "#353535",
|
||||||
|
color: "white",
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
left: "0",
|
||||||
|
position: "fixed",
|
||||||
|
width: "100%",
|
||||||
|
zIndex: "999",
|
||||||
|
},
|
||||||
|
buttonStyle: {
|
||||||
|
background: "#ffd42d",
|
||||||
|
border: "0",
|
||||||
|
borderRadius: "0px",
|
||||||
|
boxShadow: "none",
|
||||||
|
color: "black",
|
||||||
|
cursor: "pointer",
|
||||||
|
flex: "0 0 auto",
|
||||||
|
padding: "5px 10px",
|
||||||
|
margin: "15px",
|
||||||
|
},
|
||||||
|
declineButtonStyle: {
|
||||||
|
background: "#c12a2a",
|
||||||
|
border: "0",
|
||||||
|
borderRadius: "0px",
|
||||||
|
boxShadow: "none",
|
||||||
|
color: "#e5e5e5",
|
||||||
|
cursor: "pointer",
|
||||||
|
flex: "0 0 auto",
|
||||||
|
padding: "5px 10px",
|
||||||
|
margin: "15px",
|
||||||
|
},
|
||||||
|
contentStyle: {
|
||||||
|
flex: "1 0 300px",
|
||||||
|
margin: "15px",
|
||||||
|
},
|
||||||
|
overlayStyle: {
|
||||||
|
position: "fixed",
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
zIndex: "999",
|
||||||
|
backgroundColor: "rgba(0,0,0,0.3)",
|
||||||
|
},
|
||||||
|
};
|
309
src/CookieConsent.tsx
Normal file
309
src/CookieConsent.tsx
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
import Cookies from "js-cookie";
|
||||||
|
import React, { Component, CSSProperties } from "react";
|
||||||
|
import { ConditionalWrapper } from "./components/ConditionalWrapper";
|
||||||
|
import { CookieConsentProps, defaultCookieConsentProps } from "./CookieConsent.props";
|
||||||
|
import { CookieConsentState, defaultState } from "./CookieConsent.state";
|
||||||
|
import { POSITION_OPTIONS, SAME_SITE_OPTIONS, VISIBILITY_OPTIONS } from "./models/constants";
|
||||||
|
import { getCookieConsentValue, getLegacyCookieName } from "./utilities";
|
||||||
|
|
||||||
|
export class CookieConsent extends Component<CookieConsentProps, CookieConsentState> {
|
||||||
|
public static defaultProps = defaultCookieConsentProps;
|
||||||
|
|
||||||
|
state: CookieConsentState = defaultState;
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { debug } = this.props;
|
||||||
|
|
||||||
|
// if cookie undefined or debug
|
||||||
|
if (this.getCookieValue() === undefined || debug) {
|
||||||
|
this.setState({ visible: true });
|
||||||
|
// if acceptOnScroll is set to true and (cookie is undefined or debug is set to true), add a listener.
|
||||||
|
if (this.props.acceptOnScroll) {
|
||||||
|
window.addEventListener("scroll", this.handleScroll, { passive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
// remove listener if still set
|
||||||
|
this.removeScrollListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a persistent accept cookie
|
||||||
|
*/
|
||||||
|
accept(acceptedByScrolling = false) {
|
||||||
|
const { cookieName, cookieValue, hideOnAccept, onAccept } = {
|
||||||
|
...defaultCookieConsentProps,
|
||||||
|
...this.props,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setCookie(cookieName, cookieValue);
|
||||||
|
|
||||||
|
onAccept(acceptedByScrolling ?? false);
|
||||||
|
|
||||||
|
if (hideOnAccept) {
|
||||||
|
this.setState({ visible: false });
|
||||||
|
this.removeScrollListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a click on the overlay
|
||||||
|
*/
|
||||||
|
overlayClick() {
|
||||||
|
const { acceptOnOverlayClick, onOverlayClick } = {
|
||||||
|
...defaultCookieConsentProps,
|
||||||
|
...this.props,
|
||||||
|
};
|
||||||
|
if (acceptOnOverlayClick) {
|
||||||
|
this.accept();
|
||||||
|
}
|
||||||
|
onOverlayClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a persistent decline cookie
|
||||||
|
*/
|
||||||
|
decline() {
|
||||||
|
const { cookieName, declineCookieValue, hideOnDecline, onDecline, setDeclineCookie } = {
|
||||||
|
...defaultCookieConsentProps,
|
||||||
|
...this.props,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (setDeclineCookie) {
|
||||||
|
this.setCookie(cookieName, declineCookieValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDecline();
|
||||||
|
|
||||||
|
if (hideOnDecline) {
|
||||||
|
this.setState({ visible: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to set the consent cookie based on the provided variables
|
||||||
|
* Sets two cookies to handle incompatible browsers, more details:
|
||||||
|
* https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
||||||
|
*/
|
||||||
|
setCookie(cookieName: string, cookieValue: string | object) {
|
||||||
|
const { extraCookieOptions, expires, sameSite } = this.props;
|
||||||
|
let { cookieSecurity } = this.props;
|
||||||
|
|
||||||
|
if (cookieSecurity === undefined) {
|
||||||
|
cookieSecurity = window.location ? window.location.protocol === "https:" : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieOptions = { expires, ...extraCookieOptions, sameSite, secure: cookieSecurity };
|
||||||
|
|
||||||
|
// Fallback for older browsers where can not set SameSite=None,
|
||||||
|
// SEE: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
||||||
|
if (sameSite === SAME_SITE_OPTIONS.NONE) {
|
||||||
|
Cookies.set(getLegacyCookieName(cookieName), cookieValue, cookieOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the regular cookie
|
||||||
|
Cookies.set(cookieName, cookieValue, cookieOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the consent cookie
|
||||||
|
* Retrieves the regular value first and if not found the legacy one according
|
||||||
|
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
||||||
|
*/
|
||||||
|
getCookieValue() {
|
||||||
|
const { cookieName } = this.props;
|
||||||
|
return getCookieConsentValue(cookieName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks whether scroll has exceeded set amount and fire accept if so.
|
||||||
|
*/
|
||||||
|
handleScroll = () => {
|
||||||
|
const { acceptOnScrollPercentage } = { ...defaultCookieConsentProps, ...this.props };
|
||||||
|
|
||||||
|
// (top / height) - height * 100
|
||||||
|
const rootNode = document.documentElement;
|
||||||
|
const body = document.body;
|
||||||
|
const top = "scrollTop";
|
||||||
|
const height = "scrollHeight";
|
||||||
|
|
||||||
|
const percentage =
|
||||||
|
((rootNode[top] || body[top]) /
|
||||||
|
((rootNode[height] || body[height]) - rootNode.clientHeight)) *
|
||||||
|
100;
|
||||||
|
|
||||||
|
if (percentage > acceptOnScrollPercentage) {
|
||||||
|
this.accept(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
removeScrollListener = () => {
|
||||||
|
const { acceptOnScroll } = this.props;
|
||||||
|
if (acceptOnScroll) {
|
||||||
|
window.removeEventListener("scroll", this.handleScroll);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// If the bar shouldn't be visible don't render anything.
|
||||||
|
switch (this.props.visible) {
|
||||||
|
case VISIBILITY_OPTIONS.HIDDEN:
|
||||||
|
return null;
|
||||||
|
case VISIBILITY_OPTIONS.BY_COOKIE_VALUE:
|
||||||
|
if (!this.state.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
location,
|
||||||
|
style,
|
||||||
|
buttonStyle,
|
||||||
|
declineButtonStyle,
|
||||||
|
contentStyle,
|
||||||
|
disableStyles,
|
||||||
|
buttonText,
|
||||||
|
declineButtonText,
|
||||||
|
containerClasses,
|
||||||
|
contentClasses,
|
||||||
|
buttonClasses,
|
||||||
|
buttonWrapperClasses,
|
||||||
|
declineButtonClasses,
|
||||||
|
buttonId,
|
||||||
|
declineButtonId,
|
||||||
|
disableButtonStyles,
|
||||||
|
enableDeclineButton,
|
||||||
|
flipButtons,
|
||||||
|
ButtonComponent,
|
||||||
|
overlay,
|
||||||
|
overlayClasses,
|
||||||
|
overlayStyle,
|
||||||
|
ariaAcceptLabel,
|
||||||
|
ariaDeclineLabel,
|
||||||
|
customContainerAttributes,
|
||||||
|
customContentAttributes,
|
||||||
|
customButtonProps,
|
||||||
|
customDeclineButtonProps,
|
||||||
|
customButtonWrapperAttributes,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
let myStyle: CSSProperties = {};
|
||||||
|
let myButtonStyle: CSSProperties = {};
|
||||||
|
let myDeclineButtonStyle: CSSProperties = {};
|
||||||
|
let myContentStyle: CSSProperties = {};
|
||||||
|
let myOverlayStyle: CSSProperties = {};
|
||||||
|
|
||||||
|
if (disableStyles) {
|
||||||
|
// if styles are disabled use the provided styles (or none)
|
||||||
|
myStyle = Object.assign({}, style);
|
||||||
|
myButtonStyle = Object.assign({}, buttonStyle);
|
||||||
|
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
||||||
|
myContentStyle = Object.assign({}, contentStyle);
|
||||||
|
myOverlayStyle = Object.assign({}, overlayStyle);
|
||||||
|
} else {
|
||||||
|
// if styles aren't disabled merge them with the styles that are provided (or use default styles)
|
||||||
|
myStyle = Object.assign({}, { ...this.state.style, ...style });
|
||||||
|
myContentStyle = Object.assign({}, { ...this.state.contentStyle, ...contentStyle });
|
||||||
|
myOverlayStyle = Object.assign({}, { ...this.state.overlayStyle, ...overlayStyle });
|
||||||
|
|
||||||
|
// switch to disable JUST the button styles
|
||||||
|
if (disableButtonStyles) {
|
||||||
|
myButtonStyle = Object.assign({}, buttonStyle);
|
||||||
|
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
||||||
|
} else {
|
||||||
|
myButtonStyle = Object.assign({}, { ...this.state.buttonStyle, ...buttonStyle });
|
||||||
|
myDeclineButtonStyle = Object.assign(
|
||||||
|
{},
|
||||||
|
{ ...this.state.declineButtonStyle, ...declineButtonStyle }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// syntactic sugar to enable user to easily select top / bottom
|
||||||
|
switch (location) {
|
||||||
|
case POSITION_OPTIONS.TOP:
|
||||||
|
myStyle.top = "0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POSITION_OPTIONS.BOTTOM:
|
||||||
|
myStyle.bottom = "0";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonsToRender = [];
|
||||||
|
|
||||||
|
// add decline button
|
||||||
|
enableDeclineButton &&
|
||||||
|
buttonsToRender.push(
|
||||||
|
<ButtonComponent
|
||||||
|
key="declineButton"
|
||||||
|
style={myDeclineButtonStyle}
|
||||||
|
className={declineButtonClasses}
|
||||||
|
id={declineButtonId}
|
||||||
|
aria-label={ariaDeclineLabel}
|
||||||
|
onClick={() => {
|
||||||
|
this.decline();
|
||||||
|
}}
|
||||||
|
{...customDeclineButtonProps}
|
||||||
|
>
|
||||||
|
{declineButtonText}
|
||||||
|
</ButtonComponent>
|
||||||
|
);
|
||||||
|
|
||||||
|
// add accept button
|
||||||
|
buttonsToRender.push(
|
||||||
|
<ButtonComponent
|
||||||
|
key="acceptButton"
|
||||||
|
style={myButtonStyle}
|
||||||
|
className={buttonClasses}
|
||||||
|
id={buttonId}
|
||||||
|
aria-label={ariaAcceptLabel}
|
||||||
|
onClick={() => {
|
||||||
|
this.accept();
|
||||||
|
}}
|
||||||
|
{...customButtonProps}
|
||||||
|
>
|
||||||
|
{buttonText}
|
||||||
|
</ButtonComponent>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (flipButtons) {
|
||||||
|
buttonsToRender.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConditionalWrapper
|
||||||
|
condition={overlay}
|
||||||
|
wrapper={(children) => (
|
||||||
|
<div
|
||||||
|
style={myOverlayStyle}
|
||||||
|
className={overlayClasses}
|
||||||
|
onClick={() => {
|
||||||
|
this.overlayClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={`${containerClasses}`} style={myStyle} {...customContainerAttributes}>
|
||||||
|
<div style={myContentStyle} className={contentClasses} {...customContentAttributes}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
<div className={`${buttonWrapperClasses}`} {...customButtonWrapperAttributes}>
|
||||||
|
{buttonsToRender.map((button) => {
|
||||||
|
return button;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ConditionalWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CookieConsent;
|
18
src/components/ConditionalWrapper.tsx
Normal file
18
src/components/ConditionalWrapper.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { FunctionComponent, ReactNode } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
condition?: boolean;
|
||||||
|
wrapper: (_: ReactNode) => any;
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to wrap elements with a "wrapper" on a condition
|
||||||
|
* @param {object} wrappingOptions
|
||||||
|
* condition == boolean condition, when to wrap
|
||||||
|
* wrapper == style to wrap. e.g <div>{children}</div>
|
||||||
|
* children == react passes whatever is between tags as children. Don't supply this yourself.
|
||||||
|
*/
|
||||||
|
export const ConditionalWrapper: FunctionComponent<Props> = ({ condition, wrapper, children }) => {
|
||||||
|
return condition ? wrapper(children) : children;
|
||||||
|
};
|
76
src/index.d.ts
vendored
76
src/index.d.ts
vendored
@ -1,76 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import Cookies from "js-cookie";
|
|
||||||
|
|
||||||
export interface CookieConsentProps {
|
|
||||||
location?: "top" | "bottom" | "none";
|
|
||||||
sameSite?: "strict" | "lax" | "none";
|
|
||||||
visible?: "hidden" | "show" | "byCookieValue";
|
|
||||||
cookieSecurity?: boolean;
|
|
||||||
style?: object;
|
|
||||||
buttonStyle?: object;
|
|
||||||
declineButtonStyle?: object;
|
|
||||||
contentStyle?: object;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
disableStyles?: boolean;
|
|
||||||
hideOnAccept?: boolean;
|
|
||||||
hideOnDecline?: boolean;
|
|
||||||
onAccept?: (acceptedByScrolling?: boolean) => void;
|
|
||||||
onDecline?: Function;
|
|
||||||
buttonText?: Function | React.ReactNode;
|
|
||||||
declineButtonText?: Function | React.ReactNode;
|
|
||||||
cookieName?: string;
|
|
||||||
cookieValue?: string | boolean | number;
|
|
||||||
declineCookieValue?: string | boolean | number;
|
|
||||||
setDeclineCookie?: boolean;
|
|
||||||
debug?: boolean;
|
|
||||||
expires?: number;
|
|
||||||
containerClasses?: string;
|
|
||||||
contentClasses?: string;
|
|
||||||
buttonWrapperClasses?: string;
|
|
||||||
buttonClasses?: string;
|
|
||||||
declineButtonClasses?: string;
|
|
||||||
buttonId?: string;
|
|
||||||
declineButtonId?: string;
|
|
||||||
extraCookieOptions?: object;
|
|
||||||
disableButtonStyles?: boolean;
|
|
||||||
enableDeclineButton?: boolean;
|
|
||||||
flipButtons?: boolean;
|
|
||||||
ButtonComponent?: React.ElementType;
|
|
||||||
overlay?: boolean;
|
|
||||||
overlayClasses?: string;
|
|
||||||
overlayStyle?: object;
|
|
||||||
onOverlayClick?: () => void;
|
|
||||||
acceptOnOverlayClick?: boolean;
|
|
||||||
ariaAcceptLabel?: string;
|
|
||||||
ariaDeclineLabel?: string;
|
|
||||||
acceptOnScroll?: boolean;
|
|
||||||
acceptOnScrollPercentage?: number;
|
|
||||||
customContentAttributes?: object;
|
|
||||||
customContainerAttributes?: object;
|
|
||||||
customButtonProps?: object;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class CookieConsent extends React.Component<CookieConsentProps, {}> {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the consent cookie
|
|
||||||
* Retrieves the regular value first and if not found the legacy one according
|
|
||||||
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export function getCookieConsentValue(name?: string): string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the consent cookie
|
|
||||||
* Remove the cookie on browser in order to allow user to change their consent
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export function resetCookieConsentValue(name?: string): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the legacy cookie name by the regular cookie name
|
|
||||||
* @param {string} name of cookie to get
|
|
||||||
*/
|
|
||||||
export function getLegacyCookieName(name: string): string;
|
|
||||||
|
|
||||||
export { Cookies };
|
|
503
src/index.js
503
src/index.js
@ -1,503 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import Cookies from "js-cookie";
|
|
||||||
|
|
||||||
export const OPTIONS = {
|
|
||||||
TOP: "top",
|
|
||||||
BOTTOM: "bottom",
|
|
||||||
NONE: "none",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SAME_SITE_OPTIONS = {
|
|
||||||
STRICT: "strict",
|
|
||||||
LAX: "lax",
|
|
||||||
NONE: "none",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const VISIBLE_OPTIONS = {
|
|
||||||
HIDDEN: "hidden",
|
|
||||||
SHOW: "show",
|
|
||||||
BY_COOKIE_VALUE: "byCookieValue",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the consent cookie
|
|
||||||
* Retrieves the regular value first and if not found the legacy one according
|
|
||||||
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export const getCookieConsentValue = (name = defaultCookieConsentName) => {
|
|
||||||
let cookieValue = Cookies.get(name);
|
|
||||||
|
|
||||||
// if the cookieValue is undefined check for the legacy cookie
|
|
||||||
if (cookieValue === undefined) {
|
|
||||||
cookieValue = Cookies.get(getLegacyCookieName(name));
|
|
||||||
}
|
|
||||||
return cookieValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the consent cookie
|
|
||||||
* Remove the cookie on browser in order to allow user to change their consent
|
|
||||||
* @param {*} name optional name of the cookie
|
|
||||||
*/
|
|
||||||
export const resetCookieConsentValue = (name = defaultCookieConsentName) => {
|
|
||||||
Cookies.remove(name);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the legacy cookie name by the regular cookie name
|
|
||||||
* @param {string} name of cookie to get
|
|
||||||
*/
|
|
||||||
const getLegacyCookieName = (name) => {
|
|
||||||
return `${name}-legacy`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default name of the cookie which is set by CookieConsent
|
|
||||||
*/
|
|
||||||
const defaultCookieConsentName = "CookieConsent";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function to wrap elements with a "wrapper" on a condition
|
|
||||||
* @param {object} wrappingOptions
|
|
||||||
* condition == boolean condition, when to wrap
|
|
||||||
* wrapper == style to wrap. e.g <div>{children}</div>
|
|
||||||
* children == react passes whatever is between tags as children. Don't supply this yourself.
|
|
||||||
*/
|
|
||||||
const ConditionalWrapper = ({ condition, wrapper, children }) => {
|
|
||||||
return condition ? wrapper(children) : children;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CookieConsent extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
visible: false,
|
|
||||||
style: {
|
|
||||||
alignItems: "baseline",
|
|
||||||
background: "#353535",
|
|
||||||
color: "white",
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
left: "0",
|
|
||||||
position: "fixed",
|
|
||||||
width: "100%",
|
|
||||||
zIndex: "999",
|
|
||||||
},
|
|
||||||
buttonStyle: {
|
|
||||||
background: "#ffd42d",
|
|
||||||
border: "0",
|
|
||||||
borderRadius: "0px",
|
|
||||||
boxShadow: "none",
|
|
||||||
color: "black",
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: "0 0 auto",
|
|
||||||
padding: "5px 10px",
|
|
||||||
margin: "15px",
|
|
||||||
},
|
|
||||||
declineButtonStyle: {
|
|
||||||
background: "#c12a2a",
|
|
||||||
border: "0",
|
|
||||||
borderRadius: "0px",
|
|
||||||
boxShadow: "none",
|
|
||||||
color: "#e5e5e5",
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: "0 0 auto",
|
|
||||||
padding: "5px 10px",
|
|
||||||
margin: "15px",
|
|
||||||
},
|
|
||||||
contentStyle: {
|
|
||||||
flex: "1 0 300px",
|
|
||||||
margin: "15px",
|
|
||||||
},
|
|
||||||
overlayStyle: {
|
|
||||||
position: "fixed",
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
zIndex: "999",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.3)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { debug } = this.props;
|
|
||||||
|
|
||||||
// if cookie undefined or debug
|
|
||||||
if (this.getCookieValue() === undefined || debug) {
|
|
||||||
this.setState({ visible: true });
|
|
||||||
// if acceptOnScroll is set to true and (cookie is undefined or debug is set to true), add a listener.
|
|
||||||
if (this.props.acceptOnScroll) {
|
|
||||||
window.addEventListener("scroll", this.handleScroll, { passive: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
// remove listener if still set
|
|
||||||
this.removeScrollListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a persistent accept cookie
|
|
||||||
*/
|
|
||||||
accept(acceptedByScrolling = false) {
|
|
||||||
const { cookieName, cookieValue, hideOnAccept, onAccept } = this.props;
|
|
||||||
|
|
||||||
this.setCookie(cookieName, cookieValue);
|
|
||||||
|
|
||||||
onAccept(acceptedByScrolling ?? false);
|
|
||||||
|
|
||||||
if (hideOnAccept) {
|
|
||||||
this.setState({ visible: false });
|
|
||||||
this.removeScrollListener();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a click on the overlay
|
|
||||||
*/
|
|
||||||
overlayClick() {
|
|
||||||
const { acceptOnOverlayClick, onOverlayClick } = this.props;
|
|
||||||
if (acceptOnOverlayClick) {
|
|
||||||
this.accept();
|
|
||||||
}
|
|
||||||
onOverlayClick();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a persistent decline cookie
|
|
||||||
*/
|
|
||||||
decline() {
|
|
||||||
const { cookieName, declineCookieValue, hideOnDecline, onDecline, setDeclineCookie } =
|
|
||||||
this.props;
|
|
||||||
|
|
||||||
if (setDeclineCookie) {
|
|
||||||
this.setCookie(cookieName, declineCookieValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDecline();
|
|
||||||
|
|
||||||
if (hideOnDecline) {
|
|
||||||
this.setState({ visible: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to set the consent cookie based on the provided variables
|
|
||||||
* Sets two cookies to handle incompatible browsers, more details:
|
|
||||||
* https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
*/
|
|
||||||
setCookie(cookieName, cookieValue) {
|
|
||||||
const { extraCookieOptions, expires, sameSite } = this.props;
|
|
||||||
let { cookieSecurity } = this.props;
|
|
||||||
|
|
||||||
if (cookieSecurity === undefined) {
|
|
||||||
cookieSecurity = location ? location.protocol === "https:" : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cookieOptions = { expires, ...extraCookieOptions, sameSite, secure: cookieSecurity };
|
|
||||||
|
|
||||||
// Fallback for older browsers where can not set SameSite=None, SEE: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
if (sameSite === SAME_SITE_OPTIONS.NONE) {
|
|
||||||
Cookies.set(getLegacyCookieName(cookieName), cookieValue, cookieOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the regular cookie
|
|
||||||
Cookies.set(cookieName, cookieValue, cookieOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the consent cookie
|
|
||||||
* Retrieves the regular value first and if not found the legacy one according
|
|
||||||
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
|
||||||
*/
|
|
||||||
getCookieValue() {
|
|
||||||
const { cookieName } = this.props;
|
|
||||||
return getCookieConsentValue(cookieName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks whether scroll has exceeded set amount and fire accept if so.
|
|
||||||
*/
|
|
||||||
handleScroll = () => {
|
|
||||||
const { acceptOnScrollPercentage } = this.props;
|
|
||||||
|
|
||||||
// (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 > acceptOnScrollPercentage) {
|
|
||||||
this.accept(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeScrollListener = () => {
|
|
||||||
const { acceptOnScroll } = this.props;
|
|
||||||
if (acceptOnScroll) {
|
|
||||||
window.removeEventListener("scroll", this.handleScroll);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// If the bar shouldn't be visible don't render anything.
|
|
||||||
switch (this.props.visible) {
|
|
||||||
case VISIBLE_OPTIONS.HIDDEN:
|
|
||||||
return null;
|
|
||||||
case VISIBLE_OPTIONS.BY_COOKIE_VALUE:
|
|
||||||
if (!this.state.visible) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
location,
|
|
||||||
style,
|
|
||||||
buttonStyle,
|
|
||||||
declineButtonStyle,
|
|
||||||
contentStyle,
|
|
||||||
disableStyles,
|
|
||||||
buttonText,
|
|
||||||
declineButtonText,
|
|
||||||
containerClasses,
|
|
||||||
contentClasses,
|
|
||||||
buttonClasses,
|
|
||||||
buttonWrapperClasses,
|
|
||||||
declineButtonClasses,
|
|
||||||
buttonId,
|
|
||||||
declineButtonId,
|
|
||||||
disableButtonStyles,
|
|
||||||
enableDeclineButton,
|
|
||||||
flipButtons,
|
|
||||||
ButtonComponent,
|
|
||||||
overlay,
|
|
||||||
overlayClasses,
|
|
||||||
overlayStyle,
|
|
||||||
ariaAcceptLabel,
|
|
||||||
ariaDeclineLabel,
|
|
||||||
customContainerAttributes,
|
|
||||||
customContentAttributes,
|
|
||||||
customButtonProps,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
let myStyle = {};
|
|
||||||
let myButtonStyle = {};
|
|
||||||
let myDeclineButtonStyle = {};
|
|
||||||
let myContentStyle = {};
|
|
||||||
let myOverlayStyle = {};
|
|
||||||
|
|
||||||
if (disableStyles) {
|
|
||||||
// if styles are disabled use the provided styles (or none)
|
|
||||||
myStyle = Object.assign({}, style);
|
|
||||||
myButtonStyle = Object.assign({}, buttonStyle);
|
|
||||||
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
|
||||||
myContentStyle = Object.assign({}, contentStyle);
|
|
||||||
myOverlayStyle = Object.assign({}, overlayStyle);
|
|
||||||
} else {
|
|
||||||
// if styles aren't disabled merge them with the styles that are provided (or use default styles)
|
|
||||||
myStyle = Object.assign({}, { ...this.state.style, ...style });
|
|
||||||
myContentStyle = Object.assign({}, { ...this.state.contentStyle, ...contentStyle });
|
|
||||||
myOverlayStyle = Object.assign({}, { ...this.state.overlayStyle, ...overlayStyle });
|
|
||||||
|
|
||||||
// switch to disable JUST the button styles
|
|
||||||
if (disableButtonStyles) {
|
|
||||||
myButtonStyle = Object.assign({}, buttonStyle);
|
|
||||||
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
|
||||||
} else {
|
|
||||||
myButtonStyle = Object.assign({}, { ...this.state.buttonStyle, ...buttonStyle });
|
|
||||||
myDeclineButtonStyle = Object.assign(
|
|
||||||
{},
|
|
||||||
{ ...this.state.declineButtonStyle, ...declineButtonStyle }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// syntactic sugar to enable user to easily select top / bottom
|
|
||||||
switch (location) {
|
|
||||||
case OPTIONS.TOP:
|
|
||||||
myStyle.top = "0";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTIONS.BOTTOM:
|
|
||||||
myStyle.bottom = "0";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonsToRender = [];
|
|
||||||
|
|
||||||
// add decline button
|
|
||||||
enableDeclineButton &&
|
|
||||||
buttonsToRender.push(
|
|
||||||
<ButtonComponent
|
|
||||||
key="declineButton"
|
|
||||||
style={myDeclineButtonStyle}
|
|
||||||
className={declineButtonClasses}
|
|
||||||
id={declineButtonId}
|
|
||||||
aria-label={ariaDeclineLabel}
|
|
||||||
onClick={() => {
|
|
||||||
this.decline();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{declineButtonText}
|
|
||||||
</ButtonComponent>
|
|
||||||
);
|
|
||||||
|
|
||||||
// add accept button
|
|
||||||
buttonsToRender.push(
|
|
||||||
<ButtonComponent
|
|
||||||
{...customButtonProps}
|
|
||||||
key="acceptButton"
|
|
||||||
style={myButtonStyle}
|
|
||||||
className={buttonClasses}
|
|
||||||
id={buttonId}
|
|
||||||
aria-label={ariaAcceptLabel}
|
|
||||||
onClick={() => {
|
|
||||||
this.accept();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{buttonText}
|
|
||||||
</ButtonComponent>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (flipButtons) {
|
|
||||||
buttonsToRender.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConditionalWrapper
|
|
||||||
condition={overlay}
|
|
||||||
wrapper={(children) => (
|
|
||||||
<div
|
|
||||||
style={myOverlayStyle}
|
|
||||||
className={overlayClasses}
|
|
||||||
onClick={() => {
|
|
||||||
this.overlayClick();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className={`${containerClasses}`} style={myStyle} {...customContainerAttributes}>
|
|
||||||
<div style={myContentStyle} className={contentClasses} {...customContentAttributes}>
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
<div className={`${buttonWrapperClasses}`}>
|
|
||||||
{buttonsToRender.map((button) => {
|
|
||||||
return button;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ConditionalWrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CookieConsent.propTypes = {
|
|
||||||
location: PropTypes.oneOf(Object.keys(OPTIONS).map((key) => OPTIONS[key])),
|
|
||||||
visible: PropTypes.oneOf(Object.keys(VISIBLE_OPTIONS).map((key) => VISIBLE_OPTIONS[key])),
|
|
||||||
sameSite: PropTypes.oneOf(Object.keys(SAME_SITE_OPTIONS).map((key) => SAME_SITE_OPTIONS[key])),
|
|
||||||
style: PropTypes.object,
|
|
||||||
buttonStyle: PropTypes.object,
|
|
||||||
declineButtonStyle: PropTypes.object,
|
|
||||||
contentStyle: PropTypes.object,
|
|
||||||
children: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
|
||||||
disableStyles: PropTypes.bool,
|
|
||||||
hideOnAccept: PropTypes.bool,
|
|
||||||
hideOnDecline: PropTypes.bool,
|
|
||||||
onAccept: PropTypes.func,
|
|
||||||
onDecline: PropTypes.func,
|
|
||||||
buttonText: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.element]),
|
|
||||||
declineButtonText: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.element]),
|
|
||||||
cookieName: PropTypes.string,
|
|
||||||
cookieValue: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.number]),
|
|
||||||
declineCookieValue: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.number]),
|
|
||||||
setDeclineCookie: PropTypes.bool,
|
|
||||||
debug: PropTypes.bool,
|
|
||||||
expires: PropTypes.number,
|
|
||||||
containerClasses: PropTypes.string,
|
|
||||||
contentClasses: PropTypes.string,
|
|
||||||
buttonClasses: PropTypes.string,
|
|
||||||
buttonWrapperClasses: PropTypes.string,
|
|
||||||
declineButtonClasses: PropTypes.string,
|
|
||||||
buttonId: PropTypes.string,
|
|
||||||
declineButtonId: PropTypes.string,
|
|
||||||
extraCookieOptions: PropTypes.object,
|
|
||||||
disableButtonStyles: PropTypes.bool,
|
|
||||||
enableDeclineButton: PropTypes.bool,
|
|
||||||
flipButtons: PropTypes.bool,
|
|
||||||
ButtonComponent: PropTypes.elementType,
|
|
||||||
cookieSecurity: PropTypes.bool,
|
|
||||||
overlay: PropTypes.bool,
|
|
||||||
overlayClasses: PropTypes.string,
|
|
||||||
overlayStyle: PropTypes.object,
|
|
||||||
onOverlayClick: PropTypes.func,
|
|
||||||
acceptOnOverlayClick: PropTypes.bool,
|
|
||||||
ariaAcceptLabel: PropTypes.string,
|
|
||||||
ariaDeclineLabel: PropTypes.string,
|
|
||||||
acceptOnScroll: PropTypes.bool,
|
|
||||||
acceptOnScrollPercentage: PropTypes.number,
|
|
||||||
customContentAttributes: PropTypes.object,
|
|
||||||
customContainerAttributes: PropTypes.object,
|
|
||||||
customButtonProps: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
CookieConsent.defaultProps = {
|
|
||||||
disableStyles: false,
|
|
||||||
hideOnAccept: true,
|
|
||||||
hideOnDecline: true,
|
|
||||||
location: OPTIONS.BOTTOM,
|
|
||||||
visible: VISIBLE_OPTIONS.BY_COOKIE_VALUE,
|
|
||||||
onAccept: () => {},
|
|
||||||
onDecline: () => {},
|
|
||||||
cookieName: defaultCookieConsentName,
|
|
||||||
cookieValue: true,
|
|
||||||
declineCookieValue: false,
|
|
||||||
setDeclineCookie: true,
|
|
||||||
buttonText: "I understand",
|
|
||||||
declineButtonText: "I decline",
|
|
||||||
debug: false,
|
|
||||||
expires: 365,
|
|
||||||
containerClasses: "CookieConsent",
|
|
||||||
contentClasses: "",
|
|
||||||
buttonClasses: "",
|
|
||||||
buttonWrapperClasses: "",
|
|
||||||
declineButtonClasses: "",
|
|
||||||
buttonId: "rcc-confirm-button",
|
|
||||||
declineButtonId: "rcc-decline-button",
|
|
||||||
extraCookieOptions: {},
|
|
||||||
disableButtonStyles: false,
|
|
||||||
enableDeclineButton: false,
|
|
||||||
flipButtons: false,
|
|
||||||
sameSite: SAME_SITE_OPTIONS.LAX,
|
|
||||||
ButtonComponent: ({ children, ...props }) => <button {...props}>{children}</button>,
|
|
||||||
overlay: false,
|
|
||||||
overlayClasses: "",
|
|
||||||
onOverlayClick: () => {},
|
|
||||||
acceptOnOverlayClick: false,
|
|
||||||
ariaAcceptLabel: "Accept cookies",
|
|
||||||
ariaDeclineLabel: "Decline cookies",
|
|
||||||
acceptOnScroll: false,
|
|
||||||
acceptOnScrollPercentage: 25,
|
|
||||||
customContentAttributes: {},
|
|
||||||
customContainerAttributes: {},
|
|
||||||
customButtonProps: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CookieConsent;
|
|
||||||
export { Cookies };
|
|
11
src/index.tsx
Normal file
11
src/index.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { ConditionalWrapper } from "./components/ConditionalWrapper";
|
||||||
|
import { CookieConsent } from "./CookieConsent";
|
||||||
|
import { POSITION_OPTIONS, VISIBILITY_OPTIONS } from "./models/constants";
|
||||||
|
|
||||||
|
export * from "./models/constants";
|
||||||
|
export * from "./utilities";
|
||||||
|
export { Cookies, CookieConsent, ConditionalWrapper };
|
||||||
|
// backwards compatibility exports
|
||||||
|
export { POSITION_OPTIONS as OPTIONS, VISIBILITY_OPTIONS as VISIBLE_OPTIONS };
|
||||||
|
export default CookieConsent;
|
1
src/models/constants/defaultCookieName.ts
Normal file
1
src/models/constants/defaultCookieName.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const defaultCookieConsentName = "CookieConsent";
|
4
src/models/constants/index.ts
Normal file
4
src/models/constants/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from "./positionOptions";
|
||||||
|
export * from "./sameSiteOptions";
|
||||||
|
export * from "./visibilityOptions";
|
||||||
|
export * from "./defaultCookieName";
|
5
src/models/constants/positionOptions.ts
Normal file
5
src/models/constants/positionOptions.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const POSITION_OPTIONS = {
|
||||||
|
TOP: "top",
|
||||||
|
BOTTOM: "bottom",
|
||||||
|
NONE: "none",
|
||||||
|
};
|
5
src/models/constants/sameSiteOptions.ts
Normal file
5
src/models/constants/sameSiteOptions.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum SAME_SITE_OPTIONS {
|
||||||
|
STRICT = "strict",
|
||||||
|
LAX = "lax",
|
||||||
|
NONE = "none",
|
||||||
|
}
|
5
src/models/constants/visibilityOptions.ts
Normal file
5
src/models/constants/visibilityOptions.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const VISIBILITY_OPTIONS = {
|
||||||
|
HIDDEN: "hidden",
|
||||||
|
SHOW: "show",
|
||||||
|
BY_COOKIE_VALUE: "byCookieValue",
|
||||||
|
};
|
35
src/utilities.ts
Normal file
35
src/utilities.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { defaultCookieConsentName } from "./models/constants";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the consent cookie
|
||||||
|
* Retrieves the regular value first and if not found the legacy one according
|
||||||
|
* to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
||||||
|
* @param {*} name optional name of the cookie
|
||||||
|
*/
|
||||||
|
export const getCookieConsentValue = (name = defaultCookieConsentName) => {
|
||||||
|
const cookieValue = Cookies.get(name);
|
||||||
|
|
||||||
|
// if the cookieValue is undefined check for the legacy cookie
|
||||||
|
if (cookieValue === undefined) {
|
||||||
|
return Cookies.get(getLegacyCookieName(name));
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the consent cookie
|
||||||
|
* Remove the cookie on browser in order to allow user to change their consent
|
||||||
|
* @param {*} name optional name of the cookie
|
||||||
|
*/
|
||||||
|
export const resetCookieConsentValue = (name = defaultCookieConsentName) => {
|
||||||
|
Cookies.remove(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the legacy cookie name by the regular cookie name
|
||||||
|
* @param {string} name of cookie to get
|
||||||
|
*/
|
||||||
|
export const getLegacyCookieName = (name: string) => {
|
||||||
|
return `${name}-legacy`;
|
||||||
|
};
|
11
stories/defaults/intro.tsx
Normal file
11
stories/defaults/intro.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
export const Intro: FunctionComponent<Props> = () => {
|
||||||
|
return (
|
||||||
|
<h1>
|
||||||
|
<p>Debug is turned on for all stories so that the bar always shows up</p>
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
};
|
3
stories/defaults/storyProps.ts
Normal file
3
stories/defaults/storyProps.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { CookieConsentProps, defaultCookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
|
||||||
|
export const defaultStoryProps: CookieConsentProps = { ...defaultCookieConsentProps, debug: true };
|
13
stories/defaults/template.tsx
Normal file
13
stories/defaults/template.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Story } from "@storybook/react";
|
||||||
|
import CookieConsent from "../../src";
|
||||||
|
import { Intro } from "./intro";
|
||||||
|
|
||||||
|
export const DefaultTemplate: Story<any> = (args) => (
|
||||||
|
<>
|
||||||
|
<Intro />
|
||||||
|
<CookieConsent {...args}>
|
||||||
|
This website uses cookies to enhance the user experience.
|
||||||
|
<span style={{ fontSize: "10px" }}>This bit of text is smaller :O</span>
|
||||||
|
</CookieConsent>
|
||||||
|
</>
|
||||||
|
);
|
34
stories/index.stories.tsx
Normal file
34
stories/index.stories.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Meta } from "@storybook/react";
|
||||||
|
import { CookieConsent } from "../src";
|
||||||
|
import { defaultStoryProps } from "./defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "./defaults/template";
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: "CookieConsent",
|
||||||
|
component: CookieConsent,
|
||||||
|
argTypes: {
|
||||||
|
children: {
|
||||||
|
control: {
|
||||||
|
type: "text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
controls: { expanded: true },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export const Default = DefaultTemplate.bind({});
|
||||||
|
Default.args = defaultStoryProps;
|
||||||
|
|
||||||
|
// stories
|
||||||
|
export * from "./stories/acceptOnScroll.story";
|
||||||
|
export * from "./stories/additionalButtons.story";
|
||||||
|
export * from "./stories/customStyling.story";
|
||||||
|
export * from "./stories/flippedButtons.story";
|
||||||
|
export * from "./stories/muiButtons.story";
|
||||||
|
export * from "./stories/onAccept.story";
|
||||||
|
export * from "./stories/overlay.story";
|
||||||
|
export * from "./stories/rainbows.story";
|
34
stories/stories/acceptOnScroll.story.tsx
Normal file
34
stories/stories/acceptOnScroll.story.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Story } from "@storybook/react";
|
||||||
|
import CookieConsent from "../../src";
|
||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { Intro } from "../defaults/intro";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
|
||||||
|
const AcceptOnScrollTemplate: Story<any> = (args) => (
|
||||||
|
<>
|
||||||
|
<Intro />
|
||||||
|
{Array.from(Array(25).keys()).map((_something) => (
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Voluptates ipsa sequi soluta
|
||||||
|
mollitia illum, hic quaerat ipsum sint odit delectus magni neque sunt adipisci culpa harum
|
||||||
|
aut distinctio quisquam ab!
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<CookieConsent {...args}>
|
||||||
|
Scroll for {args.acceptOnScrollPercentage}% and the onAccept will trigger
|
||||||
|
</CookieConsent>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const AcceptOnScroll = AcceptOnScrollTemplate.bind({});
|
||||||
|
AcceptOnScroll.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
onAccept: (acceptedByScrolling) => {
|
||||||
|
alert(`ACCEPTED! By scrolling? ${JSON.stringify(acceptedByScrolling)}`);
|
||||||
|
},
|
||||||
|
acceptOnScroll: true,
|
||||||
|
acceptOnScrollPercentage: 25,
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { AcceptOnScroll };
|
17
stories/stories/additionalButtons.story.tsx
Normal file
17
stories/stories/additionalButtons.story.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Story } from "@storybook/react";
|
||||||
|
import CookieConsent from "../../src";
|
||||||
|
import { Intro } from "../defaults/intro";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
|
||||||
|
const AdditionalButtonsTemplate: Story<any> = (args) => (
|
||||||
|
<>
|
||||||
|
<Intro />
|
||||||
|
<CookieConsent {...args}>
|
||||||
|
<button style={{ color: "gray" }}>I am a custom config button</button>
|
||||||
|
<span style={{ fontSize: "10px" }}>This bit of text is smaller :O</span>
|
||||||
|
</CookieConsent>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
const AdditionalButtons = AdditionalButtonsTemplate.bind({});
|
||||||
|
AdditionalButtons.args = defaultStoryProps;
|
||||||
|
export { AdditionalButtons };
|
12
stories/stories/customStyling.story.tsx
Normal file
12
stories/stories/customStyling.story.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const CustomStyling = DefaultTemplate.bind({});
|
||||||
|
CustomStyling.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
style: { background: "red" },
|
||||||
|
buttonStyle: { fontWeight: "bold" },
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { CustomStyling };
|
12
stories/stories/flippedButtons.story.tsx
Normal file
12
stories/stories/flippedButtons.story.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const FlippedButtons = DefaultTemplate.bind({});
|
||||||
|
FlippedButtons.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
flipButtons: true,
|
||||||
|
enableDeclineButton: true,
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { FlippedButtons };
|
14
stories/stories/muiButtons.story.ts
Normal file
14
stories/stories/muiButtons.story.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Button } from "@mui/material";
|
||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const CustomMuiButton = DefaultTemplate.bind({});
|
||||||
|
CustomMuiButton.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
disableButtonStyles: true,
|
||||||
|
ButtonComponent: Button,
|
||||||
|
customButtonProps: { variant: "contained", style: { marginRight: "10px" } },
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { CustomMuiButton };
|
13
stories/stories/onAccept.story.tsx
Normal file
13
stories/stories/onAccept.story.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const CustomOnAccept = DefaultTemplate.bind({});
|
||||||
|
CustomOnAccept.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
onAccept: (acceptedByScrolling) => {
|
||||||
|
alert(`ACCEPTED! By scrolling? ${JSON.stringify(acceptedByScrolling)}`);
|
||||||
|
},
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { CustomOnAccept };
|
11
stories/stories/overlay.story.tsx
Normal file
11
stories/stories/overlay.story.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const Overlay = DefaultTemplate.bind({});
|
||||||
|
Overlay.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
overlay: true,
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { Overlay };
|
22
stories/stories/rainbows.story.tsx
Normal file
22
stories/stories/rainbows.story.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { CookieConsentProps } from "../../src/CookieConsent.props";
|
||||||
|
import { defaultStoryProps } from "../defaults/storyProps";
|
||||||
|
import { DefaultTemplate } from "../defaults/template";
|
||||||
|
|
||||||
|
const Rainbows = DefaultTemplate.bind({});
|
||||||
|
Rainbows.args = {
|
||||||
|
...defaultStoryProps,
|
||||||
|
buttonText: "OMG DOUBLE RAINBOW",
|
||||||
|
|
||||||
|
style: {
|
||||||
|
background: "linear-gradient(to right, orange , yellow, green, cyan, blue, violet)",
|
||||||
|
textShadow: "2px 2px black",
|
||||||
|
},
|
||||||
|
buttonStyle: {
|
||||||
|
background: "linear-gradient(to left, orange , yellow, green, cyan, blue, violet)",
|
||||||
|
color: "white",
|
||||||
|
fontWeight: "bolder",
|
||||||
|
textShadow: "2px 2px black",
|
||||||
|
},
|
||||||
|
} as CookieConsentProps;
|
||||||
|
|
||||||
|
export { Rainbows };
|
35
tsconfig.json
Normal file
35
tsconfig.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
// see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
|
||||||
|
"include": ["src", "types"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"lib": ["dom", "esnext"],
|
||||||
|
"importHelpers": true,
|
||||||
|
// output .d.ts declaration files for consumers
|
||||||
|
"declaration": true,
|
||||||
|
// output .js.map sourcemap files for consumers
|
||||||
|
"sourceMap": true,
|
||||||
|
// match output dir to input dir. e.g. dist/index instead of dist/src/index
|
||||||
|
"rootDir": "./src",
|
||||||
|
// stricter type-checking for stronger correctness. Recommended by TS
|
||||||
|
"strict": true,
|
||||||
|
// linter checks for common issues
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
// noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
// use Node's module resolution algorithm, instead of the legacy TS one
|
||||||
|
"moduleResolution": "node",
|
||||||
|
// transpile JSX to React.createElement
|
||||||
|
"jsx": "react",
|
||||||
|
// interop between ESM and CJS modules. Recommended by TS
|
||||||
|
"esModuleInterop": true,
|
||||||
|
// significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
|
||||||
|
"skipLibCheck": true,
|
||||||
|
// error out if import and file system have a casing mismatch. Recommended by TS
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
// `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
|
||||||
|
"noEmit": true,
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
var path = require("path");
|
|
||||||
var CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: "./src/index.js",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "build"),
|
|
||||||
filename: "index.js",
|
|
||||||
library: {
|
|
||||||
name: "ReactCookieConsent",
|
|
||||||
type: "umd",
|
|
||||||
},
|
|
||||||
environment: {
|
|
||||||
arrowFunction: false, // the generated runtime-code should not use arrow functions
|
|
||||||
},
|
|
||||||
globalObject: `typeof self !== 'undefined' ? self : this`,
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
include: path.resolve(__dirname, "src"),
|
|
||||||
exclude: /(node_modules|build)/,
|
|
||||||
use: {
|
|
||||||
loader: "babel-loader",
|
|
||||||
options: {
|
|
||||||
presets: ["@babel/preset-env"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
react: "commonjs react", // this line is just to use the React dependency of our parent-testing-project instead of using our own React.
|
|
||||||
},
|
|
||||||
plugins: [new CopyWebpackPlugin({ patterns: [{ from: "src/index.d.ts", to: "index.d.ts" }] })],
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user