Compare commits

...

29 Commits

Author SHA1 Message Date
a5f421b8bc release 9.0.0 2023-10-16 23:43:20 +02:00
7937a90662 made all props optional and updated docs fixes #191 and #193 2023-10-16 23:43:00 +02:00
7f5989a539 fix(ci): removed addons so it builds again 2023-05-25 13:30:12 +02:00
123affe057 docs: updated docs about cookiename - fixes #186 2023-05-25 13:10:23 +02:00
dependabot[bot]
c14e8274ad
Bump json5 from 1.0.1 to 1.0.2 (#180)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 21:25:58 +01:00
dependabot[bot]
4a1ac1ed8f
Bump decode-uri-component from 0.2.0 to 0.2.2 (#178)
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-08 10:46:10 +01:00
dependabot[bot]
823cfb143f
Bump loader-utils from 1.4.0 to 1.4.1 (#175)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 09:38:24 +01:00
a9612771f2 added stale config 2022-07-31 12:43:58 +02:00
42184054c5 storybook readme changes 2022-07-31 12:39:17 +02:00
6a122704ac auto-deploy to github pages 2022-07-31 12:36:03 +02:00
582a18bb4d release 8.0.1 2022-07-31 12:22:47 +02:00
f83c3a7227 bye bye np 2022-07-31 12:22:29 +02:00
2a1973c008 8.0.1 2022-07-31 12:17:32 +02:00
38deb77dfd second try of np.... 2022-07-31 12:16:51 +02:00
a2fd789751 disabled windows builds (I don't want to mess with settings for crlf... windows should learn to behave lol)
added npx to install-husky
removed postinstall
2022-07-31 12:14:11 +02:00
78411dcf57 8.0.0 2022-07-31 12:06:33 +02:00
c544f19c41 Switched to tsdx and Typescript
Added storybook with examples from readme
2022-07-31 12:04:58 +02:00
c6799ea446 release 7.6.0 2022-07-26 14:46:46 +02:00
d7fce12ea4 changelog version update 2022-07-26 14:46:34 +02:00
Oskar Filipowicz
d05509bf04
added customButtonWrapperAttributes prop (#167)
* added customButtonWrapperAttributes prop

* escape characters in README
2022-07-26 14:43:44 +02:00
dependabot[bot]
a7ce2de923
Bump terser from 5.7.1 to 5.14.2 (#163)
Bumps [terser](https://github.com/terser/terser) from 5.7.1 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-20 09:09:28 +02:00
d8993bead2 release 7.5.0 2022-06-18 14:30:02 +02:00
ecb5f30a7c Added to add custom properties to the decline button 2022-06-18 14:29:39 +02:00
dependabot[bot]
d1c7252546
Bump semver-regex from 3.1.3 to 3.1.4 (#158)
Bumps [semver-regex](https://github.com/sindresorhus/semver-regex) from 3.1.3 to 3.1.4.
- [Release notes](https://github.com/sindresorhus/semver-regex/releases)
- [Commits](https://github.com/sindresorhus/semver-regex/commits/v3.1.4)

---
updated-dependencies:
- dependency-name: semver-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-06 09:25:54 +02:00
602a9bfe62 release 7.4.1 2022-04-03 10:30:45 +02:00
c9a6e1f0ce release 7.4.0 2022-04-03 10:25:55 +02:00
dependabot[bot]
fefe28e288
Bump minimist from 1.2.5 to 1.2.6 (#155)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-28 11:17:52 +02:00
Abe Tomoaki
d63cb81fb7
refactor: use const instead of let. (#153) 2022-02-11 09:24:48 +01:00
e96b4fe4c0 release 7.3.1 2022-02-10 14:25:18 +01:00
45 changed files with 39727 additions and 6903 deletions

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View File

@ -1,3 +1,6 @@
*.log
.DS_Store
.cache
dist
node_modules
build/index.js.LICENSE.txt
example/*
storybook-static

6
.husky/pre-commit Executable file
View 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
View 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
View 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
View File

@ -0,0 +1,6 @@
{
"sonarlint.connectedMode.project": {
"connectionId": "public-sonarcloud",
"projectKey": "Mastermindzh_react-cookie-consent"
}
}

View File

@ -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/),
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)
- 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
View File

@ -4,9 +4,7 @@ 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)
Demo: https://mastermindzh.github.io/react-cookie-consent/
Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/example
Demo (storybook): <https://mastermindzh.github.io/react-cookie-consent/>
![Downloads](https://img.shields.io/npm/dm/react-cookie-consent) ![Dependent repos (via libraries.io)](https://img.shields.io/librariesio/dependent-repos/npm/react-cookie-consent) ![GitHub contributors](https://img.shields.io/github/contributors/mastermindzh/react-cookie-consent) ![Minified size](https://img.shields.io/bundlephobia/min/react-cookie-consent) ![npm type definitions](https://img.shields.io/npm/types/react-cookie-consent) ![license-mit](https://img.shields.io/badge/license-MIT-green)
@ -18,24 +16,28 @@ Example branch: https://github.com/Mastermindzh/react-cookie-consent/tree/exampl
<!-- toc -->
- [Installation](#installation)
- [Using it](#using-it)
- [getting the cookies value in your own code](#getting-the-cookies-value-in-your-own-code)
- [Props](#props)
- [Debugging it](#debugging-it)
- [Why are there two cookies? One of which named "Legacy"](#why-are-there-two-cookies-one-of-which-named-legacy)
- [Styling it](#styling-it)
- [Examples](#examples)
- [Changing the bar background to red](#changing-the-bar-background-to-red)
- [Changing the button font-weight to bold](#changing-the-button-font-weight-to-bold)
- [Using predefined CSS classes](#using-predefined-css-classes)
- [Accept on scroll](#accept-on-scroll)
- [Flipping the buttons](#flipping-the-buttons)
- [Extra cookie options](#extra-cookie-options)
- [Rainbows!](#rainbows)
- [Overlay](#overlay)
- [Contributor information](#contributor-information)
- [Projects using react-cookie-consent](#projects-using-react-cookie-consent)
- [:cookie: react-cookie-consent :cookie:](#cookie-react-cookie-consent-cookie)
- [Default look](#default-look)
- [Table of contents](#table-of-contents)
- [Installation](#installation)
- [Using it](#using-it)
- [getting the cookies value in your own code](#getting-the-cookies-value-in-your-own-code)
- [reset the cookies value in your own code](#reset-the-cookies-value-in-your-own-code)
- [Props](#props)
- [Debugging it](#debugging-it)
- [Why are there two cookies? One of which named "Legacy"](#why-are-there-two-cookies-one-of-which-named-legacy)
- [Styling it](#styling-it)
- [Examples](#examples)
- [Changing the bar background to red](#changing-the-bar-background-to-red)
- [Changing the button font-weight to bold](#changing-the-button-font-weight-to-bold)
- [Using predefined CSS classes](#using-predefined-css-classes)
- [Accept on scroll](#accept-on-scroll)
- [Flipping the buttons](#flipping-the-buttons)
- [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 -->
@ -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
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
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
@ -137,53 +139,55 @@ That option would be interesting if you want to allow user to change their conse
## Props
| 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. |
| 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 |
| 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) |
| 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 |
| cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. |
| 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. |
| 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. |
| 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. |
| expires | number | 365 | Number of days before the cookie expires. |
| 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. |
| containerClasses | string | "" | CSS classes to apply to the surrounding container |
| buttonClasses | string | "" | CSS classes to apply to the button |
| buttonWrapperClasses | string | "" | CSS classes to apply to the div wrapping the buttons |
| declineButtonClasses | string | "" | CSS classes to apply to the decline button |
| buttonId | string | "" | Id to apply to the button |
| declineButtonId | string | "" | Id to apply to the decline button |
| contentClasses | string | "" | CSS classes to apply to the content |
| overlayClasses | string | "" | CSS classes to apply to the surrounding overlay |
| style | object | [look at source][style] | React styling object for the bar. |
| buttonStyle | object | [look at source][buttonstyle] | React styling object for the button. |
| declineButtonStyle | object | [look at source][declinebuttonstyle] | React styling object for the decline button. |
| contentStyle | object | [look at source][contentstyle] | React styling object for the content. |
| overlayStyle | object | [look at source][overlaystyle] | React styling object for the overlay. |
| disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) |
| enableDeclineButton | boolean | false | If enabled the decline button will be rendered |
| flipButtons | boolean | false | If enabled the accept and decline buttons will be flipped |
| ButtonComponent | React component | button | React Component to render as a button. |
| sameSite | string, "strict", "lax" or "none" | none | Cookies sameSite attribute value |
| cookieSecurity | boolean ¡ | undefined | Cookie security level. Defaults to true unless running on http. |
| ariaAcceptLabel | string | Accept cookies | Aria label to set on the accept button |
| ariaDeclineLabel | string | Decline cookies | Aria label to set on the decline button |
| acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) |
| acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled |
| customContentAttributes | object | `{}` | Allows you to set custom (data) attributes on the content div |
| customContainerAttributes | object | `{}` | Allows you to set custom (data) attributes on the container div |
| onOverlayClick | function | `() => {}` | allows you to react to a click on the overlay |
| 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 |
| 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. |
| 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 |
| 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) |
| 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 |
| 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. |
| 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" |
| 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. |
| debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. |
| expires | number | 365 | Number of days before the cookie expires. |
| 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. |
| containerClasses | string | "" | CSS classes to apply to the surrounding container |
| buttonClasses | string | "" | CSS classes to apply to the button |
| buttonWrapperClasses | string | "" | CSS classes to apply to the div wrapping the buttons |
| customButtonWrapperAttributes | `React.HTMLAttributes<HTMLDivElement>` | `{}` | Allows you to set custom (data) attributes on the button wrapper div |
| declineButtonClasses | string | "" | CSS classes to apply to the decline button |
| buttonId | string | "" | Id to apply to the button |
| declineButtonId | string | "" | Id to apply to the decline button |
| contentClasses | string | "" | CSS classes to apply to the content |
| overlayClasses | string | "" | CSS classes to apply to the surrounding overlay |
| style | object | [look at source][style] | React styling object for the bar. |
| buttonStyle | object | [look at source][buttonstyle] | React styling object for the button. |
| declineButtonStyle | object | [look at source][declinebuttonstyle] | React styling object for the decline button. |
| contentStyle | object | [look at source][contentstyle] | React styling object for the content. |
| overlayStyle | object | [look at source][overlaystyle] | React styling object for the overlay. |
| disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) |
| enableDeclineButton | boolean | false | If enabled the decline button will be rendered |
| flipButtons | boolean | false | If enabled the accept and decline buttons will be flipped |
| ButtonComponent | React component | button | React Component to render as a button. |
| sameSite | string, "strict", "lax" or "none" | none | Cookies sameSite attribute value |
| cookieSecurity | boolean | undefined | Cookie security level. Defaults to true unless running on http. |
| ariaAcceptLabel | string | Accept cookies | Aria label to set on the accept button |
| ariaDeclineLabel | string | Decline cookies | Aria label to set on the decline button |
| acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) |
| acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled |
| customContentAttributes | object | `{}` | Allows you to set custom (data) attributes on the content div |
| customContainerAttributes | object | `{}` | Allows you to set custom (data) attributes on the container div |
| onOverlayClick | function | `() => {}` | allows you to react to a click on the overlay |
| 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
@ -296,7 +300,7 @@ You can add more cookie options using the extraCookieOptions parameter like so:
<CookieConsent extraCookieOptions={{ domain: "myexample.com" }}>cookie bar</CookieConsent>
```
#### Rainbows!
#### Rainbows
![rainbows!](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/rainbow.png?raw=true)

76
build/index.d.ts vendored
View File

@ -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 +0,0 @@
Subproject commit bff8dd76c5c13a0bf38a555b2d551e11540d30f0

44624
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +1,103 @@
{
"name": "react-cookie-consent",
"author": {
"name": "Rick van Lieshout",
"email": "info@rickvanlieshout.com"
},
"version": "7.3.0",
"version": "9.0.0",
"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": [
"react",
"cookie",
"consent",
"cookiebar"
],
"license": "MIT",
"homepage": "https://github.com/Mastermindzh/react-cookie-consent#readme",
"bugs": {
"url": "https://github.com/Mastermindzh/react-cookie-consent/issues"
},
"homepage": "https://github.com/Mastermindzh/react-cookie-consent#readme",
"devDependencies": {
"@babel/cli": "^7.12.1",
"@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"
"repository": {
"type": "git",
"url": "git+https://github.com/Mastermindzh/react-cookie-consent.git"
},
"prettier": "@mastermindzh/prettier-config",
"husky": {
"hooks": {
"pre-commit": "lint-staged --allow-empty"
}
"license": "MIT",
"author": {
"name": "Rick van Lieshout",
"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": {
"*.{js*,ts*,htm*,md,scss}": [
"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
View 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: {},
};

View 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
View 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;

View 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
View File

@ -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 };

View File

@ -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
View 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;

View File

@ -0,0 +1 @@
export const defaultCookieConsentName = "CookieConsent";

View File

@ -0,0 +1,4 @@
export * from "./positionOptions";
export * from "./sameSiteOptions";
export * from "./visibilityOptions";
export * from "./defaultCookieName";

View File

@ -0,0 +1,5 @@
export const POSITION_OPTIONS = {
TOP: "top",
BOTTOM: "bottom",
NONE: "none",
};

View File

@ -0,0 +1,5 @@
export enum SAME_SITE_OPTIONS {
STRICT = "strict",
LAX = "lax",
NONE = "none",
}

View File

@ -0,0 +1,5 @@
export const VISIBILITY_OPTIONS = {
HIDDEN: "hidden",
SHOW: "show",
BY_COOKIE_VALUE: "byCookieValue",
};

35
src/utilities.ts Normal file
View 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`;
};

View 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>
);
};

View File

@ -0,0 +1,3 @@
import { CookieConsentProps, defaultCookieConsentProps } from "../../src/CookieConsent.props";
export const defaultStoryProps: CookieConsentProps = { ...defaultCookieConsentProps, debug: true };

View 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
View 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";

View 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 };

View 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 };

View 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 };

View 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 };

View 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 };

View 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 };

View 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 };

View 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
View 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,
}
}

View File

@ -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" }] })],
};